# HG changeset patch # User Roland Schatz # Date 1364484924 -3600 # Node ID a1a97de0dc9dcdd2b5d1f522038f9a31b58f0ae9 # Parent fc0d57b82c86aca329499a772ba58c24d20d70ce# Parent 8cb3984da2f8efcc403b5342f5f03cd2da2d3a06 Merge. diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Thu Mar 28 16:35:24 2013 +0100 @@ -120,9 +120,9 @@ PhasePlan phasePlan = getDefaultPhasePlan(); phasePlan.addPhase(PhasePosition.AFTER_PARSING, identifyBoxingPhase); identifyBoxingPhase.apply(graph); - Collection hints = new ArrayList<>(); + Map hints = new HashMap<>(); for (Invoke invoke : graph.getInvokes()) { - hints.add(invoke); + hints.put(invoke, 1000d); } Assumptions assumptions = new Assumptions(false); diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java Thu Mar 28 16:35:24 2013 +0100 @@ -83,9 +83,9 @@ phasePlan.addPhase(PhasePosition.AFTER_PARSING, identifyBoxingPhase); phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PhiStampPhase()); identifyBoxingPhase.apply(graph); - Collection hints = new ArrayList<>(); + Map hints = new HashMap<>(); for (Invoke invoke : graph.getInvokes()) { - hints.add(invoke); + hints.put(invoke, 1000d); } Assumptions assumptions = new Assumptions(false); diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java Thu Mar 28 16:35:24 2013 +0100 @@ -60,9 +60,9 @@ private void test(String snippet) { StructuredGraph graph = parseProfiled(snippet); - Collection hints = new ArrayList<>(); + Map hints = new HashMap<>(); for (Invoke invoke : graph.getInvokes()) { - hints.add(invoke); + hints.put(invoke, 1000d); } Assumptions assumptions = new Assumptions(false); new InliningPhase(runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java Thu Mar 28 16:35:24 2013 +0100 @@ -70,9 +70,9 @@ private void test(String snippet) { StructuredGraph graph = parse(snippet); - Collection hints = new ArrayList<>(); + Map hints = new HashMap<>(); for (Invoke invoke : graph.getInvokes()) { - hints.add(invoke); + hints.put(invoke, 1000d); } Assumptions assumptions = new Assumptions(false); diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java Thu Mar 28 16:35:24 2013 +0100 @@ -88,9 +88,9 @@ for (Node n : local.usages().filter(isNotA(FrameState.class)).snapshot()) { n.replaceFirstInput(local, constant); } - Collection hints = new ArrayList<>(); + Map hints = new HashMap<>(); for (Invoke invoke : graph.getInvokes()) { - hints.add(invoke); + hints.put(invoke, 1000d); } Assumptions assumptions = new Assumptions(false); new InliningPhase(runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Thu Mar 28 16:35:24 2013 +0100 @@ -23,6 +23,7 @@ package com.oracle.graal.compiler.test.ea; import junit.framework.*; +import junit.framework.Assert; import org.junit.Test; @@ -30,7 +31,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; @@ -183,12 +183,7 @@ @Test public void testInstanceOf() { - ReturnNode returnNode = testEscapeAnalysis("testInstanceOfSnippet", null, false); - ValueNode result = returnNode.result(); - Assert.assertTrue(result instanceof ConditionalNode); - ConditionalNode conditional = (ConditionalNode) result; - Assert.assertTrue(conditional.condition() instanceof LogicConstantNode); - Assert.assertEquals(true, ((LogicConstantNode) conditional.condition()).getValue()); + testEscapeAnalysis("testInstanceOfSnippet", Constant.forInt(1), false); } public boolean testInstanceOfSnippet() { diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java Thu Mar 28 16:35:24 2013 +0100 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.test.ea; + +import static org.junit.Assert.*; + +import java.util.concurrent.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.virtual.phases.ea.*; + +public class IterativeInliningTest extends GraalCompilerTest { + + private StructuredGraph graph; + + public static class TestObject { + + public Callable callable; + + public TestObject(Callable callable) { + this.callable = callable; + } + } + + public static class TestInt implements Callable { + + public int x; + public int y; + + public TestInt(int x, int y) { + this.x = x; + this.y = y; + } + + @Override + public Integer call() throws Exception { + return new Integer(x); + } + } + + @SuppressWarnings("all") + public static int testSimpleSnippet(int b) throws Exception { + TestObject a = new TestObject(null); + a.callable = new TestInt(b, 9); + return a.callable.call(); + } + + @Test + public void testSimple() { + ValueNode result = getReturn("testSimpleSnippet").result(); + assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty()); + assertEquals(graph.getLocal(0), result); + } + + @SuppressWarnings("all") + public static int testSimpleReadSnippet(TestObject a, int b) throws Exception { + a.callable = new TestInt(b, 9); + return a.callable.call(); + } + + @Test + public void testSimpleRead() { + ValueNode result = getReturn("testSimpleReadSnippet").result(); + assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty()); + assertEquals(graph.getLocal(1), result); + } + + final ReturnNode getReturn(String snippet) { + processMethod(snippet); + assertEquals(1, graph.getNodes(ReturnNode.class).count()); + return graph.getNodes(ReturnNode.class).first(); + } + + private void processMethod(final String snippet) { + graph = parse(snippet); + new ComputeProbabilityPhase().apply(graph); + GraalOptions.PEAReadCache = true; + new IterativeInliningPhase(runtime(), new Assumptions(false), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + } +} diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Thu Mar 28 16:35:24 2013 +0100 @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.test.ea; + +import static org.junit.Assert.*; + +import java.util.concurrent.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.virtual.phases.ea.*; + +public class PEAReadEliminationTest extends GraalCompilerTest { + + private StructuredGraph graph; + + public static Object staticField; + + public static class TestObject implements Callable { + + public int x; + public int y; + + public TestObject(int x, int y) { + this.x = x; + this.y = y; + } + + @Override + public Integer call() throws Exception { + return x; + } + } + + public static class TestObject2 { + + public Object x; + public Object y; + + public TestObject2(Object x, Object y) { + this.x = x; + this.y = y; + } + } + + @SuppressWarnings("all") + public static int testSimpleSnippet(TestObject a) { + a.x = 2; + staticField = a; + return a.x; + } + + @Test + public void testSimple() { + ValueNode result = getReturn("testSimpleSnippet").result(); + assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty()); + assertTrue(result.isConstant()); + assertEquals(2, result.asConstant().asInt()); + } + + @SuppressWarnings("all") + public static int testSimpleConflictSnippet(TestObject a, TestObject b) { + a.x = 2; + b.x = 3; + staticField = a; + return a.x; + } + + @Test + public void testSimpleConflict() { + ValueNode result = getReturn("testSimpleConflictSnippet").result(); + assertFalse(result.isConstant()); + assertTrue(result instanceof LoadFieldNode); + } + + @SuppressWarnings("all") + public static int testParamSnippet(TestObject a, int b) { + a.x = b; + return a.x; + } + + @Test + public void testParam() { + ValueNode result = getReturn("testParamSnippet").result(); + assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty()); + assertEquals(graph.getLocal(1), result); + } + + @SuppressWarnings("all") + public static int testMaterializedSnippet(int a) { + TestObject obj = new TestObject(a, 0); + staticField = obj; + return obj.x; + } + + @Test + public void testMaterialized() { + ValueNode result = getReturn("testMaterializedSnippet").result(); + assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty()); + assertEquals(graph.getLocal(0), result); + } + + @SuppressWarnings("all") + public static int testSimpleLoopSnippet(TestObject obj, int a, int b) { + obj.x = a; + for (int i = 0; i < 10; i++) { + staticField = obj; + } + return obj.x; + } + + @Test + public void testSimpleLoop() { + ValueNode result = getReturn("testSimpleLoopSnippet").result(); + assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty()); + assertEquals(graph.getLocal(1), result); + } + + @SuppressWarnings("all") + public static int testBadLoopSnippet(TestObject obj, int a, int b) { + obj.x = a; + for (int i = 0; i < 10; i++) { + staticField = obj; + obj.x = 0; + } + return obj.x; + } + + @Test + public void testBadLoop() { + ValueNode result = getReturn("testBadLoopSnippet").result(); + assertEquals(1, graph.getNodes(LoadFieldNode.class).count()); + assertTrue(result instanceof LoadFieldNode); + } + + @SuppressWarnings("all") + public static int testPhiSnippet(TestObject a, int b) { + if (b < 0) { + a.x = 1; + } else { + a.x = 2; + } + return a.x; + } + + @Test + public void testPhi() { + ValueNode result = getReturn("testPhiSnippet").result(); + assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty()); + assertTrue(result instanceof PhiNode); + PhiNode phi = (PhiNode) result; + assertTrue(phi.valueAt(0).isConstant()); + assertTrue(phi.valueAt(1).isConstant()); + assertEquals(1, phi.valueAt(0).asConstant().asInt()); + assertEquals(2, phi.valueAt(1).asConstant().asInt()); + } + + @SuppressWarnings("all") + public static void testSimpleStoreSnippet(TestObject a, int b) { + a.x = b; + a.x = b; + } + + @Test + public void testSimpleStore() { + processMethod("testSimpleStoreSnippet"); + assertEquals(1, graph.getNodes().filter(StoreFieldNode.class).count()); + } + + final ReturnNode getReturn(String snippet) { + processMethod(snippet); + assertEquals(1, graph.getNodes(ReturnNode.class).count()); + return graph.getNodes(ReturnNode.class).first(); + } + + private void processMethod(final String snippet) { + graph = parse(snippet); + new ComputeProbabilityPhase().apply(graph); + Assumptions assumptions = new Assumptions(false); + new InliningPhase(runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + GraalOptions.PEAReadCache = true; + new PartialEscapeAnalysisPhase(runtime(), assumptions, false).apply(graph); + } +} diff -r fc0d57b82c86 -r a1a97de0dc9d 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 Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Thu Mar 28 16:35:24 2013 +0100 @@ -121,12 +121,16 @@ } if (GraalOptions.Inline && !plan.isPhaseDisabled(InliningPhase.class)) { - new InliningPhase(runtime, null, assumptions, cache, plan, optimisticOpts).apply(graph); - new DeadCodeEliminationPhase().apply(graph); + if (GraalOptions.IterativeInlining) { + new IterativeInliningPhase(runtime, assumptions, cache, plan, optimisticOpts).apply(graph); + } else { + new InliningPhase(runtime, null, assumptions, cache, plan, optimisticOpts).apply(graph); + new DeadCodeEliminationPhase().apply(graph); - if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(graph); - new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph); + if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(runtime, assumptions).apply(graph); + new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph); + } } } diff -r fc0d57b82c86 -r a1a97de0dc9d 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 Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Thu Mar 28 16:35:24 2013 +0100 @@ -197,6 +197,7 @@ if (inputChanged != null) { inputChanged.inputChanged(this); } + assert newInput.usages != null : "not yet added? " + newInput; newInput.usages.add(this); } } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu Mar 28 16:35:24 2013 +0100 @@ -44,6 +44,7 @@ import com.oracle.graal.hotspot.phases.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.debug.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.PhasePlan.PhasePosition; import com.oracle.graal.printer.*; @@ -76,6 +77,8 @@ private boolean quietMeterAndTime; + private long compilerStartTime; + public VMToCompilerImpl(HotSpotGraalRuntime compiler) { this.graalRuntime = compiler; @@ -196,6 +199,95 @@ t.setDaemon(true); t.start(); } + + if (GraalOptions.BenchmarkDynamicCounters) { + System.setErr(new PrintStream(new BenchmarkCountersOutputStream(System.err, " starting =====", " PASSED in ", "\n"))); + System.setOut(new PrintStream(new BenchmarkCountersOutputStream(System.out, "Iteration ~ (~s) begins: ", "Iteration ~ (~s) ends: ", "\n"))); + DynamicCounterNode.excludedClassPrefix = "Lcom/oracle/graal/"; + DynamicCounterNode.enabled = true; + } + if (GraalOptions.GenericDynamicCounters) { + DynamicCounterNode.enabled = true; + } + compilerStartTime = System.nanoTime(); + } + + private final class BenchmarkCountersOutputStream extends CallbackOutputStream { + + private long startTime; + private boolean waitingForEnd; + + private BenchmarkCountersOutputStream(PrintStream delegate, String... patterns) { + super(delegate, patterns); + } + + @Override + protected void patternFound(int index) { + switch (index) { + case 0: + startTime = System.nanoTime(); + DynamicCounterNode.clear(); + break; + case 1: + waitingForEnd = true; + break; + case 2: + if (waitingForEnd) { + waitingForEnd = false; + DynamicCounterNode.dump(delegate, (System.nanoTime() - startTime) / 1000000000d); + } + break; + } + } + } + + public abstract static class CallbackOutputStream extends OutputStream { + + protected final PrintStream delegate; + private final byte[][] patterns; + private final int[] positions; + + public CallbackOutputStream(PrintStream delegate, String... patterns) { + this.delegate = delegate; + this.positions = new int[patterns.length]; + this.patterns = new byte[patterns.length][]; + for (int i = 0; i < patterns.length; i++) { + this.patterns[i] = patterns[i].getBytes(); + } + } + + protected abstract void patternFound(int index); + + @Override + public void write(int b) throws IOException { + try { + delegate.write(b); + for (int i = 0; i < patterns.length; i++) { + int j = positions[i]; + byte[] cs = patterns[i]; + byte patternChar = cs[j]; + if (patternChar == '~' && Character.isDigit(b)) { + // nothing to do... + } else { + if (patternChar == '~') { + patternChar = cs[++positions[i]]; + } + if (b == patternChar) { + positions[i]++; + } else { + positions[i] = 0; + } + } + if (positions[i] == patterns[i].length) { + positions[i] = 0; + patternFound(i); + } + } + } catch (RuntimeException e) { + e.printStackTrace(delegate); + throw e; + } + } } /** @@ -281,6 +373,7 @@ } System.gc(); phaseTransition("bootstrap2"); + } private MetricRateInPhase parsedBytecodesPerSecond; @@ -353,6 +446,9 @@ } SnippetCounter.printGroups(TTY.out().out()); + if (GraalOptions.GenericDynamicCounters) { + DynamicCounterNode.dump(System.out, (System.nanoTime() - compilerStartTime) / 1000000000d); + } } private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) { diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu Mar 28 16:35:24 2013 +0100 @@ -529,8 +529,10 @@ Kind wordKind = graalRuntime.getTarget().wordKind; if (n instanceof ArrayLengthNode) { ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n; - SafeReadNode safeReadArrayLength = safeReadArrayLength(arrayLengthNode.array()); - graph.replaceFixedWithFixed(arrayLengthNode, safeReadArrayLength); + ValueNode array = arrayLengthNode.array(); + ReadNode arrayLengthRead = graph.add(new ReadNode(array, LocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt())); + arrayLengthRead.dependencies().add(tool.createNullCheckGuard(array)); + graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead); } else if (n instanceof Invoke) { Invoke invoke = (Invoke) n; if (invoke.callTarget() instanceof MethodCallTargetNode) { @@ -566,9 +568,6 @@ graph.addAfterFixed(metaspaceMethod, compiledEntry); } } - } else if (callTarget.invokeKind() == InvokeKind.Special || callTarget.invokeKind() == InvokeKind.Static) { - loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.node().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall, - callTarget.invokeKind())); } if (loweredCallTarget == null) { @@ -773,10 +772,6 @@ return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale); } - private SafeReadNode safeReadArrayLength(ValueNode array) { - return safeRead(array.graph(), Kind.Int, array, config.arrayLengthOffset, StampFactory.positiveInt()); - } - private static ValueNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) { StructuredGraph graph = (StructuredGraph) n.graph(); ArrayLengthNode arrayLength = graph.add(new ArrayLengthNode(n.array())); @@ -786,10 +781,6 @@ return guard; } - private static SafeReadNode safeRead(Graph graph, Kind kind, ValueNode value, int offset, Stamp stamp) { - return graph.add(new SafeReadNode(value, LocationNode.create(LocationNode.FINAL_LOCATION, kind, offset, graph), stamp)); - } - public ResolvedJavaType lookupJavaType(Class clazz) { return HotSpotResolvedObjectType.fromClass(clazz); } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPost.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPost.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPost.java Thu Mar 28 16:35:24 2013 +0100 @@ -93,5 +93,5 @@ } @NodeIntrinsic - public static native void arrayCopyWriteBarrier(Object array, Object value, int index); + public static native void arrayCopyWriteBarrier(Object array, Object value, long index); } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Thu Mar 28 16:35:24 2013 +0100 @@ -24,7 +24,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.IterableNodeType; import com.oracle.graal.loop.phases.*; import com.oracle.graal.nodes.*; @@ -88,21 +87,6 @@ new CanonicalizerPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); } - private static void replaceSnippetInvokes(StructuredGraph snippetGraph, ResolvedJavaMethod targetMethod, int bci) { - for (InvokeNode invoke : snippetGraph.getNodes(InvokeNode.class)) { - if (invoke.methodCallTarget().targetMethod() != targetMethod) { - throw new GraalInternalError("unexpected invoke in arraycopy snippet"); - } - if (invoke.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) { - InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.methodCallTarget(), bci)); - newInvoke.setStateAfter(snippetGraph.add(new FrameState(FrameState.AFTER_BCI))); - snippetGraph.replaceFixedWithFixed(invoke, newInvoke); - } else { - assert invoke.stateAfter().bci == FrameState.AFTER_BCI : invoke; - } - } - } - @Override protected StructuredGraph getSnippetGraph(LoweringTool tool) { if (!GraalOptions.IntrinsifyArrayCopy) { @@ -115,7 +99,7 @@ snippetGraph = ((StructuredGraph) snippetMethod.getCompilerStorage().get(Snippet.class)).copy(); assert snippetGraph != null : "ArrayCopySnippets should be installed"; - replaceSnippetInvokes(snippetGraph, getTargetMethod(), getBci()); + replaceSnippetInvokes(snippetGraph); } else { assert snippetGraph != null : "ArrayCopySnippets should be installed"; diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Thu Mar 28 16:35:24 2013 +0100 @@ -246,7 +246,7 @@ int header = arrayBaseOffset(Kind.Object); if (src == dest && srcPos < destPos) { // bad aliased case long start = (long) (length - 1) * scale; - int j = length - 1; + long j = (long) (length) - 1; for (long i = start; i >= 0; i -= scale) { Object a = UnsafeLoadNode.load(src, header, i + (long) srcPos * scale, Kind.Object); DirectObjectStoreNode.storeObject(dest, header, i + (long) destPos * scale, a); @@ -255,7 +255,7 @@ } } else { long end = (long) length * scale; - int j = 0; + long j = srcPos; for (long i = 0; i < end; i += scale) { Object a = UnsafeLoadNode.load(src, header, i + (long) srcPos * scale, Kind.Object); DirectObjectStoreNode.storeObject(dest, header, i + (long) destPos * scale, a); diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Thu Mar 28 16:35:24 2013 +0100 @@ -122,7 +122,7 @@ ValueNode[] state = new ValueNode[fields.length]; final LoadFieldNode[] loads = new LoadFieldNode[fields.length]; for (int i = 0; i < fields.length; i++) { - state[i] = loads[i] = graph().add(new LoadFieldNode(obj, fields[i])); + state[i] = loads[i] = new LoadFieldNode(obj, fields[i]); } final StructuredGraph structuredGraph = (StructuredGraph) graph(); @@ -130,7 +130,7 @@ public void run() { for (LoadFieldNode load : loads) { - structuredGraph.addBeforeFixed(ObjectCloneNode.this, load); + structuredGraph.addBeforeFixed(ObjectCloneNode.this, structuredGraph.add(load)); } } }); diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Thu Mar 28 16:35:24 2013 +0100 @@ -33,7 +33,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; @@ -235,21 +234,21 @@ ValueNode value = localAt(i); if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { Debug.log(" inserting proxy for %s", value); - storeLocal(i, graph.unique(new ProxyNode(value, loopExit, PhiType.Value))); + storeLocal(i, ProxyNode.forValue(value, loopExit, graph)); } } for (int i = 0; i < stackSize(); i++) { ValueNode value = stackAt(i); if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { Debug.log(" inserting proxy for %s", value); - storeStack(i, graph.unique(new ProxyNode(value, loopExit, PhiType.Value))); + storeStack(i, ProxyNode.forValue(value, loopExit, graph)); } } for (int i = 0; i < locks.length; i++) { ValueNode value = locks[i]; if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { Debug.log(" inserting proxy for %s", value); - locks[i] = graph.unique(new ProxyNode(value, loopExit, PhiType.Value)); + locks[i] = ProxyNode.forValue(value, loopExit, graph); } } } @@ -259,21 +258,21 @@ ValueNode value = localAt(i); if (value != null) { Debug.log(" inserting proxy for %s", value); - storeLocal(i, graph.unique(new ProxyNode(value, begin, PhiType.Value))); + storeLocal(i, ProxyNode.forValue(value, begin, graph)); } } for (int i = 0; i < stackSize(); i++) { ValueNode value = stackAt(i); if (value != null) { Debug.log(" inserting proxy for %s", value); - storeStack(i, graph.unique(new ProxyNode(value, begin, PhiType.Value))); + storeStack(i, ProxyNode.forValue(value, begin, graph)); } } for (int i = 0; i < locks.length; i++) { ValueNode value = locks[i]; if (value != null) { Debug.log(" inserting proxy for %s", value); - locks[i] = graph.unique(new ProxyNode(value, begin, PhiType.Value)); + locks[i] = ProxyNode.forValue(value, begin, graph); } } } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Thu Mar 28 16:35:24 2013 +0100 @@ -32,7 +32,6 @@ import com.oracle.graal.nodes.VirtualState.NodeClosure; import com.oracle.graal.nodes.VirtualState.VirtualClosure; import com.oracle.graal.nodes.cfg.*; -import com.oracle.graal.nodes.type.*; public abstract class LoopFragment { @@ -275,8 +274,7 @@ final ValueNode replaceWith; ProxyNode newVpn = getDuplicatedNode(vpn); if (newVpn != null) { - PhiNode phi = graph.add(vpn.type() == PhiType.Value ? vpn.stamp() == StampFactory.virtual() ? new PhiNode(vpn.stamp(), merge) : new PhiNode(vpn.kind(), merge) : new PhiNode( - vpn.type(), merge)); + PhiNode phi = graph.add(vpn.type() == PhiType.Value ? new PhiNode(vpn.kind(), merge) : new PhiNode(vpn.type(), merge, vpn.getIdentity())); phi.addInput(vpn); phi.addInput(newVpn); replaceWith = phi; diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java Thu Mar 28 16:35:24 2013 +0100 @@ -30,7 +30,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.VirtualState.NodeClosure; -import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; public class LoopFragmentInside extends LoopFragment { @@ -162,8 +161,7 @@ } // create a new phi (we don't patch the old one since some usages of the old one may // still be valid) - PhiNode newPhi = graph.add(phi.type() == PhiType.Value ? phi.stamp() == StampFactory.virtual() ? new PhiNode(phi.stamp(), loopBegin) : new PhiNode(phi.kind(), loopBegin) : new PhiNode( - phi.type(), loopBegin)); + PhiNode newPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), loopBegin) : new PhiNode(phi.type(), loopBegin, phi.getIdentity())); newPhi.addInput(first); for (LoopEndNode end : loopBegin.orderedLoopEnds()) { newPhi.addInput(phi.valueAt(end)); @@ -253,8 +251,7 @@ } for (final PhiNode phi : loopBegin.phis().snapshot()) { - final PhiNode firstPhi = graph.add(phi.type() == PhiType.Value ? phi.stamp() == StampFactory.virtual() ? new PhiNode(phi.stamp(), newExitMerge) : new PhiNode(phi.kind(), newExitMerge) - : new PhiNode(phi.type(), newExitMerge)); + final PhiNode firstPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), newExitMerge) : new PhiNode(phi.type(), newExitMerge, phi.getIdentity())); for (EndNode end : newExitMerge.forwardEnds()) { LoopEndNode loopEnd = reverseEnds.get(end); ValueNode prim = prim(phi.valueAt(loopEnd)); diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java Thu Mar 28 16:35:24 2013 +0100 @@ -34,12 +34,17 @@ private static final DebugMetric FULLY_UNROLLED_LOOPS = Debug.metric("FullUnrolls"); private final GraalCodeCacheProvider runtime; private final Assumptions assumptions; + private int unrollCount; public LoopFullUnrollPhase(GraalCodeCacheProvider runtime, Assumptions assumptions) { this.runtime = runtime; this.assumptions = assumptions; } + public int getUnrollCount() { + return unrollCount; + } + @Override protected void run(StructuredGraph graph) { if (graph.hasLoops()) { @@ -55,11 +60,11 @@ FULLY_UNROLLED_LOOPS.increment(); Debug.dump(graph, "After fullUnroll %s", loop); peeled = true; + unrollCount++; break; } } } while (peeled); } } - } diff -r fc0d57b82c86 -r a1a97de0dc9d 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 Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Thu Mar 28 16:35:24 2013 +0100 @@ -50,6 +50,7 @@ @Input(notDataflow = true) private MergeNode merge; @Input private final NodeInputList values = new NodeInputList<>(this); private final PhiType type; + private final Object identity; /** * Create a value phi ({@link PhiType#Value}) with the specified kind. @@ -66,6 +67,7 @@ assert stamp != StampFactory.forVoid(); this.type = PhiType.Value; this.merge = merge; + this.identity = null; } /** @@ -74,11 +76,12 @@ * @param type the type of the new phi * @param merge the merge that the new phi belongs to */ - public PhiNode(PhiType type, MergeNode merge) { + public PhiNode(PhiType type, MergeNode merge, Object identity) { super(type.stamp); assert type.stamp != null : merge + " " + type; this.type = type; this.merge = merge; + this.identity = identity; } public PhiType type() { @@ -89,6 +92,11 @@ return merge; } + public Object getIdentity() { + assert type != PhiType.Value; + return identity; + } + public void setMerge(MergeNode x) { updateUsages(merge, x); merge = x; diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Thu Mar 28 16:35:24 2013 +0100 @@ -40,10 +40,12 @@ @Input(notDataflow = true) private BeginNode proxyPoint; @Input private ValueNode value; private final PhiType type; + private final Object identity; - public ProxyNode(ValueNode value, BeginNode exit, PhiType type) { + public ProxyNode(ValueNode value, BeginNode exit, PhiType type, Object identity) { super(type == PhiType.Value ? value.stamp() : type.stamp); this.type = type; + this.identity = identity; assert exit != null; this.proxyPoint = exit; this.value = value; @@ -71,6 +73,11 @@ return type; } + public Object getIdentity() { + assert type != PhiType.Value; + return identity; + } + @Override public boolean verify() { assert value != null; @@ -100,4 +107,13 @@ } } } + + public static ProxyNode forValue(ValueNode value, BeginNode exit, StructuredGraph graph) { + return graph.unique(new ProxyNode(value, exit, PhiType.Value, null)); + } + + public static ProxyNode forMemory(ValueNode value, BeginNode exit, Object location, StructuredGraph graph) { + return graph.unique(new ProxyNode(value, exit, PhiType.Memory, location)); + } + } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Thu Mar 28 16:35:24 2013 +0100 @@ -22,6 +22,7 @@ */ package com.oracle.graal.nodes.debug; +import java.io.*; import java.util.*; import com.oracle.graal.api.meta.*; @@ -45,28 +46,39 @@ private static final int MAX_COUNTERS = 10 * 1024; private static final long[] COUNTERS = new long[MAX_COUNTERS]; private static final HashMap INDEXES = new HashMap<>(); + public static String excludedClassPrefix = null; + public static boolean enabled = false; + private final String name; + private final long increment; private final boolean addContext; - public DynamicCounterNode(String name, boolean addContext) { + public DynamicCounterNode(String name, long increment, boolean addContext) { super(StampFactory.forVoid()); + if (!enabled) { + throw new GraalInternalError("dynamic counters not enabled"); + } this.name = name; + this.increment = increment; this.addContext = addContext; } + public String getName() { + return name; + } + + public long getIncrement() { + return increment; + } + + public boolean isAddContext() { + return addContext; + } + private static synchronized int getIndex(String name) { Integer index = INDEXES.get(name); if (index == null) { index = INDEXES.size(); - if (index == 0) { - Runtime.getRuntime().addShutdownHook(new Thread() { - - @Override - public void run() { - dump(); - } - }); - } INDEXES.put(name, index); if (index >= MAX_COUNTERS) { throw new GraalInternalError("too many dynamic counters"); @@ -77,44 +89,59 @@ } } - private static synchronized void dump() { + public static synchronized void dump(PrintStream out, double seconds) { TreeMap sorted = new TreeMap<>(); long sum = 0; for (int i = 0; i < MAX_COUNTERS; i++) { sum += COUNTERS[i]; } + long cutoff = sum / 1000; int cnt = 0; for (Map.Entry entry : INDEXES.entrySet()) { - sorted.put(COUNTERS[entry.getValue()] * MAX_COUNTERS + cnt++, entry.getKey()); + if (COUNTERS[entry.getValue()] > cutoff) { + sorted.put(COUNTERS[entry.getValue()] * MAX_COUNTERS + cnt++, entry.getKey()); + } } + out.println("=========== dynamic counters, time = " + seconds + " s"); for (Map.Entry entry : sorted.entrySet()) { - System.out.println((entry.getKey() / MAX_COUNTERS) + ": " + entry.getValue()); + long counter = entry.getKey() / MAX_COUNTERS; + out.println((int) (counter / seconds) + "/s \t" + (counter * 100 / sum) + "% \t" + entry.getValue()); } - System.out.println(sum + ": total"); + out.println((int) (sum / seconds) + "/s: total"); + out.println("============================"); + clear(); + } + + public static void clear() { + Arrays.fill(COUNTERS, 0); } @Override public void lower(LoweringTool tool) { - int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", ((StructuredGraph) graph()).method())) : getIndex(name); + StructuredGraph graph = (StructuredGraph) graph(); + if (excludedClassPrefix == null || !graph.method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) { + int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", ((StructuredGraph) graph()).method())) : getIndex(name); - StructuredGraph graph = (StructuredGraph) graph(); - ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph); - ConstantNode indexConstant = ConstantNode.forInt(index, graph); - LoadIndexedNode load = graph.add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long)); - IntegerAddNode add = graph.add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(1, graph))); - StoreIndexedNode store = graph.add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add)); + ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph); + ConstantNode indexConstant = ConstantNode.forInt(index, graph); + LoadIndexedNode load = graph.add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long)); + IntegerAddNode add = graph.add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(increment, graph))); + StoreIndexedNode store = graph.add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add)); - graph.addBeforeFixed(this, load); - graph.addBeforeFixed(this, store); + graph.addBeforeFixed(this, load); + graph.addBeforeFixed(this, store); + } graph.removeFixed(this); } - public static void createCounter(String name, FixedNode before, boolean addContext) { - StructuredGraph graph = (StructuredGraph) before.graph(); - DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, addContext)); - graph.addBeforeFixed(before, counter); + public static void addCounterBefore(String name, long increment, boolean addContext, FixedNode position) { + if (enabled) { + StructuredGraph graph = (StructuredGraph) position.graph(); + DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, increment, addContext)); + graph.addBeforeFixed(position, counter); + } } } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java Thu Mar 28 16:35:24 2013 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.debug; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; + +/** + * This is a special version of the dynamic counter node that removes itself as soon as it's the + * only usage of the associated node. This way it only increments the counter if the node is + * actually executed. + */ +public class SurvivingCounterNode extends DynamicCounterNode implements Simplifiable, Virtualizable { + + @Input private ValueNode checkedValue; + + public SurvivingCounterNode(String name, long increment, boolean addContext, ValueNode checkedValue) { + super(name, increment, addContext); + this.checkedValue = checkedValue; + } + + @Override + public void simplify(SimplifierTool tool) { + if (checkedValue instanceof FloatingNode && checkedValue.usages().count() == 1) { + tool.addToWorkList(checkedValue); + ((StructuredGraph) graph()).removeFixed(this); + // ((StructuredGraph) graph()).replaceFixedWithFixed(this, graph().add(new + // DynamicCounterNode("non-surviving " + getName(), getIncrement(), isAddContext()))); + } + } + + @Override + public void virtualize(VirtualizerTool tool) { + State state = tool.getObjectState(checkedValue); + if (state != null && state.getState() == EscapeState.Virtual) { + tool.delete(); + } + } +} diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeAccessNode.java Thu Mar 28 15:33:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; - -/** - * An analog to {@link AccessNode} with the additional semantics of null-checking the receiver - * object before the access. - */ -public abstract class SafeAccessNode extends FixedWithNextNode { - - @Input private ValueNode object; - @Input private LocationNode location; - - public SafeAccessNode(ValueNode object, LocationNode location, Stamp stamp) { - super(stamp); - this.object = object; - this.location = location; - } - - public ValueNode object() { - return object; - } - - public LocationNode location() { - return location; - } -} diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java Thu Mar 28 15:33:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * An analog to {@link ReadNode} with the additional semantics of null-checking the receiver object - * before reading from it. - */ -public class SafeReadNode extends SafeAccessNode implements Lowerable { - - public SafeReadNode(ValueNode object, LocationNode location, Stamp stamp) { - super(object, location, stamp); - assert object != null && location != null; - } - - @Override - public void lower(LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) graph(); - ValueNode guard = tool.createNullCheckGuard(object()); - ReadNode read = graph.add(new ReadNode(object(), location(), stamp())); - read.dependencies().add(guard); - - graph.replaceFixedWithFixed(this, read); - } -} diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java Thu Mar 28 15:33:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * An analog to {@link WriteNode} with the additional semantics of null-checking the receiver object - * before writing to it. - */ -public class SafeWriteNode extends SafeAccessNode implements StateSplit, Lowerable { - - @Input private ValueNode value; - @Input(notDataflow = true) private FrameState stateAfter; - - public FrameState stateAfter() { - return stateAfter; - } - - public void setStateAfter(FrameState x) { - assert x == null || x.isAlive() : "frame state must be in a graph"; - updateUsages(stateAfter, x); - stateAfter = x; - } - - public boolean hasSideEffect() { - return true; - } - - public SafeWriteNode(ValueNode object, ValueNode value, LocationNode location) { - super(object, location, StampFactory.forVoid()); - this.value = value; - } - - public ValueNode value() { - return value; - } - - @Override - public void lower(LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) graph(); - ValueNode guard = tool.createNullCheckGuard(object()); - WriteNode write = graph.add(new WriteNode(object(), value(), location())); - write.dependencies().add(guard); - graph.replaceFixedWithFixed(this, write); - } -} diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java Thu Mar 28 16:35:24 2013 +0100 @@ -139,7 +139,7 @@ } Graph graph = merge.graph(); for (GuardNode guard : hits) { - PhiNode phi = graph.add(new PhiNode(PhiType.Guard, merge)); + PhiNode phi = graph.add(new PhiNode(PhiType.Guard, merge, null)); for (EndNode otherEnd : merge.forwardEnds()) { phi.addInput(graph.unique(new GuardNode(guard.condition(), BeginNode.prevBegin(otherEnd), guard.reason(), guard.action(), guard.negated()))); } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Thu Mar 28 16:35:24 2013 +0100 @@ -186,7 +186,7 @@ } else if (merged == null) { merged = last; } else { - PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge)); + PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge, key)); for (int j = 0; j < mergedStatesCount; j++) { phi.addInput(merged); } @@ -232,7 +232,7 @@ Map phis = new HashMap<>(); for (Object location : modifiedLocations) { - PhiNode phi = loop.graph().add(new PhiNode(PhiType.Memory, loop)); + PhiNode phi = loop.graph().add(new PhiNode(PhiType.Memory, loop, location)); phi.addInput(initialState.getLastLocationAccess(location)); phis.put(location, phi); initialState.lastMemorySnapshot.put(location, phi); @@ -254,7 +254,7 @@ for (Object location : modifiedLocations) { ValueNode lastAccessAtExit = state.lastMemorySnapshot.get(location); if (lastAccessAtExit != null) { - state.lastMemorySnapshot.put(location, loop.graph().add(new ProxyNode(lastAccessAtExit, exit, PhiType.Memory))); + state.lastMemorySnapshot.put(location, ProxyNode.forMemory(lastAccessAtExit, exit, location, (StructuredGraph) loop.graph())); } } } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Thu Mar 28 16:35:24 2013 +0100 @@ -57,13 +57,17 @@ private final OptimisticOptimizations optimisticOpts; private CustomCanonicalizer customCanonicalizer; + private int inliningCount; + + private int maxMethodPerInlining = Integer.MAX_VALUE; + // Metrics private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed"); private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered"); private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize"); private static final DebugMetric metricInliningRuns = Debug.metric("Runs"); - public InliningPhase(GraalCodeCacheProvider runtime, Collection hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) { + public InliningPhase(GraalCodeCacheProvider runtime, Map hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) { this(runtime, assumptions, cache, plan, createInliningPolicy(runtime, assumptions, optimisticOpts, hints), optimisticOpts); } @@ -71,6 +75,10 @@ this.customCanonicalizer = customCanonicalizer; } + public void setMaxMethodsPerInlining(int max) { + maxMethodPerInlining = max; + } + public InliningPhase(GraalCodeCacheProvider runtime, Assumptions assumptions, GraphCache cache, PhasePlan plan, InliningPolicy inliningPolicy, OptimisticOptimizations optimisticOpts) { this.runtime = runtime; this.assumptions = assumptions; @@ -80,6 +88,10 @@ this.optimisticOpts = optimisticOpts; } + public int getInliningCount() { + return inliningCount; + } + @Override protected void run(final StructuredGraph graph) { inliningPolicy.initialize(graph); @@ -89,6 +101,7 @@ if (candidate != null) { boolean isWorthInlining = inliningPolicy.isWorthInlining(candidate); + isWorthInlining &= candidate.numberOfMethods() <= maxMethodPerInlining; metricInliningConsidered.increment(); if (isWorthInlining) { @@ -102,6 +115,7 @@ if (GraalOptions.OptCanonicalizer) { new CanonicalizerPhase(runtime, assumptions, invokeUsages, mark, customCanonicalizer).apply(graph); } + inliningCount++; metricInliningPerformed.increment(); } catch (BailoutException bailout) { throw bailout; @@ -164,9 +178,9 @@ private static class GreedySizeBasedInliningDecision implements InliningDecision { private final GraalCodeCacheProvider runtime; - private final Collection hints; + private final Map hints; - public GreedySizeBasedInliningDecision(GraalCodeCacheProvider runtime, Collection hints) { + public GreedySizeBasedInliningDecision(GraalCodeCacheProvider runtime, Map hints) { this.runtime = runtime; this.hints = hints; } @@ -185,9 +199,14 @@ return InliningUtil.logInlinedMethod(info, "intrinsic"); } - int bytecodeSize = bytecodeCodeSize(info); - int complexity = compilationComplexity(info); - int compiledCodeSize = compiledCodeSize(info); + double bonus = 1; + if (hints != null && hints.containsKey(info.invoke())) { + bonus = hints.get(info.invoke()); + } + + int bytecodeSize = (int) (bytecodeCodeSize(info) / bonus); + int complexity = (int) (compilationComplexity(info) / bonus); + int compiledCodeSize = (int) (compiledCodeSize(info) / bonus); double relevance = info.invoke().inliningRelevance(); /* @@ -213,13 +232,12 @@ int invokeUsages = countInvokeUsages(info); int moreSpecificArguments = countMoreSpecificArgumentInfo(info); int level = info.level(); - boolean preferredInvoke = hints != null && hints.contains(info.invoke()); // TODO (chaeubl): compute metric that is used to check if this method should be inlined return InliningUtil.logNotInlinedMethod(info, - "(relevance=%f, bytecodes=%d, complexity=%d, codeSize=%d, probability=%f, transferredValues=%d, invokeUsages=%d, moreSpecificArguments=%d, level=%d, preferred=%b)", - relevance, bytecodeSize, complexity, compiledCodeSize, probability, transferredValues, invokeUsages, moreSpecificArguments, level, preferredInvoke); + "(relevance=%f, bytecodes=%d, complexity=%d, codeSize=%d, probability=%f, transferredValues=%d, invokeUsages=%d, moreSpecificArguments=%d, level=%d, bonus=%f)", relevance, + bytecodeSize, complexity, compiledCodeSize, probability, transferredValues, invokeUsages, moreSpecificArguments, level, bonus); } private static boolean isTrivialInlining(int bytecodeSize, int complexity, int compiledCodeSize) { @@ -329,16 +347,14 @@ private static class CFInliningPolicy implements InliningPolicy { private final InliningDecision inliningDecision; - private final Collection hints; private final Assumptions assumptions; private final OptimisticOptimizations optimisticOpts; private final Deque sortedInvokes; private NodeBitMap visitedFixedNodes; private FixedNode invokePredecessor; - public CFInliningPolicy(InliningDecision inliningPolicy, Collection hints, Assumptions assumptions, OptimisticOptimizations optimisticOpts) { + public CFInliningPolicy(InliningDecision inliningPolicy, Assumptions assumptions, OptimisticOptimizations optimisticOpts) { this.inliningDecision = inliningPolicy; - this.hints = hints; this.assumptions = assumptions; this.optimisticOpts = optimisticOpts; this.sortedInvokes = new ArrayDeque<>(); @@ -371,9 +387,6 @@ public void initialize(StructuredGraph graph) { visitedFixedNodes = graph.createNodeBitMap(true); scanGraphForInvokes(graph.start()); - if (hints != null) { - sortedInvokes.retainAll(hints); - } } public void scanInvokes(Iterable newNodes) { @@ -500,8 +513,8 @@ } } - private static InliningPolicy createInliningPolicy(GraalCodeCacheProvider runtime, Assumptions assumptions, OptimisticOptimizations optimisticOpts, Collection hints) { + private static InliningPolicy createInliningPolicy(GraalCodeCacheProvider runtime, Assumptions assumptions, OptimisticOptimizations optimisticOpts, Map hints) { InliningDecision inliningDecision = new GreedySizeBasedInliningDecision(runtime, hints); - return new CFInliningPolicy(inliningDecision, hints, assumptions, optimisticOpts); + return new CFInliningPolicy(inliningDecision, assumptions, optimisticOpts); } } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java Thu Mar 28 16:35:24 2013 +0100 @@ -27,7 +27,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.phases.*; @@ -86,7 +85,7 @@ if (lastLocationAccess instanceof ProxyNode) { ProxyNode proxy = (ProxyNode) lastLocationAccess; ValueNode value = getValue(n, proxy.value(), nodeMap); - return lastLocationAccess.graph().add(new ProxyNode(value, proxy.proxyPoint(), PhiType.Value)); + return ProxyNode.forValue(value, proxy.proxyPoint(), (StructuredGraph) lastLocationAccess.graph()); } if (lastLocationAccess instanceof WriteNode) { return ((WriteNode) lastLocationAccess).value(); diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Thu Mar 28 16:35:24 2013 +0100 @@ -128,13 +128,21 @@ } }; + private int tailDuplicationCount; + + public int getTailDuplicationCount() { + return tailDuplicationCount; + } + @Override protected void run(StructuredGraph graph) { // A snapshot is taken here, so that new MergeNode instances aren't considered for tail // duplication. for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) { if (!(merge instanceof LoopBeginNode) && merge.probability() >= GraalOptions.TailDuplicationProbability) { - tailDuplicate(merge, DEFAULT_DECISION, null); + if (tailDuplicate(merge, DEFAULT_DECISION, null)) { + tailDuplicationCount++; + } } } } @@ -155,7 +163,7 @@ * {@link PiNode}, and is used to replace {@link PiNode#object()} with the * {@link PiNode} in the duplicated branch that corresponds to the entry. */ - public static void tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List replacements) { + public static boolean tailDuplicate(MergeNode merge, TailDuplicationDecision decision, List replacements) { assert !(merge instanceof LoopBeginNode); assert replacements == null || replacements.size() == merge.forwardEndCount(); FixedNode fixed = merge; @@ -179,15 +187,18 @@ if (decision.doTransform(merge, fixedCount)) { metricDuplicationEndPerformed.increment(); new DuplicationOperation(merge, replacements).duplicate(); + return true; } } else if (merge.stateAfter() != null) { metricDuplicationOther.increment(); if (decision.doTransform(merge, fixedCount)) { metricDuplicationOtherPerformed.increment(); new DuplicationOperation(merge, replacements).duplicate(); + return true; } } } + return false; } /** diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Thu Mar 28 16:35:24 2013 +0100 @@ -49,6 +49,7 @@ public static boolean LimitInlinedRelevance = true; public static float BoostInliningForEscapeAnalysis = 2f; public static float RelevanceCapForInlining = 1f; + public static boolean IterativeInlining = ____; public static int TrivialBytecodeSize = 10; public static int NormalBytecodeSize = 150; @@ -67,6 +68,8 @@ public static int EscapeAnalysisIterations = 2; public static String EscapeAnalyzeOnly = null; public static int MaximumEscapeAnalysisArrayLength = 32; + public static boolean PEAReadCache = ____; + public static boolean PEAInliningHints = ____; public static double TailDuplicationProbability = 0.5; public static int TailDuplicationTrivialSize = 1; @@ -124,6 +127,8 @@ public static String LogFile = null; public static String MethodFilter = null; public static boolean DumpOnError = ____; + public static boolean GenericDynamicCounters = ____; + public static boolean BenchmarkDynamicCounters = ____; // Ideal graph visualizer output settings public static boolean PrintBinaryGraphs = true; diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java Thu Mar 28 16:35:24 2013 +0100 @@ -41,7 +41,7 @@ protected abstract StateT merge(MergeNode merge, List states); - protected abstract StateT afterSplit(FixedNode node, StateT oldState); + protected abstract StateT cloneState(StateT oldState); protected abstract List processLoop(Loop loop, StateT initialState); } @@ -56,25 +56,31 @@ LoopInfo info = new LoopInfo<>(); List predecessors = loop.header.getPredecessors(); for (int i = 1; i < predecessors.size(); i++) { - info.endStates.add(blockEndStates.get(predecessors.get(i).getEndNode())); + StateT endState = blockEndStates.get(predecessors.get(i).getEndNode()); + // make sure all end states are unique objects + info.endStates.add(closure.cloneState(endState)); } for (Block loopExit : loop.exits) { assert loopExit.getPredecessorCount() == 1; - StateT exitState = blockEndStates.get(loopExit.getFirstPredecessor().getEndNode()); + StateT exitState = blockEndStates.get(loopExit.getBeginNode()); assert exitState != null; - info.exitStates.add(exitState); + // make sure all exit states are unique objects + info.exitStates.add(closure.cloneState(exitState)); } return info; } public static IdentityHashMap apply(BlockIteratorClosure closure, Block start, StateT initialState, Set boundary) { Deque blockQueue = new ArrayDeque<>(); - IdentityHashMap blockEndStates = new IdentityHashMap<>(); + /* + * States are stored on EndNodes before merges, and on BeginNodes after ControlSplitNodes. + */ + IdentityHashMap states = new IdentityHashMap<>(); StateT state = initialState; Block current = start; - do { + while (true) { if (boundary == null || boundary.contains(current)) { closure.processBlock(current, state); @@ -86,7 +92,7 @@ if (current.isLoopEnd()) { // nothing to do... loop ends only lead to loop begins we've already // visited - blockEndStates.put(current.getEndNode(), state); + states.put(current.getEndNode(), state); } else { // recurse into the loop Loop loop = successor.getLoop(); @@ -98,14 +104,14 @@ int i = 0; assert loop.exits.size() == exitStates.size(); for (Block exit : loop.exits) { - blockEndStates.put(exit.getFirstPredecessor().getEndNode(), exitStates.get(i++)); + states.put(exit.getBeginNode(), exitStates.get(i++)); blockQueue.addFirst(exit); } } } else { if (successor.getBeginNode() instanceof LoopExitNode) { assert successor.getPredecessors().size() == 1; - blockEndStates.put(current.getEndNode(), state); + states.put(successor.getBeginNode(), state); current = successor; continue; } else { @@ -114,12 +120,12 @@ EndNode end = (EndNode) current.getEndNode(); // add the end node and see if the merge is ready for processing - assert !blockEndStates.containsKey(end); - blockEndStates.put(end, state); + assert !states.containsKey(end); + states.put(end, state); MergeNode merge = end.merge(); boolean endsVisited = true; for (EndNode forwardEnd : merge.forwardEnds()) { - if (!blockEndStates.containsKey(forwardEnd)) { + if (!states.containsKey(forwardEnd)) { endsVisited = false; break; } @@ -136,46 +142,34 @@ } } else { assert current.getSuccessors().size() > 1; - blockEndStates.put(current.getEndNode(), state); - for (Block block : current.getSuccessors()) { - blockQueue.addFirst(block); + for (int i = 0; i < current.getSuccessors().size(); i++) { + Block successor = current.getSuccessors().get(i); + blockQueue.addFirst(successor); + states.put(successor.getBeginNode(), i == 0 ? state : closure.cloneState(state)); } } } // get next queued block if (blockQueue.isEmpty()) { - current = null; + return states; } else { - int maxIterations = blockQueue.size(); - while (maxIterations-- > 0) { - current = blockQueue.removeFirst(); - if (current.getPredecessors().size() > 1) { - MergeNode merge = (MergeNode) current.getBeginNode(); - ArrayList states = new ArrayList<>(merge.forwardEndCount()); - for (int i = 0; i < merge.forwardEndCount(); i++) { - StateT other = blockEndStates.get(merge.forwardEndAt(i)); - assert other != null; - states.add(other); - } - state = closure.merge(merge, states); - if (state != null) { - break; - } else { - blockQueue.addLast(current); - current = null; - } - } else { - assert current.getPredecessors().size() == 1; - assert current.getBeginNode().predecessor() != null; - if (boundary == null || boundary.contains(current)) { - state = closure.afterSplit(current.getBeginNode(), blockEndStates.get(current.getBeginNode().predecessor())); - break; - } + current = blockQueue.removeFirst(); + if (current.getPredecessors().size() == 1) { + state = states.get(current.getBeginNode()); + } else { + assert current.getPredecessors().size() > 1; + MergeNode merge = (MergeNode) current.getBeginNode(); + ArrayList mergedStates = new ArrayList<>(merge.forwardEndCount()); + for (int i = 0; i < merge.forwardEndCount(); i++) { + StateT other = states.get(merge.forwardEndAt(i)); + assert other != null; + mergedStates.add(other); } + state = closure.merge(merge, mergedStates); } + assert state != null; } - } while (current != null); - return blockEndStates; + } } } diff -r fc0d57b82c86 -r a1a97de0dc9d 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 Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Thu Mar 28 16:35:24 2013 +0100 @@ -100,7 +100,7 @@ } @Override - protected HashSet afterSplit(FixedNode node, HashSet oldState) { + protected HashSet cloneState(HashSet oldState) { return new HashSet<>(oldState); } @@ -580,41 +580,45 @@ } private void addToEarliestSorting(Block b, ScheduledNode i, List sortedInstructions, NodeBitMap visited) { - if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) { - return; - } + ScheduledNode instruction = i; + while (true) { + if (instruction == null || visited.isMarked(instruction) || cfg.getNodeToBlock().get(instruction) != b || instruction instanceof PhiNode || instruction instanceof LocalNode) { + return; + } - visited.mark(i); - for (Node usage : i.usages()) { - if (usage instanceof VirtualState) { - // only fixed nodes can have VirtualState -> no need to schedule them - } else { - if (i instanceof LoopExitNode && usage instanceof ProxyNode) { - // value proxies should be scheduled before the loopexit, not after + visited.mark(instruction); + for (Node usage : instruction.usages()) { + if (usage instanceof VirtualState) { + // only fixed nodes can have VirtualState -> no need to schedule them } else { - addToEarliestSorting(b, (ScheduledNode) usage, sortedInstructions, visited); - } - } - } - - if (i instanceof BeginNode) { - ArrayList proxies = (i instanceof LoopExitNode) ? new ArrayList() : null; - for (ScheduledNode inBlock : blockToNodesMap.get(b)) { - if (!visited.isMarked(inBlock)) { - if (inBlock instanceof ProxyNode) { - proxies.add((ProxyNode) inBlock); + if (instruction instanceof LoopExitNode && usage instanceof ProxyNode) { + // value proxies should be scheduled before the loopexit, not after } else { - addToEarliestSorting(b, inBlock, sortedInstructions, visited); + addToEarliestSorting(b, (ScheduledNode) usage, sortedInstructions, visited); } } } - sortedInstructions.add(i); - if (proxies != null) { - sortedInstructions.addAll(proxies); + + if (instruction instanceof BeginNode) { + ArrayList proxies = (instruction instanceof LoopExitNode) ? new ArrayList() : null; + for (ScheduledNode inBlock : blockToNodesMap.get(b)) { + if (!visited.isMarked(inBlock)) { + if (inBlock instanceof ProxyNode) { + proxies.add((ProxyNode) inBlock); + } else { + addToEarliestSorting(b, inBlock, sortedInstructions, visited); + } + } + } + sortedInstructions.add(instruction); + if (proxies != null) { + sortedInstructions.addAll(proxies); + } + break; + } else { + sortedInstructions.add(instruction); + instruction = (ScheduledNode) instruction.predecessor(); } - } else { - sortedInstructions.add(i); - addToEarliestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited); } } } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Thu Mar 28 16:35:24 2013 +0100 @@ -56,6 +56,10 @@ return targetMethod; } + public JavaType getReturnType() { + return returnType; + } + @SuppressWarnings("unused") protected StructuredGraph getSnippetGraph(LoweringTool tool) { return null; @@ -85,4 +89,19 @@ invoke.setStateAfter(stateAfter()); return invoke; } + + protected void replaceSnippetInvokes(StructuredGraph snippetGraph) { + for (InvokeNode invoke : snippetGraph.getNodes(InvokeNode.class)) { + if (invoke.methodCallTarget().targetMethod() != getTargetMethod()) { + throw new GraalInternalError("unexpected invoke %s in snippet", getClass().getSimpleName()); + } + if (invoke.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) { + InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.methodCallTarget(), getBci())); + newInvoke.setStateAfter(snippetGraph.add(new FrameState(FrameState.AFTER_BCI))); + snippetGraph.replaceFixedWithFixed(invoke, newInvoke); + } else { + assert invoke.stateAfter().bci == FrameState.AFTER_BCI : invoke; + } + } + } } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Thu Mar 28 16:35:24 2013 +0100 @@ -30,28 +30,104 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.virtual.nodes.*; class BlockState { - private final HashMap objectStates = new HashMap<>(); - private final HashMap objectAliases = new HashMap<>(); - private final HashMap scalarAliases = new HashMap<>(); + private final IdentityHashMap objectStates = new IdentityHashMap<>(); + private final IdentityHashMap objectAliases; + private final IdentityHashMap scalarAliases; + private final HashMap readCache; + + static class ReadCacheEntry { + + public final Object identity; + public final ValueNode object; + + public ReadCacheEntry(Object identity, ValueNode object) { + this.identity = identity; + this.object = object; + } + + @Override + public int hashCode() { + int result = 31 + ((identity == null) ? 0 : identity.hashCode()); + return 31 * result + ((object == null) ? 0 : object.hashCode()); + } + + @Override + public boolean equals(Object obj) { + ReadCacheEntry other = (ReadCacheEntry) obj; + return identity == other.identity && object == other.object; + } + + @Override + public String toString() { + return object + ":" + identity; + } + } public BlockState() { + objectAliases = new IdentityHashMap<>(); + scalarAliases = new IdentityHashMap<>(); + readCache = new HashMap<>(); } public BlockState(BlockState other) { for (Map.Entry entry : other.objectStates.entrySet()) { objectStates.put(entry.getKey(), entry.getValue().cloneState()); } - for (Map.Entry entry : other.objectAliases.entrySet()) { - objectAliases.put(entry.getKey(), entry.getValue()); + objectAliases = new IdentityHashMap<>(other.objectAliases); + scalarAliases = new IdentityHashMap<>(other.scalarAliases); + readCache = new HashMap<>(other.readCache); + } + + public void addReadCache(ValueNode object, Object identity, ValueNode value) { + ValueNode cacheObject; + ObjectState obj = getObjectState(object); + if (obj != null) { + assert !obj.isVirtual(); + cacheObject = obj.getMaterializedValue(); + } else { + cacheObject = object; } - for (Map.Entry entry : other.scalarAliases.entrySet()) { - scalarAliases.put(entry.getKey(), entry.getValue()); + readCache.put(new ReadCacheEntry(identity, cacheObject), value); + } + + public ValueNode getReadCache(ValueNode object, Object identity) { + ValueNode cacheObject; + ObjectState obj = getObjectState(object); + if (obj != null) { + assert !obj.isVirtual(); + cacheObject = obj.getMaterializedValue(); + } else { + cacheObject = object; + } + ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject)); + obj = getObjectState(cacheValue); + if (obj != null) { + assert !obj.isVirtual(); + cacheValue = obj.getMaterializedValue(); + } else { + cacheValue = getScalarAlias(cacheValue); + } + return cacheValue; + } + + public void killReadCache(Object identity) { + if (identity == LocationNode.ANY_LOCATION) { + readCache.clear(); + } else { + Iterator> iter = readCache.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + if (entry.getKey().identity == identity) { + iter.remove(); + } + } } } @@ -126,6 +202,13 @@ } deferred.remove(virtual); + if (virtual instanceof VirtualInstanceNode) { + VirtualInstanceNode instance = (VirtualInstanceNode) virtual; + for (int i = 0; i < fieldState.length; i++) { + readCache.put(new ReadCacheEntry(instance.field(i), materialize), fieldState[i]); + } + } + materializeEffects.addMaterialization(materialize, fixed, values); } @@ -175,6 +258,63 @@ return objectStates.toString(); } + public void mergeReadCache(List states, MergeNode merge, GraphEffectList effects) { + for (Map.Entry entry : states.get(0).readCache.entrySet()) { + ReadCacheEntry key = entry.getKey(); + ValueNode value = entry.getValue(); + boolean phi = false; + for (int i = 1; i < states.size(); i++) { + ValueNode otherValue = states.get(i).readCache.get(key); + if (otherValue == null) { + value = null; + phi = false; + break; + } + if (!phi && otherValue != value) { + phi = true; + } + } + if (phi) { + PhiNode phiNode = new PhiNode(value.kind(), merge); + effects.addFloatingNode(phiNode); + for (int i = 0; i < states.size(); i++) { + effects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity)); + } + readCache.put(key, phiNode); + } else if (value != null) { + readCache.put(key, value); + } + } + for (PhiNode phi : merge.phis()) { + if (phi.kind() == Kind.Object) { + for (Map.Entry entry : states.get(0).readCache.entrySet()) { + if (entry.getKey().object == phi.valueAt(0)) { + mergeReadCachePhi(phi, entry.getKey().identity, states, merge, effects); + } + } + + } + } + } + + private void mergeReadCachePhi(PhiNode phi, Object identity, List states, MergeNode merge, GraphEffectList effects) { + ValueNode[] values = new ValueNode[phi.valueCount()]; + for (int i = 0; i < phi.valueCount(); i++) { + ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity); + if (value == null) { + return; + } + values[i] = value; + } + + PhiNode phiNode = new PhiNode(values[0].kind(), merge); + effects.addFloatingNode(phiNode); + for (int i = 0; i < values.length; i++) { + effects.addPhiInput(phiNode, values[i]); + } + readCache.put(new ReadCacheEntry(identity, phi), phiNode); + } + public static BlockState meetAliases(List states) { BlockState newState = new BlockState(); @@ -201,6 +341,12 @@ } } } + return newState; } + + public Map getReadCache() { + return readCache; + } + } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java Thu Mar 28 16:35:24 2013 +0100 @@ -193,7 +193,7 @@ for (int i2 = 0; i2 < levelAt(i); i2++) { str.append(" "); } - str.append(effect).toString(); + str.append(effect).append('\n'); } } return str.toString(); diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Thu Mar 28 16:35:24 2013 +0100 @@ -26,12 +26,55 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.virtual.nodes.*; public class GraphEffectList extends EffectList { + public void addCounterBefore(final String name, final int increment, final boolean addContext, final FixedNode position) { + if (!DynamicCounterNode.enabled) { + return; + } + add(new Effect() { + + @Override + public String name() { + return "addCounterBefore"; + } + + @Override + public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { + assert position.isAlive(); + DynamicCounterNode node = graph.add(new DynamicCounterNode(name, increment, addContext)); + graph.addBeforeFixed(position, node); + node.setProbability(position.probability()); + } + }); + } + + public void addSurvivingCounterBefore(final String name, final int increment, final boolean addContext, final ValueNode checkedValue, final FixedNode position) { + if (!DynamicCounterNode.enabled) { + return; + } + add(new Effect() { + + @Override + public String name() { + return "addSurvivingCounterBefore"; + } + + @Override + public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { + assert position.isAlive(); + DynamicCounterNode node = graph.add(new SurvivingCounterNode(name, increment, addContext, checkedValue)); + graph.addBeforeFixed(position, node); + node.setProbability(position.probability()); + } + }); + } + /** * Adds the given fixed node to the graph's control flow, before position (so that the original * predecessor of position will then be node's predecessor). diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Thu Mar 28 16:35:24 2013 +0100 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011, 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.virtual.phases.ea; + +import java.util.*; +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; + +public class IterativeInliningPhase extends Phase { + + private final PhasePlan plan; + + private final GraalCodeCacheProvider runtime; + private final Assumptions assumptions; + private final GraphCache cache; + private final OptimisticOptimizations optimisticOpts; + + public IterativeInliningPhase(GraalCodeCacheProvider runtime, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) { + this.runtime = runtime; + this.assumptions = assumptions; + this.cache = cache; + this.plan = plan; + this.optimisticOpts = optimisticOpts; + } + + public static final void trace(String format, Object... obj) { + if (GraalOptions.TraceEscapeAnalysis) { + Debug.log(format, obj); + } + } + + @Override + protected void run(final StructuredGraph graph) { + runIterations(graph, true); + runIterations(graph, false); + } + + private void runIterations(final StructuredGraph graph, final boolean simple) { + Boolean continueIteration = true; + for (int iteration = 0; iteration < GraalOptions.EscapeAnalysisIterations && continueIteration; iteration++) { + continueIteration = Debug.scope("iteration " + iteration, new Callable() { + + @Override + public Boolean call() { + boolean progress = false; + PartialEscapeAnalysisPhase ea = new PartialEscapeAnalysisPhase(runtime, assumptions, false); + ea.apply(graph); + progress |= ea.hasChanged(); + + Map hints = GraalOptions.PEAInliningHints ? PartialEscapeAnalysisPhase.getHints(graph) : null; + + InliningPhase inlining = new InliningPhase(runtime, hints, assumptions, cache, plan, optimisticOpts); + inlining.setMaxMethodsPerInlining(simple ? 1 : Integer.MAX_VALUE); + inlining.apply(graph); + progress |= inlining.getInliningCount() > 0; + + new DeadCodeEliminationPhase().apply(graph); + + if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(runtime, assumptions).apply(graph); + new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph); + } + + return progress; + } + }); + } + } +} diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Thu Mar 28 16:35:24 2013 +0100 @@ -30,12 +30,15 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.debug.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.schedule.*; +import com.oracle.graal.virtual.nodes.*; import com.oracle.graal.virtual.phases.ea.EffectList.Effect; public class PartialEscapeAnalysisPhase extends Phase { @@ -45,12 +48,18 @@ private CustomCanonicalizer customCanonicalizer; private final boolean iterative; + private boolean changed; + public PartialEscapeAnalysisPhase(MetaAccessProvider runtime, Assumptions assumptions, boolean iterative) { this.runtime = runtime; this.assumptions = assumptions; this.iterative = iterative; } + public boolean hasChanged() { + return changed; + } + public void setCustomCanonicalizer(CustomCanonicalizer customCanonicalizer) { this.customCanonicalizer = customCanonicalizer; } @@ -61,25 +70,23 @@ } } - public static final void error(String format, Object... obj) { - System.out.print(String.format(format, obj)); - } - @Override protected void run(final StructuredGraph graph) { if (!matches(graph, GraalOptions.EscapeAnalyzeOnly)) { return; } - boolean analyzableNodes = false; - for (Node node : graph.getNodes()) { - if (node instanceof VirtualizableAllocation) { - analyzableNodes = true; - break; + if (!GraalOptions.PEAReadCache) { + boolean analyzableNodes = false; + for (Node node : graph.getNodes()) { + if (node instanceof VirtualizableAllocation) { + analyzableNodes = true; + break; + } } - } - if (!analyzableNodes) { - return; + if (!analyzableNodes) { + return; + } } Boolean continueIteration = true; @@ -88,14 +95,16 @@ @Override public Boolean call() { + SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph, false); PartialEscapeClosure closure = new PartialEscapeClosure(graph.createNodeBitMap(), schedule, runtime, assumptions); ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock(), new BlockState(), null); - if (closure.getNewVirtualObjectCount() == 0) { + if (!closure.hasChanged()) { return false; } + changed = true; // apply the effects collected during the escape analysis iteration ArrayList obsoleteNodes = new ArrayList<>(); @@ -104,20 +113,25 @@ } trace("%s\n", closure.getEffects()); - Debug.dump(graph, "after PartialEscapeAnalysis"); + Debug.dump(graph, "after PartialEscapeAnalysis iteration"); assert noObsoleteNodes(graph, obsoleteNodes); new DeadCodeEliminationPhase().apply(graph); - if (!iterative) { - return false; - } + if (GraalOptions.OptCanonicalizer) { new CanonicalizerPhase(runtime, assumptions, null, customCanonicalizer).apply(graph); } - return true; + + return iterative; } }); } + + for (Node node : graph.getNodes()) { + if (node instanceof LoadFieldNode) { + DynamicCounterNode.addCounterBefore("load non-elim", 1, false, (FixedNode) node); + } + } } private static boolean matches(StructuredGraph graph, String filter) { @@ -128,7 +142,7 @@ return true; } - private static boolean noObsoleteNodes(StructuredGraph graph, ArrayList obsoleteNodes) { + static boolean noObsoleteNodes(StructuredGraph graph, ArrayList obsoleteNodes) { // helper code that determines the paths that keep obsolete nodes alive: NodeFlood flood = graph.createNodeFlood(); @@ -153,7 +167,7 @@ for (Node node : obsoleteNodes) { if (node instanceof FixedNode) { - assert !flood.isMarked(node); + assert !flood.isMarked(node) : node; } } @@ -182,10 +196,10 @@ boolean success = true; for (Node node : obsoleteNodes) { if (flood.isMarked(node)) { - error("offending node path:"); + System.out.print("offending node path:"); Node current = node; while (current != null) { - error(current.toString()); + System.out.println(current.toString()); current = path.get(current); if (current != null && current instanceof FixedNode && !obsoleteNodes.contains(current)) { break; @@ -196,4 +210,39 @@ } return success; } + + public static Map getHints(StructuredGraph graph) { + Map hints = null; + for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) { + double sum = 0; + double invokeSum = 0; + for (Node usage : materialize.usages()) { + if (usage instanceof FixedNode) { + sum += ((FixedNode) usage).probability(); + } else { + if (usage instanceof MethodCallTargetNode) { + invokeSum += ((MethodCallTargetNode) usage).invoke().probability(); + } + for (Node secondLevelUage : materialize.usages()) { + if (secondLevelUage instanceof FixedNode) { + sum += ((FixedNode) secondLevelUage).probability(); + } + } + } + } + // TODO(lstadler) get rid of this magic number + if (sum > 100 && invokeSum > 0) { + for (Node usage : materialize.usages()) { + if (usage instanceof MethodCallTargetNode) { + if (hints == null) { + hints = new HashMap<>(); + } + Invoke invoke = ((MethodCallTargetNode) usage).invoke(); + hints.put(invoke, sum / invokeSum); + } + } + } + } + return hints; + } } diff -r fc0d57b82c86 -r a1a97de0dc9d graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Thu Mar 28 15:33:16 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Thu Mar 28 16:35:24 2013 +0100 @@ -34,14 +34,18 @@ import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.VirtualState.NodeClosure; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.phases.*; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; import com.oracle.graal.phases.graph.ReentrantBlockIterator.LoopInfo; import com.oracle.graal.phases.schedule.*; import com.oracle.graal.virtual.nodes.*; +import com.oracle.graal.virtual.phases.ea.BlockState.ReadCacheEntry; class PartialEscapeClosure extends BlockIteratorClosure { @@ -53,6 +57,11 @@ public static final DebugMetric METRIC_MATERIALIZATIONS_LOOP_END = Debug.metric("MaterializationsLoopEnd"); public static final DebugMetric METRIC_ALLOCATION_REMOVED = Debug.metric("AllocationsRemoved"); + public static final DebugMetric METRIC_STOREFIELD_RECORDED = Debug.metric("StoreFieldRecorded"); + public static final DebugMetric METRIC_LOADFIELD_ELIMINATED = Debug.metric("LoadFieldEliminated"); + public static final DebugMetric METRIC_LOADFIELD_NOT_ELIMINATED = Debug.metric("LoadFieldNotEliminated"); + public static final DebugMetric METRIC_MEMORYCHECKOINT = Debug.metric("MemoryCheckpoint"); + private final NodeBitMap usages; private final SchedulePhase schedule; @@ -60,12 +69,20 @@ private final VirtualizerToolImpl tool; + private final Map hints = new IdentityHashMap<>(); + + private boolean changed; + public PartialEscapeClosure(NodeBitMap usages, SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) { this.usages = usages; this.schedule = schedule; tool = new VirtualizerToolImpl(effects, usages, metaAccess, assumptions); } + public boolean hasChanged() { + return changed; + } + public GraphEffectList getEffects() { return effects; } @@ -74,6 +91,10 @@ return tool.getNewVirtualObjectCount(); } + public Map getHints() { + return hints; + } + @Override protected void processBlock(Block block, BlockState state) { trace("\nBlock: %s (", block); @@ -81,27 +102,68 @@ FixedWithNextNode lastFixedNode = null; for (Node node : nodeList) { + boolean deleted; if (usages.isMarked(node) || node instanceof VirtualizableAllocation) { trace("[[%s]] ", node); - processNode((ValueNode) node, lastFixedNode == null ? null : lastFixedNode.next(), state); + deleted = processNode((ValueNode) node, lastFixedNode == null ? null : lastFixedNode.next(), state); } else { trace("%s ", node); + deleted = false; } + if (GraalOptions.PEAReadCache) { + if (!deleted) { + if (node instanceof StoreFieldNode) { + METRIC_STOREFIELD_RECORDED.increment(); + StoreFieldNode store = (StoreFieldNode) node; + ValueNode cachedValue = state.getReadCache(store.object(), store.field()); + state.killReadCache(store.field()); - if (node instanceof FixedWithNextNode && node.isAlive()) { + if (cachedValue == store.value()) { + effects.addCounterBefore("store elim", 1, false, lastFixedNode.next()); + effects.deleteFixedNode(store); + changed = true; + } else { + state.addReadCache(store.object(), store.field(), store.value()); + } + } else if (node instanceof LoadFieldNode) { + LoadFieldNode load = (LoadFieldNode) node; + ValueNode cachedValue = state.getReadCache(load.object(), load.field()); + if (cachedValue != null) { + METRIC_LOADFIELD_ELIMINATED.increment(); + effects.addCounterBefore("load elim", 1, false, lastFixedNode.next()); + effects.replaceAtUsages(load, cachedValue); + state.addScalarAlias(load, cachedValue); + changed = true; + } else { + METRIC_LOADFIELD_NOT_ELIMINATED.increment(); + state.addReadCache(load.object(), load.field(), load); + } + } else if (node instanceof MemoryCheckpoint) { + METRIC_MEMORYCHECKOINT.increment(); + MemoryCheckpoint checkpoint = (MemoryCheckpoint) node; + for (Object identity : checkpoint.getLocationIdentities()) { + state.killReadCache(identity); + } + } + } + } + if (node instanceof FixedWithNextNode) { lastFixedNode = (FixedWithNextNode) node; } } trace(")\n end state: %s\n", state); } - private void processNode(final ValueNode node, FixedNode insertBefore, final BlockState state) { + private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockState state) { tool.reset(state, node); if (node instanceof Virtualizable) { ((Virtualizable) node).virtualize(tool); } if (tool.isDeleted()) { - return; + if (tool.isCustomAction() || !(node instanceof VirtualizableAllocation || node instanceof CyclicMaterializeStoreNode)) { + changed = true; + } + return true; } if (node instanceof StateSplit) { StateSplit split = (StateSplit) node; @@ -178,15 +240,20 @@ } } if (tool.isCustomAction()) { - return; + return false; } for (ValueNode input : node.inputs().filter(ValueNode.class)) { ObjectState obj = state.getObjectState(input); if (obj != null) { + if (obj.isVirtual() && node instanceof MethodCallTargetNode) { + Invoke invoke = ((MethodCallTargetNode) node).invoke(); + hints.put(invoke, 5d); + } trace("replacing input %s at %s: %s", input, node, obj); replaceWithMaterialized(input, node, insertBefore, state, obj, METRIC_MATERIALIZATIONS_UNHANDLED); } } + return false; } private void ensureMaterialized(BlockState state, ObjectState obj, FixedNode materializeBefore, DebugMetric metric) { @@ -207,7 +274,6 @@ @Override protected BlockState merge(MergeNode merge, List states) { - BlockState newState = BlockState.meetAliases(states); // Iterative processing: @@ -300,13 +366,15 @@ } } - for (PhiNode phi : merge.phis().snapshot()) { + for (PhiNode phi : merge.phis()) { if (usages.isMarked(phi) && phi.type() == PhiType.Value) { materialized |= processPhi(newState, merge, phi, states); } } } while (materialized); + newState.mergeReadCache(states, merge, effects); + return newState; } @@ -373,7 +441,7 @@ } @Override - protected BlockState afterSplit(FixedNode node, BlockState oldState) { + protected BlockState cloneState(BlockState oldState) { return oldState.cloneState(); } @@ -421,11 +489,13 @@ List loopEndStates = info.endStates; List predecessors = loop.header.getPredecessors(); HashSet additionalMaterializations = new HashSet<>(); + HashSet additionalKilledReads = new HashSet<>(); int oldPhiCount = phis.size(); for (int i = 1; i < predecessors.size(); i++) { - processLoopEnd(loop.loopBegin(), (LoopEndNode) predecessors.get(i).getEndNode(), state, loopEndStates.get(i - 1), successEffects, additionalMaterializations, phis); + processLoopEnd(loop.loopBegin(), (LoopEndNode) predecessors.get(i).getEndNode(), state, loopEndStates.get(i - 1), successEffects, additionalMaterializations, additionalKilledReads, + phis); } - if (additionalMaterializations.isEmpty() && oldPhiCount == phis.size()) { + if (additionalMaterializations.isEmpty() && additionalKilledReads.isEmpty() && oldPhiCount == phis.size()) { effects.addAll(successEffects); assert info.exitStates.size() == loop.exits.size(); @@ -450,6 +520,9 @@ assert obj.getState() == EscapeState.Global; } } + for (ReadCacheEntry entry : additionalKilledReads) { + initialState.getReadCache().remove(entry); + } } } @@ -473,7 +546,7 @@ ObjectState valueObj = exitState.getObjectState(value); if (valueObj == null) { if ((value instanceof PhiNode && ((PhiNode) value).merge() == exitNode.loopBegin()) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) { - ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value); + ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null); obj.setEntry(i, proxy); effects.addFloatingNode(proxy); } @@ -483,7 +556,7 @@ if (initialObj == null || initialObj.isVirtual()) { ProxyNode proxy = proxies.get(obj.virtual); if (proxy == null) { - proxy = new ProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value); + proxy = new ProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value, null); effects.addFloatingNode(proxy); } else { effects.replaceFirstInput(proxy, proxy.value(), obj.getMaterializedValue()); @@ -492,10 +565,18 @@ obj.updateMaterializedValue(proxy); } else { assert initialObj.getMaterializedValue() == obj.getMaterializedValue() : "materialized value is not allowed to change within loops: " + initialObj.getMaterializedValue() + - " vs. " + obj.getMaterializedValue(); + " vs. " + obj.getMaterializedValue() + " at " + exitNode; } } } + + for (Map.Entry entry : exitState.getReadCache().entrySet()) { + if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) { + ProxyNode proxy = new ProxyNode(exitState.getReadCache(entry.getKey().object, entry.getKey().identity), exitNode, PhiType.Value, null); + effects.addFloatingNode(proxy); + entry.setValue(proxy); + } + } } private final class PhiDesc { @@ -530,7 +611,7 @@ } private void processLoopEnd(LoopBeginNode loopBegin, LoopEndNode loopEnd, BlockState initialState, BlockState loopEndState, GraphEffectList successEffects, - Set additionalMaterializations, HashSet phis) { + Set additionalMaterializations, HashSet additionalKilledReads, HashSet phis) { assert loopEnd.loopBegin() == loopBegin; boolean materialized; do { @@ -573,7 +654,7 @@ } } } - for (PhiNode phi : loopBegin.phis().snapshot()) { + for (PhiNode phi : loopBegin.phis()) { if (usages.isMarked(phi) && phi.type() == PhiType.Value) { ObjectState initialObj = initialState.getObjectState(phi.valueAt(0)); boolean initialMaterialized = initialObj == null || !initialObj.isVirtual(); @@ -662,5 +743,11 @@ } } } + + for (Map.Entry entry : initialState.getReadCache().entrySet()) { + if (loopEndState.getReadCache().get(entry.getKey()) != entry.getValue()) { + additionalKilledReads.add(entry.getKey()); + } + } } } diff -r fc0d57b82c86 -r a1a97de0dc9d mx/commands.py --- a/mx/commands.py Thu Mar 28 15:33:16 2013 +0100 +++ b/mx/commands.py Thu Mar 28 16:35:24 2013 +0100 @@ -1025,7 +1025,7 @@ vm = _vm if len(args) is 0: args = ['all'] - + vmArgs = [arg for arg in args if arg.startswith('-')] def benchmarks_in_group(group):