# HG changeset patch # User Doug Simon # Date 1366901609 -7200 # Node ID 17b598df8da98447a90d1822612777d0f7729bc4 # Parent 261a43921c5e9468384e30b9c91cd8f599f384dc# Parent cadb3702cb8f1a8fdc45f752462d77f802738e5c Merge. diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java --- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Thu Apr 25 16:53:29 2013 +0200 @@ -26,6 +26,7 @@ import java.util.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.util.*; /** * Computes an ordering of the block that can be used by the linear scan register allocator and the @@ -66,11 +67,11 @@ * * @return sorted list of blocks */ - public static List computeLinearScanOrder(int blockCount, Block startBlock) { + public static List computeLinearScanOrder(int blockCount, Block startBlock, NodesToDoubles nodeProbabilities) { List order = new ArrayList<>(); BitSet visitedBlocks = new BitSet(blockCount); - PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks); - computeLinearScanOrder(order, worklist, visitedBlocks); + PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks, nodeProbabilities); + computeLinearScanOrder(order, worklist, visitedBlocks, nodeProbabilities); assert checkOrder(order, blockCount); return order; } @@ -80,11 +81,11 @@ * * @return sorted list of blocks */ - public static List computeCodeEmittingOrder(int blockCount, Block startBlock) { + public static List computeCodeEmittingOrder(int blockCount, Block startBlock, NodesToDoubles nodeProbabilities) { List order = new ArrayList<>(); BitSet visitedBlocks = new BitSet(blockCount); - PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks); - computeCodeEmittingOrder(order, worklist, visitedBlocks); + PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks, nodeProbabilities); + computeCodeEmittingOrder(order, worklist, visitedBlocks, nodeProbabilities); assert checkOrder(order, blockCount); return order; } @@ -92,28 +93,28 @@ /** * Iteratively adds paths to the code emission block order. */ - private static void computeCodeEmittingOrder(List order, PriorityQueue worklist, BitSet visitedBlocks) { + private static void computeCodeEmittingOrder(List order, PriorityQueue worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) { while (!worklist.isEmpty()) { Block nextImportantPath = worklist.poll(); - addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks); + addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks, nodeProbabilities); } } /** * Iteratively adds paths to the linear scan block order. */ - private static void computeLinearScanOrder(List order, PriorityQueue worklist, BitSet visitedBlocks) { + private static void computeLinearScanOrder(List order, PriorityQueue worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) { while (!worklist.isEmpty()) { Block nextImportantPath = worklist.poll(); - addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks); + addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks, nodeProbabilities); } } /** * Initializes the priority queue used for the work list of blocks and adds the start block. */ - private static PriorityQueue initializeWorklist(Block startBlock, BitSet visitedBlocks) { - PriorityQueue result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, blockComparator); + private static PriorityQueue initializeWorklist(Block startBlock, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) { + PriorityQueue result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator(nodeProbabilities)); result.add(startBlock); visitedBlocks.set(startBlock.getId()); return result; @@ -122,10 +123,10 @@ /** * Add a linear path to the linear scan order greedily following the most likely successor. */ - private static void addPathToLinearScanOrder(Block block, List order, PriorityQueue worklist, BitSet visitedBlocks) { + private static void addPathToLinearScanOrder(Block block, List order, PriorityQueue worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) { block.setLinearScanNumber(order.size()); order.add(block); - Block mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks); + Block mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, nodeProbabilities); enqueueSuccessors(block, worklist, visitedBlocks); if (mostLikelySuccessor != null) { if (!mostLikelySuccessor.isLoopHeader() && mostLikelySuccessor.getPredecessorCount() > 1) { @@ -134,24 +135,24 @@ double unscheduledSum = 0.0; for (Block pred : mostLikelySuccessor.getPredecessors()) { if (pred.getLinearScanNumber() == -1) { - unscheduledSum += pred.getBeginNode().probability(); + unscheduledSum += nodeProbabilities.get(pred.getBeginNode()); } } - if (unscheduledSum > block.getProbability() / PENALTY_VERSUS_UNSCHEDULED) { + if (unscheduledSum > nodeProbabilities.get(block.getBeginNode()) / PENALTY_VERSUS_UNSCHEDULED) { // Add this merge only after at least one additional predecessor gets scheduled. visitedBlocks.clear(mostLikelySuccessor.getId()); return; } } - addPathToLinearScanOrder(mostLikelySuccessor, order, worklist, visitedBlocks); + addPathToLinearScanOrder(mostLikelySuccessor, order, worklist, visitedBlocks, nodeProbabilities); } } /** * Add a linear path to the code emission order greedily following the most likely successor. */ - private static void addPathToCodeEmittingOrder(Block block, List order, PriorityQueue worklist, BitSet visitedBlocks) { + private static void addPathToCodeEmittingOrder(Block block, List order, PriorityQueue worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) { // Skip loop headers if there is only a single loop end block to make the backward jump be a // conditional jump. @@ -180,10 +181,10 @@ } } - Block mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks); + Block mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, nodeProbabilities); enqueueSuccessors(block, worklist, visitedBlocks); if (mostLikelySuccessor != null) { - addPathToCodeEmittingOrder(mostLikelySuccessor, order, worklist, visitedBlocks); + addPathToCodeEmittingOrder(mostLikelySuccessor, order, worklist, visitedBlocks, nodeProbabilities); } } @@ -198,11 +199,12 @@ /** * Find the highest likely unvisited successor block of a given block. */ - private static Block findAndMarkMostLikelySuccessor(Block block, BitSet visitedBlocks) { + private static Block findAndMarkMostLikelySuccessor(Block block, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) { Block result = null; for (Block successor : block.getSuccessors()) { - assert successor.getProbability() >= 0.0 : "Probabilities must be positive"; - if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && (result == null || successor.getProbability() >= result.getProbability())) { + assert nodeProbabilities.get(successor.getBeginNode()) >= 0.0 : "Probabilities must be positive"; + if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && + (result == null || nodeProbabilities.get(successor.getBeginNode()) >= nodeProbabilities.get(result.getBeginNode()))) { result = successor; } } @@ -243,7 +245,13 @@ /** * Comparator for sorting blocks based on loop depth and probability. */ - private static Comparator blockComparator = new Comparator() { + private static class BlockOrderComparator implements Comparator { + + private final NodesToDoubles probabilities; + + public BlockOrderComparator(NodesToDoubles probabilities) { + this.probabilities = probabilities; + } @Override public int compare(Block a, Block b) { @@ -254,11 +262,11 @@ } // Blocks with high probability before blocks with low probability. - if (a.getProbability() > b.getProbability()) { + if (probabilities.get(a.getBeginNode()) > probabilities.get(b.getBeginNode())) { return -1; } else { return 1; } } - }; + } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -306,9 +306,8 @@ private void processMethod(final String snippet) { graph = parse(snippet); - new ComputeProbabilityPhase().apply(graph); Assumptions assumptions = new Assumptions(false); - HighTierContext context = new HighTierContext(runtime(), assumptions); + HighTierContext context = new HighTierContext(runtime(), assumptions, replacements); new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); new PartialEscapeAnalysisPhase(false, false).apply(graph, context); new CullFrameStatesPhase().apply(graph); @@ -325,9 +324,8 @@ public void run() { graph = parse(snippet); - new ComputeProbabilityPhase().apply(graph); Assumptions assumptions = new Assumptions(false); - HighTierContext context = new HighTierContext(runtime(), assumptions); + HighTierContext context = new HighTierContext(runtime(), assumptions, replacements); new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); if (loopPeeling) { new LoopTransformHighPhase().apply(graph); diff -r 261a43921c5e -r 17b598df8da9 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 Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -29,7 +29,9 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.Lowerable.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; public class FloatingReadTest extends GraphScheduleTest { @@ -57,7 +59,8 @@ public void run() { StructuredGraph graph = parse(snippet); - new LoweringPhase(null, runtime(), replacements, new Assumptions(false)).apply(graph); + HighTierContext context = new HighTierContext(runtime(), new Assumptions(false), replacements); + new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context); new FloatingReadPhase().apply(graph); ReturnNode returnNode = null; diff -r 261a43921c5e -r 17b598df8da9 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 Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -33,10 +33,12 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.Lowerable.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.schedule.*; +import com.oracle.graal.phases.tiers.*; /** * In these test the FrameStates are explicitly cleared out, so that the scheduling of @@ -221,7 +223,8 @@ Assumptions assumptions = new Assumptions(false); new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); } - new LoweringPhase(null, runtime(), replacements, new Assumptions(false)).apply(graph); + HighTierContext context = new HighTierContext(runtime(), new Assumptions(false), replacements); + new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context); if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { for (Node node : graph.getNodes()) { if (node instanceof StateSplit) { diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -32,7 +32,9 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.Lowerable.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; public class PushNodesThroughPiTest extends GraalCompilerTest { @@ -82,10 +84,11 @@ private StructuredGraph compileTestSnippet(final String snippet) { StructuredGraph graph = parse(snippet); - new LoweringPhase(null, runtime(), replacements, new Assumptions(false)).apply(graph); - new CanonicalizerPhase.Instance(runtime(), null).apply(graph); + HighTierContext context = new HighTierContext(runtime(), new Assumptions(false), replacements); + new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context); + new CanonicalizerPhase().apply(graph, context); new PushThroughPiPhase().apply(graph); - new CanonicalizerPhase.Instance(runtime(), null).apply(graph); + new CanonicalizerPhase().apply(graph, context); return graph; } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -32,7 +32,9 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.Lowerable.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; /* consider * B b = (B) a; @@ -85,11 +87,12 @@ // structure changes significantly public void run() { StructuredGraph graph = parse(snippet); - new LoweringPhase(null, runtime(), replacements, new Assumptions(false)).apply(graph); + HighTierContext context = new HighTierContext(runtime(), new Assumptions(false), replacements); + new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context); new FloatingReadPhase().apply(graph); new EliminatePartiallyRedundantGuardsPhase(true, false).apply(graph); new ReadEliminationPhase().apply(graph); - new CanonicalizerPhase.Instance(runtime(), null).apply(graph); + new CanonicalizerPhase().apply(graph, context); Debug.dump(graph, "After lowering"); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierAdditionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierAdditionTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 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.graal.compiler.test; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.hotspot.phases.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.WriteNode.WriteBarrierType; +import com.oracle.graal.nodes.spi.Lowerable.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; + +public class WriteBarrierAdditionTest extends GraalCompilerTest { + + public static class Container { + + public Container a; + public Container b; + } + + public static void test1Snippet() { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + main.a = temp1; + main.b = temp2; + } + + public static void test2Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + for (int i = 0; i < 10; i++) { + if (test) { + main.a = temp1; + main.b = temp2; + } else { + main.a = temp2; + main.b = temp1; + } + } + } + + public static void test3Snippet() { + Container[] main = new Container[10]; + Container temp1 = new Container(); + Container temp2 = new Container(); + for (int i = 0; i < 10; i++) { + main[i].a = main[i].b = temp1; + } + + for (int i = 0; i < 10; i++) { + main[i].a = main[i].b = temp2; + } + + } + + @Test + public void test1() { + test("test1Snippet", 2); + } + + @Test + public void test2() { + test("test2Snippet", 4); + } + + @Test + public void test3() { + test("test3Snippet", 4); + } + + private void test(final String snippet, final int expectedBarriers) { + Debug.scope("WriteBarrierAditionTest", new DebugDumpScope(snippet), new Runnable() { + + public void run() { + StructuredGraph graph = parse(snippet); + HighTierContext context = new HighTierContext(runtime(), new Assumptions(false), replacements); + new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context); + new WriteBarrierAdditionPhase().apply(graph); + Debug.dump(graph, "After Write Barrier Addition"); + final int barriers = graph.getNodes(SerialWriteBarrier.class).count(); + Assert.assertTrue(barriers == expectedBarriers); + for (WriteNode write : graph.getNodes(WriteNode.class)) { + if (write.getWriteBarrierType() != WriteBarrierType.NONE) { + Assert.assertTrue(write.successors().count() == 1); + Assert.assertTrue(write.next() instanceof SerialWriteBarrier); + } + } + } + }); + } +} diff -r 261a43921c5e -r 17b598df8da9 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 Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -218,12 +218,9 @@ public ReturnNode call() { new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); - for (Invoke n : graph.getInvokes()) { - n.setInliningRelevance(1); - } Assumptions assumptions = new Assumptions(false); - HighTierContext context = new HighTierContext(runtime(), assumptions); + HighTierContext context = new HighTierContext(runtime(), assumptions, replacements); new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); new DeadCodeEliminationPhase().apply(graph); new PartialEscapeAnalysisPhase(iterativeEscapeAnalysis, false).apply(graph, context); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -33,7 +33,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.phases.ea.*; @@ -101,9 +100,8 @@ private void processMethod(final String snippet) { graph = parse(snippet); - new ComputeProbabilityPhase().apply(graph); GraalOptions.OptEarlyReadElimination = true; - HighTierContext context = new HighTierContext(runtime(), new Assumptions(false)); + HighTierContext context = new HighTierContext(runtime(), new Assumptions(false), replacements); new IterativeInliningPhase(replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL, false).apply(graph, context); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -221,9 +221,8 @@ private void processMethod(final String snippet) { graph = parse(snippet); - new ComputeProbabilityPhase().apply(graph); Assumptions assumptions = new Assumptions(false); - HighTierContext context = new HighTierContext(runtime(), assumptions); + HighTierContext context = new HighTierContext(runtime(), assumptions, replacements); new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); new PartialEscapeAnalysisPhase(false, true).apply(graph, context); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -34,8 +34,10 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.nodes.*; import com.oracle.graal.virtual.phases.ea.*; @@ -131,10 +133,12 @@ try { Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", result.getNodes(NewInstanceNode.class).isEmpty()); Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", result.getNodes(NewArrayNode.class).isEmpty()); + + NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(result).apply(); double probabilitySum = 0; int materializeCount = 0; for (MaterializeObjectNode materialize : result.getNodes(MaterializeObjectNode.class)) { - probabilitySum += materialize.probability(); + probabilitySum += nodeProbabilities.get(materialize); materializeCount++; } Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount); @@ -156,12 +160,9 @@ @Override public StructuredGraph call() { StructuredGraph graph = parse(snippet); - new ComputeProbabilityPhase().apply(graph); - for (Invoke n : graph.getInvokes()) { - n.asNode().setProbability(100000); - } + Assumptions assumptions = new Assumptions(false); - HighTierContext context = new HighTierContext(runtime(), assumptions); + HighTierContext context = new HighTierContext(runtime(), assumptions, replacements); new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); new DeadCodeEliminationPhase().apply(graph); new CanonicalizerPhase().apply(graph, context); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -158,7 +158,6 @@ StructuredGraph graph = eagerInfopointMode ? parseDebug(method) : parse(method); PhasePlan phasePlan = getDefaultPhasePlan(eagerInfopointMode); Assumptions assumptions = new Assumptions(true); - new ComputeProbabilityPhase().apply(graph); Debug.dump(graph, "Graph"); new InliningPhase(runtime(), null, replacements, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); Debug.dump(graph, "Graph"); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Thu Apr 25 16:53:29 2013 +0200 @@ -38,9 +38,11 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.PhasePlan.PhasePosition; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.schedule.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.phases.ea.*; @@ -99,8 +101,8 @@ * * @param target */ - public static LIR emitHIR(GraalCodeCacheProvider runtime, TargetDescription target, StructuredGraph graph, Replacements replacements, Assumptions assumptions, GraphCache cache, PhasePlan plan, - OptimisticOptimizations optimisticOpts, final SpeculationLog speculationLog) { + public static LIR emitHIR(GraalCodeCacheProvider runtime, TargetDescription target, final StructuredGraph graph, Replacements replacements, Assumptions assumptions, GraphCache cache, + PhasePlan plan, OptimisticOptimizations optimisticOpts, final SpeculationLog speculationLog) { if (speculationLog != null) { speculationLog.snapshot(); @@ -113,15 +115,11 @@ Debug.dump(graph, "initial state"); } - if (GraalOptions.ProbabilityAnalysis && graph.start().probability() == 0) { - new ComputeProbabilityPhase().apply(graph); - } - if (GraalOptions.OptCanonicalizer) { new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph); } - HighTierContext highTierContext = new HighTierContext(runtime, assumptions); + HighTierContext highTierContext = new HighTierContext(runtime, assumptions, replacements); if (GraalOptions.Inline && !plan.isPhaseDisabled(InliningPhase.class)) { if (GraalOptions.IterativeInlining) { @@ -141,25 +139,13 @@ Suites.DEFAULT.getHighTier().apply(graph, highTierContext); - new LoweringPhase(target, runtime, replacements, assumptions).apply(graph); - - MidTierContext midTierContext = new MidTierContext(runtime, assumptions, replacements); + MidTierContext midTierContext = new MidTierContext(runtime, assumptions, replacements, target); Suites.DEFAULT.getMidTier().apply(graph, midTierContext); - plan.runPhases(PhasePosition.MID_LEVEL, graph); - - // Add safepoints to loops - new SafepointInsertionPhase().apply(graph); - - new GuardLoweringPhase(target).apply(graph); - plan.runPhases(PhasePosition.LOW_LEVEL, graph); - new LoweringPhase(target, runtime, replacements, assumptions).apply(graph); - - new FrameStateAssignmentPhase().apply(graph); - - new DeadCodeEliminationPhase().apply(graph); + LowTierContext lowTierContext = new LowTierContext(runtime, assumptions, replacements, target); + Suites.DEFAULT.getLowTier().apply(graph, lowTierContext); final SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph); @@ -170,14 +156,13 @@ assert startBlock != null; assert startBlock.getPredecessorCount() == 0; - new ComputeProbabilityPhase().apply(graph); - return Debug.scope("ComputeLinearScanOrder", new Callable() { @Override public LIR call() { - List codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock); - List linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock); + NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply(); + List codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock, nodeProbabilities); + List linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock, nodeProbabilities); LIR lir = new LIR(schedule.getCFG(), schedule.getBlockToNodesMap(), linearScanOrder, codeEmittingOrder, speculationLog); Debug.dump(lir, "After linear scan order"); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BasicCompilerConfiguration.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BasicCompilerConfiguration.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BasicCompilerConfiguration.java Thu Apr 25 16:53:29 2013 +0200 @@ -36,4 +36,8 @@ public PhaseSuite createMidTier() { return new MidTier(); } + + public PhaseSuite createLowTier() { + return new LowTier(); + } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Thu Apr 25 16:53:29 2013 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.compiler.phases; import com.oracle.graal.loop.phases.*; +import com.oracle.graal.nodes.spi.Lowerable.LoweringType; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.tiers.*; @@ -68,6 +69,8 @@ if (GraalOptions.OptCanonicalizer) { addPhase(new CanonicalizerPhase()); } + + addPhase(new LoweringPhase(LoweringType.BEFORE_GUARDS)); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 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.graal.compiler.phases; + +import com.oracle.graal.nodes.spi.Lowerable.LoweringType; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; + +public class LowTier extends PhaseSuite { + + public LowTier() { + addPhase(new LoweringPhase(LoweringType.AFTER_GUARDS)); + + addPhase(new FrameStateAssignmentPhase()); + + addPhase(new DeadCodeEliminationPhase()); + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java Thu Apr 25 16:53:29 2013 +0200 @@ -65,5 +65,10 @@ if (GraalOptions.OptCanonicalizer) { addPhase(new CanonicalizerPhase()); } + + // Add safepoints to loops + addPhase(new SafepointInsertionPhase()); + + addPhase(new GuardLoweringPhase()); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java --- a/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -30,6 +30,7 @@ import org.junit.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.Register.RegisterFlag; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.asm.amd64.*; @@ -70,8 +71,9 @@ @Override public void generateCode(AMD64Assembler asm) { - asm.addl(rsi, 5); - asm.movl(rax, rsi); + Register arg = getArgumentRegister(0, RegisterFlag.CPU); + asm.addl(arg, 5); + asm.movl(rax, arg); asm.ret(0); } }); @@ -87,8 +89,9 @@ @Override public void generateCode(AMD64Assembler asm) { - asm.addq(rsi, 1); - asm.movq(rax, rsi); + Register arg = getArgumentRegister(0, RegisterFlag.CPU); + asm.addq(arg, 1); + asm.movq(rax, arg); asm.ret(0); } }); @@ -113,4 +116,9 @@ Assert.assertArrayEquals(expectedCode, actualCode); } + + private Register getArgumentRegister(int index, RegisterFlag flag) { + Register[] regs = runtime.lookupRegisterConfig().getCallingConventionRegisters(CallingConvention.Type.JavaCall, flag); + return regs[index]; + } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Thu Apr 25 16:53:29 2013 +0200 @@ -43,11 +43,11 @@ import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.ParametersOp; +import com.oracle.graal.lir.StandardOp.PlaceholderOp; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; /** @@ -71,15 +71,43 @@ StackSlot deoptimizationRescueSlot; /** - * The position at which the instruction for saving RBP should be inserted. + * Utility for emitting the instruction to save RBP. */ - Block saveRbpBlock; - int saveRbpIndex; + class SaveRbp { + + final PlaceholderOp placeholder; + + /** + * The slot reserved for saving RBP. + */ + final StackSlot reservedSlot; + + public SaveRbp(PlaceholderOp placeholder) { + this.placeholder = placeholder; + this.reservedSlot = frameMap.allocateSpillSlot(Kind.Long); + assert reservedSlot.getRawOffset() == -16 : reservedSlot.getRawOffset(); + } - /** - * The slot reserved for saving RBP. - */ - StackSlot rbpSlot; + /** + * Replaces this operation with the appropriate move for saving rbp. + * + * @param useStack specifies if rbp must be saved to the stack + */ + public AllocatableValue finalize(boolean useStack) { + AllocatableValue dst; + if (useStack) { + dst = reservedSlot; + } else { + frameMap.freeSpillSlot(reservedSlot); + dst = newVariable(Kind.Long); + } + + placeholder.replace(lir, new MoveFromRegOp(dst, rbp.asValue(Kind.Long))); + return dst; + } + } + + private SaveRbp saveRbp; /** * List of epilogue operations that need to restore RBP. @@ -119,11 +147,9 @@ ParametersOp paramsOp = new ParametersOp(params); append(paramsOp); - saveRbpBlock = currentBlock; - saveRbpIndex = lir.lir(saveRbpBlock).size(); - append(paramsOp); // placeholder - rbpSlot = frameMap.allocateSpillSlot(Kind.Long); - assert rbpSlot.getRawOffset() == -16 : rbpSlot.getRawOffset(); + + saveRbp = new SaveRbp(new PlaceholderOp(currentBlock, lir.lir(currentBlock).size())); + append(saveRbp.placeholder); for (LocalNode local : graph.getNodes(LocalNode.class)) { Value param = params[local.index()]; @@ -238,23 +264,14 @@ @Override public void beforeRegisterAllocation() { - assert rbpSlot != null; - RegisterValue rbpParam = rbp.asValue(Kind.Long); - AllocatableValue savedRbp; - LIRInstruction saveRbp; - if (lir.hasDebugInfo()) { - savedRbp = rbpSlot; + boolean hasDebugInfo = lir.hasDebugInfo(); + AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo); + if (hasDebugInfo) { deoptimizationRescueSlot = frameMap.allocateSpillSlot(Kind.Long); - } else { - frameMap.freeSpillSlot(rbpSlot); - savedRbp = newVariable(Kind.Long); } for (AMD64HotSpotEpilogueOp op : epilogueOps) { op.savedRbp = savedRbp; } - - saveRbp = new MoveFromRegOp(savedRbp, rbpParam); - lir.lir(saveRbpBlock).set(saveRbpIndex, saveRbp); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -44,7 +44,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { byte[] formatBytes = string.getBytes(); long cstring = unsafe.allocateMemory(formatBytes.length + 1); for (int i = 0; i < formatBytes.length; i++) { diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -52,7 +52,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { if (code.isConstant() && code.asConstant().asObject() instanceof HotSpotInstalledCode) { HotSpotInstalledCode hsCode = (HotSpotInstalledCode) code.asConstant().asObject(); InvokeNode invoke = replaceWithInvoke(tool.getRuntime()); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -82,7 +82,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -64,7 +64,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TLABAllocateNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TLABAllocateNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TLABAllocateNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -45,7 +45,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPost.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPost.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPost.java Thu Apr 25 16:53:29 2013 +0200 @@ -58,7 +58,7 @@ this.precise = precise; } - public void lower(LoweringTool generator) { + public void lower(LoweringTool generator, LoweringType loweringType) { generator.getRuntime().lower(this, generator); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPre.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPre.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPre.java Thu Apr 25 16:53:29 2013 +0200 @@ -58,7 +58,7 @@ this.expectedObject = expectedObject; } - public void lower(LoweringTool generator) { + public void lower(LoweringTool generator, LoweringType loweringType) { generator.getRuntime().lower(this, generator); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -82,7 +82,7 @@ } // the canonicalization before loop unrolling is needed to propagate the length into // additions, etc. - HighTierContext context = new HighTierContext(tool.getRuntime(), tool.assumptions()); + HighTierContext context = new HighTierContext(tool.getRuntime(), tool.assumptions(), tool.getReplacements()); new CanonicalizerPhase().apply(snippetGraph, context); new LoopFullUnrollPhase().apply(snippetGraph, context); new CanonicalizerPhase().apply(snippetGraph, context); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -43,13 +43,14 @@ private ConstantNode getConstantCallTarget(MetaAccessProvider metaAccessProvider, Assumptions assumptions) { if (getCallSite().isConstant() && !getCallSite().isNullConstant()) { CallSite callSite = (CallSite) getCallSite().asConstant().asObject(); - if (callSite instanceof ConstantCallSite) { - return ConstantNode.forObject(callSite.getTarget(), metaAccessProvider, graph()); - } else if (callSite instanceof MutableCallSite || callSite instanceof VolatileCallSite && assumptions != null && assumptions.useOptimisticAssumptions()) { - MethodHandle target = callSite.getTarget(); + MethodHandle target = callSite.getTarget(); + if (!(callSite instanceof ConstantCallSite)) { + if (assumptions == null || !assumptions.useOptimisticAssumptions()) { + return null; + } assumptions.record(new Assumptions.CallSiteTargetValue(callSite, target)); - return ConstantNode.forObject(target, metaAccessProvider, graph()); } + return ConstantNode.forObject(target, metaAccessProvider, graph()); } return null; } @@ -65,7 +66,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { StructuredGraph graph = (StructuredGraph) graph(); ConstantNode target = getConstantCallTarget(tool.getRuntime(), tool.assumptions()); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Thu Apr 25 16:53:29 2013 +0200 @@ -96,11 +96,16 @@ /** * Size of the area occupied by outgoing overflow arguments. This value is adjusted as calling - * conventions for outgoing calls are retrieved. + * conventions for outgoing calls are retrieved. On some platforms, there is a minimum */ private int outgoingSize; /** + * Determines if this frame has values on the stack for outgoing calls. + */ + private boolean hasOutgoingStackArguments; + + /** * The list of stack areas allocated in this frame that are present in every reference map. */ private final List objectStackBlocks; @@ -157,8 +162,8 @@ * {@link Architecture#getReturnAddressSize() return address slot}. */ public boolean frameNeedsAllocating() { - int unalignedFrameSize = outgoingSize + spillSize - returnAddressSize(); - return unalignedFrameSize != 0; + int unalignedFrameSize = spillSize - returnAddressSize(); + return hasOutgoingStackArguments || unalignedFrameSize != 0; } /** @@ -247,6 +252,7 @@ public void reserveOutgoing(int argsSize) { assert frameSize == -1 : "frame size must not yet be fixed"; outgoingSize = Math.max(outgoingSize, argsSize); + hasOutgoingStackArguments = hasOutgoingStackArguments || argsSize > 0; } private StackSlot getSlot(Kind kind, int additionalOffset) { diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java Thu Apr 25 16:53:29 2013 +0200 @@ -117,6 +117,6 @@ @Override public String toString() { - return debugInfo != null ? debugInfo.toString() : topFrame.toString(); + return debugInfo != null ? debugInfo.toString() : topFrame != null ? topFrame.toString() : ""; } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Thu Apr 25 16:53:29 2013 +0200 @@ -24,7 +24,10 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; +import com.oracle.graal.graph.*; import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.cfg.*; + import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; /** @@ -135,4 +138,34 @@ // No code to emit. } } + + /** + * Placeholder for a LIR instruction that will be subsequently replaced. + */ + public static class PlaceholderOp extends LIRInstruction { + + /** + * The block in which this instruction is located. + */ + final Block block; + + /** + * The block index of this instruction. + */ + final int index; + + public PlaceholderOp(Block block, int index) { + this.block = block; + this.index = index; + } + + public void replace(LIR lir, LIRInstruction replacement) { + lir.lir(block).set(index, replacement); + } + + @Override + public void emitCode(TargetMethodAssembler tasm) { + throw new GraalInternalError(this + " should have been replaced"); + } + } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Thu Apr 25 16:53:29 2013 +0200 @@ -248,7 +248,6 @@ continue; } MergeNode merge = graph.add(new MergeNode()); - merge.setProbability(next.probability()); EndNode originalEnd = graph.add(new EndNode()); EndNode newEnd = graph.add(new EndNode()); merge.addForwardEnd(originalEnd); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java Thu Apr 25 16:53:29 2013 +0200 @@ -102,7 +102,6 @@ GraphUtil.killWithUnusedFloatingInputs(state); } loop.entryPoint().replaceAtPredecessor(entry); - end.setProbability(loop.entryPoint().probability()); end.setNext(loop.entryPoint()); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Thu Apr 25 16:53:29 2013 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; public abstract class LoopPolicies { @@ -35,9 +36,9 @@ } // TODO (gd) change when inversion is available - public static boolean shouldPeel(LoopEx loop) { + public static boolean shouldPeel(LoopEx loop, NodesToDoubles probabilities) { LoopBeginNode loopBegin = loop.loopBegin(); - double entryProbability = loopBegin.forwardEnd().probability(); + double entryProbability = probabilities.get(loopBegin.forwardEnd()); return entryProbability > GraalOptions.MinimumPeelProbability && loop.size() + loopBegin.graph().getNodeCount() < GraalOptions.MaximumDesiredSize; } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java Thu Apr 25 16:53:29 2013 +0200 @@ -27,7 +27,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.loop.InductionVariable.*; +import com.oracle.graal.loop.InductionVariable.Direction; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; @@ -39,7 +39,6 @@ private ControlFlowGraph cfg; public LoopsData(final StructuredGraph graph) { - cfg = Debug.scope("ControlFlowGraph", new Callable() { @Override diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java Thu Apr 25 16:53:29 2013 +0200 @@ -25,7 +25,9 @@ import com.oracle.graal.debug.*; import com.oracle.graal.loop.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; public class LoopTransformHighPhase extends Phase { @@ -33,9 +35,10 @@ protected void run(StructuredGraph graph) { if (graph.hasLoops()) { if (GraalOptions.LoopPeeling) { + NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply(); LoopsData data = new LoopsData(graph); for (LoopEx loop : data.outterFirst()) { - if (LoopPolicies.shouldPeel(loop)) { + if (LoopPolicies.shouldPeel(loop, probabilities)) { Debug.log("Peeling %s", loop); LoopTransformations.peel(loop); Debug.dump(graph, "After peeling %s", loop); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -51,7 +51,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 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 Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -96,7 +96,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -28,8 +28,6 @@ public abstract class FixedNode extends ValueNode { - private double probability; - public FixedNode(Stamp stamp) { super(stamp); } @@ -42,20 +40,6 @@ super(stamp, dependencies); } - public double probability() { - return probability; - } - - public void setProbability(double probability) { - assert probability >= 0 : String.format("Invalid argument %f, because the probability of a node must not be negative.", probability); - this.probability = probability; - assert !Double.isNaN(probability); - } - - protected void copyInto(FixedNode newNode) { - newNode.setProbability(probability); - } - @Override public boolean verify() { assertTrue(this.successors().isNotEmpty() || this.predecessor() != null, "FixedNode should not float"); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -361,13 +361,10 @@ PhiNode oldPhi = (PhiNode) oldMerge.usages().first(); PhiNode newPhi = graph().add(new PhiNode(oldPhi.stamp(), newMerge)); - double probability = 0.0; for (EndNode end : ends) { newPhi.addInput(phiValues.get(end)); newMerge.addForwardEnd(end); - probability += end.probability(); } - newMerge.setProbability(probability); FrameState stateAfter = oldMerge.stateAfter(); if (stateAfter != null) { diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Thu Apr 25 16:53:29 2013 +0200 @@ -45,14 +45,6 @@ void intrinsify(Node node); - double probability(); - - void setProbability(double value); - - double inliningRelevance(); - - void setInliningRelevance(double value); - boolean useForInlining(); void setUseForInlining(boolean value); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -41,7 +41,6 @@ private final int bci; private boolean polymorphic; private boolean useForInlining; - private double inliningRelevance; /** * Constructs a new Invoke instruction. @@ -55,7 +54,6 @@ this.bci = bci; this.polymorphic = false; this.useForInlining = true; - this.inliningRelevance = Double.NaN; } @Override @@ -83,16 +81,6 @@ } @Override - public double inliningRelevance() { - return inliningRelevance; - } - - @Override - public void setInliningRelevance(double value) { - inliningRelevance = value; - } - - @Override public Map getDebugProperties(Map map) { Map debugProperties = super.getDebugProperties(map); debugProperties.put("targetMethod", callTarget.targetName()); @@ -105,7 +93,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -42,7 +42,6 @@ private final int bci; private boolean polymorphic; private boolean useForInlining; - private double inliningRelevance; public InvokeWithExceptionNode(CallTargetNode callTarget, DispatchBeginNode exceptionEdge, int bci) { super(callTarget.returnStamp()); @@ -51,7 +50,6 @@ this.callTarget = callTarget; this.polymorphic = false; this.useForInlining = true; - this.inliningRelevance = Double.NaN; } public DispatchBeginNode exceptionEdge() { @@ -101,16 +99,6 @@ } @Override - public double inliningRelevance() { - return inliningRelevance; - } - - @Override - public void setInliningRelevance(double value) { - inliningRelevance = value; - } - - @Override public String toString(Verbosity verbosity) { if (verbosity == Verbosity.Long) { return super.toString(Verbosity.Short) + "(bci=" + bci() + ")"; @@ -140,7 +128,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialArrayRangeWriteBarrier.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialArrayRangeWriteBarrier.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialArrayRangeWriteBarrier.java Thu Apr 25 16:53:29 2013 +0200 @@ -51,7 +51,7 @@ } - public void lower(LoweringTool generator) { + public void lower(LoweringTool generator, LoweringType loweringType) { generator.getRuntime().lower(this, generator); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialWriteBarrier.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialWriteBarrier.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialWriteBarrier.java Thu Apr 25 16:53:29 2013 +0200 @@ -22,11 +22,12 @@ */ package com.oracle.graal.nodes; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public final class SerialWriteBarrier extends FixedWithNextNode implements Lowerable { +public final class SerialWriteBarrier extends FixedWithNextNode implements Lowerable, Node.IterableNodeType { @Input private ValueNode object; @Input private LocationNode location; @@ -52,7 +53,8 @@ } @Override - public void lower(LoweringTool generator) { + public void lower(LoweringTool generator, LoweringType loweringType) { + assert loweringType == LoweringType.AFTER_GUARDS; generator.getRuntime().lower(this, generator); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Thu Apr 25 16:53:29 2013 +0200 @@ -236,7 +236,6 @@ public void replaceFixedWithFixed(FixedWithNextNode node, FixedWithNextNode replacement) { assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement; - replacement.setProbability(node.probability()); FixedNode next = node.next(); node.setNext(null); replacement.setNext(next); @@ -307,7 +306,6 @@ public void addAfterFixed(FixedWithNextNode node, FixedNode newNode) { assert node != null && newNode != null && node.isAlive() && newNode.isAlive() : "cannot add " + newNode + " after " + node; - newNode.setProbability(node.probability()); FixedNode next = node.next(); node.setNext(newNode); if (next != null) { @@ -322,7 +320,6 @@ assert node != null && newNode != null && node.isAlive() && newNode.isAlive() : "cannot add " + newNode + " before " + node; assert node.predecessor() != null && node.predecessor() instanceof FixedWithNextNode : "cannot add " + newNode + " before " + node; assert newNode.next() == null : newNode; - newNode.setProbability(node.probability()); FixedWithNextNode pred = (FixedWithNextNode) node.predecessor(); pred.setNext(newNode); newNode.setNext(node); @@ -334,7 +331,6 @@ reduceTrivialMerge(begin); } else { // convert to merge MergeNode merge = this.add(new MergeNode()); - merge.setProbability(begin.probability()); this.replaceFixedWithFixed(begin, merge); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -51,7 +51,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -162,7 +162,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -103,7 +103,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -60,7 +60,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -25,6 +25,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; /** * An IsNullNode will be true if the supplied value is null, and false if it is non-null. @@ -81,7 +82,13 @@ @Override public boolean push(PiNode parent) { - replaceFirstInput(parent, parent.object()); - return true; + ObjectStamp piStamp = parent.objectStamp(); + ObjectStamp piValueStamp = parent.object().objectStamp(); + if (piStamp.nonNull() == piValueStamp.nonNull() && piStamp.alwaysNull() == piValueStamp.alwaysNull()) { + replaceFirstInput(parent, parent.object()); + return true; + } else { + return false; + } } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -48,7 +48,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { StructuredGraph graph = (StructuredGraph) graph(); LogicNode equalComp; diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -61,7 +61,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -60,7 +60,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Thu Apr 25 16:53:29 2013 +0200 @@ -29,9 +29,10 @@ public final class Block { + protected final BeginNode beginNode; + protected int id; - protected BeginNode beginNode; protected FixedNode endNode; protected Loop loop; @@ -45,8 +46,10 @@ private boolean align; private int linearScanNumber; - protected Block() { - id = ControlFlowGraph.BLOCK_ID_INITIAL; + protected Block(BeginNode node) { + this.beginNode = node; + + this.id = ControlFlowGraph.BLOCK_ID_INITIAL; this.linearScanNumber = -1; } @@ -206,10 +209,6 @@ return dominator.isDominatedBy(block); } - public double getProbability() { - return getBeginNode().probability(); - } - public int getLinearScanNumber() { return linearScanNumber; } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Thu Apr 25 16:53:29 2013 +0200 @@ -39,6 +39,7 @@ public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlocks, boolean computeLoops, boolean computeDominators, boolean computePostdominators) { ControlFlowGraph cfg = new ControlFlowGraph(graph); cfg.identifyBlocks(); + if (connectBlocks || computeLoops || computeDominators || computePostdominators) { cfg.connectBlocks(); } @@ -111,16 +112,15 @@ public void clearNodeToBlock() { nodeToBlock.clear(); for (Block block : reversePostOrder) { - identifyBlock(block, block.beginNode); + identifyBlock(block); } } protected static final int BLOCK_ID_INITIAL = -1; protected static final int BLOCK_ID_VISITED = -2; - private void identifyBlock(Block block, BeginNode begin) { - block.beginNode = begin; - Node cur = begin; + private void identifyBlock(Block block) { + Node cur = block.getBeginNode(); Node last; do { assert !cur.isDeleted(); @@ -145,9 +145,9 @@ int numBlocks = 0; for (Node node : graph.getNodes()) { if (node instanceof BeginNode) { - Block block = new Block(); + Block block = new Block((BeginNode) node); numBlocks++; - identifyBlock(block, (BeginNode) node); + identifyBlock(block); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -45,20 +45,24 @@ private static final int MAX_COUNTERS = 10 * 1024; private static final long[] COUNTERS = new long[MAX_COUNTERS]; + private static final long[] STATIC_COUNTERS = new long[MAX_COUNTERS]; + private static final String[] GROUPS = new String[MAX_COUNTERS]; private static final HashMap INDEXES = new HashMap<>(); public static String excludedClassPrefix = null; public static boolean enabled = false; private final String name; + private final String group; private final long increment; private final boolean addContext; - public DynamicCounterNode(String name, long increment, boolean addContext) { + public DynamicCounterNode(String name, String group, long increment, boolean addContext) { super(StampFactory.forVoid()); if (!enabled) { throw new GraalInternalError("dynamic counters not enabled"); } this.name = name; + this.group = group; this.increment = increment; this.addContext = addContext; } @@ -90,29 +94,51 @@ } public static synchronized void dump(PrintStream out, double seconds) { + for (String group : new HashSet<>(Arrays.asList(GROUPS))) { + dumpCounters(out, seconds, true, group); + dumpCounters(out, seconds, false, group); + } + out.println("============================"); + + clear(); + } + + private static void dumpCounters(PrintStream out, double seconds, boolean staticCounter, String group) { TreeMap sorted = new TreeMap<>(); + long[] array = staticCounter ? STATIC_COUNTERS : COUNTERS; long sum = 0; - for (int i = 0; i < MAX_COUNTERS; i++) { - sum += COUNTERS[i]; - } - long cutoff = sum / 1000; - int cnt = 0; for (Map.Entry entry : INDEXES.entrySet()) { - if (COUNTERS[entry.getValue()] > cutoff) { - sorted.put(COUNTERS[entry.getValue()] * MAX_COUNTERS + cnt++, entry.getKey()); + int index = entry.getValue(); + if (GROUPS[index].equals(group)) { + sum += array[index]; + sorted.put(array[index] * MAX_COUNTERS + index, entry.getKey()); } } - out.println("=========== dynamic counters, time = " + seconds + " s"); - for (Map.Entry entry : sorted.entrySet()) { - long counter = entry.getKey() / MAX_COUNTERS; - out.println((int) (counter / seconds) + "/s \t" + (counter * 100 / sum) + "% \t" + entry.getValue()); + long cutoff = sum / 1000; + long sum2 = 0; + if (staticCounter) { + out.println("=========== " + group + " static counters: "); + for (Map.Entry entry : sorted.entrySet()) { + long counter = entry.getKey() / MAX_COUNTERS; + sum2 += counter; + if (sum2 >= cutoff) { + out.println(counter + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue()); + } + } + out.println(sum + ": total"); + } else { + out.println("=========== " + group + " dynamic counters, time = " + seconds + " s"); + for (Map.Entry entry : sorted.entrySet()) { + long counter = entry.getKey() / MAX_COUNTERS; + sum2 += counter; + if (sum2 >= cutoff) { + out.println((int) (counter / seconds) + "/s \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue()); + } + } + out.println((int) (sum / seconds) + "/s: total"); } - out.println((int) (sum / seconds) + "/s: total"); - out.println("============================"); - - clear(); } public static void clear() { @@ -120,13 +146,15 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { if (!enabled) { throw new GraalInternalError("counter nodes shouldn't exist when not enabled"); } StructuredGraph graph = (StructuredGraph) graph(); if (excludedClassPrefix == null || !graph.method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) { int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", ((StructuredGraph) graph()).method())) : getIndex(name); + STATIC_COUNTERS[index] += increment; + GROUPS[index] = group; ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph); ConstantNode indexConstant = ConstantNode.forInt(index, graph); @@ -140,10 +168,10 @@ graph.removeFixed(this); } - public static void addCounterBefore(String name, long increment, boolean addContext, FixedNode position) { + public static void addCounterBefore(String group, String name, long increment, boolean addContext, FixedNode position) { if (enabled) { StructuredGraph graph = (StructuredGraph) position.graph(); - DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, increment, addContext)); + DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, group, increment, addContext)); graph.addBeforeFixed(position, counter); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -35,8 +35,8 @@ @Input private ValueNode checkedValue; - public SurvivingCounterNode(String name, long increment, boolean addContext, ValueNode checkedValue) { - super(name, increment, addContext); + public SurvivingCounterNode(String group, String name, long increment, boolean addContext, ValueNode checkedValue) { + super(group, name, increment, addContext); this.checkedValue = checkedValue; } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -48,11 +48,11 @@ public static AddLocationNode create(LocationNode x, LocationNode y, Graph graph) { assert x.getValueKind().equals(y.getValueKind()) && x.locationIdentity() == y.locationIdentity(); - return graph.unique(new AddLocationNode(x, y)); + return graph.unique(new AddLocationNode(x.locationIdentity(), x.getValueKind(), x, y)); } - private AddLocationNode(LocationNode x, LocationNode y) { - super(x.locationIdentity(), x.getValueKind()); + private AddLocationNode(Object identity, Kind kind, ValueNode x, ValueNode y) { + super(identity, kind); this.x = x; this.y = y; } @@ -60,7 +60,7 @@ @Override protected LocationNode addDisplacement(long displacement) { LocationNode added = getX().addDisplacement(displacement); - return graph().unique(new AddLocationNode(added, getY())); + return graph().unique(new AddLocationNode(locationIdentity(), getValueKind(), added, getY())); } @Override @@ -86,20 +86,23 @@ } @Override - public Value generateLea(LIRGeneratorTool gen, Value base) { - Value xAddr = getX().generateLea(gen, base); - return getY().generateLea(gen, xAddr); + public Value generateAddress(LIRGeneratorTool gen, Value base) { + Value xAddr = getX().generateAddress(gen, base); + return getY().generateAddress(gen, xAddr); } @Override public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) { - Value xAddr = getX().generateLea(gen, base); + Value xAddr = getX().generateAddress(gen, base); return getY().generateLoad(gen, xAddr, deopting); } @Override public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) { - Value xAddr = getX().generateLea(gen, base); + Value xAddr = getX().generateAddress(gen, base); getY().generateStore(gen, xAddr, value, deopting); } + + @NodeIntrinsic + public static native Location addLocation(@ConstantNodeParameter Object identity, @ConstantNodeParameter Kind kind, Location x, Location y); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -52,7 +52,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -49,7 +49,7 @@ @Override public void generate(LIRGeneratorTool gen) { - Value addr = getLocation().generateLea(gen, gen.operand(getObject())); + Value addr = getLocation().generateAddress(gen, gen.operand(getObject())); gen.setResult(this, addr); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -55,7 +55,7 @@ } @Override - public Value generateLea(LIRGeneratorTool gen, Value base) { + public Value generateAddress(LIRGeneratorTool gen, Value base) { return gen.emitLea(base, displacement(), Value.ILLEGAL, 0); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -58,10 +58,14 @@ } public static IndexedLocationNode create(Object identity, Kind kind, long displacement, ValueNode index, Graph graph, int indexScaling) { - return graph.unique(new IndexedLocationNode(identity, kind, index, displacement, indexScaling)); + return graph.unique(new IndexedLocationNode(identity, kind, displacement, index, indexScaling)); } - private IndexedLocationNode(Object identity, Kind kind, ValueNode index, long displacement, int indexScaling) { + private IndexedLocationNode(Object identity, Kind kind, ValueNode index, int indexScaling) { + this(identity, kind, 0, index, indexScaling); + } + + private IndexedLocationNode(Object identity, Kind kind, long displacement, ValueNode index, int indexScaling) { super(identity, kind); this.index = index; this.displacement = displacement; @@ -86,7 +90,7 @@ } @Override - public Value generateLea(LIRGeneratorTool gen, Value base) { + public Value generateAddress(LIRGeneratorTool gen, Value base) { return gen.emitLea(base, displacement, gen.operand(index()), indexScaling()); } @@ -99,4 +103,7 @@ public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) { gen.emitStore(getValueKind(), base, displacement, gen.operand(index()), indexScaling(), value, deopting); } + + @NodeIntrinsic + public static native Location indexedLocation(@ConstantNodeParameter Object identity, @ConstantNodeParameter Kind kind, int index, @ConstantNodeParameter int indexScaling); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -45,7 +45,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -30,9 +30,9 @@ import com.oracle.graal.nodes.type.*; /** - * A location for a memory access in terms of the kind of value accessed and how to access it. - * All locations have the form [base + location], where base is a node and location is defined - * by subclasses of the {@link LocationNode}. + * A location for a memory access in terms of the kind of value accessed and how to access it. All + * locations have the form [base + location], where base is a node and location is defined by + * subclasses of the {@link LocationNode}. */ public abstract class LocationNode extends FloatingNode implements LIRLowerable, ValueNumberable { @@ -41,7 +41,7 @@ /** * Creates a new unique location identity for read and write operations. - * + * * @param name the name of the new location identity, for debugging purposes * @return the new location identity */ @@ -67,6 +67,12 @@ */ public static final Object FINAL_LOCATION = createLocation("FINAL_LOCATION"); + /** + * Marker interface for locations in snippets. + */ + public interface Location { + } + public static Object getArrayLocation(Kind elementKind) { return elementKind; } @@ -93,7 +99,7 @@ // nothing to do... } - public abstract Value generateLea(LIRGeneratorTool gen, Value base); + public abstract Value generateAddress(LIRGeneratorTool gen, Value base); public abstract Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -103,11 +103,15 @@ Object locId = location().locationIdentity(); if (locId instanceof ResolvedJavaField) { ResolvedJavaType fieldType = ((ResolvedJavaField) locId).getDeclaringClass(); - ResolvedJavaType beforePiType = parent.object().objectStamp().type(); + ValueNode piValueStamp = parent.object(); + ResolvedJavaType beforePiType = piValueStamp.objectStamp().type(); if (beforePiType != null && fieldType.isAssignableFrom(beforePiType)) { - replaceFirstInput(parent, parent.object()); - return true; + ObjectStamp piStamp = parent.objectStamp(); + if (piStamp.nonNull() == piValueStamp.objectStamp().nonNull() && piStamp.alwaysNull() == piValueStamp.objectStamp().alwaysNull()) { + replaceFirstInput(parent, piValueStamp); + return true; + } } } return false; diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -47,7 +47,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -50,7 +50,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -69,7 +69,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -83,7 +83,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -64,7 +64,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -62,7 +62,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -47,7 +47,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -52,7 +52,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -105,7 +105,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -53,7 +53,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { if (isLowered()) { return; } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -54,7 +54,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -52,7 +52,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -37,7 +37,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } } diff -r 261a43921c5e -r 17b598df8da9 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 Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -48,7 +48,7 @@ return new Object[]{LocationNode.ANY_LOCATION}; } - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 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 Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -49,7 +49,7 @@ return new Object[]{LocationNode.ANY_LOCATION}; } - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -110,7 +110,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -87,7 +87,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -62,7 +62,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { tool.getRuntime().lower(this, tool); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Lowerable.java Thu Apr 25 16:53:29 2013 +0200 @@ -24,5 +24,9 @@ public interface Lowerable { - void lower(LoweringTool tool); + public enum LoweringType { + BEFORE_GUARDS, AFTER_GUARDS + } + + void lower(LoweringTool tool, LoweringType loweringType); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Thu Apr 25 16:53:29 2013 +0200 @@ -30,8 +30,6 @@ public interface LoweringTool { - TargetDescription getTarget(); - GraalCodeCacheProvider getRuntime(); Replacements getReplacements(); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java Thu Apr 25 16:53:29 2013 +0200 @@ -33,7 +33,7 @@ private final GenericStampType type; protected GenericStamp(GenericStampType type) { - super(Kind.Void); + super(type == GenericStampType.Void ? Kind.Void : Kind.Illegal); this.type = type; } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 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.graal.nodes.util; + +import java.util.*; + +import com.oracle.graal.nodes.*; + +public class NodesToDoubles { + + private final IdentityHashMap nodeProbabilities; + + public NodesToDoubles(int numberOfNodes) { + this.nodeProbabilities = new IdentityHashMap<>(numberOfNodes); + } + + public void put(FixedNode n, double value) { + nodeProbabilities.put(n, value); + } + + public double get(FixedNode n) { + Double value = nodeProbabilities.get(n); + assert value != null; + return value; + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java Mon Apr 22 18:30:33 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,459 +0,0 @@ -/* - * Copyright (c) 2011, 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.phases.common; - -import java.util.*; - -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.cfg.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.graph.*; - -/** - * Computes probabilities for nodes in a graph. - *

