# HG changeset patch # User Michael Van De Vanter # Date 1432687124 25200 # Node ID fc376e0b80baa909c6f967fb05f92425729135d8 # Parent 23bc51cd8654924e9549884cadf292d3a54ef9a5# Parent ce585b0ac3e2eef29a0c4423ab9a5c524a331a30 Merge with ce585b0ac3e2eef29a0c4423ab9a5c524a331a30 diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java Tue May 26 17:38:44 2015 -0700 @@ -174,4 +174,22 @@ } return buf.append(String.format("], notRecorded:%.6f>", getNotRecordedProbability())).toString(); } + + /** + * Returns {@code true} if all types seen at this location have been recorded in the profile. + */ + public boolean allTypesRecorded() { + return this.getNotRecordedProbability() == 0.0; + } + + /** + * Returns the single monormorphic type representing this profile or {@code null} if no such + * type exists. + */ + public ResolvedJavaType asSingleType() { + if (allTypesRecorded() && this.getTypes().length == 1) { + return getTypes()[0].getType(); + } + return null; + } } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java --- a/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java Tue May 26 17:38:44 2015 -0700 @@ -56,15 +56,6 @@ String signature() default ""; /** - * Determines if this method should be substituted in all cases, even if inlining thinks it is - * not important. - * - * Note that this is still depending on whether inlining sees the correct call target, so it's - * only a hard guarantee for static and special invocations. - */ - boolean forced() default false; - - /** * Determines if the substitution is for a method that may not be part of the runtime. For * example, a method introduced in a later JDK version. Substitutions for such methods are * omitted if the original method cannot be found. diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java --- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Tue May 26 17:38:44 2015 -0700 @@ -1075,4 +1075,9 @@ return result; } + public void emitNullCheck(Value address, LIRFrameState state) { + PlatformKind kind = address.getPlatformKind(); + assert kind == Kind.Object || kind == Kind.Long : address + " - " + kind + " not an object!"; + append(new NullCheckOp(asAddressValue(address), state)); + } } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Tue May 26 17:38:44 2015 -0700 @@ -440,17 +440,15 @@ return result; } + @Override public void emitNullCheck(Value address, LIRFrameState state) { - PlatformKind kind = address.getLIRKind().getPlatformKind(); - if (address.getLIRKind().getPlatformKind() == Kind.Int) { + PlatformKind kind = address.getPlatformKind(); + if (kind == Kind.Int) { CompressEncoding encoding = config.getOopEncoding(); - Value uncompressed; - uncompressed = emitUncompress(address, encoding, false); - - append(new NullCheckOp(load(uncompressed), state)); + Value uncompressed = emitUncompress(address, encoding, false); + append(new NullCheckOp(asAddressValue(uncompressed), state)); } else { - assert kind == Kind.Object || kind == Kind.Long : address + " - " + kind + " not an object!"; - append(new NullCheckOp(load(address), state)); + super.emitNullCheck(address, state); } } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Tue May 26 17:38:44 2015 -0700 @@ -32,7 +32,6 @@ import static com.oracle.graal.hotspot.InitTimer.*; import static com.oracle.graal.hotspot.meta.HotSpotSuitesProvider.*; import static com.oracle.graal.nodes.StructuredGraph.*; -import static com.oracle.graal.phases.common.inlining.InliningUtil.*; import java.lang.management.*; import java.util.concurrent.*; @@ -126,7 +125,12 @@ /** * Time spent in compilation. */ - public static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); + private static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); + + /** + * Meters the {@linkplain StructuredGraph#getBytecodeSize() bytecodes} compiled. + */ + private static final DebugMetric CompiledBytecodes = Debug.metric("CompiledBytecodes"); public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation"); @@ -161,8 +165,7 @@ public void runCompilation() { HotSpotVMConfig config = backend.getRuntime().getConfig(); final long threadId = Thread.currentThread().getId(); - long previousInlinedBytecodes = InlinedBytecodes.getCurrentValue(); - long previousCompilationTime = CompilationTime.getCurrentValue(); + long startCompilationTime = System.nanoTime(); HotSpotInstalledCode installedCode = null; final boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI; @@ -170,14 +173,14 @@ EventProvider eventProvider = Graal.getRequiredCapability(EventProvider.class); CompilationEvent compilationEvent = eventProvider.newCompilationEvent(); + // If there is already compiled code for this method on our level we simply return. + // Graal compiles are always at the highest compile level, even in non-tiered mode so we + // only need to check for that value. + if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) { + return; + } + try (DebugCloseable a = CompilationTime.start()) { - // If there is already compiled code for this method on our level we simply return. - // Graal compiles are always at the highest compile level, even in non-tiered mode so we - // only need to check for that value. - if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) { - return; - } - CompilationStatistics stats = CompilationStatistics.create(method, isOSR); final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed(); if (printCompilation) { @@ -193,14 +196,11 @@ // Begin the compilation event. compilationEvent.begin(); - boolean recordEvolMethodDeps = graalEnv == 0 || unsafe.getByte(graalEnv + config.graalEnvJvmtiCanHotswapOrPostBreakpointOffset) != 0; - HotSpotProviders providers = backend.getProviders(); graph = new StructuredGraph(method, entryBCI, AllowAssumptions.from(OptAssumptions.getValue())); - if (!recordEvolMethodDeps) { + if (shouldDisableMethodInliningRecording(config)) { graph.disableInlinedMethodRecording(); } - InlinedBytecodes.add(method.getCodeSize()); CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false); if (graph.getEntryBCI() != StructuredGraph.INVOCATION_ENTRY_BCI) { // for OSR, only a pointer is passed to the method. @@ -280,7 +280,8 @@ System.exit(-1); } } finally { - final int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes); + final int compiledBytecodes = graph.getBytecodeSize(); + CompiledBytecodes.add(compiledBytecodes); // Log a compilation event. if (compilationEvent.shouldWrite() && installedCode != null) { @@ -290,25 +291,40 @@ compilationEvent.setSucceeded(true); compilationEvent.setIsOsr(isOSR); compilationEvent.setCodeSize(installedCode.getSize()); - compilationEvent.setInlinedBytes(processedBytes); + compilationEvent.setInlinedBytes(compiledBytecodes); compilationEvent.commit(); } if (graalEnv != 0) { long ctask = unsafe.getAddress(graalEnv + config.graalEnvTaskOffset); assert ctask != 0L; - unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, processedBytes); + unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, compiledBytecodes); } + long compilationTime = System.nanoTime() - startCompilationTime; if ((config.ciTime || config.ciTimeEach) && installedCode != null) { - long time = CompilationTime.getCurrentValue() - previousCompilationTime; - TimeUnit timeUnit = CompilationTime.getTimeUnit(); - long timeUnitsPerSecond = timeUnit.convert(1, TimeUnit.SECONDS); + long timeUnitsPerSecond = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); CompilerToVM c2vm = backend.getRuntime().getCompilerToVM(); - c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, processedBytes, time, timeUnitsPerSecond, installedCode); + c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, compiledBytecodes, compilationTime, timeUnitsPerSecond, installedCode); } } } + /** + * Determines whether to {@linkplain StructuredGraph#disableInlinedMethodRecording() disable} + * method inlining recording for the method being compiled. + * + * @see StructuredGraph#getBytecodeSize() + */ + private boolean shouldDisableMethodInliningRecording(HotSpotVMConfig config) { + if (config.ciTime || config.ciTimeEach || CompiledBytecodes.isEnabled()) { + return false; + } + if (graalEnv == 0 || unsafe.getByte(graalEnv + config.graalEnvJvmtiCanHotswapOrPostBreakpointOffset) != 0) { + return false; + } + return true; + } + private String getMethodDescription() { return String.format("%-6d Graal %-70s %-45s %-50s %s", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature().toMethodDescriptor(), entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + entryBCI + ") "); diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java Tue May 26 17:38:44 2015 -0700 @@ -26,14 +26,10 @@ import static com.oracle.graal.hotspot.HotSpotOptionsLoader.*; import static java.lang.Double.*; -import java.lang.reflect.*; - import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.common.*; import com.oracle.graal.debug.*; import com.oracle.graal.options.*; import com.oracle.graal.options.OptionUtils.OptionConsumer; -import com.oracle.graal.phases.common.inlining.*; //JaCoCo Exclude @@ -47,17 +43,12 @@ /** * Parses the Graal specific options specified to HotSpot (e.g., on the command line). - * - * @return true if the CITime or CITimeEach HotSpot VM options are set */ - private static native boolean parseVMOptions(); + private static native void parseVMOptions(); static { - boolean timeCompilations = parseVMOptions(); - if (timeCompilations) { - unconditionallyEnableTimerOrMetric(InliningUtil.class, "InlinedBytecodes"); - unconditionallyEnableTimerOrMetric(CompilationTask.class, "CompilationTime"); - } + parseVMOptions(); + assert !Debug.Initialization.isDebugInitialized() : "The class " + Debug.class.getName() + " must not be initialized before the Graal runtime has been initialized. " + "This can be fixed by placing a call to " + Graal.class.getName() + ".runtime() on the path that triggers initialization of " + Debug.class.getName(); if (areDebugScopePatternsEnabled()) { @@ -127,33 +118,4 @@ public static boolean parseOption(String option, OptionConsumer setter) { return OptionUtils.parseOption(options, option, GRAAL_OPTION_PREFIX, setter); } - - /** - * Sets the relevant system property such that a {@link DebugTimer} or {@link DebugMetric} - * associated with a field in a class will be unconditionally enabled when it is created. - *

