# HG changeset patch # User Stefan Anzinger # Date 1410298296 25200 # Node ID 4faf9bdb9973cda0a93f38ed823b852c20228f0e # Parent 82b5a7250a0d71ea31615415e68041642e437fd6# Parent 2476180699f6e77ccbade19e96a98f2604ef5987 Merge diff -r 82b5a7250a0d -r 4faf9bdb9973 CHANGELOG.md --- a/CHANGELOG.md Tue Sep 09 12:22:48 2014 -0700 +++ b/CHANGELOG.md Tue Sep 09 14:31:36 2014 -0700 @@ -6,6 +6,9 @@ ### Truffle * Added TruffleRuntime#getCallTargets() to get all call targets that were created and are still referenced. +* Added `NeverValidAssumption` to complement `AlwaysValidAssumption`. +* Fixed a bug in `AssumedValue` that may not invalidate correctly. +* New option, TruffleCompilationExceptionsAreThrown, that will throw a OptimizationFailedException for compiler errors. ## Version 0.4 19-Aug-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/graal-0.4) diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/MoreThanEightArgsOOBTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/MoreThanEightArgsOOBTest.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.hsail.test.lambda; + +import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester; + +import org.junit.*; + +public class MoreThanEightArgsOOBTest extends GraalKernelTester { + + int[] makeIntArray(int size) { + int[] out = new int[size]; + + for (int i = 0; i < size; i++) { + out[i] = 1; + } + return out; + } + + final int rows = 4096; + final int cols = 4096; + final int loops = 1; + + @Result int[] result; + + void innerTest(int[] res, int[] a, int[] b, int[] c, int[] d, int base, int stride) { + final int resCols = a.length; + final int resRows = res.length; + final int limit = resCols - stride; + + dispatchLambdaKernel(resRows, (row) -> { + res[row] = 0; + if (a != null) { + for (int col = base; col < limit; col += 4) { + int p0 = 0; + int p1 = 0; + int p2 = 0; + int p3 = 0; + p0 = a[col] + b[col] + c[col] + d[col] + stride; + p1 = a[col + 1] + b[col + 1] + c[col + 1] + d[col + 1]; + p2 = a[col + 2] + b[col + 2] + c[col + 2] + d[col + 2]; + p3 = a[col + 3] + b[col + 3] + c[col + 3] + d[col + 5000]; + res[row] += p0 + p1 + p2 + p3; + } + } + }); + } + + @Override + public void runTest() { + int[] a; + int[] b; + int[] c; + int[] d; + + result = makeIntArray(rows); + a = makeIntArray(cols); + b = makeIntArray(cols); + c = makeIntArray(cols); + d = makeIntArray(cols); + for (int i = 0; i < loops; i++) { + innerTest(result, a, b, c, d, 0, 4); + } + } + + @Test(expected = ArrayIndexOutOfBoundsException.class) + public void test() { + testGeneratedHsail(); + } + + @Test(expected = ArrayIndexOutOfBoundsException.class) + public void testUsingLambdaMethod() { + testGeneratedHsailUsingLambdaMethod(); + } +} \ No newline at end of file diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Tue Sep 09 14:31:36 2014 -0700 @@ -269,7 +269,7 @@ } result.append("\n"); for (Node node : schedule.getBlockToNodesMap().get(block)) { - if (node.isAlive() && node.recordsUsages()) { + if (node.isAlive()) { if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode)) { int id; if (canonicalId.get(node) != null) { diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodeRefIteratorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodeRefIteratorTest.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,219 @@ +/* + * 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.graal.compiler.test; + +import org.junit.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; + +public class NodeRefIteratorTest extends GraalCompilerTest { + + @NodeInfo + static class TestNode extends Node { + @Successor Node s1; + @Successor Node s2; + @Successor NodeSuccessorList stail; + + @Input NodeInputList itail; + @Input ValueNode i1; + @Input ValueNode i2; + + public static TestNode create() { + return USE_GENERATED_NODES ? new NodeRefIteratorTest_TestNodeGen() : new TestNode(); + } + } + + @Test + public void testInputs() { + TestNode n = TestNode.create(); + + ConstantNode i1 = ConstantNode.forInt(1); + ConstantNode i2 = ConstantNode.forDouble(1.0d); + ConstantNode i3 = ConstantNode.forInt(4); + ConstantNode i4 = ConstantNode.forInt(14); + n.itail = new NodeInputList<>(n, new ValueNode[]{i3, i4}); + n.i1 = i1; + n.i2 = i2; + + NodeClassIterable inputs = n.inputs(); + + NodePosIterator iterator = inputs.iterator(); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i1); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i2); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i3); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i4); + Assert.assertFalse(iterator.hasNext()); + Assert.assertFalse(iterator.hasNext()); + + iterator = inputs.iterator(); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.nextPosition().toString(), "input 0/-1"); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.nextPosition().toString(), "input 1/-1"); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.nextPosition().toString(), "input 2/0"); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.nextPosition().toString(), "input 2/1"); + Assert.assertFalse(iterator.hasNext()); + Assert.assertFalse(iterator.hasNext()); + + iterator = inputs.iterator(); + n.i1 = i4; + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i4); + n.i2 = i1; + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i1); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i3); + n.itail.initialize(1, i4); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i4); + Assert.assertFalse(iterator.hasNext()); + + iterator = inputs.iterator(); + n.i1 = null; + n.i2 = i2; + n.itail.initialize(0, null); + n.itail.initialize(1, i4); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i2); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i4); + Assert.assertFalse(iterator.hasNext()); + + iterator = inputs.withNullIterator(); + n.i1 = null; + n.i2 = null; + n.itail.initialize(0, i3); + n.itail.initialize(1, null); + Assert.assertTrue(iterator.hasNext()); + Assert.assertNull(iterator.next()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertNull(iterator.next()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), i3); + Assert.assertTrue(iterator.hasNext()); + Assert.assertNull(iterator.next()); + Assert.assertFalse(iterator.hasNext()); + } + + @Test + public void testSuccessors() { + TestNode n = TestNode.create(); + EndNode s1 = EndNode.create(); + EndNode s2 = EndNode.create(); + EndNode s3 = EndNode.create(); + EndNode s4 = EndNode.create(); + n.s1 = s1; + n.s2 = s2; + n.stail = new NodeSuccessorList<>(n, new Node[]{s3, s4}); + + NodeClassIterable successors = n.successors(); + NodePosIterator iterator = successors.iterator(); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s1); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s2); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s3); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s4); + Assert.assertFalse(iterator.hasNext()); + Assert.assertFalse(iterator.hasNext()); + + iterator = successors.iterator(); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.nextPosition().toString(), "successor 0/-1"); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.nextPosition().toString(), "successor 1/-1"); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.nextPosition().toString(), "successor 2/0"); + Assert.assertTrue(iterator.hasNext()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.nextPosition().toString(), "successor 2/1"); + Assert.assertFalse(iterator.hasNext()); + Assert.assertFalse(iterator.hasNext()); + + iterator = successors.iterator(); + n.s1 = s4; + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s4); + n.s2 = s1; + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s1); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s3); + n.stail.initialize(1, s4); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s4); + Assert.assertFalse(iterator.hasNext()); + + iterator = successors.iterator(); + n.s1 = null; + n.s2 = s2; + n.stail.initialize(0, null); + n.stail.initialize(1, s4); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s2); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s4); + Assert.assertFalse(iterator.hasNext()); + + iterator = successors.withNullIterator(); + n.s1 = null; + n.s2 = null; + n.stail.initialize(0, s3); + n.stail.initialize(1, null); + Assert.assertTrue(iterator.hasNext()); + Assert.assertNull(iterator.next()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertNull(iterator.next()); + Assert.assertTrue(iterator.hasNext()); + Assert.assertEquals(iterator.next(), s3); + Assert.assertTrue(iterator.hasNext()); + Assert.assertNull(iterator.next()); + Assert.assertFalse(iterator.hasNext()); + } +} diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java Tue Sep 09 14:31:36 2014 -0700 @@ -242,7 +242,7 @@ } private static void outputNode(Node node) { - TTY.print(" " + node + " (usage count: " + (node.recordsUsages() ? node.usages().count() : "?") + ") (inputs:"); + TTY.print(" " + node + " (usage count: " + node.usages().count() + ") (inputs:"); for (Node input : node.inputs()) { TTY.print(" " + input.toString(Verbosity.Id)); } diff -r 82b5a7250a0d -r 4faf9bdb9973 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 Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Tue Sep 09 14:31:36 2014 -0700 @@ -25,6 +25,7 @@ import static com.oracle.graal.compiler.GraalCompiler.Options.*; import static com.oracle.graal.compiler.MethodFilter.*; import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; import java.util.*; @@ -167,7 +168,7 @@ HighTierContext highTierContext = new HighTierContext(providers, assumptions, cache, graphBuilderSuite, optimisticOpts); if (graph.start().next() == null) { graphBuilderSuite.apply(graph, highTierContext); - new DeadCodeEliminationPhase().apply(graph); + new DeadCodeEliminationPhase(OPTIONAL).apply(graph); } else { Debug.dump(graph, "initial state"); } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Tue Sep 09 14:31:36 2014 -0700 @@ -894,15 +894,26 @@ BitSet startBlockLiveIn = blockData.get(ir.getControlFlowGraph().getStartBlock()).liveIn; try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) { for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { - Value operand = intervalFor(operandNum).operand; - Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getValueForOperandFromDebugContext(operand)); + Interval interval = intervalFor(operandNum); + if (interval != null) { + Value operand = interval.operand; + Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getValueForOperandFromDebugContext(operand)); + } else { + Debug.log("var %d; missing operand", operandNum); + } } } // print some additional information to simplify debugging for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { - Value operand = intervalFor(operandNum).operand; - try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, getValueForOperandFromDebugContext(operand))) { + Interval interval = intervalFor(operandNum); + Value operand = null; + ValueNode valueForOperandFromDebugContext = null; + if (interval != null) { + operand = interval.operand; + valueForOperandFromDebugContext = getValueForOperandFromDebugContext(operand); + } + try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, valueForOperandFromDebugContext)) { Deque> definedIn = new ArrayDeque<>(); HashSet> usedIn = new HashSet<>(); diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/OptimizingLinearScanWalker.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/OptimizingLinearScanWalker.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/OptimizingLinearScanWalker.java Tue Sep 09 14:31:36 2014 -0700 @@ -74,34 +74,39 @@ void walk() { try (Scope s = Debug.scope("OptimizingLinearScanWalker")) { for (AbstractBlock block : allocator.sortedBlocks) { - if (block.getPredecessorCount() == 1) { - int nextBlock = allocator.getFirstLirInstructionId(block); - try (Scope s1 = Debug.scope("LSRAOptimization")) { - Debug.log("next block: %s (%d)", block, nextBlock); - } - try (Indent indent0 = Debug.indent()) { - walkTo(nextBlock); + optimizeBlock(block); + } + } + super.walk(); + } + + private void optimizeBlock(AbstractBlock block) { + if (block.getPredecessorCount() == 1) { + int nextBlock = allocator.getFirstLirInstructionId(block); + try (Scope s1 = Debug.scope("LSRAOptimization")) { + Debug.log("next block: %s (%d)", block, nextBlock); + } + try (Indent indent0 = Debug.indent()) { + walkTo(nextBlock); - try (Scope s1 = Debug.scope("LSRAOptimization")) { - boolean changed = true; - // we need to do this because the active lists might change - loop: while (changed) { - changed = false; - try (Indent indent1 = Debug.logAndIndent("Active intervals: (block %s [%d])", block, nextBlock)) { - for (Interval active = activeLists.get(RegisterBinding.Any); active != Interval.EndMarker; active = active.next) { - Debug.log("active (any): %s", active); - if (optimize(nextBlock, block, active, RegisterBinding.Any)) { - changed = true; - break loop; - } - } - for (Interval active = activeLists.get(RegisterBinding.Stack); active != Interval.EndMarker; active = active.next) { - Debug.log("active (stack): %s", active); - if (optimize(nextBlock, block, active, RegisterBinding.Stack)) { - changed = true; - break loop; - } - } + try (Scope s1 = Debug.scope("LSRAOptimization")) { + boolean changed = true; + // we need to do this because the active lists might change + loop: while (changed) { + changed = false; + try (Indent indent1 = Debug.logAndIndent("Active intervals: (block %s [%d])", block, nextBlock)) { + for (Interval active = activeLists.get(RegisterBinding.Any); active != Interval.EndMarker; active = active.next) { + Debug.log("active (any): %s", active); + if (optimize(nextBlock, block, active, RegisterBinding.Any)) { + changed = true; + break loop; + } + } + for (Interval active = activeLists.get(RegisterBinding.Stack); active != Interval.EndMarker; active = active.next) { + Debug.log("active (stack): %s", active); + if (optimize(nextBlock, block, active, RegisterBinding.Stack)) { + changed = true; + break loop; } } } @@ -109,7 +114,6 @@ } } } - super.walk(); } private boolean optimize(int currentPos, AbstractBlock currentBlock, Interval currentInterval, RegisterBinding binding) { diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Tue Sep 09 14:31:36 2014 -0700 @@ -34,6 +34,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.virtual.nodes.*; @@ -203,20 +204,24 @@ STATE_VIRTUAL_OBJECTS.increment(); return vobject; } - } else if (value instanceof ConstantNode) { - STATE_CONSTANTS.increment(); - return ((ConstantNode) value).getValue(); + } else { + // Remove proxies from constants so the constant can be directly embedded. + ValueNode unproxied = GraphUtil.unproxify(value); + if (unproxied instanceof ConstantNode) { + STATE_CONSTANTS.increment(); + return ((ConstantNode) unproxied).getValue(); - } else if (value != null) { - STATE_VARIABLES.increment(); - Value operand = nodeOperands.get(value); - assert operand != null && (operand instanceof Variable || operand instanceof Constant) : operand + " for " + value; - return operand; + } else if (value != null) { + STATE_VARIABLES.increment(); + Value operand = nodeOperands.get(value); + assert operand != null && (operand instanceof Variable || operand instanceof Constant) : operand + " for " + value; + return operand; - } else { - // return a dummy value because real value not needed - STATE_ILLEGALS.increment(); - return Value.ILLEGAL; + } else { + // return a dummy value because real value not needed + STATE_ILLEGALS.increment(); + return Value.ILLEGAL; + } } } catch (GraalInternalError e) { throw e.addContext("toValue: ", value); diff -r 82b5a7250a0d -r 4faf9bdb9973 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 Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Tue Sep 09 14:31:36 2014 -0700 @@ -24,12 +24,14 @@ import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.compiler.phases.HighTier.Options.*; +import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; + import com.oracle.graal.loop.phases.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.options.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.common.cfs.IterativeFlowSensitiveReductionPhase; +import com.oracle.graal.phases.common.cfs.*; import com.oracle.graal.phases.common.inlining.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.phases.ea.*; @@ -56,7 +58,7 @@ appendPhase(new IterativeInliningPhase(canonicalizer)); } else { appendPhase(new InliningPhase(canonicalizer)); - appendPhase(new DeadCodeEliminationPhase()); + appendPhase(new DeadCodeEliminationPhase(OPTIONAL)); boolean reduceOrEliminate = FlowSensitiveReduction.getValue() || ConditionalElimination.getValue(); if (reduceOrEliminate && OptCanonicalizer.getValue()) { diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java Tue Sep 09 14:31:36 2014 -0700 @@ -23,6 +23,7 @@ package com.oracle.graal.compiler.phases; import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.options.*; @@ -63,6 +64,6 @@ appendPhase(new UseTrappingNullChecksPhase()); - appendPhase(new DeadCodeEliminationPhase()); + appendPhase(new DeadCodeEliminationPhase(REQUIRED)); } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Tue Sep 09 14:31:36 2014 -0700 @@ -30,6 +30,7 @@ import java.util.*; import java.util.concurrent.*; +import com.oracle.graal.debug.DelegatingDebugConfig.Level; import com.oracle.graal.debug.internal.*; /** @@ -318,7 +319,7 @@ for (Object obj : context()) { context.add(obj); } - return Debug.sandbox("forceLog", new DelegatingDebugConfig().enable(LOG).enable(LOG_METHOD), context.toArray()); + return Debug.sandbox("forceLog", new DelegatingDebugConfig().override(Level.LOG, Integer.MAX_VALUE).enable(LOG_METHOD), context.toArray()); } /** diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DelegatingDebugConfig.java Tue Sep 09 14:31:36 2014 -0700 @@ -39,18 +39,10 @@ */ public enum Feature { /** - * @see Debug#isLogEnabled() - */ - LOG, - /** * @see Debug#isLogEnabledForMethod() */ LOG_METHOD, /** - * @see Debug#isDumpEnabled() - */ - DUMP, - /** * @see Debug#isDumpEnabledForMethod() */ DUMP_METHOD, diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java --- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java Tue Sep 09 14:31:36 2014 -0700 @@ -26,6 +26,7 @@ import org.junit.*; +import com.oracle.graal.api.runtime.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; @@ -47,6 +48,9 @@ @Before public void before() { + // Need to initialize HotSpotGraalRuntime before any Node class is initialized. + Graal.getRuntime(); + graph = new Graph(); for (int i = 0; i < nodes.length; i++) { nodes[i] = graph.add(TestNode.create()); @@ -97,24 +101,45 @@ } } - @Test(expected = AssertionError.class) + @SuppressWarnings("all") + private static boolean assertionsEnabled() { + boolean assertionsEnabled = false; + assert assertionsEnabled = true; + return assertionsEnabled; + } + + @Test public void testNewGet() { /* * Failing here is not required, but if this behavior changes, usages of get need to be * checked for compatibility. */ TestNode newNode = graph.add(TestNode.create()); - map.get(newNode); + try { + map.get(newNode); + fail("expected " + (assertionsEnabled() ? AssertionError.class.getSimpleName() : ArrayIndexOutOfBoundsException.class.getSimpleName())); + } catch (AssertionError ae) { + // thrown when assertions are enabled + } catch (ArrayIndexOutOfBoundsException e) { + // thrown when assertions are disabled + } } - @Test(expected = AssertionError.class) + @Test public void testNewSet() { /* * Failing here is not required, but if this behavior changes, usages of set need to be * checked for compatibility. */ TestNode newNode = graph.add(TestNode.create()); - map.set(newNode, 1); + try { + map.set(newNode, 1); + fail("expected " + (assertionsEnabled() ? AssertionError.class.getSimpleName() : ArrayIndexOutOfBoundsException.class.getSimpleName())); + } catch (AssertionError ae) { + // thrown when assertions are enabled + } catch (ArrayIndexOutOfBoundsException e) { + // thrown when assertions are disabled + } } @Test diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Tue Sep 09 14:31:36 2014 -0700 @@ -479,7 +479,7 @@ int minCount = Integer.MAX_VALUE; Node minCountNode = null; for (Node input : node.inputs()) { - if (input != null && input.recordsUsages()) { + if (input != null) { int estimate = input.getUsageCountUpperBound(); if (estimate == 0) { return null; diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Tue Sep 09 14:31:36 2014 -0700 @@ -189,6 +189,8 @@ return graph; } + private static final boolean USE_GENERATED_NODE_ITERATORS = Boolean.getBoolean("graal.useGeneratedNodeIterators"); + /** * Returns an {@link NodeClassIterable iterable} which can be used to traverse all non-null * input edges of this node. @@ -197,6 +199,9 @@ */ public NodeClassIterable inputs() { if (USE_GENERATED_NODES) { + if (!USE_GENERATED_NODE_ITERATORS) { + return new NodeRefIterable(this, true); + } return inputsV2(); } return getNodeClass().getInputIterable(this); @@ -210,13 +215,18 @@ */ public NodeClassIterable successors() { if (USE_GENERATED_NODES) { + if (!USE_GENERATED_NODE_ITERATORS) { + return new NodeRefIterable(this, false); + } return successorsV2(); } return getNodeClass().getSuccessorIterable(this); } + /** + * Gets the maximum number of usages this node has had at any point in time. + */ int getUsageCountUpperBound() { - assert recordsUsages(); if (usage0 == null) { return 0; } @@ -230,20 +240,10 @@ * Gets the list of nodes that use this node (i.e., as an input). */ public final NodeIterable usages() { - assert recordsUsages() : this; return new NodeUsageIterable(this); } /** - * Determines if this node records its usages (i.e. the nodes for which it is an input). All - * methods in {@link Node} that pertain to querying or updating usage information must not be - * called for a {@link Node} instance that returns false for this method. - */ - public boolean recordsUsages() { - return true; - } - - /** * Finds the index of the last non-null entry in a node array. The search assumes that all * non-null entries precede the first null entry in the array. * @@ -283,7 +283,6 @@ * @param node the node to add */ private void addUsage(Node node) { - assert recordsUsages(); incUsageModCount(); if (usage0 == null) { usage0 = node; @@ -390,7 +389,6 @@ * @return whether or not {@code usage} was in the usage list */ private boolean removeUsage(Node node) { - assert recordsUsages(); assert node != null; // It is critical that this method maintains the invariant that // the usage list has no null element preceding a non-null element @@ -441,7 +439,6 @@ } private void clearUsages() { - assert recordsUsages(); incUsageModCount(); usage0 = null; usage1 = null; @@ -494,18 +491,14 @@ assert isAlive() && (newInput == null || newInput.isAlive()) : "adding " + newInput + " to " + this + " instead of " + oldInput; if (oldInput != newInput) { if (oldInput != null) { - if (oldInput.recordsUsages()) { - boolean result = removeThisFromUsages(oldInput); - assert assertTrue(result, "not found in usages, old input: %s", oldInput); - } + boolean result = removeThisFromUsages(oldInput); + assert assertTrue(result, "not found in usages, old input: %s", oldInput); } maybeNotifyInputChanged(this); if (newInput != null) { - if (newInput.recordsUsages()) { - newInput.addUsage(this); - } + newInput.addUsage(this); } - if (oldInput != null && oldInput.recordsUsages() && oldInput.usages().isEmpty()) { + if (oldInput != null && oldInput.usages().isEmpty()) { maybeNotifyZeroUsages(oldInput); } } @@ -570,9 +563,7 @@ assert assertTrue(result, "not found in inputs, usage: %s", usage); if (other != null) { maybeNotifyInputChanged(usage); - if (other.recordsUsages()) { - other.addUsage(usage); - } + other.addUsage(usage); } } clearUsages(); @@ -592,9 +583,7 @@ assert assertTrue(result, "not found in inputs, usage: %s", usage); if (other != null) { maybeNotifyInputChanged(usage); - if (other.recordsUsages()) { - other.addUsage(usage); - } + other.addUsage(usage); } } else { if (removeStart >= 0) { @@ -678,11 +667,9 @@ private void unregisterInputs() { for (Node input : inputs()) { - if (input.recordsUsages()) { - removeThisFromUsages(input); - if (input.usages().isEmpty()) { - maybeNotifyZeroUsages(input); - } + removeThisFromUsages(input); + if (input.usages().isEmpty()) { + maybeNotifyZeroUsages(input); } } } @@ -713,9 +700,7 @@ } private boolean checkDeletion() { - if (recordsUsages()) { - assertTrue(usages().isEmpty(), "cannot delete node %s because of usages: %s", this, usages()); - } + assertTrue(usages().isEmpty(), "cannot delete node %s because of usages: %s", this, usages()); assertTrue(predecessor == null, "cannot delete node %s because of predecessor: %s", this, predecessor); return true; } @@ -743,9 +728,7 @@ clazz.copyInputs(this, newNode); if (addToGraph) { for (Node input : inputs()) { - if (input.recordsUsages()) { - input.addUsage(newNode); - } + input.addUsage(newNode); } } return newNode; @@ -817,23 +800,20 @@ assertTrue(isAlive(), "cannot verify inactive nodes (id=%d)", id); assertTrue(graph() != null, "null graph"); for (Node input : inputs()) { - assertTrue(!input.recordsUsages() || input.usages().contains(this), "missing usage in input %s", input); + assertTrue(input.usages().contains(this), "missing usage in input %s", input); } for (Node successor : successors()) { assertTrue(successor.predecessor() == this, "missing predecessor in %s (actual: %s)", successor, successor.predecessor()); assertTrue(successor.graph() == graph(), "mismatching graph in successor %s", successor); } - if (recordsUsages()) { - for (Node usage : usages()) { - assertFalse(usage.isDeleted(), "usage %s must never be deleted", usage); - assertTrue(usage.inputs().contains(this), "missing input in usage %s", usage); - NodePosIterator iterator = usage.inputs().iterator(); - while (iterator.hasNext()) { - Position pos = iterator.nextPosition(); - if (pos.get(usage) == this && pos.getInputType(usage) != InputType.Unchecked) { - assert isAllowedUsageType(pos.getInputType(usage)) : "invalid input of type " + pos.getInputType(usage) + " from " + usage + " to " + this + " (" + pos.getInputName(usage) + - ")"; - } + for (Node usage : usages()) { + assertFalse(usage.isDeleted(), "usage %s must never be deleted", usage); + assertTrue(usage.inputs().contains(this), "missing input in usage %s", usage); + NodePosIterator iterator = usage.inputs().iterator(); + while (iterator.hasNext()) { + Position pos = iterator.nextPosition(); + if (pos.get(usage) == this && pos.getInputType(usage) != InputType.Unchecked) { + assert isAllowedUsageType(pos.getInputType(usage)) : "invalid input of type " + pos.getInputType(usage) + " from " + usage + " to " + this + " (" + pos.getInputName(usage) + ")"; } } } @@ -1034,6 +1014,24 @@ return NodeClassIterable.Empty; } + /** + * Determines if this node's inputs contain a given node. + * + * @param other + */ + public boolean inputsContains(Node other) { + return false; + } + + /** + * Determines if this node's successors contain a given node. + * + * @param other + */ + public boolean successorsContains(Node other) { + return false; + } + public NodeClassIterable successorsV2() { return NodeClassIterable.Empty; } @@ -1056,6 +1054,68 @@ } /** + * Gets the number of {@link Node} and {@link NodeList} fields in this node that are + * {@link Input}s or {@link OptionalInput}s. + * + * @return {@code L << 16 | N} where {@code N} is the number of {@link Node} fields and + * {@code L} is the number of {@link NodeList} fields + */ + public int getInputsCount() { + return 0; + } + + /** + * Gets the number of {@link Node} and {@link NodeList} fields in this node that are + * {@link Successor}s. + * + * @return {@code L << 16 | N} where {@code N} is the number of {@link Node} fields and + * {@code L} is the number of {@link NodeList} fields + */ + public int getSuccessorsCount() { + return 0; + } + + /** + * Gets an input of this node at a given index. + * + * @param index index of an input {@link Node} field. This value must be in the range of the + * number of {@link Node} fields returned by {@link #getInputsCount()}. + */ + public Node getInputNodeAt(int index) { + throw new NoSuchElementException(); + } + + /** + * Gets a successor of this node at a given index. + * + * @param index index of a successor {@link Node} field. This value must be in the range of the + * number of {@link Node} fields returned by {@link #getSuccessorsCount()}. + */ + public Node getSuccessorNodeAt(int index) { + throw new NoSuchElementException(); + } + + /** + * Gets an input list at a given index. + * + * @param index index of an input {@link NodeList} field. This value must be in the range of the + * number of {@link NodeList} fields returned by {@link #getInputsCount()}. + */ + public NodeList getInputNodeListAt(int index) { + throw new NoSuchElementException(); + } + + /** + * Gets a successor list at a given index. + * + * @param index index of a successor {@link NodeList} field. This value must be in the range of + * the number of {@link NodeList} fields returned by {@link #getSuccessorsCount()}. + */ + public NodeList getSuccessorNodeListAt(int index) { + throw new NoSuchElementException(); + } + + /** * Gets an input or successor list at a given position. * * @param position diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeAllRefsIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeAllRefsIterator.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.graph; + +import com.oracle.graal.graph.Node.Input; + +/** + * An iterator over the references to a given {@link Node}'s {@linkplain Input inputs}. + * + * An iterator of this type will return null values. + */ +public final class NodeAllRefsIterator extends NodeRefIterator { + + public NodeAllRefsIterator(Node node, int nodeFields, int nodeListFields, boolean isInputs) { + super(node, nodeFields, nodeListFields, isInputs); + } + + @Override + protected void forward() { + assert needsForward; + needsForward = false; + if (index < nodeFields) { + index++; + if (index < nodeFields) { + nextElement = getNode(index); + return; + } + } else { + subIndex++; + } + + while (index < allNodeRefFields) { + if (subIndex == 0) { + list = getNodeList(index - nodeFields); + } + if (subIndex < list.size()) { + nextElement = list.get(subIndex); + return; + } + subIndex = 0; + index++; + } + } +} diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Tue Sep 09 14:31:36 2014 -0700 @@ -340,7 +340,17 @@ } /** - * Determines if a given {@link Node} class is described by the {@link NodeClass} object. + * Determines if a given {@link Node} class is described by this {@link NodeClass} object. This + * is useful for doing an exact type test (as opposed to an instanceof test) on a node. For + * example: + * + *
+     *     if (node.getNodeClass().is(BeginNode.class)) { ... }
+     *
+     *     // Due to generated Node classes, the test below
+     *     // is *not* the same as the test above:
+     *     if (node.getClass() == BeginNode.class) { ... }
+     * 
* * @param nodeClass a {@linkplain GeneratedNode non-generated} {@link Node} class */ @@ -496,6 +506,9 @@ protected final Node node; protected int index; protected int subIndex; + NodeList list; + protected boolean needsForward; + protected Node nextElement; /** * Creates an iterator that will iterate over fields in the given node. @@ -506,14 +519,16 @@ this.node = node; index = NOT_ITERABLE; subIndex = 0; + needsForward = true; } void forward() { + needsForward = false; if (index < getDirectCount()) { index++; while (index < getDirectCount()) { - Node element = getNode(node, getOffsets()[index]); - if (element != null) { + nextElement = getNode(node, getOffsets()[index]); + if (nextElement != null) { return; } index++; @@ -522,9 +537,12 @@ subIndex++; } while (index < getOffsets().length) { - NodeList list = getNodeList(node, getOffsets()[index]); + if (subIndex == 0) { + list = getNodeList(node, getOffsets()[index]); + } while (subIndex < list.size()) { - if (list.get(subIndex) != null) { + nextElement = list.get(subIndex); + if (nextElement != null) { return; } subIndex++; @@ -535,39 +553,39 @@ } private Node nextElement() { - if (index < getDirectCount()) { - return getNode(node, getOffsets()[index]); - } else if (index < getOffsets().length) { - NodeList list = getNodeList(node, getOffsets()[index]); - return list.get(subIndex); + if (needsForward) { + forward(); + } + needsForward = true; + if (index < getOffsets().length) { + return nextElement; } throw new NoSuchElementException(); } @Override public boolean hasNext() { + if (needsForward) { + forward(); + } return index < getOffsets().length; } @Override public Node next() { - try { - return nextElement(); - } finally { - forward(); - } + return nextElement(); } public Position nextPosition() { - try { - if (index < getDirectCount()) { - return new Position(getOffsets() == getNodeClass().inputOffsets, index, NOT_ITERABLE); - } else { - return new Position(getOffsets() == getNodeClass().inputOffsets, index, subIndex); - } - } finally { + if (needsForward) { forward(); } + needsForward = true; + if (index < getDirectCount()) { + return new Position(getOffsets() == getNodeClass().inputOffsets, index, NOT_ITERABLE); + } else { + return new Position(getOffsets() == getNodeClass().inputOffsets, index, subIndex); + } } @Override @@ -583,16 +601,10 @@ } private class NodeClassInputsIterator extends NodeClassIterator { + NodeClassInputsIterator(Node node) { - this(node, true); - } - - NodeClassInputsIterator(Node node, boolean forward) { super(node); assert NodeClass.this == node.getNodeClass(); - if (forward) { - forward(); - } } @Override @@ -613,22 +625,27 @@ private class NodeClassAllInputsIterator extends NodeClassInputsIterator { NodeClassAllInputsIterator(Node node) { - super(node, true); + super(node); } @Override void forward() { + needsForward = false; if (index < getDirectCount()) { index++; if (index < getDirectCount()) { + nextElement = getNode(node, getOffsets()[index]); return; } } else { subIndex++; } while (index < getOffsets().length) { - NodeList list = getNodeList(node, getOffsets()[index]); + if (subIndex == 0) { + list = getNodeList(node, getOffsets()[index]); + } if (subIndex < list.size()) { + nextElement = list.get(subIndex); return; } subIndex = 0; @@ -639,22 +656,27 @@ private class NodeClassAllSuccessorsIterator extends NodeClassSuccessorsIterator { NodeClassAllSuccessorsIterator(Node node) { - super(node, true); + super(node); } @Override void forward() { + needsForward = false; if (index < getDirectCount()) { index++; if (index < getDirectCount()) { + nextElement = getNode(node, getOffsets()[index]); return; } } else { subIndex++; } while (index < getOffsets().length) { - NodeList list = getNodeList(node, getOffsets()[index]); + if (subIndex == 0) { + list = getNodeList(node, getOffsets()[index]); + } if (subIndex < list.size()) { + nextElement = list.get(subIndex); return; } subIndex = 0; @@ -667,10 +689,9 @@ private final int modCount; private NodeClassInputsWithModCountIterator(Node node) { - super(node, false); + super(node); assert MODIFICATION_COUNTS_ENABLED; this.modCount = node.modCount(); - forward(); } @Override @@ -702,16 +723,10 @@ } private class NodeClassSuccessorsIterator extends NodeClassIterator { + NodeClassSuccessorsIterator(Node node) { - this(node, true); - } - - NodeClassSuccessorsIterator(Node node, boolean forward) { super(node); assert NodeClass.this == node.getNodeClass(); - if (forward) { - forward(); - } } @Override @@ -734,10 +749,9 @@ private final int modCount; private NodeClassSuccessorsWithModCountIterator(Node node) { - super(node, false); + super(node); assert MODIFICATION_COUNTS_ENABLED; this.modCount = node.modCount(); - forward(); } @Override diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeRefIterable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeRefIterable.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.graph; + +import static com.oracle.graal.graph.Graph.*; + +import com.oracle.graal.graph.Node.*; + +/** + * An iterator over the references to a given {@link Node}'s {@linkplain Input inputs} or + * {@linkplain Successor successors}. + */ +public final class NodeRefIterable implements NodeClassIterable { + + protected final Node node; + + /** + * Specifies if {@link #iterator()} and {@link #withNullIterator()} iterate over + * {@linkplain Input inputs} or {@linkplain Successor successors}. + */ + protected final boolean isInputs; + + public NodeRefIterable(Node node, boolean isInputs) { + this.isInputs = isInputs; + this.node = node; + } + + @Override + public NodePosIterator iterator() { + int count = isInputs ? node.getInputsCount() : node.getSuccessorsCount(); + if (count == 0) { + return NodeRefIterator.Empty; + } + int nodeFields = count & 0xFFFF; + int nodeListFields = (count >> 16) & 0xFFFF; + if (MODIFICATION_COUNTS_ENABLED) { + return new NodeRefWithModCountIterator(node, nodeFields, nodeListFields, isInputs); + } else { + return new NodeRefIterator(node, nodeFields, nodeListFields, isInputs); + } + } + + public NodePosIterator withNullIterator() { + int count = isInputs ? node.getInputsCount() : node.getSuccessorsCount(); + if (count == 0) { + return NodeRefIterator.Empty; + } + int nodeFields = count & 0xFFFF; + int nodeListFields = (count >> 16) & 0xFFFF; + return new NodeAllRefsIterator(node, nodeFields, nodeListFields, isInputs); + } + + @Override + public boolean contains(Node other) { + return isInputs ? node.inputsContains(other) : node.successorsContains(other); + } +} diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeRefIterator.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeRefIterator.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeRefIterator.java Tue Sep 09 14:31:36 2014 -0700 @@ -36,7 +36,9 @@ */ public class NodeRefIterator implements NodePosIterator { - public static final NodeRefIterator Empty = new NodeRefIterator(0, 0, false); + public static final NodeRefIterator Empty = new NodeRefIterator(); + + protected final Node node; /** * The total number of {@link Node} and {@link NodeList} fields. @@ -52,7 +54,7 @@ * Specifies if this iterator iterates over {@linkplain Input inputs} or {@linkplain Successor * successors}. */ - private final boolean isInputs; + protected final boolean isInputs; /** * Current field iteration index. @@ -65,6 +67,10 @@ */ protected int subIndex; + protected Node nextElement; + protected boolean needsForward; + protected NodeList list; + /** * Creates an iterator over a node's references (i.e., {@linkplain Input inputs} or * {@linkplain Successor successors}) to other nodes. The {@link Node} fields are iterated @@ -76,22 +82,38 @@ * @param nodeListFields the number of {@link NodeList} fields in the class hierarchy of the * node being iterated */ - protected NodeRefIterator(int nodeFields, int nodeListFields, boolean isInputs) { + protected NodeRefIterator(Node node, int nodeFields, int nodeListFields, boolean isInputs) { + this.node = node; this.allNodeRefFields = nodeListFields + nodeFields; this.nodeFields = nodeFields; this.isInputs = isInputs; - index = Node.NOT_ITERABLE; + this.needsForward = true; + index = -1; subIndex = 0; } /** + * Constructor for {@link #Empty}. + */ + private NodeRefIterator() { + this(null, 0, 0, false); + // This constructor must only be used to construct Empty + assert Empty == null; + // This must be set here to prevent multiple threads racing to + // call forward() which never needs to be done for Empty. + this.needsForward = false; + // Ensure hasNext() will always return false. + this.index = 0; + } + + /** * Gets the value of a {@link Node} field in the node. * * @param at the index of the Node field whose value is being requested. This is guaranteed to * be between 0 and the {@code nodeFields} value this iterator was constructed with */ protected Node getNode(int at) { - throw new NoSuchElementException(); + return isInputs ? node.getInputNodeAt(at) : node.getSuccessorNodeAt(at); } /** @@ -102,15 +124,16 @@ * constructed with */ protected NodeList getNodeList(int at) { - throw new NoSuchElementException(); + return isInputs ? node.getInputNodeListAt(at) : node.getSuccessorNodeListAt(at); } protected void forward() { + needsForward = false; if (index < nodeFields) { index++; while (index < nodeFields) { - Node element = getNode(index); - if (element != null) { + nextElement = getNode(index); + if (nextElement != null) { return; } index++; @@ -119,9 +142,13 @@ subIndex++; } while (index < allNodeRefFields) { - NodeList list = getNodeList(index - nodeFields); + if (subIndex == 0) { + list = getNodeList(index - nodeFields); + } + assert list == getNodeList(index - nodeFields); while (subIndex < list.size()) { - if (list.get(subIndex) != null) { + nextElement = list.get(subIndex); + if (nextElement != null) { return; } subIndex++; @@ -133,39 +160,39 @@ } private Node nextElement() { - if (index < nodeFields) { - return getNode(index); - } else if (index < allNodeRefFields) { - NodeList list = getNodeList(index - nodeFields); - return list.get(subIndex); + if (needsForward) { + forward(); + } + needsForward = true; + if (index < allNodeRefFields) { + return nextElement; } throw new NoSuchElementException(); } @Override public boolean hasNext() { - return index >= 0 && index < allNodeRefFields; + if (needsForward) { + forward(); + } + return index < allNodeRefFields; } @Override public Node next() { - try { - return nextElement(); - } finally { - forward(); - } + return nextElement(); } public Position nextPosition() { - try { - if (index < nodeFields) { - return new Position(isInputs, index, Node.NOT_ITERABLE); - } else { - return new Position(isInputs, index, subIndex); - } - } finally { + if (needsForward) { forward(); } + needsForward = true; + if (index < nodeFields) { + return new Position(isInputs, index, Node.NOT_ITERABLE); + } else { + return new Position(isInputs, index, subIndex); + } } @Override diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeRefWithModCountIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeRefWithModCountIterator.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.graph; + +import static com.oracle.graal.graph.Graph.*; + +import com.oracle.graal.graph.Node.Input; + +/** + * An iterator over the references to a given {@link Node}'s {@linkplain Input inputs}. + * + * An iterator of this type will not return null values, unless the field values are modified + * concurrently. Concurrent modifications are detected by an assertion on a best-effort basis. + */ +public final class NodeRefWithModCountIterator extends NodeRefIterator { + + private final int modCount; + + public NodeRefWithModCountIterator(Node node, int nodeFields, int nodeListFields, boolean isInputs) { + super(node, nodeFields, nodeListFields, isInputs); + assert MODIFICATION_COUNTS_ENABLED; + this.modCount = node.modCount(); + } + + @Override + public boolean hasNext() { + try { + return super.hasNext(); + } finally { + assert modCount == node.modCount() : "must not be modified"; + } + } + + @Override + public Node next() { + try { + return super.next(); + } finally { + assert modCount == node.modCount() : "must not be modified"; + } + } + + @Override + public Position nextPosition() { + try { + return super.nextPosition(); + } finally { + assert modCount == node.modCount(); + } + } +} diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java Tue Sep 09 14:31:36 2014 -0700 @@ -692,7 +692,7 @@ }; DebugConfig debugConfig = DebugScope.getConfig(); - DebugConfig fixedConfig = Debug.fixedConfig(0, 0, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.verifyHandlers(), debugConfig.output()); + DebugConfig fixedConfig = debugConfig == null ? null : Debug.fixedConfig(0, 0, false, false, false, false, debugConfig.dumpHandlers(), debugConfig.verifyHandlers(), debugConfig.output()); try (DebugConfigScope s = Debug.setConfig(fixedConfig)) { ReentrantNodeIterator.apply(closure, graph.start(), false); new WriteBarrierVerificationPhase().apply(graph); diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java Tue Sep 09 14:31:36 2014 -0700 @@ -45,10 +45,8 @@ @Override protected boolean verify(StructuredGraph graph, PhaseContext context) { for (ConstantNode node : getConstantNodes(graph)) { - if (node.recordsUsages()) { - if (isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node)) { - throw new VerificationError("illegal object constant: " + node); - } + if (isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node)) { + throw new VerificationError("illegal object constant: " + node); } } return true; diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Tue Sep 09 14:31:36 2014 -0700 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.phases; +import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.debug.*; @@ -109,6 +111,6 @@ GraphUtil.killCFG(start); Debug.dump(graph, "OnStackReplacement result"); - new DeadCodeEliminationPhase().apply(graph); + new DeadCodeEliminationPhase(OPTIONAL).apply(graph); } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java Tue Sep 09 14:31:36 2014 -0700 @@ -71,7 +71,9 @@ Iterator iterator = frontier.iterator(); while (iterator.hasNext()) { Node currentNode = iterator.next(); - assert !isSafepoint(currentNode) : "Write barrier must be present " + write; + if (isSafepoint(currentNode)) { + throw new AssertionError("Write barrier must be present " + write); + } if (useG1GC()) { if (!(currentNode instanceof G1PostWriteBarrier) || (!validateBarrier((FixedAccessNode) write, (WriteBarrier) currentNode))) { expandFrontier(frontier, currentNode); diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java Tue Sep 09 14:31:36 2014 -0700 @@ -107,12 +107,36 @@ // insert moves, delete null instructions and reset instruction ids lir.getControlFlowGraph().getBlocks().forEach(this::rewriteBlock); + + assert verifyStates(); } catch (Throwable e) { throw Debug.handle(e); } } } + private boolean verifyStates() { + map.forEach(this::verifyStateUsage); + return true; + } + + private void verifyStateUsage(DefUseTree tree) { + Variable var = tree.getVariable(); + ValueConsumer stateConsumer = new ValueConsumer() { + + @Override + public void visitValue(Value operand) { + assert !operand.equals(var) : "constant usage through variable in frame state " + var; + } + }; + for (AbstractBlock block : lir.getControlFlowGraph().getBlocks()) { + for (LIRInstruction inst : lir.getLIRforBlock(block)) { + // set instruction id to the index in the lir instruction list + inst.visitEachState(stateConsumer); + } + } + } + private static boolean isConstantLoad(LIRInstruction inst) { if (!(inst instanceof MoveOp)) { return false; diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeGenerator.java --- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeGenerator.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeGenerator.java Tue Sep 09 14:31:36 2014 -0700 @@ -47,6 +47,8 @@ */ public class GraphNodeGenerator { + private static final boolean GENERATE_ASSERTIONS = false; + private final GraphNodeProcessor env; private final Types types; private final Elements elements; @@ -283,6 +285,10 @@ enum NodeRefsType { Inputs, Successors; + + String singular() { + return name().substring(0, name().length() - 1); + } } CodeCompilationUnit process(TypeElement node, boolean constructorsOnly) { @@ -336,7 +342,7 @@ createPositionAccessibleFieldOrderClass(packageElement); if (!inputListFields.isEmpty() || !successorListFields.isEmpty()) { - createGetNodeListAtMethod(); + createGetNodeListAtPositionMethod(); createSetNodeListAtMethod(); } } @@ -352,6 +358,11 @@ createAllIteratorClass(Inputs, inputsIteratorClass.asType(), packageElement, inputFields, inputListFields); createWithModCountIteratorClass(Inputs, inputsIteratorClass.asType(), packageElement); createIterableClass(Inputs, packageElement); + createGetNodeAtMethod(NodeRefsType.Inputs, inputFields); + createCountMethod(NodeRefsType.Inputs, inputFields.size(), inputListFields.size()); + if (!inputListFields.isEmpty()) { + createGetNodeListAtIndexMethod(NodeRefsType.Inputs, inputListFields); + } } if (hasSuccessors) { @@ -364,6 +375,11 @@ createAllIteratorClass(Successors, successorsIteratorClass.asType(), packageElement, successorFields, successorListFields); createWithModCountIteratorClass(Successors, successorsIteratorClass.asType(), packageElement); createIterableClass(Successors, packageElement); + createGetNodeAtMethod(NodeRefsType.Successors, successorFields); + createCountMethod(NodeRefsType.Successors, successorFields.size(), successorListFields.size()); + if (!successorListFields.isEmpty()) { + createGetNodeListAtIndexMethod(NodeRefsType.Successors, successorListFields); + } } } compilationUnit.add(genClass); @@ -426,6 +442,22 @@ genClassName = null; } + private CodeVariableElement addParameter(CodeExecutableElement method, TypeMirror type, String name) { + return addParameter(method, type, name, true); + } + + private CodeVariableElement addParameter(CodeExecutableElement method, TypeMirror type, String name, boolean checkHiding) { + CodeVariableElement parameter = new CodeVariableElement(type, name); + if (checkHiding && hidesField(parameter.getSimpleName().toString())) { + DeclaredType suppress = (DeclaredType) getType(SuppressWarnings.class); + CodeAnnotationMirror suppressMirror = new CodeAnnotationMirror(suppress); + suppressMirror.setElementValue(suppressMirror.findExecutableElement("value"), new CodeAnnotationValue("hiding")); + parameter.getAnnotationMirrors().add(suppressMirror); + } + method.addParameter(parameter); + return parameter; + } + /** * Checks that a generated method overrides exactly one method in a super type and that the * super type is Node. @@ -448,9 +480,11 @@ private ExecutableElement createIsOptionalInputAtMethod() { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isOptionalInputAt"); - method.addParameter(new CodeVariableElement(Position.asType(), "pos")); + addParameter(method, Position.asType(), "pos"); CodeTreeBuilder b = method.createBuilder(); - b.startAssert().string("pos.isInput()").end(); + if (GENERATE_ASSERTIONS) { + b.startAssert().string("pos.isInput()").end(); + } if (!optionalInputs.isEmpty()) { b.startSwitch().string("pos.getIndex()").end().startBlock(); int index = 0; @@ -490,16 +524,13 @@ // Constructor CodeExecutableElement ctor = new CodeExecutableElement(Collections.emptySet(), null, name); - ctor.addParameter(new CodeVariableElement(getType(boolean.class), "callForward")); CodeTreeBuilder b = ctor.createBuilder(); b.startStatement().startSuperCall(); + b.string(genClassName, ".this"); b.string(String.valueOf(nodeFields.size())); b.string(String.valueOf(nodeListFields.size())); b.string(String.valueOf(nodeRefsType == NodeRefsType.Inputs)); b.end().end(); - b.startIf().string("callForward").end().startBlock(); - b.startStatement().string("forward()").end(); - b.end(); cls.add(ctor); // Methods overriding those in NodeRefIterator @@ -512,7 +543,7 @@ private void createGetFieldMethod(CodeTypeElement cls, List fields, TypeMirror returnType, String name) { if (!fields.isEmpty()) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), returnType, name); - method.addParameter(new CodeVariableElement(getType(int.class), "at")); + addParameter(method, getType(int.class), "at"); CodeTreeBuilder b = method.createBuilder(); createGetFieldCases(b, fields, returnType, null); cls.add(method); @@ -623,7 +654,7 @@ CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(String[].class), "getOrderedFieldNames"); - method.addParameter(new CodeVariableElement(getType(boolean.class), "input")); + addParameter(method, getType(boolean.class), "input", false); CodeTreeBuilder b = method.createBuilder(); b.startIf().string("input").end().startBlock(); @@ -646,34 +677,33 @@ CodeTypeElement cls = new CodeTypeElement(modifiers(PRIVATE, FINAL), ElementKind.CLASS, packageElement, name); cls.setSuperClass(inputsIteratorType); - // Constructor - CodeExecutableElement ctor = new CodeExecutableElement(Collections.emptySet(), null, name); - CodeTreeBuilder b = ctor.createBuilder(); - b.startStatement().startSuperCall(); - b.string("true"); - b.end().end(); - cls.add(ctor); - // forward() method CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), getType(void.class), "forward"); - b = method.createBuilder(); + CodeTreeBuilder b = method.createBuilder(); int nodeFieldsSize = nodeFields.size(); int nodeListFieldsSize = nodeListFields.size(); String cond = "index < " + nodeFieldsSize; + if (GENERATE_ASSERTIONS) { + b.startAssert().string("needsForward").end(); + } + b.startStatement().string("needsForward = false").end(); b.startIf().string(cond).end().startBlock(); b.startStatement().string("index++").end(); b.startIf().string(cond).end().startBlock(); + b.startStatement().string("nextElement = getNode(index)").end(); b.startStatement().string("return").end(); b.end(); b.end(); b.startElseBlock(); b.startStatement().string("subIndex++").end(); b.end(); - DeclaredType nodeListOfNode = types.getDeclaredType(NodeList, types.getWildcardType(Node.asType(), null)); int count = nodeFieldsSize + nodeListFieldsSize; b.startWhile().string("index < " + count).end().startBlock(); - b.declaration(nodeListOfNode, "list", "getNodeList(index - " + nodeFieldsSize + ")"); + b.startIf().string("subIndex == 0").end().startBlock(); + b.startStatement().string("list = getNodeList(index - " + nodeFieldsSize + ")").end(); + b.end(); b.startIf().string("subIndex < list.size()").end().startBlock(); + b.startStatement().string("nextElement = list.get(subIndex)").end(); b.startStatement().string("return").end(); b.end(); b.startStatement().string("subIndex = 0").end(); @@ -697,12 +727,8 @@ // Constructor CodeExecutableElement ctor = new CodeExecutableElement(Collections.emptySet(), null, name); CodeTreeBuilder b = ctor.createBuilder(); - b.startStatement().startSuperCall(); - b.string("false"); - b.end().end(); b.startAssert().staticReference(getType("com.oracle.graal.graph.Graph"), "MODIFICATION_COUNTS_ENABLED").end(); b.startStatement().string("this.modCount = modCount()").end(); - b.startStatement().string("forward()").end(); cls.add(ctor); // hasNext, next and nextPosition methods @@ -737,7 +763,7 @@ b.startStatement().string("return new " + nodeRefsType + "WithModCountIterator()").end(); b.end(); b.startElseBlock(); - b.startStatement().string("return new " + nodeRefsType + "Iterator(true)").end(); + b.startStatement().string("return new " + nodeRefsType + "Iterator()").end(); b.end(); cls.add(method); @@ -749,16 +775,16 @@ // contains(Node) method method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), getType(boolean.class), "contains"); - method.addParameter(new CodeVariableElement(Node.asType(), "n")); + addParameter(method, Node.asType(), "n"); b = method.createBuilder(); - b.startStatement().string("return " + nodeRefsType.name().toLowerCase() + "Contain(n)").end(); + b.startStatement().string("return " + nodeRefsType.name().toLowerCase() + "Contains(n)").end(); cls.add(method); genClass.add(cls); } private void createContainsMethod(NodeRefsType nodeRefsType, List nodeFields, List nodeListFields) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, FINAL), getType(boolean.class), nodeRefsType.name().toLowerCase() + "Contain"); - method.addParameter(new CodeVariableElement(Node.asType(), "n")); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), getType(boolean.class), nodeRefsType.name().toLowerCase() + "Contains"); + addParameter(method, Node.asType(), "n"); CodeTreeBuilder b = method.createBuilder(); for (VariableElement f : nodeFields) { b.startIf().string("n == " + f).end().startBlock(); @@ -788,7 +814,7 @@ private void createGetNodeAtMethod() { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), Node.asType(), "getNodeAt"); - method.addParameter(new CodeVariableElement(Position.asType(), "pos")); + addParameter(method, Position.asType(), "pos"); CodeTreeBuilder b = method.createBuilder(); b.startIf().string("pos.isInput()").end().startBlock(); createGetNodeAt(b, inputFields, inputListFields); @@ -800,9 +826,79 @@ checkOnlyInGenNode(method); } - private void createGetNodeListAtMethod() { + private void createCountMethod(NodeRefsType nodeRefsType, int nodesCount, int nodeListsCount) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), getType(int.class), "get" + nodeRefsType + "Count"); + CodeTreeBuilder b = method.createBuilder(); + + b.startStatement().string("return " + (nodeListsCount << 16 | nodesCount), " /* (" + nodeListsCount + " << 16 | " + nodesCount + ") */").end(); + genClass.add(method); + checkOnlyInGenNode(method); + } + + private void createGetNodeAtMethod(NodeRefsType nodeRefsType, List nodes) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), Node.asType(), "get" + nodeRefsType.singular() + "NodeAt"); + addParameter(method, getType(int.class), "index"); + CodeTreeBuilder b = method.createBuilder(); + boolean justOne = nodes.size() == 1; + if (!justOne) { + b.startSwitch().string("index").end().startBlock(); + } else if (GENERATE_ASSERTIONS) { + b.startAssert().string("index == 0").end(); + } + int index = 0; + for (VariableElement f : nodes) { + if (!justOne) { + b.startCase().string(String.valueOf(index)).end(); + } + b.startReturn(); + if (!isAssignableWithErasure(f, Node)) { + b.cast(((DeclaredType) Node.asType()).asElement().getSimpleName().toString()); + } + b.string(genClassName + ".this." + f.getSimpleName()); + b.end(); + index++; + } + if (!justOne) { + b.end(); + b.startThrow().startNew(getType(NoSuchElementException.class)).end().end(); + } + genClass.add(method); + checkOnlyInGenNode(method); + } + + private void createGetNodeListAtIndexMethod(NodeRefsType nodeRefsType, List nodeLists) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), types.getDeclaredType(NodeList, types.getWildcardType(Node.asType(), null)), "get" + + nodeRefsType.singular() + "NodeListAt"); + addParameter(method, getType(int.class), "index"); + CodeTreeBuilder b = method.createBuilder(); + + boolean justOne = nodeLists.size() == 1; + if (!justOne) { + b.startSwitch().string("index").end().startBlock(); + } else if (GENERATE_ASSERTIONS) { + b.startAssert().string("index == 0").end(); + } + int index = 0; + for (VariableElement f : nodeLists) { + if (!justOne) { + b.startCase().string(String.valueOf(index)).end(); + } + b.startReturn(); + b.string(genClassName + ".this." + f.getSimpleName()); + b.end(); + index++; + } + if (!justOne) { + b.end(); + b.startThrow().startNew(getType(NoSuchElementException.class)).end().end(); + } + genClass.add(method); + checkOnlyInGenNode(method); + } + + private void createGetNodeListAtPositionMethod() { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), types.getDeclaredType(NodeList, types.getWildcardType(Node.asType(), null)), "getNodeListAt"); - method.addParameter(new CodeVariableElement(Position.asType(), "pos")); + addParameter(method, Position.asType(), "pos"); CodeTreeBuilder b = method.createBuilder(); b.startIf().string("pos.isInput()").end().startBlock(); createGetNodeListAt(b, inputFields, inputListFields); @@ -822,8 +918,8 @@ suppressMirror.setElementValue(suppressMirror.findExecutableElement("value"), new CodeAnnotationValue("unchecked")); method.getAnnotationMirrors().add(suppressMirror); - method.addParameter(new CodeVariableElement(Position.asType(), "pos")); - method.addParameter(new CodeVariableElement(types.getDeclaredType(NodeList, types.getWildcardType(Node.asType(), null)), "list")); + addParameter(method, Position.asType(), "pos"); + addParameter(method, types.getDeclaredType(NodeList, types.getWildcardType(Node.asType(), null)), "list"); CodeTreeBuilder b = method.createBuilder(); b.startIf().string("pos.isInput()").end().startBlock(); createSetNodeListAt(b, inputFields, inputListFields); @@ -837,7 +933,7 @@ private void createGetNameOfMethod() { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), getType(String.class), "getNameOf"); - method.addParameter(new CodeVariableElement(Position.asType(), "pos")); + addParameter(method, Position.asType(), "pos"); CodeTreeBuilder b = method.createBuilder(); b.startIf().string("pos.isInput()").end().startBlock(); @@ -852,9 +948,11 @@ private void createGetInputTypeAtMethod() { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), getType(InputType.class), "getInputTypeAt"); - method.addParameter(new CodeVariableElement(Position.asType(), "pos")); + addParameter(method, Position.asType(), "pos"); CodeTreeBuilder b = method.createBuilder(); - b.startAssert().string("pos.isInput()").end(); + if (GENERATE_ASSERTIONS) { + b.startAssert().string("pos.isInput()").end(); + } boolean hasNodes = !inputFields.isEmpty(); boolean hasNodeLists = !inputListFields.isEmpty(); if (hasNodeLists || hasNodes) { @@ -882,15 +980,8 @@ private void createUpdateOrInitializeNodeAtMethod(boolean isInitialization) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), getType(void.class), (isInitialization ? "initialize" : "update") + "NodeAt"); - method.addParameter(new CodeVariableElement(Position.asType(), "pos")); - CodeVariableElement newValue = new CodeVariableElement(Node.asType(), "newValue"); - if (hidesField(newValue.getSimpleName().toString())) { - DeclaredType suppress = (DeclaredType) getType(SuppressWarnings.class); - CodeAnnotationMirror suppressMirror = new CodeAnnotationMirror(suppress); - suppressMirror.setElementValue(suppressMirror.findExecutableElement("value"), new CodeAnnotationValue("hiding")); - newValue.getAnnotationMirrors().add(suppressMirror); - } - method.addParameter(newValue); + addParameter(method, Position.asType(), "pos"); + addParameter(method, Node.asType(), "newValue"); CodeTreeBuilder b = method.createBuilder(); b.startIf().string("pos.isInput()").end().startBlock(); createUpdateOrInitializeNodeAt(b, inputFields, inputListFields, isInitialization); @@ -910,7 +1001,9 @@ } else { if (hasNodes) { if (!hasNodeLists) { - b.startAssert().string("pos.getSubIndex() == NOT_ITERABLE").end(); + if (GENERATE_ASSERTIONS) { + b.startAssert().string("pos.getSubIndex() == NOT_ITERABLE").end(); + } } else { b.startIf().string("pos.getSubIndex() == NOT_ITERABLE").end().startBlock(); } @@ -923,7 +1016,9 @@ if (hasNodeLists) { if (!hasNodes) { - b.startAssert().string("pos.getSubIndex() != NOT_ITERABLE").end(); + if (GENERATE_ASSERTIONS) { + b.startAssert().string("pos.getSubIndex() != NOT_ITERABLE").end(); + } } else { b.startElseBlock(); } @@ -941,7 +1036,9 @@ if (!hasNodeLists) { b.startThrow().startNew(getType(NoSuchElementException.class)).end().end(); } else { - b.startAssert().string("pos.getSubIndex() == NODE_LIST").end(); + if (GENERATE_ASSERTIONS) { + b.startAssert().string("pos.getSubIndex() == NODE_LIST").end(); + } b.declaration("int", "at", "pos.getIndex() - " + nodes.size()); createGetFieldCases(b, nodeLists, Node.asType(), ""); } @@ -952,7 +1049,9 @@ if (!hasNodeLists) { b.startThrow().startNew(getType(NoSuchElementException.class)).end().end(); } else { - b.startAssert().string("pos.getSubIndex() == NODE_LIST").end(); + if (GENERATE_ASSERTIONS) { + b.startAssert().string("pos.getSubIndex() == NODE_LIST").end(); + } b.declaration("int", "at", "pos.getIndex() - " + nodes.size()); createSetNodeListAtCases(b, nodeLists, Node.asType(), ""); } @@ -987,7 +1086,9 @@ } else { if (hasNodes) { if (!hasNodeLists) { - b.startAssert().string("pos.getSubIndex() == NOT_ITERABLE").end(); + if (GENERATE_ASSERTIONS) { + b.startAssert().string("pos.getSubIndex() == NOT_ITERABLE").end(); + } } else { b.startIf().string("pos.getSubIndex() == NOT_ITERABLE").end().startBlock(); } @@ -1000,7 +1101,9 @@ if (hasNodeLists) { if (!hasNodes) { - b.startAssert().string("pos.getSubIndex() != NOT_ITERABLE").end(); + if (GENERATE_ASSERTIONS) { + b.startAssert().string("pos.getSubIndex() != NOT_ITERABLE").end(); + } } else { b.startElseBlock(); } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java Tue Sep 09 14:31:36 2014 -0700 @@ -46,6 +46,11 @@ @Override public void simplify(SimplifierTool tool) { - // + Node prev = this.predecessor(); + while (prev.getNodeClass().is(BeginNode.class) && prev.usages().isEmpty()) { + BeginNode begin = (BeginNode) prev; + prev = prev.predecessor(); + graph().removeFixed(begin); + } } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Tue Sep 09 14:31:36 2014 -0700 @@ -100,7 +100,7 @@ } ValueNode removedValue = phi.valueAt(predIndex); phi.removeInput(predIndex); - if (removedValue != null && removedValue.isAlive() && removedValue.recordsUsages() && removedValue.usages().isEmpty() && GraphUtil.isFloatingNode().apply(removedValue)) { + if (removedValue != null && removedValue.isAlive() && removedValue.usages().isEmpty() && GraphUtil.isFloatingNode().apply(removedValue)) { GraphUtil.killWithUnusedFloatingInputs(removedValue); } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Tue Sep 09 14:31:36 2014 -0700 @@ -193,7 +193,13 @@ @Override public void simplify(SimplifierTool tool) { - ValueNode singleValue = singleValue(); + ValueNode singleValue; + + if (isLoopPhi() && singleBackValue() == this) { + singleValue = firstValue(); + } else { + singleValue = singleValue(); + } if (singleValue != MULTIPLE_VALUES) { for (Node node : usages().snapshot()) { diff -r 82b5a7250a0d -r 4faf9bdb9973 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 Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java Tue Sep 09 14:31:36 2014 -0700 @@ -64,32 +64,42 @@ } /** + * Replicate the {@link ValueProxyNode}s from {@code originalValue} onto {@code value}. + * + * @param originalValue a possibly proxied value + * @param value a value needing proxies + * @return proxies wrapping {@code value} + */ + private static ValueNode reproxyValue(ValueNode originalValue, ValueNode value) { + if (value.isConstant()) { + // No proxy needed + return value; + } + if (originalValue instanceof ValueProxyNode) { + ValueProxyNode proxy = (ValueProxyNode) originalValue; + return ValueProxyNode.create(reproxyValue(proxy.getOriginalNode(), value), proxy.proxyPoint()); + } else if (originalValue instanceof ValueProxy) { + ValueProxy proxy = (ValueProxy) originalValue; + return reproxyValue(proxy.getOriginalNode(), value); + } else { + return value; + } + } + + /** * Gets the length of an array if possible. * * @return a node representing the length of {@code array} or null if it is not available */ public static ValueNode readArrayLength(ValueNode originalArray, ConstantReflectionProvider constantReflection) { - ArrayLengthProvider foundArrayLengthProvider = null; - ValueNode result = originalArray; - while (true) { - if (result instanceof ArrayLengthProvider) { - foundArrayLengthProvider = (ArrayLengthProvider) result; - break; - } - if (result instanceof ValueProxy) { - result = ((ValueProxy) result).getOriginalNode(); - } else { - break; + ValueNode array = GraphUtil.unproxify(originalArray); + if (array instanceof ArrayLengthProvider) { + ValueNode length = ((ArrayLengthProvider) array).length(); + if (length != null) { + // Ensure that any proxies on the original value end up on the length value + return reproxyValue(originalArray, length); } } - - if (foundArrayLengthProvider != null) { - ValueNode length = foundArrayLengthProvider.length(); - if (length != null) { - return length; - } - } - ValueNode array = GraphUtil.unproxify(originalArray); if (constantReflection != null && array.isConstant() && !array.isNullConstant()) { Constant constantValue = array.asConstant(); if (constantValue != null && constantValue.isNonNull()) { diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Tue Sep 09 14:31:36 2014 -0700 @@ -135,17 +135,13 @@ } public static void killWithUnusedFloatingInputs(Node node) { - if (node.recordsUsages()) { - List floatingInputs = node.inputs().filter(isFloatingNode()).snapshot(); - node.safeDelete(); + List floatingInputs = node.inputs().filter(isFloatingNode()).snapshot(); + node.safeDelete(); - for (Node in : floatingInputs) { - if (in.isAlive() && (!in.recordsUsages() || in.usages().isEmpty())) { - killWithUnusedFloatingInputs(in); - } + for (Node in : floatingInputs) { + if (in.isAlive() && in.usages().isEmpty()) { + killWithUnusedFloatingInputs(in); } - } else { - assert node.inputs().isEmpty(); } } @@ -358,7 +354,7 @@ } public static boolean tryKillUnused(Node node) { - if (node.isAlive() && isFloatingNode().apply(node) && node.recordsUsages() && node.usages().isEmpty()) { + if (node.isAlive() && isFloatingNode().apply(node) && node.usages().isEmpty()) { killWithUnusedFloatingInputs(node); return true; } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Tue Sep 09 14:31:36 2014 -0700 @@ -832,9 +832,6 @@ } private GuardingNode searchAnchor(ValueNode value, ResolvedJavaType type) { - if (!value.recordsUsages()) { - return null; - } for (Node n : value.usages()) { if (n instanceof InstanceOfNode) { InstanceOfNode instanceOfNode = (InstanceOfNode) n; diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java Tue Sep 09 14:31:36 2014 -0700 @@ -22,6 +22,8 @@ */ package com.oracle.graal.phases.common; +import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; + import java.util.*; import com.oracle.graal.api.meta.*; @@ -101,7 +103,7 @@ } } - new DeadCodeEliminationPhase().apply(graph); + new DeadCodeEliminationPhase(OPTIONAL).apply(graph); } private void visitDeoptBegin(BeginNode deoptBegin, DeoptimizationAction deoptAction, DeoptimizationReason deoptReason, StructuredGraph graph) { @@ -147,11 +149,11 @@ } } } - survivingSuccessor.simplify(simplifierTool); Debug.log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin); FixedNode next = pred.next(); pred.setNext(guard); guard.setNext(next); + survivingSuccessor.simplify(simplifierTool); return; } diff -r 82b5a7250a0d -r 4faf9bdb9973 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 Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java Tue Sep 09 14:31:36 2014 -0700 @@ -22,18 +22,54 @@ */ package com.oracle.graal.phases.common; +import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Options.*; + import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.options.*; import com.oracle.graal.phases.*; public class DeadCodeEliminationPhase extends Phase { + public static class Options { + // @formatter:off + @Option(help = "Disable optional dead code eliminations") + public static final OptionValue ReduceDCE = new OptionValue<>(true); + // @formatter:on + } + // Metrics private static final DebugMetric metricNodesRemoved = Debug.metric("NodesRemoved"); + public enum Optionality { + OPTIONAL, + REQUIRED; + } + + /** + * Creates a dead code elimination phase that will be run irrespective of + * {@link Options#ReduceDCE}. + */ + public DeadCodeEliminationPhase() { + this(Optionality.REQUIRED); + } + + /** + * Creates a dead code elimination phase that will be run only if it is + * {@linkplain Optionality#REQUIRED non-optional} or {@link Options#ReduceDCE} is false. + */ + public DeadCodeEliminationPhase(Optionality optionality) { + this.optional = optionality == Optionality.OPTIONAL; + } + + private final boolean optional; + @Override public void run(StructuredGraph graph) { + if (optional && ReduceDCE.getValue()) { + return; + } NodeFlood flood = graph.createNodeFlood(); flood.add(graph.start()); diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java Tue Sep 09 14:31:36 2014 -0700 @@ -172,10 +172,14 @@ * then remove the Begin from the graph. */ nonTrappingContinuation.replaceAtUsages(InputType.Guard, trappingNullCheck); - FixedNode next = nonTrappingContinuation.next(); - nonTrappingContinuation.clearSuccessors(); - trappingNullCheck.setNext(next); - nonTrappingContinuation.safeDelete(); + if (nonTrappingContinuation.getNodeClass().is(BeginNode.class)) { + FixedNode next = nonTrappingContinuation.next(); + nonTrappingContinuation.clearSuccessors(); + trappingNullCheck.setNext(next); + nonTrappingContinuation.safeDelete(); + } else { + trappingNullCheck.setNext(nonTrappingContinuation); + } GraphUtil.killCFG(trappingContinuation); if (isNullNode.usages().isEmpty()) { diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java Tue Sep 09 14:31:36 2014 -0700 @@ -22,24 +22,23 @@ */ package com.oracle.graal.phases.common.cfs; +import static com.oracle.graal.api.meta.DeoptimizationAction.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; + +import java.lang.reflect.*; + import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Node; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.FloatingNode; -import com.oracle.graal.nodes.calc.IsNullNode; -import com.oracle.graal.nodes.extended.LoadHubNode; -import com.oracle.graal.nodes.extended.NullCheckNode; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.compiler.common.type.IllegalStamp; -import com.oracle.graal.nodes.type.StampTool; -import com.oracle.graal.nodes.util.GraphUtil; -import com.oracle.graal.phases.common.DeadCodeEliminationPhase; -import com.oracle.graal.phases.tiers.PhaseContext; - -import java.lang.reflect.Modifier; - -import static com.oracle.graal.api.meta.DeoptimizationAction.InvalidateReprofile; -import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; /** *

@@ -152,7 +151,7 @@ for (PostponedDeopt postponed : postponedDeopts) { postponed.doRewrite(falseConstant); } - new DeadCodeEliminationPhase().apply(graph); + new DeadCodeEliminationPhase(OPTIONAL).apply(graph); } for (MethodCallTargetNode mcn : graph.getNodes().filter(MethodCallTargetNode.class)) { if (mcn.isAlive() && FlowUtil.lacksUsages(mcn)) { diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java Tue Sep 09 14:31:36 2014 -0700 @@ -37,7 +37,7 @@ } public static boolean lacksUsages(Node n) { - return n.recordsUsages() && n.usages().isEmpty(); + return n.usages().isEmpty(); } public static ResolvedJavaType widen(ResolvedJavaType a, ResolvedJavaType b) { @@ -95,11 +95,11 @@ } else { /* * Not comparable, two cases: - * + * * Example 1: 'a' standing for j.l.Number and 'b' for j.l.String We return null for lack * of a value representing NullType, the right answer. Same goes when both arguments are * non-comparable interfaces. - * + * * Example 2: 'a' standing for sun/nio/ch/DirectBuffer (an interface) and b for * java/nio/Buffer (an abstract class). The class always takes precedence. */ diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java Tue Sep 09 14:31:36 2014 -0700 @@ -45,4 +45,6 @@ int getNodeCount(); Iterable getInvokes(); + + double getProbability(Invoke invoke); } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java Tue Sep 09 14:31:36 2014 -0700 @@ -22,21 +22,21 @@ */ package com.oracle.graal.phases.common.inlining.info.elem; +import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; + import java.util.*; -import com.oracle.graal.api.meta.Constant; -import com.oracle.graal.api.meta.ResolvedJavaMethod; -import com.oracle.graal.compiler.common.type.Stamp; -import com.oracle.graal.debug.Debug; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.common.CanonicalizerPhase; -import com.oracle.graal.phases.common.DeadCodeEliminationPhase; -import com.oracle.graal.phases.common.cfs.FlowUtil; -import com.oracle.graal.phases.common.inlining.InliningUtil; -import com.oracle.graal.phases.tiers.HighTierContext; - -import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.common.cfs.*; +import com.oracle.graal.phases.common.inlining.*; +import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.tiers.*; /** *

@@ -56,6 +56,8 @@ private final StructuredGraph graph; + private FixedNodeProbabilityCache probabilites = new FixedNodeProbabilityCache(); + public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) { StructuredGraph original = getOriginalGraph(method, context, canonicalizer); // TODO copying the graph is only necessary if it is modified or if it contains any invokes @@ -245,7 +247,7 @@ } assert newGraph.start().next() != null : "graph needs to be populated by the GraphBuilderSuite"; - new DeadCodeEliminationPhase().apply(newGraph); + new DeadCodeEliminationPhase(OPTIONAL).apply(newGraph); if (OptCanonicalizer.getValue()) { canonicalizer.apply(newGraph, context); @@ -270,6 +272,11 @@ return graph.getInvokes(); } + @Override + public double getProbability(Invoke invoke) { + return probabilites.applyAsDouble(invoke.asNode()); + } + public StructuredGraph getGraph() { return graph; } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableMacroNode.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableMacroNode.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableMacroNode.java Tue Sep 09 14:31:36 2014 -0700 @@ -22,6 +22,7 @@ */ package com.oracle.graal.phases.common.inlining.info.elem; +import com.oracle.graal.compiler.common.*; import com.oracle.graal.nodes.FixedWithNextNode; import com.oracle.graal.nodes.Invoke; @@ -48,4 +49,8 @@ public Class getMacroNodeClass() { return macroNodeClass; } + + public double getProbability(Invoke invoke) { + throw GraalInternalError.shouldNotReachHere("No invokes in inlineable"); + } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java Tue Sep 09 14:31:36 2014 -0700 @@ -24,7 +24,6 @@ import com.oracle.graal.api.meta.ProfilingInfo; import com.oracle.graal.api.meta.ResolvedJavaMethod; -import com.oracle.graal.nodes.FixedNode; import com.oracle.graal.nodes.Invoke; import com.oracle.graal.nodes.StructuredGraph; import com.oracle.graal.nodes.spi.Replacements; @@ -33,7 +32,6 @@ import com.oracle.graal.phases.common.inlining.info.elem.Inlineable; import java.util.Map; -import java.util.function.ToDoubleFunction; import static com.oracle.graal.compiler.common.GraalOptions.RelevanceCapForInlining; import static com.oracle.graal.phases.common.inlining.InliningPhase.Options.AlwaysInlineIntrinsics; @@ -100,14 +98,14 @@ return size; } - protected static double determineInvokeProbability(ToDoubleFunction probabilities, InlineInfo info) { + protected static double determineInvokeProbability(InlineInfo info) { double invokeProbability = 0; for (int i = 0; i < info.numberOfMethods(); i++) { Inlineable callee = info.inlineableElementAt(i); Iterable invokes = callee.getInvokes(); if (invokes.iterator().hasNext()) { for (Invoke invoke : invokes) { - invokeProbability += probabilities.applyAsDouble(invoke.asNode()); + invokeProbability += callee.getProbability(invoke); } } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/GreedyInliningPolicy.java Tue Sep 09 14:31:36 2014 -0700 @@ -24,7 +24,6 @@ import com.oracle.graal.debug.Debug; import com.oracle.graal.debug.DebugMetric; -import com.oracle.graal.nodes.FixedNode; import com.oracle.graal.nodes.Invoke; import com.oracle.graal.nodes.StructuredGraph; import com.oracle.graal.nodes.spi.Replacements; @@ -33,7 +32,6 @@ import com.oracle.graal.phases.common.inlining.walker.MethodInvocation; import java.util.Map; -import java.util.function.ToDoubleFunction; import static com.oracle.graal.compiler.common.GraalOptions.*; @@ -55,7 +53,7 @@ } @Override - public boolean isWorthInlining(ToDoubleFunction probabilities, Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { + public boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { final InlineInfo info = invocation.callee(); final double probability = invocation.probability(); @@ -97,7 +95,7 @@ * inline those methods but increases bootstrap time (maybe those methods are also getting * queued in the compilation queue concurrently) */ - double invokes = determineInvokeProbability(probabilities, info); + double invokes = determineInvokeProbability(info); if (LimitInlinedInvokes.getValue() > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue() * inliningBonus) { InliningUtil.logNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes, relevance, probability, inliningBonus, nodes); diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineEverythingPolicy.java Tue Sep 09 14:31:36 2014 -0700 @@ -23,13 +23,10 @@ package com.oracle.graal.phases.common.inlining.policy; import com.oracle.graal.api.code.BailoutException; -import com.oracle.graal.nodes.FixedNode; import com.oracle.graal.nodes.StructuredGraph; import com.oracle.graal.nodes.spi.Replacements; import com.oracle.graal.phases.common.inlining.walker.MethodInvocation; -import java.util.function.ToDoubleFunction; - import static com.oracle.graal.compiler.common.GraalOptions.MaximumDesiredSize; public final class InlineEverythingPolicy implements InliningPolicy { @@ -41,7 +38,7 @@ return true; } - public boolean isWorthInlining(ToDoubleFunction probabilities, Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { + public boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed) { return true; } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InliningPolicy.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InliningPolicy.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InliningPolicy.java Tue Sep 09 14:31:36 2014 -0700 @@ -22,16 +22,13 @@ */ package com.oracle.graal.phases.common.inlining.policy; -import com.oracle.graal.nodes.FixedNode; import com.oracle.graal.nodes.StructuredGraph; import com.oracle.graal.nodes.spi.Replacements; import com.oracle.graal.phases.common.inlining.walker.MethodInvocation; -import java.util.function.ToDoubleFunction; - public interface InliningPolicy { boolean continueInlining(StructuredGraph graph); - boolean isWorthInlining(ToDoubleFunction probabilities, Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed); + boolean isWorthInlining(Replacements replacements, MethodInvocation invocation, int inliningDepth, boolean fullyProcessed); } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java Tue Sep 09 14:31:36 2014 -0700 @@ -46,12 +46,10 @@ import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph; import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode; import com.oracle.graal.phases.common.inlining.policy.InliningPolicy; -import com.oracle.graal.phases.graph.FixedNodeProbabilityCache; import com.oracle.graal.phases.tiers.HighTierContext; import com.oracle.graal.phases.util.Providers; import java.util.*; -import java.util.function.ToDoubleFunction; import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.phases.common.inlining.walker.CallsiteHolderDummy.DUMMY_CALLSITE_HOLDER; @@ -95,7 +93,6 @@ */ private final ArrayDeque graphQueue = new ArrayDeque<>(); private final ArrayDeque invocationQueue = new ArrayDeque<>(); - private final ToDoubleFunction probabilities = new FixedNodeProbabilityCache(); private final HighTierContext context; private final int maxMethodPerInlining; @@ -426,7 +423,7 @@ Assumptions callerAssumptions = parentInvocation.assumptions(); metricInliningConsidered.increment(); - if (inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), calleeInvocation, inliningDepth, true)) { + if (inliningPolicy.isWorthInlining(context.getReplacements(), calleeInvocation, inliningDepth, true)) { doInline(callerCallsiteHolder, calleeInvocation, callerAssumptions); return true; } @@ -683,7 +680,7 @@ final MethodInvocation currentInvocation = currentInvocation(); - final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), currentInvocation, inliningDepth(), false)); + final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(context.getReplacements(), currentInvocation, inliningDepth(), false)); if (backtrack) { int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs(); assert remainingGraphs > 0; diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java Tue Sep 09 14:31:36 2014 -0700 @@ -104,7 +104,11 @@ if (current instanceof MergeNode) { MergeNode currentMerge = (MergeNode) current; NodeInputList currentForwardEnds = currentMerge.forwardEnds(); - // Using simple iteration instead of lambda as the lambda blows up the stack + /* + * Use simple iteration instead of streams, since the stream infrastructure adds + * many frames which causes the recursion to overflow the stack earlier than it + * would otherwise. + */ for (AbstractEndNode endNode : currentForwardEnds) { probability += applyAsDouble(endNode); } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue Sep 09 14:31:36 2014 -0700 @@ -625,10 +625,8 @@ cdbc.apply(cfg.getNodeToBlock().get(succ)); } ensureScheduledUsages(node, strategy); - if (node.recordsUsages()) { - for (Node usage : node.usages()) { - blocksForUsage(node, usage, cdbc, strategy); - } + for (Node usage : node.usages()) { + blocksForUsage(node, usage, cdbc, strategy); } if (assertionEnabled()) { @@ -820,10 +818,8 @@ } private void ensureScheduledUsages(Node node, SchedulingStrategy strategy) { - if (node.recordsUsages()) { - for (Node usage : node.usages().filter(ScheduledNode.class)) { - assignBlockToNode((ScheduledNode) usage, strategy); - } + for (Node usage : node.usages().filter(ScheduledNode.class)) { + assignBlockToNode((ScheduledNode) usage, strategy); } // now true usages are ready } @@ -1149,16 +1145,14 @@ } visited.mark(instruction); - if (instruction.recordsUsages()) { - for (Node usage : instruction.usages()) { - if (usage instanceof VirtualState) { - // only fixed nodes can have VirtualState -> no need to schedule them + for (Node usage : instruction.usages()) { + if (usage instanceof VirtualState) { + // only fixed nodes can have VirtualState -> no need to schedule them + } else { + if (instruction instanceof LoopExitNode && usage instanceof ProxyNode) { + // value proxies should be scheduled before the loopexit, not after } else { - if (instruction instanceof LoopExitNode && usage instanceof ProxyNode) { - // value proxies should be scheduled before the loopexit, not after - } else { - addToEarliestSorting(b, (ScheduledNode) usage, sortedInstructions, visited); - } + addToEarliestSorting(b, (ScheduledNode) usage, sortedInstructions, visited); } } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Tue Sep 09 14:31:36 2014 -0700 @@ -33,6 +33,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; @@ -128,7 +129,8 @@ private void writeGraph(Graph graph, SchedulePhase predefinedSchedule) throws IOException { SchedulePhase schedule = predefinedSchedule; if (schedule == null) { - if (PrintIdealGraphSchedule.getValue()) { + // Also provide a schedule when an error occurs + if (PrintIdealGraphSchedule.getValue() || Debug.contextLookup(Throwable.class) != null) { try { schedule = new SchedulePhase(); schedule.apply((StructuredGraph) graph); diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java Tue Sep 09 14:31:36 2014 -0700 @@ -343,7 +343,7 @@ out.println("=== Succesors ==="); printNamedNodes(node, node.successors().iterator(), "", "\n", null); out.println("=== Usages ==="); - if (node.recordsUsages() && !node.usages().isEmpty()) { + if (!node.usages().isEmpty()) { for (Node usage : node.usages()) { out.print(nodeToString(usage)).print(" "); } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Tue Sep 09 14:31:36 2014 -0700 @@ -343,8 +343,7 @@ } public void cleanUpReturnCheckCast(Node newInstance) { - if (newInstance.recordsUsages() && newInstance instanceof ValueNode && - (((ValueNode) newInstance).getKind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) { + if (newInstance instanceof ValueNode && (((ValueNode) newInstance).getKind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) { StructuredGraph graph = (StructuredGraph) newInstance.graph(); for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) { for (Node checkCastUsage : checkCastNode.usages().snapshot()) { diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Tue Sep 09 14:31:36 2014 -0700 @@ -25,6 +25,7 @@ import static com.oracle.graal.api.meta.MetaUtil.*; import static com.oracle.graal.compiler.GraalCompiler.*; import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; import java.lang.reflect.*; import java.util.*; @@ -511,7 +512,7 @@ new CollapseFrameForSingleSideEffectPhase().apply(graph); break; } - new DeadCodeEliminationPhase().apply(graph); + new DeadCodeEliminationPhase(REQUIRED).apply(graph); } /** @@ -613,7 +614,7 @@ */ protected void afterInlining(StructuredGraph graph) { new NodeIntrinsificationPhase(providers, snippetReflection).apply(graph); - new DeadCodeEliminationPhase().apply(graph); + new DeadCodeEliminationPhase(OPTIONAL).apply(graph); if (OptCanonicalizer.getValue()) { new CanonicalizerPhase(true).apply(graph, new PhaseContext(providers, assumptions)); } @@ -686,7 +687,7 @@ end.disableSafepoint(); } - new DeadCodeEliminationPhase().apply(graph); + new DeadCodeEliminationPhase(REQUIRED).apply(graph); } catch (Throwable e) { throw Debug.handle(e); } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Tue Sep 09 14:31:36 2014 -0700 @@ -26,6 +26,7 @@ import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.debug.Debug.*; import static com.oracle.graal.graph.util.CollectionsAccess.*; +import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; import static com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates.*; import static java.util.FormattableFlags.*; @@ -670,7 +671,7 @@ } } - new DeadCodeEliminationPhase().apply(snippetCopy); + new DeadCodeEliminationPhase(REQUIRED).apply(snippetCopy); assert checkAllVarargPlaceholdersAreDeleted(parameterCount, placeholders); diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Tue Sep 09 14:31:36 2014 -0700 @@ -377,8 +377,8 @@ } @Override - public List getCallTargets() { - return new ArrayList<>(callTargets.keySet()); + public Collection getCallTargets() { + return Collections.unmodifiableSet(callTargets.keySet()); } public void notifyTransferToInterpreter() { diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Tue Sep 09 14:31:36 2014 -0700 @@ -206,13 +206,13 @@ @Override public void invalidate() { this.runtime.invalidateInstalledCode(this); - invalidateInlining(); } protected void invalidate(Node oldNode, Node newNode, CharSequence reason) { if (isValid()) { CompilerAsserts.neverPartOfCompilation(); invalidate(); + invalidateInlining(); compilationProfile.reportInvalidated(); logOptimizedInvalidated(this, oldNode, newNode, reason); } @@ -273,14 +273,15 @@ // Compilation was successful. } else { compilationPolicy.recordCompilationFailure(t); - logOptimizingFailed(this, t.getMessage()); if (t instanceof BailoutException) { + logOptimizingFailed(this, t.getMessage()); // Bailout => move on. - } else { - if (TruffleCompilationExceptionsAreFatal.getValue()) { - t.printStackTrace(OUT); - System.exit(-1); - } + } else if (TruffleCompilationExceptionsAreFatal.getValue()) { + logOptimizingFailed(this, t.getMessage()); + t.printStackTrace(OUT); + System.exit(-1); + } else if (TruffleCompilationExceptionsAreThrown.getValue()) { + throw new OptimizationFailedException(t, rootNode); } } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Tue Sep 09 14:31:36 2014 -0700 @@ -132,17 +132,27 @@ } HighTierContext tierContext = new HighTierContext(providers, assumptions, graphCache, new PhaseSuite(), OptimisticOptimizations.NONE); - for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) { - Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage()); - throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception); - } - // EA frame and clean up. try (Scope pe = Debug.scope("TrufflePartialEscape", graph)) { new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext); } catch (Throwable t) { Debug.handle(t); } + + // to make frame propagations visible retry expandTree + while (expandTree(graph, assumptions)) { + try (Scope pe = Debug.scope("TrufflePartialEscape", graph)) { + new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext); + } catch (Throwable t) { + Debug.handle(t); + } + } + + for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) { + Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage()); + throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception); + } + new VerifyNoIntrinsicsLeftPhase().apply(graph, false); for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) { materializeNode.replaceAtUsages(materializeNode.getFrame()); @@ -184,15 +194,16 @@ new DebugHistogramAsciiPrinter(TTY.out().out()).print(histogram); } - private void expandTree(StructuredGraph graph, Assumptions assumptions) { + private boolean expandTree(StructuredGraph graph, Assumptions assumptions) { PhaseContext phaseContext = new PhaseContext(providers, assumptions); TruffleExpansionLogger expansionLogger = null; if (TraceTruffleExpansion.getValue()) { expansionLogger = new TruffleExpansionLogger(providers, graph); } - boolean changed; + boolean changed = false; + boolean changedInIteration; do { - changed = false; + changedInIteration = false; for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class)) { InvokeKind kind = methodCallTargetNode.invokeKind(); try (Indent id1 = Debug.logAndIndent("try inlining %s, kind = %s", methodCallTargetNode.targetMethod(), kind)) { @@ -205,7 +216,7 @@ Class macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod()); if (macroSubstitution != null) { InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution); - changed = true; + changed = changedInIteration = true; continue; } @@ -215,7 +226,8 @@ } if (inlineGraph != null) { - changed = expandTreeInline(graph, phaseContext, expansionLogger, methodCallTargetNode, inlineGraph); + expandTreeInline(graph, phaseContext, expansionLogger, methodCallTargetNode, inlineGraph); + changed = changedInIteration = true; } } } @@ -224,14 +236,15 @@ throw new BailoutException("Truffle compilation is exceeding maximum node count: " + graph.getNodeCount()); } } - } while (changed); + } while (changedInIteration); if (TraceTruffleExpansion.getValue()) { expansionLogger.print(); } + return changed; } - private boolean expandTreeInline(StructuredGraph graph, PhaseContext phaseContext, TruffleExpansionLogger expansionLogger, MethodCallTargetNode methodCallTargetNode, StructuredGraph inlineGraph) { + private void expandTreeInline(StructuredGraph graph, PhaseContext phaseContext, TruffleExpansionLogger expansionLogger, MethodCallTargetNode methodCallTargetNode, StructuredGraph inlineGraph) { try (Indent indent = Debug.logAndIndent("inline graph %s", methodCallTargetNode.targetMethod())) { int nodeCountBefore = graph.getNodeCount(); if (TraceTruffleExpansion.getValue()) { @@ -248,8 +261,6 @@ } AbstractInlineInfo.getInlinedParameterUsages(canonicalizedNodes, inlineGraph, inlined); canonicalizer.applyIncremental(graph, phaseContext, canonicalizedNodes); - - return true; } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java Tue Sep 09 14:31:36 2014 -0700 @@ -243,7 +243,7 @@ Mark beforeInvokeMark = graph.getMark(); expandInvoke(methodCallTarget); for (Node arg : argumentSnapshot) { - if (arg != null && arg.recordsUsages()) { + if (arg != null) { for (Node argUsage : arg.usages()) { if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) { canonicalizerUsages.add(argUsage); diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Tue Sep 09 14:31:36 2014 -0700 @@ -116,6 +116,8 @@ @Option(help = "") public static final OptionValue TruffleCompilationExceptionsAreFatal = new OptionValue<>(false); @Option(help = "") + public static final OptionValue TruffleCompilationExceptionsAreThrown = new OptionValue<>(false); + @Option(help = "") public static final OptionValue TraceTruffleInlining = new OptionValue<>(false); @Option(help = "") public static final OptionValue TraceTruffleSplitting = new OptionValue<>(false); diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java Tue Sep 09 14:31:36 2014 -0700 @@ -23,6 +23,7 @@ package com.oracle.graal.virtual.phases.ea; import static com.oracle.graal.debug.Debug.*; +import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; import java.util.*; @@ -100,7 +101,7 @@ Debug.dump(graph, "after " + getName() + " iteration"); } - new DeadCodeEliminationPhase().apply(graph); + new DeadCodeEliminationPhase(REQUIRED).apply(graph); Set changedNodes = listener.getNodes(); for (Node node : graph.getNodes()) { diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Tue Sep 09 14:31:36 2014 -0700 @@ -24,6 +24,7 @@ import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.debug.Debug.*; +import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; import java.util.*; @@ -70,7 +71,7 @@ inlining.apply(graph, context); progress |= inlining.getInliningCount() > 0; - new DeadCodeEliminationPhase().apply(graph); + new DeadCodeEliminationPhase(OPTIONAL).apply(graph); boolean reduceOrEliminate = FlowSensitiveReduction.getValue() || ConditionalElimination.getValue(); if (reduceOrEliminate && OptCanonicalizer.getValue()) { diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java Tue Sep 09 14:31:36 2014 -0700 @@ -62,9 +62,6 @@ InferStamps.inferStamps(graph); for (ValueNode node : graph.getNodes().filter(ValueNode.class)) { - if (!node.recordsUsages()) { - continue; - } for (Node usage : node.usages()) { if (usage instanceof AccessMonitorNode) { verify(!isWord(node), node, usage, "word value has no monitor"); diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java Tue Sep 09 14:31:36 2014 -0700 @@ -86,7 +86,7 @@ public void testGetCallTargets1() { RootNode rootNode = createTestRootNode(); RootCallTarget target = runtime.createCallTarget(rootNode); - assertTrue(runtime.getCallTargets().indexOf(target) != -1); + assertTrue(runtime.getCallTargets().contains(target)); } @Test @@ -94,8 +94,8 @@ RootNode rootNode = createTestRootNode(); RootCallTarget target1 = runtime.createCallTarget(rootNode); RootCallTarget target2 = runtime.createCallTarget(rootNode); - assertTrue(runtime.getCallTargets().indexOf(target1) != -1); - assertTrue(runtime.getCallTargets().indexOf(target2) != -1); + assertTrue(runtime.getCallTargets().contains(target1)); + assertTrue(runtime.getCallTargets().contains(target2)); } /* diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/BytesSourceSectionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/BytesSourceSectionTest.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,81 @@ +/* + * 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.test.source; + +import static org.junit.Assert.*; + +import java.nio.charset.*; + +import org.junit.*; + +import com.oracle.truffle.api.source.*; + +public class BytesSourceSectionTest { + + @Test + public void testSectionsFromLineNumberASCII() { + final byte[] bytes = "foo\nbar\nbaz\n".getBytes(StandardCharsets.UTF_8); + final Source source = Source.fromBytes(bytes, "description", new BytesDecoder.UTF8BytesDecoder()); + assertEquals("foo", source.createSection("identifier", 1).getCode()); + assertEquals("bar", source.createSection("identifier", 2).getCode()); + assertEquals("baz", source.createSection("identifier", 3).getCode()); + } + + @Test + public void testSectionsFromOffsetsASCII() { + final byte[] bytes = "foo\nbar\nbaz\n".getBytes(StandardCharsets.UTF_8); + final Source source = Source.fromBytes(bytes, "description", new BytesDecoder.UTF8BytesDecoder()); + assertEquals("foo", source.createSection("identifier", 0, 3).getCode()); + assertEquals("bar", source.createSection("identifier", 4, 3).getCode()); + assertEquals("baz", source.createSection("identifier", 8, 3).getCode()); + } + + @Test + public void testSectionsFromLineNumberUTF8() { + // ☃ is three bytes in UTF8 + final byte[] bytes = "foo\n☃\nbaz\n".getBytes(StandardCharsets.UTF_8); + final Source source = Source.fromBytes(bytes, "description", new BytesDecoder.UTF8BytesDecoder()); + assertEquals("foo", source.createSection("identifier", 1).getCode()); + assertEquals("☃", source.createSection("identifier", 2).getCode()); + assertEquals("baz", source.createSection("identifier", 3).getCode()); + } + + @Test + public void testSectionsFromOffsetsUTF8() { + // ☃ is three bytes in UTF8 + final byte[] bytes = "foo\n☃\nbaz\n".getBytes(StandardCharsets.UTF_8); + final Source source = Source.fromBytes(bytes, "description", new BytesDecoder.UTF8BytesDecoder()); + assertEquals("foo", source.createSection("identifier", 0, 3).getCode()); + assertEquals("☃", source.createSection("identifier", 4, 3).getCode()); + assertEquals("baz", source.createSection("identifier", 8, 3).getCode()); + } + + @Test + public void testOffset() { + final byte[] bytes = "xxxfoo\nbar\nbaz\nxxx".getBytes(StandardCharsets.UTF_8); + final Source source = Source.fromBytes(bytes, 3, bytes.length - 6, "description", new BytesDecoder.UTF8BytesDecoder()); + assertEquals("foo", source.createSection("identifier", 0, 3).getCode()); + assertEquals("bar", source.createSection("identifier", 4, 3).getCode()); + assertEquals("baz", source.createSection("identifier", 8, 3).getCode()); + } +} diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/ExactClassValueProfileTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/ExactClassValueProfileTest.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test.utilities; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.junit.*; +import org.junit.experimental.theories.*; +import org.junit.runner.*; + +import com.oracle.truffle.api.utilities.*; + +@RunWith(Theories.class) +public class ExactClassValueProfileTest { + + @DataPoint public static final String O1 = new String(); + @DataPoint public static final String O2 = new String(); + @DataPoint public static final Object O3 = new Object(); + @DataPoint public static final Integer O4 = new Integer(1); + @DataPoint public static final Integer O5 = null; + + private ExactClassValueProfile profile; + + @Before + public void create() { + profile = (ExactClassValueProfile) ValueProfile.createClassProfile(); + } + + @Test + public void testInitial() { + assertThat(profile.isGeneric(), is(false)); + assertThat(profile.isUninitialized(), is(true)); + assertNull(profile.getCachedClass()); + profile.toString(); // test that it is not crashing + } + + @Theory + public void testProfileOne(Object value) { + Object result = profile.profile(value); + + assertThat(result, is(value)); + assertEquals(profile.getCachedClass(), expectedClass(value)); + assertThat(profile.isUninitialized(), is(false)); + profile.toString(); // test that it is not crashing + } + + @Theory + public void testProfileTwo(Object value0, Object value1) { + Object result0 = profile.profile(value0); + Object result1 = profile.profile(value1); + + assertThat(result0, is(value0)); + assertThat(result1, is(value1)); + + Object expectedClass = expectedClass(value0) == expectedClass(value1) ? expectedClass(value0) : Object.class; + + assertEquals(profile.getCachedClass(), expectedClass); + assertThat(profile.isUninitialized(), is(false)); + assertThat(profile.isGeneric(), is(expectedClass == Object.class)); + profile.toString(); // test that it is not crashing + } + + @Theory + public void testProfileThree(Object value0, Object value1, Object value2) { + Object result0 = profile.profile(value0); + Object result1 = profile.profile(value1); + Object result2 = profile.profile(value2); + + assertThat(result0, is(value0)); + assertThat(result1, is(value1)); + assertThat(result2, is(value2)); + + Object expectedClass = expectedClass(value0) == expectedClass(value1) && expectedClass(value1) == expectedClass(value2) ? expectedClass(value0) : Object.class; + + assertEquals(profile.getCachedClass(), expectedClass); + assertThat(profile.isUninitialized(), is(false)); + assertThat(profile.isGeneric(), is(expectedClass == Object.class)); + profile.toString(); // test that it is not crashing + } + + private static Class expectedClass(Object value) { + return value == null ? Object.class : value.getClass(); + } + +} diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/IdentityValueProfileTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/IdentityValueProfileTest.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test.utilities; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import org.junit.*; +import org.junit.experimental.theories.*; +import org.junit.runner.*; + +import com.oracle.truffle.api.utilities.*; + +@RunWith(Theories.class) +public class IdentityValueProfileTest { + + @DataPoint public static final String O1 = new String(); + @DataPoint public static final String O2 = O1; + @DataPoint public static final Object O3 = new Object(); + @DataPoint public static final Integer O4 = new Integer(1); + @DataPoint public static final Integer O5 = null; + + private IdentityValueProfile profile; + + @Before + public void create() { + profile = (IdentityValueProfile) ValueProfile.createIdentityProfile(); + } + + @Test + public void testInitial() { + assertThat(profile.isGeneric(), is(false)); + assertThat(profile.isUninitialized(), is(true)); + profile.toString(); // test that it is not crashing + } + + @Theory + public void testProfileOne(Object value) { + Object result = profile.profile(value); + + assertThat(result, is(value)); + assertEquals(profile.getCachedValue(), value); + assertThat(profile.isUninitialized(), is(false)); + profile.toString(); // test that it is not crashing + } + + @Theory + public void testProfileTwo(Object value0, Object value1) { + Object result0 = profile.profile(value0); + Object result1 = profile.profile(value1); + + assertThat(result0, is(value0)); + assertThat(result1, is(value1)); + + if (value0 == value1) { + assertThat(profile.getCachedValue(), is(value0)); + assertThat(profile.isGeneric(), is(false)); + } else { + assertThat(profile.isGeneric(), is(true)); + } + assertThat(profile.isUninitialized(), is(false)); + profile.toString(); // test that it is not crashing + } + + @Theory + public void testProfileThree(Object value0, Object value1, Object value2) { + Object result0 = profile.profile(value0); + Object result1 = profile.profile(value1); + Object result2 = profile.profile(value2); + + assertThat(result0, is(value0)); + assertThat(result1, is(value1)); + assertThat(result2, is(value2)); + + if (value0 == value1 && value1 == value2) { + assertThat(profile.getCachedValue(), is(value0)); + assertThat(profile.isGeneric(), is(false)); + } else { + assertThat(profile.isGeneric(), is(true)); + } + assertThat(profile.isUninitialized(), is(false)); + profile.toString(); // test that it is not crashing + } +} diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/NeverValidAssumptionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/utilities/NeverValidAssumptionTest.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.test.utilities; + +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.utilities.*; + +public class NeverValidAssumptionTest { + + @Test + public void testCheck() { + final NeverValidAssumption assumption = NeverValidAssumption.INSTANCE; + + try { + assumption.check(); + fail(); + } catch (InvalidAssumptionException e) { + } catch (Exception e) { + fail(); + } + } + + @Test + public void testIsValid() { + final NeverValidAssumption assumption = NeverValidAssumption.INSTANCE; + assertFalse(assumption.isValid()); + } + + @Test(expected = UnsupportedOperationException.class) + public void testCannotInvalidate() { + final NeverValidAssumption assumption = NeverValidAssumption.INSTANCE; + assumption.invalidate(); + } + +} diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/OptimizationFailedException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/OptimizationFailedException.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api; + +import com.oracle.truffle.api.nodes.*; + +public class OptimizationFailedException extends RuntimeException { + + private final RootNode rootNode; + + public OptimizationFailedException(Throwable cause, RootNode rootNode) { + super(cause); + this.rootNode = rootNode; + } + + public RootNode getRootNode() { + return rootNode; + } + + private static final long serialVersionUID = -8797188744430210785L; + +} diff -r 82b5a7250a0d -r 4faf9bdb9973 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 Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Tue Sep 09 14:31:36 2014 -0700 @@ -142,7 +142,7 @@ * Returns a list of all still referenced {@link RootCallTarget} instances that were created * using {@link #createCallTarget(RootNode)}. */ - List getCallTargets(); + Collection getCallTargets(); /** * Internal API method. Do not use. diff -r 82b5a7250a0d -r 4faf9bdb9973 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 Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java Tue Sep 09 14:31:36 2014 -0700 @@ -135,8 +135,8 @@ } @Override - public List getCallTargets() { - return new ArrayList<>(callTargets.keySet()); + public Collection getCallTargets() { + return Collections.unmodifiableSet(callTargets.keySet()); } @Override diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToProbeCollectionMap.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToProbeCollectionMap.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToProbeCollectionMap.java Tue Sep 09 14:31:36 2014 -0700 @@ -145,4 +145,19 @@ return probes; } + + public void forget(Source source) { + final Set mappedLines = lineToProbesMap.keySet(); + if (mappedLines.size() > 0) { + List forgetLines = new ArrayList<>(); + for (LineLocation line : mappedLines) { + if (line.getSource().equals(source)) { + forgetLines.add(line); + } + } + for (LineLocation line : forgetLines) { + lineToProbesMap.remove(line); + } + } + } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/script/TruffleScriptEngineFactory.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/script/TruffleScriptEngineFactory.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/script/TruffleScriptEngineFactory.java Tue Sep 09 14:31:36 2014 -0700 @@ -38,7 +38,7 @@ * * @param engine a just-created engine */ - protected void engineCreated(ScriptEngine engine) { + protected final void engineCreated(ScriptEngine engine) { } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/BytesDecoder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/BytesDecoder.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.source; + +import java.nio.charset.*; +import java.util.*; + +/** + * For a language where strings do not map into Java strings, provides utilities to find line + * endings and to decode raw bytes into an approximate representation for tools to display. + *

+ * See {@link Source#fromBytes}. + */ +public interface BytesDecoder { + + String decode(byte[] bytes, int byteIndex, int length); + + void decodeLines(byte[] bytes, int byteIndex, int length, LineMarker lineMarker); + + public interface LineMarker { + + void markLine(int index); + + } + + public static class UTF8BytesDecoder implements BytesDecoder { + + @Override + public String decode(byte[] bytes, int byteIndex, int length) { + return new String(Arrays.copyOfRange(bytes, byteIndex, byteIndex + length), StandardCharsets.UTF_8); + } + + @Override + public void decodeLines(byte[] bytes, int byteIndex, int length, LineMarker lineMarker) { + for (int n = byteIndex; n < byteIndex + length; n++) { + if (bytes[n] == '\n') { + lineMarker.markLine(n + 1); + } + } + } + + } + +} diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Tue Sep 09 14:31:36 2014 -0700 @@ -158,6 +158,37 @@ } /** + * Creates a source from raw bytes. This can be used if the encoding of strings in your language + * is not compatible with Java strings, or if your parser returns byte indices instead of + * character indices. The returned source is then indexed by byte, not by character. + * + * @param bytes the raw bytes of the source + * @param description a note about the origin, possibly useful for debugging + * @param decoder how to decode the bytes into Java strings + * @return a newly created, non-indexed source representation + */ + public static Source fromBytes(byte[] bytes, String description, BytesDecoder decoder) { + return fromBytes(bytes, 0, bytes.length, description, decoder); + } + + /** + * Creates a source from raw bytes. This can be used if the encoding of strings in your language + * is not compatible with Java strings, or if your parser returns byte indices instead of + * character indices. The returned source is then indexed by byte, not by character. Offsets are + * relative to byteIndex. + * + * @param bytes the raw bytes of the source + * @param byteIndex where the string starts in the byte array + * @param length the length of the string in the byte array + * @param description a note about the origin, possibly useful for debugging + * @param decoder how to decode the bytes into Java strings + * @return a newly created, non-indexed source representation + */ + public static Source fromBytes(byte[] bytes, int byteIndex, int length, String description, BytesDecoder decoder) { + return new BytesSource(description, bytes, byteIndex, length, decoder); + } + + /** * Creates a source from literal text, but which acts as a file and can be retrieved by name * (unlike other literal sources); intended for testing. * @@ -246,6 +277,10 @@ */ public abstract String getCode(); + public String getCode(int charIndex, int charLength) { + return getCode().substring(charIndex, charIndex + charLength); + } + /** * Gets the text (not including a possible terminating newline) in a (1-based) numbered line. */ @@ -368,10 +403,7 @@ * @throws IllegalStateException if the source is one of the "null" instances */ public final SourceSection createSection(String identifier, int charIndex, int length) throws IllegalArgumentException { - final int codeLength = getCode().length(); - if (!(charIndex >= 0 && length >= 0 && charIndex + length <= codeLength)) { - throw new IllegalArgumentException("text positions out of range"); - } + checkRange(charIndex, length); checkTextMap(); final int startLine = getLineNumber(charIndex); final int startColumn = charIndex - getLineStartOffset(startLine) + 1; @@ -379,6 +411,12 @@ return new DefaultSourceSection(this, identifier, startLine, startColumn, charIndex, length); } + protected void checkRange(int charIndex, int length) { + if (!(charIndex >= 0 && length >= 0 && charIndex + length <= getCode().length())) { + throw new IllegalArgumentException("text positions out of range"); + } + } + /** * Creates a representation of a line of text in the source identified only by line number, from * which the character information will be computed. @@ -409,15 +447,19 @@ private TextMap checkTextMap() { if (textMap == null) { - final String code = getCode(); - if (code == null) { - throw new RuntimeException("can't read file " + getName()); - } - textMap = new TextMap(code); + textMap = createTextMap(); } return textMap; } + protected TextMap createTextMap() { + final String code = getCode(); + if (code == null) { + throw new RuntimeException("can't read file " + getName()); + } + return TextMap.fromString(code); + } + private static final class LiteralSource extends Source { private final String name; // Name used originally to describe the source @@ -621,6 +663,74 @@ } + private static final class BytesSource extends Source { + + private final String name; + private final byte[] bytes; + private final int byteIndex; + private final int length; + private final BytesDecoder decoder; + + public BytesSource(String name, byte[] bytes, int byteIndex, int length, BytesDecoder decoder) { + this.name = name; + this.bytes = bytes; + this.byteIndex = byteIndex; + this.length = length; + this.decoder = decoder; + } + + @Override + protected void reset() { + } + + @Override + public String getName() { + return name; + } + + @Override + public String getShortName() { + return name; + } + + @Override + public String getPath() { + return name; + } + + @Override + public URL getURL() { + return null; + } + + @Override + public Reader getReader() { + return null; + } + + @Override + public String getCode() { + return decoder.decode(bytes, byteIndex, length); + } + + @Override + public String getCode(int byteOffset, int codeLength) { + return decoder.decode(bytes, byteIndex + byteOffset, codeLength); + } + + @Override + protected void checkRange(int charIndex, int rangeLength) { + if (!(charIndex >= 0 && rangeLength >= 0 && charIndex + rangeLength <= length)) { + throw new IllegalArgumentException("text positions out of range"); + } + } + + @Override + protected TextMap createTextMap() { + return TextMap.fromBytes(bytes, byteIndex, length, decoder); + } + } + private static final class DefaultSourceSection implements SourceSection { private final Source source; @@ -704,7 +814,7 @@ @Override public final String getCode() { - return getSource().getCode().substring(charIndex, charIndex + charLength); + return getSource().getCode(charIndex, charLength); } @Override @@ -866,12 +976,18 @@ // Is the final text character a newline? final boolean finalNL; + public TextMap(int[] nlOffsets, int textLength, boolean finalNL) { + this.nlOffsets = nlOffsets; + this.textLength = textLength; + this.finalNL = finalNL; + } + /** * Constructs map permitting translation between 0-based character offsets and 1-based * lines/columns. */ - public TextMap(String text) { - this.textLength = text.length(); + public static TextMap fromString(String text) { + final int textLength = text.length(); final ArrayList lines = new ArrayList<>(); lines.add(0); int offset = 0; @@ -887,12 +1003,37 @@ } lines.add(Integer.MAX_VALUE); - nlOffsets = new int[lines.size()]; + final int[] nlOffsets = new int[lines.size()]; for (int line = 0; line < lines.size(); line++) { nlOffsets[line] = lines.get(line); } - finalNL = textLength > 0 && (textLength == nlOffsets[nlOffsets.length - 2]); + final boolean finalNL = textLength > 0 && (textLength == nlOffsets[nlOffsets.length - 2]); + + return new TextMap(nlOffsets, textLength, finalNL); + } + + public static TextMap fromBytes(byte[] bytes, int byteIndex, int length, BytesDecoder bytesDecoder) { + final ArrayList lines = new ArrayList<>(); + lines.add(0); + + bytesDecoder.decodeLines(bytes, byteIndex, length, new BytesDecoder.LineMarker() { + + public void markLine(int index) { + lines.add(index); + } + }); + + lines.add(Integer.MAX_VALUE); + + final int[] nlOffsets = new int[lines.size()]; + for (int line = 0; line < lines.size(); line++) { + nlOffsets[line] = lines.get(line); + } + + final boolean finalNL = length > 0 && (length == nlOffsets[nlOffsets.length - 2]); + + return new TextMap(nlOffsets, length, finalNL); } /** diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/AssumedValue.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/AssumedValue.java Tue Sep 09 12:22:48 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/AssumedValue.java Tue Sep 09 14:31:36 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,12 +35,19 @@ */ public class AssumedValue { + private final String name; + @CompilationFinal private T value; - private final CyclicAssumption assumption; + @CompilationFinal private Assumption assumption; + + public AssumedValue(T initialValue) { + this(null, initialValue); + } public AssumedValue(String name, T initialValue) { - assumption = new CyclicAssumption(name); + this.name = name; value = initialValue; + assumption = Truffle.getRuntime().createAssumption(name); } /** @@ -49,9 +56,9 @@ */ public T get() { try { - assumption.getAssumption().check(); + assumption.check(); } catch (InvalidAssumptionException e) { - // No need to rewrite anything - just pick up the new value + // No need to rewrite anything - just pick up the new values } return value; @@ -61,8 +68,12 @@ * Set a new value, which will be picked up the next time {@link #get} is called. */ public void set(T newValue) { + CompilerDirectives.transferToInterpreter(); + value = newValue; - assumption.invalidate(); + final Assumption oldAssumption = assumption; + assumption = Truffle.getRuntime().createAssumption(name); + oldAssumption.invalidate(); } } diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ExactClassValueProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ExactClassValueProfile.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.utilities; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; + +/** + * Represents a {@link ValueProfile} that speculates on the exact class of a value. + */ +public final class ExactClassValueProfile extends ValueProfile { + + @CompilationFinal protected Class cachedClass; + + ExactClassValueProfile() { + } + + @SuppressWarnings("unchecked") + @Override + public T profile(T value) { + if (cachedClass != null && cachedClass.isInstance(value)) { + return (T) cachedClass.cast(value); + } else { + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (cachedClass == null && value != null) { + cachedClass = value.getClass(); + } else { + cachedClass = Object.class; + } + } + return value; + } + + public boolean isGeneric() { + return cachedClass == Object.class; + } + + public boolean isUninitialized() { + return cachedClass == null; + } + + public Class getCachedClass() { + return cachedClass; + } + + @Override + public String toString() { + return String.format("%s(%s)@%x", getClass().getSimpleName(), isUninitialized() ? "uninitialized" : (isGeneric() ? "generic" : cachedClass.getName()), hashCode()); + } +} diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/IdentityValueProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/IdentityValueProfile.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.utilities; + +import java.util.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; + +/** + * Represents a {@link ValueProfile} that speculates on the object identity of a value. + */ +public final class IdentityValueProfile extends ValueProfile { + + private static final Object UNINITIALIZED = new Object(); + private static final Object GENERIC = new Object(); + + @CompilationFinal protected Object cachedValue = UNINITIALIZED; + + IdentityValueProfile() { + } + + @Override + @SuppressWarnings("unchecked") + public T profile(T value) { + if (cachedValue != GENERIC) { + if (cachedValue == value) { + return (T) cachedValue; + } else { + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (cachedValue == UNINITIALIZED) { + cachedValue = value; + } else { + cachedValue = GENERIC; + } + } + } + return value; + } + + public boolean isGeneric() { + return getCachedValue() == GENERIC; + } + + public boolean isUninitialized() { + return getCachedValue() == UNINITIALIZED; + } + + public Object getCachedValue() { + return cachedValue; + } + + @Override + public String toString() { + return String.format("%s(%s)@%x", getClass().getSimpleName(), isUninitialized() ? "uninitialized" : (isGeneric() ? "generic" : String.format("@%x", Objects.hash(cachedValue))), hashCode()); + } + +} diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/NeverValidAssumption.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/NeverValidAssumption.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,61 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.utilities; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.nodes.*; + +/** + * An assumption that is never valid. Used as a placeholder where an assumption is needed that + * should be invalid from the start. + */ +public final class NeverValidAssumption implements Assumption { + + public static final NeverValidAssumption INSTANCE = new NeverValidAssumption(); + + private NeverValidAssumption() { + } + + @Override + public void check() throws InvalidAssumptionException { + throw new InvalidAssumptionException(); + } + + @Override + public void invalidate() { + throw new UnsupportedOperationException("Cannot invalidate this assumption - it is never valid"); + } + + @Override + public String getName() { + return getClass().getName(); + } + + @Override + public boolean isValid() { + return false; + } + +} diff -r 82b5a7250a0d -r 4faf9bdb9973 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java Tue Sep 09 14:31:36 2014 -0700 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.utilities; + +/** + * Utility class to speculate on certain properties of values. + * + * Example usage: + * + *

+ * private final ValueProfile classProfile = ValueProfile.createClassProfile();
+ *
+ * return classProfile.profile(value);
+ * 
+ * + * All instances of {@code ValueProfile} (and subclasses) must be held in {@code final} fields for + * compiler optimizations to take effect. + * + * @see #createIdentityProfile() + * @see #createClassProfile() + */ +public abstract class ValueProfile { + + public abstract T profile(T value); + + /** + * Returns a {@link ValueProfile} that speculates on the exact class of a value. + */ + public static ValueProfile createClassProfile() { + return new ExactClassValueProfile(); + } + + /** + * Returns a {@link ValueProfile} that speculates on the object identity of a value. + */ + public static ValueProfile createIdentityProfile() { + return new IdentityValueProfile(); + } + +} diff -r 82b5a7250a0d -r 4faf9bdb9973 mx/mx_graal.py --- a/mx/mx_graal.py Tue Sep 09 12:22:48 2014 -0700 +++ b/mx/mx_graal.py Tue Sep 09 14:31:36 2014 -0700 @@ -378,7 +378,9 @@ def _jdksDir(): return os.path.abspath(join(_installed_jdks if _installed_jdks else _graal_home, 'jdk' + str(mx.java().version))) -def _handle_missing_VM(bld, vm): +def _handle_missing_VM(bld, vm=None): + if not vm: + vm = _get_vm() mx.log('The ' + bld + ' ' + vm + ' VM has not been created') if sys.stdout.isatty(): if mx.ask_yes_no('Build it now', 'y'): @@ -387,10 +389,12 @@ return mx.abort('You need to run "mx --vm ' + vm + ' --vmbuild ' + bld + ' build" to build the selected VM') -def _jdk(build='product', vmToCheck=None, create=False, installJars=True): +def _jdk(build=None, vmToCheck=None, create=False, installJars=True): """ Get the JDK into which Graal is installed, creating it first if necessary. """ + if not build: + build = _vmbuild if _vmSourcesAvailable else 'product' jdk = join(_jdksDir(), build) if create: srcJdk = mx.java().jdk @@ -462,7 +466,7 @@ if not exists(jdk): if _installed_jdks: mx.log("The selected JDK directory does not (yet) exist: " + jdk) - _handle_missing_VM(build, vmToCheck if vmToCheck else 'graal') + _handle_missing_VM(build, vmToCheck) if installJars: for jdkDist in _jdkDeployedDists: @@ -655,8 +659,7 @@ def jdkhome(vm=None): """return the JDK directory selected for the 'vm' command""" - build = _vmbuild if _vmSourcesAvailable else 'product' - return _jdk(build, installJars=False) + return _jdk(installJars=False) def print_jdkhome(args, vm=None): """print the JDK directory selected for the 'vm' command""" @@ -975,7 +978,7 @@ elif _vm_cwd is not None and _vm_cwd != cwd: mx.abort("conflicting working directories: do not set --vmcwd for this command") - build = vmbuild if vmbuild is not None else _vmbuild if _vmSourcesAvailable else 'product' + build = vmbuild if vmbuild else _vmbuild if _vmSourcesAvailable else 'product' jdk = _jdk(build, vmToCheck=vm, installJars=False) _updateInstalledGraalOptionsFile(jdk) mx.expand_project_in_args(args) @@ -1331,6 +1334,41 @@ mx.abort(codeOrMessage) return self +def ctw(args): + """run CompileTheWorld""" + from sanitycheck import CTWMode + modes = { + 'noinline' : CTWMode.NoInline, + 'nocomplex' : CTWMode.NoComplex, + 'full' : CTWMode.Full + } + mode = sanitycheck.CTWMode.NoInline + vmargs = [] + for a in args: + m = modes.get(a, None) + if m: + mode = m + else: + vmargs.append(a) + + jdk = _jdk(installJars=False) + rtjar = join(jdk, 'jre', 'lib', 'rt.jar') + + vm_ = _get_vm() + + args = vmargs + ['-XX:+CompileTheWorld', '-Xbootclasspath/p:' + rtjar] + if vm_ == 'graal': + args += ['-XX:+BootstrapGraal'] + if mode >= CTWMode.NoInline: + if not isGraalEnabled(vm_): + args.append('-XX:-Inline') + else: + args.append('-G:-Inline') + if mode >= CTWMode.NoComplex: + if isGraalEnabled(vm_): + args += ['-G:-OptLoopTransform', '-G:-OptTailDuplication', '-G:-FullUnroll', '-G:-MemoryAwareScheduling', '-G:-NewMemoryAwareScheduling', '-G:-PartialEscapeAnalysis'] + vm(args) + def _basic_gate_body(args, tasks): t = Task('BuildHotSpotGraal: fastdebug,product') buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product']) @@ -2248,6 +2286,7 @@ 'c1visualizer' : [c1visualizer, ''], 'checkheaders': [checkheaders, ''], 'clean': [clean, ''], + 'ctw': [ctw, '[-vmoptions|noinline|nocomplex|full]'], 'findbugs': [findbugs, ''], 'generateZshCompletion' : [generateZshCompletion, ''], 'hsdis': [hsdis, '[att]'], diff -r 82b5a7250a0d -r 4faf9bdb9973 mx/projects --- a/mx/projects Tue Sep 09 12:22:48 2014 -0700 +++ b/mx/projects Tue Sep 09 14:31:36 2014 -0700 @@ -103,6 +103,7 @@ distribution@TRUFFLE@path=build/truffle.jar distribution@TRUFFLE@subDir=graal distribution@TRUFFLE@sourcesPath=build/truffle.src.zip +distribution@TRUFFLE@javaCompliance=1.7 distribution@TRUFFLE@dependencies=\ com.oracle.truffle.api.dsl,\ com.oracle.nfi @@ -119,6 +120,7 @@ distribution@TRUFFLE-DSL-PROCESSOR@path=build/truffle-dsl-processor.jar distribution@TRUFFLE-DSL-PROCESSOR@subDir=graal distribution@TRUFFLE-DSL-PROCESSOR@sourcesPath=build/truffle-dsl-processor.src.zip +distribution@TRUFFLE-DSL-PROCESSOR@javaCompliance=1.7 distribution@TRUFFLE-DSL-PROCESSOR@dependencies=\ com.oracle.truffle.dsl.processor distribution@TRUFFLE-DSL-PROCESSOR@distDependencies=TRUFFLE diff -r 82b5a7250a0d -r 4faf9bdb9973 mxtool/mx.py --- a/mxtool/mx.py Tue Sep 09 12:22:48 2014 -0700 +++ b/mxtool/mx.py Tue Sep 09 14:31:36 2014 -0700 @@ -64,7 +64,7 @@ A distribution is a jar or zip file containing the output from one or more Java projects. """ class Distribution: - def __init__(self, suite, name, path, sourcesPath, deps, mainClass, excludedDependencies, distDependencies): + def __init__(self, suite, name, path, sourcesPath, deps, mainClass, excludedDependencies, distDependencies, javaCompliance): self.suite = suite self.name = name self.path = path.replace('/', os.sep) @@ -75,6 +75,7 @@ self.mainClass = mainClass self.excludedDependencies = excludedDependencies self.distDependencies = distDependencies + self.javaCompliance = JavaCompliance(javaCompliance) if javaCompliance else None def sorted_deps(self, includeLibs=False, transitive=False): deps = [] @@ -169,6 +170,10 @@ if isCoveredByDependecy: continue + if self.javaCompliance: + if p.javaCompliance > self.javaCompliance: + abort("Compliance level doesn't match: Distribution {0} requires {1}, but {2} is {3}.".format(self.name, self.javaCompliance, p.name, p.javaCompliance)) + # skip a Java project if its Java compliance level is "higher" than the configured JDK jdk = java(p.javaCompliance) assert jdk @@ -930,7 +935,8 @@ mainClass = attrs.pop('mainClass', None) exclDeps = pop_list(attrs, 'exclude') distDeps = pop_list(attrs, 'distDependencies') - d = Distribution(self, name, path, sourcesPath, deps, mainClass, exclDeps, distDeps) + javaCompliance = attrs.pop('javaCompliance', None) + d = Distribution(self, name, path, sourcesPath, deps, mainClass, exclDeps, distDeps, javaCompliance) d.__dict__.update(attrs) self.dists.append(d) @@ -955,7 +961,8 @@ mainClass = None exclDeps = [] distDeps = [] - d = Distribution(self, dname, path, sourcesPath, deps, mainClass, exclDeps, distDeps) + javaCompliance = None + d = Distribution(self, dname, path, sourcesPath, deps, mainClass, exclDeps, distDeps, javaCompliance) d.subDir = os.path.relpath(os.path.dirname(p.dir), self.dir) self.dists.append(d) p.definedAnnotationProcessors = annotationProcessors @@ -2445,11 +2452,11 @@ if p.definedAnnotationProcessorsDist: updatedAnnotationProcessorDists.add(p.definedAnnotationProcessorsDist) + tasks[p.name] = task if args.parallelize: # Best to initialize class paths on main process jdk.bootclasspath() task.proc = None - tasks[p.name] = task else: task.execute() @@ -3107,11 +3114,12 @@ if config.exists(): os.unlink(config.path) - if args.dist: - for d in _dists.keys(): - log('Removing distribution {0}...'.format(d)) - _rmIfExists(distribution(d).path) - _rmIfExists(distribution(d).sourcesPath) + if args.java: + if args.dist: + for d in _dists.keys(): + log('Removing distribution {0}...'.format(d)) + _rmIfExists(distribution(d).path) + _rmIfExists(distribution(d).sourcesPath) if suppliedParser: return args @@ -3970,14 +3978,14 @@ out.open('source-roots') out.element('root', {'id' : 'src.dir'}) if len(p.annotation_processors()) > 0: - out.element('root', {'id' : 'src.ap-source-output.dir'}) + out.element('root', {'id' : 'src.ap-source-output.dir', 'name' : 'Generated Packages'}) out.close('source-roots') out.open('test-roots') out.close('test-roots') out.close('data') firstDep = True - for dep in p.all_deps([], True): + for dep in p.all_deps([], includeLibs=False, includeAnnotationProcessors=True): if dep == p: continue @@ -4012,7 +4020,10 @@ annotationProcessorSrcFolder = "" if len(p.annotation_processors()) > 0: annotationProcessorEnabled = "true" - annotationProcessorSrcFolder = "src.ap-source-output.dir=${build.generated.sources.dir}/ap-source-output" + genSrcDir = p.source_gen_dir() + if not exists(genSrcDir): + os.makedirs(genSrcDir) + annotationProcessorSrcFolder = "src.ap-source-output.dir=" + genSrcDir content = """ annotation.processing.enabled=""" + annotationProcessorEnabled + """ @@ -4025,7 +4036,6 @@ build.classes.excludes=**/*.java,**/*.form # This directory is removed when the project is cleaned: build.dir=bin -build.generated.dir=${build.dir}/generated build.generated.sources.dir=${build.dir}/generated-sources # Only compile against the classpath explicitly listed here: build.sysclasspath=ignore @@ -4046,7 +4056,7 @@ includes=** jar.compress=false # Space-separated list of extra javac options -javac.compilerargs= +javac.compilerargs=-XDignore.symbol.file javac.deprecation=false javac.source=""" + str(p.javaCompliance) + """ javac.target=""" + str(p.javaCompliance) + """ @@ -4090,13 +4100,11 @@ srcDir = join(p.dir, src) if not exists(srcDir): os.mkdir(srcDir) - ref = 'file.reference.' + p.name + '-' + src - print >> out, ref + '=' + src if mainSrc: - print >> out, 'src.dir=${' + ref + '}' + print >> out, 'src.dir=' + srcDir mainSrc = False else: - print >> out, 'src.' + src + '.dir=${' + ref + '}' + print >> out, 'src.' + src + '.dir=' + srcDir javacClasspath = [] @@ -4117,24 +4125,19 @@ if dep.isLibrary(): path = dep.get_path(resolve=True) - if path: - if os.sep == '\\': - path = path.replace('\\', '\\\\') - ref = 'file.reference.' + dep.name + '-bin' - print >> out, ref + '=' + path - libFiles.append(path) + libFiles.append(path) elif dep.isProject(): - n = dep.name.replace('.', '_') - relDepPath = os.path.relpath(dep.dir, p.dir).replace(os.sep, '/') - ref = 'reference.' + n + '.jar' - print >> out, 'project.' + n + '=' + relDepPath - print >> out, ref + '=${project.' + n + '}/dist/' + dep.name + '.jar' - - if not dep in annotationProcessorOnlyDeps: - javacClasspath.append('${' + ref + '}') - else: - annotationProcessorReferences.append('${' + ref + '}') + path = join(dep.dir, 'dist', dep.name + '.jar') + + if path: + if os.sep == '\\': + path = path.replace('\\', '\\\\') + + if not dep in annotationProcessorOnlyDeps: + javacClasspath.append(path) + else: + annotationProcessorReferences.append(path) print >> out, 'javac.classpath=\\\n ' + (os.pathsep + '\\\n ').join(javacClasspath) print >> out, 'javac.processorpath=' + (os.pathsep + '\\\n ').join(['${javac.classpath}'] + annotationProcessorReferences) @@ -4146,10 +4149,12 @@ if updated: log('If using NetBeans:') - log(' 1. Ensure that the following platform(s) are defined (Tools -> Java Platforms):') + # http://stackoverflow.com/questions/24720665/cant-resolve-jdk-internal-package + log(' 1. Edit etc/netbeans.conf in your NetBeans installation and modify netbeans_default_options variable to include "-J-DCachingArchiveProvider.disableCtSym=true"') + log(' 2. Ensure that the following platform(s) are defined (Tools -> Java Platforms):') for jdk in jdks: log(' JDK_' + str(jdk.version)) - log(' 2. Open/create a Project Group for the directory containing the projects (File -> Project Group -> New Group... -> Folder of Projects)') + log(' 3. Open/create a Project Group for the directory containing the projects (File -> Project Group -> New Group... -> Folder of Projects)') _zip_files(files, suite.dir, configZip.path) _zip_files(libFiles, suite.dir, configLibsZip) diff -r 82b5a7250a0d -r 4faf9bdb9973 src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Tue Sep 09 12:22:48 2014 -0700 +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Tue Sep 09 14:31:36 2014 -0700 @@ -516,10 +516,11 @@ const VMRegPair *regs, Label& skip_fixup); void gen_i2c_adapter(int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs); + // VMReg max_arg, + int comp_args_on_stack, // VMRegStackSlots + const BasicType *sig_bt, + const VMRegPair *regs, + int frame_extension_argument = -1); AdapterGenerator(MacroAssembler *_masm) : masm(_masm) {} }; @@ -763,12 +764,13 @@ __ bind(L_fail); } -void AdapterGenerator::gen_i2c_adapter( - int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs) { +void AdapterGenerator::gen_i2c_adapter(int total_args_passed, + // VMReg max_arg, + int comp_args_on_stack, // VMRegStackSlots + const BasicType *sig_bt, + const VMRegPair *regs, + int frame_extension_argument) { + assert(frame_extension_argument == -1, "unsupported"); // Generate an I2C adapter: adjust the I-frame to make space for the C-frame // layout. Lesp was saved by the calling I-frame and will be restored on @@ -1026,9 +1028,10 @@ int total_args_passed, int comp_args_on_stack, const BasicType *sig_bt, - const VMRegPair *regs) { + const VMRegPair *regs, + int frame_extension_arguments) { AdapterGenerator agen(masm); - agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs); + agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, frame_extension_arguments); } // --------------------------------------------------------------- diff -r 82b5a7250a0d -r 4faf9bdb9973 src/cpu/x86/vm/frame_x86.cpp --- a/src/cpu/x86/vm/frame_x86.cpp Tue Sep 09 12:22:48 2014 -0700 +++ b/src/cpu/x86/vm/frame_x86.cpp Tue Sep 09 14:31:36 2014 -0700 @@ -695,6 +695,13 @@ DESCRIBE_FP_OFFSET(interpreter_frame_locals); DESCRIBE_FP_OFFSET(interpreter_frame_bcx); DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp); + } else if (is_entry_frame()) { + // This could be more descriptive if we use the enum in + // stubGenerator to map to real names but it's most important to + // claim these frame slots so the error checking works. + for (int i = 0; i < entry_frame_after_call_words; i++) { + values.describe(frame_no, fp() - i, err_msg("call_stub word fp - %d", i)); + } } } #endif diff -r 82b5a7250a0d -r 4faf9bdb9973 src/cpu/x86/vm/sharedRuntime_x86_32.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Tue Sep 09 12:22:48 2014 -0700 +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Tue Sep 09 14:31:36 2014 -0700 @@ -712,10 +712,12 @@ } void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs + int frame_extension_argument) { + assert(frame_extension_arguments == -1, "unsupported"); // Note: rsi contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled diff -r 82b5a7250a0d -r 4faf9bdb9973 src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Tue Sep 09 12:22:48 2014 -0700 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Tue Sep 09 14:31:36 2014 -0700 @@ -643,10 +643,11 @@ } void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs, + int frame_extension_argument) { // Note: r13 contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled @@ -704,6 +705,42 @@ __ block_comment("} verify_i2ce "); } +#ifdef GRAAL + if (frame_extension_argument != -1) { + // The frame_extension_argument is an int that describes the + // expected amount of argument space in the caller frame. If that + // is greater than total_args_passed then enlarge the caller frame + // by that amount to ensure deopt works correctly. + assert(frame_extension_argument < total_args_passed, "out of range"); + assert(sig_bt[frame_extension_argument] == T_INT, "wrong signature"); + + Label done; + int i = frame_extension_argument; + int ld_off = (total_args_passed - i)*Interpreter::stackElementSize; + // Check if anything needs to be done. Too much space is ok. + __ movl(r13, Address(rsp, ld_off)); + __ cmpl(r13, total_args_passed); + __ jcc(Assembler::lessEqual, done); + // Save the old rsp for the copy code + __ movptr(r11, rsp); + // Enlarge the frame + __ subl(r13, total_args_passed); + __ shlq(r13, 3); + __ subptr(rsp, r13); + + // Now copy the arguments in reverse order so they don't get + // overwritten during the copy. + for (int i = total_args_passed - 1; i >= 0; i--) { + int ld_off = (total_args_passed - i) * Interpreter::stackElementSize; + __ movptr(r13, Address(r11, ld_off)); + __ movptr(Address(rsp, ld_off), r13); + } + __ bind(done); + } +#else + assert(frame_extension_argument == -1, "unsupported"); +#endif + // Must preserve original SP for loading incoming arguments because // we need to align the outgoing SP for compiled code. __ movptr(r11, rsp); diff -r 82b5a7250a0d -r 4faf9bdb9973 src/gpu/hsail/vm/gpu_hsail.cpp --- a/src/gpu/hsail/vm/gpu_hsail.cpp Tue Sep 09 12:22:48 2014 -0700 +++ b/src/gpu/hsail/vm/gpu_hsail.cpp Tue Sep 09 14:31:36 2014 -0700 @@ -249,6 +249,7 @@ int myActionReason = Deoptimization::make_trap_request(Deoptimization::trap_request_reason(pdeopt->reason()), Deoptimization::Action_none); javaArgs.push_int(myActionReason); javaArgs.push_oop((oop) NULL); + javaArgs.push_int(mh->size_of_parameters()); if (TraceGPUInteraction) { tty->print_cr("[HSAIL] Deoptimizing to host for workitem=%d (slot=%d) with deoptId=%d, frame=" INTPTR_FORMAT ", actionAndReason=%d", workitem, k, deoptId, hsailFrame, myActionReason); // show the $d registers or stack slots containing references diff -r 82b5a7250a0d -r 4faf9bdb9973 src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Tue Sep 09 12:22:48 2014 -0700 +++ b/src/share/vm/graal/graalCompiler.cpp Tue Sep 09 14:31:36 2014 -0700 @@ -63,7 +63,7 @@ CompilationPolicy::completed_vm_startup(); #ifndef PRODUCT - if (CompileTheWorld) { + if (CompileTheWorld && !BootstrapGraal) { compile_the_world(); } #endif @@ -113,6 +113,11 @@ tty->print_cr(" in %d ms (compiled %d methods)", os::javaTimeMillis() - start, _methodsCompiled); } _bootstrapping = false; +#ifndef PRODUCT + if (CompileTheWorld) { + compile_the_world(); + } +#endif } void GraalCompiler::compile_method(methodHandle method, int entry_bci, CompileTask* task) { diff -r 82b5a7250a0d -r 4faf9bdb9973 src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Tue Sep 09 12:22:48 2014 -0700 +++ b/src/share/vm/graal/graalRuntime.cpp Tue Sep 09 14:31:36 2014 -0700 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "asm/codeBuffer.hpp" #include "compiler/compileBroker.hpp" +#include "compiler/disassembler.hpp" #include "graal/graalRuntime.hpp" #include "graal/graalCompilerToVM.hpp" #include "graal/graalCompiler.hpp" @@ -56,7 +57,12 @@ graal_compute_offsets(); +#ifdef TARGET_ARCH_x86 +#ifdef _LP64 + // Only supported on x86_64 for now _external_deopt_i2c_entry = create_external_deopt_i2c(); +#endif +#endif // Ensure _non_oop_bits is initialized Universe::non_oop_word(); @@ -88,7 +94,7 @@ cb.insts()->initialize_shared_locs((relocInfo*)buffer_locs, sizeof(buffer_locs)/sizeof(relocInfo)); MacroAssembler masm(&cb); - int total_args_passed = 5; + int total_args_passed = 6; BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed); VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed); @@ -98,13 +104,19 @@ sig_bt[i++] = T_VOID; // long stakes 2 slots sig_bt[i++] = T_INT; sig_bt[i++] = T_OBJECT; + sig_bt[i++] = T_INT; // The number of actual arguments pass to the method. int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed, false); - SharedRuntime::gen_i2c_adapter(&masm, total_args_passed, comp_args_on_stack, sig_bt, regs); + SharedRuntime::gen_i2c_adapter(&masm, total_args_passed, comp_args_on_stack, sig_bt, regs, total_args_passed - 1); masm.flush(); - return AdapterBlob::create(&cb)->content_begin(); + AdapterBlob* adapter = AdapterBlob::create(&cb); + if (PrintAdapterHandlers) { + tty->print_cr("Decoding external_deopt_i2c"); + Disassembler::decode(adapter->code_begin(), adapter->code_end()); + } + return adapter->code_begin(); } BasicType GraalRuntime::kindToBasicType(jchar ch) { diff -r 82b5a7250a0d -r 4faf9bdb9973 src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Tue Sep 09 12:22:48 2014 -0700 +++ b/src/share/vm/graal/graalRuntime.hpp Tue Sep 09 14:31:36 2014 -0700 @@ -217,7 +217,10 @@ static BasicType kindToBasicType(jchar ch); static address create_external_deopt_i2c(); - static address get_external_deopt_i2c_entry() {return _external_deopt_i2c_entry;} + static address get_external_deopt_i2c_entry() { + guarantee(_external_deopt_i2c_entry != NULL, "unsupported"); + return _external_deopt_i2c_entry; + } // The following routines are all called from compiled Graal code diff -r 82b5a7250a0d -r 4faf9bdb9973 src/share/vm/runtime/sharedRuntime.hpp --- a/src/share/vm/runtime/sharedRuntime.hpp Tue Sep 09 12:22:48 2014 -0700 +++ b/src/share/vm/runtime/sharedRuntime.hpp Tue Sep 09 14:31:36 2014 -0700 @@ -405,7 +405,8 @@ int total_args_passed, int comp_args_on_stack, const BasicType *sig_bt, - const VMRegPair *regs); + const VMRegPair *regs, + int frame_extension_argument = -1); // OSR support