- * The computation of absolute probabilities works in three steps: - *

    - *
  1. {@link PropagateProbability} traverses the graph in post order (merges after their ends, ...) - * and keeps track of the "probability state". Whenever it encounters a {@link ControlSplitNode} it - * uses the split's probability information to divide the probability upon the successors. Whenever - * it encounters an {@link Invoke} it assumes that the exception edge is unlikely and propagates the - * whole probability to the normal successor. Whenever it encounters a {@link MergeNode} it sums up - * the probability of all predecessors. It also maintains a set of active loops (whose - * {@link LoopBeginNode} has been visited) and builds def/use information for step 2.
  2. - *
  3. - *
  4. {@link PropagateLoopFrequency} propagates the loop frequencies and multiplies each - * {@link FixedNode}'s probability with its loop frequency.
  5. - *
- * TODO: add exception probability information to Invokes - */ -public class ComputeProbabilityPhase extends Phase { - - private static final double EPSILON = 1d / Integer.MAX_VALUE; - - @Override - protected void run(StructuredGraph graph) { - new PropagateProbability(graph.start()).apply(); - Debug.dump(graph, "After PropagateProbability"); - computeLoopFactors(); - Debug.dump(graph, "After computeLoopFactors"); - new PropagateLoopFrequency(graph.start()).apply(); - new ComputeInliningRelevanceIterator(graph).apply(); - } - - private void computeLoopFactors() { - for (LoopInfo info : loopInfos) { - double frequency = info.loopFrequency(); - assert frequency != -1; - } - } - - private static boolean isRelativeProbability(double prob) { - // 1.01 to allow for some rounding errors - return prob >= 0 && prob <= 1.01; - } - - public static class LoopInfo { - - public final LoopBeginNode loopBegin; - - public final NodeMap> requires; - - private double loopFrequency = -1; - public boolean ended = false; - - public LoopInfo(LoopBeginNode loopBegin) { - this.loopBegin = loopBegin; - this.requires = loopBegin.graph().createNodeMap(); - } - - public double loopFrequency() { - if (loopFrequency == -1 && ended) { - double backEdgeProb = 0.0; - for (LoopEndNode le : loopBegin.loopEnds()) { - double factor = 1; - Set requireds = requires.get(le); - for (LoopInfo required : requireds) { - double t = required.loopFrequency(); - if (t == -1) { - return -1; - } - factor *= t; - } - backEdgeProb += le.probability() * factor; - } - double d = loopBegin.probability() - backEdgeProb; - if (d < EPSILON) { - d = EPSILON; - } - loopFrequency = loopBegin.probability() / d; - loopBegin.setLoopFrequency(loopFrequency); - } - return loopFrequency; - } - } - - public Set loopInfos = new HashSet<>(); - public Map> mergeLoops = new IdentityHashMap<>(); - - private class Probability implements MergeableState { - - public double probability; - public HashSet loops; - public LoopInfo loopInfo; - - public Probability(double probability, HashSet loops) { - this.probability = probability; - this.loops = new HashSet<>(4); - if (loops != null) { - this.loops.addAll(loops); - } - } - - @Override - public Probability clone() { - return new Probability(probability, loops); - } - - @Override - public boolean merge(MergeNode merge, List withStates) { - if (merge.forwardEndCount() > 1) { - HashSet intersection = new HashSet<>(loops); - for (Probability other : withStates) { - intersection.retainAll(other.loops); - } - for (LoopInfo info : loops) { - if (!intersection.contains(info)) { - double loopFrequency = info.loopFrequency(); - if (loopFrequency == -1) { - return false; - } - probability *= loopFrequency; - } - } - for (Probability other : withStates) { - double prob = other.probability; - for (LoopInfo info : other.loops) { - if (!intersection.contains(info)) { - double loopFrequency = info.loopFrequency(); - if (loopFrequency == -1) { - return false; - } - prob *= loopFrequency; - } - } - probability += prob; - } - loops = intersection; - mergeLoops.put(merge, new HashSet<>(intersection)); - assert isRelativeProbability(probability) : probability; - } - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - loopInfo = new LoopInfo(loopBegin); - loopInfos.add(loopInfo); - loops.add(loopInfo); - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - assert loopInfo != null; - List loopEnds = loopBegin.orderedLoopEnds(); - int i = 0; - for (Probability proba : loopEndStates) { - LoopEndNode loopEnd = loopEnds.get(i++); - Set requires = loopInfo.requires.get(loopEnd); - if (requires == null) { - requires = new HashSet<>(); - loopInfo.requires.set(loopEnd, requires); - } - for (LoopInfo innerLoop : proba.loops) { - if (innerLoop != loopInfo && !this.loops.contains(innerLoop)) { - requires.add(innerLoop); - } - } - } - loopInfo.ended = true; - } - - @Override - public void afterSplit(BeginNode node) { - assert node.predecessor() != null; - Node pred = node.predecessor(); - if (pred instanceof Invoke) { - Invoke x = (Invoke) pred; - if (x.next() != node) { - probability = 0; - } - } else { - assert pred instanceof ControlSplitNode; - ControlSplitNode x = (ControlSplitNode) pred; - probability *= x.probability(node); - } - } - } - - private class PropagateProbability extends PostOrderNodeIterator { - - public PropagateProbability(FixedNode start) { - super(start, new Probability(1d, null)); - } - - @Override - protected void node(FixedNode node) { - node.setProbability(state.probability); - } - } - - private class LoopCount implements MergeableState { - - public double count; - - public LoopCount(double count) { - this.count = count; - } - - @Override - public LoopCount clone() { - return new LoopCount(count); - } - - @Override - public boolean merge(MergeNode merge, List withStates) { - assert merge.forwardEndCount() == withStates.size() + 1; - if (merge.forwardEndCount() > 1) { - Set loops = mergeLoops.get(merge); - assert loops != null; - double countProd = 1; - for (LoopInfo loop : loops) { - countProd *= loop.loopFrequency(); - } - count = countProd; - } - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - count *= loopBegin.loopFrequency(); - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - // nothing to do... - } - - @Override - public void afterSplit(BeginNode node) { - // nothing to do... - } - } - - private class PropagateLoopFrequency extends PostOrderNodeIterator { - - public PropagateLoopFrequency(FixedNode start) { - super(start, new LoopCount(1d)); - } - - @Override - protected void node(FixedNode node) { - node.setProbability(node.probability() * state.count); - } - - } - - private static class ComputeInliningRelevanceIterator extends ScopedPostOrderNodeIterator { - - private final HashMap scopes; - private double currentProbability; - private double parentRelevance; - - public ComputeInliningRelevanceIterator(StructuredGraph graph) { - super(graph); - this.scopes = computeLowestPathProbabilities(computeScopeInformation(graph)); - } - - @Override - protected void initializeScope() { - Scope scope = scopes.get(currentScopeStart); - parentRelevance = getParentScopeRelevance(scope); - currentProbability = scope.minPathProbability; - } - - private static double getParentScopeRelevance(Scope scope) { - if (scope.start instanceof LoopBeginNode) { - assert scope.parent != null; - double parentProbability = 0; - for (EndNode end : ((LoopBeginNode) scope.start).forwardEnds()) { - parentProbability += end.probability(); - } - return parentProbability / scope.parent.minPathProbability; - } else { - assert scope.parent == null; - return 1.0; - } - } - - @Override - protected void invoke(Invoke invoke) { - assert !Double.isNaN(invoke.probability()); - invoke.setInliningRelevance((invoke.probability() / currentProbability) * Math.min(1.0, parentRelevance)); - assert !Double.isNaN(invoke.inliningRelevance()); - } - - private static Scope[] computeScopeInformation(StructuredGraph graph) { - ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false); - - Loop[] loops = cfg.getLoops(); - HashMap processedScopes = new HashMap<>(); - Scope[] scopes = new Scope[loops.length + 1]; - Scope methodScope = new Scope(graph.start(), null); - processedScopes.put(null, methodScope); - - scopes[0] = methodScope; - for (int i = 0; i < loops.length; i++) { - scopes[i + 1] = createScope(loops[i], processedScopes); - } - - return scopes; - } - - private static Scope createScope(Loop loop, HashMap processedLoops) { - Scope parent = processedLoops.get(loop.parent); - if (parent == null) { - parent = createScope(loop.parent, processedLoops); - } - Scope result = new Scope(loop.loopBegin(), parent); - processedLoops.put(loop, result); - return result; - } - - private static HashMap computeLowestPathProbabilities(Scope[] scopes) { - HashMap result = new HashMap<>(); - - for (Scope scope : scopes) { - double lowestPathProbability = computeLowestPathProbability(scope); - scope.minPathProbability = Math.max(EPSILON, lowestPathProbability); - result.put(scope.start, scope); - } - - return result; - } - - private static double computeLowestPathProbability(Scope scope) { - FixedNode scopeStart = scope.start; - ArrayList pathBeginNodes = new ArrayList<>(); - pathBeginNodes.add(scopeStart); - double minPathProbability = scopeStart.probability(); - boolean isLoopScope = scopeStart instanceof LoopBeginNode; - - do { - Node current = pathBeginNodes.remove(pathBeginNodes.size() - 1); - do { - if (isLoopScope && current instanceof LoopExitNode && ((LoopBeginNode) scopeStart).loopExits().contains((LoopExitNode) current)) { - return minPathProbability; - } else if (current instanceof LoopBeginNode && current != scopeStart) { - current = getMaxProbabilityLoopExit((LoopBeginNode) current, pathBeginNodes); - minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability); - } else if (current instanceof ControlSplitNode) { - current = getMaxProbabilitySux((ControlSplitNode) current, pathBeginNodes); - minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability); - } else { - assert current.successors().count() <= 1; - current = current.successors().first(); - } - } while (current != null); - } while (!pathBeginNodes.isEmpty()); - - return minPathProbability; - } - - private static double getMinPathProbability(FixedNode current, double minPathProbability) { - if (current != null && current.probability() < minPathProbability) { - return current.probability(); - } - return minPathProbability; - } - - private static Node getMaxProbabilitySux(ControlSplitNode controlSplit, ArrayList pathBeginNodes) { - Node maxSux = null; - double maxProbability = 0.0; - int pathBeginCount = pathBeginNodes.size(); - - for (Node sux : controlSplit.successors()) { - double probability = controlSplit.probability((BeginNode) sux); - if (probability > maxProbability) { - maxProbability = probability; - maxSux = sux; - truncate(pathBeginNodes, pathBeginCount); - } else if (probability == maxProbability) { - pathBeginNodes.add((FixedNode) sux); - } - } - - return maxSux; - } - - private static Node getMaxProbabilityLoopExit(LoopBeginNode loopBegin, ArrayList pathBeginNodes) { - Node maxSux = null; - double maxProbability = 0.0; - int pathBeginCount = pathBeginNodes.size(); - - for (LoopExitNode sux : loopBegin.loopExits()) { - double probability = sux.probability(); - if (probability > maxProbability) { - maxProbability = probability; - maxSux = sux; - truncate(pathBeginNodes, pathBeginCount); - } else if (probability == maxProbability) { - pathBeginNodes.add(sux); - } - } - - return maxSux; - } - - public static void truncate(ArrayList pathBeginNodes, int pathBeginCount) { - for (int i = pathBeginNodes.size() - pathBeginCount; i > 0; i--) { - pathBeginNodes.remove(pathBeginNodes.size() - 1); - } - } - } - - private static class Scope { - - public final FixedNode start; - public final Scope parent; - public double minPathProbability; - - public Scope(FixedNode start, Scope parent) { - this.start = start; - this.parent = parent; - } - } -} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java Thu Apr 25 16:53:29 2013 +0200 @@ -32,17 +32,15 @@ // Metrics private static final DebugMetric metricNodesRemoved = Debug.metric("NodesRemoved"); - private NodeFlood flood; - @Override protected void run(StructuredGraph graph) { - this.flood = graph.createNodeFlood(); + NodeFlood flood = graph.createNodeFlood(); flood.add(graph.start()); - iterateSuccessors(); - disconnectCFGNodes(graph); - iterateInputs(graph); - deleteNodes(graph); + iterateSuccessors(flood); + disconnectCFGNodes(flood, graph); + iterateInputs(flood, graph); + deleteNodes(flood, graph); // remove chained Merges for (MergeNode merge : graph.getNodes(MergeNode.class)) { @@ -52,7 +50,7 @@ } } - private void iterateSuccessors() { + private static void iterateSuccessors(NodeFlood flood) { for (Node current : flood) { if (current instanceof EndNode) { EndNode end = (EndNode) current; @@ -65,7 +63,7 @@ } } - private void disconnectCFGNodes(StructuredGraph graph) { + private static void disconnectCFGNodes(NodeFlood flood, StructuredGraph graph) { for (EndNode node : graph.getNodes(EndNode.class)) { if (!flood.isMarked(node)) { MergeNode merge = node.merge(); @@ -95,7 +93,7 @@ } } - private void deleteNodes(StructuredGraph graph) { + private static void deleteNodes(NodeFlood flood, StructuredGraph graph) { for (Node node : graph.getNodes()) { if (!flood.isMarked(node)) { node.clearInputs(); @@ -110,7 +108,7 @@ } } - private void iterateInputs(StructuredGraph graph) { + private static void iterateInputs(NodeFlood flood, StructuredGraph graph) { for (Node node : graph.getNodes()) { if (node instanceof LocalNode) { flood.add(node); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Thu Apr 25 16:53:29 2013 +0200 @@ -25,7 +25,6 @@ import java.util.*; import java.util.Map.Entry; -import com.oracle.graal.api.code.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -34,8 +33,9 @@ import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.schedule.*; +import com.oracle.graal.phases.tiers.*; -public class GuardLoweringPhase extends Phase { +public class GuardLoweringPhase extends BasePhase { private abstract static class ScheduledNodeIterator { @@ -81,9 +81,14 @@ protected abstract void processNode(Node node); } - private class UseImplicitNullChecks extends ScheduledNodeIterator { + private static class UseImplicitNullChecks extends ScheduledNodeIterator { private final IdentityHashMap nullGuarded = new IdentityHashMap<>(); + private final int implicitNullCheckLimit; + + UseImplicitNullChecks(int implicitNullCheckLimit) { + this.implicitNullCheckLimit = implicitNullCheckLimit; + } @Override protected void processNode(Node node) { @@ -134,9 +139,17 @@ nullGuarded.put(obj, guard); } } + + private boolean isImplicitNullCheck(LocationNode location) { + if (location instanceof ConstantLocationNode) { + return ((ConstantLocationNode) location).displacement() < implicitNullCheckLimit; + } else { + return false; + } + } } - private class LowerGuards extends ScheduledNodeIterator { + private static class LowerGuards extends ScheduledNodeIterator { private final Block block; @@ -193,35 +206,21 @@ } } - private TargetDescription target; - - public GuardLoweringPhase(TargetDescription target) { - this.target = target; - } - @Override - protected void run(StructuredGraph graph) { + protected void run(StructuredGraph graph, MidTierContext context) { SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph); for (Block block : schedule.getCFG().getBlocks()) { - processBlock(block, schedule); + processBlock(block, schedule, context.getTarget().implicitNullCheckLimit); } } - private void processBlock(Block block, SchedulePhase schedule) { + private static void processBlock(Block block, SchedulePhase schedule, int implicitNullCheckLimit) { List nodes = schedule.nodesFor(block); - if (GraalOptions.OptImplicitNullChecks && target.implicitNullCheckLimit > 0) { - new UseImplicitNullChecks().processNodes(nodes, block.getBeginNode()); + if (GraalOptions.OptImplicitNullChecks && implicitNullCheckLimit > 0) { + new UseImplicitNullChecks(implicitNullCheckLimit).processNodes(nodes, block.getBeginNode()); } new LowerGuards(block).processNodes(nodes, block.getBeginNode()); } - - private boolean isImplicitNullCheck(LocationNode location) { - if (location instanceof ConstantLocationNode) { - return ((ConstantLocationNode) location).displacement() < target.implicitNullCheckLimit; - } else { - return false; - } - } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Thu Apr 25 16:53:29 2013 +0200 @@ -33,12 +33,14 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.PhasePlan.PhasePosition; import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer; import com.oracle.graal.phases.common.InliningUtil.InlineInfo; import com.oracle.graal.phases.common.InliningUtil.InliningCallback; import com.oracle.graal.phases.common.InliningUtil.InliningPolicy; +import com.oracle.graal.phases.graph.*; public class InliningPhase extends Phase implements InliningCallback { @@ -99,13 +101,15 @@ @Override protected void run(final StructuredGraph graph) { + NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply(); + NodesToDoubles nodeRelevance = new ComputeInliningRelevanceClosure(graph, nodeProbabilities).apply(); inliningPolicy.initialize(graph); while (inliningPolicy.continueInlining(graph)) { final InlineInfo candidate = inliningPolicy.next(); if (candidate != null) { - boolean isWorthInlining = inliningPolicy.isWorthInlining(candidate); + boolean isWorthInlining = inliningPolicy.isWorthInlining(candidate, nodeProbabilities, nodeRelevance); isWorthInlining &= candidate.numberOfMethods() <= maxMethodPerInlining; metricInliningConsidered.increment(); @@ -120,6 +124,10 @@ if (GraalOptions.OptCanonicalizer) { new CanonicalizerPhase.Instance(runtime, assumptions, invokeUsages, mark, customCanonicalizer).apply(graph); } + + nodeProbabilities = new ComputeProbabilityClosure(graph).apply(); + nodeRelevance = new ComputeInliningRelevanceClosure(graph, nodeProbabilities).apply(); + inliningCount++; metricInliningPerformed.increment(); } catch (BailoutException bailout) { @@ -157,10 +165,8 @@ } assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING"; - if (GraalOptions.ProbabilityAnalysis) { - new DeadCodeEliminationPhase().apply(newGraph); - new ComputeProbabilityPhase().apply(newGraph); - } + new DeadCodeEliminationPhase().apply(newGraph); + if (GraalOptions.OptCanonicalizer) { new CanonicalizerPhase.Instance(runtime, assumptions).apply(newGraph); } @@ -177,7 +183,7 @@ private interface InliningDecision { - boolean isWorthInlining(InlineInfo info); + boolean isWorthInlining(InlineInfo info, NodesToDoubles nodeProbabilities, NodesToDoubles nodeRelevance); } private static class GreedySizeBasedInliningDecision implements InliningDecision { @@ -193,8 +199,7 @@ } @Override - public boolean isWorthInlining(InlineInfo info) { - assert GraalOptions.ProbabilityAnalysis; + public boolean isWorthInlining(InlineInfo info, NodesToDoubles nodeProbabilities, NodesToDoubles nodeRelevance) { /* * TODO (chaeubl): invoked methods that are on important paths but not yet compiled -> * will be compiled anyways and it is likely that we are the only caller... might be @@ -220,8 +225,7 @@ int bytecodeSize = (int) (bytecodeCodeSize(info) / bonus); int complexity = (int) (compilationComplexity(info) / bonus); int compiledCodeSize = (int) (compiledCodeSize(info) / bonus); - double relevance = info.invoke().inliningRelevance(); - + double relevance = nodeRelevance.get(info.invoke().asNode()); /* * as long as the compiled code size is small enough (or the method was not yet * compiled), we can do a pretty general inlining that suits most situations @@ -240,7 +244,7 @@ * the normal inlining did not fit this invoke, so check if we have any reason why we * should still do the inlining */ - double probability = info.invoke().probability(); + double probability = nodeProbabilities.get(info.invoke().asNode()); int transferredValues = numberOfTransferredValues(info); int invokeUsages = countInvokeUsages(info); int moreSpecificArguments = countMoreSpecificArgumentInfo(info); @@ -409,8 +413,9 @@ return info; } - public boolean isWorthInlining(InlineInfo info) { - return inliningDecision.isWorthInlining(info); + @Override + public boolean isWorthInlining(InlineInfo info, NodesToDoubles nodeProbabilities, NodesToDoubles nodeRelevance) { + return inliningDecision.isWorthInlining(info, nodeProbabilities, nodeRelevance); } public void initialize(StructuredGraph graph) { diff -r 261a43921c5e -r 17b598df8da9 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 Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Thu Apr 25 16:53:29 2013 +0200 @@ -70,7 +70,7 @@ void scanInvokes(Iterable newNodes); - boolean isWorthInlining(InlineInfo info); + boolean isWorthInlining(InlineInfo info, NodesToDoubles nodeProbabilities, NodesToDoubles nodeRelevance); } /** @@ -260,7 +260,6 @@ } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) { throw new GraalInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass); } - macroNode.setProbability(invoke.asNode().probability()); CallTargetNode callTarget = invoke.callTarget(); if (invoke instanceof InvokeNode) { graph.replaceFixedWithFixed((InvokeNode) invoke, graph.add(macroNode)); @@ -466,7 +465,6 @@ ValueNode originalReceiver = ((MethodCallTargetNode) invoke.callTarget()).receiver(); // setup merge and phi nodes for results and exceptions MergeNode returnMerge = graph.add(new MergeNode()); - returnMerge.setProbability(invoke.probability()); returnMerge.setStateAfter(invoke.stateAfter().duplicate(invoke.stateAfter().bci)); PhiNode returnValuePhi = null; @@ -481,7 +479,6 @@ ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge(); exceptionMerge = graph.add(new MergeNode()); - exceptionMerge.setProbability(exceptionEdge.probability()); FixedNode exceptionSux = exceptionEdge.next(); graph.addBeforeFixed(exceptionSux, exceptionMerge); @@ -492,20 +489,13 @@ // create one separate block for each invoked method BeginNode[] successors = new BeginNode[numberOfMethods + 1]; for (int i = 0; i < numberOfMethods; i++) { - double probability = 0; - for (int j = 0; j < typesToConcretes.length; j++) { - if (typesToConcretes[j] == i) { - probability += ptypes.get(j).getProbability(); - } - } - - successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, invoke.probability() * probability, true); + successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true); } // create the successor for an unknown type FixedNode unknownTypeSux; if (shouldFallbackToInvoke()) { - unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, notRecordedTypeProbability, false); + unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, false); } else { unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)); } @@ -612,7 +602,6 @@ assert concretes.size() == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0; BeginNode calleeEntryNode = graph.add(new BeginNode()); - calleeEntryNode.setProbability(invoke.probability()); BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph); BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux}; @@ -649,15 +638,12 @@ } private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, - double probability, boolean useForInlining) { - Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining, probability); + boolean useForInlining) { + Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining); BeginNode calleeEntryNode = graph.add(new BeginNode()); calleeEntryNode.setNext(duplicatedInvoke.asNode()); - calleeEntryNode.setProbability(probability); EndNode endNode = graph.add(new EndNode()); - endNode.setProbability(probability); - duplicatedInvoke.setNext(endNode); returnMerge.addForwardEnd(endNode); @@ -667,13 +653,11 @@ return calleeEntryNode; } - private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining, double probability) { + private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining) { Invoke result = (Invoke) invoke.asNode().copyWithInputs(); Node callTarget = result.callTarget().copyWithInputs(); result.asNode().replaceFirstInput(result.callTarget(), callTarget); result.setUseForInlining(useForInlining); - result.setProbability(probability); - result.setInliningRelevance(invoke.inliningRelevance() * probability); Kind kind = invoke.asNode().kind(); if (kind != Kind.Void) { @@ -738,8 +722,6 @@ InliningUtil.receiverNullCheck(invoke); BeginNode invocationEntry = graph.add(new BeginNode()); - invocationEntry.setProbability(invoke.probability()); - BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph); BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux}; createDispatchOnTypeBeforeInvoke(graph, successors, true); @@ -966,6 +948,7 @@ return graph.unique(new PiNode(receiver, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType), anchor)); } + // TODO (chaeubl): cleanup this method private static boolean checkInvokeConditions(Invoke invoke) { if (invoke.predecessor() == null || !invoke.asNode().isAlive()) { return logNotInlinedMethodAndReturnFalse(invoke, "the invoke is dead code"); @@ -974,6 +957,7 @@ } else if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() == null) { return logNotInlinedMethodAndReturnFalse(invoke, "target method is null"); } else if (invoke.stateAfter() == null) { + // TODO (chaeubl): why should an invoke not have a state after? return logNotInlinedMethodAndReturnFalse(invoke, "the invoke has no after state"); } else if (!invoke.useForInlining()) { return logNotInlinedMethodAndReturnFalse(invoke, "the invoke is marked to be not used for inlining"); @@ -1127,27 +1111,8 @@ } FrameState outerFrameState = null; - double invokeProbability = invoke.asNode().probability(); int callerLockDepth = stateAfter.nestedLockDepth(); for (Node node : duplicates.values()) { - if (GraalOptions.ProbabilityAnalysis) { - if (node instanceof FixedNode) { - FixedNode fixed = (FixedNode) node; - double newProbability = fixed.probability() * invokeProbability; - if (GraalOptions.LimitInlinedProbability) { - newProbability = Math.min(newProbability, invokeProbability); - } - fixed.setProbability(newProbability); - } - if (node instanceof Invoke) { - Invoke newInvoke = (Invoke) node; - double newRelevance = newInvoke.inliningRelevance() * invoke.inliningRelevance(); - if (GraalOptions.LimitInlinedRelevance) { - newRelevance = Math.min(newRelevance, invoke.inliningRelevance()); - } - newInvoke.setInliningRelevance(newRelevance); - } - } if (node instanceof FrameState) { FrameState frameState = (FrameState) node; assert frameState.bci != FrameState.BEFORE_BCI : frameState; diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Thu Apr 25 16:53:29 2013 +0200 @@ -26,47 +26,45 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.spi.Lowerable.LoweringType; import com.oracle.graal.phases.*; import com.oracle.graal.phases.schedule.*; +import com.oracle.graal.phases.tiers.*; /** * Processes all {@link Lowerable} nodes to do their lowering. */ -public class LoweringPhase extends Phase { +public class LoweringPhase extends BasePhase { final class LoweringToolImpl implements LoweringTool { + private final PhaseContext context; private final FixedNode guardAnchor; private final NodeBitMap activeGuards; private FixedWithNextNode lastFixedNode; private ControlFlowGraph cfg; - public LoweringToolImpl(FixedNode guardAnchor, NodeBitMap activeGuards, ControlFlowGraph cfg) { + public LoweringToolImpl(PhaseContext context, FixedNode guardAnchor, NodeBitMap activeGuards, ControlFlowGraph cfg) { + this.context = context; this.guardAnchor = guardAnchor; this.activeGuards = activeGuards; this.cfg = cfg; } @Override - public TargetDescription getTarget() { - return target; - } - - @Override public GraalCodeCacheProvider getRuntime() { - return runtime; + return (GraalCodeCacheProvider) context.getRuntime(); } @Override public Replacements getReplacements() { - return replacements; + return context.getReplacements(); } @Override @@ -81,11 +79,14 @@ @Override public Assumptions assumptions() { - return assumptions; + return context.getAssumptions(); } @Override public ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) { + if (loweringType == LoweringType.AFTER_GUARDS) { + throw new GraalInternalError("Cannot create guards in after-guard lowering"); + } if (GraalOptions.OptEliminateGuards) { for (Node usage : condition.usages()) { if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage) && ((GuardNode) usage).negated() == negated) { @@ -116,18 +117,10 @@ } } - private final TargetDescription target; - private final GraalCodeCacheProvider runtime; - private final Replacements replacements; - private final Assumptions assumptions; + private final LoweringType loweringType; - private boolean deferred; - - public LoweringPhase(TargetDescription target, GraalCodeCacheProvider runtime, Replacements replacements, Assumptions assumptions) { - this.target = target; - this.runtime = runtime; - this.replacements = replacements; - this.assumptions = assumptions; + public LoweringPhase(LoweringType loweringType) { + this.loweringType = loweringType; } private static boolean containsLowerable(NodeIterable nodes) { @@ -140,20 +133,18 @@ } @Override - protected void run(final StructuredGraph graph) { + protected void run(final StructuredGraph graph, PhaseContext context) { int i = 0; NodeBitMap processed = graph.createNodeBitMap(); while (true) { + Round round = new Round(i++, context, processed); int mark = graph.getMark(); - final SchedulePhase schedule = new SchedulePhase(); - schedule.apply(graph, false); - deferred = false; - processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null, schedule, processed); - Debug.dump(graph, "Lowering iteration %d", i++); - new CanonicalizerPhase.Instance(runtime, assumptions, mark, null).apply(graph); + IncrementalCanonicalizerPhase canonicalizer = new IncrementalCanonicalizerPhase<>(); + canonicalizer.addPhase(round); + canonicalizer.apply(graph, context); - if (!deferred && !containsLowerable(graph.getNewNodes(mark))) { + if (!round.deferred && !containsLowerable(graph.getNewNodes(mark))) { // No new lowerable nodes - done! break; } @@ -162,76 +153,98 @@ } } - private void processBlock(Block block, NodeBitMap activeGuards, FixedNode parentAnchor, SchedulePhase schedule, NodeBitMap processed) { + private final class Round extends Phase { - FixedNode anchor = parentAnchor; - if (anchor == null) { - anchor = block.getBeginNode(); + private final PhaseContext context; + private final NodeBitMap processed; + private final SchedulePhase schedule; + private boolean deferred = false; + + private Round(int iteration, PhaseContext context, NodeBitMap processed) { + super(String.format("Lowering iteration %d", iteration)); + this.context = context; + this.processed = processed; + this.schedule = new SchedulePhase(); } - process(block, activeGuards, anchor, schedule, processed); - // Process always reached block first. - Block alwaysReachedBlock = block.getPostdominator(); - if (alwaysReachedBlock != null && alwaysReachedBlock.getDominator() == block) { - processBlock(alwaysReachedBlock, activeGuards, anchor, schedule, processed); + @Override + public void run(StructuredGraph graph) { + schedule.apply(graph, false); + processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null); } - // Now go for the other dominators. - for (Block dominated : block.getDominated()) { - if (dominated != alwaysReachedBlock) { - assert dominated.getDominator() == block; - processBlock(dominated, activeGuards, null, schedule, processed); + private void processBlock(Block block, NodeBitMap activeGuards, FixedNode parentAnchor) { + + FixedNode anchor = parentAnchor; + if (anchor == null) { + anchor = block.getBeginNode(); + } + process(block, activeGuards, anchor); + + // Process always reached block first. + Block alwaysReachedBlock = block.getPostdominator(); + if (alwaysReachedBlock != null && alwaysReachedBlock.getDominator() == block) { + processBlock(alwaysReachedBlock, activeGuards, anchor); + } + + // Now go for the other dominators. + for (Block dominated : block.getDominated()) { + if (dominated != alwaysReachedBlock) { + assert dominated.getDominator() == block; + processBlock(dominated, activeGuards, null); + } + } + + if (parentAnchor == null && GraalOptions.OptEliminateGuards) { + for (GuardNode guard : anchor.usages().filter(GuardNode.class)) { + activeGuards.clear(guard); + } } } - if (parentAnchor == null && GraalOptions.OptEliminateGuards) { - for (GuardNode guard : anchor.usages().filter(GuardNode.class)) { - activeGuards.clear(guard); - } - } - } + private void process(final Block b, final NodeBitMap activeGuards, final FixedNode anchor) { - private void process(final Block b, final NodeBitMap activeGuards, final FixedNode anchor, SchedulePhase schedule, NodeBitMap processed) { + final LoweringToolImpl loweringTool = new LoweringToolImpl(context, anchor, activeGuards, schedule.getCFG()); - final LoweringToolImpl loweringTool = new LoweringToolImpl(anchor, activeGuards, schedule.getCFG()); + // Lower the instructions of this block. + List nodes = schedule.nodesFor(b); - // Lower the instructions of this block. - List nodes = schedule.nodesFor(b); - - for (Node node : nodes) { - FixedNode nextFixedNode = null; - if (node instanceof FixedWithNextNode && node.isAlive()) { - FixedWithNextNode fixed = (FixedWithNextNode) node; - nextFixedNode = fixed.next(); - loweringTool.setLastFixedNode(fixed); - } + for (Node node : nodes) { + FixedNode nextFixedNode = null; + if (node instanceof FixedWithNextNode && node.isAlive()) { + FixedWithNextNode fixed = (FixedWithNextNode) node; + nextFixedNode = fixed.next(); + loweringTool.setLastFixedNode(fixed); + } - if (node.isAlive() && !processed.isMarked(node) && node instanceof Lowerable) { - if (loweringTool.lastFixedNode() == null) { - // We cannot lower the node now because we don't have a fixed node to anchor the - // replacements. - // This can happen when previous lowerings in this lowering iteration deleted - // the BeginNode of this block. - // In the next iteration, we will have the new BeginNode available, and we can - // lower this node. - deferred = true; - } else { - processed.mark(node); - ((Lowerable) node).lower(loweringTool); + if (node.isAlive() && !processed.isMarked(node) && node instanceof Lowerable) { + if (loweringTool.lastFixedNode() == null) { + /* + * We cannot lower the node now because we don't have a fixed node to anchor + * the replacements. This can happen when previous lowerings in this + * lowering iteration deleted the BeginNode of this block. In the next + * iteration, we will have the new BeginNode available, and we can lower + * this node. + */ + deferred = true; + } else { + processed.mark(node); + ((Lowerable) node).lower(loweringTool, loweringType); + } } - } - if (loweringTool.lastFixedNode() == node && !node.isAlive()) { - if (nextFixedNode == null || !nextFixedNode.isAlive()) { - loweringTool.setLastFixedNode(null); - } else { - Node prev = nextFixedNode.predecessor(); - if (prev != node && prev instanceof FixedWithNextNode) { - loweringTool.setLastFixedNode((FixedWithNextNode) prev); - } else if (nextFixedNode instanceof FixedWithNextNode) { - loweringTool.setLastFixedNode((FixedWithNextNode) nextFixedNode); + if (loweringTool.lastFixedNode() == node && !node.isAlive()) { + if (nextFixedNode == null || !nextFixedNode.isAlive()) { + loweringTool.setLastFixedNode(null); } else { - loweringTool.setLastFixedNode(null); + Node prev = nextFixedNode.predecessor(); + if (prev != node && prev instanceof FixedWithNextNode) { + loweringTool.setLastFixedNode((FixedWithNextNode) prev); + } else if (nextFixedNode instanceof FixedWithNextNode) { + loweringTool.setLastFixedNode((FixedWithNextNode) nextFixedNode); + } else { + loweringTool.setLastFixedNode(null); + } } } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Thu Apr 25 16:53:29 2013 +0200 @@ -35,6 +35,7 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; /** * This class is a phase that looks for opportunities for tail duplication. The static method @@ -129,10 +130,12 @@ @Override protected void run(StructuredGraph graph) { + NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply(); + // A snapshot is taken here, so that new MergeNode instances aren't considered for tail // duplication. for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) { - if (!(merge instanceof LoopBeginNode) && merge.probability() >= GraalOptions.TailDuplicationProbability) { + if (!(merge instanceof LoopBeginNode) && nodeProbabilities.get(merge) >= GraalOptions.TailDuplicationProbability) { tailDuplicate(merge, DEFAULT_DECISION, null); } } @@ -219,7 +222,7 @@ * */ private void duplicate() { - Debug.log("tail duplication at merge %s in %s (prob %f)", merge, graph.method(), merge.probability()); + Debug.log("tail duplication at merge %s in %s", merge, graph.method()); ValueAnchorNode anchor = addValueAnchor(); @@ -420,9 +423,7 @@ */ private EndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) { MergeNode newBottomMerge = graph.add(new MergeNode()); - newBottomMerge.setProbability(successor.probability()); EndNode newBottomEnd = graph.add(new EndNode()); - newBottomEnd.setProbability(successor.probability()); newBottomMerge.addForwardEnd(newBottomEnd); newBottomMerge.setStateAfter(stateAfterMerge); ((FixedWithNextNode) successor.predecessor()).setNext(newBottomEnd); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Thu Apr 25 16:53:29 2013 +0200 @@ -47,8 +47,6 @@ static boolean InlineMegamorphicCalls = ____; public static int MaximumDesiredSize = 5000; public static int MaximumRecursiveInlining = 1; - public static boolean LimitInlinedProbability = ____; - public static boolean LimitInlinedRelevance = true; public static float BoostInliningForEscapeAnalysis = 2f; public static float RelevanceCapForInlining = 1f; public static boolean IterativeInlining = ____; @@ -75,9 +73,6 @@ public static double TailDuplicationProbability = 0.5; public static int TailDuplicationTrivialSize = 1; - // absolute probability analysis - public static boolean ProbabilityAnalysis = true; - // profiling information public static int DeoptsToDisableOptimisticOptimization = 40; public static int MatureExecutionsBranch = 1; diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java Thu Apr 25 16:53:29 2013 +0200 @@ -53,10 +53,6 @@ if (checkDeoptimizations(method.getProfilingInfo(), deoptReason)) { enabledOpts.add(optimization); } else { - /* - * TODO (chaeubl): see GRAAL-75 (remove when we are sure that optimistic optimizations - * are not disabled unnecessarily - */ disabledOptimisticOptsMetric.increment(); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhasePlan.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhasePlan.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhasePlan.java Thu Apr 25 16:53:29 2013 +0200 @@ -51,7 +51,6 @@ public static enum PhasePosition { AFTER_PARSING, HIGH_LEVEL, - MID_LEVEL, LOW_LEVEL } // @formatter:on diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,223 @@ +/* + * Copyright (c) 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.graal.phases.graph; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.util.*; + +public class ComputeInliningRelevanceClosure { + + private static final double EPSILON = 1d / Integer.MAX_VALUE; + + private final StructuredGraph graph; + private final NodesToDoubles nodeProbabilities; + private final NodesToDoubles nodeRelevances; + + public ComputeInliningRelevanceClosure(StructuredGraph graph, NodesToDoubles nodeProbabilities) { + this.graph = graph; + this.nodeProbabilities = nodeProbabilities; + this.nodeRelevances = new NodesToDoubles(graph.getNodeCount()); + } + + public NodesToDoubles apply() { + new ComputeInliningRelevanceIterator(graph).apply(); + return nodeRelevances; + } + + private class ComputeInliningRelevanceIterator extends ScopedPostOrderNodeIterator { + + private final HashMap scopes; + private double currentProbability; + private double parentRelevance; + + public ComputeInliningRelevanceIterator(StructuredGraph graph) { + super(graph); + this.scopes = computeLowestPathProbabilities(); + } + + @Override + protected void initializeScope() { + Scope scope = scopes.get(currentScopeStart); + parentRelevance = getParentScopeRelevance(scope); + currentProbability = scope.minPathProbability; + } + + private double getParentScopeRelevance(Scope scope) { + if (scope.start instanceof LoopBeginNode) { + assert scope.parent != null; + double parentProbability = 0; + for (EndNode end : ((LoopBeginNode) scope.start).forwardEnds()) { + parentProbability += nodeProbabilities.get(end); + } + return parentProbability / scope.parent.minPathProbability; + } else { + assert scope.parent == null; + return 1.0; + } + } + + @Override + protected void invoke(Invoke invoke) { + double probability = nodeProbabilities.get(invoke.asNode()); + assert !Double.isNaN(probability); + + double relevance = (probability / currentProbability) * Math.min(1.0, parentRelevance); + nodeRelevances.put(invoke.asNode(), relevance); + assert !Double.isNaN(relevance); + } + + private HashMap computeLowestPathProbabilities() { + HashMap result = new HashMap<>(); + + for (Scope scope : computeScopes()) { + double lowestPathProbability = computeLowestPathProbability(scope); + scope.minPathProbability = Math.max(EPSILON, lowestPathProbability); + result.put(scope.start, scope); + } + + return result; + } + + private Scope[] computeScopes() { + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false); + + Loop[] loops = cfg.getLoops(); + HashMap processedScopes = new HashMap<>(); + Scope[] result = new Scope[loops.length + 1]; + Scope methodScope = new Scope(graph.start(), null); + processedScopes.put(null, methodScope); + + result[0] = methodScope; + for (int i = 0; i < loops.length; i++) { + result[i + 1] = createScope(loops[i], processedScopes); + } + + return result; + } + + private Scope createScope(Loop loop, HashMap processedLoops) { + Scope parent = processedLoops.get(loop.parent); + if (parent == null) { + parent = createScope(loop.parent, processedLoops); + } + Scope result = new Scope(loop.loopBegin(), parent); + processedLoops.put(loop, result); + return result; + } + + private double computeLowestPathProbability(Scope scope) { + FixedNode scopeStart = scope.start; + ArrayList pathBeginNodes = new ArrayList<>(); + pathBeginNodes.add(scopeStart); + double minPathProbability = nodeProbabilities.get(scopeStart); + boolean isLoopScope = scopeStart instanceof LoopBeginNode; + + do { + Node current = pathBeginNodes.remove(pathBeginNodes.size() - 1); + do { + if (isLoopScope && current instanceof LoopExitNode && ((LoopBeginNode) scopeStart).loopExits().contains((LoopExitNode) current)) { + return minPathProbability; + } else if (current instanceof LoopBeginNode && current != scopeStart) { + current = getMaxProbabilityLoopExit((LoopBeginNode) current, pathBeginNodes); + minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability); + } else if (current instanceof ControlSplitNode) { + current = getMaxProbabilitySux((ControlSplitNode) current, pathBeginNodes); + minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability); + } else { + assert current.successors().count() <= 1; + current = current.successors().first(); + } + } while (current != null); + } while (!pathBeginNodes.isEmpty()); + + return minPathProbability; + } + + private double getMinPathProbability(FixedNode current, double minPathProbability) { + if (current != null && nodeProbabilities.get(current) < minPathProbability) { + return nodeProbabilities.get(current); + } + return minPathProbability; + } + + private Node getMaxProbabilitySux(ControlSplitNode controlSplit, ArrayList pathBeginNodes) { + Node maxSux = null; + double maxProbability = 0.0; + int pathBeginCount = pathBeginNodes.size(); + + for (Node sux : controlSplit.successors()) { + double probability = controlSplit.probability((BeginNode) sux); + if (probability > maxProbability) { + maxProbability = probability; + maxSux = sux; + truncate(pathBeginNodes, pathBeginCount); + } else if (probability == maxProbability) { + pathBeginNodes.add((FixedNode) sux); + } + } + + return maxSux; + } + + private Node getMaxProbabilityLoopExit(LoopBeginNode loopBegin, ArrayList pathBeginNodes) { + Node maxSux = null; + double maxProbability = 0.0; + int pathBeginCount = pathBeginNodes.size(); + + for (LoopExitNode sux : loopBegin.loopExits()) { + double probability = nodeProbabilities.get(sux); + if (probability > maxProbability) { + maxProbability = probability; + maxSux = sux; + truncate(pathBeginNodes, pathBeginCount); + } else if (probability == maxProbability) { + pathBeginNodes.add(sux); + } + } + + return maxSux; + } + + private void truncate(ArrayList pathBeginNodes, int pathBeginCount) { + for (int i = pathBeginNodes.size() - pathBeginCount; i > 0; i--) { + pathBeginNodes.remove(pathBeginNodes.size() - 1); + } + } + } + + private static class Scope { + + public final FixedNode start; + public final Scope parent; + public double minPathProbability; + + public Scope(FixedNode start, Scope parent) { + this.start = start; + this.parent = parent; + } + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2011, 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.phases.graph; + +import java.util.*; + +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; + +/** + * Computes probabilities for nodes in a graph. + *

+ * The computation of absolute probabilities works in three steps: + *

    + *
  1. {@link PropagateProbability} traverses the graph in post order (merges after their ends, ...) + * and keeps track of the "probability state". Whenever it encounters a {@link ControlSplitNode} it + * uses the split's probability information to divide the probability upon the successors. Whenever + * it encounters an {@link Invoke} it assumes that the exception edge is unlikely and propagates the + * whole probability to the normal successor. Whenever it encounters a {@link MergeNode} it sums up + * the probability of all predecessors. It also maintains a set of active loops (whose + * {@link LoopBeginNode} has been visited) and builds def/use information for step 2.
  2. + *
  3. + *
  4. {@link PropagateLoopFrequency} propagates the loop frequencies and multiplies each + * {@link FixedNode}'s probability with its loop frequency.
  5. + *
+ * TODO: add exception probability information to Invokes + */ +public class ComputeProbabilityClosure { + + private static final double EPSILON = 1d / Integer.MAX_VALUE; + + private final StructuredGraph graph; + private final NodesToDoubles nodeProbabilities; + private final Set loopInfos; + private final Map> mergeLoops; + + public ComputeProbabilityClosure(StructuredGraph graph) { + this.graph = graph; + this.nodeProbabilities = new NodesToDoubles(graph.getNodeCount()); + this.loopInfos = new HashSet<>(); + this.mergeLoops = new IdentityHashMap<>(); + } + + public NodesToDoubles apply() { + new PropagateProbability(graph.start()).apply(); + Debug.dump(graph, "After PropagateProbability"); + computeLoopFactors(); + Debug.dump(graph, "After computeLoopFactors"); + new PropagateLoopFrequency(graph.start()).apply(); + return nodeProbabilities; + } + + private void computeLoopFactors() { + for (LoopInfo info : loopInfos) { + double frequency = info.loopFrequency(nodeProbabilities); + assert frequency != -1; + } + } + + private static boolean isRelativeProbability(double prob) { + // 1.01 to allow for some rounding errors + return prob >= 0 && prob <= 1.01; + } + + public static class LoopInfo { + + public final LoopBeginNode loopBegin; + + public final NodeMap> requires; + + private double loopFrequency = -1; + public boolean ended = false; + + public LoopInfo(LoopBeginNode loopBegin) { + this.loopBegin = loopBegin; + this.requires = loopBegin.graph().createNodeMap(); + } + + public double loopFrequency(NodesToDoubles nodeProbabilities) { + if (loopFrequency == -1 && ended) { + double backEdgeProb = 0.0; + for (LoopEndNode le : loopBegin.loopEnds()) { + double factor = 1; + Set requireds = requires.get(le); + for (LoopInfo required : requireds) { + double t = required.loopFrequency(nodeProbabilities); + if (t == -1) { + return -1; + } + factor *= t; + } + backEdgeProb += nodeProbabilities.get(le) * factor; + } + double d = nodeProbabilities.get(loopBegin) - backEdgeProb; + if (d < EPSILON) { + d = EPSILON; + } + loopFrequency = nodeProbabilities.get(loopBegin) / d; + loopBegin.setLoopFrequency(loopFrequency); + } + return loopFrequency; + } + } + + private class Probability implements MergeableState { + + public double probability; + public HashSet loops; + public LoopInfo loopInfo; + + public Probability(double probability, HashSet loops) { + this.probability = probability; + this.loops = new HashSet<>(4); + if (loops != null) { + this.loops.addAll(loops); + } + } + + @Override + public Probability clone() { + return new Probability(probability, loops); + } + + @Override + public boolean merge(MergeNode merge, List withStates) { + if (merge.forwardEndCount() > 1) { + HashSet intersection = new HashSet<>(loops); + for (Probability other : withStates) { + intersection.retainAll(other.loops); + } + for (LoopInfo info : loops) { + if (!intersection.contains(info)) { + double loopFrequency = info.loopFrequency(nodeProbabilities); + if (loopFrequency == -1) { + return false; + } + probability *= loopFrequency; + } + } + for (Probability other : withStates) { + double prob = other.probability; + for (LoopInfo info : other.loops) { + if (!intersection.contains(info)) { + double loopFrequency = info.loopFrequency(nodeProbabilities); + if (loopFrequency == -1) { + return false; + } + prob *= loopFrequency; + } + } + probability += prob; + } + loops = intersection; + mergeLoops.put(merge, new HashSet<>(intersection)); + assert isRelativeProbability(probability) : probability; + } + return true; + } + + @Override + public void loopBegin(LoopBeginNode loopBegin) { + loopInfo = new LoopInfo(loopBegin); + loopInfos.add(loopInfo); + loops.add(loopInfo); + } + + @Override + public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { + assert loopInfo != null; + List loopEnds = loopBegin.orderedLoopEnds(); + int i = 0; + for (Probability proba : loopEndStates) { + LoopEndNode loopEnd = loopEnds.get(i++); + Set requires = loopInfo.requires.get(loopEnd); + if (requires == null) { + requires = new HashSet<>(); + loopInfo.requires.set(loopEnd, requires); + } + for (LoopInfo innerLoop : proba.loops) { + if (innerLoop != loopInfo && !this.loops.contains(innerLoop)) { + requires.add(innerLoop); + } + } + } + loopInfo.ended = true; + } + + @Override + public void afterSplit(BeginNode node) { + assert node.predecessor() != null; + Node pred = node.predecessor(); + if (pred instanceof Invoke) { + Invoke x = (Invoke) pred; + if (x.next() != node) { + probability = 0; + } + } else { + assert pred instanceof ControlSplitNode; + ControlSplitNode x = (ControlSplitNode) pred; + probability *= x.probability(node); + } + } + } + + private class PropagateProbability extends PostOrderNodeIterator { + + public PropagateProbability(FixedNode start) { + super(start, new Probability(1d, null)); + } + + @Override + protected void node(FixedNode node) { + nodeProbabilities.put(node, state.probability); + } + } + + private class LoopCount implements MergeableState { + + public double count; + + public LoopCount(double count) { + this.count = count; + } + + @Override + public LoopCount clone() { + return new LoopCount(count); + } + + @Override + public boolean merge(MergeNode merge, List withStates) { + assert merge.forwardEndCount() == withStates.size() + 1; + if (merge.forwardEndCount() > 1) { + Set loops = mergeLoops.get(merge); + assert loops != null; + double countProd = 1; + for (LoopInfo loop : loops) { + countProd *= loop.loopFrequency(nodeProbabilities); + } + count = countProd; + } + return true; + } + + @Override + public void loopBegin(LoopBeginNode loopBegin) { + count *= loopBegin.loopFrequency(); + } + + @Override + public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { + // nothing to do... + } + + @Override + public void afterSplit(BeginNode node) { + // nothing to do... + } + } + + private class PropagateLoopFrequency extends PostOrderNodeIterator { + + public PropagateLoopFrequency(FixedNode start) { + super(start, new LoopCount(1d)); + } + + @Override + protected void node(FixedNode node) { + nodeProbabilities.put(node, nodeProbabilities.get(node) * state.count); + } + + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java Thu Apr 25 16:53:29 2013 +0200 @@ -29,4 +29,6 @@ PhaseSuite createHighTier(); PhaseSuite createMidTier(); + + PhaseSuite createLowTier(); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java Thu Apr 25 16:53:29 2013 +0200 @@ -24,10 +24,11 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.spi.*; public class HighTierContext extends PhaseContext { - public HighTierContext(MetaAccessProvider runtime, Assumptions assumptions) { - super(runtime, assumptions); + public HighTierContext(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements) { + super(runtime, assumptions, replacements); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/LowTierContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/LowTierContext.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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.graal.phases.tiers; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.spi.*; + +public class LowTierContext extends PhaseContext { + + private final TargetDescription target; + + public LowTierContext(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements, TargetDescription target) { + super(runtime, assumptions, replacements); + this.target = target; + } + + public TargetDescription getTarget() { + return target; + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/MidTierContext.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/MidTierContext.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/MidTierContext.java Thu Apr 25 16:53:29 2013 +0200 @@ -28,14 +28,14 @@ public class MidTierContext extends PhaseContext { - private final Replacements replacements; + private final TargetDescription target; - public MidTierContext(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements) { - super(runtime, assumptions); - this.replacements = replacements; + public MidTierContext(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements, TargetDescription target) { + super(runtime, assumptions, replacements); + this.target = target; } - public Replacements getReplacements() { - return replacements; + public TargetDescription getTarget() { + return target; } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/PhaseContext.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/PhaseContext.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/PhaseContext.java Thu Apr 25 16:53:29 2013 +0200 @@ -24,15 +24,18 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.spi.*; public class PhaseContext { private final MetaAccessProvider runtime; private final Assumptions assumptions; + private final Replacements replacements; - public PhaseContext(MetaAccessProvider runtime, Assumptions assumptions) { + public PhaseContext(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements) { this.runtime = runtime; this.assumptions = assumptions; + this.replacements = replacements; } public MetaAccessProvider getRuntime() { @@ -42,4 +45,8 @@ public Assumptions getAssumptions() { return assumptions; } + + public Replacements getReplacements() { + return replacements; + } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java Thu Apr 25 16:53:29 2013 +0200 @@ -33,6 +33,7 @@ private final PhaseSuite highTier; private final PhaseSuite midTier; + private final PhaseSuite lowTier; private static final Map configurations; @@ -44,6 +45,10 @@ return midTier; } + public PhaseSuite getLowTier() { + return lowTier; + } + static { configurations = new HashMap<>(); for (CompilerConfiguration config : ServiceLoader.loadInstalled(CompilerConfiguration.class)) { @@ -60,6 +65,7 @@ private Suites(CompilerConfiguration config) { highTier = config.createHighTier(); midTier = config.createMidTier(); + lowTier = config.createLowTier(); } public static Suites createDefaultSuites() { diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Thu Apr 25 16:53:29 2013 +0200 @@ -146,7 +146,8 @@ } else if (object instanceof StructuredGraph) { if (cfgPrinter.cfg == null) { - cfgPrinter.cfg = ControlFlowGraph.compute((StructuredGraph) object, true, true, true, false); + StructuredGraph graph = (StructuredGraph) object; + cfgPrinter.cfg = ControlFlowGraph.compute(graph, true, true, true, false); } cfgPrinter.printCFG(message, Arrays.asList(cfgPrinter.cfg.getBlocks())); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -50,7 +50,6 @@ StructuredGraph graph = parse(snippet); PhasePlan phasePlan = getDefaultPhasePlan(); Assumptions assumptions = new Assumptions(true); - new ComputeProbabilityPhase().apply(graph); Debug.dump(graph, "Graph"); new InliningPhase(runtime(), null, replacements, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); Debug.dump(graph, "Graph"); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Thu Apr 25 16:53:29 2013 +0200 @@ -379,10 +379,7 @@ end.disableSafepoint(); } - if (GraalOptions.ProbabilityAnalysis) { - new DeadCodeEliminationPhase().apply(graph); - new ComputeProbabilityPhase().apply(graph); - } + new DeadCodeEliminationPhase().apply(graph); return graph; } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -61,7 +61,7 @@ public static native void storeInt(Object obj, @ConstantNodeParameter int displacement, long offset, int value); @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { StructuredGraph graph = (StructuredGraph) this.graph(); IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, 1); WriteNode write = graph.add(new WriteNode(object, value, location, WriteBarrierType.NONE)); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -67,7 +67,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { StructuredGraph snippetGraph = getSnippetGraph(tool); InvokeNode invoke = replaceWithInvoke(); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/CyclicMaterializeStoreNode.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/CyclicMaterializeStoreNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/CyclicMaterializeStoreNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -68,7 +68,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { StructuredGraph graph = (StructuredGraph) graph(); ResolvedJavaType type = object.objectStamp().type(); FixedWithNextNode store; diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -79,7 +79,7 @@ } @Override - public void lower(LoweringTool tool) { + public void lower(LoweringTool tool, LoweringType loweringType) { virtualObject.materializeAt(this, values, isDefault(), lockCount); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Thu Apr 25 16:53:29 2013 +0200 @@ -169,7 +169,6 @@ MaterializeObjectNode materialize = new MaterializeObjectNode(virtual, obj.getLockCount()); ValueNode[] values = new ValueNode[obj.getEntries().length]; - materialize.setProbability(fixed.probability()); obj.escape(materialize, state); deferred.add(virtual); for (int i = 0; i < fieldState.length; i++) { diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Thu Apr 25 16:53:29 2013 +0200 @@ -33,7 +33,7 @@ public class GraphEffectList extends EffectList { - public void addCounterBefore(final String name, final int increment, final boolean addContext, final FixedNode position) { + public void addCounterBefore(final String group, final String name, final int increment, final boolean addContext, final FixedNode position) { if (!DynamicCounterNode.enabled) { return; } @@ -47,14 +47,13 @@ @Override public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { assert position.isAlive(); - DynamicCounterNode node = graph.add(new DynamicCounterNode(name, increment, addContext)); + DynamicCounterNode node = graph.add(new DynamicCounterNode(group, name, increment, addContext)); graph.addBeforeFixed(position, node); - node.setProbability(position.probability()); } }); } - public void addSurvivingCounterBefore(final String name, final int increment, final boolean addContext, final ValueNode checkedValue, final FixedNode position) { + public void addSurvivingCounterBefore(final String group, final String name, final int increment, final boolean addContext, final ValueNode checkedValue, final FixedNode position) { if (!DynamicCounterNode.enabled) { return; } @@ -68,9 +67,8 @@ @Override public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { assert position.isAlive(); - DynamicCounterNode node = graph.add(new SurvivingCounterNode(name, increment, addContext, checkedValue)); + DynamicCounterNode node = graph.add(new SurvivingCounterNode(group, name, increment, addContext, checkedValue)); graph.addBeforeFixed(position, node); - node.setProbability(position.probability()); } }); } @@ -94,7 +92,6 @@ public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { assert !node.isAlive() && !node.isDeleted() && position.isAlive(); graph.addBeforeFixed(position, graph.add(node)); - node.setProbability(position.probability()); } }); } @@ -140,7 +137,6 @@ public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { assert !node.isAlive() && !node.isDeleted() && position.isAlive(); graph.addBeforeFixed(position, graph.add(node)); - node.setProbability(position.probability()); for (int i = 0; i < values.length; i++) { node.getValues().set(i, values[i]); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Thu Apr 25 16:53:29 2013 +0200 @@ -31,6 +31,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer; @@ -200,20 +201,21 @@ } public static Map getHints(StructuredGraph graph) { + NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply(); Map hints = null; for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) { double sum = 0; double invokeSum = 0; for (Node usage : materialize.usages()) { if (usage instanceof FixedNode) { - sum += ((FixedNode) usage).probability(); + sum += probabilities.get((FixedNode) usage); } else { if (usage instanceof MethodCallTargetNode) { - invokeSum += ((MethodCallTargetNode) usage).invoke().probability(); + invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode()); } for (Node secondLevelUage : materialize.usages()) { if (secondLevelUage instanceof FixedNode) { - sum += ((FixedNode) secondLevelUage).probability(); + sum += probabilities.get(((FixedNode) secondLevelUage)); } } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/AssumptionsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/AssumptionsTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,139 @@ +/* + * 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.api.codegen.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.AssumptionsTestFactory.DerivedAssumptionNodeFactory; +import com.oracle.truffle.api.codegen.test.AssumptionsTestFactory.DerivedAssumptionRedeclaredNodeFactory; +import com.oracle.truffle.api.codegen.test.AssumptionsTestFactory.MultipleAssumptionsNodeFactory; +import com.oracle.truffle.api.codegen.test.AssumptionsTestFactory.SingleAssumptionNodeFactory; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; + +public class AssumptionsTest { + + @Test + public void testSingleAssumption() { + Assumption assumption = Truffle.getRuntime().createAssumption(); + TestRootNode root = TestHelper.createRoot(SingleAssumptionNodeFactory.getInstance(), assumption); + + Assert.assertEquals(42, TestHelper.executeWith(root)); + assumption.invalidate(); + Assert.assertEquals("42", TestHelper.executeWith(root)); + } + + @NodeAssumptions("assumption") + abstract static class SingleAssumptionNode extends ValueNode { + + @Specialization(order = 0, assumptions = "assumption") + int doInt() { + return 42; + } + + @Specialization + Object doObject() { + return "42"; + } + } + + @Test + public void testMultipleAssumption() { + Assumption assumption1 = Truffle.getRuntime().createAssumption(); + Assumption assumption2 = Truffle.getRuntime().createAssumption(); + TestRootNode root = TestHelper.createRoot(MultipleAssumptionsNodeFactory.getInstance(), assumption1, assumption2); + + Assert.assertEquals(42, TestHelper.executeWith(root)); + assumption2.invalidate(); + Assert.assertEquals("42", TestHelper.executeWith(root)); + assumption1.invalidate(); + Assert.assertEquals("43", TestHelper.executeWith(root)); + } + + @NodeAssumptions({"assumption1", "assumption2"}) + abstract static class MultipleAssumptionsNode extends ValueNode { + + @Specialization(assumptions = {"assumption1", "assumption2"}) + int doInt() { + return 42; + } + + @Specialization(assumptions = "assumption1") + Object doObject() { + return "42"; + } + + @Generic + Object doGeneric() { + return "43"; + } + } + + @Test + public void testDerivedAssumption() { + Assumption additionalAssumption = Truffle.getRuntime().createAssumption(); + Assumption assumption = Truffle.getRuntime().createAssumption(); + TestRootNode root = TestHelper.createRoot(DerivedAssumptionNodeFactory.getInstance(), assumption, additionalAssumption); + + Assert.assertEquals(42, TestHelper.executeWith(root)); + assumption.invalidate(); + Assert.assertEquals(43, TestHelper.executeWith(root)); + additionalAssumption.invalidate(); + Assert.assertEquals("42", TestHelper.executeWith(root)); + } + + @NodeAssumptions({"additionalAssumption"}) + abstract static class DerivedAssumptionNode extends SingleAssumptionNode { + + @Specialization(order = 1, assumptions = "additionalAssumption") + int doIntDerived() { + return 43; + } + } + + @Test + public void testDerivedAssumptionRedeclared() { + Assumption additionalAssumption = Truffle.getRuntime().createAssumption(); + Assumption assumption = Truffle.getRuntime().createAssumption(); + TestRootNode root = TestHelper.createRoot(DerivedAssumptionRedeclaredNodeFactory.getInstance(), additionalAssumption, assumption); + + Assert.assertEquals(42, TestHelper.executeWith(root)); + assumption.invalidate(); + Assert.assertEquals(43, TestHelper.executeWith(root)); + additionalAssumption.invalidate(); + Assert.assertEquals("42", TestHelper.executeWith(root)); + } + + @NodeAssumptions({"additionalAssumption", "assumption"}) + abstract static class DerivedAssumptionRedeclaredNode extends SingleAssumptionNode { + + @Specialization(order = 1, assumptions = "additionalAssumption") + int doIntDerived() { + return 43; + } + + } + +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -36,7 +36,7 @@ @Test public void testAdd() { - TestRootNode node = create(AddNodeFactory.getInstance()); + TestRootNode node = createRoot(AddNodeFactory.getInstance()); assertEquals(42, executeWith(node, 19, 23)); assertEquals(42d, executeWith(node, 19d, 23d)); assertEquals(42d, executeWith(node, "19", "23")); @@ -45,7 +45,7 @@ @Test(expected = RuntimeException.class) public void testAddUnsupported() { - TestRootNode node = create(AddNodeFactory.getInstance()); + TestRootNode node = createRoot(AddNodeFactory.getInstance()); executeWith(node, new Object(), new Object()); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -39,7 +39,7 @@ @Test public void testConcat() { - TestRootNode node = create(StrConcatFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrConcatFactory.getInstance(), new Context()); Str str1 = new Str("42"); Str str2 = new Str(" is the number."); assertEquals(str1.concat(str2), executeWith(node, str1, str2)); @@ -47,13 +47,13 @@ @Test(expected = UnsupportedOperationException.class) public void testConcatUnsupported() { - TestRootNode node = create(StrConcatFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrConcatFactory.getInstance(), new Context()); executeWith(node, 42, new Str(" is the number.")); } @Test public void testSubstrSpecialized() { - TestRootNode node = create(StrSubstrFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrSubstrFactory.getInstance(), new Context()); Str str = new Str("test 42"); assertEquals(str.substr(5, 7), executeWith(node, str, 5, 7)); @@ -61,7 +61,7 @@ @Test public void testSubstrGeneric() { - TestRootNode node = create(StrSubstrFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrSubstrFactory.getInstance(), new Context()); Str str = new Str("test 42"); assertEquals(Str.substr(str, "5", "7"), executeWith(node, str, "5", "7")); @@ -69,27 +69,27 @@ @Test(expected = UnsupportedOperationException.class) public void testSubstrUnsupported() { - TestRootNode node = create(StrSubstrFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrSubstrFactory.getInstance(), new Context()); executeWith(node, new Object(), "5", "7"); } @Test public void testLength() { - TestRootNode node = create(StrLengthFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrLengthFactory.getInstance(), new Context()); Str testStr = new Str("test 42"); assertEquals(testStr.length(), executeWith(node, testStr)); } @Test(expected = UnsupportedOperationException.class) public void testLengthUnsupported() { - TestRootNode node = create(StrLengthFactory.getInstance(), new Context()); + TestRootNode node = createRoot(StrLengthFactory.getInstance(), new Context()); executeWith(node, new Object()); } @Test public void testAccessContext() { Context context = new Context(); - TestRootNode node = create(StrAccessContextFactory.getInstance(), context); + TestRootNode node = createRoot(StrAccessContextFactory.getInstance(), context); // accessible by node assertSame(context, node.getNode().getContext()); // accessible by execution diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/ExecuteEvaluatedTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/ExecuteEvaluatedTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/ExecuteEvaluatedTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -22,48 +22,86 @@ */ package com.oracle.truffle.api.codegen.test; +import org.junit.*; + import com.oracle.truffle.api.*; import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.DoubleEvaluatedNodeFactory; +import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.EvaluatedNodeFactory; +import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.UseDoubleEvaluatedNodeFactory; +import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.UseEvaluatedNodeFactory; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ArgumentNode; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestArguments; import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; public class ExecuteEvaluatedTest { - /* Represents target[element] */ - @NodeChildren({@NodeChild("target"), @NodeChild("element")}) - abstract static class ReadElementNode extends ValueNode { + @Test + public void testSingleEvaluated() { + ArgumentNode arg0 = new ArgumentNode(0); + CallTarget callTarget = TestHelper.createCallTarget(UseEvaluatedNodeFactory.create(arg0, EvaluatedNodeFactory.create(null))); + + Assert.assertEquals(43, callTarget.call(new TestArguments(42))); + Assert.assertEquals(1, arg0.getInvocationCount()); + } + + @NodeChild("exp") + abstract static class EvaluatedNode extends ValueNode { @Specialization - int getInt(Object[] target, int element) { - return (int) target[element]; + int doExecuteWith(int exp) { + return exp + 1; } - public abstract Object executeWith(VirtualFrame frame, Object targetValue); + public abstract Object executeEvaluated(VirtualFrame frame, Object targetValue); + + public abstract int executeIntEvaluated(VirtualFrame frame, Object targetValue) throws UnexpectedResultException; } - /* Represents target[element]() */ - @NodeChildren({@NodeChild("target"), @NodeChild(value = "element", type = ReadElementNode.class, executeWith = "target")}) - abstract static class ElementCallNode extends ValueNode { + @NodeChildren({@NodeChild("exp0"), @NodeChild(value = "exp1", type = EvaluatedNode.class, executeWith = "exp0")}) + abstract static class UseEvaluatedNode extends ValueNode { @Specialization - Object call(Object receiver, Object callTarget) { - return ((CallTarget) callTarget).call(new TestArguments(receiver)); + int call(int exp0, int exp1) { + Assert.assertEquals(exp0 + 1, exp1); + return exp1; } + } + @Test + public void testDoubleEvaluated() { + ArgumentNode arg0 = new ArgumentNode(0); + ArgumentNode arg1 = new ArgumentNode(1); + CallTarget callTarget = TestHelper.createCallTarget(UseDoubleEvaluatedNodeFactory.create(arg0, arg1, DoubleEvaluatedNodeFactory.create(null, null))); + + Assert.assertEquals(85, callTarget.call(new TestArguments(42, 43))); + Assert.assertEquals(1, arg0.getInvocationCount()); + Assert.assertEquals(1, arg1.getInvocationCount()); } - public static class TestArguments extends Arguments { + @NodeChildren({@NodeChild("exp0"), @NodeChild("exp1")}) + abstract static class DoubleEvaluatedNode extends ValueNode { - private final Object receiver; - - public TestArguments(Object receiver) { - this.receiver = receiver; + @Specialization + int doExecuteWith(int exp0, int exp1) { + return exp0 + exp1; } - public Object getReceiver() { - return receiver; + public abstract Object executeEvaluated(VirtualFrame frame, Object exp0, Object exp1); + + public abstract int executeIntEvaluated(VirtualFrame frame, Object exp0, Object exp1) throws UnexpectedResultException; + } + + @NodeChildren({@NodeChild("exp0"), @NodeChild("exp1"), @NodeChild(value = "exp2", type = DoubleEvaluatedNode.class, executeWith = {"exp0", "exp1"})}) + abstract static class UseDoubleEvaluatedNode extends ValueNode { + + @Specialization + int call(int exp0, int exp1, int exp2) { + Assert.assertEquals(exp0 + exp1, exp2); + return exp2; } - } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -40,7 +40,7 @@ @Test public void testGuardInvocations() { - TestRootNode root = create(InvocationGuardFactory.getInstance()); + TestRootNode root = createRoot(InvocationGuardFactory.getInstance()); assertEquals(Integer.MAX_VALUE, executeWith(root, Integer.MAX_VALUE - 1, 1)); assertEquals(1, InvocationGuard.specializedInvocations); @@ -76,7 +76,7 @@ @Test public void testGuardGlobal() { - TestRootNode root = create(GlobalFlagGuardFactory.getInstance()); + TestRootNode root = createRoot(GlobalFlagGuardFactory.getInstance()); assertEquals(42, executeWith(root, NULL)); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java Thu Apr 25 16:53:29 2013 +0200 @@ -42,7 +42,7 @@ return nodes; } - static TestRootNode create(NodeFactory factory, Object... constants) { + static E createNode(NodeFactory factory, Object... constants) { ArgumentNode[] argumentNodes = arguments(factory.getExecutionSignature().size()); List argumentList = new ArrayList<>(); @@ -52,11 +52,23 @@ } else { argumentList.addAll(Arrays.asList(argumentNodes)); } - return new TestRootNode<>(factory.createNode(argumentList.toArray(new Object[argumentList.size()]))); + return factory.createNode(argumentList.toArray(new Object[argumentList.size()])); + } + + static TestRootNode createRoot(NodeFactory factory, Object... constants) { + return new TestRootNode<>(createNode(factory, constants)); + } + + static CallTarget createCallTarget(ValueNode node) { + return createCallTarget(new TestRootNode<>(node)); + } + + static CallTarget createCallTarget(TestRootNode node) { + return Truffle.getRuntime().createCallTarget(node); } static Object executeWith(TestRootNode node, Object... values) { - return Truffle.getRuntime().createCallTarget(node).call(new TestArguments(values)); + return createCallTarget(node).call(new TestArguments(values)); } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -101,14 +101,20 @@ public static class ArgumentNode extends ValueNode { + private int invocationCount; final int index; public ArgumentNode(int index) { this.index = index; } + public int getInvocationCount() { + return invocationCount; + } + @Override public Object execute(VirtualFrame frame) { + invocationCount++; return ((TestArguments) frame.getArguments()).get(index); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeAssumptions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeAssumptions.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,38 @@ +/* + * 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.api.codegen; + +import java.lang.annotation.*; + +/** + * Declares one or multiple assumptions for use inside a source code generation enabled node. + * Declared assumptions must be passed to the {@link NodeFactory#createNode(Object...)} method as + * parameters. + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE}) +public @interface NodeAssumptions { + + String[] value(); + +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java Thu Apr 25 16:53:29 2013 +0200 @@ -24,6 +24,8 @@ import java.lang.annotation.*; +import com.oracle.truffle.api.nodes.*; + @Retention(RetentionPolicy.CLASS) @Target({ElementType.TYPE}) public @interface NodeChild { @@ -32,5 +34,14 @@ Class type() default NodeClass.InheritNode.class; + /** + * Executes the {@link NodeChild} with values from other defined {@link NodeChild} elements. + * These referenced children must be defined before the current node in the execution order. The + * current node {@link #type()} attribute must be set to a {@link Node} which supports the + * evaluated execution with the number of {@link #executeWith()} arguments that are defined. For + * example if this child is executed with one argument, the {@link #type()} attribute must + * define a node which publicly declares a method with the signature + * Object execute*(VirtualFrame, Object). + */ String[] executeWith() default {}; } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java Thu Apr 25 16:53:29 2013 +0200 @@ -36,4 +36,11 @@ String[] guards() default {}; + /** + * Defines the assumptions to check for this specialization. When the specialization method is + * invoked it is guaranteed that the assigned assumptions still hold. To declare assumptions use + * the {@link NodeAssumptions} annotation at class level. + */ + String[] assumptions() default {}; + } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -34,12 +34,7 @@ *

* Dynamically typed languages can speculate on the type of a frame slot and only fall back at run * time to a more generic type if necessary. The new type of a frame slot can be set using the - * {@link FrameSlot#setType(Class)} method. It is the responsibility of the language implementor to - * update the content of currently active frames (using {@link Frame#updateToLatestVersion()}). - * Also, nodes that depend a specific type of a frame slot must be replaced. Such node can register - * a listener that implements {@link FrameSlotTypeListener} using - * {@link FrameSlot#registerOneShotTypeListener(FrameSlotTypeListener)}. The event of a type change - * on the frame slot will fire only once for the next upcoming change. + * {@link FrameSlot#setType(Class)} method. *

* *

@@ -53,10 +48,10 @@ public void test() { TruffleRuntime runtime = Truffle.getRuntime(); FrameDescriptor frameDescriptor = new FrameDescriptor(); - FrameSlot slot = frameDescriptor.addFrameSlot("localVar", Integer.class); + FrameSlot slot = frameDescriptor.addFrameSlot("localVar", int.class); TestRootNode rootNode = new TestRootNode(new IntAssignLocal(slot, new StringTestChildNode()), new IntReadLocal(slot)); CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor); - Assert.assertEquals(Integer.class, slot.getType()); + Assert.assertEquals(int.class, slot.getType()); Object result = target.call(); Assert.assertEquals("42", result); Assert.assertEquals(Object.class, slot.getType()); @@ -102,35 +97,29 @@ } - class IntAssignLocal extends FrameSlotNode implements FrameSlotTypeListener { + class IntAssignLocal extends FrameSlotNode { @Child private TestChildNode value; IntAssignLocal(FrameSlot slot, TestChildNode value) { super(slot); this.value = adoptChild(value); - slot.registerOneShotTypeListener(this); } @Override Object execute(VirtualFrame frame) { Object o = value.execute(frame); if (o instanceof Integer) { - frame.setInt(slot, (Integer) o); - } else { - slot.setType(Object.class); - frame.updateToLatestVersion(); - frame.setObject(slot, o); + try { + frame.setInt(slot, (Integer) o); + } catch (FrameSlotTypeException e) { + // fall through + } } + FrameUtil.setObjectSafe(frame, slot, o); + this.replace(new ObjectAssignLocal(slot, value)); return null; } - - @Override - public void typeChanged(FrameSlot changedSlot, Class oldType) { - if (changedSlot.getType() == Object.class) { - this.replace(new ObjectAssignLocal(changedSlot, value)); - } - } } class ObjectAssignLocal extends FrameSlotNode { @@ -145,27 +134,27 @@ @Override Object execute(VirtualFrame frame) { Object o = value.execute(frame); - frame.setObject(slot, o); + try { + frame.setObject(slot, o); + } catch (FrameSlotTypeException e) { + FrameUtil.setObjectSafe(frame, slot, o); + } return null; } } - class IntReadLocal extends FrameSlotNode implements FrameSlotTypeListener { + class IntReadLocal extends FrameSlotNode { IntReadLocal(FrameSlot slot) { super(slot); - slot.registerOneShotTypeListener(this); } @Override Object execute(VirtualFrame frame) { - return frame.getInt(slot); - } - - @Override - public void typeChanged(FrameSlot changedSlot, Class oldType) { - if (changedSlot.getType() == Object.class) { - this.replace(new ObjectReadLocal(changedSlot)); + try { + return frame.getInt(slot); + } catch (FrameSlotTypeException e) { + return this.replace(new ObjectReadLocal(slot)).execute(frame); } } } @@ -178,7 +167,11 @@ @Override Object execute(VirtualFrame frame) { - return frame.getObject(slot); + try { + return frame.getObject(slot); + } catch (FrameSlotTypeException e) { + throw new IllegalStateException(e); + } } } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -64,7 +64,7 @@ public void test() { TruffleRuntime runtime = Truffle.getRuntime(); FrameDescriptor frameDescriptor = new FrameDescriptor(); - FrameSlot slot = frameDescriptor.addFrameSlot("localVar", Integer.class); + FrameSlot slot = frameDescriptor.addFrameSlot("localVar", int.class); TestRootNode rootNode = new TestRootNode(new AssignLocal(slot), new ReadLocal(slot)); CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor); Object result = target.call(); @@ -109,7 +109,11 @@ @Override int execute(VirtualFrame frame) { - frame.setInt(slot, 42); + try { + frame.setInt(slot, 42); + } catch (FrameSlotTypeException e) { + throw new IllegalStateException(e); + } return 0; } } @@ -122,7 +126,11 @@ @Override int execute(VirtualFrame frame) { - return frame.getInt(slot); + try { + return frame.getInt(slot); + } catch (FrameSlotTypeException e) { + throw new IllegalStateException(e); + } } } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -47,10 +47,10 @@ public void test() { TruffleRuntime runtime = Truffle.getRuntime(); FrameDescriptor frameDescriptor = new FrameDescriptor(); - FrameSlot slot = frameDescriptor.addFrameSlot("localVar", Integer.class); + FrameSlot slot = frameDescriptor.addFrameSlot("localVar", int.class); TestRootNode rootNode = new TestRootNode(new IntAssignLocal(slot, new StringTestChildNode()), new IntReadLocal(slot)); CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor); - Assert.assertEquals(Integer.class, slot.getType()); + Assert.assertEquals(int.class, slot.getType()); Object result = target.call(); Assert.assertEquals("42", result); Assert.assertEquals(Object.class, slot.getType()); @@ -104,34 +104,31 @@ } - class IntAssignLocal extends FrameSlotNode implements FrameSlotTypeListener { + class IntAssignLocal extends FrameSlotNode { @Child private TestChildNode value; IntAssignLocal(FrameSlot slot, TestChildNode value) { super(slot); this.value = adoptChild(value); - slot.registerOneShotTypeListener(this); } @Override Object execute(VirtualFrame frame) { try { - frame.setInt(slot, value.executeInt(frame)); + int result = value.executeInt(frame); + try { + frame.setInt(slot, result); + } catch (FrameSlotTypeException e) { + FrameUtil.setObjectSafe(frame, slot, result); + replace(new ObjectAssignLocal(slot, value)); + } } catch (UnexpectedResultException e) { - slot.setType(Object.class); - frame.updateToLatestVersion(); - frame.setObject(slot, e.getResult()); + FrameUtil.setObjectSafe(frame, slot, e.getResult()); + replace(new ObjectAssignLocal(slot, value)); } return null; } - - @Override - public void typeChanged(FrameSlot changedSlot, Class oldType) { - if (changedSlot.getType() == Object.class) { - this.replace(new ObjectAssignLocal(changedSlot, value)); - } - } } class ObjectAssignLocal extends FrameSlotNode { @@ -146,32 +143,36 @@ @Override Object execute(VirtualFrame frame) { Object o = value.execute(frame); - frame.setObject(slot, o); + try { + frame.setObject(slot, o); + } catch (FrameSlotTypeException e) { + FrameUtil.setObjectSafe(frame, slot, o); + } return null; } } - class IntReadLocal extends FrameSlotNode implements FrameSlotTypeListener { + class IntReadLocal extends FrameSlotNode { IntReadLocal(FrameSlot slot) { super(slot); - slot.registerOneShotTypeListener(this); } @Override Object execute(VirtualFrame frame) { - return executeInt(frame); + try { + return frame.getInt(slot); + } catch (FrameSlotTypeException e) { + return replace(new ObjectReadLocal(slot)).execute(frame); + } } @Override - int executeInt(VirtualFrame frame) { - return frame.getInt(slot); - } - - @Override - public void typeChanged(FrameSlot changedSlot, Class oldType) { - if (changedSlot.getType() == Object.class) { - this.replace(new ObjectReadLocal(changedSlot)); + int executeInt(VirtualFrame frame) throws UnexpectedResultException { + try { + return frame.getInt(slot); + } catch (FrameSlotTypeException e) { + return replace(new ObjectReadLocal(slot)).executeInt(frame); } } } @@ -184,7 +185,11 @@ @Override Object execute(VirtualFrame frame) { - return frame.getObject(slot); + try { + return frame.getObject(slot); + } catch (FrameSlotTypeException e) { + throw new IllegalStateException(e); + } } } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Assumption.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Assumption.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,66 @@ +/* + * 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. + * + * 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; + +import com.oracle.truffle.api.nodes.*; + +/** + * An assumption is a global boolean flag that starts with the value true (i.e., the assumption is + * valid) and can subsequently be invalidated (using {@link Assumption#invalidate()}). Once + * invalidated, an assumption can never get valid again. Assumptions can be created using the + * {@link TruffleRuntime#createAssumption()} or the {@link TruffleRuntime#createAssumption(String)} + * method. The Truffle compiler has special knowledge of this class in order to produce efficient + * machine code for checking an assumption in case the assumption object is a compile time constant. + * Therefore, assumptions should be stored in final fields in Truffle nodes. + */ +public interface Assumption { + + /** + * Checks that this assumption is still valid. The method throws an exception, if this is no + * longer the case. This method is preferred over the {@link #isValid()} method when writing + * guest language interpreter code. The catch block should perform a node rewrite (see + * {@link Node#replace(Node)}) with a node that no longer relies on the assumption. + * + * @throws InvalidAssumptionException If the assumption is no longer valid. + */ + void check() throws InvalidAssumptionException; + + /** + * Checks whether the assumption is still valid. + * + * @return a boolean value indicating the validity of the assumption + */ + boolean isValid(); + + /** + * Invalidates this assumption. Performs no operation, if the assumption is already invalid. + */ + void invalidate(); + + /** + * A name for the assumption that is used for debug output. + * + * @return the name of the assumption + */ + String getName(); +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerAsserts.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerAsserts.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 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; + +/** + * Assertions about the code produced by the Truffle compiler. All operations have no effect when + * either executed in the interpreter or in the compiled code. The assertions are checked during + * code generation and the Truffle compiler produces for failing assertions a stack trace that + * identifies the code position of the assertion in the context of the current compilation. + * + */ +public class CompilerAsserts { + + /** + * Assertion that this code position should never be reached during compilation. It can be used + * for exceptional code paths or rare code paths that should never be included in a compilation + * unit. See {@link CompilerDirectives#transferToInterpreter()} for the corresponding compiler + * directive. + */ + public static void neverPartOfCompilation() { + } + + /** + * Assertion that the corresponding value is reduced to a constant during compilation. + * + * @param value the value that must be constant during compilation + * @return the value given as parameter + */ + public static boolean compilationConstant(boolean value) { + return value; + } + + /** + * Assertion that the corresponding value is reduced to a constant during compilation. + * + * @param value the value that must be constant during compilation + * @return the value given as parameter + */ + public static byte compilationConstant(byte value) { + return value; + } + + /** + * Assertion that the corresponding value is reduced to a constant during compilation. + * + * @param value the value that must be constant during compilation + * @return the value given as parameter + */ + public static char compilationConstant(char value) { + return value; + } + + /** + * Assertion that the corresponding value is reduced to a constant during compilation. + * + * @param value the value that must be constant during compilation + * @return the value given as parameter + */ + public static short compilationConstant(short value) { + return value; + } + + /** + * Assertion that the corresponding value is reduced to a constant during compilation. + * + * @param value the value that must be constant during compilation + * @return the value given as parameter + */ + public static int compilationConstant(int value) { + return value; + } + + /** + * Assertion that the corresponding value is reduced to a constant during compilation. + * + * @param value the value that must be constant during compilation + * @return the value given as parameter + */ + public static long compilationConstant(long value) { + return value; + } + + /** + * Assertion that the corresponding value is reduced to a constant during compilation. + * + * @param value the value that must be constant during compilation + * @return the value given as parameter + */ + public static float compilationConstant(float value) { + return value; + } + + /** + * Assertion that the corresponding value is reduced to a constant during compilation. + * + * @param value the value that must be constant during compilation + * @return the value given as parameter + */ + public static double compilationConstant(double value) { + return value; + } + + /** + * Assertion that the corresponding value is reduced to a constant during compilation. + * + * @param value the value that must be constant during compilation + * @return the value given as parameter + */ + public static Object compilationConstant(Object value) { + return value; + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 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; + +import java.util.concurrent.*; + +/** + * Directives that influence the optimizations of the Truffle compiler. All of the operations have + * no effect when executed in the Truffle interpreter. + */ +public class CompilerDirectives { + + private static final double SLOWPATH_PROBABILITY = 0.0001; + + /** + * Directive for the compiler to discontinue compilation at this code position and instead + * insert a transfer to the interpreter. + */ + public static void transferToInterpreter() { + } + + /** + * Directive for the compiler that the given runnable should only be executed in the interpreter + * and ignored in the compiled code. + * + * @param runnable the closure that should only be executed in the interpreter + */ + public static void interpreterOnly(Runnable runnable) { + runnable.run(); + } + + /** + * Directive for the compiler that the given callable should only be executed in the + * interpreter. + * + * @param callable the closure that should only be executed in the interpreter + * @return the result of executing the closure in the interpreter and null in the compiled code + * @throws Exception If the closure throws an exception when executed in the interpreter. + */ + public static T interpreterOnly(Callable callable) throws Exception { + return callable.call(); + } + + /** + * Directive for the compiler that the current path has a very low probability to be executed. + */ + public static void slowpath() { + injectBranchProbability(SLOWPATH_PROBABILITY); + } + + /** + * Injects a probability for the current path into the probability information of the + * immediately preceeding branch instruction. + * + * @param probability the probability value between 0.0 and 1.0 that should be injected + */ + public static void injectBranchProbability(double probability) { + assert probability >= 0.0 && probability <= 1.0; + } + + /** + * Bails out of a compilation (e.g., for guest language features that should never be compiled). + * + * @param reason the reason for the bailout + */ + public static void bailout(String reason) { + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExactMath.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExactMath.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,92 @@ +/* + * 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. + * + * 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; + +/** + * This class contains methods that will be part of java.lang.Math starting with JDK 8. Until JDK 8 + * is release, we duplicate them here because they are generally useful for dynamic language + * implementations. + */ +public class ExactMath { + + public static int addExact(int x, int y) { + int r = x + y; + // HD 2-12 Overflow iff both arguments have the opposite sign of the result + if (((x ^ r) & (y ^ r)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return r; + } + + public static long addExact(long x, long y) { + long r = x + y; + // HD 2-12 Overflow iff both arguments have the opposite sign of the result + if (((x ^ r) & (y ^ r)) < 0) { + throw new ArithmeticException("long overflow"); + } + return r; + } + + public static int subtractExact(int x, int y) { + int r = x - y; + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of x + if (((x ^ y) & (x ^ r)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return r; + } + + public static long subtractExact(long x, long y) { + long r = x - y; + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of x + if (((x ^ y) & (x ^ r)) < 0) { + throw new ArithmeticException("long overflow"); + } + return r; + } + + public static int multiplyExact(int x, int y) { + long r = (long) x * (long) y; + if ((int) r != r) { + throw new ArithmeticException("long overflow"); + } + return (int) r; + } + + public static long multiplyExact(long x, long y) { + long r = x * y; + long ax = Math.abs(x); + long ay = Math.abs(y); + if (((ax | ay) >>> 31 != 0)) { + // Some bits greater than 2^31 that might cause overflow + // Check the result using the divide operator + // and check for the special case of Long.MIN_VALUE * -1 + if (((y != 0) && (r / y != x)) || (x == Long.MIN_VALUE && y == -1)) { + throw new ArithmeticException("long overflow"); + } + } + return r; + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/LoopCountReceiver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/LoopCountReceiver.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,28 @@ +/* + * 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. + * + * 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; + +public interface LoopCountReceiver { + + void reportLoopCount(int count); +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 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; + +/** + * Represents the source code of a guest language program. + */ +public interface Source { + + /** + * Returns the name of this resource holding a guest language program. An example would be the + * name of a guest language source code file. + * + * @return the name of the guest language program + */ + String getName(); + + /** + * Returns the guest language source code represented by this source object. + * + * @return the source code as a String object + */ + String getCode(); +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 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; + +/** + * Represents a section in the source code of a guest language program. + */ +public class SourceSection { + + private final Source source; + private final String identifier; + private final int startLine; + private final int startColumn; + private final int charIndex; + private final int charLength; + + /** + * Creates a new object representing a section in the source code of a guest language program. + * + * @param source object representing the source program this is should be a section of + * @param identifier an identifier used when printing the section + * @param startLine the index of the start line of the section + * @param startColumn the index of the start column of the section + * @param charIndex the index of the first character of the section + * @param charLength the length of the section in number of characters + */ + public SourceSection(Source source, String identifier, int startLine, int startColumn, int charIndex, int charLength) { + this.source = source; + this.identifier = identifier; + this.startLine = startLine; + this.startColumn = startColumn; + this.charIndex = charIndex; + this.charLength = charLength; + } + + /** + * Returns the source object representing the source program this is a section of. + * + * @return the source object + */ + public final Source getSource() { + return source; + } + + /** + * Returns the index of the start line of this source section (inclusive). + * + * @return the start line + */ + public final int getStartLine() { + return startLine; + } + + /** + * Returns the index of the start column of this source section (inclusive). + * + * @return the start column + */ + public final int getStartColumn() { + return startColumn; + } + + /** + * Returns the index of the first character of this section. All characters of the source can be + * retrieved via the {@link Source#getCode()} method. + * + * @return the character index + */ + public final int getCharIndex() { + return charIndex; + } + + /** + * Returns the length of this section in characters. All characters of the source can be + * retrieved via the {@link Source#getCode()} method. + * + * @return the character length + */ + public final int getCharLength() { + return charLength; + } + + /** + * Returns the identifier of this source section that is used for printing the section. + * + * @return the identifier of the section + */ + public final String getIdentifier() { + return identifier; + } + + /** + * Returns the code represented by this code section. + * + * @return the code as a String object + */ + public final String getCode() { + return getSource().getCode().substring(charIndex, charLength); + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Thu Apr 25 16:53:29 2013 +0200 @@ -60,6 +60,21 @@ CallTarget createCallTarget(RootNode rootNode, FrameDescriptor frameDescriptor); /** + * Creates a new assumption object that can be checked and invalidated. + * + * @return the newly created assumption object + */ + Assumption createAssumption(); + + /** + * Creates a new assumption object with a given name that can be checked and invalidated. + * + * @param name the name for the new assumption + * @return the newly created assumption object + */ + Assumption createAssumption(String name); + + /** * Creates a new materialized frame object that can be used to store values. * * @return the newly created materialized frame object diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/DefaultTypeConversion.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/DefaultTypeConversion.java Mon Apr 22 18:30:33 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +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. - * - * 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.frame; - -/** - * Default type conversion semantics where a conversion is without changing any data. - */ -public final class DefaultTypeConversion implements TypeConversion { - - private static DefaultTypeConversion instance = new DefaultTypeConversion(); - - public static TypeConversion getInstance() { - return instance; - } - - private DefaultTypeConversion() { - - } - - @Override - public Class getTopType() { - return Object.class; - } - - @Override - public Object convertTo(Class targetType, Object value) { - return value; - } -} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java Thu Apr 25 16:53:29 2013 +0200 @@ -46,7 +46,7 @@ * @param slot the slot of the local variable * @return the current value of the local variable */ - Object getObject(FrameSlot slot); + Object getObject(FrameSlot slot) throws FrameSlotTypeException; /** * Write access to a local variable of type {@link Object}. @@ -54,7 +54,7 @@ * @param slot the slot of the local variable * @param value the new value of the local variable */ - void setObject(FrameSlot slot, Object value); + void setObject(FrameSlot slot, Object value) throws FrameSlotTypeException; /** * Read access to a local variable of type boolean. @@ -62,7 +62,7 @@ * @param slot the slot of the local variable * @return the current value of the local variable */ - boolean getBoolean(FrameSlot slot); + boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException; /** * Write access to a local variable of type boolean. @@ -70,7 +70,7 @@ * @param slot the slot of the local variable * @param value the new value of the local variable */ - void setBoolean(FrameSlot slot, boolean value); + void setBoolean(FrameSlot slot, boolean value) throws FrameSlotTypeException; /** * Read access to a local variable of type int. @@ -78,7 +78,7 @@ * @param slot the slot of the local variable * @return the current value of the local variable */ - int getInt(FrameSlot slot); + int getInt(FrameSlot slot) throws FrameSlotTypeException; /** * Write access to a local variable of type int. @@ -86,7 +86,7 @@ * @param slot the slot of the local variable * @param value the new value of the local variable */ - void setInt(FrameSlot slot, int value); + void setInt(FrameSlot slot, int value) throws FrameSlotTypeException; /** * Read access to a local variable of type long. @@ -94,7 +94,7 @@ * @param slot the slot of the local variable * @return the current value of the local variable */ - long getLong(FrameSlot slot); + long getLong(FrameSlot slot) throws FrameSlotTypeException; /** * Write access to a local variable of type long. @@ -102,7 +102,7 @@ * @param slot the slot of the local variable * @param value the new value of the local variable */ - void setLong(FrameSlot slot, long value); + void setLong(FrameSlot slot, long value) throws FrameSlotTypeException; /** * Read access to a local variable of type float. @@ -110,7 +110,7 @@ * @param slot the slot of the local variable * @return the current value of the local variable */ - float getFloat(FrameSlot slot); + float getFloat(FrameSlot slot) throws FrameSlotTypeException; /** * Write access to a local variable of type float. @@ -118,7 +118,7 @@ * @param slot the slot of the local variable * @param value the new value of the local variable */ - void setFloat(FrameSlot slot, float value); + void setFloat(FrameSlot slot, float value) throws FrameSlotTypeException; /** * Read access to a local variable of type double. @@ -126,7 +126,7 @@ * @param slot the slot of the local variable * @return the current value of the local variable */ - double getDouble(FrameSlot slot); + double getDouble(FrameSlot slot) throws FrameSlotTypeException; /** * Write access to a local variable of type double. @@ -134,9 +134,15 @@ * @param slot the slot of the local variable * @param value the new value of the local variable */ - void setDouble(FrameSlot slot, double value); + void setDouble(FrameSlot slot, double value) throws FrameSlotTypeException; - void updateToLatestVersion(); + /** + * Read access to a local variable of any type. + * + * @param slot the slot of the local variable + * @return the current value of the local variable or defaultValue if unset + */ + Object getValue(FrameSlot slot); /** * Converts this virtual frame into a packed frame that has no longer direct access to the local diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java Thu Apr 25 16:53:29 2013 +0200 @@ -24,30 +24,33 @@ import java.util.*; +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.impl.*; + /** * Descriptor of the slots of frame objects. Multiple frame instances are associated with one such * descriptor. */ -public final class FrameDescriptor { +public final class FrameDescriptor implements Cloneable { - protected final TypeConversion typeConversion; + private final FrameTypeConversion typeConversion; private final ArrayList slots; - private FrameVersionImpl lastVersion; private final HashMap identifierToSlotMap; + private Assumption version; public FrameDescriptor() { - this(DefaultTypeConversion.getInstance()); + this(DefaultFrameTypeConversion.getInstance()); } - public FrameDescriptor(TypeConversion typeConversion) { + public FrameDescriptor(FrameTypeConversion typeConversion) { this.typeConversion = typeConversion; slots = new ArrayList<>(); identifierToSlotMap = new HashMap<>(); - lastVersion = new FrameVersionImpl(); + version = createVersion(); } public FrameSlot addFrameSlot(Object identifier) { - return addFrameSlot(identifier, typeConversion.getTopType()); + return addFrameSlot(identifier, null); } public FrameSlot addFrameSlot(Object identifier, Class type) { @@ -55,6 +58,7 @@ FrameSlotImpl slot = new FrameSlotImpl(this, identifier, slots.size(), type); slots.add(slot); identifierToSlotMap.put(identifier, slot); + updateVersion(); return slot; } @@ -70,8 +74,12 @@ return addFrameSlot(identifier); } - public FrameVersion getCurrentVersion() { - return lastVersion; + public FrameSlot findOrAddFrameSlot(Object identifier, Class type) { + FrameSlot result = findFrameSlot(identifier); + if (result != null) { + return result; + } + return addFrameSlot(identifier, type); } public int getSize() { @@ -82,121 +90,42 @@ return Collections.unmodifiableList(slots); } - protected void appendVersion(FrameVersionImpl newVersion) { - lastVersion.next = newVersion; - lastVersion = newVersion; - } -} - -class FrameVersionImpl implements FrameVersion { - - protected FrameVersionImpl next; - - @Override - public final FrameVersion getNext() { - return next; - } -} - -class TypeChangeFrameVersionImpl extends FrameVersionImpl implements FrameVersion.TypeChange { - - private final FrameSlotImpl slot; - private final Class oldType; - private final Class newType; - - protected TypeChangeFrameVersionImpl(FrameSlotImpl slot, Class oldType, Class newType) { - this.slot = slot; - this.oldType = oldType; - this.newType = newType; - } - - @Override - public final void applyTransformation(Frame frame) { - Object value = slot.getValue(oldType, frame); - slot.setValue(newType, frame, value); - } -} - -class FrameSlotImpl implements FrameSlot { - - private final FrameDescriptor descriptor; - private final Object identifier; - private final int index; - private Class type; - private ArrayList listeners; - - protected FrameSlotImpl(FrameDescriptor descriptor, Object identifier, int index, Class type) { - this.descriptor = descriptor; - this.identifier = identifier; - this.index = index; - this.type = type; - assert type != null; - } - - public Object getIdentifier() { - return identifier; - } - - public int getIndex() { - return index; + /** + * (db) to retrieve the list of all the identifiers associated with this frame descriptor. + * + * @return the list of all the identifiers in this frame descriptor + */ + public Set getIdentifiers() { + return Collections.unmodifiableSet(identifierToSlotMap.keySet()); } - public Class getType() { - return type; - } - - protected Object getValue(Class accessType, Frame frame) { - if (accessType == Integer.class) { - return frame.getInt(this); - } else if (accessType == Long.class) { - return frame.getLong(this); - } else if (accessType == Float.class) { - return frame.getFloat(this); - } else if (accessType == Double.class) { - return frame.getDouble(this); - } else { - return frame.getObject(this); + /** + * (db): this method is used for creating a clone of the {@link FrameDescriptor} object ready + * for parallel execution. + */ + public FrameDescriptor copy() { + FrameDescriptor clonedFrameDescriptor = new FrameDescriptor(this.typeConversion); + for (int i = 0; i < this.getSlots().size(); i++) { + Object identifier = this.getSlots().get(i).getIdentifier(); + clonedFrameDescriptor.addFrameSlot(identifier); } + return clonedFrameDescriptor; } - protected void setValue(Class accessType, Frame frame, Object value) { - Object newValue = descriptor.typeConversion.convertTo(accessType, value); - if (accessType == Integer.class) { - frame.setInt(this, (Integer) newValue); - } else if (accessType == Long.class) { - frame.setLong(this, (Long) newValue); - } else if (accessType == Float.class) { - frame.setFloat(this, (Float) newValue); - } else if (accessType == Double.class) { - frame.setDouble(this, (Double) newValue); - } else { - frame.setObject(this, newValue); - } + void updateVersion() { + version.invalidate(); + version = createVersion(); + } + + public Assumption getVersion() { + return version; } - public void setType(final Class type) { - final Class oldType = this.type; - this.type = type; - ArrayList oldListeners = this.listeners; - this.listeners = null; - if (oldListeners != null) { - for (FrameSlotTypeListener listener : oldListeners) { - listener.typeChanged(this, oldType); - } - } - descriptor.appendVersion(new TypeChangeFrameVersionImpl(this, oldType, type)); + private static Assumption createVersion() { + return Truffle.getRuntime().createAssumption("frame version"); } - @Override - public String toString() { - return "[" + index + "," + identifier + "]"; - } - - @Override - public void registerOneShotTypeListener(FrameSlotTypeListener listener) { - if (listeners == null) { - listeners = new ArrayList<>(); - } - listeners.add(listener); + public FrameTypeConversion getTypeConversion() { + return typeConversion; } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java Thu Apr 25 16:53:29 2013 +0200 @@ -25,7 +25,7 @@ /** * A slot in a frame that can store a value of a given type. */ -public interface FrameSlot { +public interface FrameSlot extends Cloneable { Object getIdentifier(); @@ -35,5 +35,5 @@ void setType(Class type); - void registerOneShotTypeListener(FrameSlotTypeListener listener); + FrameDescriptor getFrameDescriptor(); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotImpl.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,66 @@ +/* + * 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. + * + * 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.frame; + +public final class FrameSlotImpl implements FrameSlot { + + private final FrameDescriptor descriptor; + private final Object identifier; + private final int index; + private Class type; + + protected FrameSlotImpl(FrameDescriptor descriptor, Object identifier, int index, Class type) { + this.descriptor = descriptor; + this.identifier = identifier; + this.index = index; + this.type = type; + } + + public Object getIdentifier() { + return identifier; + } + + public int getIndex() { + return index; + } + + public Class getType() { + return type; + } + + public void setType(final Class type) { + assert this.type != type; + this.type = type; + this.descriptor.updateVersion(); + } + + @Override + public String toString() { + return "[" + index + "," + identifier + "," + type + "]"; + } + + @Override + public FrameDescriptor getFrameDescriptor() { + return this.descriptor; + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotTypeException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotTypeException.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,36 @@ +/* + * 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. + * + * 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.frame; + +import com.oracle.truffle.api.nodes.*; + +/** + * Exception thrown if the frame slot type does not match the access type. + */ +public final class FrameSlotTypeException extends SlowPathException { + + private static final long serialVersionUID = 6972120475215757452L; + + public FrameSlotTypeException() { + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotTypeListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotTypeListener.java Mon Apr 22 18:30:33 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +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. - * - * 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.frame; - -/** - * Listener for the event of a type change of a frame slot. - */ -public interface FrameSlotTypeListener { - - void typeChanged(FrameSlot slot, Class oldType); -} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameTypeConversion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameTypeConversion.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 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.frame; + +/** + * Interface for defining type conversions for frame slot values. + */ +public interface FrameTypeConversion { + + Object getDefaultValue(); + + void updateFrameSlot(Frame frame, FrameSlot slot, Object value); +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 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.frame; + +public final class FrameUtil { + + /** + * Write access to a local variable of type {@link Object}. + * + * Sets the frame slot type to {@link Object} if it isn't already. + * + * @param slot the slot of the local variable + * @param value the new value of the local variable + */ + public static void setObjectSafe(Frame frame, FrameSlot slot, Object value) { + if (slot.getType() != Object.class) { + slot.setType(Object.class); + } + try { + frame.setObject(slot, value); + } catch (FrameSlotTypeException e) { + throw new IllegalStateException(); + } + } + + /** + * Write access to a local variable of type {@code boolean}. + * + * Sets the frame slot type to {@code boolean} if it isn't already. + * + * @param slot the slot of the local variable + * @param value the new value of the local variable + */ + public static void setBooleanSafe(Frame frame, FrameSlot slot, boolean value) { + if (slot.getType() != boolean.class) { + slot.setType(boolean.class); + } + try { + frame.setBoolean(slot, value); + } catch (FrameSlotTypeException e) { + throw new IllegalStateException(); + } + } + + /** + * Write access to a local variable of type {@code int}. + * + * Sets the frame slot type to {@code int} if it isn't already. + * + * @param slot the slot of the local variable + * @param value the new value of the local variable + */ + public static void setIntSafe(Frame frame, FrameSlot slot, int value) { + if (slot.getType() != int.class) { + slot.setType(int.class); + } + try { + frame.setInt(slot, value); + } catch (FrameSlotTypeException e) { + throw new IllegalStateException(); + } + } + + /** + * Write access to a local variable of type {@code long}. + * + * Sets the frame slot type to {@code long} if it isn't already. + * + * @param slot the slot of the local variable + * @param value the new value of the local variable + */ + public static void setLongSafe(Frame frame, FrameSlot slot, long value) { + if (slot.getType() != long.class) { + slot.setType(long.class); + } + try { + frame.setLong(slot, value); + } catch (FrameSlotTypeException e) { + throw new IllegalStateException(); + } + } + + /** + * Write access to a local variable of type {@code float}. + * + * Sets the frame slot type to {@code float} if it isn't already. + * + * @param slot the slot of the local variable + * @param value the new value of the local variable + */ + public static void setFloatSafe(Frame frame, FrameSlot slot, float value) { + if (slot.getType() != float.class) { + slot.setType(float.class); + } + try { + frame.setFloat(slot, value); + } catch (FrameSlotTypeException e) { + throw new IllegalStateException(); + } + } + + /** + * Write access to a local variable of type {@code double}. + * + * Sets the frame slot type to {@code double} if it isn't already. + * + * @param slot the slot of the local variable + * @param value the new value of the local variable + */ + public static void setDoubleSafe(Frame frame, FrameSlot slot, double value) { + if (slot.getType() != double.class) { + slot.setType(double.class); + } + try { + frame.setDouble(slot, value); + } catch (FrameSlotTypeException e) { + throw new IllegalStateException(); + } + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameVersion.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameVersion.java Mon Apr 22 18:30:33 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +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. - * - * 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.frame; - -/** - * Represents a specific version of a frame. - */ -public interface FrameVersion { - - FrameVersion getNext(); - - public interface Resize { - - int getNewSize(); - } - - public interface TypeChange { - - void applyTransformation(Frame frame); - } -} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/MaterializedFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/MaterializedFrame.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/MaterializedFrame.java Thu Apr 25 16:53:29 2013 +0200 @@ -30,4 +30,5 @@ * also does not provide access to the caller frame. */ public interface MaterializedFrame extends Frame { + } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java Thu Apr 25 16:53:29 2013 +0200 @@ -104,6 +104,11 @@ } @Override + public Object getValue(FrameSlot slot) { + throw new UnsupportedOperationException("native frame"); + } + + @Override public PackedFrame pack() { return this; } @@ -124,10 +129,6 @@ } @Override - public void updateToLatestVersion() { - } - - @Override public FrameDescriptor getFrameDescriptor() { throw new UnsupportedOperationException("native frame"); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/TypeConversion.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/TypeConversion.java Mon Apr 22 18:30:33 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +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. - * - * 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.frame; - -/** - * Interface for defining type conversions for frame slot values. - */ -public interface TypeConversion { - - Class getTopType(); - - Object convertTo(Class targetType, Object value); -} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractAssumption.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractAssumption.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,46 @@ +/* + * 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. + * + * 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.impl; + +import com.oracle.truffle.api.*; + +public abstract class AbstractAssumption implements Assumption { + + protected final String name; + protected boolean isValid; + + protected AbstractAssumption(String name) { + this.name = name; + this.isValid = true; + } + + @Override + public String getName() { + return name; + } + + @Override + public String toString() { + return "Assumption: " + name; + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultAssumption.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultAssumption.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,49 @@ +/* + * 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. + * + * 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.impl; + +import com.oracle.truffle.api.nodes.*; + +public final class DefaultAssumption extends AbstractAssumption { + + public DefaultAssumption(String name) { + super(name); + } + + @Override + public void check() throws InvalidAssumptionException { + if (!isValid) { + throw new InvalidAssumptionException(); + } + } + + @Override + public void invalidate() { + isValid = false; + } + + @Override + public boolean isValid() { + return isValid; + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java Thu Apr 25 16:53:29 2013 +0200 @@ -31,14 +31,15 @@ protected final RootNode rootNode; protected final FrameDescriptor frameDescriptor; - protected DefaultCallTarget(RootNode function, FrameDescriptor frameDescriptor) { + public DefaultCallTarget(RootNode function, FrameDescriptor frameDescriptor) { this.rootNode = function; this.frameDescriptor = frameDescriptor; + this.rootNode.setCallTarget(this); } @Override public String toString() { - return "DefaultCallTarget " + rootNode; + return "CallTarget " + rootNode; } @Override @@ -46,4 +47,8 @@ VirtualFrame frame = new DefaultVirtualFrame(frameDescriptor, caller, args); return rootNode.execute(frame); } + + public RootNode getRootNode() { + return rootNode; + } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultFrameTypeConversion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultFrameTypeConversion.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 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.impl; + +import com.oracle.truffle.api.frame.*; + +/** + * Interface for defining type conversions for frame slot values. + */ +public class DefaultFrameTypeConversion implements FrameTypeConversion { + + private static final DefaultFrameTypeConversion INSTANCE = new DefaultFrameTypeConversion(); + + @Override + public Object getDefaultValue() { + return null; + } + + @Override + public void updateFrameSlot(Frame frame, FrameSlot slot, Object value) { + FrameUtil.setObjectSafe(frame, slot, value); + } + + public static DefaultFrameTypeConversion getInstance() { + return INSTANCE; + } +} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java Thu Apr 25 16:53:29 2013 +0200 @@ -39,68 +39,68 @@ } @Override - public Object getObject(FrameSlot slot) { + public Object getObject(FrameSlot slot) throws FrameSlotTypeException { return wrapped.getObject(slot); } @Override - public void setObject(FrameSlot slot, Object value) { + public void setObject(FrameSlot slot, Object value) throws FrameSlotTypeException { wrapped.setObject(slot, value); } @Override - public boolean getBoolean(FrameSlot slot) { + public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException { return wrapped.getBoolean(slot); } @Override - public void setBoolean(FrameSlot slot, boolean value) { + public void setBoolean(FrameSlot slot, boolean value) throws FrameSlotTypeException { wrapped.setBoolean(slot, value); } @Override - public int getInt(FrameSlot slot) { + public int getInt(FrameSlot slot) throws FrameSlotTypeException { return wrapped.getInt(slot); } @Override - public void setInt(FrameSlot slot, int value) { + public void setInt(FrameSlot slot, int value) throws FrameSlotTypeException { wrapped.setInt(slot, value); } @Override - public long getLong(FrameSlot slot) { + public long getLong(FrameSlot slot) throws FrameSlotTypeException { return wrapped.getLong(slot); } @Override - public void setLong(FrameSlot slot, long value) { + public void setLong(FrameSlot slot, long value) throws FrameSlotTypeException { wrapped.setLong(slot, value); } @Override - public float getFloat(FrameSlot slot) { + public float getFloat(FrameSlot slot) throws FrameSlotTypeException { return wrapped.getFloat(slot); } @Override - public void setFloat(FrameSlot slot, float value) { + public void setFloat(FrameSlot slot, float value) throws FrameSlotTypeException { wrapped.setFloat(slot, value); } @Override - public double getDouble(FrameSlot slot) { + public double getDouble(FrameSlot slot) throws FrameSlotTypeException { return wrapped.getDouble(slot); } @Override - public void setDouble(FrameSlot slot, double value) { + public void setDouble(FrameSlot slot, double value) throws FrameSlotTypeException { wrapped.setDouble(slot, value); } @Override - public void updateToLatestVersion() { - wrapped.updateToLatestVersion(); + public Object getValue(FrameSlot slot) { + return wrapped.getValue(slot); } @Override diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java Thu Apr 25 16:53:29 2013 +0200 @@ -38,13 +38,13 @@ } @Override - public CallTarget createCallTarget(RootNode rootNode, FrameDescriptor frameDescriptor) { - return new DefaultCallTarget(rootNode, frameDescriptor); + public CallTarget createCallTarget(RootNode rootNode) { + return createCallTarget(rootNode, new FrameDescriptor()); } @Override - public CallTarget createCallTarget(RootNode rootNode) { - return createCallTarget(rootNode, new FrameDescriptor()); + public CallTarget createCallTarget(RootNode rootNode, FrameDescriptor frameDescriptor) { + return new DefaultCallTarget(rootNode, frameDescriptor); } @Override @@ -56,4 +56,14 @@ public MaterializedFrame createMaterializedFrame(Arguments arguments, FrameDescriptor frameDescriptor) { return new DefaultMaterializedFrame(new DefaultVirtualFrame(frameDescriptor, null, arguments)); } + + @Override + public Assumption createAssumption() { + return createAssumption(null); + } + + @Override + public Assumption createAssumption(String name) { + return new DefaultAssumption(name); + } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java Thu Apr 25 16:53:29 2013 +0200 @@ -29,29 +29,18 @@ public final class DefaultVirtualFrame implements VirtualFrame { - private static final Object UNDEFINED_OBJECT = null; - private static final Boolean UNDEFINED_BOOLEAN = false; - private static final Integer UNDEFINED_INTEGER = 0; - private static final Float UNDEFINED_FLOAT = 0.0f; - private static final Long UNDEFINED_LONG = 0L; - private static final Double UNDEFINED_DOUBLE = 0.0d; - private final FrameDescriptor descriptor; private final PackedFrame caller; private final Arguments arguments; - private FrameVersion currentVersion; - protected Object[] locals; - protected Class[] tags; + private Object[] locals; + private Class[] tags; public DefaultVirtualFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments arguments) { this.descriptor = descriptor; this.caller = caller; this.arguments = arguments; - this.currentVersion = descriptor.getCurrentVersion(); this.locals = new Object[descriptor.getSize()]; - // The tags are only needed for assertion checking, so initialize the field only when - // assertions are enabled - assert (this.tags = new Class[descriptor.getSize()]) != null; + this.tags = new Class[descriptor.getSize()]; } @Override @@ -75,126 +64,140 @@ } @Override - public Object getObject(FrameSlot slot) { - return get(slot, Object.class, UNDEFINED_OBJECT); - } - - @Override - public void setObject(FrameSlot slot, Object value) { - set(slot, Object.class, value); + public Object getObject(FrameSlot slot) throws FrameSlotTypeException { + verifyGet(slot, Object.class); + return locals[slot.getIndex()]; } @Override - public boolean getBoolean(FrameSlot slot) { - return (Boolean) get(slot, Boolean.class, UNDEFINED_BOOLEAN); - } - - @Override - public void setBoolean(FrameSlot slot, boolean value) { - set(slot, Boolean.class, value); - } - - @Override - public int getInt(FrameSlot slot) { - return (Integer) get(slot, Integer.class, UNDEFINED_INTEGER); + public void setObject(FrameSlot slot, Object value) throws FrameSlotTypeException { + verifySet(slot, Object.class); + locals[slot.getIndex()] = value; } @Override - public void setInt(FrameSlot slot, int value) { - set(slot, Integer.class, value); - } - - @Override - public long getLong(FrameSlot slot) { - return (Long) get(slot, Long.class, UNDEFINED_LONG); + public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException { + verifyGet(slot, boolean.class); + return (boolean) locals[slot.getIndex()]; } @Override - public void setLong(FrameSlot slot, long value) { - set(slot, Long.class, value); + public void setBoolean(FrameSlot slot, boolean value) throws FrameSlotTypeException { + verifySet(slot, boolean.class); + locals[slot.getIndex()] = value; } @Override - public float getFloat(FrameSlot slot) { - return (Float) get(slot, Float.class, UNDEFINED_FLOAT); - } - - @Override - public void setFloat(FrameSlot slot, float value) { - set(slot, Float.class, value); - } - - @Override - public double getDouble(FrameSlot slot) { - return (Double) get(slot, Double.class, UNDEFINED_DOUBLE); + public int getInt(FrameSlot slot) throws FrameSlotTypeException { + verifyGet(slot, int.class); + return (int) locals[slot.getIndex()]; } @Override - public void setDouble(FrameSlot slot, double value) { - set(slot, Double.class, value); - } - - private Object get(FrameSlot slot, Class accessType, Object defaultValue) { - Object value = locals[slot.getIndex()]; - assert verifyGet(slot, accessType, value); - if (value == null) { - return defaultValue; - } else { - return value; - } + public void setInt(FrameSlot slot, int value) throws FrameSlotTypeException { + verifySet(slot, int.class); + locals[slot.getIndex()] = value; } - private boolean verifyGet(FrameSlot slot, Class accessType, Object value) { - assert descriptor.getSlots().get(slot.getIndex()) == slot; - Class tag = tags[slot.getIndex()]; - if (value == null) { - assert tag == null || tag == Object.class; - } else { - assert tag == accessType : "Local variable " + slot + " was written with set" + tag.getSimpleName() + ", but is read with get" + accessType.getSimpleName(); - } - return true; + @Override + public long getLong(FrameSlot slot) throws FrameSlotTypeException { + verifyGet(slot, long.class); + return (long) locals[slot.getIndex()]; } - private void set(FrameSlot slot, Class accessType, Object value) { - assert verifySet(slot, accessType, value); + @Override + public void setLong(FrameSlot slot, long value) throws FrameSlotTypeException { + verifySet(slot, long.class); locals[slot.getIndex()] = value; } - private boolean verifySet(FrameSlot slot, Class accessType, Object value) { - assert descriptor.getSlots().get(slot.getIndex()) == slot; - tags[slot.getIndex()] = accessType; - assert accessType.isAssignableFrom(slot.getType()) : "Local variable " + slot + ": " + accessType + " is not assignable from " + slot.getType(); - if (value == null) { - assert accessType == Object.class; - } else { - assert slot.getType().isAssignableFrom(value.getClass()) : "Local variable " + slot + ": " + slot.getType() + " is not assignable from " + value.getClass(); - } - return true; + @Override + public float getFloat(FrameSlot slot) throws FrameSlotTypeException { + verifyGet(slot, float.class); + return (float) locals[slot.getIndex()]; } @Override - public void updateToLatestVersion() { - if (currentVersion.getNext() != null) { - doUpdateToLatestVersion(); - } + public void setFloat(FrameSlot slot, float value) throws FrameSlotTypeException { + verifySet(slot, float.class); + locals[slot.getIndex()] = value; } - private void doUpdateToLatestVersion() { - FrameVersion version = currentVersion; - while (version.getNext() != null) { - version = version.getNext(); - if (version instanceof FrameVersion.TypeChange) { - ((FrameVersion.TypeChange) version).applyTransformation(this); - } else if (version instanceof FrameVersion.Resize) { - int newSize = ((FrameVersion.Resize) version).getNewSize(); - locals = Arrays.copyOf(locals, newSize); - } - } - currentVersion = version; + @Override + public double getDouble(FrameSlot slot) throws FrameSlotTypeException { + verifyGet(slot, double.class); + return (double) locals[slot.getIndex()]; + } + + @Override + public void setDouble(FrameSlot slot, double value) throws FrameSlotTypeException { + verifySet(slot, double.class); + locals[slot.getIndex()] = value; } @Override public FrameDescriptor getFrameDescriptor() { return this.descriptor; } + + @Override + public Object getValue(FrameSlot slot) { + int index = slot.getIndex(); + if (index >= tags.length) { + assert index >= 0 && index < descriptor.getSize(); + return descriptor.getTypeConversion().getDefaultValue(); + } + Class tag = tags[index]; + if (tag == null) { + return descriptor.getTypeConversion().getDefaultValue(); + } else { + return locals[index]; + } + } + + private void verifySet(FrameSlot slot, Class accessType) throws FrameSlotTypeException { + Class slotType = slot.getType(); + if (slotType != accessType) { + if (slotType == null) { + slot.setType(accessType); + } else { + throw new FrameSlotTypeException(); + } + } + int slotIndex = slot.getIndex(); + if (slotIndex >= tags.length) { + resize(); + } + tags[slotIndex] = accessType; + } + + private void verifyGet(FrameSlot slot, Class accessType) throws FrameSlotTypeException { + Class slotType = slot.getType(); + if (slotType != accessType) { + if (slotType == null && accessType == Object.class) { + slot.setType(Object.class); + this.setObject(slot, descriptor.getTypeConversion().getDefaultValue()); + } else { + throw new FrameSlotTypeException(); + } + } + int slotIndex = slot.getIndex(); + if (slotIndex >= tags.length) { + resize(); + } + if (tags[slotIndex] != accessType) { + descriptor.getTypeConversion().updateFrameSlot(this, slot, getValue(slot)); + if (tags[slotIndex] != accessType) { + throw new FrameSlotTypeException(); + } + } + } + + private void resize() { + int newSize = descriptor.getSize(); + if (newSize > tags.length) { + locals = Arrays.copyOf(locals, newSize); + tags = Arrays.copyOf(tags, newSize); + } + } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/intrinsics/ExactMath.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/intrinsics/ExactMath.java Mon Apr 22 18:30:33 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +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. - * - * 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.intrinsics; - -/** - * This class contains methods that will be part of java.lang.Math starting with JDK 8. Until JDK 8 - * is release, we duplicate them here because they are generally useful for dynamic language - * implementations. - */ -public class ExactMath { - - public static int addExact(int x, int y) { - int r = x + y; - // HD 2-12 Overflow iff both arguments have the opposite sign of the result - if (((x ^ r) & (y ^ r)) < 0) { - throw new ArithmeticException("integer overflow"); - } - return r; - } - - public static long addExact(long x, long y) { - long r = x + y; - // HD 2-12 Overflow iff both arguments have the opposite sign of the result - if (((x ^ r) & (y ^ r)) < 0) { - throw new ArithmeticException("long overflow"); - } - return r; - } - - public static int subtractExact(int x, int y) { - int r = x - y; - // HD 2-12 Overflow iff the arguments have different signs and - // the sign of the result is different than the sign of x - if (((x ^ y) & (x ^ r)) < 0) { - throw new ArithmeticException("integer overflow"); - } - return r; - } - - public static long subtractExact(long x, long y) { - long r = x - y; - // HD 2-12 Overflow iff the arguments have different signs and - // the sign of the result is different than the sign of x - if (((x ^ y) & (x ^ r)) < 0) { - throw new ArithmeticException("long overflow"); - } - return r; - } - - public static int multiplyExact(int x, int y) { - long r = (long) x * (long) y; - if ((int) r != r) { - throw new ArithmeticException("long overflow"); - } - return (int) r; - } - - public static long multiplyExact(long x, long y) { - long r = x * y; - long ax = Math.abs(x); - long ay = Math.abs(y); - if (((ax | ay) >>> 31 != 0)) { - // Some bits greater than 2^31 that might cause overflow - // Check the result using the divide operator - // and check for the special case of Long.MIN_VALUE * -1 - if (((y != 0) && (r / y != x)) || (x == Long.MIN_VALUE && y == -1)) { - throw new ArithmeticException("long overflow"); - } - } - return r; - } -} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/intrinsics/TruffleIntrinsics.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/intrinsics/TruffleIntrinsics.java Mon Apr 22 18:30:33 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +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. - * - * 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.intrinsics; - -/** - * Predefined Truffle intrinsics that allow direct influence of the generated machine code. - */ -public final class TruffleIntrinsics { - - /** - * Specifies that the compiler should put a deoptimization point at this position that will - * continue execution in the interpreter. Should be used to cut off cold paths that should not - * be part of the compiled machine code. - */ - public static void deoptimize() { - } - - /** - * Checks whether the Thread has been interrupted in the interpreter in order to avoid endless - * loops. The compiled code may choose a more efficient implementation. - */ - public static void checkThreadInterrupted() { - if (Thread.currentThread().isInterrupted()) { - throw new RuntimeException("Timeout"); - } - } -} diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InvalidAssumptionException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InvalidAssumptionException.java Thu Apr 25 16:53:29 2013 +0200 @@ -0,0 +1,34 @@ +/* + * 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. + * + * 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; + +/** + * An exception that should be thrown if an assumption is checked and the check fails. The Truffle + * optimizer has special knowledge of this exception class and will never compile a catch block that + * catches this exception type. + */ +public final class InvalidAssumptionException extends SlowPathException { + + private static final long serialVersionUID = -6801338218909717979L; + +} diff -r 261a43921c5e -r 17b598df8da9 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 Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Thu Apr 25 16:53:29 2013 +0200 @@ -25,6 +25,8 @@ import java.lang.annotation.*; import java.util.*; +import com.oracle.truffle.api.*; + /** * Abstract base class for all Truffle nodes. */ @@ -37,6 +39,8 @@ private Node parent; + private SourceSection sourceSection; + /** * Marks array fields that are children of this node. */ @@ -54,6 +58,34 @@ } /** + * Assigns a link to a guest language source section to this node. + * + * @param section the object representing a section in guest language source code + */ + public final void assignSourceSection(SourceSection section) { + if (sourceSection != null) { + throw new IllegalStateException("Source section is already assigned."); + } + this.sourceSection = section; + } + + /** + * Clears any previously assigned guest language source code from this node. + */ + public final void clearSourceSection() { + this.sourceSection = null; + } + + /** + * Retrieves the guest language source code section that is currently assigned to this node. + * + * @return the assigned source code section + */ + public final SourceSection getSourceSection() { + return sourceSection; + } + + /** * Method that updates the link to the parent in the array of specified new child nodes to this * node. * @@ -103,38 +135,37 @@ } /** - * Replaces one child of this node with another node. + * Replaces this node with another node. If there is a source section (see + * {@link #getSourceSection()}) associated with this node, it is transferred to the new node. * - * @param oldChild the old child - * @param newChild the new child that should replace the old child - * @return the new child + * @param newNode the new node that is the replacement + * @param reason a description of the reason for the replacement + * @return the new node */ - public final T replaceChild(T oldChild, T newChild) { + @SuppressWarnings({"unchecked"}) + public final T replace(T newNode, String reason) { + assert this.getParent() != null; + if (sourceSection != null) { + // Pass on the source section to the new node. + newNode.assignSourceSection(sourceSection); + } + return (T) this.getParent().replaceChild(this, newNode); + } + + private T replaceChild(T oldChild, T newChild) { NodeUtil.replaceChild(this, oldChild, newChild); adoptChild(newChild); return newChild; } /** - * Replaces this node with another node. - * - * @param newNode the new node that is the replacement - * @param reason a description of the reason for the replacement - * @return the new node - */ - @SuppressWarnings({"unchecked"}) - public T replace(T newNode, String reason) { - assert this.getParent() != null; - return (T) this.getParent().replaceChild(this, newNode); - } - - /** - * Replaces this node with another node. + * Replaces this node with another node. If there is a source section (see + * {@link #getSourceSection()}) associated with this node, it is transferred to the new node. * * @param newNode the new node that is the replacement * @return the new node */ - public T replace(T newNode) { + public final T replace(T newNode) { return replace(newNode, ""); } diff -r 261a43921c5e -r 17b598df8da9 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 Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Thu Apr 25 16:53:29 2013 +0200 @@ -99,6 +99,18 @@ this.parentOffset = parentOffsetTemp; } + + public long getParentOffset() { + return parentOffset; + } + + public long[] getNodeFieldOffsets() { + return nodeFieldOffsets; + } + + public long[] getNodeArrayFieldOffsets() { + return nodeArrayFieldOffsets; + } } public static class NodeIterator implements Iterator { @@ -180,7 +192,7 @@ return array; } - private static final Unsafe unsafe = getUnsafe(); + protected static final Unsafe unsafe = getUnsafe(); private static Unsafe getUnsafe() { try { diff -r 261a43921c5e -r 17b598df8da9 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 Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -39,4 +39,14 @@ * @return the value of the execution */ public abstract Object execute(VirtualFrame frame); + + private CallTarget callTarget; + + public CallTarget getCallTarget() { + return callTarget; + } + + public void setCallTarget(CallTarget callTarget) { + this.callTarget = callTarget; + } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/SlowPathException.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/SlowPathException.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/SlowPathException.java Thu Apr 25 16:53:29 2013 +0200 @@ -33,7 +33,36 @@ /** * Creates an exception thrown to enter a slow path. */ + public SlowPathException() { + } + + /** + * Creates an exception thrown to enter a slow path. + */ public SlowPathException(String message, Throwable cause) { super(message, cause); } + + /** + * Creates an exception thrown to enter a slow path. + */ + public SlowPathException(String message) { + super(message); + } + + /** + * Creates an exception thrown to enter a slow path. + */ + public SlowPathException(Throwable cause) { + super(cause); + } + + /** + * For performance reasons, this exception does not record any stack trace information. + */ + @SuppressWarnings("sync-override") + @Override + public Throwable fillInStackTrace() { + return null; + } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java Thu Apr 25 16:53:29 2013 +0200 @@ -39,7 +39,6 @@ * @param result the alternative result */ public UnexpectedResultException(Object result) { - super(null, null); assert !(result instanceof Throwable); this.result = result; } @@ -50,13 +49,4 @@ public Object getResult() { return result; } - - /** - * For performance reasons, this exception does not record any stack trace information. - */ - @SuppressWarnings("sync-override") - @Override - public Throwable fillInStackTrace() { - return null; - } } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Thu Apr 25 16:53:29 2013 +0200 @@ -28,8 +28,8 @@ import javax.lang.model.type.*; import javax.tools.Diagnostic.*; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.intrinsics.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.nodes.Node.Children; @@ -43,10 +43,11 @@ private final TypeMirror nodeArray; private final TypeMirror unexpectedValueException; private final TypeMirror frame; + private final TypeMirror assumption; + private final TypeMirror invalidAssumption; private final DeclaredType childAnnotation; private final DeclaredType childrenAnnotation; - private final TypeMirror typeConversion; - private final TypeMirror truffleIntrinsics; + private final TypeMirror compilerDirectives; private final List errors = new ArrayList<>(); @@ -57,8 +58,9 @@ frame = getRequired(context, VirtualFrame.class); childAnnotation = getRequired(context, Child.class); childrenAnnotation = getRequired(context, Children.class); - typeConversion = getRequired(context, TypeConversion.class); - truffleIntrinsics = getRequired(context, TruffleIntrinsics.class); + compilerDirectives = getRequired(context, CompilerDirectives.class); + assumption = getRequired(context, Assumption.class); + invalidAssumption = getRequired(context, InvalidAssumptionException.class); } public boolean verify(ProcessorContext context, Element element, AnnotationMirror mirror) { @@ -81,12 +83,16 @@ return (DeclaredType) type; } - public TypeMirror getTruffleIntrinsics() { - return truffleIntrinsics; + public TypeMirror getInvalidAssumption() { + return invalidAssumption; } - public TypeMirror getTypeConversion() { - return typeConversion; + public TypeMirror getAssumption() { + return assumption; + } + + public TypeMirror getCompilerDirectives() { + return compilerDirectives; } public TypeMirror getNode() { diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Thu Apr 25 16:53:29 2013 +0200 @@ -44,8 +44,8 @@ } @Override - protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) { - List execTypes = nodeData.findGenericExecutableTypes(getContext()); + protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, int evaluatedCount) { + List execTypes = nodeData.findGenericExecutableTypes(getContext(), evaluatedCount); List types = new ArrayList<>(); for (ExecutableTypeData type : execTypes) { types.add(type.getType().getPrimitiveType()); @@ -57,7 +57,7 @@ @Override protected ParameterSpec createReturnParameterSpec() { - return super.createValueParameterSpec("returnValue", getNode()); + return super.createValueParameterSpec("returnValue", getNode(), 0); } @Override diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java Thu Apr 25 16:53:29 2013 +0200 @@ -22,10 +22,14 @@ */ package com.oracle.truffle.codegen.processor.node; +import java.util.*; + import javax.lang.model.element.*; import javax.lang.model.type.*; +import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.typesystem.*; public class NodeChildData extends MessageContainer { @@ -54,6 +58,9 @@ private final Cardinality cardinality; private final ExecutionKind executionKind; + + private List executeWith = Collections.emptyList(); + private NodeData nodeData; public NodeChildData(Element sourceElement, AnnotationMirror sourceMirror, String name, TypeMirror nodeType, Element accessElement, Cardinality cardinality, ExecutionKind executionKind) { @@ -66,6 +73,34 @@ this.executionKind = executionKind; } + public List getExecuteWith() { + return executeWith; + } + + void setExecuteWith(List executeWith) { + this.executeWith = executeWith; + } + + public ExecutableTypeData findExecutableType(ProcessorContext context, TypeData targetType) { + ExecutableTypeData executableType = nodeData.findExecutableType(targetType, getExecuteWith().size()); + if (executableType == null) { + executableType = findAnyGenericExecutableType(context); + } + return executableType; + } + + public List findGenericExecutableTypes(ProcessorContext context) { + return nodeData.findGenericExecutableTypes(context, getExecuteWith().size()); + } + + public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) { + return nodeData.findAnyGenericExecutableType(context, getExecuteWith().size()); + } + + public List findExecutableTypes() { + return nodeData.getExecutableTypes(getExecuteWith().size()); + } + @Override public Element getMessageElement() { return sourceElement; diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Thu Apr 25 16:53:29 2013 +0200 @@ -67,6 +67,10 @@ return name; } + private static String valueNameEvaluated(ActualParameter targetParameter) { + return valueName(targetParameter) + "Evaluated"; + } + private static String valueName(ActualParameter param) { return param.getLocalName(); } @@ -137,7 +141,7 @@ } } - private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) { + private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) { CodeTreeBuilder builder = parent.create(); boolean castedValues = sourceMethod != targetMethod; @@ -150,43 +154,47 @@ TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement()); NodeData node = (NodeData) targetMethod.getTemplate(); - boolean accessible = targetMethod.canBeAccessedByInstanceOf(getContext(), node.getNodeType()); - if (accessible) { - if (builder.findMethod().getModifiers().contains(STATIC)) { + if (target == null) { + boolean accessible = targetMethod.canBeAccessedByInstanceOf(getContext(), node.getNodeType()); + if (accessible) { + if (builder.findMethod().getModifiers().contains(STATIC)) { + if (method.getModifiers().contains(STATIC)) { + builder.type(targetClass.asType()); + } else { + builder.string(THIS_NODE_LOCAL_VAR_NAME); + } + } else { + if (targetMethod instanceof ExecutableTypeData) { + builder.string("this"); + } else { + builder.string("super"); + } + } + } else { if (method.getModifiers().contains(STATIC)) { builder.type(targetClass.asType()); } else { - builder.string(THIS_NODE_LOCAL_VAR_NAME); - } - } else { - if (targetMethod instanceof ExecutableTypeData) { - builder.string("this"); - } else { - builder.string("super"); + ActualParameter parameter = null; + for (ActualParameter searchParameter : targetMethod.getParameters()) { + if (searchParameter.getSpecification().isSignature()) { + parameter = searchParameter; + break; + } + } + ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName()); + assert parameter != null; + + if (castedValues && sourceParameter != null) { + builder.string(valueName(sourceParameter, parameter)); + } else { + builder.string(valueName(parameter)); + } } } + builder.string("."); } else { - if (method.getModifiers().contains(STATIC)) { - builder.type(targetClass.asType()); - } else { - ActualParameter parameter = null; - for (ActualParameter searchParameter : targetMethod.getParameters()) { - if (searchParameter.getSpecification().isSignature()) { - parameter = searchParameter; - break; - } - } - ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName()); - assert parameter != null; - - if (castedValues && sourceParameter != null) { - builder.string(valueName(sourceParameter, parameter)); - } else { - builder.string(valueName(parameter)); - } - } + builder.tree(target); } - builder.string("."); builder.startCall(method.getSimpleName().toString()); for (ActualParameter targetParameter : targetMethod.getParameters()) { @@ -289,11 +297,11 @@ } private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData sourceSpecialization, SpecializationData targetSpecialization, boolean castValues, - CodeTree guardedStatements, CodeTree elseStatements) { + CodeTree guardedStatements, CodeTree elseStatements, boolean emitAssumptions) { NodeData node = targetSpecialization.getNode(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); - CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, sourceSpecialization, targetSpecialization); + CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, sourceSpecialization, targetSpecialization, emitAssumptions); CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, sourceSpecialization, targetSpecialization); Set valuesNeedsCast; @@ -304,14 +312,20 @@ // find out which values needs a cast valuesNeedsCast = new HashSet<>(); for (GuardData guard : targetSpecialization.getGuards()) { - for (ActualParameter parameter : guard.getParameters()) { - NodeChildData field = node.findChild(parameter.getSpecification().getName()); + for (ActualParameter targetParameter : guard.getParameters()) { + NodeChildData field = node.findChild(targetParameter.getSpecification().getName()); if (field == null) { continue; } - TypeData typeData = parameter.getTypeSystemType(); - if (typeData != null && !typeData.isGeneric()) { - valuesNeedsCast.add(parameter.getLocalName()); + TypeData targetType = targetParameter.getTypeSystemType(); + ActualParameter sourceParameter = sourceSpecialization.findParameter(targetParameter.getLocalName()); + if (sourceParameter == null) { + sourceParameter = targetParameter; + } + TypeData sourceType = sourceParameter.getTypeSystemType(); + + if (sourceType.needsCastTo(targetType)) { + valuesNeedsCast.add(targetParameter.getLocalName()); } } } @@ -353,14 +367,14 @@ return builder.getRoot(); } - private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { + private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, TemplateMethod valueSpecialization, SpecializationData guardedSpecialization) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; if (guardedSpecialization.getGuards().size() > 0) { // Explicitly specified guards for (GuardData guard : guardedSpecialization.getGuards()) { builder.string(andOperator); - builder.tree(createTemplateMethodCall(parent, valueSpecialization, guard, null)); + builder.tree(createTemplateMethodCall(parent, null, valueSpecialization, guard, null)); andOperator = " && "; } } @@ -368,7 +382,7 @@ return builder.isEmpty() ? null : builder.getRoot(); } - private CodeTree createCasts(CodeTreeBuilder parent, Set castWhiteList, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { + private CodeTree createCasts(CodeTreeBuilder parent, Set castWhiteList, TemplateMethod valueSpecialization, SpecializationData guardedSpecialization) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); // Implict guards based on method signature for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { @@ -378,6 +392,14 @@ } ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName()); + if (valueParam == null) { + /* + * If used inside a function execute method. The value param may not exist. In that + * case it assumes that the value is already converted. + */ + valueParam = guardedParam; + } + if (castWhiteList != null && !castWhiteList.contains(guardedParam.getLocalName())) { continue; } @@ -392,10 +414,26 @@ return builder.getRoot(); } - private CodeTree createImplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { + private CodeTree createImplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean emitAssumptions) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); // Implict guards based on method signature String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; + + if (emitAssumptions) { + boolean isStatic = parent.findMethod().getModifiers().contains(STATIC); + + for (String assumption : guardedSpecialization.getAssumptions()) { + builder.string(andOperator); + if (isStatic) { + builder.string(THIS_NODE_LOCAL_VAR_NAME); + } else { + builder.string("this"); + } + builder.string(".").string(assumption).string(".isValid()"); + andOperator = " && "; + } + } + for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { NodeChildData field = guardedSpecialization.getNode().findChild(guardedParam.getSpecification().getName()); if (field == null) { @@ -403,6 +441,14 @@ } ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName()); + if (valueParam == null) { + /* + * If used inside a function execute method. The value param may not exist. In that + * case it assumes that the value is already converted. + */ + valueParam = guardedParam; + } + CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam); if (implicitGuard == null) { continue; @@ -423,7 +469,7 @@ TypeData targetType = target.getTypeSystemType(); TypeData sourceType = source.getTypeSystemType(); - if (targetType.equalsType(sourceType) || targetType.isGeneric()) { + if (!sourceType.needsCastTo(targetType)) { return null; } @@ -528,6 +574,19 @@ return constructors; } + private static ExecutableElement findCopyConstructor(TypeMirror type) { + for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(type).getEnclosedElements())) { + if (constructor.getModifiers().contains(PRIVATE)) { + continue; + } + if (isCopyConstructor(constructor)) { + return constructor; + } + } + + return null; + } + private static boolean isCopyConstructor(ExecutableElement element) { if (element.getParameters().size() != 1) { return false; @@ -578,6 +637,10 @@ } } + for (String assumption : node.getAssumptions()) { + clazz.add(createAssumptionField(assumption)); + } + createConstructors(node, clazz); if (node.getExtensionElements() != null) { @@ -588,103 +651,102 @@ } private void createConstructors(NodeData node, CodeTypeElement clazz) { - List signatureConstructors = new ArrayList<>(); - ExecutableElement copyConstructor = null; - List constructors = ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements()); - for (ExecutableElement constructor : constructors) { - if (constructor.getModifiers().contains(Modifier.PRIVATE) || constructor.getParameters().isEmpty()) { - continue; - } - - if (isCopyConstructor(constructor)) { - assert copyConstructor == null; - copyConstructor = createConstructor(clazz, constructor, true); - } else { - signatureConstructors.add(createConstructor(clazz, constructor, false)); + List constructors = findUserConstructors(node.getNodeType()); + if (constructors.isEmpty()) { + clazz.add(createUserConstructor(clazz, null)); + } else { + for (ExecutableElement constructor : constructors) { + clazz.add(createUserConstructor(clazz, constructor)); } } - - if (copyConstructor == null && node.needsRewrites(getContext())) { - clazz.add(createConstructor(clazz, null, true)); - } else if (copyConstructor != null) { - clazz.add(copyConstructor); - } - - if (signatureConstructors.isEmpty() && !node.getChildren().isEmpty()) { - clazz.add(createConstructor(clazz, null, false)); - } else { - clazz.getEnclosedElements().addAll(signatureConstructors); + if (node.needsRewrites(getContext())) { + clazz.add(createCopyConstructor(clazz, findCopyConstructor(node.getNodeType()))); } } - private CodeExecutableElement createConstructor(CodeTypeElement type, ExecutableElement superConstructor, boolean copyConstructor) { + private CodeExecutableElement createUserConstructor(CodeTypeElement type, ExecutableElement superConstructor) { CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); CodeTreeBuilder builder = method.createBuilder(); - if (!copyConstructor) { - if (superConstructor != null) { - for (VariableElement param : superConstructor.getParameters()) { - method.getParameters().add(CodeVariableElement.clone(param)); - } + + if (superConstructor != null) { + for (VariableElement param : superConstructor.getParameters()) { + method.getParameters().add(CodeVariableElement.clone(param)); } - for (NodeChildData child : getModel().getChildren()) { - method.getParameters().add(new CodeVariableElement(child.getNodeType(), child.getName())); - } - } else { - if (!(superConstructor == null && getModel().getChildren().isEmpty())) { - method.getParameters().add(new CodeVariableElement(type.asType(), "copy")); - } + } + + for (VariableElement var : type.getFields()) { + method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString())); } if (superConstructor != null) { - builder.startStatement(); - builder.startSuperCall(); - if (copyConstructor) { - builder.string("copy"); - } else { - for (VariableElement param : superConstructor.getParameters()) { - builder.string(param.getSimpleName().toString()); - } + builder.startStatement().startSuperCall(); + for (VariableElement param : superConstructor.getParameters()) { + builder.string(param.getSimpleName().toString()); } - builder.end(); - builder.end(); + builder.end().end(); } - for (NodeChildData child : getModel().getChildren()) { - + for (VariableElement var : type.getFields()) { builder.startStatement(); - builder.string("this.").string(child.getName()).string(" = "); - - if (child.getCardinality() == Cardinality.MANY) { - builder.startCall("adoptChildren"); + String varName = var.getSimpleName().toString(); + builder.string("this.").string(varName); + if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { + builder.string(" = adoptChild(").string(varName).string(")"); + } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { + builder.string(" = adoptChildren(").string(varName).string(")"); } else { - builder.startCall("adoptChild"); + builder.string(" = ").string(varName); } - - builder.startGroup(); - if (copyConstructor) { - builder.string("copy."); - } - builder.string(child.getName()); builder.end(); - - builder.end(); - builder.end(); - } - return method; } + private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor) { + CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); + CodeTreeBuilder builder = method.createBuilder(); + if (!(superConstructor == null && type.getFields().isEmpty())) { + method.getParameters().add(new CodeVariableElement(type.asType(), "copy")); + } + + if (superConstructor != null) { + builder.startStatement().startSuperCall().string("copy").end().end(); + } + + for (VariableElement var : type.getFields()) { + builder.startStatement(); + String varName = var.getSimpleName().toString(); + builder.string("this.").string(varName); + if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { + builder.string(" = adoptChild(copy.").string(varName).string(")"); + } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { + builder.string(" = adoptChildren(copy.").string(varName).string(")"); + } else { + builder.string(" = copy.").string(varName); + } + builder.end(); + } + return method; + } + + private CodeVariableElement createAssumptionField(String assumption) { + CodeVariableElement var = new CodeVariableElement(getContext().getTruffleTypes().getAssumption(), assumption); + var.getModifiers().add(Modifier.FINAL); + return var; + } + private CodeVariableElement createChildField(NodeChildData child) { + CodeVariableElement var = new CodeVariableElement(child.getNodeType(), child.getName()); + var.getModifiers().add(Modifier.PROTECTED); + DeclaredType annotationType; if (child.getCardinality() == Cardinality.MANY) { + var.getModifiers().add(Modifier.FINAL); annotationType = getContext().getTruffleTypes().getChildrenAnnotation(); } else { annotationType = getContext().getTruffleTypes().getChildAnnotation(); } - CodeVariableElement var = new CodeVariableElement(child.getNodeType(), child.getName()); - var.getModifiers().add(Modifier.PROTECTED); var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType)); return var; } @@ -726,11 +788,8 @@ createFactoryMethods(node, clazz, createVisibility); - if (node.getSpecializations().size() > 1) { + if (node.needsRewrites(context)) { clazz.add(createCreateSpecializedMethod(node, createVisibility)); - } - - if (node.needsRewrites(context)) { clazz.add(createSpecializeMethod(node)); } @@ -910,7 +969,7 @@ private CodeExecutableElement createCreateNodeSpecializedMethod(NodeData node) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNodeSpecialized"); - CodeVariableElement nodeParam = new CodeVariableElement(node.getNodeType(), "thisNode"); + CodeVariableElement nodeParam = new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME); CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Class.class), "types"); method.addParameter(nodeParam); method.addParameter(arguments); @@ -926,7 +985,9 @@ builder.startBlock(); builder.startReturn().startCall("createSpecialized"); - builder.string("thisNode"); + builder.startGroup(); + builder.string(THIS_NODE_LOCAL_VAR_NAME); + builder.end(); builder.string("types[0]"); builder.end().end(); @@ -1083,10 +1144,16 @@ CodeTreeBuilder body = method.createBuilder(); - body.startStatement(); - body.type(generatedNode.asType()).string(" ").string(THIS_NODE_LOCAL_VAR_NAME + "Cast"); - body.string(" = ").string("(").type(generatedNode.asType()).string(") ").string(THIS_NODE_LOCAL_VAR_NAME); - body.end(); + boolean hasCopyConstructor = findCopyConstructor(generatedNode.asType()) != null; + + final String thisLocalVariableName = THIS_NODE_LOCAL_VAR_NAME + "Cast"; + + if (hasCopyConstructor) { + body.startStatement(); + body.type(generatedNode.asType()).string(" ").string(thisLocalVariableName); + body.string(" = ").string("(").type(generatedNode.asType()).string(") ").string(THIS_NODE_LOCAL_VAR_NAME); + body.end(); + } boolean first = true; for (TypeData type : node.getTypeSystem().getTypes()) { @@ -1099,16 +1166,12 @@ body.startElseIf(); } body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock(); - body.startReturn().startNew(nodeSpecializationClassName(specialization)); - body.string(THIS_NODE_LOCAL_VAR_NAME + "Cast"); - body.end().end(); // new, return + body.tree(createReturnNewSpecialization(body, specialization, thisLocalVariableName, hasCopyConstructor)); body.end(); // if } } - body.startReturn().startNew(nodeSpecializationClassName(node.getGenericSpecialization())); - body.string(THIS_NODE_LOCAL_VAR_NAME + "Cast"); - body.end().end(); + body.tree(createReturnNewSpecialization(body, node.getGenericSpecialization(), thisLocalVariableName, hasCopyConstructor)); return method; } @@ -1121,22 +1184,31 @@ CodeTreeBuilder body = method.createBuilder(); body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); + boolean hasCopyConstructor = findCopyConstructor(generatedNode.asType()) != null; + for (int i = 1; i < node.getSpecializations().size(); i++) { SpecializationData specialization = node.getSpecializations().get(i); body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(specialization)).string(".class)").end(); - CodeTreeBuilder guarded = new CodeTreeBuilder(body); - guarded.startReturn().startNew(nodeSpecializationClassName(specialization)); - guarded.string(THIS_NODE_LOCAL_VAR_NAME); - guarded.end().end(); + CodeTree guarded = createReturnNewSpecialization(body, specialization, THIS_NODE_LOCAL_VAR_NAME, hasCopyConstructor); - body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, false, guarded.getRoot(), null)); + body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, false, guarded, null, true)); } body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); return method; } + private CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startReturn().startNew(nodeSpecializationClassName(specialization)); + if (hasCopyConstructor) { + builder.string(thisLocalVariableName); + } + builder.end().end(); + return builder.getRoot(); + } + private List createGeneratedGenericMethod(NodeData node) { TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); if (node.needsRewrites(context)) { @@ -1153,7 +1225,7 @@ } else { String methodName = generatedGenericMethodName(current); CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, methodName); - method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); + method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME)); addInternalValueParameters(method, node.getGenericSpecialization(), true); emitGeneratedGenericSpecialization(method.createBuilder(), current, next); @@ -1166,7 +1238,7 @@ return methods; } else { CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, generatedGenericMethodName(null)); - method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); + method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME)); addInternalValueParameters(method, node.getGenericSpecialization(), true); emitInvokeDoMethod(method.createBuilder(), node.getGenericSpecialization(), 0); return Arrays.asList(method); @@ -1186,7 +1258,7 @@ addInternalValueParameterNames(nextBuilder, next, next, null, true, true); nextBuilder.end().end(); - invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot()); + invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot(), true); } builder.tree(invokeMethod); @@ -1205,7 +1277,7 @@ emitEncounteredSynthetic(builder); } else { builder.startReturn(); - builder.tree(createTemplateMethodCall(builder, specialization.getNode().getGenericSpecialization(), specialization, null)); + builder.tree(createTemplateMethodCall(builder, null, specialization.getNode().getGenericSpecialization(), specialization, null)); builder.end(); // return } @@ -1272,7 +1344,7 @@ } } - if (node.needsRewrites(getContext()) && !specialization.isGeneric() && !specialization.isUninitialized()) { + if (specialization.hasRewrite(getContext())) { buildSpecializeAndExecute(clazz, specialization); } } @@ -1301,7 +1373,12 @@ int i = 0; for (VariableElement param : method.getParameters()) { CodeVariableElement var = CodeVariableElement.clone(param); - var.setName(valueName(execType.getParameters().get(i))); + ActualParameter actualParameter = execType.getParameters().get(i); + if (actualParameter.getSpecification().isSignature()) { + var.setName(valueNameEvaluated(actualParameter)); + } else { + var.setName(valueName(actualParameter)); + } method.getParameters().set(i, var); i++; } @@ -1356,7 +1433,7 @@ CodeTreeBuilder builder = new CodeTreeBuilder(parent); NodeData node = specialization.getNode(); - ExecutableTypeData castedType = node.findExecutableType(type); + ExecutableTypeData castedType = node.findExecutableType(type, 0); TypeData primaryType = castExecutable.getType(); boolean needsTry = castExecutable.hasUnexpectedValue(getContext()); @@ -1371,17 +1448,13 @@ ActualParameter targetParameter = castExecutable.findParameter(sourceParameter.getLocalName()); if (targetParameter != null) { - TypeData sourceType = sourceParameter.getTypeSystemType(); - TypeData targetType = targetParameter.getTypeSystemType(); - if (sourceType.needsCastTo(targetType)) { - executeParameters.add(targetParameter); - } + executeParameters.add(targetParameter); } } builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null, true)); - CodeTree primaryExecuteCall = createTemplateMethodCall(builder, executable, castExecutable, null); + CodeTree primaryExecuteCall = createTemplateMethodCall(builder, null, executable, castExecutable, null); if (needsTry) { if (!returnVoid) { builder.declaration(primaryType.getPrimitiveType(), "value"); @@ -1448,6 +1521,24 @@ return builder.getRoot(); } + private CodeTree createExpectType(NodeData node, TypeData castedType, CodeTree value) { + if (castedType == null) { + return value; + } else if (castedType.isVoid()) { + return value; + } else if (castedType.isGeneric()) { + return value; + } + + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + String targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType); + startCallTypeSystemMethod(getContext(), builder, node, targetMethodName); + + builder.tree(value); + builder.end().end(); + return builder.getRoot(); + } + private CodeTree createFunctionalExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); if (specialization.isUninitialized()) { @@ -1458,7 +1549,7 @@ CodeTree executeNode; if (specialization.isUninitialized()) { - builder.tree(createSpecializeCall(builder, executable, specialization)); + builder.tree(createSpecializeCall(builder, specialization)); } executeNode = createExecute(builder, executable, specialization); @@ -1467,7 +1558,7 @@ if (next != null) { returnSpecialized = createReturnSpecializeAndExecute(builder, executable, next, null); } - builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized)); + builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized, false)); return builder.getRoot(); } @@ -1475,12 +1566,12 @@ private CodeTree createDeoptimize(CodeTreeBuilder parent) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); builder.startStatement(); - builder.startStaticCall(getContext().getTruffleTypes().getTruffleIntrinsics(), "deoptimize").end(); + builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end(); builder.end(); return builder.getRoot(); } - private CodeTree createSpecializeCall(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { + private CodeTree createSpecializeCall(CodeTreeBuilder parent, SpecializationData specialization) { NodeData node = specialization.getNode(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); @@ -1492,28 +1583,35 @@ builder.startCall(factoryClassName(node), "specialize"); builder.string("this"); builder.typeLiteral(builder.findMethod().getEnclosingElement().asType()); - addInternalValueParameterNames(builder, executable, specialization, null, true, true); + addInternalValueParameterNames(builder, specialization, specialization, null, true, true); builder.end(); // call replace, call specialize } else { builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); } builder.end().end(); + emitSpecializationListeners(builder, node); return builder.getRoot(); } private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { NodeData node = specialization.getNode(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); - if (!specialization.getExceptions().isEmpty()) { + if (!specialization.getExceptions().isEmpty() || !specialization.getAssumptions().isEmpty()) { builder.startTryBlock(); } + for (String assumption : specialization.getAssumptions()) { + builder.startStatement(); + builder.string("this.").string(assumption).string(".check()"); + builder.end(); + } + CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent); if (specialization.isUninitialized()) { String genericMethodName = generatedGenericMethodName(null); returnBuilder.startCall(factoryClassName(node), genericMethodName); returnBuilder.string("this"); - addInternalValueParameterNames(returnBuilder, executable, specialization, null, true, true); + addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); returnBuilder.end(); } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { emitEncounteredSynthetic(builder); @@ -1527,10 +1625,10 @@ returnBuilder.startCall(factoryClassName(node), genericMethodName); returnBuilder.string("this"); - addInternalValueParameterNames(returnBuilder, executable, specialization, null, true, true); + addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); returnBuilder.end(); } else { - returnBuilder.tree(createTemplateMethodCall(returnBuilder, executable, specialization, null)); + returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null)); } if (!returnBuilder.isEmpty()) { @@ -1556,6 +1654,12 @@ } builder.end(); } + if (!specialization.getAssumptions().isEmpty()) { + builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex"); + builder.tree(createReturnSpecializeAndExecute(parent, executable, specialization.findNextSpecialization(), null)); + builder.end(); + } + return builder.getRoot(); } @@ -1572,34 +1676,39 @@ } TypeData targetType = targetParameter.getTypeSystemType(); - ExecutableTypeData targetExecutable = field.getNodeData().findExecutableType(targetType); + ExecutableTypeData targetExecutable = field.findExecutableType(getContext(), targetType); ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName()); - String targetVariableName = null; + String targetVariableName = valueName(targetParameter); CodeTree executionExpression = null; if (cast || sourceParameter != null) { TypeData sourceType = sourceParameter.getTypeSystemType(); if (!sourceType.needsCastTo(targetType)) { if (field.isShortCircuit() && sourceParameter != null) { - builder.tree(createShortCircuitValue(builder, sourceExecutable, specialization, field, targetParameter.getPreviousParameter(), unexpectedParameter)); + builder.tree(createShortCircuitValue(builder, specialization, field, targetParameter.getPreviousParameter(), unexpectedParameter)); } - continue; + builder.startStatement(); + builder.type(targetParameter.getType()).string(" "); + builder.string(valueName(targetParameter)).string(" = "); + builder.tree(CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter))); + builder.end(); + } else { + executionExpression = createExpectType(sourceNode, targetExecutable, CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter))); } - executionExpression = createExpectType(sourceNode, targetExecutable, CodeTreeBuilder.singleString(valueName(targetParameter))); - targetVariableName = castValueName(targetParameter); } else if (sourceParameter == null) { - targetVariableName = valueName(targetParameter); - executionExpression = createExecuteChildExpression(builder, field, targetParameter); + executionExpression = createExecuteChildExpression(builder, field, targetParameter, unexpectedParameter); } - CodeTreeVariable executionVar = new CodeTreeVariable(); - CodeTree shortCircuitTree = createShortCircuitTree(builder, executionVar, targetVariableName, sourceExecutable, specialization, targetParameter, unexpectedParameter); - CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpression, targetVariableName, specialization, sourceExecutable, targetExecutable, targetParameter, - shortCircuitTree != executionVar); + if (executionExpression != null) { + CodeTreeVariable executionVar = new CodeTreeVariable(); + CodeTree shortCircuitTree = createShortCircuitTree(builder, executionVar, targetVariableName, specialization, targetParameter, unexpectedParameter); + CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpression, targetVariableName, specialization, sourceExecutable, targetExecutable, targetParameter, + shortCircuitTree != executionVar); - executionVar.set(unexpectedTree); - builder.tree(shortCircuitTree); + executionVar.set(unexpectedTree); + builder.tree(shortCircuitTree); + } } return builder.getRoot(); } @@ -1607,7 +1716,7 @@ private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { for (TemplateMethod listener : node.getSpecializationListeners()) { builder.startStatement(); - builder.tree(createTemplateMethodCall(builder, listener, listener, null)); + builder.tree(createTemplateMethodCall(builder, null, listener, listener, null)); builder.end(); // statement } } @@ -1616,6 +1725,12 @@ ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); boolean unexpected = targetExecutable.hasUnexpectedValue(getContext()); + boolean cast = false; + if (targetExecutable.getType().needsCastTo(param.getTypeSystemType())) { + unexpected = true; + cast = true; + } + builder.startStatement(); if (!shortCircuit) { @@ -1634,7 +1749,11 @@ builder.string(targetVariableName); } builder.string(" = "); - builder.tree(body); + if (cast) { + builder.tree(createExpectType(specialization.getNode(), specialization.getReturnSignature(), body)); + } else { + builder.tree(body); + } builder.end(); if (unexpected) { @@ -1651,9 +1770,9 @@ return builder.getRoot(); } - private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter) { + private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter, ActualParameter unexpectedParameter) { TypeData type = sourceParameter.getTypeSystemType(); - ExecutableTypeData execType = targetField.getNodeData().findExecutableType(type); + ExecutableTypeData execType = targetField.findExecutableType(getContext(), type); /* * FIXME Temporary deactivated due to partial evaluation failure else if @@ -1675,16 +1794,47 @@ } builder.string("."); } + builder.startCall(execType.getMethodName()); - if (execType.getParameters().size() == 1) { - builder.string("frameValue"); + + List signatureParameters = getModel().getSignatureParameters(); + int index = 0; + for (ActualParameter parameter : execType.getParameters()) { + + if (!parameter.getSpecification().isSignature()) { + builder.string(parameter.getLocalName()); + } else { + if (index < signatureParameters.size()) { + ActualParameter specializationParam = signatureParameters.get(index); + + String localName = specializationParam.getLocalName(); + if (unexpectedParameter != null && unexpectedParameter.getLocalName().equals(specializationParam.getLocalName())) { + localName = "ex.getResult()"; + } + + TypeData sourceType = specializationParam.getTypeSystemType(); + TypeData targetType = parameter.getTypeSystemType(); + + CodeTree value = CodeTreeBuilder.singleString(localName); + + if (sourceType.needsCastTo(targetType)) { + value = createCallTypeSystemMethod(getContext(), builder, getModel().getNode(), TypeSystemCodeGenerator.asTypeMethodName(targetType), value); + } + builder.tree(value); + } else { + builder.defaultValue(parameter.getType()); + } + index++; + } } + builder.end(); + return builder.getRoot(); } - private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, ExecutableTypeData currentExecutable, SpecializationData specialization, - ActualParameter parameter, ActualParameter exceptionParam) { + private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ActualParameter parameter, + ActualParameter exceptionParam) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); NodeChildData forField = specialization.getNode().findChild(parameter.getSpecification().getName()); @@ -1698,7 +1848,7 @@ ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter); - builder.tree(createShortCircuitValue(builder, currentExecutable, specialization, forField, shortCircuitParam, exceptionParam)); + builder.tree(createShortCircuitValue(builder, specialization, forField, shortCircuitParam, exceptionParam)); builder.declaration(parameter.getType(), targetVariableName, CodeTreeBuilder.createBuilder().defaultValue(parameter.getType())); builder.startIf().string(shortCircuitParam.getLocalName()).end(); @@ -1709,8 +1859,7 @@ return builder.getRoot(); } - private CodeTree createShortCircuitValue(CodeTreeBuilder parent, ExecutableTypeData currentExecutable, SpecializationData specialization, NodeChildData forField, - ActualParameter shortCircuitParam, ActualParameter exceptionParam) { + private CodeTree createShortCircuitValue(CodeTreeBuilder parent, SpecializationData specialization, NodeChildData forField, ActualParameter shortCircuitParam, ActualParameter exceptionParam) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); int shortCircuitIndex = 0; for (NodeChildData field : specialization.getNode().getChildren()) { @@ -1724,7 +1873,7 @@ builder.startStatement().type(shortCircuitParam.getType()).string(" ").string(valueName(shortCircuitParam)).string(" = "); ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex); - builder.tree(createTemplateMethodCall(builder, currentExecutable, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null)); + builder.tree(createTemplateMethodCall(builder, null, specialization, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null)); builder.end(); // statement return builder.getRoot(); @@ -1734,8 +1883,8 @@ CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); specializeCall.startCall("specializeAndExecute"); specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class"); - addInternalValueParameterNames(specializeCall, executable, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, - true); + addInternalValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), nextSpecialization.getNode().getGenericSpecialization(), + exceptionParam != null ? exceptionParam.getLocalName() : null, true, true); specializeCall.end().end(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Thu Apr 25 16:53:29 2013 +0200 @@ -49,6 +49,7 @@ private List specializationListeners; private Map> executableTypes; private List shortCircuits; + private List assumptions; public NodeData(TypeElement type, String id) { super(type, null, null); @@ -68,6 +69,7 @@ this.shortCircuits = splitSource.shortCircuits; this.fields = splitSource.fields; this.children = splitSource.children; + this.assumptions = splitSource.assumptions; } public boolean isSplitByMethodName() { @@ -143,6 +145,14 @@ return getTemplateType().asType(); } + void setAssumptions(List assumptions) { + this.assumptions = assumptions; + } + + public List getAssumptions() { + return assumptions; + } + public boolean needsFactory() { if (specializations == null) { return false; @@ -214,8 +224,8 @@ return methods; } - public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type) { - List types = findGenericExecutableTypes(context); + public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type, int evaluatedCount) { + List types = findGenericExecutableTypes(context, evaluatedCount); for (ExecutableTypeData availableType : types) { if (Utils.typeEquals(availableType.getType().getBoxedType(), type.getBoxedType())) { return availableType; @@ -224,8 +234,8 @@ return null; } - public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) { - List types = findGenericExecutableTypes(context); + public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context, int evaluatedCount) { + List types = findGenericExecutableTypes(context, evaluatedCount); for (ExecutableTypeData type : types) { if (type.getType().isGeneric()) { return type; @@ -241,6 +251,9 @@ } public List getExecutableTypes(int evaluatedCount) { + if (executableTypes == null) { + return Collections.emptyList(); + } if (evaluatedCount == -1) { List typeData = new ArrayList<>(); for (int currentEvaluationCount : executableTypes.keySet()) { @@ -248,13 +261,17 @@ } return typeData; } else { - return executableTypes.get(evaluatedCount); + List types = executableTypes.get(evaluatedCount); + if (types == null) { + return Collections.emptyList(); + } + return types; } } - public List findGenericExecutableTypes(ProcessorContext context) { + public List findGenericExecutableTypes(ProcessorContext context, int evaluatedCount) { List types = new ArrayList<>(); - for (ExecutableTypeData type : getExecutableTypes(0)) { + for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) { if (!type.hasUnexpectedValue(context)) { types.add(type); } @@ -262,8 +279,8 @@ return types; } - public ExecutableTypeData findExecutableType(TypeData prmitiveType) { - for (ExecutableTypeData type : getExecutableTypes(0)) { + public ExecutableTypeData findExecutableType(TypeData prmitiveType, int evaluatedCount) { + for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) { if (Utils.typeEquals(type.getType().getPrimitiveType(), prmitiveType.getPrimitiveType())) { return type; } @@ -304,7 +321,7 @@ break; } } - return needsRewrites; + return needsRewrites || getSpecializations().size() > 1; } public SpecializationData getGenericSpecialization() { @@ -339,6 +356,7 @@ dumpProperty(builder, indent, "fields", getChildren()); dumpProperty(builder, indent, "executableTypes", getExecutableTypes()); dumpProperty(builder, indent, "specializations", getSpecializations()); + dumpProperty(builder, indent, "assumptions", getAssumptions()); dumpProperty(builder, indent, "messages", collectMessages()); if (getDeclaredNodes().size() > 0) { builder.append(String.format("\n%s children = [", indent)); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java Thu Apr 25 16:53:29 2013 +0200 @@ -42,7 +42,8 @@ return template; } - protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) { + @SuppressWarnings("unused") + protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, int evaluatedCount) { ParameterSpec spec = new ParameterSpec(valueName, nodeTypeMirrors(nodeData)); spec.setSignature(true); return spec; @@ -61,7 +62,7 @@ } protected ParameterSpec createReturnParameterSpec() { - return createValueParameterSpec("returnValue", getNode()); + return createValueParameterSpec("returnValue", getNode(), 0); } @Override @@ -95,7 +96,7 @@ if (getNode().getChildren() != null) { for (NodeChildData child : getNode().getChildren()) { if (child.getExecutionKind() == ExecutionKind.DEFAULT) { - ParameterSpec spec = createValueParameterSpec(child.getName(), child.getNodeData()); + ParameterSpec spec = createValueParameterSpec(child.getName(), child.getNodeData(), child.getExecuteWith().size()); if (child.getCardinality().isMany()) { spec.setCardinality(Cardinality.MANY); spec.setIndexed(true); @@ -110,7 +111,7 @@ if (shortCircuitsEnabled) { methodSpec.addRequired(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class))); } - methodSpec.addRequired(createValueParameterSpec(valueName, child.getNodeData())); + methodSpec.addRequired(createValueParameterSpec(valueName, child.getNodeData(), child.getExecuteWith().size())); } else { assert false; } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Thu Apr 25 16:53:29 2013 +0200 @@ -310,7 +310,7 @@ GenericParser parser = new GenericParser(context, node); MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, true, null); - ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context); + ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context, 0); assert anyGenericReturnType != null; ActualParameter returnType = new ActualParameter(specification.getReturnType(), anyGenericReturnType.getType(), 0, false); @@ -322,7 +322,7 @@ if (child == null) { actualType = specializationParameter.getTypeSystemType(); } else { - ExecutableTypeData paramType = child.getNodeData().findAnyGenericExecutableType(context); + ExecutableTypeData paramType = child.findAnyGenericExecutableType(context); assert paramType != null; actualType = paramType.getType(); } @@ -562,15 +562,30 @@ splitByMethodName = Utils.getAnnotationValue(Boolean.class, nodeClass, "splitByMethodName"); } + List assumptionsList = new ArrayList<>(); + + for (int i = lookupTypes.size() - 1; i >= 0; i--) { + TypeElement type = lookupTypes.get(i); + AnnotationMirror assumptions = Utils.findAnnotationMirror(context.getEnvironment(), type, NodeAssumptions.class); + if (assumptions != null) { + List assumptionStrings = Utils.getAnnotationValueList(String.class, assumptions, "value"); + for (String string : assumptionStrings) { + if (assumptionsList.contains(string)) { + assumptionsList.remove(string); + } + assumptionsList.add(string); + } + } + } + nodeData.setAssumptions(new ArrayList<>(assumptionsList)); nodeData.setNodeType(nodeType); nodeData.setSplitByMethodName(splitByMethodName); nodeData.setTypeSystem(typeSystem); nodeData.setFields(parseFields(elements)); + parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); + // parseChildren invokes cyclic parsing. + nodeData.setChildren(parseChildren(elements, lookupTypes)); nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements))); - parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); - - // parseChildren invokes cyclic parsing. - nodeData.setChildren(parseChildren(templateType, elements, lookupTypes)); return nodeData; } @@ -707,7 +722,7 @@ return fields; } - private List parseChildren(TypeElement templateType, List elements, final List typeHierarchy) { + private List parseChildren(List elements, final List typeHierarchy) { Set shortCircuits = new HashSet<>(); for (ExecutableElement method : ElementFilter.methodsIn(elements)) { AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); @@ -750,7 +765,7 @@ kind = ExecutionKind.SHORT_CIRCUIT; } - NodeChildData nodeChild = new NodeChildData(templateType, childMirror, name, childType, getter, cardinality, kind); + NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, getter, cardinality, kind); parsedChildren.add(nodeChild); @@ -763,8 +778,6 @@ nodeChild.setNode(fieldNodeData); if (fieldNodeData == null) { nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(childType)); - } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) { - nodeChild.addError("No executable generic types found for node '%s'.", Utils.getQualifiedName(type)); } } } @@ -778,6 +791,53 @@ encounteredNames.add(child.getName()); } } + + for (NodeChildData child : filteredChildren) { + List executeWithStrings = Utils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith"); + AnnotationValue executeWithValue = Utils.getAnnotationValue(child.getMessageAnnotation(), "executeWith"); + List executeWith = new ArrayList<>(); + for (String executeWithString : executeWithStrings) { + + if (child.getName().equals(executeWithString)) { + child.addError(executeWithValue, "The child node '%s' cannot be executed with itself.", executeWithString); + continue; + } + + NodeChildData found = null; + boolean before = true; + for (NodeChildData resolveChild : filteredChildren) { + if (resolveChild == child) { + before = false; + continue; + } + if (resolveChild.getName().equals(executeWithString)) { + found = resolveChild; + break; + } + } + + if (found == null) { + child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The child node was not found.", child.getName(), executeWithString); + continue; + } else if (!before) { + child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The node %s is executed after the current node.", child.getName(), executeWithString, + executeWithString); + continue; + } + executeWith.add(found); + } + child.setExecuteWith(executeWith); + if (child.getNodeData() == null) { + continue; + } + + List types = child.findGenericExecutableTypes(context); + if (types.isEmpty()) { + child.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", executeWith.size(), Utils.getSimpleName(child.getNodeType())); + continue; + } + } + return filteredChildren; } @@ -915,7 +975,7 @@ continue; } ExecutableTypeData found = null; - List executableElements = field.getNodeData().findGenericExecutableTypes(context); + List executableElements = field.findGenericExecutableTypes(context); for (ExecutableTypeData executable : executableElements) { if (executable.getType().equalsType(parameter.getTypeSystemType())) { found = executable; diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Thu Apr 25 16:53:29 2013 +0200 @@ -36,8 +36,9 @@ private final boolean uninitialized; private final List exceptions; private List guardDefinitions = Collections.emptyList(); - private List guards; + private List guards = Collections.emptyList(); private List shortCircuits; + private List assumptions = Collections.emptyList(); private boolean useSpecializationsForGeneric = true; private NodeData node; @@ -59,7 +60,6 @@ this.generic = generic; this.uninitialized = uninitialized; this.exceptions = Collections.emptyList(); - this.guards = new ArrayList<>(); } @Override @@ -81,12 +81,15 @@ if (!getGuards().isEmpty()) { return true; } + if (!getAssumptions().isEmpty()) { + return true; + } for (ActualParameter parameter : getParameters()) { - NodeChildData field = getNode().findChild(parameter.getSpecification().getName()); - if (field == null) { + NodeChildData child = getNode().findChild(parameter.getSpecification().getName()); + if (child == null) { continue; } - ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getTypeSystemType()); + ExecutableTypeData type = child.findExecutableType(context, parameter.getTypeSystemType()); if (type.hasUnexpectedValue(context)) { return true; } @@ -175,6 +178,14 @@ return useSpecializationsForGeneric; } + public List getAssumptions() { + return assumptions; + } + + void setAssumptions(List assumptions) { + this.assumptions = assumptions; + } + public SpecializationData findNextSpecialization() { List specializations = node.getSpecializations(); for (int i = 0; i < specializations.size() - 1; i++) { diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java Thu Apr 25 16:53:29 2013 +0200 @@ -53,7 +53,7 @@ return Specialization.class; } - private static SpecializationData parseSpecialization(TemplateMethod method) { + private SpecializationData parseSpecialization(TemplateMethod method) { int order = Utils.getAnnotationValue(Integer.class, method.getMarkerAnnotation(), "order"); if (order < 0 && order != Specialization.DEFAULT_ORDER) { method.addError("Invalid order attribute %d. The value must be >= 0 or the default value."); @@ -82,7 +82,15 @@ List guardDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards"); specialization.setGuardDefinitions(guardDefs); + List assumptionDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "assumptions"); + specialization.setAssumptions(assumptionDefs); + + for (String assumption : assumptionDefs) { + if (!getNode().getAssumptions().contains(assumption)) { + specialization.addError("Undeclared assumption '%s' used. Use @NodeAssumptions to declare them.", assumption); + } + } + return specialization; } - } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java Thu Apr 25 16:53:29 2013 +0200 @@ -34,11 +34,15 @@ private final List messages = new ArrayList<>(); public final void addWarning(String text, Object... params) { - getMessages().add(new Message(this, String.format(text, params), Kind.WARNING)); + getMessages().add(new Message(null, this, String.format(text, params), Kind.WARNING)); } public final void addError(String text, Object... params) { - getMessages().add(new Message(this, String.format(text, params), Kind.ERROR)); + addError(null, text, params); + } + + public final void addError(AnnotationValue value, String text, Object... params) { + getMessages().add(new Message(value, this, String.format(text, params), Kind.ERROR)); } protected List findChildContainers() { @@ -150,15 +154,21 @@ public static final class Message { private final MessageContainer originalContainer; + private final AnnotationValue annotationValue; private final String text; private final Kind kind; - public Message(MessageContainer originalContainer, String text, Kind kind) { + public Message(AnnotationValue annotationValue, MessageContainer originalContainer, String text, Kind kind) { + this.annotationValue = annotationValue; this.originalContainer = originalContainer; this.text = text; this.kind = kind; } + public AnnotationValue getAnnotationValue() { + return annotationValue; + } + public MessageContainer getOriginalContainer() { return originalContainer; } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Thu Apr 25 16:53:29 2013 +0200 @@ -206,6 +206,17 @@ return types; } + public List getSignatureParameters() { + List types = new ArrayList<>(); + for (ActualParameter parameter : getParameters()) { + if (!parameter.getSpecification().isSignature()) { + continue; + } + types.add(parameter); + } + return types; + } + @Override public int compareTo(TemplateMethod o) { if (this == o) { diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java Thu Apr 25 16:53:29 2013 +0200 @@ -79,15 +79,10 @@ String name = typeName(typeSystem); CodeTypeElement clazz = createClass(typeSystem, modifiers(PUBLIC), name, typeSystem.getTemplateType().asType(), false); - clazz.getImplements().add(getContext().getTruffleTypes().getTypeConversion()); - clazz.add(createConstructorUsingFields(modifiers(PROTECTED), clazz)); CodeVariableElement singleton = createSingleton(clazz); clazz.add(singleton); - clazz.add(createGetTopType(typeSystem)); - clazz.add(createConvertTo(typeSystem, singleton)); - for (TypeData type : typeSystem.getTypes()) { if (!type.isGeneric()) { CodeExecutableElement isType = createIsTypeMethod(type); @@ -125,58 +120,6 @@ return new ArrayList<>(sourceTypes); } - private CodeExecutableElement createConvertTo(TypeSystemData typeSystem, CodeVariableElement singleton) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(Object.class), "convertTo"); - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "targetType")); - method.addParameter(new CodeVariableElement(getContext().getType(Object.class), "value")); - - CodeTreeBuilder builder = method.createBuilder(); - - boolean first = true; - for (TypeData type : typeSystem.getTypes()) { - if (first) { - builder.startIf(); - first = false; - } else { - builder.startElseIf(); - } - builder.string("targetType").string(" == ").typeLiteral(type.getBoxedType()); - builder.end(); // if - builder.startBlock(); - - builder.startReturn(); - - if (typeEquals(type.getBoxedType(), getContext().getType(Object.class))) { - builder.string("value"); - } else { - builder.string(singleton.getName()).string(".").startCall(asTypeMethodName(type)).string("value").end(); - } - - builder.end(); // return - - builder.end(); // block - } - - builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); - - return method; - } - - private CodeExecutableElement createGetTopType(TypeSystemData typeSystem) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(Class.class), "getTopType"); - - CodeTreeBuilder builder = method.createBuilder(); - builder.startReturn(); - if (!typeSystem.getTypes().isEmpty()) { - builder.typeLiteral(typeSystem.getTypes().get(0).getBoxedType()); - } else { - builder.null_(); - } - builder.end(); // return - - return method; - } - private static String typeName(TypeSystemData typeSystem) { String name = getSimpleName(typeSystem.getTemplateType()); return name + "Gen"; diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AbstractTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AbstractTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AbstractTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -62,4 +62,5 @@ System.setErr(origErr); Assert.assertEquals(repeat(concat(expectedOutput), REPEATS), new String(out.toByteArray())); } + } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AddTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AddTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/AddTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -28,25 +28,25 @@ public class AddTest extends AbstractTest { private static String[] INPUT = new String[] { -"function main { ", -" print 3 + 4; ", -" print 3 + \"4\"; ", -" print \"3\" + 4; ", -" print \"3\" + \"4\"; ", -" print 3 + 4000000000000; ", -" print 3000000000000 + 4; ", -" print 3000000000000 + 4000000000000; ", -"} ", + "function main { ", + " print 3 + 4; ", + " print 3 + \"4\"; ", + " print \"3\" + 4; ", + " print \"3\" + \"4\"; ", + " print 3 + 4000000000000; ", + " print 3000000000000 + 4; ", + " print 3000000000000 + 4000000000000; ", + "} ", }; private static String[] OUTPUT = new String[] { -"7", -"34", -"34", -"34", -"4000000000003", -"3000000000004", -"7000000000000", + "7", + "34", + "34", + "34", + "4000000000003", + "3000000000004", + "7000000000000", }; @Test diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/ComparisonTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/ComparisonTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/ComparisonTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -28,25 +28,25 @@ public class ComparisonTest extends AbstractTest { private static String[] INPUT = new String[] { -"function main { ", -" print 4 < 20; ", -" print 4 < \"20\"; ", -" print \"4\" < 20; ", -" print \"4\" < \"20\"; ", -" print 4 < 20000000000000; ", -" print 4000000000000 < 20; ", -" print 4000000000000 < 20000000000000; ", -"} ", + "function main { ", + " print 4 < 20; ", + " print 4 < \"20\"; ", + " print \"4\" < 20; ", + " print \"4\" < \"20\"; ", + " print 4 < 20000000000000; ", + " print 4000000000000 < 20; ", + " print 4000000000000 < 20000000000000; ", + "} ", }; private static String[] OUTPUT = new String[] { -"true", -"false", -"false", -"false", -"true", -"false", -"true", + "true", + "false", + "false", + "false", + "true", + "false", + "true", }; @Test diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/DivTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/DivTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/DivTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -28,19 +28,19 @@ public class DivTest extends AbstractTest { private static String[] INPUT = new String[] { -"function main { ", -" print 4 / 2; ", -" print 4 / 4000000000000; ", -" print 3000000000000 / 3; ", -" print 3000000000000 / 3000000000000; ", -"} ", + "function main { ", + " print 4 / 2; ", + " print 4 / 4000000000000; ", + " print 3000000000000 / 3; ", + " print 3000000000000 / 3000000000000; ", + "} ", }; private static String[] OUTPUT = new String[] { -"2", -"0", -"1000000000000", -"1", + "2", + "0", + "1000000000000", + "1", }; @Test diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/LoopPrintTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/LoopPrintTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/LoopPrintTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -28,17 +28,17 @@ public class LoopPrintTest extends AbstractTest { private static String[] INPUT = new String[] { -"function main { ", -" i = 0; ", -" while (i < 1000) { ", -" i = i + 1; ", -" } ", -" print i; ", -"} ", + "function main { ", + " i = 0; ", + " while (i < 1000) { ", + " i = i + 1; ", + " } ", + " print i; ", + "} ", }; private static String[] OUTPUT = new String[] { -"1000", + "1000", }; @Test diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/LoopTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/LoopTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/LoopTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -28,17 +28,17 @@ public class LoopTest extends AbstractTest { private static String[] INPUT = new String[] { -"function main { ", -" i = 0; ", -" while (i < 1000) { ", -" i = i + 1; ", -" } ", -" return i; ", -"} ", + "function main { ", + " i = 0; ", + " while (i < 1000) { ", + " i = i + 1; ", + " } ", + " return i; ", + "} ", }; private static String[] OUTPUT = new String[] { -"1000", + "1000", }; @Test diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/MulTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/MulTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/MulTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -28,19 +28,19 @@ public class MulTest extends AbstractTest { private static String[] INPUT = new String[] { -"function main { ", -" print 3 * 4; ", -" print 3 * 4000000000000; ", -" print 3000000000000 * 4; ", -" print 3000000000000 * 4000000000000; ", -"} ", + "function main { ", + " print 3 * 4; ", + " print 3 * 4000000000000; ", + " print 3000000000000 * 4; ", + " print 3000000000000 * 4000000000000; ", + "} ", }; private static String[] OUTPUT = new String[] { -"12", -"12000000000000", -"12000000000000", -"12000000000000000000000000", + "12", + "12000000000000", + "12000000000000", + "12000000000000000000000000", }; @Test diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SubTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SubTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SubTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -28,19 +28,19 @@ public class SubTest extends AbstractTest { private static String[] INPUT = new String[] { -"function main { ", -" print 3 - 4; ", -" print 3 - 4000000000000; ", -" print 3000000000000 - 4; ", -" print 3000000000000 - 4000000000000; ", -"} ", + "function main { ", + " print 3 - 4; ", + " print 3 - 4000000000000; ", + " print 3000000000000 - 4; ", + " print 3000000000000 - 4000000000000; ", + "} ", }; private static String[] OUTPUT = new String[] { -"-1", -"-3999999999997", -"2999999999996", -"-1000000000000", + "-1", + "-3999999999997", + "2999999999996", + "-1000000000000", }; @Test diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SumTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SumTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SumTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -28,19 +28,19 @@ public class SumTest extends AbstractTest { private static String[] INPUT = new String[] { -"function main { ", -" i = 0; ", -" sum = 0; ", -" while (i < 100000) { ", -" sum = sum + 1000000; ", -" i = i + 1; ", -" } ", -" return sum; ", -"} ", + "function main { ", + " i = 0; ", + " sum = 0; ", + " while (i < 100000) { ", + " sum = sum + 1000000; ", + " i = i + 1; ", + " } ", + " return sum; ", + "} ", }; private static String[] OUTPUT = new String[] { -"100000000000", + "100000000000", }; @Test diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/TernaryTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/TernaryTest.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/TernaryTest.java Thu Apr 25 16:53:29 2013 +0200 @@ -28,13 +28,13 @@ public class TernaryTest extends AbstractTest { private static String[] INPUT = new String[] { -"function main { " + -" print #(1 < 2) ? 1 : 2;" + -" print #(2 < 1) ? 100000000000000 : 1; ", -" print #(1 < 2) ? 100000000000000 : 1; ", -" print #(2 < 1) ? \"wrong\" : \"true\";", -" print #(2 < 1) ? \"wrong\" : 1;", -"} ", + "function main { " + + " print #(1 < 2) ? 1 : 2;" + + " print #(2 < 1) ? 100000000000000 : 1; ", + " print #(1 < 2) ? 100000000000000 : 1; ", + " print #(2 < 1) ? \"wrong\" : \"true\";", + " print #(2 < 1) ? \"wrong\" : 1;", + "} ", }; private static String[] OUTPUT = new String[] { diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java Thu Apr 25 16:53:29 2013 +0200 @@ -51,7 +51,7 @@ } public void startFunction() { - frameDescriptor = new FrameDescriptor(SLTypesGen.SLTYPES); + frameDescriptor = new FrameDescriptor(); } public void createFunction(StatementNode body, String name) { @@ -59,7 +59,7 @@ } public TypedNode createLocal(String name) { - return ReadLocalNodeFactory.create(frameDescriptor.findOrAddFrameSlot(name)); + return ReadLocalNodeFactory.create(frameDescriptor.findOrAddFrameSlot(name, int.class)); } public TypedNode createStringLiteral(String value) { @@ -67,7 +67,7 @@ } public StatementNode createAssignment(String name, TypedNode right) { - return WriteLocalNodeFactory.create(frameDescriptor.findOrAddFrameSlot(name), right); + return WriteLocalNodeFactory.create(frameDescriptor.findOrAddFrameSlot(name, int.class), right); } public StatementNode createPrint(List expressions) { @@ -123,7 +123,7 @@ } public StatementNode createReturn(TypedNode value) { - FrameSlot slot = frameDescriptor.findOrAddFrameSlot(""); + FrameSlot slot = frameDescriptor.findOrAddFrameSlot("", int.class); if (returnValue == null) { returnValue = ReadLocalNodeFactory.create(slot); } diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -24,8 +24,8 @@ import java.math.*; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.codegen.*; -import com.oracle.truffle.api.intrinsics.*; public abstract class ArithmeticNode extends BinaryNode { diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FrameSlotNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FrameSlotNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FrameSlotNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -24,20 +24,12 @@ import com.oracle.truffle.api.frame.*; -public abstract class FrameSlotNode extends TypedNode implements FrameSlotTypeListener { +public abstract class FrameSlotNode extends TypedNode { protected final FrameSlot slot; public FrameSlotNode(FrameSlot slot) { this.slot = slot; - slot.registerOneShotTypeListener(this); - } - - @Override - public void typeChanged(FrameSlot changedSlot, Class oldType) { - if (getParent() != null) { - replace(specialize(changedSlot.getType())); - } } protected abstract FrameSlotNode specialize(Class clazz); diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadLocalNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadLocalNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ReadLocalNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.truffle.sl.nodes; -import java.math.*; - import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.api.frame.*; @@ -37,29 +35,23 @@ this(specialized.slot); } - @Specialization - public int doInteger(VirtualFrame frame) { + @Specialization(rewriteOn = {FrameSlotTypeException.class}) + public int doInteger(VirtualFrame frame) throws FrameSlotTypeException { return frame.getInt(slot); } - @Specialization - public BigInteger doBigInteger(VirtualFrame frame) { - return (BigInteger) frame.getObject(slot); - } - - @Specialization - public boolean doBoolean(VirtualFrame frame) { + @Specialization(rewriteOn = {FrameSlotTypeException.class}) + public boolean doBoolean(VirtualFrame frame) throws FrameSlotTypeException { return frame.getBoolean(slot); } - @Specialization - public String doString(VirtualFrame frame) { - return (String) frame.getObject(slot); - } - - @Generic - public Object doGeneric(VirtualFrame frame) { - return frame.getObject(slot); + @Generic(useSpecializations = false) + public Object doObject(VirtualFrame frame) { + try { + return frame.getObject(slot); + } catch (FrameSlotTypeException e) { + throw new RuntimeException("uninitialized variable " + slot.getIdentifier()); + } } @Override diff -r 261a43921c5e -r 17b598df8da9 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java Mon Apr 22 18:30:33 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java Thu Apr 25 16:53:29 2013 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.truffle.sl.nodes; -import java.math.*; - import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.api.frame.*; @@ -38,42 +36,28 @@ this(node.slot); } - @Specialization - public int write(VirtualFrame frame, int right) { + @Specialization(rewriteOn = FrameSlotTypeException.class) + public int write(VirtualFrame frame, int right) throws FrameSlotTypeException { frame.setInt(slot, right); return right; } - @Specialization - public BigInteger write(VirtualFrame frame, BigInteger right) { - frame.setObject(slot, right); - return right; - } - - @Specialization - public boolean write(VirtualFrame frame, boolean right) { + @Specialization(rewriteOn = FrameSlotTypeException.class) + public boolean write(VirtualFrame frame, boolean right) throws FrameSlotTypeException { frame.setBoolean(slot, right); return right; } - @Specialization - public String write(VirtualFrame frame, String right) { - frame.setObject(slot, right); - return right; - } - @Generic(useSpecializations = false) public Object writeGeneric(VirtualFrame frame, Object right) { - frame.setObject(slot, right); + try { + frame.setObject(slot, right); + } catch (FrameSlotTypeException e) { + FrameUtil.setObjectSafe(frame, slot, right); + } return right; } - @SpecializationListener - protected void onSpecialize(VirtualFrame frame, Object value) { - slot.setType(value.getClass()); - frame.updateToLatestVersion(); - } - @Override protected FrameSlotNode specialize(Class clazz) { return WriteLocalNodeFactory.createSpecialized(this, clazz); diff -r 261a43921c5e -r 17b598df8da9 make/build-graal.xml diff -r 261a43921c5e -r 17b598df8da9 mx/commands.py --- a/mx/commands.py Mon Apr 22 18:30:33 2013 +0200 +++ b/mx/commands.py Thu Apr 25 16:53:29 2013 +0200 @@ -812,6 +812,7 @@ testfile = os.environ.get('MX_TESTFILE', None) if testfile is None: (_, testfile) = tempfile.mkstemp(".testclasses", "graal") + os.close(_) def harness(projectscp, vmArgs): if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource): diff -r 261a43921c5e -r 17b598df8da9 mxtool/mx.py --- a/mxtool/mx.py Mon Apr 22 18:30:33 2013 +0200 +++ b/mxtool/mx.py Thu Apr 25 16:53:29 2013 +0200 @@ -980,11 +980,14 @@ for arg in args: assert isinstance(arg, types.StringTypes), 'argument is not a string: ' + str(arg) + if env is None: + env = os.environ + if _opts.verbose: if _opts.very_verbose: log('Environment variables:') - for key in sorted(os.environ.keys()): - log(' ' + key + '=' + os.environ[key]) + for key in sorted(env.keys()): + log(' ' + key + '=' + env[key]) log(' '.join(args)) if timeout is None and _opts.ptimeout != 0: diff -r 261a43921c5e -r 17b598df8da9 src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Mon Apr 22 18:30:33 2013 +0200 +++ b/src/os/windows/vm/os_windows.cpp Thu Apr 25 16:53:29 2013 +0200 @@ -2179,7 +2179,7 @@ ctx->Rax = (DWORD64)min_jlong; // result } else { ctx->Rip = (DWORD64)pc + 2; // idiv reg, reg is 2 bytes - ctx->Rax = (DWORD64)min_jint; // result + ctx->Rax = (DWORD64)min_jlong; // result } ctx->Rdx = (DWORD64)0; // remainder // Continue the execution