# HG changeset patch # User Lukas Stadler # Date 1389798716 -3600 # Node ID c215dec9d3cfce818c8cb329d4247e4691a34a58 # Parent 056d9d7dc0614e3ea180f19eef2f3babac380f68 allow multiple ReturnNodes per graph diff -r 056d9d7dc061 -r c215dec9d3cf graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java Wed Jan 15 16:08:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java Wed Jan 15 16:11:56 2014 +0100 @@ -46,6 +46,11 @@ return ret.result(); } + private static IfNode getIfNode(StructuredGraph graph) { + assertTrue(graph.start().next() instanceof IfNode); + return (IfNode) graph.start().next(); + } + @Test public void testCanonicalComparison() { StructuredGraph referenceGraph = parse("referenceCanonicalComparison"); @@ -98,11 +103,9 @@ for (int i = 1; i <= 4; i++) { StructuredGraph graph = getCanonicalizedGraph("integerTest" + i); - ValueNode result = getResult(graph); - assertTrue(result instanceof ConditionalNode); - ConditionalNode mat = (ConditionalNode) result; - assertTrue(mat.condition() instanceof IntegerTestNode); - IntegerTestNode test = (IntegerTestNode) mat.condition(); + IfNode ifNode = getIfNode(graph); + assertTrue(ifNode.condition() instanceof IntegerTestNode); + IntegerTestNode test = (IntegerTestNode) ifNode.condition(); ParameterNode param0 = graph.getParameter(0); ParameterNode param1 = graph.getParameter(1); assertTrue((test.x() == param0 && test.y() == param1) || (test.x() == param1 && test.y() == param0)); @@ -133,8 +136,8 @@ assertTrue(result.isConstant() && result.asConstant().asLong() == 1); result = getResult(getCanonicalizedGraph("integerTestCanonicalization2")); assertTrue(result.isConstant() && result.asConstant().asLong() == 1); - result = getResult(getCanonicalizedGraph("integerTestCanonicalization3")); - assertTrue(result instanceof ConditionalNode); + StructuredGraph graph = getCanonicalizedGraph("integerTestCanonicalization3"); + assertEquals(2, graph.getNodes(ReturnNode.class).count()); } public static int integerTestCanonicalization1(boolean b) { diff -r 056d9d7dc061 -r c215dec9d3cf graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java Wed Jan 15 16:08:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java Wed Jan 15 16:11:56 2014 +0100 @@ -68,6 +68,7 @@ for (Node n : graph.getNodes()) { if (n instanceof ReturnNode) { + assert returnNode == null; returnNode = (ReturnNode) n; } else if (n instanceof MonitorExit) { monitorexit = (MonitorExit) n; diff -r 056d9d7dc061 -r c215dec9d3cf graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Wed Jan 15 16:08:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Wed Jan 15 16:11:56 2014 +0100 @@ -115,7 +115,7 @@ for (TestMode mode : TestMode.values()) { SchedulePhase schedule = getFinalSchedule("testSplit1Snippet", mode); assertReadWithinStartBlock(schedule, true); - assertReadWithinReturnBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); } } @@ -138,7 +138,7 @@ public void testSplit2() { SchedulePhase schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES); assertReadWithinStartBlock(schedule, false); - assertReadWithinReturnBlock(schedule, true); + assertReadWithinAllReturnBlocks(schedule, true); } /** @@ -163,7 +163,7 @@ SchedulePhase schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES); assertEquals(6, schedule.getCFG().getBlocks().length); assertReadWithinStartBlock(schedule, true); - assertReadWithinReturnBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); } /** @@ -188,7 +188,7 @@ SchedulePhase schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES); assertEquals(6, schedule.getCFG().getBlocks().length); assertReadWithinStartBlock(schedule, false); - assertReadWithinReturnBlock(schedule, true); + assertReadWithinAllReturnBlocks(schedule, true); } /** @@ -210,7 +210,7 @@ SchedulePhase schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES); assertEquals(7, schedule.getCFG().getBlocks().length); assertReadWithinStartBlock(schedule, true); - assertReadWithinReturnBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); } public String testStringReplaceSnippet(String input) { @@ -246,7 +246,7 @@ SchedulePhase schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES); assertEquals(7, schedule.getCFG().getBlocks().length); assertReadWithinStartBlock(schedule, false); - assertReadWithinReturnBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); } /** @@ -261,10 +261,11 @@ public void testArrayCopy() { SchedulePhase schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES); StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph(); - ReturnNode ret = graph.getNodes().filter(ReturnNode.class).first(); + assertEquals(1, graph.getNodes(ReturnNode.class).count()); + ReturnNode ret = graph.getNodes(ReturnNode.class).first(); assertTrue(ret.result() instanceof FloatingReadNode); assertEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result())); - assertReadWithinReturnBlock(schedule, true); + assertReadWithinAllReturnBlocks(schedule, true); } /** @@ -305,7 +306,7 @@ assertEquals(4, schedule.getCFG().getBlocks().length); assertEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count()); assertReadWithinStartBlock(schedule, false); - assertReadWithinReturnBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); assertReadAndWriteInSameBlock(schedule, false); } @@ -326,7 +327,7 @@ SchedulePhase schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES); assertEquals(4, schedule.getCFG().getBlocks().length); assertReadWithinStartBlock(schedule, false); - assertReadWithinReturnBlock(schedule, true); + assertReadWithinAllReturnBlocks(schedule, true); } /** @@ -345,9 +346,9 @@ @Test public void testIfRead4() { SchedulePhase schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES); - assertEquals(4, schedule.getCFG().getBlocks().length); + assertEquals(3, schedule.getCFG().getBlocks().length); assertReadWithinStartBlock(schedule, false); - assertReadWithinReturnBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); assertReadAndWriteInSameBlock(schedule, true); } @@ -366,7 +367,7 @@ SchedulePhase schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES); assertEquals(4, schedule.getCFG().getBlocks().length); assertReadWithinStartBlock(schedule, false); - assertReadWithinReturnBlock(schedule, true); + assertReadWithinAllReturnBlocks(schedule, true); assertReadAndWriteInSameBlock(schedule, false); } @@ -432,7 +433,7 @@ public void testBlockSchedule2() { SchedulePhase schedule = getFinalSchedule("testBlockSchedule2Snippet", TestMode.WITHOUT_FRAMESTATES, MemoryScheduling.OPTIMAL, SchedulingStrategy.LATEST); assertReadWithinStartBlock(schedule, false); - assertReadWithinReturnBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); assertReadAndWriteInSameBlock(schedule, false); } @@ -454,7 +455,7 @@ * read of container.b for increment operation should be in return block. TODO: not sure * though, could be replaced by read of container.b of the loop header... */ - assertReadWithinReturnBlock(schedule, true); + assertReadWithinAllReturnBlocks(schedule, true); } public static void testProxy2Snippet() { @@ -476,7 +477,7 @@ public void testProxy2() { SchedulePhase schedule = getFinalSchedule("testProxy2Snippet", TestMode.WITHOUT_FRAMESTATES); assertReadWithinStartBlock(schedule, false); - assertReadWithinReturnBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); } private int hash = 0; @@ -499,7 +500,7 @@ public void testStringHashCode() { SchedulePhase schedule = getFinalSchedule("testStringHashCodeSnippet", TestMode.WITHOUT_FRAMESTATES); assertReadWithinStartBlock(schedule, true); - assertReadWithinReturnBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); hash = 0x1337; value[0] = 'a'; @@ -531,30 +532,26 @@ public void testLoop4() { SchedulePhase schedule = getFinalSchedule("testLoop4Snippet", TestMode.WITHOUT_FRAMESTATES); assertReadWithinStartBlock(schedule, false); - assertReadWithinReturnBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); } - private void assertReadWithinReturnBlock(SchedulePhase schedule, boolean withinReturnBlock) { + private void assertReadWithinAllReturnBlocks(SchedulePhase schedule, boolean withinReturnBlock) { StructuredGraph graph = schedule.getCFG().graph; - assertEquals(graph.getNodes().filter(ReturnNode.class).count(), 1); + assertTrue(graph.getNodes(ReturnNode.class).isNotEmpty()); - Block end = null; - outer: for (Block b : schedule.getCFG().getBlocks()) { - for (Node n : b.getNodes()) { - if (n instanceof ReturnNode) { - end = b; - break outer; + int withRead = 0; + int returnBlocks = 0; + for (ReturnNode returnNode : graph.getNodes(ReturnNode.class)) { + Block block = schedule.getCFG().getNodeToBlock().get(returnNode); + for (Node node : schedule.getBlockToNodesMap().get(block)) { + if (node instanceof FloatingReadNode) { + withRead++; + break; } } + returnBlocks++; } - assertNotNull("no block with ReturnNode found", end); - boolean readEncountered = false; - for (Node node : schedule.getBlockToNodesMap().get(end)) { - if (node instanceof FloatingReadNode) { - readEncountered = true; - } - } - assertEquals(readEncountered, withinReturnBlock); + assertEquals(withRead == returnBlocks, withinReturnBlock); } private void assertReadWithinStartBlock(SchedulePhase schedule, boolean withinStartBlock) { diff -r 056d9d7dc061 -r c215dec9d3cf graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java Wed Jan 15 16:08:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java Wed Jan 15 16:11:56 2014 +0100 @@ -76,7 +76,6 @@ test("test1Snippet"); } - @Test(expected = AssertionError.class) public void test2() { test("test2Snippet"); } diff -r 056d9d7dc061 -r c215dec9d3cf graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EAMergingTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EAMergingTest.java Wed Jan 15 16:08:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EAMergingTest.java Wed Jan 15 16:11:56 2014 +0100 @@ -33,8 +33,9 @@ @Test public void testSimpleMerge() { testEscapeAnalysis("simpleMergeSnippet", null, false); - assertTrue(returnNode.result() instanceof PhiNode); - PhiNode phi = (PhiNode) returnNode.result(); + assertEquals(1, returnNodes.size()); + assertTrue(returnNodes.get(0).result() instanceof PhiNode); + PhiNode phi = (PhiNode) returnNodes.get(0).result(); assertTrue(phi.valueAt(0) instanceof ParameterNode); assertTrue(phi.valueAt(1) instanceof ParameterNode); } diff -r 056d9d7dc061 -r c215dec9d3cf graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java Wed Jan 15 16:08:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java Wed Jan 15 16:11:56 2014 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.compiler.test.ea; +import java.util.*; + import org.junit.*; import com.oracle.graal.api.code.*; @@ -119,7 +121,7 @@ protected StructuredGraph graph; protected HighTierContext context; - protected ReturnNode returnNode; + protected List returnNodes; /** * Runs Escape Analysis on the given snippet and makes sure that no allocations remain in the @@ -134,8 +136,10 @@ protected void testEscapeAnalysis(String snippet, final Constant expectedConstantResult, final boolean iterativeEscapeAnalysis) { prepareGraph(snippet, iterativeEscapeAnalysis); if (expectedConstantResult != null) { - Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant()); - Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant()); + for (ReturnNode returnNode : returnNodes) { + Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant()); + Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant()); + } } int newInstanceCount = graph.getNodes().filter(NewInstanceNode.class).count() + graph.getNodes().filter(NewArrayNode.class).count() + graph.getNodes().filter(CommitAllocationNode.class).count(); @@ -153,8 +157,7 @@ new DeadCodeEliminationPhase().apply(graph); new CanonicalizerPhase(true).apply(graph, context); new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(true)).apply(graph, context); - Assert.assertEquals(1, graph.getNodes().filter(ReturnNode.class).count()); - returnNode = graph.getNodes().filter(ReturnNode.class).first(); + returnNodes = graph.getNodes(ReturnNode.class).snapshot(); } catch (Throwable e) { throw Debug.handle(e); } diff -r 056d9d7dc061 -r c215dec9d3cf graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Wed Jan 15 16:08:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Wed Jan 15 16:11:56 2014 +0100 @@ -213,8 +213,9 @@ prepareGraph("testFullyUnrolledLoopSnippet", false); new LoopFullUnrollPhase(new CanonicalizerPhase(true)).apply(graph, context); new PartialEscapePhase(false, new CanonicalizerPhase(true)).apply(graph, context); - Assert.assertTrue(returnNode.result() instanceof AllocatedObjectNode); - CommitAllocationNode commit = ((AllocatedObjectNode) returnNode.result()).getCommit(); + Assert.assertEquals(1, returnNodes.size()); + Assert.assertTrue(returnNodes.get(0).result() instanceof AllocatedObjectNode); + CommitAllocationNode commit = ((AllocatedObjectNode) returnNodes.get(0).result()).getCommit(); Assert.assertEquals(2, commit.getValues().size()); Assert.assertEquals(1, commit.getVirtualObjects().size()); Assert.assertTrue("non-cyclic data structure expected", commit.getVirtualObjects().get(0) != commit.getValues().get(0)); diff -r 056d9d7dc061 -r c215dec9d3cf graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.java Wed Jan 15 16:08:57 2014 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.java Wed Jan 15 16:11:56 2014 +0100 @@ -86,8 +86,9 @@ @Test public void testMergedDouble() { testEscapeAnalysis("testMergedDoubleSnippet", null, false); - Assert.assertTrue(returnNode.result() instanceof PhiNode); - PhiNode phi = (PhiNode) returnNode.result(); + Assert.assertEquals(1, returnNodes.size()); + Assert.assertTrue(returnNodes.get(0).result() instanceof PhiNode); + PhiNode phi = (PhiNode) returnNodes.get(0).result(); Assert.assertTrue(phi.valueAt(0) instanceof LoadFieldNode); Assert.assertTrue(phi.valueAt(1) instanceof LoadFieldNode); } diff -r 056d9d7dc061 -r c215dec9d3cf 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 15 16:08:57 2014 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Jan 15 16:11:56 2014 +0100 @@ -120,7 +120,6 @@ private ValueNode methodSynchronizedObject; private ExceptionDispatchBlock unwindBlock; - private Block returnBlock; private FixedWithNextNode lastInstr; // the last instruction added @@ -198,7 +197,6 @@ this.stream = new BytecodeStream(method.getCode()); this.constantPool = method.getConstantPool(); unwindBlock = null; - returnBlock = null; methodSynchronizedObject = null; this.currentGraph = graph; this.frameState = new FrameStateBuilder(method, graph, graphBuilderConfig.eagerResolving()); @@ -270,7 +268,6 @@ for (Block block : blockMap.blocks) { processBlock(block); } - processBlock(returnBlock); processBlock(unwindBlock); Debug.dump(currentGraph, "After bytecode parsing"); @@ -305,16 +302,6 @@ return unwindBlock; } - private Block returnBlock(int bci) { - if (returnBlock == null) { - returnBlock = new Block(); - returnBlock.startBci = bci; - returnBlock.endBci = bci; - returnBlock.blockID = Integer.MAX_VALUE; - } - return returnBlock; - } - public BytecodeStream stream() { return stream; } @@ -1264,11 +1251,18 @@ } private void genReturn(ValueNode x) { + frameState.setRethrowException(false); frameState.clearStack(); - if (x != null) { - frameState.push(x.kind(), x); + if (graphBuilderConfig.eagerInfopointMode()) { + append(new InfopointNode(InfopointReason.METHOD_END, frameState.create(bci()))); } - appendGoto(createTarget(returnBlock(bci()), frameState)); + + synchronizedEpilogue(FrameState.AFTER_BCI, x); + if (frameState.lockDepth() != 0) { + throw new BailoutException("unbalanced monitors"); + } + + append(new ReturnNode(x)); } private MonitorEnterNode genMonitorEnter(ValueNode x) { @@ -1648,10 +1642,7 @@ ((MergeNode) lastInstr).setStateAfter(frameState.create(bci)); } - if (block == returnBlock) { - frameState.setRethrowException(false); - createReturn(); - } else if (block == unwindBlock) { + if (block == unwindBlock) { frameState.setRethrowException(false); createUnwind(); } else if (block instanceof ExceptionDispatchBlock) { @@ -1692,26 +1683,12 @@ append(new UnwindNode(exception)); } - private void createReturn() { - Kind returnKind = method.getSignature().getReturnKind().getStackKind(); - ValueNode x = returnKind == Kind.Void ? null : frameState.pop(returnKind); - assert frameState.stackSize() == 0; - - if (graphBuilderConfig.eagerInfopointMode()) { - append(new InfopointNode(InfopointReason.METHOD_END, frameState.create(bci()))); - } - - synchronizedEpilogue(FrameState.AFTER_BCI, x); - if (frameState.lockDepth() != 0) { - throw new BailoutException("unbalanced monitors"); - } - - append(new ReturnNode(x)); - } - private void synchronizedEpilogue(int bci, ValueNode returnValue) { if (Modifier.isSynchronized(method.getModifiers())) { MonitorExitNode monitorExit = genMonitorExit(methodSynchronizedObject, returnValue); + if (returnValue != null) { + frameState.push(returnValue.kind(), returnValue); + } monitorExit.setStateAfter(frameState.create(bci)); assert !frameState.rethrowException(); } diff -r 056d9d7dc061 -r c215dec9d3cf graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Wed Jan 15 16:08:57 2014 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Wed Jan 15 16:11:56 2014 +0100 @@ -1295,8 +1295,10 @@ */ public static Map inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) { final NodeInputList parameters = invoke.callTarget().arguments(); - StructuredGraph graph = invoke.asNode().graph(); + FixedNode invokeNode = invoke.asNode(); + StructuredGraph graph = invokeNode.graph(); assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal(); + Kind returnKind = invokeNode.kind(); FrameState stateAfter = invoke.stateAfter(); assert stateAfter == null || stateAfter.isAlive(); @@ -1305,7 +1307,7 @@ } ArrayList nodes = new ArrayList<>(inlineGraph.getNodes().count()); - ReturnNode returnNode = null; + ArrayList returnNodes = new ArrayList<>(4); UnwindNode unwindNode = null; final StartNode entryPointNode = inlineGraph.start(); FixedNode firstCFGNode = entryPointNode.next(); @@ -1318,8 +1320,7 @@ } else { nodes.add(node); if (node instanceof ReturnNode) { - assert returnNode == null; - returnNode = (ReturnNode) node; + returnNodes.add((ReturnNode) node); } else if (node instanceof UnwindNode) { assert unwindNode == null; unwindNode = (UnwindNode) node; @@ -1327,7 +1328,7 @@ } } - final AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(invoke.asNode()); + final AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(invokeNode); DuplicationReplacement localReplacement = new DuplicationReplacement() { public Node replacement(Node node) { @@ -1340,12 +1341,12 @@ } }; - assert invoke.asNode().successors().first() != null : invoke; - assert invoke.asNode().predecessor() != null; + assert invokeNode.successors().first() != null : invoke; + assert invokeNode.predecessor() != null; Map duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement); FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); - invoke.asNode().replaceAtPredecessor(firstCFGNodeDuplicate); + invokeNode.replaceAtPredecessor(firstCFGNodeDuplicate); FrameState stateAtExceptionEdge = null; if (invoke instanceof InvokeWithExceptionNode) { @@ -1400,7 +1401,8 @@ if (frameState != null) { assert frameState.bci != FrameState.BEFORE_BCI : frameState; if (frameState.bci == FrameState.AFTER_BCI) { - frameState.replaceAndDelete(stateAfter); + frameState.replaceAndDelete(returnKind == Kind.Void ? stateAfter : stateAfter.duplicateModified(stateAfter.bci, stateAfter.rethrowException(), returnKind, + frameState.stackAt(0))); } else if (frameState.bci == FrameState.AFTER_EXCEPTION_BCI) { if (frameState.isAlive()) { assert stateAtExceptionEdge != null; @@ -1413,7 +1415,7 @@ if (frameState.outerFrameState() == null) { assert frameState.bci == FrameState.INVALID_FRAMESTATE_BCI || frameState.method() == inlineGraph.method(); if (outerFrameState == null) { - outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.asNode().kind()); + outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invokeNode.kind()); outerFrameState.setDuringCall(true); } frameState.setOuterFrameState(outerFrameState); @@ -1430,27 +1432,55 @@ } else { assert checkContainsOnlyInvalidOrAfterFrameState(duplicates); } - Node returnValue = null; - if (returnNode != null) { - if (returnNode.result() instanceof ParameterNode) { - returnValue = localReplacement.replacement(returnNode.result()); - } else if (returnNode.result() != null) { - returnValue = duplicates.get(returnNode.result()); + if (!returnNodes.isEmpty()) { + FixedNode n = invoke.next(); + invoke.setNext(null); + if (returnNodes.size() == 1) { + ReturnNode returnNode = (ReturnNode) duplicates.get(returnNodes.get(0)); + Node returnValue = returnNode.result(); + invokeNode.replaceAtUsages(returnValue); + returnNode.clearInputs(); + returnNode.replaceAndDelete(n); + } else { + ArrayList returnDuplicates = new ArrayList<>(returnNodes.size()); + for (ReturnNode returnNode : returnNodes) { + returnDuplicates.add((ReturnNode) duplicates.get(returnNode)); + } + MergeNode merge = graph.add(new MergeNode()); + merge.setStateAfter(stateAfter); + ValueNode returnValue = mergeReturns(merge, returnDuplicates); + invokeNode.replaceAtUsages(returnValue); + merge.setNext(n); } - invoke.asNode().replaceAtUsages(returnValue); - Node returnDuplicate = duplicates.get(returnNode); - returnDuplicate.clearInputs(); - Node n = invoke.next(); - invoke.setNext(null); - returnDuplicate.replaceAndDelete(n); } - invoke.asNode().replaceAtUsages(null); - GraphUtil.killCFG(invoke.asNode()); + invokeNode.replaceAtUsages(null); + GraphUtil.killCFG(invokeNode); return duplicates; } + public static ValueNode mergeReturns(MergeNode merge, List returnNodes) { + PhiNode returnValuePhi = null; + + for (ReturnNode returnNode : returnNodes) { + // create and wire up a new EndNode + EndNode endNode = merge.graph().add(new EndNode()); + merge.addForwardEnd(endNode); + + if (returnNode.result() != null) { + if (returnValuePhi == null) { + returnValuePhi = merge.graph().addWithoutUnique(new PhiNode(returnNode.result().kind(), merge)); + } + returnValuePhi.addInput(returnNode.result()); + } + returnNode.clearInputs(); + returnNode.replaceAndDelete(endNode); + + } + return returnValuePhi; + } + private static boolean checkContainsOnlyInvalidOrAfterFrameState(Map duplicates) { for (Node node : duplicates.values()) { if (node instanceof FrameState) { diff -r 056d9d7dc061 -r c215dec9d3cf 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 15 16:08:57 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Wed Jan 15 16:11:56 2014 +0100 @@ -36,9 +36,8 @@ import com.oracle.graal.debug.*; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.debug.internal.*; +import com.oracle.graal.graph.*; import com.oracle.graal.graph.Graph.Mark; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; import com.oracle.graal.loop.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.GuardsStage; @@ -623,43 +622,49 @@ assert checkAllVarargPlaceholdersAreDeleted(parameterCount, placeholders); new FloatingReadPhase(FloatingReadPhase.ExecutionMode.ANALYSIS_ONLY).apply(snippetCopy); - this.memoryMap = null; this.snippet = snippetCopy; - ReturnNode retNode = null; + List returnNodes = new ArrayList<>(4); + List memMaps = new ArrayList<>(4); StartNode entryPointNode = snippet.start(); - nodes = new ArrayList<>(snippet.getNodeCount()); - boolean seenReturn = false; - boolean containsMemoryMap = false; - for (Node node : snippet.getNodes()) { - if (node == entryPointNode || node == entryPointNode.stateAfter()) { - // Do nothing. - } else { - nodes.add(node); - if (node instanceof ReturnNode) { - retNode = (ReturnNode) node; - NodeIterable memstates = retNode.inputs().filter(MemoryMapNode.class); - assert memstates.count() == 1; - memoryMap = memstates.first(); - retNode.replaceFirstInput(memoryMap, null); - memoryMap.safeDelete(); - - assert !seenReturn : "can handle only one ReturnNode"; - seenReturn = true; - } else if (node instanceof MemoryMapNode) { - containsMemoryMap = true; - } + for (ReturnNode retNode : snippet.getNodes(ReturnNode.class)) { + MemoryMapNode memMap = retNode.getMemoryMap(); + memMaps.add(memMap); + retNode.setMemoryMap(null); + returnNodes.add(retNode); + if (memMap.usages().isEmpty()) { + memMap.safeDelete(); } } - assert !containsMemoryMap; + assert snippet.getNodes().filter(MemoryMapNode.class).isEmpty(); + if (returnNodes.isEmpty()) { + this.returnNode = null; + this.memoryMap = null; + } else if (returnNodes.size() == 1) { + this.returnNode = returnNodes.get(0); + this.memoryMap = memMaps.get(0); + } else { + MergeNode merge = snippet.add(new MergeNode()); + ValueNode returnValue = InliningUtil.mergeReturns(merge, returnNodes); + this.returnNode = snippet.add(new ReturnNode(returnValue)); + this.memoryMap = FloatingReadPhase.mergeMemoryMaps(merge, memMaps); + merge.setNext(this.returnNode); + } this.sideEffectNodes = curSideEffectNodes; this.deoptNodes = curDeoptNodes; this.stampNodes = curStampNodes; - this.returnNode = retNode; + + nodes = new ArrayList<>(snippet.getNodeCount()); + for (Node node : snippet.getNodes()) { + if (node != entryPointNode && node != entryPointNode.stateAfter()) { + nodes.add(node); + } + } Debug.metric(debugValueName("SnippetTemplateNodeCount", args)).add(nodes.size()); args.info.notifyNewTemplate(); + Debug.dump(snippet, "SnippetTemplate final state"); } private static boolean checkAllVarargPlaceholdersAreDeleted(int parameterCount, VarargsPlaceholderNode[] placeholders) { @@ -737,7 +742,7 @@ /** * map of killing locations to memory checkpoints (nodes). */ - private MemoryMapNode memoryMap; + private final MemoryMapNode memoryMap; /** * Times instantiations of this template. @@ -1019,25 +1024,18 @@ } } - for (ValueNode stampNode : stampNodes) { - Node stampDup = duplicates.get(stampNode); - ((ValueNode) stampDup).setStamp(((ValueNode) replacee).stamp()); - } + updateStamps(replacee, duplicates); // Replace all usages of the replacee with the value returned by the snippet ValueNode returnValue = null; if (returnNode != null && !(replacee instanceof ControlSinkNode)) { - if (returnNode.result() instanceof ParameterNode) { - returnValue = (ValueNode) replacements.get(returnNode.result()); - } else if (returnNode.result() != null) { - returnValue = (ValueNode) duplicates.get(returnNode.result()); - } - Node returnDuplicate = duplicates.get(returnNode); + ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode); + returnValue = returnDuplicate.result(); MemoryMapNode mmap = new DuplicateMapper(duplicates, replaceeGraph.start()); if (returnValue == null && replacee.usages().isNotEmpty() && replacee instanceof MemoryCheckpoint) { replacer.replace(replacee, (ValueNode) returnDuplicate.predecessor(), mmap); } else { - assert returnValue != null || replacee.usages().isEmpty() : this + " " + returnValue + " " + returnNode + " " + replacee.usages(); + assert returnValue != null || replacee.usages().isEmpty(); replacer.replace(replacee, returnValue, mmap); } if (returnDuplicate.isAlive()) { @@ -1056,6 +1054,30 @@ } } + private void propagateStamp(Node node) { + if (node instanceof PhiNode) { + PhiNode phi = (PhiNode) node; + if (phi.inferPhiStamp()) { + for (Node usage : node.usages()) { + propagateStamp(usage); + } + } + } + } + + private void updateStamps(ValueNode replacee, Map duplicates) { + for (ValueNode stampNode : stampNodes) { + Node stampDup = duplicates.get(stampNode); + ((ValueNode) stampDup).setStamp(replacee.stamp()); + } + for (ParameterNode paramNode : snippet.getNodes(ParameterNode.class)) { + for (Node usage : paramNode.usages()) { + Node usageDup = duplicates.get(usage); + propagateStamp(usageDup); + } + } + } + /** * Gets a copy of the specialized graph. */ @@ -1102,23 +1124,14 @@ ((StateSplit) sideEffectDup).setStateAfter(((StateSplit) replacee).stateAfter()); } } - for (ValueNode stampNode : stampNodes) { - Node stampDup = duplicates.get(stampNode); - ((ValueNode) stampDup).setStamp(((ValueNode) replacee).stamp()); - } + updateStamps(replacee, duplicates); // Replace all usages of the replacee with the value returned by the snippet - assert returnNode != null : replaceeGraph; - ValueNode returnValue = null; - if (returnNode.result() instanceof ParameterNode) { - returnValue = (ValueNode) replacements.get(returnNode.result()); - } else { - returnValue = (ValueNode) duplicates.get(returnNode.result()); - } + ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode); + ValueNode returnValue = returnDuplicate.result(); assert returnValue != null || replacee.usages().isEmpty(); replacer.replace(replacee, returnValue, new DuplicateMapper(duplicates, replaceeGraph.start())); - Node returnDuplicate = duplicates.get(returnNode); if (returnDuplicate.isAlive()) { returnDuplicate.clearInputs(); returnDuplicate.replaceAndDelete(next);