# HG changeset patch # User Tom Rodriguez # Date 1391036539 28800 # Node ID d7ed39d0a6d9ee35bca8a9b40d82776447f904b2 # Parent d006a6332db88ed8fcfcef132ae2d5a810508404# Parent 460e453d6fecc62c92217dae900a7e3fd8e48679 Merge diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java --- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java Wed Jan 29 15:02:19 2014 -0800 @@ -397,13 +397,17 @@ } // Checkstyle: stop method name check - public final void bra(String tgt, int pred) { + /* + * Emit conditional branch to target 'tgt' guarded by predicate register 'pred' whose state is + * tested to be 'predCheck'. + */ + public final void bra(String tgt, int pred, boolean predCheck) { assert pred >= 0; if (tgt.equals("?")) { Thread.dumpStack(); } - emitString("@%p" + pred + " " + "bra" + " " + tgt + ";"); + emitString("@" + (predCheck ? "%p" : "!%p") + pred + " " + "bra" + " " + tgt + ";"); } public final void bra(String src) { diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlPTXTest.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlPTXTest.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlPTXTest.java Wed Jan 29 15:02:19 2014 -0800 @@ -26,18 +26,26 @@ public class ControlPTXTest extends PTXTest { - @Ignore("[CUDA] *** Error (status=702): Synchronize kernel") @Test - public void testControl() { + public void testControl1() { test("testLoop", 42); test("testSwitchDefault1I", 3); test("testSwitch1I", 2); test("testIfElse1I", 222); test("testIfElse2I", 19, 64); + } - test("testIntegerTestBranch2I", 0xff00, 0x00ff); + @Test + public void testControl2() { compileKernel("testStatic"); compileKernel("testCall"); + } + + @Ignore("[CUDA] Check for malformed PTX kernel or incorrect PTX compilation options") + @Test + public void testControl3() { + // test("testIntegerTestBranch2I", 0xff00, 0x00ff); + compileKernel("testIntegerTestBranch2I"); compileKernel("testLookupSwitch1I"); } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/SynchronizedMethodDeoptimizationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/SynchronizedMethodDeoptimizationTest.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/SynchronizedMethodDeoptimizationTest.java Wed Jan 29 15:02:19 2014 -0800 @@ -22,52 +22,29 @@ */ package com.oracle.graal.compiler.test.deopt; -import java.lang.reflect.*; - import org.junit.*; -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.*; +import com.oracle.graal.compiler.test.ea.EATestBase.TestClassObject; /** * In the following tests, we try to deoptimize out of synchronized methods. */ public class SynchronizedMethodDeoptimizationTest extends GraalCompilerTest { - public static final int N = 15000; + public static final TestClassObject testObject = null; public static synchronized Object testMethodSynchronized(Object o) { if (o == null) { - return null; + // this branch will always deoptimize + return testObject.x; } return o; } @Test public void test1() { - Method method = getMethod("testMethodSynchronized"); - String testString = "test"; - for (int i = 0; i < N; ++i) { - Assert.assertEquals(testString, testMethodSynchronized(testString)); - } - final StructuredGraph graph = parseProfiled(method); - final ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method); - InstalledCode compiledMethod = getCode(javaMethod, graph); - try { - Object result = compiledMethod.executeVarargs(testString); - Assert.assertEquals(testString, result); - } catch (InvalidInstalledCodeException t) { - Assert.fail("method invalidated"); - } - - try { - Object result = compiledMethod.executeVarargs(new Object[]{null}); - Assert.assertEquals(null, result); - Assert.assertFalse(compiledMethod.isValid()); - } catch (InvalidInstalledCodeException t) { - Assert.fail("method invalidated"); - } + test("testMethodSynchronized", "test"); + test("testMethodSynchronized", (Object) null); } } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java Wed Jan 29 15:02:19 2014 -0800 @@ -107,7 +107,7 @@ public static int getIndex(DynamicCounterNode counter) { if (!enabled) { - throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled"); + throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled: " + counter.getGroup() + ", " + counter.getName()); } String name = counter.getName(); String group = counter.getGroup(); @@ -332,12 +332,15 @@ if (index >= config.graalCountersSize) { throw new GraalInternalError("too many counters, reduce number of counters or increase GRAAL_COUNTERS_SIZE (current value: " + config.graalCountersSize + ")"); } - ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, config.graalCountersThreadOffset + Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph); - ReadNode read = graph.add(new ReadNode(thread, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false)); + ConstantLocationNode arrayLocation = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, config.graalCountersThreadOffset, graph); + ReadNode readArray = graph.add(new ReadNode(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE, false)); + ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph); + ReadNode read = graph.add(new ReadNode(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false)); IntegerAddNode add = graph.unique(new IntegerAddNode(Kind.Long, read, counter.getIncrement())); - WriteNode write = graph.add(new WriteNode(thread, add, location, BarrierType.NONE, false)); + WriteNode write = graph.add(new WriteNode(readArray, add, location, BarrierType.NONE, false)); graph.addBeforeFixed(counter, thread); + graph.addBeforeFixed(counter, readArray); graph.addBeforeFixed(counter, read); graph.addBeforeFixed(counter, write); } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Wed Jan 29 15:02:19 2014 -0800 @@ -282,7 +282,7 @@ write.setStateAfter(store.stateAfter()); graph.replaceFixedWithFixed(store, write); } else if (n instanceof LoadHubNode) { - if (graph.getGuardsStage().ordinal() == StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) { + if (graph.getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) { LoadHubNode loadHub = (LoadHubNode) n; assert loadHub.kind() == wordKind; ValueNode object = loadHub.object(); @@ -443,11 +443,11 @@ newObjectSnippets.lower((DynamicNewArrayNode) n, registers, tool); } } else if (n instanceof MonitorEnterNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { monitorSnippets.lower((MonitorEnterNode) n, registers, tool); } } else if (n instanceof MonitorExitNode) { - if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { monitorSnippets.lower((MonitorExitNode) n, tool); } } else if (n instanceof G1PreWriteBarrier) { diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Wed Jan 29 15:02:19 2014 -0800 @@ -78,10 +78,7 @@ ProxyNode proxy = (ProxyNode) usage; proxy.replaceAndDelete(proxy.value()); } - FixedNode next = osr.next(); - osr.setNext(null); - ((FixedWithNextNode) osr.predecessor()).setNext(next); - GraphUtil.killWithUnusedFloatingInputs(osr); + GraphUtil.removeFixedWithUnusedInputs(osr); Debug.dump(graph, "OnStackReplacement loop peeling result"); } while (true); diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Wed Jan 29 15:02:19 2014 -0800 @@ -230,7 +230,7 @@ Arguments args; StructuredGraph graph = instanceOf.graph(); - if (hintInfo.hintHitProbability >= hintHitProbabilityThresholdForDeoptimizingSnippet()) { + if (hintInfo.hintHitProbability >= hintHitProbabilityThresholdForDeoptimizingSnippet() && hintInfo.exact == null) { Hints hints = createHints(hintInfo, providers.getMetaAccess(), false, graph); args = new Arguments(instanceofWithProfile, graph.getGuardsStage(), tool.getLoweringStage()); args.add("object", object); @@ -256,7 +256,7 @@ } args.add("trueValue", replacer.trueValue); args.add("falseValue", replacer.falseValue); - if (hintInfo.hintHitProbability >= hintHitProbabilityThresholdForDeoptimizingSnippet()) { + if (hintInfo.hintHitProbability >= hintHitProbabilityThresholdForDeoptimizingSnippet() && hintInfo.exact == null) { args.addConst("nullSeen", hintInfo.profile.getNullSeen() != TriState.FALSE); } return args; diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Wed Jan 29 15:02:19 2014 -0800 @@ -34,7 +34,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.graph.iterators.*; @@ -425,7 +424,6 @@ public void lower(MonitorEnterNode monitorenterNode, HotSpotRegistersProvider registers, LoweringTool tool) { StructuredGraph graph = monitorenterNode.graph(); checkBalancedMonitors(graph, tool); - FrameState stateAfter = monitorenterNode.stateAfter(); Arguments args; if (useFastLocking) { @@ -435,24 +433,15 @@ } args.add("object", monitorenterNode.object()); args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth()); - boolean tracingEnabledForMethod = stateAfter != null && (isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); args.addConst("threadRegister", registers.getThreadRegister()); args.addConst("stackPointerRegister", registers.getStackPointerRegister()); - args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || tracingEnabledForMethod); - - Map nodes = template(args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args); + args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(graph.method())); - for (Node n : nodes.values()) { - if (n instanceof BeginLockScopeNode) { - BeginLockScopeNode begin = (BeginLockScopeNode) n; - begin.setStateAfter(stateAfter); - } - } + template(args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args); } public void lower(MonitorExitNode monitorexitNode, LoweringTool tool) { StructuredGraph graph = monitorexitNode.graph(); - FrameState stateAfter = monitorexitNode.stateAfter(); Arguments args; if (useFastLocking) { @@ -462,16 +451,9 @@ } args.add("object", monitorexitNode.object()); args.addConst("lockDepth", monitorexitNode.getMonitorId().getLockDepth()); - args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); - - Map nodes = template(args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args); + args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(graph.method())); - for (Node n : nodes.values()) { - if (n instanceof EndLockScopeNode) { - EndLockScopeNode end = (EndLockScopeNode) n; - end.setStateAfter(stateAfter); - } - } + template(args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args); } static boolean isTracingEnabledForType(ValueNode object) { diff -r d006a6332db8 -r d7ed39d0a6d9 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 Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Jan 29 15:02:19 2014 -0800 @@ -1067,15 +1067,6 @@ } } - private ConstantNode genTypeOrDeopt(Representation representation, JavaType type, boolean initialized) { - if (initialized) { - return appendConstant(((ResolvedJavaType) type).getEncoding(representation)); - } else { - handleUnresolvedExceptionType(representation, type); - return null; - } - } - private void appendOptimizedStoreField(StoreFieldNode store) { append(store); } @@ -1711,14 +1702,17 @@ ResolvedJavaType resolvedCatchType = (ResolvedJavaType) catchType; for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) { if (skippedType.isAssignableFrom(resolvedCatchType)) { - append(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); + Block nextBlock = block.successors.size() == 1 ? unwindBlock(block.deoptBci) : block.successors.get(1); + ValueNode exception = frameState.stackAt(0); + FixedNode trueSuccessor = currentGraph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); + FixedNode nextDispatch = createTarget(nextBlock, frameState); + append(new IfNode(currentGraph.unique(new InstanceOfNode((ResolvedJavaType) catchType, exception, null)), trueSuccessor, nextDispatch, 0)); return; } } } - ConstantNode typeInstruction = genTypeOrDeopt(Representation.ObjectHub, catchType, initialized); - if (typeInstruction != null) { + if (initialized) { Block nextBlock = block.successors.size() == 1 ? unwindBlock(block.deoptBci) : block.successors.get(1); ValueNode exception = frameState.stackAt(0); CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) catchType, exception, null, false)); @@ -1730,6 +1724,8 @@ FixedNode nextDispatch = createTarget(nextBlock, frameState); checkCast.setNext(catchSuccessor); append(new IfNode(currentGraph.unique(new InstanceOfNode((ResolvedJavaType) catchType, exception, null)), checkCast, nextDispatch, 0.5)); + } else { + handleUnresolvedExceptionType(Representation.ObjectHub, catchType); } } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Wed Jan 29 15:02:19 2014 -0800 @@ -86,9 +86,9 @@ @Override public void emitCode(CompilationResultBuilder crb, PTXMacroAssembler masm) { if (crb.isSuccessorEdge(trueDestination)) { - masm.bra(masm.nameOf(falseDestination.label()), predRegNum); + masm.bra(masm.nameOf(falseDestination.label()), predRegNum, false); } else { - masm.bra(masm.nameOf(trueDestination.label())); + masm.bra(masm.nameOf(trueDestination.label()), predRegNum, true); if (!crb.isSuccessorEdge(falseDestination)) { masm.jmp(falseDestination.label()); } @@ -238,7 +238,7 @@ default: throw new GraalInternalError("switch only supported for int, long and object"); } - masm.bra(masm.nameOf(target), predRegNum); + masm.bra(masm.nameOf(target), predRegNum, true); } }; strategy.run(closure); @@ -281,7 +281,7 @@ // Jump to default target if index is not within the jump table if (defaultTarget != null) { - masm.bra(masm.nameOf(defaultTarget.label()), predRegNum); + masm.bra(masm.nameOf(defaultTarget.label()), predRegNum, true); } // address of jump table diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed Jan 29 15:02:19 2014 -0800 @@ -51,7 +51,7 @@ tool.deleteBranch(next); } - DeoptimizeNode deopt = graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, getReason())); + DeoptimizeNode deopt = graph().add(new DeoptimizeNode(getAction(), getReason())); deopt.setDeoptimizationState(getDeoptimizationState()); setNext(deopt); } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java Wed Jan 29 15:02:19 2014 -0800 @@ -31,6 +31,7 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; public class LoopBeginNode extends MergeNode implements IterableNodeType, LIRLowerable { @@ -184,7 +185,11 @@ public void removeExits() { for (LoopExitNode loopexit : loopExits().snapshot()) { loopexit.removeProxies(); + FrameState stateAfter = loopexit.stateAfter(); graph().replaceFixedWithFixed(loopexit, graph().add(new BeginNode())); + if (stateAfter != null && stateAfter.isAlive() && stateAfter.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(stateAfter); + } } } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Wed Jan 29 15:02:19 2014 -0800 @@ -33,11 +33,34 @@ * The Java bytecode specification allows non-balanced locking. Graal does not handle such cases and * throws a {@link BailoutException} instead during graph building. */ -public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint { +public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint, DeoptimizingNode { + @Input private FrameState deoptState; @Input private ValueNode object; @Input private MonitorIdNode monitorId; + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public FrameState getDeoptimizationState() { + return deoptState; + } + + @Override + public void setDeoptimizationState(FrameState f) { + updateUsages(deoptState, f); + deoptState = f; + } + + @Override + public FrameState getState() { + assert deoptState == null || stateAfter() == null; + return deoptState == null ? stateAfter() : deoptState; + } + public ValueNode object() { return object; } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Wed Jan 29 15:02:19 2014 -0800 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.java; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; @@ -30,7 +31,7 @@ /** * The {@code MonitorEnterNode} represents the acquisition of a monitor. */ -public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, MonitorEnter, MemoryCheckpoint.Single { +public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorEnter, MemoryCheckpoint.Single { /** * Creates a new MonitorEnterNode. diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Wed Jan 29 15:02:19 2014 -0800 @@ -58,7 +58,7 @@ @Override public void simplify(SimplifierTool tool) { - if (escapedReturnValue != null && stateAfter().bci != FrameState.AFTER_BCI) { + if (escapedReturnValue != null && stateAfter() != null && stateAfter().bci != FrameState.AFTER_BCI) { ValueNode returnValue = escapedReturnValue; setEscapedReturnValue(null); tool.removeIfUnused(returnValue); diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Wed Jan 29 15:02:19 2014 -0800 @@ -137,6 +137,13 @@ } } + public static void removeFixedWithUnusedInputs(FixedWithNextNode fixed) { + FixedNode next = fixed.next(); + fixed.setNext(null); + fixed.replaceAtPredecessor(next); + killWithUnusedFloatingInputs(fixed); + } + public static void checkRedundantPhi(PhiNode phiNode) { if (phiNode.isDeleted() || phiNode.valueCount() == 1) { return; diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Wed Jan 29 15:02:19 2014 -0800 @@ -626,7 +626,7 @@ if (type != ObjectStamp.typeOrNull(receiver)) { ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod()); if (method != null) { - if ((method.getModifiers() & Modifier.FINAL) != 0 || (type.getModifiers() & Modifier.FINAL) != 0) { + if (Modifier.isFinal(method.getModifiers()) || Modifier.isFinal(type.getModifiers())) { callTarget.setInvokeKind(InvokeKind.Special); callTarget.setTargetMethod(method); } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LockEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LockEliminationPhase.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LockEliminationPhase.java Wed Jan 29 15:02:19 2014 -0800 @@ -36,19 +36,8 @@ if (next instanceof MonitorEnterNode) { MonitorEnterNode monitorEnterNode = (MonitorEnterNode) next; if (monitorEnterNode.object() == node.object()) { - FixedNode monitorEnterSuccessor = monitorEnterNode.next(); - monitorEnterNode.setNext(null); - ((FixedWithNextNode) node.predecessor()).setNext(monitorEnterSuccessor); - FrameState stateAfterFirst = node.stateAfter(); - FrameState stateAfterSecond = monitorEnterNode.stateAfter(); - node.safeDelete(); - monitorEnterNode.safeDelete(); - if (stateAfterFirst.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(stateAfterFirst); - } - if (stateAfterSecond.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(stateAfterSecond); - } + GraphUtil.removeFixedWithUnusedInputs(monitorEnterNode); + GraphUtil.removeFixedWithUnusedInputs(node); } } } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Wed Jan 29 15:02:19 2014 -0800 @@ -569,11 +569,7 @@ LoopTransformations.fullUnroll(loop, phaseContext, new CanonicalizerPhase(true)); new CanonicalizerPhase(true).applyIncremental(snippetCopy, phaseContext, mark); } - FixedNode explodeLoopNext = explodeLoop.next(); - explodeLoop.clearSuccessors(); - explodeLoop.replaceAtPredecessor(explodeLoopNext); - explodeLoop.replaceAtUsages(null); - GraphUtil.killCFG(explodeLoop); + GraphUtil.removeFixedWithUnusedInputs(explodeLoop); exploded = true; } } while (exploded); diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ControlFlowExceptionPartialEvaluationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/ControlFlowExceptionPartialEvaluationTest.java Wed Jan 29 15:02:19 2014 -0800 @@ -0,0 +1,102 @@ +/* + * 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.graal.truffle.test; + +import org.junit.*; + +import com.oracle.graal.truffle.test.nodes.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +@Ignore("Currently ignored due to problems with code coverage tools.") +public class ControlFlowExceptionPartialEvaluationTest extends PartialEvaluationTest { + + public static Object constant42() { + return 42; + } + + @Test + public void catchControlFlowException() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new CatchControlFlowExceptionTestNode(new ThrowControlFlowExceptionTestNode()); + assertPartialEvalEquals("constant42", new RootTestNode(fd, "catchControlFlowException", result)); + } + + @Test + public void catchSlowPathAndControlFlowException() { + FrameDescriptor fd = new FrameDescriptor(); + AbstractTestNode result = new CatchSlowPathAndControlFlowExceptionTestNode(new ThrowControlFlowExceptionTestNode()); + assertPartialEvalEquals("constant42", new RootTestNode(fd, "catchSlowPathAndControlFlowException", result)); + } + + public static class ThrowControlFlowExceptionTestNode extends AbstractTestNode { + + @Override + public int execute(VirtualFrame frame) { + throw new ControlFlowException(); + } + } + + public static class CatchControlFlowExceptionTestNode extends AbstractTestNode { + + @Child private AbstractTestNode child; + + public CatchControlFlowExceptionTestNode(AbstractTestNode child) { + this.child = adoptChild(child); + } + + @Override + public int execute(VirtualFrame frame) { + try { + return child.execute(frame); + } catch (ControlFlowException e) { + return 42; + } + } + } + + public static class CatchSlowPathAndControlFlowExceptionTestNode extends AbstractTestNode { + + @Child private AbstractTestNode child; + + public CatchSlowPathAndControlFlowExceptionTestNode(AbstractTestNode child) { + this.child = adoptChild(child); + } + + @Override + public int execute(VirtualFrame frame) { + try { + return executeChild(frame); + } catch (SlowPathException spe) { + return -1; + } catch (ControlFlowException e) { + return 42; + } + } + + @SuppressWarnings("unused") + private int executeChild(VirtualFrame frame) throws SlowPathException { + return child.execute(frame); + } + } +} diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Wed Jan 29 15:02:19 2014 -0800 @@ -27,7 +27,6 @@ import org.junit.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; @@ -39,9 +38,7 @@ import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.phases.util.*; import com.oracle.graal.printer.*; -import com.oracle.graal.runtime.*; import com.oracle.graal.truffle.*; import com.oracle.graal.virtual.phases.ea.*; import com.oracle.truffle.api.*; @@ -50,15 +47,12 @@ public class PartialEvaluationTest extends GraalCompilerTest { private static final long UNROLL_LIMIT = 100; - private final PartialEvaluator partialEvaluator; + private final TruffleCompilerImpl truffleCompiler; public PartialEvaluationTest() { // Make sure Truffle runtime is initialized. Assert.assertTrue(Truffle.getRuntime() instanceof GraalTruffleRuntime); - Replacements truffleReplacements = ((GraalTruffleRuntime) Truffle.getRuntime()).getReplacements(); - Providers providers = getProviders().copyWith(truffleReplacements); - TruffleCache truffleCache = new TruffleCache(providers, GraphBuilderConfiguration.getDefault(), TruffleCompilerImpl.Optimizations); - this.partialEvaluator = new PartialEvaluator(Graal.getRequiredCapability(RuntimeProvider.class), providers, truffleCache); + this.truffleCompiler = new TruffleCompilerImpl(); DebugEnvironment.initialize(System.out); } @@ -70,7 +64,7 @@ protected InstalledCode assertPartialEvalEquals(String methodName, RootNode root, Arguments arguments) { Assumptions assumptions = new Assumptions(true); StructuredGraph actual = partialEval(root, arguments, assumptions, true); - InstalledCode result = new TruffleCompilerImpl().compileMethodHelper(actual, GraphBuilderConfiguration.getDefault(), assumptions, root.toString(), getSpeculationLog()); + InstalledCode result = truffleCompiler.compileMethodHelper(actual, assumptions, root.toString(), getSpeculationLog()); StructuredGraph expected = parseForComparison(methodName); removeFrameStates(actual); Assert.assertEquals(getCanonicalGraphString(expected, true), getCanonicalGraphString(actual, true)); @@ -102,7 +96,7 @@ try (Scope s = Debug.scope("TruffleCompilation", new TruffleDebugJavaMethod(compilable))) { - StructuredGraph resultGraph = partialEvaluator.createGraph(compilable, assumptions); + StructuredGraph resultGraph = truffleCompiler.getPartialEvaluator().createGraph(compilable, assumptions); CanonicalizerPhase canonicalizer = new CanonicalizerPhase(canonicalizeReads); PhaseContext context = new PhaseContext(getProviders(), assumptions); diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Wed Jan 29 15:02:19 2014 -0800 @@ -56,7 +56,6 @@ super(rootNode); this.compiler = compiler; this.compilationProfile = new CompilationProfile(compilationThreshold, invokeCounter, rootNode.toString()); - this.getRootNode().setCallTarget(this); if (TruffleUseTimeForCompilationDecision.getValue()) { compilationPolicy = new TimedCompilationPolicy(); @@ -261,8 +260,8 @@ } int notInlinedCallSiteCount = TruffleInliningImpl.getInlinableCallSites(callTarget).size(); - int nodeCount = NodeUtil.countNodes(callTarget.getRootNode()); - int inlinedCallSiteCount = NodeUtil.countNodes(callTarget.getRootNode(), InlinedCallSite.class); + int nodeCount = NodeUtil.countNodes(callTarget.getRootNode(), null, true); + int inlinedCallSiteCount = countInlinedNodes(callTarget.getRootNode()); String comment = callTarget.installedCode == null ? " int" : ""; comment += callTarget.compilationEnabled ? "" : " fail"; OUT.printf("%-50s | %10d | %15d | %15d | %10d | %3d%s\n", callTarget.getRootNode(), callTarget.callCount, inlinedCallSiteCount, notInlinedCallSiteCount, nodeCount, @@ -277,6 +276,18 @@ OUT.printf("%-50s | %10d | %15d | %15d | %10d | %3d\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNotInlinedCallSiteCount, totalNodeCount, totalInvalidationCount); } + private static int countInlinedNodes(Node rootNode) { + List callers = NodeUtil.findAllNodeInstances(rootNode, CallNode.class); + int count = 0; + for (CallNode callNode : callers) { + if (callNode.isInlined()) { + count++; + count += countInlinedNodes(callNode.getInlinedRoot()); + } + } + return count; + } + private static void registerCallTarget(OptimizedCallTarget callTarget) { callTargets.put(callTarget, 0); } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Wed Jan 29 15:02:19 2014 -0800 @@ -68,16 +68,16 @@ private final Providers providers; private final ResolvedJavaMethod executeHelperMethod; private final CanonicalizerPhase canonicalizer; - private final ResolvedJavaType[] skippedExceptionTypes; + private final GraphBuilderConfiguration config; private Set constantReceivers; private final GraphCache cache; private final TruffleCache truffleCache; - public PartialEvaluator(RuntimeProvider runtime, Providers providers, TruffleCache truffleCache) { + public PartialEvaluator(RuntimeProvider runtime, Providers providers, TruffleCache truffleCache, GraphBuilderConfiguration config) { this.providers = providers; CustomCanonicalizer customCanonicalizer = new PartialEvaluatorCanonicalizer(providers.getMetaAccess(), providers.getConstantReflection()); this.canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue(), customCanonicalizer); - this.skippedExceptionTypes = TruffleCompilerImpl.getSkippedExceptionTypes(providers.getMetaAccess()); + this.config = config; this.cache = runtime.getGraphCache(); this.truffleCache = truffleCache; try { @@ -98,9 +98,6 @@ constantReceivers = new HashSet<>(); } - final GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(); - config.setSkippedExceptionTypes(skippedExceptionTypes); - final StructuredGraph graph = new StructuredGraph(executeHelperMethod); try (Scope s = Debug.scope("createGraph", graph)) { diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Wed Jan 29 15:02:19 2014 -0800 @@ -36,7 +36,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.CompilerThreadFactory.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; @@ -65,15 +64,16 @@ private final Suites suites; private final PartialEvaluator partialEvaluator; private final Backend backend; - private final ResolvedJavaType[] skippedExceptionTypes; + private final GraphBuilderConfiguration config; private final RuntimeProvider runtime; private final TruffleCache truffleCache; private final ThreadPoolExecutor compileQueue; - private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{SlowPathException.class, UnexpectedResultException.class, ArithmeticException.class}; + private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class}; public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability, OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints); + private static final OptimisticOptimizations OptimizationsGraal = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability); public TruffleCompilerImpl() { this.runtime = Graal.getRequiredCapability(RuntimeProvider.class); @@ -81,10 +81,9 @@ Replacements truffleReplacements = ((GraalTruffleRuntime) Truffle.getRuntime()).getReplacements(); this.providers = backend.getProviders().copyWith(truffleReplacements); this.suites = backend.getSuites().getDefaultSuites(); - this.skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); // Create compilation queue. - CompilerThreadFactory factory = new CompilerThreadFactory("TruffleCompilerThread", new DebugConfigAccess() { + CompilerThreadFactory factory = new CompilerThreadFactory("TruffleCompilerThread", new CompilerThreadFactory.DebugConfigAccess() { public GraalDebugConfig getDebugConfig() { if (Debug.isEnabled()) { GraalDebugConfig debugConfig = DebugEnvironment.initialize(TTY.out().out()); @@ -97,18 +96,21 @@ }); compileQueue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), factory); - final GraphBuilderConfiguration config = GraphBuilderConfiguration.getEagerDefault(); - config.setSkippedExceptionTypes(skippedExceptionTypes); - this.truffleCache = new TruffleCache(providers, config, TruffleCompilerImpl.Optimizations); + ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); + GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault(); + eagerConfig.setSkippedExceptionTypes(skippedExceptionTypes); + this.truffleCache = new TruffleCache(providers, eagerConfig, TruffleCompilerImpl.Optimizations); - this.partialEvaluator = new PartialEvaluator(runtime, providers, truffleCache); + this.config = GraphBuilderConfiguration.getDefault(); + this.config.setSkippedExceptionTypes(skippedExceptionTypes); + this.partialEvaluator = new PartialEvaluator(runtime, providers, truffleCache, config); if (Debug.isEnabled()) { DebugEnvironment.initialize(System.out); } } - static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) { + private static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) { ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length]; for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) { skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]); @@ -135,8 +137,6 @@ private InstalledCode compileMethodImpl(final OptimizedCallTarget compilable) { final StructuredGraph graph; - final GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(); - config.setSkippedExceptionTypes(skippedExceptionTypes); GraphCache graphCache = runtime.getGraphCache(); if (graphCache != null) { graphCache.removeStaleGraphs(); @@ -156,7 +156,7 @@ } long timePartialEvaluationFinished = System.nanoTime(); int nodeCountPartialEval = graph.getNodeCount(); - InstalledCode compiledMethod = compileMethodHelper(graph, config, assumptions, compilable.toString(), compilable.getSpeculationLog()); + InstalledCode compiledMethod = compileMethodHelper(graph, assumptions, compilable.toString(), compilable.getSpeculationLog()); long timeCompilationFinished = System.nanoTime(); int nodeCountLowered = graph.getNodeCount(); @@ -168,7 +168,7 @@ } if (TraceTruffleCompilation.getValue()) { - int nodeCountTruffle = NodeUtil.countNodes(compilable.getRootNode()); + int nodeCountTruffle = NodeUtil.countNodes(compilable.getRootNode(), null, true); byte[] code = compiledMethod.getCode(); OUT.printf("[truffle] optimized %-50s %x |Nodes %7d |Time %5.0f(%4.0f+%-4.0f)ms |Nodes %5d/%5d |CodeSize %d\n", compilable.getRootNode(), compilable.hashCode(), nodeCountTruffle, (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, @@ -186,29 +186,34 @@ private class InlineTreeVisitor implements NodeVisitor { public boolean visit(Node node) { - if (node instanceof InlinedCallSite) { - InlinedCallSite inlinedCallSite = (InlinedCallSite) node; - int indent = this.indent(node); - for (int i = 0; i < indent; ++i) { - OUT.print(" "); + if (node instanceof CallNode) { + CallNode callNode = (CallNode) node; + if (callNode.isInlined()) { + int indent = this.indent(node); + for (int i = 0; i < indent; ++i) { + OUT.print(" "); + } + OUT.println(callNode.getCallTarget()); + callNode.getInlinedRoot().accept(this); } - OUT.println(inlinedCallSite.getCallTarget()); } return true; } private int indent(Node n) { if (n instanceof RootNode) { + CallNode inlinedParent = ((RootNode) n).getParentInlinedCall(); + if (inlinedParent != null) { + return indent(inlinedParent) + 1; + } return 0; - } else if (n instanceof InlinedCallSite) { - return indent(n.getParent()) + 1; } else { return indent(n.getParent()); } } } - public InstalledCode compileMethodHelper(StructuredGraph graph, GraphBuilderConfiguration config, Assumptions assumptions, String name, SpeculationLog speculationLog) { + public InstalledCode compileMethodHelper(StructuredGraph graph, Assumptions assumptions, String name, SpeculationLog speculationLog) { try (Scope s = Debug.scope("TruffleFinal")) { Debug.dump(graph, "After TruffleTier"); } catch (Throwable e) { @@ -220,8 +225,8 @@ CodeCacheProvider codeCache = providers.getCodeCache(); CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false); CompilationResult compilationResult = new CompilationResult(name); - result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, createGraphBuilderSuite(config), OptimisticOptimizations.ALL, getProfilingInfo(graph), - speculationLog, suites, false, compilationResult, CompilationResultBuilderFactory.Default); + result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, createGraphBuilderSuite(), OptimizationsGraal, getProfilingInfo(graph), speculationLog, + suites, false, compilationResult, CompilationResultBuilderFactory.Default); } catch (Throwable e) { throw Debug.handle(e); } @@ -259,7 +264,7 @@ return installedCode; } - private PhaseSuite createGraphBuilderSuite(GraphBuilderConfiguration config) { + private PhaseSuite createGraphBuilderSuite() { PhaseSuite suite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); ListIterator> iterator = suite.findPhase(GraphBuilderPhase.class); iterator.remove(); @@ -277,4 +282,8 @@ } } } + + public PartialEvaluator getPartialEvaluator() { + return partialEvaluator; + } } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java Wed Jan 29 15:02:19 2014 -0800 @@ -73,7 +73,7 @@ if (!policy.isWorthInlining(inlinableCallSite)) { break; } - if (inlinableCallSite.getCallSite().inline(target)) { + if (inlinableCallSite.getCallSite().inline()) { if (TraceTruffleInlining.getValue()) { printCallSiteInfo(policy, inlinableCallSite, "inlined"); } @@ -84,7 +84,7 @@ if (inlined) { for (InlinableCallSiteInfo callSite : inlinableCallSites) { - callSite.getCallSite().resetCallCount(); + CallNode.internalResetCallCount(callSite.getCallSite()); } } else { if (TraceTruffleInliningDetails.getValue()) { @@ -114,7 +114,7 @@ private final int callerInvocationCount; public InliningPolicy(OptimizedCallTarget caller) { - this.callerNodeCount = NodeUtil.countNodes(caller.getRootNode()); + this.callerNodeCount = NodeUtil.countNodes(caller.getRootNode(), null, true); this.callerInvocationCount = caller.getCompilationProfile().getOriginalInvokeCounter(); } @@ -155,15 +155,17 @@ private static final class InlinableCallSiteInfo { - private final InlinableCallSite callSite; + private final CallNode callSite; private final int callCount; private final int nodeCount; private final int recursiveDepth; - public InlinableCallSiteInfo(InlinableCallSite callSite) { + public InlinableCallSiteInfo(CallNode callSite) { + assert callSite.isInlinable(); this.callSite = callSite; - this.callCount = callSite.getCallCount(); - this.nodeCount = NodeUtil.countNodes(callSite.getInlineTree()); + this.callCount = CallNode.internalGetCallCount(callSite); + RootCallTarget target = (RootCallTarget) callSite.getCallTarget(); + this.nodeCount = target.getRootNode().getInlineNodeCount(); this.recursiveDepth = calculateRecursiveDepth(); } @@ -173,21 +175,23 @@ private int calculateRecursiveDepth() { int depth = 0; - Node parent = ((Node) callSite).getParent(); - while (!(parent instanceof RootNode)) { - assert parent != null; - if (parent instanceof InlinedCallSite && ((InlinedCallSite) parent).getCallTarget() == callSite.getCallTarget()) { - depth++; + + Node parent = callSite.getParent(); + while (parent != null) { + if (parent instanceof RootNode) { + RootNode root = ((RootNode) parent); + if (root.getCallTarget() == callSite.getCallTarget()) { + depth++; + } + parent = root.getParentInlinedCall(); + } else { + parent = parent.getParent(); } - parent = parent.getParent(); - } - if (((RootNode) parent).getCallTarget() == callSite.getCallTarget()) { - depth++; } return depth; } - public InlinableCallSite getCallSite() { + public CallNode getCallSite() { return callSite; } @@ -206,8 +210,15 @@ @Override public boolean visit(Node node) { - if (node instanceof InlinableCallSite) { - inlinableCallSites.add(new InlinableCallSiteInfo((InlinableCallSite) node)); + if (node instanceof CallNode) { + CallNode callNode = (CallNode) node; + if (!callNode.isInlined()) { + if (callNode.isInlinable()) { + inlinableCallSites.add(new InlinableCallSiteInfo(callNode)); + } + } else { + callNode.getInlinedRoot().accept(this); + } } return true; } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/UnsupportedSpecializationTest.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/UnsupportedSpecializationTest.java Wed Jan 29 15:02:19 2014 -0800 @@ -0,0 +1,58 @@ +/* + * 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.api.dsl.test; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; +import com.oracle.truffle.api.dsl.test.UnsupportedSpecializationTestFactory.Undefined1Factory; + +public class UnsupportedSpecializationTest { + + @Test + public void testUndefined1() { + TestRootNode root = TestHelper.createRoot(Undefined1Factory.getInstance()); + try { + TestHelper.executeWith(root, ""); + Assert.fail(); + } catch (UnsupportedSpecializationException e) { + Assert.assertNotNull(e.getSuppliedValues()); + Assert.assertEquals(1, e.getSuppliedValues().length); + Assert.assertEquals("", e.getSuppliedValues()[0]); + Assert.assertEquals(root.getNode(), e.getNode()); + } + } + + @NodeChild("a") + abstract static class Undefined1 extends ValueNode { + + @Specialization + public int doInteger(@SuppressWarnings("unused") int a) { + throw new AssertionError(); + } + } + + // TODO more tests required +} diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/UnsupportedSpecializationException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/UnsupportedSpecializationException.java Wed Jan 29 15:02:19 2014 -0800 @@ -0,0 +1,62 @@ +/* + * 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.util.*; + +import com.oracle.truffle.api.nodes.*; + +/** + * Thrown by the generated code of Truffle-DSL if no compatible Specialization could be found for + * the provided values. + */ +public final class UnsupportedSpecializationException extends RuntimeException { + + private static final long serialVersionUID = -2122892028296836269L; + + private final Node node; + private final Object[] suppliedValues; + + public UnsupportedSpecializationException(Node node, Object... suppliedValues) { + super("Unexpected values provided for " + node + ": " + Arrays.toString(suppliedValues)); + this.node = node; + this.suppliedValues = suppliedValues; + } + + /** + * Returns the {@link Node} that caused the this {@link UnsupportedSpecializationException}. + */ + public Node getNode() { + return node; + } + + /** + * Returns the dynamic values that were supplied to the node. + */ + public Object[] getSuppliedValues() { + return suppliedValues; + } + +} diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java Wed Jan 29 15:02:19 2014 -0800 @@ -0,0 +1,264 @@ +/* + * 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. 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.nodes; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.impl.*; + +/** + * This node represents a call to a static {@link CallTarget}. This node should be used whenever a + * {@link CallTarget} is considered constant at a certain location in the tree. This enables the + * Truffle runtime to perform inlining or other optimizations for this call-site. + * + * @see #create(CallTarget) to create a CallNode instance. + */ +public abstract class CallNode extends Node { + + protected final CallTarget callTarget; + + private CallNode(CallTarget callTarget) { + this.callTarget = callTarget; + } + + /** + * @return the constant {@link CallTarget} that is associated with this {@link CallNode}. + */ + public CallTarget getCallTarget() { + return callTarget; + } + + /** + * Calls this constant target passing a caller frame and arguments. + * + * @param caller the caller frame + * @param arguments the arguments that should be passed to the callee + * @return the return result of the call + */ + public abstract Object call(PackedFrame caller, Arguments arguments); + + /** + * Returns true if the {@link CallTarget} contained in this {@link CallNode} can be + * inlined. A {@link CallTarget} is considered inlinable if it was created using + * {@link TruffleRuntime#createCallTarget(RootNode)} and if the enclosed {@link RootNode} + * returns true for {@link RootNode#isInlinable()}. + */ + public abstract boolean isInlinable(); + + /** + * @return true if this {@link CallNode} was already inlined. + */ + public abstract boolean isInlined(); + + /** + * Enforces an inlining optimization on this {@link CallNode} instance. If not performed + * manually the Truffle runtime may perform inlining using an heuristic to optimize the + * performance of the execution. It is recommended to implement an version of + * {@link RootNode#inline()} that adapts the inlining for possible guest language specific + * behavior. If the this {@link CallNode} is not inlinable or is already inlined + * false is returned. + * + * @return true if the inlining operation was successful. + */ + public abstract boolean inline(); + + /** + * Returns the inlined root node if the call node was inlined. If the {@link CallNode} was not + * inlined null is returned. + * + * @return the inlined root node returned by {@link RootNode#inline()} + */ + public RootNode getInlinedRoot() { + return null; + } + + /** + * Creates a new {@link CallNode} using a {@link CallTarget}. + * + * @param target the {@link CallTarget} to call + * @return a call node that calls the provided target + */ + public static CallNode create(CallTarget target) { + if (isInlinable(target)) { + return new InlinableCallNode(target); + } else { + return new DefaultCallNode(target); + } + } + + /** + * Warning: this is internal API and may change without notice. + */ + public static int internalGetCallCount(CallNode callNode) { + if (callNode.isInlinable() && !callNode.isInlined()) { + return ((InlinableCallNode) callNode).getCallCount(); + } + throw new UnsupportedOperationException(); + } + + /** + * Warning: this is internal API and may change without notice. + */ + public static void internalResetCallCount(CallNode callNode) { + if (callNode.isInlinable() && !callNode.isInlined()) { + ((InlinableCallNode) callNode).resetCallCount(); + return; + } + } + + private static boolean isInlinable(CallTarget callTarget) { + if (callTarget instanceof DefaultCallTarget) { + return (((DefaultCallTarget) callTarget).getRootNode()).isInlinable(); + } + return false; + } + + @Override + public String toString() { + return getParent() != null ? getParent().toString() : super.toString(); + } + + static final class DefaultCallNode extends CallNode { + + public DefaultCallNode(CallTarget target) { + super(target); + } + + @Override + public Object call(PackedFrame caller, Arguments arguments) { + return callTarget.call(caller, arguments); + } + + @Override + public boolean inline() { + return false; + } + + @Override + public boolean isInlinable() { + return false; + } + + @Override + public boolean isInlined() { + return false; + } + + } + + static final class InlinableCallNode extends CallNode { + + private int callCount; + + public InlinableCallNode(CallTarget target) { + super(target); + } + + @Override + public Object call(PackedFrame parentFrame, Arguments arguments) { + if (CompilerDirectives.inInterpreter()) { + callCount++; + } + return callTarget.call(parentFrame, arguments); + } + + @Override + public boolean inline() { + DefaultCallTarget defaultTarget = (DefaultCallTarget) getCallTarget(); + RootNode originalRootNode = defaultTarget.getRootNode(); + if (originalRootNode.isInlinable()) { + RootNode inlinedRootNode = defaultTarget.getRootNode().inline(); + inlinedRootNode.setCallTarget(callTarget); + inlinedRootNode.setParentInlinedCall(this); + replace(new InlinedCallNode(defaultTarget, inlinedRootNode)); + return true; + } + return false; + } + + @Override + public boolean isInlined() { + return false; + } + + @Override + public boolean isInlinable() { + return true; + } + + /* Truffle internal API. */ + int getCallCount() { + return callCount; + } + + /* Truffle internal API. */ + void resetCallCount() { + callCount = 0; + } + + } + + static final class InlinedCallNode extends CallNode { + + private final RootNode inlinedRoot; + + public InlinedCallNode(DefaultCallTarget callTarget, RootNode inlinedRoot) { + super(callTarget); + this.inlinedRoot = inlinedRoot; + } + + @Override + public Object call(PackedFrame caller, Arguments arguments) { + return inlinedRoot.execute(Truffle.getRuntime().createVirtualFrame(caller, arguments, inlinedRoot.getFrameDescriptor())); + } + + @Override + public InlinedCallNode copy() { + return new InlinedCallNode((DefaultCallTarget) getCallTarget(), NodeUtil.cloneNode(inlinedRoot)); + } + + @Override + public RootNode getInlinedRoot() { + return inlinedRoot; + } + + @Override + public boolean inline() { + return false; + } + + @Override + public boolean isInlinable() { + return true; + } + + @Override + public boolean isInlined() { + return true; + } + + } + +} diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinableCallSite.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinableCallSite.java Wed Jan 29 14:06:32 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 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.nodes; - -import com.oracle.truffle.api.*; - -/** - * Denotes a call node that can inline the tree of its associated call target. - * - * @see InlinedCallSite - */ -public interface InlinableCallSite { - - /** - * Returns the number of calls since the last reset of the call count. - * - * @return the current call count. - */ - int getCallCount(); - - /** - * Resets the call count to 0. - */ - void resetCallCount(); - - /** - * Returns the tree that would be inlined by a call to {@link #inline(FrameFactory)}. - * - * @return the node tree to be inlined. - */ - Node getInlineTree(); - - /** - * Returns the call target associated with this call site. - * - * @return the inlinable {@link CallTarget}. - */ - CallTarget getCallTarget(); - - /** - * Instructs the call node to inline the associated call target. - * - * @param factory Frame factory for creating new virtual frames for inlined calls. - * @return {@code true} if call target was inlined; {@code false} otherwise. - */ - boolean inline(FrameFactory factory); -} diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinedCallSite.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinedCallSite.java Wed Jan 29 14:06:32 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 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.nodes; - -import com.oracle.truffle.api.*; - -/** - * Denotes a call node with an inlined call target. Allows for recursive call detection. - * - * @see InlinableCallSite - */ -public interface InlinedCallSite { - - /** - * Returns the call target that has been inlined at this call site. - * - * @return the inlined call target. - */ - CallTarget getCallTarget(); -} diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Wed Jan 29 15:02:19 2014 -0800 @@ -246,7 +246,7 @@ } private void reportReplace() { - RootNode rootNode = getRootNode(); + RootNode rootNode = NodeUtil.findOutermostRootNode(this); if (rootNode != null) { if (rootNode.getCallTarget() instanceof ReplaceObserver) { ((ReplaceObserver) rootNode.getCallTarget()).nodeReplaced(); diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Wed Jan 29 15:02:19 2014 -0800 @@ -451,6 +451,31 @@ return null; } + /** + * Returns the outermost not inlined {@link RootNode} which is a parent of this node. + * + * @see RootNode#getParentInlinedCall() + * @param node to search + * @return the outermost {@link RootNode} + */ + public static RootNode findOutermostRootNode(Node node) { + Node parent = node; + while (parent != null) { + if (parent instanceof RootNode) { + RootNode root = (RootNode) parent; + Node next = root.getParentInlinedCall(); + if (next != null) { + parent = next; + } else { + return root; + } + } else { + parent = parent.getParent(); + } + } + return null; + } + public static T findParent(Node start, Class clazz) { Node parent = start.getParent(); if (parent == null) { @@ -571,24 +596,26 @@ } public static int countNodes(Node root) { - return countNodes(root, null); + return countNodes(root, null, false); } - public static int countNodes(Node root, Class clazz) { - NodeCountVisitor nodeCount = new NodeCountVisitor(root, clazz); + public static int countNodes(Node root, Class clazz, boolean countInlinedCallNodes) { + NodeCountVisitor nodeCount = new NodeCountVisitor(root, clazz, countInlinedCallNodes); root.accept(nodeCount); return nodeCount.nodeCount; } private static final class NodeCountVisitor implements NodeVisitor { + private Node root; + private boolean inspectInlinedCalls; int nodeCount; - private final Node root; private final Class clazz; - private NodeCountVisitor(Node root, Class clazz) { + private NodeCountVisitor(Node root, Class clazz, boolean inspectInlinedCalls) { this.root = root; this.clazz = clazz; + this.inspectInlinedCalls = inspectInlinedCalls; } @Override @@ -596,9 +623,18 @@ if (node instanceof RootNode && node != root) { return false; } + if (clazz == null || clazz.isInstance(node)) { nodeCount++; } + + if (inspectInlinedCalls && node instanceof CallNode) { + CallNode call = (CallNode) node; + if (call.isInlined()) { + call.getInlinedRoot().getChildren().iterator().next().accept(this); + } + } + return true; } } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Wed Jan 29 15:02:19 2014 -0800 @@ -25,6 +25,7 @@ package com.oracle.truffle.api.nodes; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.*; import com.oracle.truffle.api.frame.*; /** @@ -37,6 +38,12 @@ private CallTarget callTarget; private final FrameDescriptor frameDescriptor; + /* + * Internal field to keep reference to the inlined call node. The inlined parent should not be + * the same as the Node parent to keep the same tree hierarchy if inlined vs not inlined. + */ + @CompilationFinal private CallNode parentInlinedCall; + protected RootNode() { this(null, null); } @@ -55,6 +62,58 @@ } /** + * Creates a copy of the current {@link RootNode} for use as inlined AST. The default + * implementation copies this {@link RootNode} and all its children recursively. It is + * recommended to override this method to provide an implementation that copies an uninitialized + * version of this AST. An uninitialized version of an AST was usually never executed which + * means that it has not yet collected any profiling feedback. Please note that changes in the + * behavior of this method might also require changes in {@link #getInlineNodeCount()}. + * + * @see RootNode#getInlineNodeCount() + * @see RootNode#isInlinable() + * + * @return the copied RootNode for inlining + * @throws UnsupportedOperationException if {@link #isInlinable()} returns false + */ + public RootNode inline() { + if (!isInlinable()) { + throw new UnsupportedOperationException("Inlining is not enabled."); + } + return NodeUtil.cloneNode(this); + } + + /** + * Returns the number of nodes that would be returned if {@link #inline()} would get invoked. + * This node count may be used for the calculation in a smart inlining heuristic. + * + * @see RootNode#inline() + * @see RootNode#isInlinable() + * + * @return the number of nodes that will get inlined + * @throws UnsupportedOperationException if {@link #isInlinable()} returns false + */ + public int getInlineNodeCount() { + if (!isInlinable()) { + throw new UnsupportedOperationException("Inlining is not enabled."); + } + return NodeUtil.countNodes(this); + } + + /** + * Returns true if this RootNode can be inlined. If this method returns true implementations of + * {@link #inline()} and {@link #getInlineNodeCount()} must be provided. Returns + * true by default. + * + * @see RootNode#inline() + * @see RootNode#getInlineNodeCount() + * + * @return true if this RootNode can be inlined + */ + public boolean isInlinable() { + return true; + } + + /** * Executes this function using the specified frame and returns the result value. * * @param frame the frame of the currently executing guest language method @@ -66,11 +125,27 @@ return callTarget; } - public FrameDescriptor getFrameDescriptor() { + public final FrameDescriptor getFrameDescriptor() { return frameDescriptor; } public void setCallTarget(CallTarget callTarget) { this.callTarget = callTarget; } + + /* Internal API. Do not use. */ + void setParentInlinedCall(CallNode inlinedParent) { + this.parentInlinedCall = inlinedParent; + } + + /** + * Returns the {@link CallNode} that uses this {@link RootNode} for an inlined call. Returns + * null if this {@link RootNode} is not inlined into a caller. This method can be + * used to also traverse parent {@link CallTarget} that have been inlined into this call. + * + * @return the responsible {@link CallNode} for inlining. + */ + public final CallNode getParentInlinedCall() { + return parentInlinedCall; + } } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Wed Jan 29 15:02:19 2014 -0800 @@ -331,11 +331,10 @@ } protected void emitEncounteredSynthetic(CodeTreeBuilder builder, TemplateMethod current) { - builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)); - builder.startCall("createInfo0"); - builder.doubleQuote("Unsupported values"); + builder.startThrow().startNew(getContext().getType(UnsupportedSpecializationException.class)); + builder.string("this"); addInternalValueParameterNames(builder, current, current, null, false, null); - builder.end().end().end(); + builder.end().end(); } private static List findUserConstructors(TypeMirror nodeType) { diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java Wed Jan 29 15:02:19 2014 -0800 @@ -19,7 +19,7 @@ import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind; import com.oracle.truffle.api.nodes.instrument.*; import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.call.*; +import com.oracle.truffle.ruby.nodes.call.CallNode; import com.oracle.truffle.ruby.nodes.literal.*; import com.oracle.truffle.ruby.nodes.methods.*; diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLSimpleTestSuite.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLSimpleTestSuite.java Wed Jan 29 15:02:19 2014 -0800 @@ -0,0 +1,35 @@ +/* + * 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 org.junit.runner.*; + +@RunWith(SLTestRunner.class) +@SLTestSuite({"graal/com.oracle.truffle.sl.test/tests", "tests"}) +public class SLSimpleTestSuite { + + public static void main(String[] args) throws Exception { + SLTestRunner.runInMain(SLSimpleTestSuite.class, args); + } + +} diff -r d006a6332db8 -r d7ed39d0a6d9 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 Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Wed Jan 29 15:02:19 2014 -0800 @@ -23,103 +23,143 @@ package com.oracle.truffle.sl.test; import java.io.*; +import java.nio.charset.*; import java.nio.file.*; import java.nio.file.attribute.*; import java.util.*; import org.junit.*; +import org.junit.internal.*; +import org.junit.runner.*; +import org.junit.runner.manipulation.*; +import org.junit.runner.notification.*; +import org.junit.runners.*; +import org.junit.runners.model.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.runtime.*; +import com.oracle.truffle.sl.test.SLTestRunner.TestCase; -public class SLTestRunner { +public final class SLTestRunner extends ParentRunner { private static final int REPEATS = 10; - private static final String TEST_DIR = "graal/com.oracle.truffle.sl.test/tests"; + private static final String INPUT_SUFFIX = ".sl"; private static final String OUTPUT_SUFFIX = ".output"; - static class TestCase { - protected final String name; - protected final Source input; - protected final String expectedOutput; - protected String actualOutput; + private static final String LF = System.getProperty("line.separator"); - protected TestCase(String name, Source input, String expectedOutput) { - this.name = name; + public static final class TestCase { + private final Source input; + private final String expectedOutput; + private final Description name; + + public TestCase(Class testClass, String name, Source input, String expectedOutput) { this.input = input; this.expectedOutput = expectedOutput; + this.name = Description.createTestDescription(testClass, name); + } + } + + private final SourceManager sourceManager = new SourceManager(); + private final List testCases; + + public SLTestRunner(Class runningClass) throws InitializationError { + super(runningClass); + try { + testCases = createTests(runningClass); + } catch (IOException e) { + throw new InitializationError(e); } } - protected boolean useConsole = false; + @Override + protected Description describeChild(TestCase child) { + return child.name; + } - protected final SourceManager sourceManager = new SourceManager(); - protected final List testCases = new ArrayList<>(); + @Override + protected List getChildren() { + return testCases; + } + + @Override + public void filter(Filter filter) throws NoTestsRemainException { + super.filter(filter); + } - protected boolean runTests(String namePattern) throws IOException { - Path testsRoot = FileSystems.getDefault().getPath(TEST_DIR); + protected List createTests(final Class c) throws IOException, InitializationError { + SLTestSuite suite = c.getAnnotation(SLTestSuite.class); + if (suite == null) { + throw new InitializationError(String.format("@%s annotation required on class '%s' to run with '%s'.", SLTestSuite.class.getSimpleName(), c.getName(), SLTestRunner.class.getSimpleName())); + } + + String[] pathes = suite.value(); - Files.walkFileTree(testsRoot, new SimpleFileVisitor() { + Path root = null; + for (String path : pathes) { + root = FileSystems.getDefault().getPath(path); + if (Files.exists(root)) { + break; + } + } + if (root == null && pathes.length > 0) { + throw new FileNotFoundException(pathes[0]); + } + + final Path rootPath = root; + + final List foundCases = new ArrayList<>(); + Files.walkFileTree(rootPath, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path inputFile, BasicFileAttributes attrs) throws IOException { String name = inputFile.getFileName().toString(); if (name.endsWith(INPUT_SUFFIX)) { - name = name.substring(0, name.length() - INPUT_SUFFIX.length()); - Path outputFile = inputFile.resolveSibling(name + OUTPUT_SUFFIX); + String baseName = name.substring(0, name.length() - INPUT_SUFFIX.length()); + + Path outputFile = inputFile.resolveSibling(baseName + OUTPUT_SUFFIX); if (!Files.exists(outputFile)) { throw new Error("Output file does not exist: " + outputFile); } - testCases.add(new TestCase(name, sourceManager.get(inputFile.toString()), new String(Files.readAllBytes(outputFile)))); + // fix line feeds for non unix os + StringBuilder outFile = new StringBuilder(); + for (String line : Files.readAllLines(outputFile, Charset.defaultCharset())) { + outFile.append(line); + outFile.append(LF); + } + foundCases.add(new TestCase(c, baseName, sourceManager.get(inputFile.toString()), outFile.toString())); } return FileVisitResult.CONTINUE; } }); - - if (testCases.size() == 0) { - System.out.format("No test cases match filter %s", namePattern); - return false; - } - - boolean success = true; - for (TestCase testCase : testCases) { - if (namePattern.length() == 0 || testCase.name.toLowerCase().contains(namePattern.toLowerCase())) { - success = success & executeTest(testCase); - } - } - return success; + return foundCases; } - protected boolean executeTest(TestCase testCase) { - System.out.format("Running %s\n", testCase.name); + @Override + protected void runChild(TestCase testCase, RunNotifier notifier) { + notifier.fireTestStarted(testCase.name); ByteArrayOutputStream out = new ByteArrayOutputStream(); - PrintStream printer = new PrintStream(useConsole ? new SplitOutputStream(out, System.err) : out); + PrintStream printer = new PrintStream(out); PrintStream origErr = System.err; try { System.setErr(printer); SLContext context = new SLContext(sourceManager, printer); SLMain.run(context, testCase.input, null, REPEATS); + + String actualOutput = new String(out.toByteArray()); + + Assert.assertEquals(repeat(testCase.expectedOutput, REPEATS), actualOutput); + } catch (AssertionError e) { + notifier.fireTestFailure(new Failure(testCase.name, e)); } catch (Throwable ex) { - ex.printStackTrace(printer); + notifier.fireTestFailure(new Failure(testCase.name, ex)); } finally { System.setErr(origErr); - } - testCase.actualOutput = new String(out.toByteArray()); - - if (testCase.actualOutput.equals(repeat(testCase.expectedOutput, REPEATS))) { - System.out.format("OK %s\n", testCase.name); - return true; - } else { - if (!useConsole) { - System.out.format("== Expected ==\n%s\n", testCase.expectedOutput); - System.out.format("== Actual ==\n%s\n", testCase.actualOutput); - } - System.out.format("FAILED %s\n", testCase.name); - return false; + notifier.fireTestFinished(testCase.name); } } @@ -131,19 +171,35 @@ return result.toString(); } - public static void main(String[] args) throws IOException { - String namePattern = ""; + public static void runInMain(Class testClass, String[] args) throws InitializationError, NoTestsRemainException { + JUnitCore core = new JUnitCore(); + core.addListener(new TextListener(System.out)); + SLTestRunner suite = new SLTestRunner(testClass); if (args.length > 0) { - namePattern = args[0]; + suite.filter(new NameFilter(args[0])); } - boolean success = new SLTestRunner().runTests(namePattern); - if (!success) { + Result r = core.run(suite); + if (!r.wasSuccessful()) { System.exit(1); } } - @Test - public void test() throws IOException { - Assert.assertTrue(runTests("")); + private static final class NameFilter extends Filter { + private final String pattern; + + private NameFilter(String pattern) { + this.pattern = pattern.toLowerCase(); + } + + @Override + public boolean shouldRun(Description description) { + return description.getMethodName().toLowerCase().contains(pattern); + } + + @Override + public String describe() { + return "Filter contains " + pattern; + } } + } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestSuite.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestSuite.java Wed Jan 29 15:02:19 2014 -0800 @@ -0,0 +1,37 @@ +/* + * 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 java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SLTestSuite { + + /** + * Defines the base path of the test suite. Multiple base pathes can be specified. However only + * the first base that exists is used to lookup the test cases. + */ + String[] value(); + +} diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SplitOutputStream.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SplitOutputStream.java Wed Jan 29 14:06:32 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +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. - * - * 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 java.io.*; - -public class SplitOutputStream extends OutputStream { - - private final OutputStream[] outputs; - - public SplitOutputStream(OutputStream... outputs) { - this.outputs = outputs; - } - - @Override - public void write(int b) throws IOException { - for (OutputStream out : outputs) { - out.write(b); - } - } - - @Override - public void write(byte[] b) throws IOException { - for (OutputStream out : outputs) { - out.write(b); - } - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - for (OutputStream out : outputs) { - out.write(b, off, len); - } - } - - @Override - public void flush() throws IOException { - for (OutputStream out : outputs) { - out.flush(); - } - } - - @Override - public void close() throws IOException { - for (OutputStream out : outputs) { - out.close(); - } - } -} diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Wed Jan 29 15:02:19 2014 -0800 @@ -73,8 +73,19 @@ return inlineImmediatly; } - public SLExpressionNode inline() { - return NodeUtil.cloneNode(uninitializedBody); + @Override + public RootNode inline() { + return new SLRootNode(getFrameDescriptor().shallowCopy(), NodeUtil.cloneNode(uninitializedBody), name, inlineImmediatly); + } + + @Override + public int getInlineNodeCount() { + return NodeUtil.countNodes(uninitializedBody); + } + + @Override + public boolean isInlinable() { + return true; } public Node getUninitializedBody() { diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Wed Jan 29 15:02:19 2014 -0800 @@ -27,27 +27,29 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.runtime.*; -abstract class SLDirectDispatchNode extends SLAbstractDispatchNode { +final class SLDirectDispatchNode extends SLAbstractDispatchNode { protected final SLFunction cachedFunction; protected final RootCallTarget cachedCallTarget; protected final Assumption cachedCallTargetStable; + @Child protected CallNode callNode; @Child protected SLAbstractDispatchNode nextNode; protected SLDirectDispatchNode(SLAbstractDispatchNode next, SLFunction cachedFunction) { this.cachedFunction = cachedFunction; this.cachedCallTarget = cachedFunction.getCallTarget(); this.cachedCallTargetStable = cachedFunction.getCallTargetStable(); + this.callNode = adoptChild(CallNode.create(cachedCallTarget)); this.nextNode = adoptChild(next); } @Override - protected final Object executeCall(VirtualFrame frame, SLFunction function, SLArguments arguments) { + protected Object executeCall(VirtualFrame frame, SLFunction function, SLArguments arguments) { if (this.cachedFunction == function) { try { cachedCallTargetStable.check(); - return executeCurrent(frame, arguments); + return callNode.call(frame.pack(), arguments); } catch (InvalidAssumptionException ex) { /* * Remove ourselfs from the polymorphic inline cache, so that we fail the check only @@ -61,6 +63,4 @@ } return nextNode.executeCall(frame, function, arguments); } - - protected abstract Object executeCurrent(VirtualFrame frame, SLArguments arguments); } diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInlinableDirectDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInlinableDirectDispatchNode.java Wed Jan 29 14:06:32 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2013, 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.nodes.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -final class SLInlinableDirectDispatchNode extends SLDirectDispatchNode implements InlinableCallSite { - - @CompilationFinal private int callCount; - - protected SLInlinableDirectDispatchNode(SLAbstractDispatchNode next, SLFunction cachedFunction) { - super(next, cachedFunction); - } - - @Override - protected Object executeCurrent(VirtualFrame frame, SLArguments arguments) { - if (CompilerDirectives.inInterpreter()) { - callCount++; - } - return cachedCallTarget.call(frame.pack(), arguments); - } - - @Override - public boolean inline(FrameFactory factory) { - CompilerAsserts.neverPartOfCompilation(); - RootNode root = cachedCallTarget.getRootNode(); - SLExpressionNode inlinedNode = ((SLRootNode) root).inline(); - assert inlinedNode != null; - replace(new SLInlinedDirectDispatchNode(this, inlinedNode), "Inlined " + root); - /* We are always able to inline if required. */ - return true; - } - - @Override - public int getCallCount() { - return callCount; - } - - @Override - public void resetCallCount() { - callCount = 0; - } - - @Override - public Node getInlineTree() { - RootNode root = cachedCallTarget.getRootNode(); - if (root instanceof SLRootNode) { - return ((SLRootNode) root).getUninitializedBody(); - } - return null; - } - - @Override - public CallTarget getCallTarget() { - return cachedCallTarget; - } -} diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInlinedDirectDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInlinedDirectDispatchNode.java Wed Jan 29 14:06:32 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2013, 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.nodes.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -final class SLInlinedDirectDispatchNode extends SLDirectDispatchNode implements InlinedCallSite { - - private final FrameDescriptor descriptor; - @Child private SLExpressionNode inlinedBody; - - protected SLInlinedDirectDispatchNode(SLInlinableDirectDispatchNode prev, SLExpressionNode inlinedBody) { - super(prev.nextNode, prev.cachedFunction); - this.descriptor = cachedCallTarget.getRootNode().getFrameDescriptor(); - this.inlinedBody = adoptChild(inlinedBody); - } - - @Override - protected Object executeCurrent(VirtualFrame frame, SLArguments arguments) { - VirtualFrame newFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), arguments, descriptor); - return inlinedBody.executeGeneric(newFrame); - } - - @Override - public CallTarget getCallTarget() { - return cachedCallTarget; - } -} diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedCallNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedCallNode.java Wed Jan 29 14:06:32 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedCallNode.java Wed Jan 29 15:02:19 2014 -0800 @@ -43,7 +43,7 @@ SLAbstractDispatchNode specialized; if (depth < INLINE_CACHE_SIZE) { SLAbstractDispatchNode next = new SLUninitializedCallNode(); - SLAbstractDispatchNode direct = new SLInlinableDirectDispatchNode(next, function); + SLAbstractDispatchNode direct = new SLDirectDispatchNode(next, function); specialized = replace(direct); } else { SLAbstractDispatchNode generic = new SLGenericDispatchNode(); diff -r d006a6332db8 -r d7ed39d0a6d9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java diff -r d006a6332db8 -r d7ed39d0a6d9 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Wed Jan 29 14:06:32 2014 -0800 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Wed Jan 29 15:02:19 2014 -0800 @@ -553,7 +553,7 @@ //------------------------------------------------------------------------------------------------ set_int("graalCountersThreadOffset", in_bytes(JavaThread::graal_counters_offset())); - set_int("graalCountersSize", (jint) GRAAL_COUNTERS_SIZE); + set_int("graalCountersSize", (jint) GraalCounterSize); #undef set_boolean #undef set_int @@ -816,7 +816,7 @@ C2V_END C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv *env, jobject)) - typeArrayOop arrayOop = oopFactory::new_longArray(GRAAL_COUNTERS_SIZE, CHECK_NULL); + typeArrayOop arrayOop = oopFactory::new_longArray(GraalCounterSize, CHECK_NULL); JavaThread::collect_counters(arrayOop); return (jlongArray) JNIHandles::make_local(arrayOop); C2V_END diff -r d006a6332db8 -r d7ed39d0a6d9 src/share/vm/graal/graalGlobals.hpp --- a/src/share/vm/graal/graalGlobals.hpp Wed Jan 29 14:06:32 2014 -0800 +++ b/src/share/vm/graal/graalGlobals.hpp Wed Jan 29 15:02:19 2014 -0800 @@ -55,6 +55,12 @@ product(intx, TraceGraal, 0, \ "Trace level for Graal") \ \ + product(intx, GraalCounterSize, 0, \ + "Reserved size for benchmark counters") \ + \ + product(bool, GraalCountersExcludeCompiler, true, \ + "Exclude Graal compiler threads from benchmark counters") \ + \ product(bool, GraalDeferredInitBarriers, true, \ "Defer write barriers of young objects") \ \ diff -r d006a6332db8 -r d7ed39d0a6d9 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Jan 29 14:06:32 2014 -0800 +++ b/src/share/vm/runtime/thread.cpp Wed Jan 29 15:02:19 2014 -0800 @@ -1418,31 +1418,27 @@ #ifdef GRAAL -#if GRAAL_COUNTERS_SIZE > 0 -jlong JavaThread::_graal_old_thread_counters[GRAAL_COUNTERS_SIZE]; +jlong* JavaThread::_graal_old_thread_counters; bool graal_counters_include(oop threadObj) { - return !GRAAL_COUNTERS_EXCLUDE_COMPILER_THREADS || threadObj == NULL || threadObj->klass() != SystemDictionary::CompilerThread_klass(); + return !GraalCountersExcludeCompiler || threadObj == NULL || threadObj->klass() != SystemDictionary::CompilerThread_klass(); } void JavaThread::collect_counters(typeArrayOop array) { - MutexLocker tl(Threads_lock); - for (int i = 0; i < array->length(); i++) { - array->long_at_put(i, _graal_old_thread_counters[i]); - } - for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { - if (graal_counters_include(tp->threadObj())) { - for (int i = 0; i < array->length(); i++) { - array->long_at_put(i, array->long_at(i) + tp->_graal_counters[i]); + if (GraalCounterSize > 0) { + MutexLocker tl(Threads_lock); + for (int i = 0; i < array->length(); i++) { + array->long_at_put(i, _graal_old_thread_counters[i]); + } + for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { + if (graal_counters_include(tp->threadObj())) { + for (int i = 0; i < array->length(); i++) { + array->long_at_put(i, array->long_at(i) + tp->_graal_counters[i]); + } } } } } -#else -void JavaThread::collect_counters(typeArrayOop array) { - // empty -} -#endif // GRAAL_COUNTERS_SIZE > 0 #endif // GRAAL @@ -1486,11 +1482,12 @@ _graal_alternate_call_target = NULL; _graal_implicit_exception_pc = NULL; _graal_compiling = false; -#if GRAAL_COUNTERS_SIZE > 0 - for (int i = 0; i < GRAAL_COUNTERS_SIZE; i++) { - _graal_counters[i] = 0; + if (GraalCounterSize > 0) { + _graal_counters = NEW_C_HEAP_ARRAY(jlong, GraalCounterSize, mtInternal); + memset(_graal_counters, 0, sizeof(jlong) * GraalCounterSize); + } else { + _graal_counters = NULL; } -#endif // GRAAL_COUNTER_SIZE > 0 #endif // GRAAL (void)const_cast(_exception_oop = NULL); _exception_pc = 0; @@ -1680,13 +1677,14 @@ if (_thread_profiler != NULL) delete _thread_profiler; if (_thread_stat != NULL) delete _thread_stat; -#if defined(GRAAL) && (GRAAL_COUNTERS_SIZE > 0) - if (graal_counters_include(threadObj())) { - for (int i = 0; i < GRAAL_COUNTERS_SIZE; i++) { +#ifdef GRAAL + if (GraalCounterSize > 0 && graal_counters_include(threadObj())) { + for (int i = 0; i < GraalCounterSize; i++) { _graal_old_thread_counters[i] += _graal_counters[i]; } + FREE_C_HEAP_ARRAY(jlong, _graal_counters, mtInternal); } -#endif +#endif // GRAAL } @@ -3458,6 +3456,15 @@ // Initialize global data structures and create system classes in heap vm_init_globals(); +#ifdef GRAAL + if (GraalCounterSize > 0) { + JavaThread::_graal_old_thread_counters = NEW_C_HEAP_ARRAY(jlong, GraalCounterSize, mtInternal); + memset(JavaThread::_graal_old_thread_counters, 0, sizeof(jlong) * GraalCounterSize); + } else { + JavaThread::_graal_old_thread_counters = NULL; + } +#endif // GRAAL + // Attach the main thread to this os thread JavaThread* main_thread = new JavaThread(); main_thread->set_thread_state(_thread_in_vm); @@ -4109,6 +4116,12 @@ delete thread; +#ifdef GRAAL + if (GraalCounterSize > 0) { + FREE_C_HEAP_ARRAY(jlong, JavaThread::_graal_old_thread_counters, mtInternal); + } +#endif // GRAAL + // exit_globals() will delete tty exit_globals(); diff -r d006a6332db8 -r d7ed39d0a6d9 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Wed Jan 29 14:06:32 2014 -0800 +++ b/src/share/vm/runtime/thread.hpp Wed Jan 29 15:02:19 2014 -0800 @@ -922,16 +922,10 @@ address _graal_implicit_exception_pc; // pc at which the most recent implicit exception occurred bool _graal_compiling; - // number of counters, increase as needed. 0 == disabled -#define GRAAL_COUNTERS_SIZE (0) -#define GRAAL_COUNTERS_EXCLUDE_COMPILER_THREADS (true) - -#if GRAAL_COUNTERS_SIZE > 0 - jlong _graal_counters[GRAAL_COUNTERS_SIZE]; - static jlong _graal_old_thread_counters[GRAAL_COUNTERS_SIZE]; -#endif // GRAAL_COUNTERS_SIZE > 0 + jlong* _graal_counters; public: + static jlong* _graal_old_thread_counters; static void collect_counters(typeArrayOop array); private: #endif // GRAAL @@ -1394,11 +1388,7 @@ #ifdef GRAAL static ByteSize graal_alternate_call_target_offset() { return byte_offset_of(JavaThread, _graal_alternate_call_target); } static ByteSize graal_implicit_exception_pc_offset() { return byte_offset_of(JavaThread, _graal_implicit_exception_pc); } -#if GRAAL_COUNTERS_SIZE > 0 static ByteSize graal_counters_offset() { return byte_offset_of(JavaThread, _graal_counters ); } -#else - static ByteSize graal_counters_offset() { return in_ByteSize(0); } -#endif // GRAAL_COUNTERS_SIZE > 0 #endif // GRAAL static ByteSize exception_oop_offset() { return byte_offset_of(JavaThread, _exception_oop ); } static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc ); }