- * This method verifies that the named field exists and is of an expected type. However, it does - * not verify that the timer or metric created has the same name of the field. - * - * @param c the class in which the field is declared - * @param name the name of the field - */ - private static void unconditionallyEnableTimerOrMetric(Class c, String name) { - try { - Field field = c.getDeclaredField(name); - String propertyName; - if (DebugTimer.class.isAssignableFrom(field.getType())) { - propertyName = Debug.ENABLE_TIMER_PROPERTY_NAME_PREFIX + name; - } else { - assert DebugMetric.class.isAssignableFrom(field.getType()); - propertyName = Debug.ENABLE_METRIC_PROPERTY_NAME_PREFIX + name; - } - String previous = System.setProperty(propertyName, "true"); - if (previous != null) { - System.err.println("Overrode value \"" + previous + "\" of system property \"" + propertyName + "\" with \"true\""); - } - } catch (Exception e) { - throw new GraalInternalError(e); - } - } } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Tue May 26 17:38:44 2015 -0700 @@ -201,13 +201,13 @@ Word top = readTlabTop(thread); Word end = readTlabEnd(thread); Word newTop = top.add(allocationSize); - if ((skipNegativeCheck || belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) && useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { + if (probability(FREQUENT_PROBABILITY, skipNegativeCheck || belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) && useTLAB() && + probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { writeTlabTop(thread, newTop); emitPrefetchAllocate(newTop, true); newarray_loopInit.inc(); result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, true); } else { - newarray_stub.inc(); result = newArray(HotSpotBackend.NEW_ARRAY, hub, length); } profileAllocation("array", allocationSize, typeContext); @@ -233,7 +233,7 @@ @Snippet public static Object allocateArrayDynamic(Class elementType, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) { Word hub = loadWordFromObject(elementType, arrayKlassOffset(), CLASS_ARRAY_KLASS_LOCATION); - if (hub.equal(Word.zero()) || !belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { + if (probability(BranchProbabilityNode.NOT_FREQUENT_PROBABILITY, hub.equal(Word.zero()) || !belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH))) { return dynamicNewArrayStub(DYNAMIC_NEW_ARRAY, elementType, length); } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Tue May 26 17:38:44 2015 -0700 @@ -1613,9 +1613,7 @@ } // Record inlined method dependency in the graph - if (graph.isInlinedMethodRecordingEnabled()) { - graph.getInlinedMethods().add(targetMethod); - } + graph.recordInlinedMethod(targetMethod); } } @@ -3070,7 +3068,26 @@ JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); if (typeCheckPlugin == null || !typeCheckPlugin.checkCast(this, object, resolvedType, profile)) { - ValueNode checkCastNode = append(createCheckCast(resolvedType, object, profile, false)); + ValueNode checkCastNode = null; + if (profile != null) { + if (profile.getNullSeen().isFalse()) { + object = append(GuardingPiNode.createNullCheck(object)); + ResolvedJavaType singleType = profile.asSingleType(); + if (singleType != null) { + LogicNode typeCheck = append(TypeCheckNode.create(singleType, object)); + if (typeCheck.isTautology()) { + checkCastNode = object; + } else { + GuardingPiNode piNode = append(new GuardingPiNode(object, typeCheck, false, DeoptimizationReason.TypeCheckedInliningViolated, + DeoptimizationAction.InvalidateReprofile, StampFactory.exactNonNull(singleType))); + checkCastNode = piNode; + } + } + } + } + if (checkCastNode == null) { + checkCastNode = append(createCheckCast(resolvedType, object, profile, false)); + } frameState.apush(checkCastNode); } } else { @@ -3087,7 +3104,21 @@ JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); if (typeCheckPlugin == null || !typeCheckPlugin.instanceOf(this, object, resolvedType, profile)) { - ValueNode instanceOfNode = createInstanceOf(resolvedType, object, profile); + ValueNode instanceOfNode = null; + if (profile != null) { + if (profile.getNullSeen().isFalse()) { + object = append(GuardingPiNode.createNullCheck(object)); + ResolvedJavaType singleType = profile.asSingleType(); + if (singleType != null) { + LogicNode typeCheck = append(TypeCheckNode.create(singleType, object)); + append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile)); + instanceOfNode = LogicConstantNode.forBoolean(resolvedType.isAssignableFrom(singleType)); + } + } + } + if (instanceOfNode == null) { + instanceOfNode = createInstanceOf(resolvedType, object, profile); + } frameState.ipush(append(genConditional(genUnique(instanceOfNode)))); } } else { diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java Tue May 26 17:38:44 2015 -0700 @@ -31,7 +31,8 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; import com.oracle.graal.compiler.common.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.ImplicitNullCheck; @@ -280,16 +281,15 @@ public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { try (ScratchRegister scratchReg = masm.getScratchRegister()) { Register scratch = scratchReg.getRegister(); - StackSlot intInput = reInterprete(asStackSlot(getInput())); - StackSlot intResult = reInterprete(asStackSlot(getResult())); + StackSlot intInput = reInterpret(asStackSlot(getInput())); + StackSlot intResult = reInterpret(asStackSlot(getResult())); // move stack slot move(crb, masm, scratch.asValue(intInput.getLIRKind()), intInput, SPARCDelayedControlTransfer.DUMMY); move(crb, masm, intResult, scratch.asValue(intResult.getLIRKind()), delayedControlTransfer); } - } - private static StackSlot reInterprete(StackSlot slot) { + private static StackSlot reInterpret(StackSlot slot) { switch ((Kind) slot.getPlatformKind()) { case Boolean: case Byte: @@ -357,60 +357,7 @@ @Override public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - final SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch); - final Register dst = asRegister(result); - delayedControlTransfer.emitControlTransfer(crb, masm); - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - switch ((Kind) kind) { - case Boolean: - case Byte: - if (signExtend) { - masm.ldsb(addr, dst); - } else { - masm.ldub(addr, dst); - } - break; - case Short: - if (signExtend) { - masm.ldsh(addr, dst); - } else { - masm.lduh(addr, dst); - } - break; - case Char: - if (signExtend) { - masm.ldsh(addr, dst); - } else { - masm.lduh(addr, dst); - } - break; - case Int: - if (signExtend) { - masm.ldsw(addr, dst); - } else { - masm.lduw(addr, dst); - } - break; - case Long: - masm.ldx(addr, dst); - break; - case Float: - masm.ldf(addr, dst); - break; - case Double: - masm.lddf(addr, dst); - break; - case Object: - masm.ldx(addr, dst); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } + emitLoad(address.toAddress(), result, signExtend, kind, delayedControlTransfer, state, crb, masm); } } @@ -455,7 +402,7 @@ } } - public static final class MembarOp extends SPARCLIRInstruction { + public static final class MembarOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MembarOp.class); private final int barriers; @@ -467,6 +414,7 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + delayedControlTransfer.emitControlTransfer(crb, masm); masm.membar(barriers); } } @@ -474,10 +422,10 @@ public static final class NullCheckOp extends SPARCLIRInstruction implements NullCheck, SPARCTailDelayedLIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(NullCheckOp.class); - @Use({REG}) protected AllocatableValue input; + @Use({COMPOSITE}) protected SPARCAddressValue input; @State protected LIRFrameState state; - public NullCheckOp(Variable input, LIRFrameState state) { + public NullCheckOp(SPARCAddressValue input, LIRFrameState state) { super(TYPE); this.input = input; this.state = state; @@ -486,8 +434,9 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { delayedControlTransfer.emitControlTransfer(crb, masm); + SPARCAddress addr = input.toAddress(); crb.recordImplicitException(masm.position(), state); - masm.ldx(new SPARCAddress(asRegister(input), 0), g0); + masm.ldx(addr, g0); } public Value getCheckedValue() { @@ -518,8 +467,8 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - move(crb, masm, result, newValue, delayedControlTransfer); - compareAndSwap(masm, address, cmpValue, result); + move(crb, masm, result, newValue, SPARCDelayedControlTransfer.DUMMY); + compareAndSwap(crb, masm, address, cmpValue, result, delayedControlTransfer); } } @@ -572,42 +521,7 @@ @Override public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - assert isRegister(input); - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch); - delayedControlTransfer.emitControlTransfer(crb, masm); - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - switch ((Kind) kind) { - case Boolean: - case Byte: - masm.stb(asRegister(input), addr); - break; - case Short: - case Char: - masm.sth(asRegister(input), addr); - break; - case Int: - masm.stw(asRegister(input), addr); - break; - case Long: - masm.stx(asRegister(input), addr); - break; - case Object: - masm.stx(asRegister(input), addr); - break; - case Float: - masm.stf(asRegister(input), addr); - break; - case Double: - masm.stdf(asRegister(input), addr); - break; - default: - throw GraalInternalError.shouldNotReachHere("missing: " + kind); - } - } + emitStore(input, address.toAddress(), kind, delayedControlTransfer, state, crb, masm); } } @@ -664,13 +578,15 @@ if (isRegister(result)) { reg2reg(crb, masm, result, input, delaySlotLir); } else if (isStackSlot(result)) { - reg2stack(crb, masm, result, input, delaySlotLir); + SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); + emitStore(input, resultAddress, input.getPlatformKind(), delaySlotLir, null, crb, masm); } else { throw GraalInternalError.shouldNotReachHere(); } } else if (isStackSlot(input)) { if (isRegister(result)) { - stack2reg(crb, masm, result, input, delaySlotLir); + SPARCAddress inputAddress = (SPARCAddress) crb.asAddress(input); + emitLoad(inputAddress, result, false, input.getPlatformKind(), delaySlotLir, null, crb, masm); } else { throw GraalInternalError.shouldNotReachHere(); } @@ -680,7 +596,8 @@ const2reg(crb, masm, result, constant, delaySlotLir); } else if (isStackSlot(result)) { if (constant.isDefaultForKind() || constant.isNull()) { - reg2stack(crb, masm, result, g0.asValue(LIRKind.derive(input)), delaySlotLir); + SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); + emitStore(g0.asValue(LIRKind.derive(input)), resultAddress, input.getPlatformKind(), delaySlotLir, null, crb, masm); } else { try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); @@ -690,7 +607,8 @@ } else { new Setx(value, scratch).emit(masm); } - reg2stack(crb, masm, result, scratch.asValue(LIRKind.derive(input)), delaySlotLir); + SPARCAddress resultAddress = (SPARCAddress) crb.asAddress(result); + emitStore(scratch.asValue(LIRKind.derive(input)), resultAddress, input.getPlatformKind(), delaySlotLir, null, crb, masm); } } } else { @@ -757,78 +675,6 @@ } } - private static void reg2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { - SPARCAddress dst = (SPARCAddress) crb.asAddress(result); - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - dst = generateSimm13OffsetLoad(dst, masm, scratch); - Register src = asRegister(input); - delaySlotLir.emitControlTransfer(crb, masm); - switch (input.getKind()) { - case Byte: - case Boolean: - masm.stb(src, dst); - break; - case Char: - case Short: - masm.sth(src, dst); - break; - case Int: - masm.stw(src, dst); - break; - case Long: - case Object: - masm.stx(src, dst); - break; - case Float: - masm.stf(src, dst); - break; - case Double: - masm.stdf(src, dst); - break; - default: - throw GraalInternalError.shouldNotReachHere("Input is a: " + input.getKind() + "(" + input + ")"); - } - } - } - - private static void stack2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) { - SPARCAddress src = (SPARCAddress) crb.asAddress(input); - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - src = generateSimm13OffsetLoad(src, masm, scratch); - Register dst = asRegister(result); - delaySlotLir.emitControlTransfer(crb, masm); - switch (input.getKind()) { - case Boolean: - case Byte: - masm.ldub(src, dst); - break; - case Short: - masm.lduh(src, dst); - break; - case Char: - masm.lduh(src, dst); - break; - case Int: - masm.lduw(src, dst); - break; - case Long: - case Object: - masm.ldx(src, dst); - break; - case Float: - masm.ldf(src, dst); - break; - case Double: - masm.lddf(src, dst); - break; - default: - throw GraalInternalError.shouldNotReachHere("Input is a: " + input.getKind()); - } - } - } - private static void const2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, JavaConstant input, SPARCDelayedControlTransfer delaySlotLir) { try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); @@ -934,7 +780,9 @@ } } - protected static void compareAndSwap(SPARCMacroAssembler masm, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue) { + protected static void compareAndSwap(CompilationResultBuilder crb, SPARCMacroAssembler masm, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue, + SPARCDelayedControlTransfer delay) { + delay.emitControlTransfer(crb, masm); switch (cmpValue.getKind()) { case Int: masm.cas(asRegister(address), asRegister(cmpValue), asRegister(newValue)); @@ -947,4 +795,101 @@ throw GraalInternalError.shouldNotReachHere(); } } + + private static void emitLoad(SPARCAddress address, Value result, boolean signExtend, PlatformKind kind, SPARCDelayedControlTransfer delayedControlTransfer, LIRFrameState state, + CompilationResultBuilder crb, SPARCMacroAssembler masm) { + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + final SPARCAddress addr = generateSimm13OffsetLoad(address, masm, scratch); + final Register dst = asRegister(result); + delayedControlTransfer.emitControlTransfer(crb, masm); + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + switch ((Kind) kind) { + case Boolean: + case Byte: + if (signExtend) { + masm.ldsb(addr, dst); + } else { + masm.ldub(addr, dst); + } + break; + case Short: + if (signExtend) { + masm.ldsh(addr, dst); + } else { + masm.lduh(addr, dst); + } + break; + case Char: + if (signExtend) { + masm.ldsh(addr, dst); + } else { + masm.lduh(addr, dst); + } + break; + case Int: + if (signExtend) { + masm.ldsw(addr, dst); + } else { + masm.lduw(addr, dst); + } + break; + case Long: + masm.ldx(addr, dst); + break; + case Float: + masm.ldf(addr, dst); + break; + case Double: + masm.lddf(addr, dst); + break; + case Object: + masm.ldx(addr, dst); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } + + private static void emitStore(Value input, SPARCAddress address, PlatformKind kind, SPARCDelayedControlTransfer delayedControlTransfer, LIRFrameState state, CompilationResultBuilder crb, + SPARCMacroAssembler masm) { + try (ScratchRegister sc = masm.getScratchRegister()) { + Register scratch = sc.getRegister(); + SPARCAddress addr = generateSimm13OffsetLoad(address, masm, scratch); + delayedControlTransfer.emitControlTransfer(crb, masm); + if (state != null) { + crb.recordImplicitException(masm.position(), state); + } + switch ((Kind) kind) { + case Boolean: + case Byte: + masm.stb(asRegister(input), addr); + break; + case Short: + case Char: + masm.sth(asRegister(input), addr); + break; + case Int: + masm.stw(asRegister(input), addr); + break; + case Long: + masm.stx(asRegister(input), addr); + break; + case Object: + masm.stx(asRegister(input), addr); + break; + case Float: + masm.stf(asRegister(input), addr); + break; + case Double: + masm.stdf(asRegister(input), addr); + break; + default: + throw GraalInternalError.shouldNotReachHere("missing: " + kind); + } + } + } } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Tue May 26 17:38:44 2015 -0700 @@ -81,6 +81,15 @@ this.negated = negateCondition; } + public static ValueNode createNullCheck(ValueNode object) { + ObjectStamp objectStamp = (ObjectStamp) object.stamp(); + if (objectStamp.nonNull()) { + return object; + } else { + return new GuardingPiNode(object); + } + } + @Override public void lower(LoweringTool tool) { GuardingNode guard = tool.createGuard(next(), condition, reason, action, negated); diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java Tue May 26 17:38:44 2015 -0700 @@ -55,4 +55,22 @@ public static LogicNode or(LogicNode a, boolean negateA, LogicNode b, boolean negateB, double shortCircuitProbability) { return a.graph().unique(new ShortCircuitOrNode(a, negateA, b, negateB, shortCircuitProbability)); } + + public final boolean isTautology() { + if (this instanceof LogicConstantNode) { + LogicConstantNode logicConstantNode = (LogicConstantNode) this; + return logicConstantNode.getValue(); + } + + return false; + } + + public final boolean isContradiction() { + if (this instanceof LogicConstantNode) { + LogicConstantNode logicConstantNode = (LogicConstantNode) this; + return !logicConstantNode.getValue(); + } + + return false; + } } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Tue May 26 17:38:44 2015 -0700 @@ -116,9 +116,10 @@ private final Assumptions assumptions; /** - * The methods that were inlined while constructing this graph. + * Records the methods that were inlined while constructing this graph along with how many times + * each method was inlined. */ - private Set inlinedMethods = new HashSet<>(); + private Map inlinedMethods = new HashMap<>(); /** * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start() @@ -515,12 +516,12 @@ } /** - * Disables recording of methods inlined while constructing this graph. This can be done at most + * Disables method inlining recording while constructing this graph. This can be done at most * once and must be done before any inlined methods are recorded. */ public void disableInlinedMethodRecording() { - assert inlinedMethods != null : "cannot disable inlined method recording more than once"; - assert inlinedMethods.isEmpty() : "cannot disable inlined method recording once methods have been recorded"; + assert inlinedMethods != null : "cannot disable method inlining recording more than once"; + assert inlinedMethods.isEmpty() : "cannot disable method inlining recording once methods have been recorded"; inlinedMethods = null; } @@ -531,11 +532,69 @@ /** * Gets the methods that were inlined while constructing this graph. * - * @return {@code null} if inlined method recording has been + * @return {@code null} if method inlining recording has been * {@linkplain #disableInlinedMethodRecording() disabled} */ public Set getInlinedMethods() { - return inlinedMethods; + return inlinedMethods == null ? null : inlinedMethods.keySet(); + } + + /** + * If method inlining recording has not been {@linkplain #disableInlinedMethodRecording() + * disabled}, records that {@code inlinedMethod} was inlined to this graph. Otherwise, this + * method does nothing. + */ + public void recordInlinedMethod(ResolvedJavaMethod inlinedMethod) { + if (inlinedMethods != null) { + Integer count = inlinedMethods.get(inlinedMethod); + if (count != null) { + inlinedMethods.put(inlinedMethod, count + 1); + } else { + inlinedMethods.put(inlinedMethod, 1); + } + } + } + + /** + * If method inlining recording has not been {@linkplain #disableInlinedMethodRecording() + * disabled}, updates the {@linkplain #getInlinedMethods() inlined methods} of this graph with + * the inlined methods of another graph. Otherwise, this method does nothing. + */ + public void updateInlinedMethods(StructuredGraph other) { + if (inlinedMethods != null) { + assert this != other; + Map otherInlinedMethods = other.inlinedMethods; + if (otherInlinedMethods != null) { + for (Map.Entry e : otherInlinedMethods.entrySet()) { + ResolvedJavaMethod key = e.getKey(); + Integer count = inlinedMethods.get(key); + if (count != null) { + inlinedMethods.put(key, count + e.getValue()); + } else { + inlinedMethods.put(key, e.getValue()); + } + } + } + } + } + + /** + * Gets the input bytecode {@linkplain ResolvedJavaMethod#getCodeSize() size} from which this + * graph is constructed. This ignores how many bytecodes in each constituent method are actually + * parsed (which may be none for methods whose IR is retrieved from a cache or less than the + * full amount for any given method due to profile guided branch pruning). If method inlining + * recording has been {@linkplain #disableInlinedMethodRecording() disabled} for this graph, + * bytecode counts for inlined methods are not included in the returned value. + */ + public int getBytecodeSize() { + int res = method.getCodeSize(); + if (inlinedMethods != null) { + for (Map.Entry e : inlinedMethods.entrySet()) { + int inlinedBytes = e.getValue() * e.getKey().getCodeSize(); + res += inlinedBytes; + } + } + return res; } /** diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Tue May 26 17:38:44 2015 -0700 @@ -132,7 +132,7 @@ return LogicConstantNode.contradiction(); } else { boolean superType = inputType.isAssignableFrom(type); - if (!superType && !isInterfaceOrArrayOfInterface(inputType) && !isInterfaceOrArrayOfInterface(type)) { + if (!superType && (type.asExactType() != null || (!isInterfaceOrArrayOfInterface(inputType) && !isInterfaceOrArrayOfInterface(type)))) { return LogicConstantNode.contradiction(); } // since the subtype comparison was only performed on a declared type we don't diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java Tue May 26 17:38:44 2015 -0700 @@ -166,7 +166,7 @@ if (objectType != null) { ResolvedJavaType instanceofType = type; if (instanceofType.equals(objectType)) { - if (objectStamp.nonNull()) { + if (objectStamp.nonNull() && (objectStamp.isExactType() || objectType.isFinal())) { return TriState.TRUE; } } else { diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Tue May 26 17:38:44 2015 -0700 @@ -123,11 +123,6 @@ Collection getAllReplacements(); /** - * Determines whether the replacement of this method is flagged as being inlined always. - */ - boolean isForcedSubstitution(ResolvedJavaMethod methodAt); - - /** * Register snippet templates. */ void registerSnippetTemplateCache(SnippetTemplateCache snippetTemplates); diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Tue May 26 17:38:44 2015 -0700 @@ -53,12 +53,6 @@ public class InliningUtil { private static final String inliningDecisionsScopeString = "InliningDecisions"; - /** - * Meters the size (in bytecodes) of all methods processed during compilation (i.e., top level - * and all inlined methods), irrespective of how many bytecodes in each method are actually - * parsed (which may be none for methods whose IR is retrieved from a cache). - */ - public static final DebugMetric InlinedBytecodes = Debug.metric("InlinedBytecodes"); /** * Print a HotSpot-style inlining message to the console. @@ -321,7 +315,7 @@ unwindNode = (UnwindNode) duplicates.get(unwindNode); } - finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph.getInlinedMethods(), canonicalizedNodes); + finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph, canonicalizedNodes); GraphUtil.killCFG(invokeNode); @@ -329,7 +323,7 @@ } public static ValueNode finishInlining(Invoke invoke, StructuredGraph graph, FixedNode firstNode, List returnNodes, UnwindNode unwindNode, Assumptions inlinedAssumptions, - Set inlinedMethods, List canonicalizedNodes) { + StructuredGraph inlineGraph, List canonicalizedNodes) { FixedNode invokeNode = invoke.asNode(); FrameState stateAfter = invoke.stateAfter(); assert stateAfter == null || stateAfter.isAlive(); @@ -401,9 +395,7 @@ } // Copy inlined methods from inlinee to caller - if (inlinedMethods != null && graph.getInlinedMethods() != null) { - graph.getInlinedMethods().addAll(inlinedMethods); - } + graph.updateInlinedMethods(inlineGraph); return returnValue; } @@ -486,7 +478,7 @@ * pop return kind from invoke's stateAfter and replace with this frameState's return * value (top of stack) */ - if (invokeReturnKind != Kind.Void && (alwaysDuplicateStateAfter || (frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)))) { + if (frameState.stackSize() > 0 && (alwaysDuplicateStateAfter || stateAfterReturn.stackAt(0) != frameState.stackAt(0))) { stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0)); } @@ -541,8 +533,11 @@ // in the intrinsic code. assert inlinedMethod.getAnnotation(MethodSubstitution.class) != null : "expected an intrinsic when inlinee frame state matches method of call target but does not match the method of the inlinee graph: " + frameState; + } else if (frameState.method().getName().equals(inlinedMethod.getName())) { + // This can happen for method substitutions. } else { - throw new AssertionError(frameState.toString()); + throw new AssertionError(String.format("inlinedMethod=%s frameState.method=%s frameState=%s invoke.method=%s", inlinedMethod, frameState.method(), frameState, + invoke.callTarget().targetMethod())); } } return true; diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java Tue May 26 17:38:44 2015 -0700 @@ -57,11 +57,8 @@ Map duplicateMap = InliningUtil.inline(invoke, calleeGraph, receiverNullCheck, canonicalizeNodes); getInlinedParameterUsages(canonicalizeNodes, calleeGraph, duplicateMap); - InliningUtil.InlinedBytecodes.add(concrete.getCodeSize()); StructuredGraph graph = invoke.asNode().graph(); - if (graph.isInlinedMethodRecordingEnabled()) { - graph.getInlinedMethods().add(concrete); - } + graph.recordInlinedMethod(concrete); return canonicalizeNodes; } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java Tue May 26 17:38:44 2015 -0700 @@ -78,9 +78,6 @@ if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i), info.invoke().bci())) { return false; } - if (!replacements.isForcedSubstitution(info.methodAt(i))) { - return false; - } } return true; } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Tue May 26 17:38:44 2015 -0700 @@ -117,7 +117,7 @@ return "it is an abstract method"; } else if (!method.getDeclaringClass().isInitialized()) { return "the method's class is not initialized"; - } else if (!method.canBeInlined() && !context.getReplacements().isForcedSubstitution(method)) { + } else if (!method.canBeInlined()) { return "it is marked non-inlinable"; } else if (countRecursiveInlining(method) > MaximumRecursiveInlining.getValue()) { return "it exceeds the maximum recursive inlining depth"; diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java Tue May 26 17:38:44 2015 -0700 @@ -39,7 +39,8 @@ public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { InlineInfo inlineInfo = replacements.getInlineInfo(b, method, args, returnType); if (inlineInfo == null) { - if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) { + if (InlineDuringParsing.getValue() && method.hasBytecodes() && !method.isSynchronized() && method.getCode().length <= TrivialInliningSize.getValue() && + b.getDepth() < InlineDuringParsingMaxDepth.getValue()) { return new InlineInfo(method, false); } } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Tue May 26 17:38:44 2015 -0700 @@ -135,7 +135,6 @@ */ protected class ClassReplacements { public final Map methodSubstitutions = CollectionsFactory.newMap(); - public final Set forcedSubstitutions = new HashSet<>(); public ClassReplacements(Class[] substitutionClasses, AtomicReference ref) { for (Class substitutionClass : substitutionClasses) { @@ -172,10 +171,7 @@ if (originalMethods != null) { for (Executable originalMethod : originalMethods) { if (originalMethod != null && (guard == null || guard.execute())) { - ResolvedJavaMethod original = registerMethodSubstitution(this, originalMethod, substituteMethod); - if (original != null && methodSubstitution.forced()) { - forcedSubstitutions.add(original); - } + registerMethodSubstitution(this, originalMethod, substituteMethod); } } } @@ -663,12 +659,6 @@ return result; } - @Override - public boolean isForcedSubstitution(ResolvedJavaMethod method) { - ClassReplacements cr = getClassReplacements(method.getDeclaringClass().getName()); - return cr != null && cr.forcedSubstitutions.contains(method); - } - public boolean hasSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly, int callerBci) { if (!fromBytecodeOnly) { InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method); diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExpectError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExpectError.java Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl.test; + +import java.lang.annotation.*; + +/** + * This annotation is internally known by the dsl processor and used to expect errors for testing + * purposes. This is not part of public API. + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface ExpectError { + + String[] value(); + +} diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.java Tue May 26 17:38:44 2015 -0700 @@ -105,7 +105,6 @@ } @Specialization(contains = "doPowCached", guards = {"exponent == cachedExponent", "cachedExponent <= 10"}) - @ExplodeLoop double doPowCachedExponent(double base, int exponent, @Cached("exponent") int cachedExponent) { doPowCachedExponent++; double result = 1.0; diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl.test.processor; + +import java.io.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.test.*; +import com.oracle.truffle.api.source.*; + +public class LanguageRegistrationTest { + + @ExpectError("Registered language class must be public") + @TruffleLanguage.Registration(name = "myLang", mimeType = "text/x-my") + private static final class MyLang { + } + + @ExpectError("Registered language inner-class must be static") + @TruffleLanguage.Registration(name = "myLangNonStatic", mimeType = "text/x-my") + public final class MyLangNonStatic { + } + + @ExpectError("Registered language class must subclass TruffleLanguage") + @TruffleLanguage.Registration(name = "myLang", mimeType = "text/x-my") + public static final class MyLangNoSubclass { + } + + @ExpectError("Language must have a public constructor accepting TruffleLanguage.Env as parameter") + @TruffleLanguage.Registration(name = "myLangNoCnstr", mimeType = "text/x-my") + public static final class MyLangWrongConstr extends TruffleLanguage { + private MyLangWrongConstr() { + super(null); + } + + @Override + protected Object eval(Source code) throws IOException { + return null; + } + + @Override + protected Object findExportedSymbol(String globalName) { + return null; + } + + @Override + protected Object getLanguageGlobal() { + return null; + } + + @Override + protected boolean isObjectOfLanguage(Object object) { + return false; + } + } + + @ExpectError("Language must have a public constructor accepting TruffleLanguage.Env as parameter") + @TruffleLanguage.Registration(name = "myLangNoCnstr", mimeType = "text/x-my") + public static final class MyLangNoConstr extends TruffleLanguage { + public MyLangNoConstr() { + super(null); + } + + @Override + protected Object eval(Source code) throws IOException { + return null; + } + + @Override + protected Object findExportedSymbol(String globalName) { + return null; + } + + @Override + protected Object getLanguageGlobal() { + return null; + } + + @Override + protected boolean isObjectOfLanguage(Object object) { + return false; + } + } + + @TruffleLanguage.Registration(name = "myLangGood", mimeType = "text/x-my") + public static final class MyLangGood extends TruffleLanguage { + public MyLangGood(TruffleLanguage.Env env) { + super(env); + } + + @Override + protected Object eval(Source code) throws IOException { + return null; + } + + @Override + protected Object findExportedSymbol(String globalName) { + return null; + } + + @Override + protected Object getLanguageGlobal() { + return null; + } + + @Override + protected boolean isObjectOfLanguage(Object object) { + return false; + } + } +} diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/TruffleProcessorTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/TruffleProcessorTest.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/TruffleProcessorTest.java Tue May 26 17:38:44 2015 -0700 @@ -22,19 +22,27 @@ */ package com.oracle.truffle.api.dsl.test.processor; -import com.oracle.truffle.dsl.processor.verify.VerifyTruffleProcessor; -import java.util.Locale; -import java.util.ServiceLoader; -import javax.annotation.processing.Processor; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; import static org.junit.Assert.*; -import org.junit.Test; + +import java.util.*; + +import javax.annotation.processing.*; +import javax.tools.*; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.test.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.dsl.processor.verify.*; /** * Verify errors emitted by the processor. */ public class TruffleProcessorTest { + // + // AnnotationProcessor test using the NetBeans style + // + @Test public void childCannotBeFinal() throws Exception { // @formatter:off @@ -78,4 +86,16 @@ } fail(sb.toString()); } + + // + // and now the Truffle traditional way + // + + abstract class MyNode extends Node { + @ExpectError("@Child field cannot be final") @Child final MyNode first; + + MyNode(MyNode n) { + this.first = n; + } + } } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ExpectError.java --- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ExpectError.java Tue May 26 16:44:24 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.dsl; - -import java.lang.annotation.*; - -/** - * This annotation is internally known by the dsl processor and used to expect errors for testing - * purposes. This is not part of public API. - */ -@Retention(RetentionPolicy.RUNTIME) -public @interface ExpectError { - - String[] value(); - -} diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java Tue May 26 17:38:44 2015 -0700 @@ -24,16 +24,17 @@ import com.oracle.truffle.api.vm.TruffleVM; import java.util.Random; +import org.junit.Test; /** * A collection of tests that can certify language implementaiton to be complient with most recent * requirements of the Truffle infrastructure and tooling. Subclass, implement abstract methods and * include in your test suite. */ -public abstract class TruffleTCK { - private TruffleVM vm; +public class TruffleTCK { // abstract + private TruffleVM tckVM; - protected TruffleTCK() { + public TruffleTCK() { // protected } /** @@ -45,8 +46,11 @@ * for internal testing. * * @return initialized Truffle virtual machine + * @throws java.lang.Exception thrown when the VM preparation fails */ - protected abstract TruffleVM prepareVM() throws Exception; + protected TruffleVM prepareVM() throws Exception { // abstract + return null; + } /** * Name of function which will return value 42 as a number. The return value of the method @@ -55,7 +59,9 @@ * * @return name of globally exported symbol */ - protected abstract String fourtyTwo(); + protected String fourtyTwo() { // abstract + return null; + } /** * Name of function to add two integer values together. The symbol will be invoked with two @@ -64,20 +70,26 @@ * * @return name of globally exported symbol */ - protected abstract String plusInt(); + protected String plusInt() { // abstract + return null; + } private TruffleVM vm() throws Exception { - if (vm == null) { - vm = prepareVM(); + if (tckVM == null) { + tckVM = prepareVM(); } - return vm; + return tckVM; } // // The tests // + @Test public void testFortyTwo() throws Exception { + if (getClass() == TruffleTCK.class) { + return; + } TruffleVM.Symbol fourtyTwo = findGlobalSymbol(fourtyTwo()); Object res = fourtyTwo.invoke(null); @@ -89,7 +101,11 @@ assert 42 == n.intValue() : "The value is 42 = " + n.intValue(); } + @Test public void testPlusWithInts() throws Exception { + if (getClass() == TruffleTCK.class) { + return; + } Random r = new Random(); int a = r.nextInt(100); int b = r.nextInt(100); diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java Tue May 26 17:38:44 2015 -0700 @@ -35,10 +35,11 @@ @Before public void initInDifferentThread() throws InterruptedException { + final TruffleVM.Builder b = TruffleVM.newVM(); Thread t = new Thread("Initializer") { @Override public void run() { - tvm = TruffleVM.create(); + tvm = b.build(); } }; t.start(); diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Tue May 26 17:38:44 2015 -0700 @@ -29,10 +29,13 @@ import com.oracle.truffle.api.vm.TruffleVM; import com.oracle.truffle.api.vm.TruffleVM.Language; import java.io.IOException; +import java.io.Reader; +import java.io.Writer; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.lang.reflect.Constructor; /** * An entry point for everyone who wants to implement a Truffle based language. By providing @@ -42,7 +45,17 @@ * language support, multi tennat hosting, debugging, etc.) will be made available to them. */ public abstract class TruffleLanguage { - private Env env; + private final Env env; + + /** + * Constructor to be called by subclasses. + * + * @param env language environment that will be available via {@link #env()} method to + * subclasses. + */ + protected TruffleLanguage(Env env) { + this.env = env; + } /** * The annotation to use to register your language to the {@link TruffleVM Truffle} system. By @@ -72,11 +85,6 @@ String[] mimeType(); } - @SuppressWarnings("all") - void attachEnv(Env env) { - this.env = env; - } - protected final Env env() { if (this.env == null) { throw new NullPointerException("Accessing env before initialization is finished"); @@ -129,10 +137,20 @@ public static final class Env { private final TruffleVM vm; private final TruffleLanguage lang; + private final Reader in; + private final Writer err; + private final Writer out; - Env(TruffleVM vm, TruffleLanguage lang) { + Env(TruffleVM vm, Constructor langConstructor, Writer out, Writer err, Reader in) { this.vm = vm; - this.lang = lang; + this.in = in; + this.err = err; + this.out = out; + try { + this.lang = (TruffleLanguage) langConstructor.newInstance(this); + } catch (Exception ex) { + throw new IllegalStateException("Cannot construct language " + langConstructor.getDeclaringClass().getName(), ex); + } } /** @@ -147,17 +165,42 @@ public Object importSymbol(String globalName) { return API.importSymbol(vm, lang, globalName); } + + /** + * Input associated with this {@link TruffleVM}. + * + * @return reader, never null + */ + public Reader stdIn() { + return in; + } + + /** + * Standard output writer for this {@link TruffleVM}. + * + * @return writer, never null + */ + public Writer stdOut() { + return out; + } + + /** + * Standard error writer for this {@link TruffleVM}. + * + * @return writer, never null + */ + public Writer stdErr() { + return err; + } } private static final AccessAPI API = new AccessAPI(); private static final class AccessAPI extends Accessor { - @Override - protected Env attachEnv(TruffleVM vm, TruffleLanguage l) { - Env env = new Env(vm, l); - l.attachEnv(env); - return env; + protected TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz, Writer stdOut, Writer stdErr, Reader stdIn) { + Env env = new Env(vm, langClazz, stdOut, stdErr, stdIn); + return env.lang; } @Override diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java Tue May 26 17:38:44 2015 -0700 @@ -25,10 +25,12 @@ package com.oracle.truffle.api.impl; import com.oracle.truffle.api.TruffleLanguage; -import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.vm.TruffleVM; import com.oracle.truffle.api.source.Source; import java.io.IOException; +import java.lang.reflect.Constructor; +import java.io.Reader; +import java.io.Writer; import java.util.ServiceLoader; /** @@ -38,7 +40,7 @@ private static Accessor API; private static Accessor SPI; static { - TruffleLanguage lng = new TruffleLanguage() { + TruffleLanguage lng = new TruffleLanguage(null) { @Override protected Object eval(Source code) throws IOException { return null; @@ -76,8 +78,8 @@ } } - protected Env attachEnv(TruffleVM vm, TruffleLanguage l) { - return API.attachEnv(vm, l); + protected TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz, Writer stdOut, Writer stdErr, Reader stdIn) { + return API.attachEnv(vm, langClazz, stdOut, stdErr, stdIn); } protected Object eval(TruffleLanguage l, Source s) throws IOException { diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java Tue May 26 17:38:44 2015 -0700 @@ -32,7 +32,11 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.io.Reader; +import java.lang.reflect.Constructor; +import java.io.Writer; import java.net.URI; import java.net.URL; import java.net.URLConnection; @@ -52,10 +56,10 @@ import java.util.logging.Logger; /** - * Virtual machine for Truffle based languages. Use {@link #create()} to instantiate new isolated - * virtual machine ready for execution of various languages. All the languages in a single virtual - * machine see each other exported global symbols and can co-operate. Use {@link #create()} multiple - * times to create different, isolated virtual machines completely separated from each other. + * Virtual machine for Truffle based languages. Use {@link #newVM()} to create new isolated virtual + * machine ready for execution of various languages. All the languages in a single virtual machine + * see each other exported global symbols and can co-operate. Use {@link #newVM()} multiple times to + * create different, isolated virtual machines completely separated from each other. *

* Once instantiated use {@link #eval(java.net.URI)} with a reference to a file or URL or directly * pass code snippet into the virtual machine via {@link #eval(java.lang.String, java.lang.String)}. @@ -64,17 +68,41 @@ * initialized, it remains so, until the virtual machine isn't garbage collected. *

* The TruffleVM is single-threaded and tries to enforce that. It records the thread it - * has been {@link #create() created} by and checks that all subsequent calls are coming from the - * same thread. + * has been {@link Builder#build() created} by and checks that all subsequent calls are coming from + * the same thread. */ public final class TruffleVM { private static final Logger LOG = Logger.getLogger(TruffleVM.class.getName()); private static final SPIAccessor SPI = new SPIAccessor(); private final Thread initThread; private final Map langs; + private final Reader in; + private final Writer err; + private final Writer out; + /** + * Private & temporary only constructor. + */ private TruffleVM() { - initThread = Thread.currentThread(); + this.initThread = null; + this.in = null; + this.err = null; + this.out = null; + this.langs = null; + } + + /** + * Real constructor used from the builder. + * + * @param out stdout + * @param err stderr + * @param in stdin + */ + private TruffleVM(Writer out, Writer err, Reader in) { + this.out = out; + this.err = err; + this.in = in; + this.initThread = Thread.currentThread(); this.langs = new HashMap<>(); Enumeration en; try { @@ -110,14 +138,105 @@ } /** - * Creates new Truffle virtual machine. It searches for {@link Registration languages - * registered} in the system class loader and makes them available for later evaluation via + * Creation of new Truffle virtual machine. Use the {@link Builder} methods to configure your + * virtual machine and then create one using {@link Builder#build()}: + * + *

+     * {@link TruffleVM} vm = {@link TruffleVM}.{@link TruffleVM#newVM() newVM()}
+     *     .{@link Builder#stdOut(java.io.Writer) stdOut}({@link Writer yourWriter})
+     *     .{@link Builder#stdErr(java.io.Writer) stdErr}({@link Writer yourWriter})
+     *     .{@link Builder#stdIn(java.io.Reader) stdIn}({@link Reader yourReader})
+     *     .{@link Builder#build() build()};
+     * 
+ * + * It searches for {@link Registration languages registered} in the system class loader and + * makes them available for later evaluation via * {@link #eval(java.lang.String, java.lang.String)} methods. * * @return new, isolated virtual machine with pre-registered languages */ - public static TruffleVM create() { - return new TruffleVM(); + public static TruffleVM.Builder newVM() { + // making Builder non-static inner class is a + // nasty trick to avoid the Builder class to appear + // in Javadoc next to TruffleVM class + TruffleVM vm = new TruffleVM(); + return vm.new Builder(); + } + + /** + * Builder for a new {@link TruffleVM}. Call various configuration methods in a chain and at the + * end create new {@link TruffleVM virtual machine}: + * + *
+     * {@link TruffleVM} vm = {@link TruffleVM}.{@link TruffleVM#newVM() newVM()}
+     *     .{@link Builder#stdOut(java.io.Writer) stdOut}({@link Writer yourWriter})
+     *     .{@link Builder#stdErr(java.io.Writer) stdErr}({@link Writer yourWriter})
+     *     .{@link Builder#stdIn(java.io.Reader) stdIn}({@link Reader yourReader})
+     *     .{@link Builder#build() build()};
+     * 
+ */ + public final class Builder { + private Writer out; + private Writer err; + private Reader in; + + Builder() { + } + + /** + * Changes the defaut output for languages running in to be created + * {@link TruffleVM virtual machine}. The default is to use {@link System#out}. + * + * @param w the writer to use as output + * @return instance of this builder + */ + public Builder stdOut(Writer w) { + out = w; + return this; + } + + /** + * Changes the error output for languages running in to be created + * {@link TruffleVM virtual machine}. The default is to use {@link System#err}. + * + * @param w the writer to use as output + * @return instance of this builder + */ + public Builder stdErr(Writer w) { + err = w; + return this; + } + + /** + * Changes the defaut input for languages running in to be created + * {@link TruffleVM virtual machine}. The default is to use {@link System#out}. + * + * @param r the reader to use as input + * @return instance of this builder + */ + public Builder stdIn(Reader r) { + in = r; + return this; + } + + /** + * Creates the {@link TruffleVM Truffle virtual machine}. The configuration is taken from + * values passed into configuration methods in this class. + * + * @return new, isolated virtual machine with pre-registered languages + */ + public TruffleVM build() { + if (out == null) { + out = new OutputStreamWriter(System.out); + } + if (err == null) { + err = new OutputStreamWriter(System.err); + } + if (in == null) { + in = new InputStreamReader(System.in); + } + return new TruffleVM(out, err, in); + } } /** @@ -147,7 +266,13 @@ if (location.getScheme().equals("file")) { File file = new File(location); s = Source.fromFileName(file.getPath(), true); - mimeType = file.getName().endsWith(".c") ? "text/x-c" : Files.probeContentType(file.toPath()); + if (file.getName().endsWith(".c")) { + mimeType = "text/x-c"; + } else if (file.getName().endsWith(".sl")) { + mimeType = "application/x-sl"; + } else { + mimeType = Files.probeContentType(file.toPath()); + } } else { URL url = location.toURL(); s = Source.fromURL(url, location.toString()); @@ -327,9 +452,9 @@ if (impl == null) { String n = props.getProperty("className"); try { - TruffleLanguage lang = (TruffleLanguage) Class.forName(n, true, loader()).newInstance(); - SPI.attachEnv(TruffleVM.this, lang); - impl = lang; + Class langClazz = Class.forName(n, true, loader()); + Constructor constructor = langClazz.getConstructor(Env.class); + impl = SPI.attachEnv(TruffleVM.this, constructor, out, err, in); } catch (Exception ex) { throw new IllegalStateException("Cannot initialize " + getName() + " language with implementation " + n, ex); } @@ -361,8 +486,8 @@ } @Override - public Env attachEnv(TruffleVM vm, TruffleLanguage l) { - return super.attachEnv(vm, l); + public TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz, Writer stdOut, Writer stdErr, Reader stdIn) { + return super.attachEnv(vm, langClazz, stdOut, stdErr, stdIn); } @Override diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package.html Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,12 @@ + + + + Truffle Virtual Machine + + + + +
Central place to control Truffle Virtual Machine and + all languages hosted in it.
+ + diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ExpectError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ExpectError.java Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.dsl.processor; + +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.tools.Diagnostic.*; + +public class ExpectError { + + public static void assertNoErrorExpected(ProcessingEnvironment processingEnv, Element element) { + TypeElement eee = processingEnv.getElementUtils().getTypeElement(TruffleTypes.EXPECT_ERROR_CLASS_NAME); + if (eee != null) { + for (AnnotationMirror am : element.getAnnotationMirrors()) { + if (am.getAnnotationType().asElement().equals(eee)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Expected an error, but none found!", element); + } + } + } + } + + public static boolean isExpectedError(ProcessingEnvironment processingEnv, Element element, String message) { + TypeElement eee = processingEnv.getElementUtils().getTypeElement(TruffleTypes.EXPECT_ERROR_CLASS_NAME); + if (eee != null) { + for (AnnotationMirror am : element.getAnnotationMirrors()) { + if (am.getAnnotationType().asElement().equals(eee)) { + Map vals = am.getElementValues(); + if (vals.size() == 1) { + AnnotationValue av = vals.values().iterator().next(); + if (av.getValue() instanceof List) { + List arr = (List) av.getValue(); + for (Object o : arr) { + if (o instanceof AnnotationValue) { + AnnotationValue ov = (AnnotationValue) o; + if (message.equals(ov.getValue())) { + return true; + } + } + } + } + } + } + } + } + return false; + } + +} diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java Tue May 26 17:38:44 2015 -0700 @@ -22,22 +22,18 @@ */ package com.oracle.truffle.dsl.processor; +import java.io.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.tools.Diagnostic.Kind; +import javax.tools.*; + +import com.oracle.truffle.api.*; import com.oracle.truffle.api.TruffleLanguage.Registration; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Properties; -import java.util.Set; -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; -import javax.tools.Diagnostic.Kind; -import javax.tools.FileObject; -import javax.tools.StandardLocation; @SupportedAnnotationTypes("com.oracle.truffle.api.*") public final class LanguageRegistrationProcessor extends AbstractProcessor { @@ -72,12 +68,57 @@ Registration annotation = e.getAnnotation(Registration.class); if (annotation != null && e.getKind() == ElementKind.CLASS) { if (!e.getModifiers().contains(Modifier.PUBLIC)) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Registered language class must be public", e); + emitError("Registered language class must be public", e); + continue; + } + if (e.getEnclosingElement().getKind() != ElementKind.PACKAGE && !e.getModifiers().contains(Modifier.STATIC)) { + emitError("Registered language inner-class must be static", e); + continue; + } + TypeMirror truffleLang = processingEnv.getElementUtils().getTypeElement(TruffleLanguage.class.getName()).asType(); + if (!processingEnv.getTypeUtils().isAssignable(e.asType(), truffleLang)) { + emitError("Registered language class must subclass TruffleLanguage", e); + continue; } + boolean found = false; + for (Element mem : e.getEnclosedElements()) { + if (mem.getKind() != ElementKind.CONSTRUCTOR) { + continue; + } + ExecutableElement ee = (ExecutableElement) mem; + if (ee.getParameters().size() != 1) { + continue; + } + if (!ee.getModifiers().contains(Modifier.PUBLIC)) { + continue; + } + TypeMirror env = processingEnv.getElementUtils().getTypeElement(TruffleLanguage.Env.class.getCanonicalName()).asType(); + if (processingEnv.getTypeUtils().isSameType(ee.getParameters().get(0).asType(), env)) { + found = true; + break; + } + } + if (!found) { + emitError("Language must have a public constructor accepting TruffleLanguage.Env as parameter", e); + continue; + } + assertNoErrorExpected(e); createProviderFile((TypeElement) e, annotation); } } return true; } + + void assertNoErrorExpected(Element e) { + ExpectError.assertNoErrorExpected(processingEnv, e); + } + + void emitError(String msg, Element e) { + if (ExpectError.isExpectedError(processingEnv, e, msg)) { + return; + } + processingEnv.getMessager().printMessage(Kind.ERROR, msg, e); + } + } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Tue May 26 17:38:44 2015 -0700 @@ -44,6 +44,8 @@ */ public final class TruffleTypes { + public static final String EXPECT_ERROR_CLASS_NAME = "com.oracle.truffle.api.dsl.test.ExpectError"; + private final DeclaredType node; private final ArrayType nodeArray; private final TypeMirror unexpectedValueException; @@ -94,7 +96,7 @@ nodeFactory = getRequired(context, NodeFactory.class); nodeFactoryBase = getRequired(context, NodeFactoryBase.class); dslMetadata = getRequired(context, DSLMetadata.class); - expectError = (TypeElement) getRequired(context, ExpectError.class).asElement(); + expectError = getOptional(context, EXPECT_ERROR_CLASS_NAME); generateNodeFactory = getRequired(context, GenerateNodeFactory.class); } @@ -158,6 +160,10 @@ return (DeclaredType) type; } + private static TypeElement getOptional(ProcessorContext context, String name) { + return context.getEnvironment().getElementUtils().getTypeElement(name); + } + public TypeMirror getInvalidAssumption() { return invalidAssumption; } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java Tue May 26 17:38:44 2015 -0700 @@ -37,7 +37,7 @@ @DSLOptions public class TypeSystemParser extends AbstractParser { - public static final List> ANNOTATIONS = Arrays.asList(TypeSystem.class, ExpectError.class); + public static final List> ANNOTATIONS = Arrays.asList(TypeSystem.class); @Override public Class getAnnotationType() { diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/verify/VerifyTruffleProcessor.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/verify/VerifyTruffleProcessor.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/verify/VerifyTruffleProcessor.java Tue May 26 17:38:44 2015 -0700 @@ -35,6 +35,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.dsl.processor.*; @SupportedAnnotationTypes({"com.oracle.truffle.api.CompilerDirectives.TruffleBoundary", "com.oracle.truffle.api.nodes.Node.Child"}) public class VerifyTruffleProcessor extends AbstractProcessor { @@ -116,12 +117,25 @@ for (Element e : roundEnv.getElementsAnnotatedWith(Child.class)) { if (e.getModifiers().contains(Modifier.FINAL)) { - errorMessage(e, "@Child field cannot be final"); + emitError("@Child field cannot be final", e); + continue; } + assertNoErrorExpected(e); } return false; } + void assertNoErrorExpected(Element element) { + ExpectError.assertNoErrorExpected(processingEnv, element); + } + + void emitError(String message, Element element) { + if (ExpectError.isExpectedError(processingEnv, element, message)) { + return; + } + processingEnv.getMessager().printMessage(Kind.ERROR, message, element); + } + /** * Determines if a given exception is (most likely) caused by Bug 367599. diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.sl.test; + +import com.oracle.truffle.api.test.vm.TruffleTCK; +import com.oracle.truffle.api.vm.TruffleVM; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * This is the way to verify your language implementation is compatible. + * + */ +public class SLTckTest extends TruffleTCK { + @Test + public void testVerifyPresence() { + TruffleVM vm = TruffleVM.newVM().build(); + assertTrue("Our language is present", vm.getLanguages().containsKey("application/x-sl")); + } + + @Override + protected TruffleVM prepareVM() throws Exception { + TruffleVM vm = TruffleVM.newVM().build(); + vm.eval("application/x-sl", // your langage + "function fourtyTwo() {\n" + // your script + " return 42;\n" + // + "}\n" + // + "function plus(a, b) {\n" + // + " return a + b;\n" + // + "}\n" // + ); + return vm; + } + + @Override + protected String fourtyTwo() { + return "fourtyTwo"; + } + + @Override + protected String plusInt() { + return "plus"; + } +} diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Tue May 26 17:38:44 2015 -0700 @@ -37,11 +37,9 @@ import org.junit.runners.model.*; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.TruffleVM; import com.oracle.truffle.sl.SLMain; import com.oracle.truffle.sl.builtins.*; -import com.oracle.truffle.sl.factory.*; -import com.oracle.truffle.sl.runtime.*; import com.oracle.truffle.sl.test.SLTestRunner.TestCase; public final class SLTestRunner extends ParentRunner { @@ -167,22 +165,16 @@ ByteArrayOutputStream out = new ByteArrayOutputStream(); PrintWriter printer = new PrintWriter(out); try { - SLContext context = SLContextFactory.create(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats))), printer); - for (NodeFactory builtin : builtins) { - context.installBuiltin(builtin); - } - /* - * TruffleVM vm = TruffleVM.create(); String script = readAllLines(testCase.path); for - * (int i = 0; i < repeats; i++) { vm.eval("application/x-sl", script); } - */ - final Source source = Source.fromText(readAllLines(testCase.path), testCase.sourceName); - SLMain.run(context, source, null, repeats); + TruffleVM vm = TruffleVM.newVM().stdIn(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats)))).stdOut(printer).build(); + + String script = readAllLines(testCase.path); + SLMain.run(vm, testCase.path.toUri(), null, printer, repeats, builtins); printer.flush(); String actualOutput = new String(out.toByteArray()); - Assert.assertEquals(repeat(testCase.expectedOutput, repeats), actualOutput); + Assert.assertEquals(script, repeat(testCase.expectedOutput, repeats), actualOutput); } catch (Throwable ex) { - notifier.fireTestFailure(new Failure(testCase.name, ex)); + notifier.fireTestFailure(new Failure(testCase.name, new IllegalStateException("Cannot run " + testCase.sourceName, ex))); } finally { notifier.fireTestFinished(testCase.name); } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.output Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,1 @@ +Undefined function: foo diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.sl Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,3 @@ +function main() { + foo(); +} diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Tue May 26 17:38:44 2015 -0700 @@ -24,6 +24,8 @@ import java.io.*; import java.math.*; +import java.net.*; +import java.util.*; import java.util.Scanner; import com.oracle.truffle.api.*; @@ -32,6 +34,7 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.api.vm.*; +import com.oracle.truffle.api.vm.TruffleVM.Symbol; import com.oracle.truffle.sl.builtins.*; import com.oracle.truffle.sl.factory.*; import com.oracle.truffle.sl.nodes.*; @@ -132,10 +135,17 @@ */ @TruffleLanguage.Registration(name = "sl", mimeType = "application/x-sl") public class SLMain extends TruffleLanguage { + private static SLMain LAST; + private static List> builtins = Collections.emptyList(); private final SLContext context; - public SLMain() { - this.context = SLContextFactory.create(new BufferedReader(new InputStreamReader(System.in)), new PrintWriter(System.out)); + public SLMain(Env env) { + super(env); + context = SLContextFactory.create(new BufferedReader(env().stdIn()), new PrintWriter(env().stdOut(), true)); + LAST = this; + for (NodeFactory builtin : builtins) { + context.installBuiltin(builtin); + } } /* Demonstrate per-type tabulation of node execution counts */ @@ -149,7 +159,7 @@ * The main entry point. Use the mx command "mx sl" to run it with the correct class path setup. */ public static void main(String[] args) throws IOException { - TruffleVM vm = TruffleVM.create(); + TruffleVM vm = TruffleVM.newVM().build(); assert vm.getLanguages().containsKey("application/x-sl"); int repeats = 1; @@ -157,12 +167,17 @@ repeats = Integer.parseInt(args[1]); } + if (args.length == 0) { + vm.eval("application/x-sl", new InputStreamReader(System.in)); + } else { + vm.eval(new File(args[0]).toURI()); + } + Symbol main = vm.findGlobalSymbol("main"); + if (main == null) { + throw new SLException("No function main() defined in SL source file."); + } while (repeats-- > 0) { - if (args.length == 0) { - vm.eval("application/x-sl", new InputStreamReader(System.in)); - } else { - vm.eval(new File(args[0]).toURI()); - } + main.invoke(null); } } @@ -170,7 +185,9 @@ * Parse and run the specified SL source. Factored out in a separate method so that it can also * be used by the unit test harness. */ - public static long run(SLContext context, Source source, PrintWriter logOutput, int repeats) { + public static long run(TruffleVM context, URI source, PrintWriter logOutput, PrintWriter out, int repeats, List> currentBuiltins) throws IOException { + builtins = currentBuiltins; + if (logOutput != null) { logOutput.println("== running on " + Truffle.getRuntime().getName()); // logOutput.println("Source = " + source.getCode()); @@ -199,11 +216,14 @@ } /* Parse the SL source file. */ - Parser.parseSL(context, source); + Object result = context.eval(source); + if (result != null) { + out.println(result); + } /* Lookup our main entry point, which is per definition always named "main". */ - SLFunction main = context.getFunctionRegistry().lookup("main"); - if (main.getCallTarget() == null) { + Symbol main = context.findGlobalSymbol("main"); + if (main == null) { throw new SLException("No function main() defined in SL source file."); } @@ -214,19 +234,21 @@ /* Change to dump the AST to IGV over the network. */ boolean dumpASTToIGV = false; - printScript("before execution", context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV); + printScript("before execution", LAST.context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV); long totalRuntime = 0; try { for (int i = 0; i < repeats; i++) { long start = System.nanoTime(); /* Call the main entry point, without any arguments. */ try { - Object result = main.getCallTarget().call(); + result = main.invoke(null); if (result != SLNull.SINGLETON) { - context.getOutput().println(result); + out.println(result); } } catch (UnsupportedSpecializationException ex) { - context.getOutput().println(formatTypeError(ex)); + out.println(formatTypeError(ex)); + } catch (SLUndefinedFunctionException ex) { + out.println(String.format("Undefined function: %s", ex.getFunctionName())); } long end = System.nanoTime(); totalRuntime += end - start; @@ -237,7 +259,7 @@ } } finally { - printScript("after execution", context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV); + printScript("after execution", LAST.context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV); } if (nodeExecCounter != null) { nodeExecCounter.print(System.out); @@ -306,7 +328,7 @@ if (ex.getNode() != null && ex.getNode().getSourceSection() != null) { SourceSection ss = ex.getNode().getSourceSection(); if (ss != null && !(ss instanceof NullSourceSection)) { - result.append(" at ").append(ss.getSource().getName()).append(" line ").append(ss.getStartLine()).append(" col ").append(ss.getStartColumn()); + result.append(" at ").append(ss.getSource().getShortName()).append(" line ").append(ss.getStartLine()).append(" col ").append(ss.getStartColumn()); } } result.append(": operation"); @@ -355,17 +377,22 @@ @Override protected Object findExportedSymbol(String globalName) { + for (SLFunction f : context.getFunctionRegistry().getFunctions()) { + if (globalName.equals(f.getName())) { + return f; + } + } return null; } @Override protected Object getLanguageGlobal() { - return null; + return context; } @Override protected boolean isObjectOfLanguage(Object object) { - return false; + return object instanceof SLFunction; } } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java Tue May 26 17:38:44 2015 -0700 @@ -52,20 +52,22 @@ StringBuilder str = new StringBuilder(); Truffle.getRuntime().iterateFrames(frameInstance -> { - dumpFrame(str, frameInstance.getCallTarget(), frameInstance.getFrame(FrameAccess.READ_ONLY, true)); + CallTarget callTarget = frameInstance.getCallTarget(); + Frame frame = frameInstance.getFrame(FrameAccess.READ_ONLY, true); + RootNode rn = ((RootCallTarget) callTarget).getRootNode(); + if (rn.getClass().getName().contains("SLFunctionForeignAccess")) { + return 1; + } + if (str.length() > 0) { + str.append(System.getProperty("line.separator")); + } + str.append("Frame: ").append(rn.toString()); + FrameDescriptor frameDescriptor = frame.getFrameDescriptor(); + frameDescriptor.getSlots().stream().forEach((s) -> { + str.append(", ").append(s.getIdentifier()).append("=").append(frame.getValue(s)); + }); return null; }); return str.toString(); } - - private static void dumpFrame(StringBuilder str, CallTarget callTarget, Frame frame) { - if (str.length() > 0) { - str.append(System.getProperty("line.separator")); - } - str.append("Frame: ").append(((RootCallTarget) callTarget).getRootNode().toString()); - FrameDescriptor frameDescriptor = frame.getFrameDescriptor(); - for (FrameSlot s : frameDescriptor.getSlots()) { - str.append(", ").append(s.getIdentifier()).append("=").append(frame.getValue(s)); - } - } } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java Tue May 26 17:38:44 2015 -0700 @@ -34,6 +34,11 @@ public abstract Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments); + @Specialization(guards = "function.getCallTarget() == null") + protected Object doUndefinedFunction(SLFunction function, @SuppressWarnings("unused") Object[] arguments) { + throw new SLUndefinedFunctionException(function.getName()); + } + /** * Inline cached specialization of the dispatch. * diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUndefinedFunctionException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUndefinedFunctionException.java Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.sl.nodes.call; + +public class SLUndefinedFunctionException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private final String functionName; + + public SLUndefinedFunctionException(String functionName) { + this.functionName = functionName; + } + + public String getFunctionName() { + return functionName; + } + +} diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java Tue May 26 17:38:44 2015 -0700 @@ -52,7 +52,7 @@ return left instanceof Boolean && needsRightNode(((Boolean) left).booleanValue()); } - @Specialization(rewriteOn = RuntimeException.class) + @Specialization protected boolean doBoolean(boolean left, boolean hasRight, boolean right) { return left || right; } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Tue May 26 17:38:44 2015 -0700 @@ -30,7 +30,6 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.object.*; import com.oracle.truffle.api.source.*; -import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.builtins.*; import com.oracle.truffle.sl.nodes.*; import com.oracle.truffle.sl.nodes.local.*; @@ -158,11 +157,6 @@ */ public void executeMain(Source source) { Parser.parseSL(this, source); - SLFunction main = getFunctionRegistry().lookup("main"); - if (main.getCallTarget() == null) { - throw new SLException("No function main() defined in SL source file."); - } - main.getCallTarget().call(); } public DynamicObject createObject() { diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java Tue May 26 16:44:24 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java Tue May 26 17:38:44 2015 -0700 @@ -23,6 +23,7 @@ package com.oracle.truffle.sl.runtime; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.interop.*; import com.oracle.truffle.api.utilities.*; /** @@ -41,7 +42,7 @@ * per name exists, the {@link SLFunctionRegistry} creates an instance also when performing name * lookup. A function that has been looked up, i.e., used, but not defined, has no call target. */ -public final class SLFunction { +public final class SLFunction implements TruffleObject { /** The name of the function. */ private final String name; @@ -90,4 +91,14 @@ public String toString() { return name; } + + /** + * In case you want some of your objects to co-operate with other languages, you need to make + * them implement {@link TruffleObject} and provide additional {@link SLFunctionForeignAccess + * foreign access implementation}. + */ + @Override + public ForeignAccessFactory getForeignAccessFactory() { + return SLFunctionForeignAccess.INSTANCE; + } } diff -r 23bc51cd8654 -r fc376e0b80ba graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.sl.runtime; + +import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.ForeignAccessFactory; +import com.oracle.truffle.api.interop.InteropPredicate; +import com.oracle.truffle.api.interop.exception.UnsupportedMessageException; +import com.oracle.truffle.api.interop.messages.Message; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.interop.ForeignAccessArguments; +import com.oracle.truffle.interop.messages.Execute; +import com.oracle.truffle.interop.messages.Receiver; +import com.oracle.truffle.sl.nodes.call.SLDispatchNode; +import com.oracle.truffle.sl.nodes.call.SLDispatchNodeGen; +import java.math.BigInteger; + +/** + * Implementation of foreing access for {@link SLFunction}. + */ +final class SLFunctionForeignAccess implements ForeignAccessFactory { + public static final ForeignAccessFactory INSTANCE = new SLFunctionForeignAccess(); + + private SLFunctionForeignAccess() { + } + + @Override + public InteropPredicate getLanguageCheck() { + return (com.oracle.truffle.api.interop.TruffleObject o) -> o instanceof SLFunction; + } + + @Override + public CallTarget getAccess(Message tree) { + if (Execute.create(Receiver.create(), 0).matchStructure(tree)) { + return Truffle.getRuntime().createCallTarget(new SLForeignCallerRootNode()); + } else { + throw new UnsupportedMessageException(tree.toString() + " not supported"); + } + } + + private static class SLForeignCallerRootNode extends RootNode { + @Child private SLDispatchNode dispatch = SLDispatchNodeGen.create(); + + @Override + public Object execute(VirtualFrame frame) { + SLFunction function = (SLFunction) ForeignAccessArguments.getReceiver(frame.getArguments()); + // the calling convention of interop passes the receiver of a + // function call (the this object) + // as an implicit 1st argument; we need to ignore this argument for SL + Object[] arguments = ForeignAccessArguments.extractUserArguments(1, frame.getArguments()); + for (int i = 0; i < arguments.length; i++) { + if (arguments[i] instanceof Long) { + continue; + } + if (arguments[i] instanceof BigInteger) { + continue; + } + if (arguments[i] instanceof Number) { + arguments[i] = ((Number) arguments[i]).longValue(); + } + } + + return dispatch.executeDispatch(frame, function, arguments); + } + + } + +} diff -r 23bc51cd8654 -r fc376e0b80ba hotspot/.project --- a/hotspot/.project Tue May 26 16:44:24 2015 -0700 +++ b/hotspot/.project Tue May 26 17:38:44 2015 -0700 @@ -133,7 +133,7 @@ make 2 - WORKSPACE_LOC/make + PARENT-1-PROJECT_LOC/make solaris diff -r 23bc51cd8654 -r fc376e0b80ba mx/mx_graal.py --- a/mx/mx_graal.py Tue May 26 16:44:24 2015 -0700 +++ b/mx/mx_graal.py Tue May 26 17:38:44 2015 -0700 @@ -37,6 +37,7 @@ import itertools import json, textwrap import fnmatch +import mx_graal_makefile # This works because when mx loads this file, it makes sure __file__ gets an absolute path _graal_home = dirname(dirname(__file__)) @@ -1752,6 +1753,7 @@ parser = ArgumentParser(prog='mx gate') parser.add_argument('-j', '--omit-java-clean', action='store_false', dest='cleanJava', help='omit cleaning Java native code') parser.add_argument('-n', '--omit-native-clean', action='store_false', dest='cleanNative', help='omit cleaning and building native code') + parser.add_argument('-i', '--omit-ide-clean', action='store_false', dest='cleanIde', help='omit cleaning the ide project files') parser.add_argument('-g', '--only-build-graalvm', action='store_false', dest='buildNonGraal', help='only build the Graal VM') parser.add_argument('-t', '--task-filter', help='comma separated list of substrings to select subset of tasks to be run') parser.add_argument('--jacocout', help='specify the output directory for jacoco report') @@ -1784,10 +1786,11 @@ clean(cleanArgs) _clean() - with Task('IDEConfigCheck', tasks): + with Task('IDEConfigCheck', tasks) as t: if t: - mx.ideclean([]) - mx.ideinit([]) + if args.cleanIde: + mx.ideclean([]) + mx.ideinit([]) eclipse_exe = mx.get_env('ECLIPSE_EXE') if eclipse_exe is not None: @@ -2660,6 +2663,7 @@ 'sl' : [sl, '[SL args|@VM options]'], 'sldebug' : [sldebug, '[SL args|@VM options]'], 'jol' : [jol, ''], + 'makefile' : [mx_graal_makefile.build_makefile, 'build makefiles for JDK build'], } mx.add_argument('--jacoco', help='instruments com.oracle.* classes using JaCoCo', default='off', choices=['off', 'on', 'append']) diff -r 23bc51cd8654 -r fc376e0b80ba mx/mx_graal_makefile.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mx/mx_graal_makefile.py Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,183 @@ +import mx, os, sys +# +# ---------------------------------------------------------------------------------------------------- +# +# Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ---------------------------------------------------------------------------------------------------- +# + + +def build_makefile(args): + """Build a Makefile from the suitte.py to build graa.jar without python""" + if len(args) == 0 or args[0] == "-": + do_build_makefile(lambda l: sys.stdout.write(l + os.linesep)) + elif args[0] == "-o": + with open(args[1], "w") as f: + do_build_makefile(lambda l: f.write(l + os.linesep)) + +def relative_dep_path(d): + if isinstance(d, str): d = mx.dependency(d) + return os.path.basename(d.get_path(False)) + +def createMakeRule(p, bootClasspath): + def filterDeps(deps, t): + def typeFilter(project): # filters + if isinstance(project, str): + project = mx.dependency(project, True) + return isinstance(project, t) + return [d for d in deps if typeFilter(d)] + + + canonicalDeps = p.canonical_deps() + canonicalProjectDep = filterDeps(canonicalDeps, mx.Project) + canonicalProjectDepDirs = ['$(TARGET)/' +i for i in canonicalProjectDep] + canonicalLibDep = filterDeps(canonicalDeps, mx.Library) + canonicalLibDepJars = ["$(LIB)/" + relative_dep_path(d) for d in canonicalLibDep] + + allDep = p.all_deps([], True, False, includeAnnotationProcessors=True) + allProcessorDistNames = [x.definedAnnotationProcessorsDist.name for x in filterDeps(allDep, mx.Project) if x.definedAnnotationProcessors != None] + allProjectDep = filterDeps(allDep, mx.Project) + allProjectDepDir = ['$(TARGET)/' +i.name for i in allProjectDep] + allLibDep = filterDeps(allDep, mx.Library) + allLibDepJar = ["$(LIB)/" + relative_dep_path(d) for d in allLibDep] + + processor = p.annotation_processors_path() + if processor != None: processor = processor.replace(p.suite.dir, "$(TARGET)") + + cp = allLibDepJar +allProjectDepDir + props = { + 'name': p.name, + 'project_deps': ' '.join(canonicalProjectDepDirs + canonicalLibDepJars + allProcessorDistNames), + 'cp_deps': ('-cp ' + ':'.join(cp)) if len(cp) > 0 else '', + 'cp_boot': ('-bootclasspath ' + bootClasspath) if len(bootClasspath) > 0 else '', + 'processor': ('-processorpath ' + processor) if processor != None else '' + } + return """$(TARGET)/{name}: $(shell find graal/{name}/src/ -type f -name *.java) {project_deps} +\t$(eval TMP := $(shell mktemp -d)) +\ttest ! -d $(TARGET)/{name} || cp -Rp $(TARGET)/{name} $(TMP) +\t$(JAVAC) -d $(TMP) {cp_boot} {processor} {cp_deps} $(shell find graal/{name}/src/ -type f -name *.java) +\ttest ! -d graal/{name}/src/META-INF || (mkdir -p $(TARGET)/{name}/META-INF/ && cp -r graal/{name}/src/META-INF/ $(TARGET)/{name}/) +\tmkdir -p $(TARGET)/{name} +\tcp -r $(TMP)/* $(TARGET)/{name} +\ttouch $(TARGET)/{name} +\trm -r $(TMP) +""".format(**props) + +def createDistributionRule(dist): + depDirs = ' '.join(['$(TARGET)/' + i.name for i in dist.sorted_deps(False, True)]) + depDirsStar = ' '.join(['$(TARGET)/' + i.name + '/*' for i in dist.sorted_deps(False, True)]) + jarPath = os.path.relpath(dist.path, dist.suite.dir) + jarDir = os.path.dirname(jarPath) + props = { + 'dist_name': dist.name, + 'depDirs': depDirs, + 'depDirsStar': depDirsStar, + 'jar_path': jarPath, + 'jar_dir': jarDir, + 'providers_dir': '$(TMP)/META-INF/providers/ ', + 'services_dir': '$(TMP)/META-INF/services/' + } + return """{dist_name}: {depDirs} +\t$(eval TMP := $(shell mktemp -d)) +\tmkdir -p $(TARGET){jar_dir} +\ttouch $(TARGET)/{jar_path} +\tcp -r {depDirsStar} $(TMP) +\ttest -d {services_dir} || mkdir -p {services_dir} +\ttest ! -d {providers_dir} || (cd {providers_dir} && for i in $$(ls); do c=$$(cat $$i); echo $$i >> {services_dir}$$c; done) +\ttest ! -d {providers_dir} || rm -r {providers_dir} +\t$(JAR) cvf $(TARGET){jar_path} -C $(TMP) . +\trm -r $(TMP) +""".format(**props) + +def createDownloadRule(lib): + http_urls = [u for u in lib.urls if u.startswith("http")] + if len(http_urls) == 0: http_urls = [u for u in lib.urls if u.startswith("jar")] + if len(http_urls) == 0: raise BaseException("No http url specified for downloading library %s: available urls: %s" % (lib.name, lib.urls)) + url = http_urls[0] + tofile = '$(LIB)/' + relative_dep_path(lib) + if url.startswith("jar"): + props = { + 'url': url[url.find(":")+1:url.rfind("!")], + 'archive_file': url[url.rfind("!")+1:], + 'dest': tofile + } + dl = """\t$(eval TMP := $(shell mktemp -d)) +\tcd $(TMP) && $(WGET) -O dl.zip {url} && $(JAR) xf dl.zip +\tmv $(TMP)/{archive_file} {dest} +\trm -rf $(TMP)""".format(**props) + else: + dl = "\t$(WGET) -O {} {}".format(tofile, url) + return """{}:\n{}""".format(tofile, dl) + + +def create_suite_build(suite, out): + for p in suite.projects: + java = mx.java(p.javaCompliance) + bootClassPath = java.bootclasspath() + bootClassPath = bootClassPath.replace(java.jdk, "$(JDK)") + out(createMakeRule(p, bootClassPath)) + for l in suite.libs: + out(createDownloadRule(l)) + + distributionNames = [] + for d in suite.dists: + distributionNames.append(d.name) + out(createDistributionRule(d)) + out("{0}: {1}\n.PHONY: {1}".format(suite.name, " ".join(distributionNames))) + + +def do_build_makefile(out): + out("""VERBOSE= +TARGET=build/ +LIB=$(TARGET)/lib +JDK= + +WGET=wget +JAVAC=$(JDK)/bin/javac +JAR=$(JDK)/bin/jar + + +ifeq ($(JDK),) +$(error Variable JDK must be set to a JDK installation.) +endif +ifneq ($(VERBOSE),) +SHELL=sh -x +endif + +all: default + +$(TARGET): +\tmkdir -p $(TARGET) + +$(LIB): +\tmkdir -p $(LIB) +""") + suiteNames = [] + for s in mx.suites(): + suiteNames.append(s.name) + create_suite_build(s, out) + + out("""default: $(TARGET) $(LIB) {0} +.PHONY: {0} + """.format(" ".join(suiteNames))) + diff -r 23bc51cd8654 -r fc376e0b80ba mx/suite.py --- a/mx/suite.py Tue May 26 16:44:24 2015 -0700 +++ b/mx/suite.py Tue May 26 17:38:44 2015 -0700 @@ -119,36 +119,6 @@ "sha1" : "59b64c974662b5cf9dbd3cf9045d293853dd7a51", }, - "OKRA" : { - "path" : "lib/okra-1.10.jar", - "urls" : [ - "http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.10.jar", - "http://cr.openjdk.java.net/~tdeneau/okra-1.10.jar", - ], - "sha1" : "96eb3c0ec808ed944ba88d1eb9311058fe0f3d1e", - "sourcePath" : "lib/okra-1.10-src.jar", - "sourceUrls" : [ - "http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.10-src.jar", - "http://cr.openjdk.java.net/~tdeneau/okra-1.10-src.jar", - ], - "sourceSha1" : "75751bb148fcebaba78ff590f883a114b2b09176", - }, - - "OKRA_WITH_SIM" : { - "path" : "lib/okra-1.10-with-sim.jar", - "urls" : [ - "http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.10-with-sim.jar", - "http://cr.openjdk.java.net/~tdeneau/okra-1.10-with-sim.jar", - ], - "sha1" : "7b8db879f1dbcf571290add78d9af24e15a2a50d", - "sourcePath" : "lib/okra-1.10-with-sim-src.jar", - "sourceSha1" : "7eefd94f16a3e3fd3b8f470cf91e265c6f5e7767", - "sourceUrls" : [ - "http://lafo.ssw.uni-linz.ac.at/graal-external-deps/okra-1.10-with-sim-src.jar", - "http://cr.openjdk.java.net/~tdeneau/okra-1.10-with-sim-src.jar", - ], - }, - "JAVA_ALLOCATION_INSTRUMENTER" : { "path" : "lib/java-allocation-instrumenter.jar", "sourcePath" : "lib/java-allocation-instrumenter.jar", @@ -1129,6 +1099,7 @@ "sourceDirs" : ["src"], "dependencies" : [ "com.oracle.truffle.api.dsl", + "com.oracle.truffle.interop", "com.oracle.truffle.api.object", "com.oracle.truffle.tools", "FINDBUGS" @@ -1143,8 +1114,8 @@ "subDir" : "graal", "sourceDirs" : ["src"], "dependencies" : [ - "com.oracle.truffle.sl", - "JUNIT", + "com.oracle.truffle.api.test", + "com.oracle.truffle.sl" ], "checkstyle" : "com.oracle.graal.graph", "javaCompliance" : "1.8", diff -r 23bc51cd8654 -r fc376e0b80ba mxtool/CheckCopyright.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mxtool/CheckCopyright.java Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,918 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.io.*; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.*; +import java.util.regex.*; + + +/** + * A program to check the existence and correctness of the copyright notice on a given set of sources. + * Sources are defined to be those under management by Mercurial and various options are available + * to limit the set of sources scanned. + */ +public class CheckCopyright { + + static class YearInfo { + + final int firstYear; + final int lastYear; + + YearInfo(int firstYear, int lastYear) { + this.firstYear = firstYear; + this.lastYear = lastYear; + } + + @Override + public boolean equals(Object other) { + final YearInfo yearInfo = (YearInfo) other; + return yearInfo.firstYear == firstYear && yearInfo.lastYear == lastYear; + } + + @Override + public int hashCode() { + return firstYear ^ lastYear; + } + } + + static class Info extends YearInfo { + + final String fileName; + + Info(String fileName, int firstYear, int lastYear) { + super(firstYear, lastYear); + this.fileName = fileName; + } + + @Override + public String toString() { + return fileName + " " + firstYear + ", " + lastYear; + } + } + + private static abstract class CopyrightHandler { + enum CommentType{ + STAR, HASH + } + + private static Map copyrightMap; + private static String copyrightFiles = ".*/makefile|.*/Makefile|.*\\.sh|.*\\.bash|.*\\.mk|.*\\.java|.*\\.c|.*\\.h|.*\\.py|.*\\.g|.*\\.r"; + private static Pattern copyrightFilePattern; + + protected final String suffix; + private CopyrightHandler customHandler; + + CopyrightHandler(CommentType commentType) { + this.suffix = commentType.name().toLowerCase(); + initCopyrightMap(); + } + + void addCustomhandler(CopyrightHandler copyrightHandler) { + this.customHandler = copyrightHandler; + } + + /** + * Add @code extension to files handled by this {@code CopyrightKind} + */ + protected void updateMap(String extension) { + copyrightMap.put(extension, this); + } + + static void addCopyrightFilesPattern(String pattern) { + copyrightFiles += "|" + pattern; + } + + protected abstract void readCopyrights() throws IOException; + + protected abstract Matcher getMatcher(String fileName, String fileContent) throws IOException; + + protected abstract String getText(String fileName) throws IOException ; + + protected abstract boolean handlesFile(String fileName); + + /** + * Checks that the Oracle copyright year info was correct. + * @return {@code false} if the year info was incorrect and was not fixed otherwise return {@code true} + * @throws IOException + */ + protected abstract boolean checkYearInfo(String fileName, String fileContent, Matcher matcher, Info info) throws IOException; + + static String getCopyrightText(String fileName) throws IOException { + return getCopyrightHandler(fileName).getText(fileName); + } + + private static CopyrightHandler getCopyrightHandler(String fileName) { + initCopyrightMap(); + if (!copyrightFilePattern.matcher(fileName).matches()) { + return null; + } + CopyrightHandler ck = getDefaultHandler(fileName); + if (ck.customHandler != null && ck.customHandler.handlesFile(fileName)) { + return ck.customHandler; + } else { + return ck; + } + } + + private static void initCopyrightMap() { + if (copyrightMap == null) { + copyrightMap = new HashMap(); + copyrightFilePattern = Pattern.compile(copyrightFiles); + } + } + + static CopyrightHandler getDefaultHandler(String fileName) { + int index = fileName.lastIndexOf(File.separatorChar); + if (index > 0) { + fileName = fileName.substring(index + 1); + } + String ext = ""; + index = fileName.lastIndexOf('.'); + if (index > 0) { + ext = fileName.substring(index + 1); + } + if (fileName.equals("makefile")) { + ext = "mk"; + } + CopyrightHandler ck = copyrightMap.get(ext); + assert ck != null : fileName; + return ck; + } + + protected String readCopyright(InputStream is) throws IOException { + byte[] b = new byte[16384]; + int n = is.read(b); + is.close(); + return new String(b, 0, n); + } + + } + + private static class DefaultCopyrightHandler extends CopyrightHandler { + private static String ORACLE_COPYRIGHT = "oracle.copyright"; + private static String ORACLE_COPYRIGHT_REGEX = "oracle.copyright.regex"; + + private String copyrightRegex; + private String copyright; + Pattern copyrightPattern; + + DefaultCopyrightHandler(CopyrightHandler.CommentType commentType) throws IOException { + super(commentType); + if (commentType == CopyrightHandler.CommentType.STAR) { + updateMap("java"); + updateMap("c"); + updateMap("h"); + updateMap("g"); + } else { + updateMap("r"); + updateMap("R"); + updateMap("py"); + updateMap("sh"); + updateMap("mk"); + updateMap("bash"); + updateMap(""); + } + readCopyrights(); + } + + private String readCopyright(String name) throws IOException { + String copyRightDir = COPYRIGHT_DIR.getValue(); + String fileName = "copyrights/" + name + "." + suffix; + String copyrightPath; + if (copyRightDir != null) { + copyrightPath = new File(new File(copyRightDir), fileName).getAbsolutePath(); + } else { + URL url = CheckCopyright.class.getResource(fileName); + try { + copyrightPath = url.toURI().getPath(); + } catch (URISyntaxException ex) { + throw new IOException(ex); + } + } + InputStream is = new FileInputStream(copyrightPath); + return readCopyright(is); + } + + @Override + protected void readCopyrights() throws IOException { + copyright = readCopyright(ORACLE_COPYRIGHT); + copyrightRegex = readCopyright(ORACLE_COPYRIGHT_REGEX); + copyrightPattern = Pattern.compile(copyrightRegex, Pattern.DOTALL); + } + + @Override + protected Matcher getMatcher(String fileName, String fileContent) { + return copyrightPattern.matcher(fileContent); + } + + @Override + protected String getText(String fileName) { + return copyright; + } + + @Override + protected boolean handlesFile(String fileName) { + return true; + } + + /** + * Check the year info against the copyright header. + * N.B. In the case of multiple matching groups, only the last group is checked. + * I.e., only the last lines containing year info is checked/updated. + */ + @Override + protected boolean checkYearInfo(String fileName, String fileContent, Matcher matcher, Info info) throws IOException { + int yearInCopyright; + int yearInCopyrightIndex; + int groupCount = matcher.groupCount(); + String yearInCopyrightString = matcher.group(groupCount); + yearInCopyright = Integer.parseInt(yearInCopyrightString); + yearInCopyrightIndex = matcher.start(groupCount); + if (yearInCopyright != info.lastYear) { + System.out.println(fileName + " copyright last modified year " + yearInCopyright + ", hg last modified year " + info.lastYear); + if (FIX.getValue()) { + // Use currentYear as that is what it will be when it's checked in! + System.out.println("updating last modified year of " + fileName + " to " + info.lastYear); + // If the previous copyright only specified a single (initial) year, we convert it to the pair form + String newContent = fileContent.substring(0, yearInCopyrightIndex); + if (matcher.group(groupCount - 1) == null) { + // single year form + newContent += yearInCopyrightString + ", "; + } + newContent += info.lastYear + fileContent.substring(yearInCopyrightIndex + 4); + final FileOutputStream os = new FileOutputStream(fileName); + os.write(newContent.getBytes()); + os.close(); + return true; + } else { + return false; + } + } + return true; + } + + } + + private static class CustomCopyrightHandler extends CopyrightHandler { + private Map overrides = new HashMap(); + private CopyrightHandler defaultHandler; + + CustomCopyrightHandler(CopyrightHandler.CommentType commentType, CopyrightHandler defaultHandler) { + super(commentType); + this.defaultHandler = defaultHandler; + } + + void addFile(String fileName, String copyright) { + overrides.put(fileName, copyright); + } + + @Override + protected void readCopyrights() throws IOException { + } + + @Override + protected Matcher getMatcher(String fileName, String fileContent) throws IOException { + String copyright = overrides.get(fileName); + assert copyright != null : fileName; + try (InputStream fs = new FileInputStream(copyright + "." + suffix + ".regex")) { + return Pattern.compile(readCopyright(fs), Pattern.DOTALL).matcher(fileContent); + } + } + + @Override + protected String getText(String fileName) throws IOException { + String copyright = overrides.get(fileName); + assert copyright != null : fileName; + try (InputStream fs = new FileInputStream(copyright + "." + suffix)) { + return readCopyright(fs); + } + } + + @Override + protected boolean handlesFile(String fileName) { + return overrides.get(fileName) != null; + } + + @Override + protected boolean checkYearInfo(String fileName, String fileContent, Matcher matcher, Info info) throws IOException { + // This is a bit tacky + String copyright = overrides.get(fileName); + if (copyright.endsWith("no.copyright")) { + return true; + } + return defaultHandler.checkYearInfo(fileName, fileContent, matcher, info); + } + } + + private static void initCopyrightKinds() throws IOException { + CopyrightHandler starHandler = new DefaultCopyrightHandler(CopyrightHandler.CommentType.STAR); + CopyrightHandler hashHandler = new DefaultCopyrightHandler(CopyrightHandler.CommentType.HASH); + + String customCopyrightDir = CUSTOM_COPYRIGHT_DIR.getValue(); + if (customCopyrightDir != null) { + CustomCopyrightHandler customStarHandler = new CustomCopyrightHandler(CopyrightHandler.CommentType.STAR, starHandler); + CustomCopyrightHandler customHashHandler = new CustomCopyrightHandler(CopyrightHandler.CommentType.HASH, hashHandler); + starHandler.addCustomhandler(customStarHandler); + hashHandler.addCustomhandler(customHashHandler); + + File overrides = new File(new File(customCopyrightDir), "overrides"); + if (overrides.exists()) { + ArrayList lines = new ArrayList<>(); + boolean changed = false; + try (BufferedReader br = new BufferedReader(new FileReader( + overrides))) { + while (true) { + String line = br.readLine(); + if (line == null) { + break; + } + if (line.length() == 0 || line.startsWith("#")) { + lines.add(line); + continue; + } + String[] parts = line.split(","); + // filename,copyright-file + CopyrightHandler defaultHandler = CopyrightHandler.getDefaultHandler(parts[0]); + if (defaultHandler == null) { + System.err.println("no default copyright handler for: " + parts[0]); + System.exit(1); + } + if (!new File(parts[0]).exists()) { + System.err.printf("file %s in overrides file does not exist", parts[0]); + if (FIX.getValue()) { + System.err.print(" - removing"); + line = null; + changed = true; + } + System.err.println(); + } + if (line != null) { + lines.add(line); + } + CustomCopyrightHandler customhandler = (CustomCopyrightHandler) defaultHandler.customHandler; + customhandler.addFile(parts[0], new File(new File(customCopyrightDir), parts[1]).getAbsolutePath()); + } + } + if (changed) { + try (BufferedWriter bw = new BufferedWriter(new FileWriter( + overrides))) { + for (String line : lines) { + bw.write(line); + bw.write('\n'); + } + } + } + } + } + } + + private static int currentYear = Calendar.getInstance().get(Calendar.YEAR); + private static Options options = new Options(); + private static Option help = options.newBooleanOption("help", false, "Show help message and exit."); + private static Option COPYRIGHT_DIR = options.newStringOption("copyright-dir", null, "override default location of copyright files"); + private static Option> FILES_TO_CHECK = options.newStringListOption("files", null, "list of files to check"); + private static Option FILE_LIST = options.newStringOption("file-list", null, "file containing list of files to check"); + private static Option DIR_WALK = options.newBooleanOption("list-dir", false, "check all files in directory tree requiring a copyright (ls -R)"); + private static Option HG_ALL = options.newBooleanOption("hg-all", false, "check all hg managed files requiring a copyright (hg status --all)"); + private static Option HG_MODIFIED = options.newBooleanOption("hg-modified", false, "check all modified hg managed files requiring a copyright (hg status)"); + private static Option HG_OUTGOING = options.newBooleanOption("hg-outgoing", false, "check outgoing hg managed files requiring a copyright (hg outgoing)"); + private static Option HG_LOG = options.newStringOption("hg-last", "0", "check hg managed files requiring a copyright in last N changesets (hg log -l N)"); + private static Option> PROJECT = options.newStringListOption("projects", null, "filter files to specific projects"); + private static Option OUTGOING_REPO = options.newStringOption("hg-repo", null, "override outgoing repository"); + private static Option EXHAUSTIVE = options.newBooleanOption("hg-exhaustive", false, "check all hg managed files"); + private static Option FIX = options.newBooleanOption("fix", false, "fix all copyright errors"); + private static Option FILE_PATTERN = options.newStringOption("file-pattern", null, "append additional file patterns for copyright checks"); + private static Option REPORT_ERRORS = options.newBooleanOption("report-errors", false, "report non-fatal errors"); + private static Option HALT_ON_ERROR = options.newBooleanOption("halt-on-error", false, "continue after normally fatal error"); + private static Option HG_PATH = options.newStringOption("hg-path", "hg", "path to hg executable"); + private static Option VERBOSE = options.newBooleanOption("verbose", false, "verbose output"); + private static Option VERY_VERBOSE = options.newBooleanOption("very-verbose", false, "very verbose output"); + private static Option CUSTOM_COPYRIGHT_DIR = options.newStringOption("custom-copyright-dir", null, "file containing filenames with custom copyrights"); + + private static String CANNOT_FOLLOW_FILE = "abort: cannot follow"; + private static String hgPath; + private static boolean error; +// private static File workSpaceDirectory; + private static boolean verbose; + private static boolean veryVerbose; + + public static void main(String[] args) { + // parse the arguments + options.parseArguments(args); + if (help.getValue()) { + options.printHelp(); + return; + } + + verbose = VERBOSE.getValue(); + veryVerbose = VERY_VERBOSE.getValue(); + + hgPath = HG_PATH.getValue(); + + if (FILE_PATTERN.getValue() != null) { + CopyrightHandler.addCopyrightFilesPattern(FILE_PATTERN.getValue()); + } + + try { + initCopyrightKinds(); + List filesToCheck = null; + if (HG_ALL.getValue()) { + filesToCheck = getAllFiles(true); + } else if (HG_OUTGOING.getValue()) { + filesToCheck = getOutgoingFiles(); + } else if (HG_MODIFIED.getValue()) { + filesToCheck = getAllFiles(false); + } else if (Integer.parseInt(HG_LOG.getValue()) > 0) { + filesToCheck = getLastNFiles(Integer.parseInt(HG_LOG.getValue())); + } else if (FILE_LIST.getValue() != null) { + filesToCheck = readFileList(FILE_LIST.getValue()); + } else if (DIR_WALK.getValue()) { + filesToCheck = getDirWalkFiles(); + } else if (FILES_TO_CHECK.getValue() != null) { + filesToCheck = FILES_TO_CHECK.getValue(); + } else { + // no option set, default to HG_ALL + filesToCheck = getAllFiles(true); + } + if (filesToCheck != null && filesToCheck.size() > 0) { + processFiles(filesToCheck); + } else { + System.out.println("nothing to check"); + } + System.exit(error ? 1 : 0); + } catch (Exception ex) { + System.err.println("processing failed: " + ex); + ex.printStackTrace(); + } + } + + private static void processFiles(List fileNames) throws Exception { + final List projects = PROJECT.getValue(); + Calendar cal = Calendar.getInstance(); + for (String fileName : fileNames) { + if (projects == null || isInProjects(fileName, projects)) { + File file = new File(fileName); + if (file.isDirectory()) { + continue; + } + if (verbose) { + System.out.println("checking " + fileName); + } + try { + Info info = null; + if (DIR_WALK.getValue()) { + info = getFromLastModified(cal, fileName); + } else { + final List logInfo = hglog(fileName); + if (logInfo.size() == 0) { + // an added file, so go with last modified + info = getFromLastModified(cal, fileName); + } else { + info = getInfo(fileName, true, logInfo); + } + } + checkFile(fileName, info); + } catch (Exception e) { + System.err.format("COPYRIGHT CHECK WARNING: error while processing %s: %s%n", fileName, e.getMessage()); + } + } + } + } + + private static Info getFromLastModified(Calendar cal, String fileName) { + File file = new File(fileName); + cal.setTimeInMillis(file.lastModified()); + int year = cal.get(Calendar.YEAR); + return new Info(fileName, year, year); + } + + private static boolean isInProjects(String fileName, List projects) { + final int ix = fileName.indexOf(File.separatorChar); + if (ix < 0) { + return false; + } + final String fileProject = fileName.substring(0, ix); + for (String project : projects) { + if (fileProject.equals(project)) { + return true; + } + } + return false; + } + + private static List readFileList(String fileListName) throws IOException { + final List result = new ArrayList(); + BufferedReader b = null; + try { + b = new BufferedReader(new FileReader(fileListName)); + while (true) { + final String fileName = b.readLine(); + if (fileName == null) { + break; + } + if (fileName.length() == 0) { + continue; + } + result.add(fileName); + } + } finally { + if (b != null) { + b.close(); + } + } + return result; + } + + private static Info getInfo(String fileName, boolean lastOnly, List logInfo) { + // process sequence of changesets + int lastYear = 0; + int firstYear = 0; + int ix = 0; + + while (ix < logInfo.size()) { + Map tagMap = new HashMap<>(); + ix = getChangeset(logInfo, ix, tagMap); + String date = tagMap.get("date"); + assert date != null; + final int csYear = getYear(date); + if (lastYear == 0) { + lastYear = csYear; + firstYear = lastYear; + } else { + firstYear = csYear; + } + // if we only want the last modified year, quit now + if (lastOnly) { + break; + } + + } + + if (HG_MODIFIED.getValue()) { + // We are only looking at modified and, therefore, uncommitted files. + // This means that the lastYear value will be the current year once the + // file is committed, so that is what we want to check against. + lastYear = currentYear; + } + return new Info(fileName, firstYear, lastYear); + } + + /** + * Process all the changeset data, storing in {@outMap}. + * Return updated value of {@code ix}. + */ + private static int getChangeset(List logInfo, int ixx, Map outMap) { + int ix = ixx; + String s = logInfo.get(ix++); + while (s.length() > 0) { + int cx = s.indexOf(':'); + String tag = s.substring(0, cx); + String value = s.substring(cx + 1); + outMap.put(tag, value); + s = logInfo.get(ix++); + } + return ix; + } + + private static int getYear(String dateLine) { + final String[] parts = dateLine.split(" "); + assert parts[parts.length - 2].startsWith("20"); + return Integer.parseInt(parts[parts.length - 2]); + } + + private static void checkFile(String c, Info info) throws IOException { + String fileName = info.fileName; + File file = new File(fileName); + if (!file.exists()) { + System.err.println("COPYRIGHT CHECK WARNING: file " + file + " doesn't exist"); + return; + } + int fileLength = (int) file.length(); + byte[] fileContentBytes = new byte[fileLength]; + FileInputStream is = new FileInputStream(file); + is.read(fileContentBytes); + is.close(); + final String fileContent = new String(fileContentBytes); + CopyrightHandler copyrightHandler = CopyrightHandler.getCopyrightHandler(fileName); + if (file.getName().equals("Makefile")) { + System.console(); + } + if (copyrightHandler != null) { + Matcher copyrightMatcher = copyrightHandler.getMatcher(fileName, fileContent); + if (copyrightMatcher.matches()) { + error = error | !copyrightHandler.checkYearInfo(fileName, fileContent, copyrightMatcher, info); + } else { + // If copyright is missing, insert it, otherwise user has to manually fix existing copyright. + if (!fileContent.contains("Copyright")) { + System.out.print("file " + fileName + " has missing copyright"); + if (FIX.getValue()) { + final FileOutputStream os = new FileOutputStream(file); + os.write(CopyrightHandler.getCopyrightText(fileName) + .getBytes()); + os.write(fileContentBytes); + os.close(); + System.out.println("...fixed"); + } else { + System.out.println(); + error = true; + } + } else { + System.out.println("file " + fileName + " has malformed copyright" + (FIX.getValue() ? " not fixing" : "")); + error = true; + } + } + } else if (EXHAUSTIVE.getValue()) { + System.out.println("ERROR: file " + fileName + " has no copyright"); + error = true; + } + } + + + private static List hglog(String fileName) throws Exception { + final String[] cmd = new String[] {hgPath, "log", "-f", fileName}; + return exec(null, cmd, true); + } + + private static List getLastNFiles(int n) throws Exception { + final String[] cmd = new String[] {hgPath, "log", "-v", "-l", Integer.toString(n)}; + return getFilesFiles(exec(null, cmd, false)); + } + + private static List getAllFiles(boolean all) throws Exception { + final String[] cmd; + if (HG_MODIFIED.getValue()) { + cmd = new String[] {hgPath, "status"}; + } else { + cmd = new String[] {hgPath, "status", "--all"}; + } + List output = exec(null, cmd, true); + final List result = new ArrayList(output.size()); + for (String s : output) { + final char ch = s.charAt(0); + if (!(ch == 'R' || ch == 'I' || ch == '?' || ch == '!')) { + result.add(s.substring(2)); + } + } + return result; + } + + private static List getOutgoingFiles() throws Exception { + final String[] cmd; + if (OUTGOING_REPO.getValue() == null) { + cmd = new String[] {hgPath, "-v", "outgoing"}; + } else { + cmd = new String[] {hgPath, "-v", "outgoing", OUTGOING_REPO.getValue()}; + } + + final List output = exec(null, cmd, false); // no outgoing exits with result 1 + return getFilesFiles(output); + } + + private static List getFilesFiles(List output) { + // there may be multiple changesets so merge the "files:" + final Map outSet = new TreeMap(); + for (String s : output) { + if (s.startsWith("files:")) { + int ix = s.indexOf(' '); + while (ix < s.length() && s.charAt(ix) == ' ') { + ix++; + } + final String[] files = s.substring(ix).split(" "); + for (String file : files) { + outSet.put(file, file); + } + } + } + return new ArrayList(outSet.values()); + } + + private static List getDirWalkFiles() { + File cwd = new File(System.getProperty("user.dir")); + ArrayList result = new ArrayList(); + getDirWalkFiles(cwd, result); + // remove "user.dir" prefix to make files relative as per hg + String cwdPath = cwd.getAbsolutePath() + '/'; + for (int i = 0; i < result.size(); i++) { + String path = result.get(i); + result.set(i, path.replace(cwdPath, "")); + } + return result; + } + + private static void getDirWalkFiles(File dir, ArrayList list) { + File[] files = dir.listFiles(); + for (File file : files) { + if (ignoreFile(file.getName())) { + continue; + } + if (file.isDirectory()) { + getDirWalkFiles(file, list); + } else { + list.add(file.getAbsolutePath()); + } + } + } + + private static final String IGNORE_LIST = "\\.hg|.*\\.class|bin|src_gen"; + private static final Pattern ignorePattern = Pattern.compile(IGNORE_LIST); + + private static boolean ignoreFile(String name) { + return ignorePattern.matcher(name).matches(); + } + + private static List exec(File workingDir, String[] command, boolean failOnError) throws IOException, InterruptedException { + List result = new ArrayList(); + if (veryVerbose) { + System.out.println("Executing process in directory: " + workingDir); + for (String c : command) { + System.out.println(" " + c); + } + } + final Process process = Runtime.getRuntime().exec(command, null, workingDir); + try { + result = readOutput(process.getInputStream()); + final int exitValue = process.waitFor(); + if (exitValue != 0) { + final List errorResult = readOutput(process.getErrorStream()); + if (REPORT_ERRORS.getValue()) { + System.err.print("execution of command: "); + for (String c : command) { + System.err.print(c); + System.err.print(' '); + } + System.err.println("failed with result " + exitValue); + for (String e : errorResult) { + System.err.println(e); + } + } + if (failOnError && HALT_ON_ERROR.getValue()) { + if (!cannotFollowNonExistentFile(errorResult)) { + throw new Error("terminating"); + } + } + } + } finally { + process.destroy(); + } + return result; + } + + private static boolean cannotFollowNonExistentFile(List errorResult) { + return errorResult.size() == 1 && errorResult.get(0).startsWith(CANNOT_FOLLOW_FILE); + } + + private static List readOutput(InputStream is) throws IOException { + final List result = new ArrayList(); + BufferedReader bs = null; + try { + bs = new BufferedReader(new InputStreamReader(is)); + while (true) { + final String line = bs.readLine(); + if (line == null) { + break; + } + result.add(line); + } + } finally { + if (bs != null) { + bs.close(); + } + } + return result; + } + + private static class Options { + private static Map> optionMap = new TreeMap<>(); + + private Option newBooleanOption(String name, boolean defaultValue, String help) { + Option option = new Option(name, help, defaultValue, false, false); + optionMap.put(key(name), option); + return option; + } + + private Option newStringOption(String name, String defaultValue, String help) { + Option option = new Option(name, help, defaultValue); + optionMap.put(key(name), option); + return option; + } + + private Option> newStringListOption(String name, List defaultValue, String help) { + Option> option = new Option>(name, help, defaultValue, true, true); + optionMap.put(key(name), option); + return option; + } + + private static String key(String name) { + return "--" + name; + } + + void parseArguments(String[] args) { + for (int i = 0; i < args.length; i++) { + final String arg = args[i]; + if (arg.startsWith("--")) { + Option option = optionMap.get(arg); + if (option == null || (option.consumesNext() && i == args.length - 1)) { + System.out.println("usage:"); + printHelp(); + System.exit(1); + } + if (option.consumesNext()) { + i++; + option.setValue(args[i]); + } else { + option.setValue(true); + } + } + } + } + + void printHelp() { + int maxKeyLen = 0; + for (Map.Entry> entrySet : optionMap.entrySet()) { + int l = entrySet.getKey().length(); + if (l > maxKeyLen) { + maxKeyLen = l; + } + } + for (Map.Entry> entrySet : optionMap.entrySet()) { + String key = entrySet.getKey(); + System.out.printf(" %s", key); + for (int i = 0; i < maxKeyLen - key.length(); i++) { + System.out.print(' '); + } + System.out.printf(" %s%n", entrySet.getValue().help); + } + } +} + + private static class Option { + private final String name; + private final String help; + private final boolean consumesNext; + private final boolean isList; + private T value; + + Option(String name, String help, T defaultValue, boolean consumesNext, boolean isList) { + this.name = name; + this.help = help; + this.value = defaultValue; + this.consumesNext = consumesNext; + this.isList = isList; + + } + + Option(String name, String help, T defaultValue) { + this(name, help, defaultValue, true, false); + } + + T getValue() { + return value; + } + + boolean consumesNext() { + return consumesNext; + } + + @SuppressWarnings("unchecked") + void setValue(boolean value) { + this.value = (T) new Boolean(value); + } + + @SuppressWarnings("unchecked") + void setValue(String value) { + if (isList) { + String[] parts = value.split(","); + this.value = (T) Arrays.asList(parts); + } else { + this.value = (T) value; + } + } + + @SuppressWarnings("unused") + String getName() { + return name; + } + } + +} diff -r 23bc51cd8654 -r fc376e0b80ba mxtool/copyrights/oracle.copyright.hash --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mxtool/copyrights/oracle.copyright.hash Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,22 @@ +# +# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# diff -r 23bc51cd8654 -r fc376e0b80ba mxtool/copyrights/oracle.copyright.regex.hash --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mxtool/copyrights/oracle.copyright.regex.hash Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,1 @@ +(?:#!.*\n#\n#\ -*\n)?#\n# Copyright \(c\) (?:(20[0-9][0-9]), )?(20[0-9][0-9]), Oracle and/or its affiliates. All rights reserved.\n# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n#\n# This code is free software; you can redistribute it and/or modify it\n# under the terms of the GNU General Public License version 2 only, as\n# published by the Free Software Foundation.\n#\n# This code is distributed in the hope that it will be useful, but WITHOUT\n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n# version 2 for more details \(a copy is included in the LICENSE file that\n# accompanied this code\).\n#\n# You should have received a copy of the GNU General Public License version\n# 2 along with this work; if not, write to the Free Software Foundation,\n# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n#\n# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n# or visit www.oracle.com if you need additional information or have any\n# questions.\n#\n.* diff -r 23bc51cd8654 -r fc376e0b80ba mxtool/copyrights/oracle.copyright.regex.star --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mxtool/copyrights/oracle.copyright.regex.star Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,1 @@ +/\*\n \* Copyright \(c\) (?:(20[0-9][0-9]), )?(20[0-9][0-9]), Oracle and/or its affiliates. All rights reserved.\n \* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n \*\n \* This code is free software; you can redistribute it and/or modify it\n \* under the terms of the GNU General Public License version 2 only, as\n \* published by the Free Software Foundation.\n \*\n \* This code is distributed in the hope that it will be useful, but WITHOUT\n \* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n \* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n \* version 2 for more details \(a copy is included in the LICENSE file that\n \* accompanied this code\).\n \*\n \* You should have received a copy of the GNU General Public License version\n \* 2 along with this work; if not, write to the Free Software Foundation,\n \* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n \*\n \* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n \* or visit www.oracle.com if you need additional information or have any\n \* questions.\n \*/\n.* diff -r 23bc51cd8654 -r fc376e0b80ba mxtool/copyrights/oracle.copyright.star --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mxtool/copyrights/oracle.copyright.star Tue May 26 17:38:44 2015 -0700 @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ diff -r 23bc51cd8654 -r fc376e0b80ba mxtool/mx.py --- a/mxtool/mx.py Tue May 26 16:44:24 2015 -0700 +++ b/mxtool/mx.py Tue May 26 17:38:44 2015 -0700 @@ -2318,15 +2318,8 @@ def _init_classpaths(self): if not self._classpaths_initialized: - myDir = dirname(__file__) - outDir = join(dirname(__file__), '.jdk' + str(self.version)) - if not exists(outDir): - os.makedirs(outDir) - javaSource = join(myDir, 'ClasspathDump.java') - javaClass = join(outDir, 'ClasspathDump.class') - if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource): - subprocess.check_call([self.javac, '-d', _cygpathU2W(outDir), _cygpathU2W(javaSource)], stderr=subprocess.PIPE, stdout=subprocess.PIPE) - self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', _cygpathU2W(outDir), 'ClasspathDump'], stderr=subprocess.PIPE).split('|')] + _, binDir = _compile_mx_class('ClasspathDump', jdk=self) + self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', _cygpathU2W(binDir), 'ClasspathDump'], stderr=subprocess.PIPE).split('|')] if self.javaCompliance <= JavaCompliance('1.8'): # All 3 system properties accessed by ClasspathDump are expected to exist if not self._bootclasspath or not self._extdirs or not self._endorseddirs: @@ -2537,15 +2530,12 @@ assert not path.endswith(os.sep) - myDir = dirname(__file__) - javaSource = join(myDir, 'URLConnectionDownload.java') - javaClass = join(myDir, 'URLConnectionDownload.class') - if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource): - subprocess.check_call([java().javac, '-d', _cygpathU2W(myDir), _cygpathU2W(javaSource)]) + _, binDir = _compile_mx_class('URLConnectionDownload') + verbose = [] if sys.stderr.isatty(): verbose.append("-v") - if run([java().java, '-cp', _cygpathU2W(myDir), 'URLConnectionDownload', _cygpathU2W(path)] + verbose + urls, nonZeroIsFatal=False) == 0: + if run([java().java, '-cp', _cygpathU2W(binDir), 'URLConnectionDownload', _cygpathU2W(path)] + verbose + urls, nonZeroIsFatal=False) == 0: return abort('Could not download to ' + path + ' from any of the following URLs:\n\n ' + @@ -5442,6 +5432,65 @@ _show_section('projects', s.projects) _show_section('distributions', s.dists) +def _compile_mx_class(javaClassName, classpath=None, jdk=None): + myDir = dirname(__file__) + binDir = join(myDir, 'bin' if not jdk else '.jdk' + str(jdk.version)) + javaSource = join(myDir, javaClassName + '.java') + javaClass = join(binDir, javaClassName + '.class') + if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource): + if not exists(binDir): + os.mkdir(binDir) + javac = jdk.javac if jdk else java().javac + cmd = [javac, '-d', _cygpathU2W(binDir)] + if classpath: + cmd += ['-cp', _separatedCygpathU2W(binDir + os.pathsep + classpath)] + cmd += [_cygpathU2W(javaSource)] + try: + subprocess.check_call(cmd) + except subprocess.CalledProcessError: + abort('failed to compile:' + javaSource) + + return (myDir, binDir) + +def checkcopyrights(args): + '''run copyright check on the sources''' + class CP(ArgumentParser): + def format_help(self): + return ArgumentParser.format_help(self) + self._get_program_help() + + def _get_program_help(self): + help_output = subprocess.check_output([java().java, '-cp', _cygpathU2W(binDir), 'CheckCopyright', '--help']) + return '\nother argumemnts preceded with --\n' + help_output + + myDir, binDir = _compile_mx_class('CheckCopyright') + + parser = CP(prog='mx checkcopyrights') + + parser.add_argument('--primary', action='store_true', help='limit checks to primary suite') + parser.add_argument('remainder', nargs=REMAINDER, metavar='...') + args = parser.parse_args(args) + remove_doubledash(args.remainder) + + + # ensure compiled form of code is up to date + + result = 0 + # copyright checking is suite specific as each suite may have different overrides + for s in suites(True): + if args.primary and not s.primary: + continue + custom_copyrights = _cygpathU2W(join(s.mxDir, 'copyrights')) + custom_args = [] + if exists(custom_copyrights): + custom_args = ['--custom-copyright-dir', custom_copyrights] + rc = run([java().java, '-cp', _cygpathU2W(binDir), 'CheckCopyright', '--copyright-dir', _cygpathU2W(myDir)] + custom_args + args.remainder, cwd=s.dir, nonZeroIsFatal=False) + result = result if rc == 0 else rc + return result + +def remove_doubledash(args): + if '--' in args: + args.remove('--') + def ask_yes_no(question, default=None): """""" assert not default or default == 'y' or default == 'n' @@ -5485,6 +5534,7 @@ 'build': [build, '[options]'], 'checkstyle': [checkstyle, ''], 'canonicalizeprojects': [canonicalizeprojects, ''], + 'checkcopyrights': [checkcopyrights, '[options]'], 'clean': [clean, ''], 'eclipseinit': [eclipseinit, ''], 'eclipseformat': [eclipseformat, ''], diff -r 23bc51cd8654 -r fc376e0b80ba src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Tue May 26 16:44:24 2015 -0700 +++ b/src/share/vm/graal/graalRuntime.cpp Tue May 26 17:38:44 2015 -0700 @@ -725,12 +725,11 @@ GraalRuntime::initialize_natives(env, c2vmClass); JVM_END -// private static boolean HotSpotOptions.parseVMOptions() -JVM_ENTRY(jboolean, JVM_ParseGraalOptions(JNIEnv *env, jclass c)) +// private static void HotSpotOptions.parseVMOptions() +JVM_ENTRY(void, JVM_ParseGraalOptions(JNIEnv *env, jclass c)) HandleMark hm; KlassHandle hotSpotOptionsClass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c))); - bool result = GraalRuntime::parse_arguments(hotSpotOptionsClass, CHECK_false); - return result; + GraalRuntime::parse_arguments(hotSpotOptionsClass, CHECK); JVM_END @@ -803,19 +802,18 @@ return JNI_OK; } -bool GraalRuntime::parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS) { +void GraalRuntime::parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS) { ResourceMark rm(THREAD); // Process option overrides from graal.options first - parse_graal_options_file(hotSpotOptionsClass, CHECK_false); + parse_graal_options_file(hotSpotOptionsClass, CHECK); // Now process options on the command line int numOptions = Arguments::num_graal_args(); for (int i = 0; i < numOptions; i++) { char* arg = Arguments::graal_args_array()[i]; - parse_argument(hotSpotOptionsClass, arg, CHECK_false); + parse_argument(hotSpotOptionsClass, arg, CHECK); } - return CITime || CITimeEach; } void GraalRuntime::check_required_value(const char* name, size_t name_len, const char* value, TRAPS) { diff -r 23bc51cd8654 -r fc376e0b80ba src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Tue May 26 16:44:24 2015 -0700 +++ b/src/share/vm/graal/graalRuntime.hpp Tue May 26 17:38:44 2015 -0700 @@ -231,10 +231,10 @@ static jint check_arguments(TRAPS); /** - * Parses the Graal specific VM options that were presented by the launcher and sets + * Parses the JVMCI specific VM options that were presented by the launcher and sets * the relevants Java fields. */ - static bool parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS); + static void parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS); static BasicType kindToBasicType(jchar ch);