# HG changeset patch # User Christian Haeubl # Date 1364992882 -7200 # Node ID 6d884611d4c1b3992006f29c70de4bef7bfc0425 # Parent d343737786fe4be683b62d2fbba02078283be13a# Parent c7672a325fafa7cae55d2ef0861dc9d194dc3d2e Merge. diff -r d343737786fe -r 6d884611d4c1 .hgignore --- a/.hgignore Thu Mar 28 17:11:06 2013 +0100 +++ b/.hgignore Wed Apr 03 14:41:22 2013 +0200 @@ -67,5 +67,6 @@ *.bgv core.* *.jar +*.jar.* eclipse-build.xml rebuild-launch.out diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java Wed Apr 03 14:41:22 2013 +0200 @@ -43,11 +43,6 @@ InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult); /** - * Returns the size in bytes for locking information on the stack. - */ - int getSizeOfLockData(); - - /** * Returns a disassembly of some compiled code. * * @param compResult some compiled code diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/MonitorValue.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/MonitorValue.java Thu Mar 28 17:11:06 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * 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.api.code; - -import com.oracle.graal.api.meta.*; - -/** - * Represents lock information in the debug information. - */ -public final class MonitorValue extends Value { - - private static final long serialVersionUID = 8241681800464483691L; - - private Value owner; - private final Value lockData; - private final boolean eliminated; - - public MonitorValue(Value owner, Value lockData, boolean eliminated) { - super(Kind.Illegal); - this.owner = owner; - this.lockData = lockData; - this.eliminated = eliminated; - } - - public Value getOwner() { - return owner; - } - - public void setOwner(Value newOwner) { - this.owner = newOwner; - } - - public Value getLockData() { - return lockData; - } - - public boolean isEliminated() { - return eliminated; - } - - @Override - public String toString() { - return "monitor[" + owner + (lockData != null ? ", " + lockData : "") + (eliminated ? ", eliminated" : "") + "]"; - } -} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Graal.java --- a/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Graal.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/Graal.java Wed Apr 03 14:41:22 2013 +0200 @@ -36,26 +36,38 @@ try { runtime = initializeRuntime(); } catch (UnsatisfiedLinkError e) { - runtime = new GraalRuntime() { - - @Override - public String getName() { - return ""; - } - - @Override - public T getCapability(Class clazz) { - return null; - } - }; + runtime = new InvalidGraalRuntime(); } } public static T getRequiredCapability(Class clazz) { T t = getRuntime().getCapability(clazz); if (t == null) { - throw new IllegalAccessError("Runtime does not expose required capability " + clazz.getName()); + String javaHome = System.getProperty("java.home"); + String vmName = System.getProperty("java.vm.name"); + StringBuilder errorMessage = new StringBuilder(); + if (runtime.getClass() == InvalidGraalRuntime.class) { + errorMessage.append(String.format("The VM does not support the Graal API.\n")); + } else { + errorMessage.append(String.format("The VM does not expose required Graal capability %s.\n", clazz.getName())); + } + errorMessage.append(String.format("Currently used Java home directory is %s.\n", javaHome)); + errorMessage.append(String.format("Currently used VM configuration is: %s", vmName)); + throw new UnsupportedOperationException(errorMessage.toString()); } return t; } + + private static final class InvalidGraalRuntime implements GraalRuntime { + + @Override + public String getName() { + return ""; + } + + @Override + public T getCapability(Class clazz) { + return null; + } + } } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.compiler.ptx.test; +import java.lang.reflect.*; + import org.junit.*; import com.oracle.graal.api.code.*; @@ -35,7 +37,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.*; -import com.oracle.graal.phases.PhasePlan.*; +import com.oracle.graal.phases.PhasePlan.PhasePosition; import com.oracle.graal.ptx.*; /** @@ -90,7 +92,12 @@ public static void main(String[] args) { BasicPTXTest basicPTXTest = new BasicPTXTest(); - System.out.println("testAddSnippet: \n" + new String(basicPTXTest.test("testAddSnippet").getTargetCode())); - System.out.println("testArraySnippet: \n" + new String(basicPTXTest.test("testArraySnippet").getTargetCode())); + Method[] methods = BasicPTXTest.class.getMethods(); + for (Method m : methods) { + if (m.getAnnotation(Test.class) != null) { + String name = m.getName() + "Snippet"; + System.out.println(name + ": \n" + new String(basicPTXTest.test(name).getTargetCode())); + } + } } } diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -71,11 +71,15 @@ protected final Backend backend; public GraalCompilerTest() { - DebugEnvironment.initialize(System.out); this.runtime = Graal.getRequiredCapability(GraalCodeCacheProvider.class); this.backend = Graal.getRequiredCapability(Backend.class); } + @BeforeClass + public static void initializeDebgging() { + DebugEnvironment.initialize(System.out); + } + protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { String expectedString = getCanonicalGraphString(expected); String actualString = getCanonicalGraphString(graph); diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Apr 03 14:41:22 2013 +0200 @@ -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); + } } } @@ -164,16 +168,16 @@ } new RemoveValueProxyPhase().apply(graph); + if (GraalOptions.CullFrameStates) { + new CullFrameStatesPhase().apply(graph); + } + if (GraalOptions.OptCanonicalizer) { new CanonicalizerPhase(runtime, assumptions).apply(graph); } new LoweringPhase(target, runtime, assumptions).apply(graph); - if (GraalOptions.CullFrameStates) { - new CullFrameStatesPhase().apply(graph); - } - if (GraalOptions.OptFloatingReads) { int mark = graph.getMark(); new FloatingReadPhase().apply(graph); diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Wed Apr 03 14:41:22 2013 +0200 @@ -34,18 +34,21 @@ import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.virtual.nodes.*; +/** + * Builds {@link LIRFrameState}s from {@link FrameState}s. + */ public class DebugInfoBuilder { - private final NodeMap nodeOperands; + protected final NodeMap nodeOperands; public DebugInfoBuilder(NodeMap nodeOperands) { this.nodeOperands = nodeOperands; } - private HashMap virtualObjects = new HashMap<>(); - private IdentityHashMap objectStates = new IdentityHashMap<>(); + protected HashMap virtualObjects = new HashMap<>(); + protected IdentityHashMap objectStates = new IdentityHashMap<>(); - public LIRFrameState build(FrameState topState, List lockData, short reason, LabelRef exceptionEdge) { + public LIRFrameState build(FrameState topState, short reason, LabelRef exceptionEdge) { assert virtualObjects.size() == 0; assert objectStates.size() == 0; @@ -65,7 +68,7 @@ current = current.outerFrameState(); } while (current != null); - BytecodeFrame frame = computeFrameForState(topState, lockData); + BytecodeFrame frame = computeFrameForState(topState); VirtualObject[] virtualObjectsArray = null; if (virtualObjects.size() != 0) { @@ -103,43 +106,62 @@ } objectStates.clear(); + return newLIRFrameState(reason, exceptionEdge, frame, virtualObjectsArray); + } + + protected LIRFrameState newLIRFrameState(short reason, LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) { return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge, reason); } - private BytecodeFrame computeFrameForState(FrameState state, List lockDataSlots) { + protected BytecodeFrame computeFrameForState(FrameState state) { int numLocals = state.localsSize(); int numStack = state.stackSize(); int numLocks = state.locksSize(); Value[] values = new Value[numLocals + numStack + numLocks]; - for (int i = 0; i < numLocals; i++) { - values[i] = toValue(state.localAt(i)); - } - for (int i = 0; i < numStack; i++) { - values[numLocals + i] = toValue(state.stackAt(i)); - } - for (int i = 0; i < numLocks; i++) { - // frames are traversed from the outside in, so the locks for the current frame are at - // the end of the lockDataSlots list - StackSlot lockData = lockDataSlots.get(lockDataSlots.size() - numLocks + i); - values[numLocals + numStack + i] = new MonitorValue(toValue(state.lockAt(i)), lockData, state.lockAt(i) instanceof VirtualObjectNode); - } + computeLocals(state, numLocals, values); + computeStack(state, numLocals, numStack, values); + computeLocks(state, values); BytecodeFrame caller = null; if (state.outerFrameState() != null) { - // remove the locks that were used for this frame from the lockDataSlots list - List nextLockDataSlots = lockDataSlots.subList(0, lockDataSlots.size() - numLocks); - caller = computeFrameForState(state.outerFrameState(), nextLockDataSlots); - } else { - if (lockDataSlots.size() != numLocks) { - throw new BailoutException("unbalanced monitors: found monitor for unknown frame (%d != %d) at %s", lockDataSlots.size(), numLocks, state); - } + caller = computeFrameForState(state.outerFrameState()); } assert state.bci >= 0 || state.bci == FrameState.BEFORE_BCI : "bci == " + state.bci; return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks); } - private Value toValue(ValueNode value) { + protected void computeLocals(FrameState state, int numLocals, Value[] values) { + for (int i = 0; i < numLocals; i++) { + values[i] = computeLocalValue(state, i); + } + } + + protected Value computeLocalValue(FrameState state, int i) { + return toValue(state.localAt(i)); + } + + protected void computeStack(FrameState state, int numLocals, int numStack, Value[] values) { + for (int i = 0; i < numStack; i++) { + values[numLocals + i] = computeStackValue(state, i); + } + } + + protected Value computeStackValue(FrameState state, int i) { + return toValue(state.stackAt(i)); + } + + protected void computeLocks(FrameState state, Value[] values) { + for (int i = 0; i < state.locksSize(); i++) { + values[state.localsSize() + state.stackSize() + i] = computeLockValue(state, i); + } + } + + protected Value computeLockValue(FrameState state, int i) { + return toValue(state.lockAt(i)); + } + + protected Value toValue(ValueNode value) { if (value instanceof VirtualObjectNode) { VirtualObjectNode obj = (VirtualObjectNode) value; EscapeObjectState state = objectStates.get(obj); diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed Apr 03 14:41:22 2013 +0200 @@ -63,7 +63,7 @@ protected final TargetDescription target; protected final ResolvedJavaMethod method; - private final DebugInfoBuilder debugInfoBuilder; + protected final DebugInfoBuilder debugInfoBuilder; protected Block currentBlock; private ValueNode currentInstruction; @@ -76,22 +76,6 @@ private final BlockMap blockLastState; /** - * The number of currently locked monitors. - */ - private int currentLockCount; - - /** - * Mapping from blocks to the number of locked monitors at the end of the block. - */ - private final BlockMap blockLastLockCount; - - /** - * Contains the lock data slot for each lock depth (so these may be reused within a compiled - * method). - */ - private final ArrayList lockDataSlots; - - /** * Checks whether the supplied constant can be used without loading it into a register for store * operations, i.e., on the right hand side of a memory access. * @@ -109,12 +93,15 @@ this.method = method; this.nodeOperands = graph.createNodeMap(); this.lir = lir; - this.debugInfoBuilder = new DebugInfoBuilder(nodeOperands); - this.blockLastLockCount = new BlockMap<>(lir.cfg); - this.lockDataSlots = new ArrayList<>(); + this.debugInfoBuilder = createDebugInfoBuilder(nodeOperands); this.blockLastState = new BlockMap<>(lir.cfg); } + @SuppressWarnings("hiding") + protected DebugInfoBuilder createDebugInfoBuilder(NodeMap nodeOperands) { + return new DebugInfoBuilder(nodeOperands); + } + @Override public TargetDescription target() { return target; @@ -248,7 +235,7 @@ if (needOnlyOopMaps()) { return new LIRFrameState(null, null, null, (short) -1); } - return debugInfoBuilder.build(state, lockDataSlots.subList(0, currentLockCount), lir.getDeoptimizationReasons().addSpeculation(reason), exceptionEdge); + return debugInfoBuilder.build(state, lir.getDeoptimizationReasons().addSpeculation(reason), exceptionEdge); } /** @@ -297,22 +284,10 @@ if (block == lir.cfg.getStartBlock()) { assert block.getPredecessorCount() == 0; - currentLockCount = 0; emitPrologue(); } else { assert block.getPredecessorCount() > 0; - - currentLockCount = -1; - for (Block pred : block.getPredecessors()) { - Integer predLocks = blockLastLockCount.get(pred); - if (currentLockCount == -1) { - currentLockCount = predLocks; - } else { - assert (predLocks == null && pred.isLoopEnd()) || currentLockCount == predLocks; - } - } - FrameState fs = null; for (Block pred : block.getPredecessors()) { @@ -401,7 +376,6 @@ // share the frame state that flowed into the loop assert blockLastState.get(block) == null || blockLastState.get(block) == lastState; - blockLastLockCount.put(currentBlock, currentLockCount); blockLastState.put(block, lastState); currentBlock = null; @@ -480,36 +454,6 @@ append(new ParametersOp(params)); } - /** - * Increases the number of currently locked monitors and makes sure that a lock data slot is - * available for the new lock. - */ - public void lock() { - if (lockDataSlots.size() == currentLockCount) { - lockDataSlots.add(frameMap.allocateStackBlock(runtime.getSizeOfLockData(), false)); - } - currentLockCount++; - } - - /** - * Decreases the number of currently locked monitors. - * - * @throws GraalInternalError if the number of currently locked monitors is already zero. - */ - public void unlock() { - if (currentLockCount == 0) { - throw new GraalInternalError("unmatched locks"); - } - currentLockCount--; - } - - /** - * @return The lock data slot for the topmost locked monitor. - */ - public StackSlot peekLock() { - return lockDataSlots.get(currentLockCount - 1); - } - @Override public void visitReturn(ReturnNode x) { Value operand = Value.ILLEGAL; diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Wed Apr 03 14:41:22 2013 +0200 @@ -197,6 +197,7 @@ if (inputChanged != null) { inputChanged.inputChanged(this); } + assert newInput.usages != null : "not yet added? " + newInput; newInput.usages.add(this); } } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Wed Apr 03 14:41:22 2013 +0200 @@ -35,6 +35,8 @@ import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.AMD64Address.*; import com.oracle.graal.compiler.amd64.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; @@ -84,6 +86,19 @@ */ List epilogueOps = new ArrayList<>(2); + @SuppressWarnings("hiding") + @Override + protected DebugInfoBuilder createDebugInfoBuilder(NodeMap nodeOperands) { + assert runtime().config.basicLockSize == 8; + HotSpotLockStack lockStack = new HotSpotLockStack(frameMap, Kind.Long); + return new HotSpotDebugInfoBuilder(nodeOperands, lockStack); + } + + @Override + public StackSlot getLockSlot(int lockDepth) { + return ((HotSpotDebugInfoBuilder) debugInfoBuilder).lockStack().makeLockSlot(lockDepth); + } + @Override protected void emitPrologue() { diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/InstalledCodeExecuteHelperTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/InstalledCodeExecuteHelperTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.spi.*; + +public class InstalledCodeExecuteHelperTest extends GraalCompilerTest { + + private static final int ITERATIONS = 100000000; + + @Ignore + @Test + public void test1() throws NoSuchMethodException, SecurityException { + + final Method benchrMethod = InstalledCodeExecuteHelperTest.class.getMethod("bench", long.class, long.class); + final ResolvedJavaMethod benchJavaMethod = Graal.getRequiredCapability(GraalCodeCacheProvider.class).lookupJavaMethod(benchrMethod); + HotSpotInstalledCode benchCode = (HotSpotInstalledCode) getCode(benchJavaMethod, parse(benchrMethod)); + + final Method wrapperMethod = InstalledCodeExecuteHelperTest.class.getMethod("executeWrapper", long.class, long.class, Object.class, Object.class, Object.class); + final ResolvedJavaMethod wrapperJavaMethod = Graal.getRequiredCapability(GraalCodeCacheProvider.class).lookupJavaMethod(wrapperMethod); + HotSpotInstalledCode wrapperCode = (HotSpotInstalledCode) getCode(wrapperJavaMethod, parse(wrapperMethod)); + + final Method fooMethod = InstalledCodeExecuteHelperTest.class.getMethod("foo", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) Graal.getRequiredCapability(GraalCodeCacheProvider.class).lookupJavaMethod(fooMethod); + HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + + System.out.println(wrapperCode.executeVarargs(fooCode.getnmethod(), fooJavaMethod.getMetaspaceMethod(), null, null, null)); + + long nmethod = fooCode.getnmethod(); + long metaspacemethod = fooJavaMethod.getMetaspaceMethod(); + + System.out.println("Without replaced InstalledCode.execute:" + bench(nmethod, metaspacemethod)); + + System.out.println("WITH replaced InstalledCode.execute:" + benchCode.executeVarargs(nmethod, metaspacemethod)); + + } + + public static Long bench(long nmethod, long metaspacemethod) { + long start = System.currentTimeMillis(); + + for (int i = 0; i < ITERATIONS; i++) { + HotSpotInstalledCode.executeHelper(nmethod, metaspacemethod, null, null, null); + } + + long end = System.currentTimeMillis(); + return (end - start); + } + + public static Object foo(@SuppressWarnings("unused") Object a1, @SuppressWarnings("unused") Object a2, @SuppressWarnings("unused") Object a3) { + return 42; + } + + public static Object executeWrapper(long nmethod, long metaspaceMethod, Object arg1, Object arg2, Object arg3) { + return HotSpotInstalledCode.executeHelper(nmethod, metaspaceMethod, arg1, arg2, arg3); + } + +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,67 @@ +/* + * 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.hotspot; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.virtual.*; + +/** + * Extends {@link DebugInfoBuilder} to allocate the extra debug information required for locks. + */ +public class HotSpotDebugInfoBuilder extends DebugInfoBuilder { + + private final HotSpotLockStack lockStack; + + public HotSpotDebugInfoBuilder(NodeMap nodeOperands, HotSpotLockStack lockStack) { + super(nodeOperands); + this.lockStack = lockStack; + } + + public HotSpotLockStack lockStack() { + return lockStack; + } + + @Override + protected Value computeLockValue(FrameState state, int i) { + int lockDepth = i; + if (state.outerFrameState() != null) { + lockDepth = state.outerFrameState().nestedLockDepth(); + } + StackSlot slot = lockStack.makeLockSlot(lockDepth); + ValueNode lock = state.lockAt(i); + Value object = toValue(lock); + boolean eliminated = lock instanceof VirtualObjectNode; + return new HotSpotMonitorValue(object, slot, eliminated); + } + + @Override + protected LIRFrameState newLIRFrameState(short reason, LabelRef exceptionEdge, BytecodeFrame frame, VirtualObject[] virtualObjectsArray) { + return new HotSpotLIRFrameState(frame, virtualObjectsArray, exceptionEdge, reason); + } +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRFrameState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRFrameState.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,53 @@ +/* + * 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.hotspot; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.LIRInstruction.ValueProcedure; + +/** + * Extends {@link LIRFrameState} to handle {@link HotSpotMonitorValue}s correctly. + */ +class HotSpotLIRFrameState extends LIRFrameState { + + public HotSpotLIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge, short deoptimizationReason) { + super(topFrame, virtualObjects, exceptionEdge, deoptimizationReason); + } + + @Override + protected Value processValue(ValueProcedure proc, Value value) { + if (value instanceof HotSpotMonitorValue) { + HotSpotMonitorValue monitor = (HotSpotMonitorValue) value; + if (processed(monitor.getOwner())) { + monitor.setOwner(proc.doValue(monitor.getOwner(), OperandMode.ALIVE, STATE_FLAGS)); + } + return value; + } else { + return super.processValue(proc, value); + } + } +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRGenerator.java Wed Apr 03 14:41:22 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.hotspot; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.hotspot.nodes.*; @@ -42,4 +43,9 @@ void emitTailcall(Value[] args, Value address); void visitDirectCompareAndSwap(DirectCompareAndSwapNode x); + + /** + * Gets a stack slot for a lock at a given lock nesting depth. + */ + StackSlot getLockSlot(int lockDepth); } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLockStack.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLockStack.java Wed Apr 03 14:41:22 2013 +0200 @@ -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.hotspot; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.lir.*; + +/** + * Manages allocation and re-use of lock slots in a scoped manner. The slots are used in HotSpot's + * lightweight locking mechanism to store the mark word of an object being locked. + */ +public class HotSpotLockStack { + + private StackSlot[] locks; + private final FrameMap frameMap; + private final Kind slotKind; + + public HotSpotLockStack(FrameMap frameMap, Kind slotKind) { + this.frameMap = frameMap; + this.slotKind = slotKind; + } + + /** + * Gets a stack slot for a lock at a given lock nesting depth, allocating it first if necessary. + */ + public StackSlot makeLockSlot(int lockDepth) { + if (locks == null) { + locks = new StackSlot[lockDepth + 1]; + } else if (locks.length < lockDepth + 1) { + locks = Arrays.copyOf(locks, lockDepth + 1); + } + if (locks[lockDepth] == null) { + locks[lockDepth] = frameMap.allocateSpillSlot(slotKind); + } + return locks[lockDepth]; + } +} diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java Wed Apr 03 14:41:22 2013 +0200 @@ -51,6 +51,10 @@ return isDefault; } + public long getnmethod() { + return nmethod; + } + @Override public ResolvedJavaMethod getMethod() { return method; @@ -104,4 +108,8 @@ public byte[] getCode() { return HotSpotGraalRuntime.getInstance().getCompilerToVM().getCode(nmethod); } + + public static Object executeHelper(long nmethod, long metaspaceMethod, Object arg1, Object arg2, Object arg3) { + return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethod(metaspaceMethod, nmethod, arg1, arg2, arg3); + } } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMonitorValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMonitorValue.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,66 @@ +/* + * 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.hotspot.meta; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; + +/** + * Represents lock information in the debug information. + */ +public final class HotSpotMonitorValue extends Value { + + private static final long serialVersionUID = 8241681800464483691L; + + private Value owner; + private final StackSlot slot; + private final boolean eliminated; + + public HotSpotMonitorValue(Value owner, StackSlot slot, boolean eliminated) { + super(Kind.Illegal); + this.owner = owner; + this.slot = slot; + this.eliminated = eliminated; + } + + public Value getOwner() { + return owner; + } + + public void setOwner(Value newOwner) { + this.owner = newOwner; + } + + public Value getSlot() { + return slot; + } + + public boolean isEliminated() { + return eliminated; + } + + @Override + public String toString() { + return "monitor[" + owner + (slot != null ? ", " + slot : "") + (eliminated ? ", eliminated" : "") + "]"; + } +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Wed Apr 03 14:41:22 2013 +0200 @@ -73,6 +73,10 @@ return holder; } + public long getMetaspaceMethod() { + return metaspaceMethod; + } + /** * Gets the address of the C++ Method object for this method. */ diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Wed Apr 03 14:41:22 2013 +0200 @@ -487,11 +487,6 @@ } @Override - public int getSizeOfLockData() { - return config.basicLockSize; - } - - @Override public boolean constantEquals(Constant x, Constant y) { return x.equals(y); } @@ -529,8 +524,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 +563,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) { @@ -611,12 +605,18 @@ FixedWithNextNode first = memoryWrite; if (field.getKind() == Kind.Object && !memoryWrite.value().objectStamp().alwaysNull()) { - WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(memoryWrite.object(), null, memoryWrite.location(), true)); - WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(memoryWrite.object(), memoryWrite.value(), memoryWrite.location(), false)); - graph.addBeforeFixed(memoryWrite, writeBarrierPre); - graph.addAfterFixed(memoryWrite, writeBarrierPost); - first = writeBarrierPre; - last = writeBarrierPost; + if (config.useG1GC) { + WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(memoryWrite.object(), null, memoryWrite.location(), true)); + WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(memoryWrite.object(), memoryWrite.value(), memoryWrite.location(), false)); + graph.addBeforeFixed(memoryWrite, writeBarrierPre); + graph.addAfterFixed(memoryWrite, writeBarrierPost); + first = writeBarrierPre; + last = writeBarrierPost; + } else { + FieldWriteBarrier writeBarrier = graph.add(new FieldWriteBarrier(memoryWrite.object())); + graph.addAfterFixed(memoryWrite, writeBarrier); + last = writeBarrier; + } } if (storeField.isVolatile()) { MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); @@ -631,14 +631,25 @@ LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1); if (expected.kind() == Kind.Object && !cas.newValue().objectStamp().alwaysNull()) { ResolvedJavaType type = cas.object().objectStamp().type(); - WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(cas.object(), null, location, true)); - graph.addBeforeFixed(cas, writeBarrierPre); if (type != null && !type.isArray() && !MetaUtil.isJavaLangObject(type)) { - WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(cas.object(), cas.newValue(), location, false)); - graph.addAfterFixed(cas, writeBarrierPost); + // Use a field write barrier since it's not an array store + if (config.useG1GC) { + WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(cas.object(), null, location, true)); + WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(cas.object(), cas.newValue(), location, false)); + graph.addBeforeFixed(cas, writeBarrierPre); + graph.addAfterFixed(cas, writeBarrierPost); + } else { + graph.addAfterFixed(cas, graph.add(new FieldWriteBarrier(cas.object()))); + } } else { - WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(cas.object(), cas.newValue(), location, true)); - graph.addAfterFixed(cas, writeBarrierPost); + // This may be an array store so use an array write barrier + if (config.useG1GC) { + WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(cas.object(), null, location, true)); + graph.addBeforeFixed(cas, writeBarrierPre); + graph.addAfterFixed(cas, graph.add(new WriteBarrierPost(cas.object(), cas.newValue(), location, true))); + } else { + graph.addAfterFixed(cas, graph.add(new ArrayWriteBarrier(cas.object(), location))); + } } } } else if (n instanceof LoadIndexedNode) { @@ -682,10 +693,14 @@ graph.replaceFixedWithFixed(storeIndexed, memoryWrite); if (elementKind == Kind.Object && !value.objectStamp().alwaysNull()) { - WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(array, null, arrayLocation, true)); - graph.addBeforeFixed(memoryWrite, writeBarrierPre); - WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(array, value, arrayLocation, true)); - graph.addAfterFixed(memoryWrite, writeBarrierPost); + if (config.useG1GC) { + WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(array, null, arrayLocation, true)); + graph.addBeforeFixed(memoryWrite, writeBarrierPre); + WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(array, value, arrayLocation, true)); + graph.addAfterFixed(memoryWrite, writeBarrierPost); + } else { + graph.addAfterFixed(memoryWrite, graph.add(new ArrayWriteBarrier(array, arrayLocation))); + } } } else if (n instanceof UnsafeLoadNode) { UnsafeLoadNode load = (UnsafeLoadNode) n; @@ -705,12 +720,25 @@ graph.replaceFixedWithFixed(store, write); if (write.value().kind() == Kind.Object && !write.value().objectStamp().alwaysNull()) { ResolvedJavaType type = object.objectStamp().type(); - WriteBarrierPre writeBarrierPre = new WriteBarrierPre(object, null, location, true); - graph.addBeforeFixed(write, graph.add(writeBarrierPre)); + // WriteBarrier writeBarrier; if (type != null && !type.isArray() && !MetaUtil.isJavaLangObject(type)) { - graph.addAfterFixed(write, graph.add(new WriteBarrierPost(object, write.value(), location, false))); + // Use a field write barrier since it's not an array store + if (config.useG1GC) { + WriteBarrierPre writeBarrierPre = new WriteBarrierPre(object, null, location, true); + graph.addBeforeFixed(write, graph.add(writeBarrierPre)); + graph.addAfterFixed(write, graph.add(new WriteBarrierPost(object, write.value(), location, false))); + } else { + graph.addAfterFixed(write, graph.add(new FieldWriteBarrier(object))); + } } else { - graph.addAfterFixed(write, graph.add(new WriteBarrierPost(object, write.value(), location, true))); + // This may be an array store so use an array write barrier + if (config.useG1GC) { + WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(object, null, location, true)); + graph.addBeforeFixed(write, writeBarrierPre); + graph.addAfterFixed(write, graph.add(new WriteBarrierPost(object, write.value(), location, true))); + } else { + graph.addAfterFixed(write, graph.add(new ArrayWriteBarrier(object, location))); + } } } } else if (n instanceof LoadHubNode) { @@ -743,12 +771,14 @@ monitorSnippets.lower((MonitorEnterNode) n, tool); } else if (n instanceof MonitorExitNode) { monitorSnippets.lower((MonitorExitNode) n, tool); - } else if (n instanceof SerialWriteBarrierPost) { - writeBarrierSnippets.lower((SerialWriteBarrierPost) n, tool); - } else if (n instanceof G1WriteBarrierPre) { - writeBarrierSnippets.lower((G1WriteBarrierPre) n, tool); - } else if (n instanceof G1WriteBarrierPost) { - writeBarrierSnippets.lower((G1WriteBarrierPost) n, tool); + } else if (n instanceof FieldWriteBarrier) { + writeBarrierSnippets.lower((FieldWriteBarrier) n, tool); + } else if (n instanceof ArrayWriteBarrier) { + writeBarrierSnippets.lower((ArrayWriteBarrier) n, tool); + } else if (n instanceof WriteBarrierPre) { + writeBarrierSnippets.lower((WriteBarrierPre) n, tool); + } else if (n instanceof WriteBarrierPost) { + writeBarrierSnippets.lower((WriteBarrierPost) n, tool); } else if (n instanceof TLABAllocateNode) { newObjectSnippets.lower((TLABAllocateNode) n, tool); } else if (n instanceof InitializeObjectNode) { @@ -773,10 +803,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 +812,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 d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayWriteBarrier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayWriteBarrier.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.nodes; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public final class ArrayWriteBarrier extends FixedWithNextNode implements Lowerable { + + @Input private ValueNode object; + @Input private LocationNode location; + + public ValueNode getObject() { + return object; + } + + public LocationNode getLocation() { + return location; + } + + public ArrayWriteBarrier(ValueNode object, LocationNode location) { + super(StampFactory.forVoid()); + this.object = object; + this.location = location; + } + + public void lower(LoweringTool generator) { + generator.getRuntime().lower(this, generator); + } +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; +import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.type.*; @@ -37,15 +38,25 @@ * is locked (ensuring the GC sees and updates the object) so it must come after any null pointer * check on the object. */ -public final class BeginLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorEnter { +public final class BeginLockScopeNode extends AbstractStateSplit implements LIRGenLowerable, MonitorEnter, MonitorReference { private final boolean eliminated; + private int lockDepth = -1; + public BeginLockScopeNode(boolean eliminated) { super(StampFactory.forWord()); this.eliminated = eliminated; } + public int getLockDepth() { + return lockDepth; + } + + public void setLockDepth(int lockDepth) { + this.lockDepth = lockDepth; + } + @Override public boolean hasSideEffect() { return false; @@ -58,11 +69,12 @@ @Override public void generate(LIRGenerator gen) { - gen.lock(); - StackSlot lockData = gen.peekLock(); + assert lockDepth != -1; assert stateAfter() != null; + HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen; + StackSlot slot = hsGen.getLockSlot(lockDepth); if (!eliminated) { - Value result = gen.emitLea(lockData); + Value result = gen.emitLea(slot); gen.setResult(this, result); } } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -22,26 +22,42 @@ */ package com.oracle.graal.hotspot.nodes; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; +import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.word.*; /** * Intrinsic for getting the lock in the current {@linkplain BeginLockScopeNode lock scope}. */ -public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable { +public final class CurrentLockNode extends FixedWithNextNode implements LIRGenLowerable, MonitorReference { + + private int lockDepth = -1; public CurrentLockNode() { super(StampFactory.forWord()); } + public int getLockDepth() { + return lockDepth; + } + + public void setLockDepth(int lockDepth) { + this.lockDepth = lockDepth; + } + @Override public void generate(LIRGenerator gen) { + assert lockDepth != -1; + HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen; + StackSlot slot = hsGen.getLockSlot(lockDepth); // The register allocator cannot handle stack -> register moves so we use an LEA here - Value result = gen.emitMove(gen.emitLea(gen.peekLock())); + Value result = gen.emitMove(gen.emitLea(slot)); gen.setResult(this, result); } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -50,7 +50,6 @@ @Override public void generate(LIRGenerator gen) { - gen.unlock(); } @NodeIntrinsic diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FieldWriteBarrier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FieldWriteBarrier.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.nodes; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public final class FieldWriteBarrier extends FixedWithNextNode implements Lowerable { + + @Input private ValueNode object; + + public ValueNode getObject() { + return object; + } + + public FieldWriteBarrier(ValueNode object) { + super(StampFactory.forVoid()); + this.object = object; + } + + public void lower(LoweringTool generator) { + generator.getRuntime().lower(this, generator); + } +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1WriteBarrierPost.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1WriteBarrierPost.java Thu Mar 28 17:11:06 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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.hotspot.nodes; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; - -public class G1WriteBarrierPost extends WriteBarrierPost implements Lowerable { - - @Input private ValueNode object; - @Input private ValueNode value; - @Input private LocationNode location; - private final boolean precise; - - @Override - public ValueNode getObject() { - return object; - } - - @Override - public ValueNode getValue() { - return value; - } - - @Override - public LocationNode getLocation() { - return location; - } - - @Override - public boolean usePrecise() { - return precise; - } - - public G1WriteBarrierPost(ValueNode object, ValueNode value, LocationNode location, boolean precise) { - this.object = object; - this.value = value; - this.location = location; - this.precise = precise; - } - - @Override - public void lower(LoweringTool generator) { - generator.getRuntime().lower(this, generator); - } - -} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1WriteBarrierPre.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1WriteBarrierPre.java Thu Mar 28 17:11:06 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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.hotspot.nodes; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; - -public final class G1WriteBarrierPre extends WriteBarrierPre implements Lowerable { - - @Input private ValueNode object; - @Input private LocationNode location; - @Input private ValueNode expectedObject; - private final boolean doLoad; - - @Override - public ValueNode getObject() { - return object; - } - - @Override - public ValueNode getExpectedObject() { - return expectedObject; - } - - @Override - public boolean doLoad() { - return doLoad; - } - - @Override - public LocationNode getLocation() { - return location; - } - - public G1WriteBarrierPre(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad) { - this.object = object; - this.doLoad = doLoad; - this.location = location; - this.expectedObject = expectedObject; - } - - @Override - public void lower(LoweringTool generator) { - generator.getRuntime().lower(this, generator); - } - -} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,87 @@ +/* + * 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.hotspot.nodes; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.word.*; + +public class HotSpotInstalledCodeExecuteNode extends AbstractCallNode implements Lowerable { + + @Input private final ValueNode targetAddress; + @Input private final ValueNode metaspaceObject; + private final Class[] signature; + + public HotSpotInstalledCodeExecuteNode(Kind kind, ValueNode targetAddress, ValueNode metaspaceObject, Class[] signature, ValueNode arg1, ValueNode arg2, ValueNode arg3) { + super(StampFactory.forKind(kind), new ValueNode[]{arg1, arg2, arg3}); + this.targetAddress = targetAddress; + this.metaspaceObject = metaspaceObject; + this.signature = signature; + } + + @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + + @Override + public void lower(LoweringTool tool) { + replaceWithInvoke(tool); + } + + private InvokeNode replaceWithInvoke(LoweringTool tool) { + InvokeNode invoke = createInvoke(tool); + ((StructuredGraph) graph()).replaceFixedWithFixed(this, invoke); + return invoke; + } + + protected InvokeNode createInvoke(LoweringTool tool) { + ResolvedJavaMethod method = null; + try { + method = tool.getRuntime().lookupJavaMethod(HotSpotInstalledCodeExecuteNode.class.getMethod("placeholder", Object.class, Object.class, Object.class)); + } catch (NoSuchMethodException | SecurityException e) { + throw new IllegalStateException(); + } + ResolvedJavaType[] signatureTypes = new ResolvedJavaType[signature.length]; + for (int i = 0; i < signature.length; i++) { + signatureTypes[i] = tool.getRuntime().lookupJavaType(signature[i]); + } + HotSpotIndirectCallTargetNode callTarget = graph().add( + new HotSpotIndirectCallTargetNode(metaspaceObject, targetAddress, arguments, stamp(), signatureTypes, method, CallingConvention.Type.JavaCall)); + InvokeNode invoke = graph().add(new InvokeNode(callTarget, 0)); + invoke.setStateAfter(stateAfter()); + return invoke; + } + + public static Object placeholder(@SuppressWarnings("unused") Object a1, @SuppressWarnings("unused") Object a2, @SuppressWarnings("unused") Object a3) { + return 1; + } + + @NodeIntrinsic + public static native T call(@ConstantNodeParameter Kind kind, Word targetAddress, long metaspaceObject, @ConstantNodeParameter Class[] signature, Object arg1, Object arg2, Object arg3); + +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Wed Apr 03 14:41:22 2013 +0200 @@ -26,16 +26,19 @@ import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; +import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.word.*; /** * Node implementing a call to HotSpot's {@code graal_monitorexit} stub. */ -public class MonitorExitStubCall extends FixedWithNextNode implements LIRGenLowerable { +public class MonitorExitStubCall extends FixedWithNextNode implements LIRGenLowerable, MonitorReference { @Input private final ValueNode object; + private int lockDepth; public static final Descriptor MONITOREXIT = new Descriptor("monitorexit", true, void.class, Object.class, Word.class); public MonitorExitStubCall(ValueNode object) { @@ -43,10 +46,21 @@ this.object = object; } + public int getLockDepth() { + return lockDepth; + } + + public void setLockDepth(int lockDepth) { + this.lockDepth = lockDepth; + } + @Override public void generate(LIRGenerator gen) { + assert lockDepth != -1; + HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen; + StackSlot slot = hsGen.getLockSlot(lockDepth); RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MonitorExitStubCall.MONITOREXIT); - gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object), gen.emitLea(gen.peekLock())); + gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object), gen.emitLea(slot)); } @NodeIntrinsic diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialWriteBarrierPost.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialWriteBarrierPost.java Thu Mar 28 17:11:06 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.graal.hotspot.nodes; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; - -public class SerialWriteBarrierPost extends WriteBarrierPost implements Lowerable { - - @Input private ValueNode object; - @Input private LocationNode location; - private final boolean usePrecise; - - public SerialWriteBarrierPost(ValueNode object, LocationNode location, boolean usePrecise) { - this.object = object; - this.location = location; - this.usePrecise = usePrecise; - } - - @Override - public ValueNode getObject() { - return object; - } - - @Override - public LocationNode getLocation() { - return location; - } - - @Override - public boolean usePrecise() { - return usePrecise; - } - - @Override - public void lower(LoweringTool generator) { - generator.getRuntime().lower(this, generator); - } - -} diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPost.java Wed Apr 03 14:41:22 2013 +0200 @@ -22,18 +22,15 @@ */ package com.oracle.graal.hotspot.nodes; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; - -import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; -public class WriteBarrierPost extends WriteBarrier implements Lowerable { +public final class WriteBarrierPost extends FixedWithNextNode implements Lowerable { @Input private ValueNode object; @Input private ValueNode value; - @Input private ValueNode index; @Input private LocationNode location; private final boolean precise; @@ -53,45 +50,15 @@ return precise; } - public WriteBarrierPost() { - this.precise = false; - } - - public WriteBarrierPost(ValueNode object, ValueNode value, ValueNode index) { - this.object = object; - this.value = value; - this.index = index; - this.precise = true; - this.location = null; - } - public WriteBarrierPost(ValueNode object, ValueNode value, LocationNode location, boolean precise) { + super(StampFactory.forVoid()); this.object = object; this.value = value; this.location = location; this.precise = precise; } - @Override public void lower(LoweringTool generator) { - StructuredGraph graph = (StructuredGraph) this.graph(); - if (location == null) { // Come from array copy intrinsic - LocationNode arrayLocation = IndexedLocationNode.create(LocationNode.getArrayLocation(Kind.Object), Kind.Object, arrayBaseOffset(Kind.Object), index, graph, arrayIndexScale(Kind.Object)); - if (useG1GC()) { - graph.replaceFixedWithFixed(this, graph().add(new G1WriteBarrierPost(object, value, arrayLocation, true))); - } else { - graph.replaceFixedWithFixed(this, graph().add(new SerialWriteBarrierPost(object, arrayLocation, true))); - } - } else { // Normal WriteBarrier - assert location != null; - if (useG1GC()) { - graph.replaceFixedWithFixed(this, graph().add(new G1WriteBarrierPost(object, value, location, precise))); - } else { - graph.replaceFixedWithFixed(this, graph().add(new SerialWriteBarrierPost(object, location, precise))); - } - } + generator.getRuntime().lower(this, generator); } - - @NodeIntrinsic - public static native void arrayCopyWriteBarrier(Object array, Object value, int index); } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPre.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPre.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPre.java Wed Apr 03 14:41:22 2013 +0200 @@ -22,13 +22,12 @@ */ package com.oracle.graal.hotspot.nodes; -import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; - import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; -public class WriteBarrierPre extends WriteBarrier implements Lowerable { +public final class WriteBarrierPre extends FixedWithNextNode implements Lowerable { @Input private ValueNode object; @Input private LocationNode location; @@ -51,25 +50,16 @@ return location; } - public WriteBarrierPre() { - this.doLoad = false; - } - public WriteBarrierPre(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad) { + super(StampFactory.forVoid()); this.object = object; this.doLoad = doLoad; this.location = location; this.expectedObject = expectedObject; } - @Override public void lower(LoweringTool generator) { - StructuredGraph graph = (StructuredGraph) this.graph(); - if (useG1GC()) { - graph.replaceFixedWithFixed(this, graph().add(new G1WriteBarrierPre(getObject(), getExpectedObject(), getLocation(), doLoad()))); - } else { - graph.removeFixed(this); - } + generator.getRuntime().lower(this, generator); } } diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Wed Apr 03 14:41:22 2013 +0200 @@ -37,7 +37,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.Snippet.*; import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; @@ -236,8 +236,9 @@ } } + // Does NOT perform store checks @Snippet - private static void arrayObjectCopy(Object src, int srcPos, Object dest, int destPos, int length) { + public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) { objectCounter.inc(); checkNonNull(src); checkNonNull(dest); @@ -246,49 +247,45 @@ int header = arrayBaseOffset(Kind.Object); if (src == dest && srcPos < destPos) { // bad aliased case long start = (long) (length - 1) * scale; - int j = 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); - WriteBarrierPost.arrayCopyWriteBarrier(dest, a, j); - j--; } } else { long end = (long) length * scale; - int j = 0; 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); - WriteBarrierPost.arrayCopyWriteBarrier(dest, a, j); - j++; + + } + } + if (length > 0) { + int cardShift = cardTableShift(); + long cardStart = cardTableStart(); + long dstAddr = GetObjectAddressNode.get(dest); + long start = (dstAddr + header + (long) destPos * scale) >>> cardShift; + long end = (dstAddr + header + ((long) destPos + length - 1) * scale) >>> cardShift; + long count = end - start + 1; + while (count-- > 0) { + DirectStoreNode.store((start + cardStart) + count, false, Kind.Boolean); } } } - // Does NOT perform store checks - @Snippet - public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) { - arrayObjectCopy(src, srcPos, dest, destPos, length); - } - @Snippet public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) { + + // loading the hubs also checks for nullness Word srcHub = loadHub(src); Word destHub = loadHub(dest); + int layoutHelper = checkArrayType(srcHub); - int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); - final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) == 0); if (srcHub.equal(destHub) && src != dest) { probability(FAST_PATH_PROBABILITY); + checkLimits(src, srcPos, dest, destPos, length); - if (isObjectArray) { - genericObjectExactCallCounter.inc(); - probability(FAST_PATH_PROBABILITY); - arrayObjectCopy(src, srcPos, dest, destPos, length); - } else { - genericPrimitiveCallCounter.inc(); - arraycopyInnerloop(src, srcPos, dest, destPos, length, layoutHelper); - } + + arraycopyInnerloop(src, srcPos, dest, destPos, length, layoutHelper); } else { genericObjectCallCounter.inc(); System.arraycopy(src, srcPos, dest, destPos, length); @@ -316,11 +313,29 @@ srcOffset = srcOffset.add(1); } while (destOffset.belowThan(destEnd)) { - Word word = srcOffset.readWord(0, UNKNOWN_LOCATION); - destOffset.writeWord(0, word, ANY_LOCATION); + destOffset.writeWord(0, srcOffset.readWord(0, UNKNOWN_LOCATION), ANY_LOCATION); destOffset = destOffset.add(wordSize()); srcOffset = srcOffset.add(wordSize()); } + + if ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) != 0) { + genericPrimitiveCallCounter.inc(); + + } else { + probability(LIKELY_PROBABILITY); + genericObjectExactCallCounter.inc(); + + if (length > 0) { + int cardShift = cardTableShift(); + long cardStart = cardTableStart(); + Word destCardOffset = destStart.unsignedShiftRight(cardShift).add(Word.unsigned(cardStart)); + Word destCardEnd = destEnd.subtract(1).unsignedShiftRight(cardShift).add(Word.unsigned(cardStart)); + while (destCardOffset.belowOrEqual(destCardEnd)) { + DirectStoreNode.store(destCardOffset.rawValue(), false, Kind.Boolean); + destCardOffset = destCardOffset.add(1); + } + } + } } private static final SnippetCounter.Group checkCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("System.arraycopy checkInputs") : null; diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java Wed Apr 03 14:41:22 2013 +0200 @@ -81,9 +81,8 @@ } exactHit.inc(); } - /** - * make sure that the unsafeCast is done *after* the check above, - * cf. {@link ReadAfterCheckCast}*/ + /* make sure that the unsafeCast is done *after* the check above, + * cf. ReadAfterCheckCast */ BeginNode anchorNode = BeginNode.anchor(StampFactory.forNodeIntrinsic()); return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic(), anchorNode); } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotInstalledCodeIntrinsics.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotInstalledCodeIntrinsics.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,38 @@ +/* + * 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.hotspot.replacements; + +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.*; + +@ServiceProvider(ReplacementsProvider.class) +public class HotSpotInstalledCodeIntrinsics implements ReplacementsProvider { + + @Override + public void installReplacements(ReplacementsInstaller installer) { + if (GraalOptions.IntrinsifyInstalledCodeMethods) { + installer.installSubstitutions(HotSpotInstalledCodeSubstitutions.class); + } + } +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotInstalledCodeSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotInstalledCodeSubstitutions.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.replacements; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.replacements.Snippet.Fold; +import com.oracle.graal.word.*; + +@ClassSubstitution(HotSpotInstalledCode.class) +public class HotSpotInstalledCodeSubstitutions { + + @MethodSubstitution + public static Object executeHelper(long nmethod, long metaspaceMethod, final Object arg1, final Object arg2, final Object arg3) { + final int verifiedEntryPointOffset = HotSpotSnippetUtils.verifiedEntryPointOffset(); + final Word callTarget = Word.unsigned(nmethod).readWord(verifiedEntryPointOffset); + return HotSpotInstalledCodeExecuteNode.call(Kind.Object, callTarget, metaspaceMethod, getSignature(), arg1, arg2, arg3); + } + + @Fold + private static Class[] getSignature() { + return new Class[]{Object.class, Object.class, Object.class}; + } +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java Wed Apr 03 14:41:22 2013 +0200 @@ -594,4 +594,9 @@ return IdentityHashCodeStubCall.call(x); } + + @Fold + public static int verifiedEntryPointOffset() { + return config().nmethodEntryOffset; + } } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Wed Apr 03 14:41:22 2013 +0200 @@ -451,6 +451,9 @@ BeginLockScopeNode begin = (BeginLockScopeNode) n; begin.setStateAfter(stateAfter); } + if (n instanceof MonitorReference) { + ((MonitorReference) n).setLockDepth(monitorenterNode.getLockDepth()); + } } } @@ -474,6 +477,9 @@ EndLockScopeNode end = (EndLockScopeNode) n; end.setStateAfter(stateAfter); } + if (n instanceof MonitorReference) { + ((MonitorReference) n).setLockDepth(monitorexitNode.getLockDepth()); + } } } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Wed Apr 03 14:41:22 2013 +0200 @@ -136,6 +136,7 @@ @ConstantParameter("alignment") int alignment, @ConstantParameter("headerSize") int headerSize, @ConstantParameter("log2ElementSize") int log2ElementSize, + @ConstantParameter("fillContents") boolean fillContents, @ConstantParameter("type") ResolvedJavaType type) { if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { probability(DEOPT_PATH_PROBABILITY); @@ -144,7 +145,7 @@ } int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); Word memory = TLABAllocateNode.allocateVariableSize(allocationSize); - return InitializeArrayNode.initialize(memory, length, allocationSize, type, true, false); + return InitializeArrayNode.initialize(memory, length, allocationSize, type, fillContents, false); } /** @@ -240,7 +241,7 @@ allocate = snippet("allocate", int.class); initializeObject = snippet("initializeObject", Word.class, Word.class, Word.class, int.class, boolean.class, boolean.class); initializeArray = snippet("initializeArray", Word.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class, boolean.class); - allocateArrayAndInitialize = snippet("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, ResolvedJavaType.class); + allocateArrayAndInitialize = snippet("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, boolean.class, ResolvedJavaType.class); newmultiarray = snippet("newmultiarray", Word.class, int.class, int[].class); } @@ -299,7 +300,8 @@ InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); graph.replaceFixedWithFixed(newArrayNode, initializeNode); } else { - Key key = new Key(allocateArrayAndInitialize).add("alignment", alignment).add("headerSize", headerSize).add("log2ElementSize", log2ElementSize).add("type", arrayType); + Key key = new Key(allocateArrayAndInitialize).add("alignment", alignment).add("headerSize", headerSize).add("log2ElementSize", log2ElementSize).add("fillContents", + newArrayNode.fillContents()).add("type", arrayType); Arguments arguments = new Arguments().add("length", lengthNode); SnippetTemplate template = cache.get(key, assumptions); Debug.log("Lowering allocateArrayAndInitialize in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, arguments); diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Wed Apr 03 14:41:22 2013 +0200 @@ -40,7 +40,7 @@ public class WriteBarrierSnippets implements Snippets { @Snippet - public static void g1WriteBarrierPre(@Parameter("object") Object obj, @Parameter("expectedObject") Object expobj, @Parameter("location") Object location, + public static void g1PreWriteBarrier(@Parameter("object") Object obj, @Parameter("expectedObject") Object expobj, @Parameter("location") Object location, @ConstantParameter("doLoad") boolean doLoad) { Word thread = thread(); Object object = FixedValueAnchorNode.getObject(obj); @@ -48,9 +48,11 @@ Word field = (Word) Word.fromArray(object, location); Word previousOop = (Word) Word.fromObject(expectedObject); byte markingValue = thread.readByte(HotSpotSnippetUtils.g1SATBQueueMarkingOffset()); + Word bufferAddress = thread.readWord(HotSpotSnippetUtils.g1SATBQueueBufferOffset()); Word indexAddress = thread.add(HotSpotSnippetUtils.g1SATBQueueIndexOffset()); Word indexValue = indexAddress.readWord(0); + if (markingValue != (byte) 0) { if (doLoad) { previousOop = field.readWord(0); @@ -63,13 +65,14 @@ indexAddress.writeWord(0, nextIndex); } else { WriteBarrierPreStubCall.call(previousOop); + } } } } @Snippet - public static void g1WriteBarrierPost(@Parameter("object") Object obj, @Parameter("value") Object value, @Parameter("location") Object location, @ConstantParameter("usePrecise") boolean usePrecise) { + public static void g1PostWriteBarrier(@Parameter("object") Object obj, @Parameter("value") Object value, @Parameter("location") Object location, @ConstantParameter("usePrecise") boolean usePrecise) { Word thread = thread(); Object object = FixedValueAnchorNode.getObject(obj); Object wrObject = FixedValueAnchorNode.getObject(value); @@ -96,6 +99,7 @@ cardBase = cardBase.add(Word.unsigned(cardTableStart())); } Word cardAddress = cardBase.add(displacement); + if (xorResult.notEqual(Word.zero())) { if (writtenValue.notEqual(Word.zero())) { byte cardByte = cardAddress.readByte(0); @@ -115,14 +119,24 @@ } @Snippet - public static void serialWriteBarrierPost(@Parameter("object") Object obj, @Parameter("location") Object location, @ConstantParameter("usePrecise") boolean usePrecise) { + public static void serialFieldWriteBarrier(@Parameter("object") Object obj) { Object object = FixedValueAnchorNode.getObject(obj); - Pointer oop; - if (usePrecise) { - oop = Word.fromArray(object, location); + Pointer oop = Word.fromObject(object); + Word base = (Word) oop.unsignedShiftRight(cardTableShift()); + long startAddress = cardTableStart(); + int displacement = 0; + if (((int) startAddress) == startAddress) { + displacement = (int) startAddress; } else { - oop = Word.fromObject(object); + base = base.add(Word.unsigned(cardTableStart())); } + base.writeByte(displacement, (byte) 0); + } + + @Snippet + public static void serialArrayWriteBarrier(@Parameter("object") Object obj, @Parameter("location") Object location) { + Object object = FixedValueAnchorNode.getObject(obj); + Pointer oop = Word.fromArray(object, location); Word base = (Word) oop.unsignedShiftRight(cardTableShift()); long startAddress = cardTableStart(); int displacement = 0; @@ -136,30 +150,40 @@ public static class Templates extends AbstractTemplates { - private final ResolvedJavaMethod serialWriteBarrierPost; - private final ResolvedJavaMethod g1WriteBarrierPre; - private final ResolvedJavaMethod g1WriteBarrierPost; + private final ResolvedJavaMethod serialFieldWriteBarrier; + private final ResolvedJavaMethod serialArrayWriteBarrier; + private final ResolvedJavaMethod g1PreWriteBarrier; + private final ResolvedJavaMethod g1PostWriteBarrier; public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { super(runtime, assumptions, target, WriteBarrierSnippets.class); - serialWriteBarrierPost = snippet("serialWriteBarrierPost", Object.class, Object.class, boolean.class); - g1WriteBarrierPre = snippet("g1WriteBarrierPre", Object.class, Object.class, Object.class, boolean.class); - g1WriteBarrierPost = snippet("g1WriteBarrierPost", Object.class, Object.class, Object.class, boolean.class); + serialFieldWriteBarrier = snippet("serialFieldWriteBarrier", Object.class); + serialArrayWriteBarrier = snippet("serialArrayWriteBarrier", Object.class, Object.class); + g1PreWriteBarrier = snippet("g1PreWriteBarrier", Object.class, Object.class, Object.class, boolean.class); + g1PostWriteBarrier = snippet("g1PostWriteBarrier", Object.class, Object.class, Object.class, boolean.class); } - public void lower(SerialWriteBarrierPost fieldWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) { - ResolvedJavaMethod method = serialWriteBarrierPost; + public void lower(ArrayWriteBarrier arrayWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) { + ResolvedJavaMethod method = serialArrayWriteBarrier; Key key = new Key(method); - key.add("usePrecise", fieldWriteBarrier.usePrecise()); + Arguments arguments = new Arguments(); + arguments.add("object", arrayWriteBarrier.getObject()); + arguments.add("location", arrayWriteBarrier.getLocation()); + SnippetTemplate template = cache.get(key, assumptions); + template.instantiate(runtime, arrayWriteBarrier, DEFAULT_REPLACER, arguments); + } + + public void lower(FieldWriteBarrier fieldWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) { + ResolvedJavaMethod method = serialFieldWriteBarrier; + Key key = new Key(method); Arguments arguments = new Arguments(); arguments.add("object", fieldWriteBarrier.getObject()); - arguments.add("location", fieldWriteBarrier.getLocation()); SnippetTemplate template = cache.get(key, assumptions); template.instantiate(runtime, fieldWriteBarrier, DEFAULT_REPLACER, arguments); } - public void lower(G1WriteBarrierPre writeBarrierPre, @SuppressWarnings("unused") LoweringTool tool) { - ResolvedJavaMethod method = g1WriteBarrierPre; + public void lower(WriteBarrierPre writeBarrierPre, @SuppressWarnings("unused") LoweringTool tool) { + ResolvedJavaMethod method = g1PreWriteBarrier; Key key = new Key(method); key.add("doLoad", writeBarrierPre.doLoad()); Arguments arguments = new Arguments(); @@ -170,8 +194,8 @@ template.instantiate(runtime, writeBarrierPre, DEFAULT_REPLACER, arguments); } - public void lower(G1WriteBarrierPost writeBarrierPost, @SuppressWarnings("unused") LoweringTool tool) { - ResolvedJavaMethod method = g1WriteBarrierPost; + public void lower(WriteBarrierPost writeBarrierPost, @SuppressWarnings("unused") LoweringTool tool) { + ResolvedJavaMethod method = g1PostWriteBarrier; Key key = new Key(method); key.add("usePrecise", writeBarrierPost.usePrecise()); Arguments arguments = new Arguments(); diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Wed Apr 03 14:41:22 2013 +0200 @@ -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); } } } @@ -377,10 +376,10 @@ } /** - * @return true if there are no locks within this frame state. + * @return the current lock depth */ - public boolean locksEmpty() { - return locks.length == 0; + public int lockDepth() { + return locks.length; } /** diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Wed Apr 03 14:41:22 2013 +0200 @@ -1153,18 +1153,18 @@ } private MonitorEnterNode genMonitorEnter(ValueNode x) { + MonitorEnterNode monitorEnter = currentGraph.add(new MonitorEnterNode(x, frameState.lockDepth())); frameState.pushLock(x); - MonitorEnterNode monitorEnter = currentGraph.add(new MonitorEnterNode(x)); appendWithBCI(monitorEnter); return monitorEnter; } private MonitorExitNode genMonitorExit(ValueNode x) { ValueNode lockedObject = frameState.popLock(); + MonitorExitNode monitorExit = currentGraph.add(new MonitorExitNode(x, frameState.lockDepth())); if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) { throw new BailoutException("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject)); } - MonitorExitNode monitorExit = currentGraph.add(new MonitorExitNode(x)); appendWithBCI(monitorExit); return monitorExit; } @@ -1568,7 +1568,7 @@ } synchronizedEpilogue(FrameState.AFTER_BCI); - if (!frameState.locksEmpty()) { + if (frameState.lockDepth() != 0) { throw new BailoutException("unbalanced monitors"); } ReturnNode returnNode = currentGraph.add(new ReturnNode(x)); diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/ConvertJTT.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/ConvertJTT.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/ConvertJTT.java Wed Apr 03 14:41:22 2013 +0200 @@ -52,8 +52,7 @@ try { processFile(file.toPath(), new File(targetDir, file.getName()).toPath(), packageName); } catch (RuntimeException e) { - e.printStackTrace(); - System.out.println("in file " + file.getAbsolutePath()); + throw new RuntimeException(String.format("Exception while processing file %s", file.getAbsolutePath()), e); } } } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java Wed Apr 03 14:41:22 2013 +0200 @@ -50,10 +50,8 @@ FloatField = Field_get03.class.getField("floatField"); DoubleField = Field_get03.class.getField("doubleField"); BooleanField = Field_get03.class.getField("booleanField"); - } catch (SecurityException e) { - e.printStackTrace(); - } catch (NoSuchFieldException e) { - e.printStackTrace(); + } catch (SecurityException | NoSuchFieldException e) { + throw new RuntimeException(e); } } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java Wed Apr 03 14:41:22 2013 +0200 @@ -80,24 +80,23 @@ * We filter out constant and illegal values ourself before calling the procedure, so * {@link OperandFlag#CONST} and {@link OperandFlag#ILLEGAL} need not be set. */ - private static final EnumSet STATE_FLAGS = EnumSet.of(OperandFlag.REG, OperandFlag.STACK); + protected static final EnumSet STATE_FLAGS = EnumSet.of(OperandFlag.REG, OperandFlag.STACK); - private void processValues(Value[] values, ValueProcedure proc) { + protected void processValues(Value[] values, ValueProcedure proc) { for (int i = 0; i < values.length; i++) { Value value = values[i]; - if (value instanceof MonitorValue) { - MonitorValue monitor = (MonitorValue) value; - if (processed(monitor.getOwner())) { - monitor.setOwner(proc.doValue(monitor.getOwner(), OperandMode.ALIVE, STATE_FLAGS)); - } - - } else if (processed(value)) { - values[i] = proc.doValue(value, OperandMode.ALIVE, STATE_FLAGS); - } + values[i] = processValue(proc, value); } } - private boolean processed(Value value) { + protected Value processValue(ValueProcedure proc, Value value) { + if (processed(value)) { + return proc.doValue(value, OperandMode.ALIVE, STATE_FLAGS); + } + return value; + } + + protected boolean processed(Value value) { if (isIllegal(value)) { // Ignore dead local variables. return false; diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Wed Apr 03 14:41:22 2013 +0200 @@ -273,6 +273,18 @@ } /** + * Gets the number of locked monitors in this frame state and all + * {@linkplain #outerFrameState() outer} frame states. + */ + public int nestedLockDepth() { + int depth = locksSize(); + for (FrameState outer = outerFrameState(); outer != null; outer = outer.outerFrameState()) { + depth += outer.locksSize(); + } + return depth; + } + + /** * Gets the value in the local variables at the specified index. * * @param i the index into the locals diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -45,6 +45,20 @@ if (x().isConstant() && !y().isConstant()) { return graph().unique(new IntegerAddNode(kind(), y(), x())); } + if (x() instanceof IntegerSubNode) { + IntegerSubNode sub = (IntegerSubNode) x(); + if (sub.y() == y()) { + // (a - b) + b + return sub.x(); + } + } + if (y() instanceof IntegerSubNode) { + IntegerSubNode sub = (IntegerSubNode) y(); + if (sub.y() == x()) { + // b + (a - b) + return sub.x(); + } + } if (x().isConstant()) { if (kind() == Kind.Int) { return ConstantNode.forInt(x().asConstant().asInt() + y().asConstant().asInt(), graph()); @@ -73,6 +87,8 @@ } if (x() instanceof NegateNode) { return IntegerArithmeticNode.sub(y(), ((NegateNode) x()).x()); + } else if (y() instanceof NegateNode) { + return IntegerArithmeticNode.sub(x(), ((NegateNode) y()).x()); } return this; } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -45,6 +45,40 @@ if (x() == y()) { return ConstantNode.forIntegerKind(kind(), 0, graph()); } + if (x() instanceof IntegerAddNode) { + IntegerAddNode x = (IntegerAddNode) x(); + if (x.y() == y()) { + // (a + b) - b + return x.x(); + } + if (x.x() == y()) { + // (a + b) - a + return x.y(); + } + } else if (x() instanceof IntegerSubNode) { + IntegerSubNode x = (IntegerSubNode) x(); + if (x.x() == y()) { + // (a - b) - a + return graph().unique(new NegateNode(x.y())); + } + } + if (y() instanceof IntegerAddNode) { + IntegerAddNode y = (IntegerAddNode) y(); + if (y.x() == x()) { + // a - (a + b) + return graph().unique(new NegateNode(y.y())); + } + if (y.y() == x()) { + // b - (a + b) + return graph().unique(new NegateNode(y.x())); + } + } else if (y() instanceof IntegerSubNode) { + IntegerSubNode y = (IntegerSubNode) y(); + if (y.x() == x()) { + // a - (a - b) + return y.y(); + } + } if (x().isConstant() && y().isConstant()) { if (kind() == Kind.Int) { return ConstantNode.forInt(x().asConstant().asInt() - y().asConstant().asInt(), graph()); @@ -76,6 +110,9 @@ } return BinaryNode.reassociate(this, ValueNode.isConstantPredicate()); } + if (y() instanceof NegateNode) { + return IntegerArithmeticNode.add(x(), ((NegateNode) y()).x()); + } return this; } diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorReference.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MonitorReference.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.extended; + +/** + * Denotes an instruction that references a monitor and wants to know its lock nesting depth. + */ +public interface MonitorReference { + + /** + * Sets the depth of the lock referenced by this operation. + */ + void setLockDepth(int lockDepth); + + /** + * Gets the depth of the lock referenced by this operation. + */ + int getLockDepth(); +} diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 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 d343737786fe -r 6d884611d4c1 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 17:11:06 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 d343737786fe -r 6d884611d4c1 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 17:11:06 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 d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -29,15 +29,18 @@ /** * The {@code MonitorEnterNode} represents the acquisition of a monitor. */ -public final class MonitorEnterNode extends AccessMonitorNode implements Lowerable, MonitorEnter { +public final class MonitorEnterNode extends AccessMonitorNode implements Lowerable, MonitorEnter, MonitorReference { + + private int lockDepth; /** * Creates a new MonitorEnterNode. * * @param object the instruction producing the object */ - public MonitorEnterNode(ValueNode object) { + public MonitorEnterNode(ValueNode object, int lockDepth) { super(object); + this.lockDepth = lockDepth; } @Override @@ -48,4 +51,12 @@ public void lower(LoweringTool tool) { tool.getRuntime().lower(this, tool); } + + public int getLockDepth() { + return lockDepth; + } + + public void setLockDepth(int lockDepth) { + this.lockDepth = lockDepth; + } } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -30,15 +30,18 @@ /** * The {@code MonitorEnterNode} represents a monitor release. */ -public final class MonitorExitNode extends AccessMonitorNode implements Lowerable, Node.IterableNodeType, MonitorExit { +public final class MonitorExitNode extends AccessMonitorNode implements Lowerable, Node.IterableNodeType, MonitorExit, MonitorReference { + + private int lockDepth; /** * Creates a new MonitorExitNode. * * @param object the instruction produces the object value */ - public MonitorExitNode(ValueNode object) { + public MonitorExitNode(ValueNode object, int lockDepth) { super(object); + this.lockDepth = lockDepth; } @Override @@ -49,4 +52,12 @@ public void lower(LoweringTool tool) { tool.getRuntime().lower(this, tool); } + + public int getLockDepth() { + return lockDepth; + } + + public void setLockDepth(int lockDepth) { + this.lockDepth = lockDepth; + } } diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Wed Apr 03 14:41:22 2013 +0200 @@ -57,20 +57,20 @@ 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(MetaAccessProvider runtime, Collection hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) { + public InliningPhase(MetaAccessProvider runtime, Map hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) { this(runtime, assumptions, cache, plan, createInliningPolicy(runtime, assumptions, optimisticOpts, hints), optimisticOpts); } - public void setCustomCanonicalizer(CustomCanonicalizer customCanonicalizer) { - this.customCanonicalizer = customCanonicalizer; - } - public InliningPhase(MetaAccessProvider runtime, Assumptions assumptions, GraphCache cache, PhasePlan plan, InliningPolicy inliningPolicy, OptimisticOptimizations optimisticOpts) { this.runtime = runtime; this.assumptions = assumptions; @@ -79,6 +79,18 @@ this.inliningPolicy = inliningPolicy; this.optimisticOpts = optimisticOpts; } + + public void setCustomCanonicalizer(CustomCanonicalizer customCanonicalizer) { + this.customCanonicalizer = customCanonicalizer; + } + + public void setMaxMethodsPerInlining(int max) { + maxMethodPerInlining = max; + } + + public int getInliningCount() { + return inliningCount; + } @Override protected void run(final StructuredGraph 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 MetaAccessProvider runtime; - private final Collection hints; + private final Map hints; - public GreedySizeBasedInliningDecision(MetaAccessProvider runtime, Collection hints) { + public GreedySizeBasedInliningDecision(MetaAccessProvider 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(MetaAccessProvider runtime, Assumptions assumptions, OptimisticOptimizations optimisticOpts, Collection hints) { + private static InliningPolicy createInliningPolicy(MetaAccessProvider 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 d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Wed Apr 03 14:41:22 2013 +0200 @@ -1094,6 +1094,7 @@ FrameState outerFrameState = null; double invokeProbability = invoke.node().probability(); + int callerLockDepth = stateAfter.nestedLockDepth(); for (Node node : duplicates.values()) { if (GraalOptions.ProbabilityAnalysis) { if (node instanceof FixedNode) { @@ -1137,6 +1138,10 @@ } } } + if (callerLockDepth != 0 && node instanceof MonitorReference) { + MonitorReference monitor = (MonitorReference) node; + monitor.setLockDepth(monitor.getLockDepth() + callerLockDepth); + } } Node returnValue = null; diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Wed Apr 03 14:41:22 2013 +0200 @@ -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; @@ -209,7 +214,7 @@ public static boolean IntrinsifyUnsafeMethods = true; public static boolean IntrinsifyMathMethods = true; public static boolean IntrinsifyAESMethods = true; - + public static boolean IntrinsifyInstalledCodeMethods = true; /** * Counts the various paths taken through snippets. */ diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Wed Apr 03 14:41:22 2013 +0200 @@ -62,11 +62,16 @@ } } - public static Class[] signatureToTypes(Signature signature, ResolvedJavaType accessingClass) { - int count = signature.getParameterCount(false); + public static Class[] signatureToTypes(Signature signature, JavaType receiverType, ResolvedJavaType accessingClass) { + int count = signature.getParameterCount(receiverType != null); Class[] result = new Class[count]; - for (int i = 0; i < result.length; ++i) { - result[i] = getMirrorOrFail(signature.getParameterType(i, accessingClass).resolve(accessingClass), Thread.currentThread().getContextClassLoader()); + int j = 0; + if (receiverType != null) { + result[0] = getMirrorOrFail(receiverType.resolve(accessingClass), Thread.currentThread().getContextClassLoader()); + j = 1; + } + for (int i = 0; i + j < result.length; ++i) { + result[i + j] = getMirrorOrFail(signature.getParameterType(i, accessingClass).resolve(accessingClass), Thread.currentThread().getContextClassLoader()); } return result; } @@ -75,10 +80,12 @@ ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); ResolvedJavaType declaringClass = target.getDeclaringClass(); + JavaType receiverType = invoke.methodCallTarget().isStatic() ? null : declaringClass; if (intrinsic != null) { assert target.getAnnotation(Fold.class) == null; - Class[] parameterTypes = signatureToTypes(target.getSignature(), declaringClass); + // TODO mjj non-static intrinsic? + Class[] parameterTypes = signatureToTypes(target.getSignature(), null, declaringClass); ResolvedJavaType returnType = target.getSignature().getReturnType(declaringClass).resolve(declaringClass); // Prepare the arguments for the reflective constructor call on the node class. @@ -98,7 +105,7 @@ // Clean up checkcast instructions inserted by javac if the return type is generic. cleanUpReturnCheckCast(newInstance); } else if (target.getAnnotation(Fold.class) != null) { - Class[] parameterTypes = signatureToTypes(target.getSignature(), declaringClass); + Class[] parameterTypes = signatureToTypes(target.getSignature(), receiverType, declaringClass); // Prepare the arguments for the reflective method call Object[] arguments = prepareArguments(invoke, parameterTypes, target, true); @@ -109,6 +116,7 @@ if (!invoke.methodCallTarget().isStatic()) { receiver = arguments[0]; arguments = Arrays.asList(arguments).subList(1, arguments.length).toArray(); + parameterTypes = Arrays.asList(parameterTypes).subList(1, parameterTypes.length).toArray(new Class[parameterTypes.length - 1]); } // Call the method diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Wed Apr 03 14:41:22 2013 +0200 @@ -41,6 +41,7 @@ import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.Snippet.Parameter; import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; import com.oracle.graal.word.phases.*; diff -r d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java Wed Apr 03 14:41:22 2013 +0200 @@ -53,8 +53,8 @@ try { field.setAccessible(true); str.append(str.length() > 0 ? ", " : "").append(name).append("=").append(format(field.get(this))); - } catch (Exception e) { - e.printStackTrace(); + } catch (SecurityException | IllegalAccessException e) { + throw new RuntimeException(e); } } } @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 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 17:11:06 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Wed Apr 03 14:41:22 2013 +0200 @@ -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 d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen.test; + +import org.junit.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.BinaryNodeTestFactory.AddNodeFactory; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; + +import static junit.framework.Assert.*; +import static com.oracle.truffle.api.codegen.test.TestHelper.*; + +public class BinaryNodeTest { + + @Test + public void testAdd() { + TestRootNode node = create(AddNodeFactory.getInstance()); + assertEquals(42, executeWith(node, 19, 23)); + assertEquals(42d, executeWith(node, 19d, 23d)); + assertEquals(42d, executeWith(node, "19", "23")); + assertEquals(42, executeWith(node, 19, 23)); + } + + @Test(expected = RuntimeException.class) + public void testAddUnsupported() { + TestRootNode node = create(AddNodeFactory.getInstance()); + executeWith(node, new Object(), new Object()); + } + + abstract static class BinaryNode extends ValueNode { + + @Child protected ValueNode leftNode; + @Child protected ValueNode rightNode; + + public BinaryNode(ValueNode left, ValueNode right) { + this.leftNode = left; + this.rightNode = right; + } + + public BinaryNode(BinaryNode prev) { + this(prev.leftNode, prev.rightNode); + } + } + + abstract static class AddNode extends BinaryNode { + + public AddNode(ValueNode left, ValueNode right) { + super(left, right); + } + + public AddNode(AddNode prev) { + super(prev); + } + + @Specialization + int add(int left, int right) { + return left + right; + } + + @Generic + Object add(Object left, Object right) { + return convertDouble(left) + convertDouble(right); + } + + static double convertDouble(Object value) { + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } else if (value instanceof String) { + return Double.parseDouble((String) value); + } + throw new RuntimeException("Invalid datatype"); + } + + } + +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryOperationTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryOperationTest.java Thu Mar 28 17:11:06 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.codegen.test; - -import com.oracle.truffle.api.codegen.*; -import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; - -public class BinaryOperationTest { - - static int convertInt(Object value) { - if (value instanceof Number) { - return ((Number) value).intValue(); - } else if (value instanceof String) { - return Integer.parseInt((String) value); - } - throw new RuntimeException("Invalid datatype"); - } - - @NodeClass(BinaryNode.class) - abstract static class BinaryNode extends ValueNode { - - @Child protected ValueNode leftNode; - @Child protected ValueNode rightNode; - - public BinaryNode(ValueNode left, ValueNode right) { - this.leftNode = left; - this.rightNode = right; - } - - public BinaryNode(BinaryNode prev) { - this(prev.leftNode, prev.rightNode); - } - - @Specialization - int add(int left, int right) { - return left + right; - } - - @Generic - int add(Object left, Object right) { - return convertInt(left) + convertInt(right); - } - - @Specialization - int sub(int left, int right) { - return left + right; - } - - @Generic - int sub(Object left, Object right) { - return convertInt(left) + convertInt(right); - } - - } - -} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen.test; + +import static com.oracle.truffle.api.codegen.test.TestHelper.*; +import static junit.framework.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrAccessContextFactory; +import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrConcatFactory; +import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrLengthFactory; +import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrSubstrFactory; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ChildrenNode; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; + +public class BuiltinTest { + + @Test + public void testConcat() { + TestRootNode node = create(StrConcatFactory.getInstance(), new Context()); + Str str1 = new Str("42"); + Str str2 = new Str(" is the number."); + assertEquals(str1.concat(str2), executeWith(node, str1, str2)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testConcatUnsupported() { + TestRootNode node = create(StrConcatFactory.getInstance(), new Context()); + executeWith(node, 42, new Str(" is the number.")); + } + + @Test + public void testSubstrSpecialized() { + TestRootNode node = create(StrSubstrFactory.getInstance(), new Context()); + Str str = new Str("test 42"); + + assertEquals(str.substr(5, 7), executeWith(node, str, 5, 7)); + } + + @Test + public void testSubstrGeneric() { + TestRootNode node = create(StrSubstrFactory.getInstance(), new Context()); + Str str = new Str("test 42"); + + assertEquals(Str.substr(str, "5", "7"), executeWith(node, str, "5", "7")); + } + + @Test(expected = UnsupportedOperationException.class) + public void testSubstrUnsupported() { + TestRootNode node = create(StrSubstrFactory.getInstance(), new Context()); + executeWith(node, new Object(), "5", "7"); + } + + @Test + public void testLength() { + TestRootNode node = create(StrLengthFactory.getInstance(), new Context()); + Str testStr = new Str("test 42"); + assertEquals(testStr.length(), executeWith(node, testStr)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testLengthUnsupported() { + TestRootNode node = create(StrLengthFactory.getInstance(), new Context()); + executeWith(node, new Object()); + } + + @Test + public void testAccessContext() { + Context context = new Context(); + TestRootNode node = create(StrAccessContextFactory.getInstance(), context); + // accessible by node + assertSame(context, node.getNode().getContext()); + // accessible by execution + assertSame(context, executeWith(node)); + } + + @NodeClass(BuiltinNode.class) + static class Str { + + private final String internal; + + public Str(String internal) { + this.internal = internal; + } + + @Specialization + Str concat(Str s1) { + return new Str(internal + s1.internal); + } + + @Specialization + Str substr(int beginIndex, int endIndex) { + return new Str(internal.substring(beginIndex, endIndex)); + } + + @Generic + static Str substr(Object thisValue, Object beginIndex, Object endIndex) { + if (!(thisValue instanceof Str)) { + throw new UnsupportedOperationException(); + } + return ((Str) thisValue).substr(convertInt(beginIndex), convertInt(endIndex)); + } + + @Specialization + int length() { + return internal.length(); + } + + @Specialization + static Object accessContext(Context context) { + return context; + } + + static int convertInt(Object value) { + if (value instanceof Number) { + return ((Number) value).intValue(); + } else if (value instanceof String) { + return Integer.parseInt((String) value); + } + throw new RuntimeException("Invalid datatype"); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Str) { + return internal.equals(((Str) obj).internal); + } + return super.equals(obj); + } + + @Override + public String toString() { + return internal; + } + + @Override + public int hashCode() { + return internal.hashCode(); + } + } + + abstract static class BuiltinNode extends ChildrenNode { + + protected final Context context; + + public BuiltinNode(BuiltinNode node) { + this(node.context, node.children); + } + + public BuiltinNode(Context context, ValueNode... children) { + super(children); + this.context = context; + } + + public Context getContext() { + return context; + } + + } + + static class Context { + + } + +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen.test; + +import static com.oracle.truffle.api.codegen.test.TestHelper.*; +import static junit.framework.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.GuardsTestFactory.GlobalFlagGuardFactory; +import com.oracle.truffle.api.codegen.test.GuardsTestFactory.InvocationGuardFactory; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ChildrenNode; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; + +@SuppressWarnings("unused") +public class GuardsTest { + + private static final Object NULL = new Object(); + + @Test + public void testGuardInvocations() { + TestRootNode root = create(InvocationGuardFactory.getInstance()); + + assertEquals(Integer.MAX_VALUE, executeWith(root, Integer.MAX_VALUE - 1, 1)); + assertEquals(1, InvocationGuard.specializedInvocations); + assertEquals(0, InvocationGuard.genericInvocations); + + assertEquals(42, executeWith(root, Integer.MAX_VALUE, 1)); + assertEquals(1, InvocationGuard.specializedInvocations); + assertEquals(1, InvocationGuard.genericInvocations); + } + + public abstract static class InvocationGuard extends ChildrenNode { + + static int specializedInvocations = 0; + static int genericInvocations = 0; + + public InvocationGuard(ValueNode... children) { + super(children); + } + + public InvocationGuard(InvocationGuard node) { + super(node); + } + + boolean guard(int value0, int value1) { + return value0 != Integer.MAX_VALUE; + } + + @Specialization(guards = "guard") + int doSpecialized(int value0, int value1) { + specializedInvocations++; + return value0 + value1; + } + + @Generic + int doGeneric(Object value0, Object value1) { + genericInvocations++; + return 42; // the generic answer to all questions + } + } + + @Test + public void testGuardGlobal() { + TestRootNode root = create(GlobalFlagGuardFactory.getInstance()); + + assertEquals(42, executeWith(root, NULL)); + + GlobalFlagGuard.globalFlag = true; + assertEquals(41, executeWith(root, NULL)); + + GlobalFlagGuard.globalFlag = false; + assertEquals(42, executeWith(root, NULL)); + } + + public abstract static class GlobalFlagGuard extends ChildrenNode { + + static boolean globalFlag = false; + + public GlobalFlagGuard(ValueNode... children) { + super(children); + } + + public GlobalFlagGuard(GlobalFlagGuard node) { + super(node); + } + + static boolean globalFlagGuard() { + return globalFlag; + } + + @Specialization(guards = "globalFlagGuard") + int doSpecialized(Object value0) { + return 41; + } + + @Generic + int doGeneric(Object value0) { + return 42; // the generic answer to all questions + } + } + +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java Thu Mar 28 17:11:06 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.codegen.test; - -import org.junit.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.codegen.*; -import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode; -import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; - -public class RuntimeStringTest { - - @Test - public void testSubstr() { - executeAndAssert(new RuntimeString("es"), "substr", new RuntimeString("test"), 1, 3); - } - - @Test - public void testConcat() { - executeAndAssert(new RuntimeString("concatconcat"), "concat", new RuntimeString("concat"), new RuntimeString("concat")); - } - - @Test(expected = ArrayIndexOutOfBoundsException.class) - public void testConcatFail() { - executeAndAssert(new RuntimeString("concatconcat"), "concat", new RuntimeString("concat")); - } - - @Test - public void testFindMethodByMethodName() { - // TODO - } - - private static void executeAndAssert(Object expectedResult, String name, Object... argumentsArray) { - ArgNode[] args = new ArgNode[argumentsArray.length]; - for (int i = 0; i < args.length; i++) { - args[i] = new ArgNode(argumentsArray, i); - } - - BuiltinNode node = null; - for (NodeFactory nodeFactory : RuntimeStringTestFactory.getFactories()) { - GeneratedBy generated = nodeFactory.getClass().getAnnotation(GeneratedBy.class); - Assert.assertNotNull(generated); - Assert.assertNotSame("", generated.methodName()); - if (generated.methodName().equals(name)) { - node = nodeFactory.createNode((Object) args); - break; - } - } - Assert.assertNotNull("Node not found", node); - CallTarget target = Truffle.getRuntime().createCallTarget(new TestRootNode(node)); - Assert.assertEquals(expectedResult, target.call()); - } - - static class ArgNode extends ValueNode { - - final Object[] arguments; - final int index; - - ArgNode(Object[] args, int index) { - this.arguments = args; - this.index = index; - } - - @Override - Object execute() { - return arguments[index]; - } - - } - - abstract static class BuiltinNode extends ValueNode { - - @Children ArgNode[] parameters; - - BuiltinNode(ArgNode[] parameters) { - this.parameters = adoptChildren(parameters); - } - - BuiltinNode(BuiltinNode prev) { - this(prev.parameters); - } - - } - - @NodeClass(BuiltinNode.class) - static class RuntimeString { - - private final String internal; - - public RuntimeString(String internal) { - this.internal = internal; - } - - @Specialization - static RuntimeString concat(RuntimeString s1, RuntimeString s2) { - return new RuntimeString(s1.internal + s2.internal); - } - - @Specialization - RuntimeString substr(int beginIndex, int endIndex) { - return new RuntimeString(internal.substring(beginIndex, endIndex)); - } - - @Generic - RuntimeString substr(Object beginIndex, Object endIndex) { - return substr(convertInt(beginIndex), convertInt(endIndex)); - } - - static int convertInt(Object value) { - if (value instanceof Number) { - return ((Number) value).intValue(); - } else if (value instanceof String) { - return Integer.parseInt((String) value); - } - throw new RuntimeException("Invalid datatype"); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof RuntimeString) { - return internal.equals(((RuntimeString) obj).internal); - } - return super.equals(obj); - } - - @Override - public int hashCode() { - return internal.hashCode(); - } - - @Override - public String toString() { - return internal; - } - - } - -} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen.test; + +import java.util.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.*; + +/** + * Utility class to provide some test helper functions. + */ +class TestHelper { + + private static ArgumentNode[] arguments(int count) { + ArgumentNode[] nodes = new ArgumentNode[count]; + for (int i = 0; i < nodes.length; i++) { + nodes[i] = new ArgumentNode(i); + } + return nodes; + } + + static TestRootNode create(NodeFactory factory, Object... constants) { + ArgumentNode[] argumentNodes = arguments(factory.getExecutionSignature().size()); + + List argumentList = new ArrayList<>(); + argumentList.addAll(Arrays.asList(constants)); + if (ChildrenNode.class.isAssignableFrom(factory.getNodeClass())) { + argumentList.add(argumentNodes); + } else { + argumentList.addAll(Arrays.asList(argumentNodes)); + } + return new TestRootNode<>(factory.createNode(argumentList.toArray(new Object[argumentList.size()]))); + } + + static Object executeWith(TestRootNode node, Object... values) { + return Truffle.getRuntime().createCallTarget(node).call(new TestArguments(values)); + } + +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java Wed Apr 03 14:41:22 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,50 +22,97 @@ */ package com.oracle.truffle.api.codegen.test; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.codegen.*; -import com.oracle.truffle.api.codegen.test.RuntimeStringTest.RuntimeString; +import com.oracle.truffle.api.codegen.test.BuiltinTest.Str; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; public class TypeSystemTest { - @TypeSystem({int.class, RuntimeString.class}) + @TypeSystem({int.class, Str.class}) static class SimpleTypes { } @TypeSystemReference(SimpleTypes.class) abstract static class ValueNode extends Node { - int executeInt() throws UnexpectedResultException { - return SimpleTypesGen.SIMPLETYPES.expectInteger(execute()); + int executeInt(VirtualFrame frame) throws UnexpectedResultException { + return SimpleTypesGen.SIMPLETYPES.expectInteger(execute(frame)); + } + + Str executeStr(VirtualFrame frame) throws UnexpectedResultException { + return SimpleTypesGen.SIMPLETYPES.expectStr(execute(frame)); } - RuntimeString executeString() { - return new RuntimeString(execute().toString()); + abstract Object execute(VirtualFrame frame); + } + + @TypeSystemReference(SimpleTypes.class) + abstract static class ChildrenNode extends ValueNode { + + @Children protected ValueNode[] children; + + public ChildrenNode(ValueNode... children) { + this.children = adoptChildren(children); } - @SuppressWarnings("static-method") - final long executeSpecial() { - return 42L; + public ChildrenNode(ChildrenNode node) { + this(node.children); } - abstract Object execute(); - } @TypeSystemReference(SimpleTypes.class) - static class TestRootNode extends RootNode { + static class TestRootNode extends RootNode { - @Child private ValueNode node; + @Child private E node; - public TestRootNode(ValueNode node) { + public TestRootNode(E node) { this.node = adoptChild(node); } @Override public Object execute(VirtualFrame frame) { - return node.execute(); + return node.execute(frame); + } + + public E getNode() { + return node; } } + static class TestArguments extends Arguments { + + private final Object[] values; + + public TestArguments(Object... values) { + this.values = values; + } + + public Object[] getValues() { + return values; + } + + public Object get(int index) { + return values[index]; + } + + } + + static class ArgumentNode extends ValueNode { + + final int index; + + public ArgumentNode(int index) { + this.index = index; + } + + @Override + Object execute(VirtualFrame frame) { + return ((TestArguments) frame.getArguments()).get(index); + } + + } + } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java Wed Apr 03 14:41:22 2013 +0200 @@ -41,7 +41,7 @@ * *
    *
  • What do I need to get started? {@link com.oracle.truffle.api.codegen.test.TypeSystemTest}
  • - *
  • How would you generate function nodes for runtime objects? {@link com.oracle.truffle.api.codegen.test.RuntimeStringTest}
  • + *
  • How would you generate function nodes for runtime objects? {@link com.oracle.truffle.api.codegen.test.BuiltinTest}
  • *
*

* diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java Wed Apr 03 14:41:22 2013 +0200 @@ -86,12 +86,12 @@ @Override public boolean getBoolean(FrameSlot slot) { - return (Boolean) get(slot, Float.class, UNDEFINED_BOOLEAN); + return (Boolean) get(slot, Boolean.class, UNDEFINED_BOOLEAN); } @Override public void setBoolean(FrameSlot slot, boolean value) { - set(slot, Float.class, value); + set(slot, Boolean.class, value); } @Override diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java Wed Apr 03 14:41:22 2013 +0200 @@ -30,10 +30,9 @@ import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; import com.oracle.truffle.codegen.processor.typesystem.*; -public class ExecutableTypeMethodParser extends MethodParser { +public class ExecutableTypeMethodParser extends NodeMethodParser { public ExecutableTypeMethodParser(ProcessorContext context, NodeData node) { super(context, node); @@ -43,15 +42,16 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + List types = new ArrayList<>(); types.addAll(getNode().getTypeSystem().getPrimitiveTypeMirrors()); types.add(getContext().getType(void.class)); - ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types, false, Cardinality.ONE); - - List parameters = new ArrayList<>(); - parameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true)); - return new MethodSpec(new ArrayList(), returnTypeSpec, parameters); + ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types); + returnTypeSpec.setSignature(true); + MethodSpec spec = new MethodSpec(returnTypeSpec); + spec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame())); + return spec; } @Override diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Wed Apr 03 14:41:22 2013 +0200 @@ -31,9 +31,8 @@ import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.*; -public class GenericParser extends MethodParser { +public class GenericParser extends NodeMethodParser { public GenericParser(ProcessorContext context, NodeData node) { super(context, node); @@ -45,18 +44,20 @@ } @Override - protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, boolean optional) { + protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) { List execTypes = nodeData.findGenericExecutableTypes(getContext()); List types = new ArrayList<>(); for (ExecutableTypeData type : execTypes) { types.add(type.getType().getPrimitiveType()); } - return new ParameterSpec(valueName, types, false, Cardinality.ONE); + ParameterSpec spec = new ParameterSpec(valueName, types); + spec.setSignature(true); + return spec; } @Override protected ParameterSpec createReturnParameterSpec() { - return super.createValueParameterSpec("returnValue", getNode(), false); + return super.createValueParameterSpec("returnValue", getNode()); } @Override diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java Thu Mar 28 17:11:06 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.codegen.processor.node; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.node.NodeFieldData.*; -import com.oracle.truffle.codegen.processor.template.*; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; - -public abstract class MethodParser extends TemplateMethodParser { - - public MethodParser(ProcessorContext context, NodeData node) { - super(context, node); - } - - public NodeData getNode() { - return template; - } - - protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, boolean optional) { - return new ParameterSpec(valueName, nodeData, optional, Cardinality.ONE); - } - - protected ParameterSpec createReturnParameterSpec() { - return createValueParameterSpec("operation", getNode(), false); - } - - @Override - public boolean isParsable(ExecutableElement method) { - return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; - } - - @SuppressWarnings("unused") - protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, String shortCircuitName) { - List defaultParameters = new ArrayList<>(); - - if (getNode().supportsFrame()) { - defaultParameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true)); - } - - TypeMirror declaredType = Utils.findNearestEnclosingType(method).asType(); - - List prefixTypes = new ArrayList<>(); - - if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(declaredType, template.getNodeType())) { - prefixTypes.add(getNode().getTemplateType().asType()); - } - - for (NodeFieldData field : getNode().getFields()) { - if (field.getKind() == FieldKind.FIELD) { - ParameterSpec spec = new ParameterSpec(field.getName(), field.getType(), true); - spec.setLocal(true); - defaultParameters.add(spec); - } - } - - for (NodeFieldData field : getNode().getFields()) { - if (field.getExecutionKind() == ExecutionKind.IGNORE) { - continue; - } - - if (field.getExecutionKind() == ExecutionKind.DEFAULT) { - ParameterSpec spec = createValueParameterSpec(field.getName(), field.getNodeData(), false); - if (field.getKind() == FieldKind.CHILDREN) { - spec.setCardinality(Cardinality.MULTIPLE); - spec.setIndexed(true); - } - defaultParameters.add(spec); - } else if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) { - String valueName = field.getName(); - if (shortCircuitName != null && valueName.equals(shortCircuitName)) { - break; - } - - defaultParameters.add(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class), false)); - defaultParameters.add(createValueParameterSpec(valueName, field.getNodeData(), false)); - } else { - assert false; - } - } - - return new MethodSpec(prefixTypes, createReturnParameterSpec(), defaultParameters); - } - - private static String shortCircuitValueName(String valueName) { - return "has" + Utils.firstLetterUpperCase(valueName); - } - -} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Wed Apr 03 14:41:22 2013 +0200 @@ -117,24 +117,28 @@ } } - private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod target, TemplateMethod sourceMethod, TemplateMethod castMethod, String unexpectedValueName) { + private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) { CodeTreeBuilder builder = parent.create(); - boolean castedValues = sourceMethod != castMethod; + boolean castedValues = sourceMethod != targetMethod; builder.startGroup(); - ExecutableElement method = target.getMethod(); + ExecutableElement method = targetMethod.getMethod(); if (method == null) { - throw new IllegalStateException("Cannot call synthtetic operation methods."); + throw new IllegalStateException("Cannot call synthetic operation methods."); } TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement()); - NodeData node = (NodeData) castMethod.getTemplate(); + NodeData node = (NodeData) targetMethod.getTemplate(); TypeSystemData typeSystem = node.getTypeSystem(); - boolean accessible = target.canBeAccessedByInstanceOf(node.getNodeType()); + boolean accessible = targetMethod.canBeAccessedByInstanceOf(node.getNodeType()); if (accessible) { if (builder.findMethod().getModifiers().contains(STATIC)) { - builder.string(THIS_NODE_LOCAL_VAR_NAME); + if (method.getModifiers().contains(STATIC)) { + builder.type(targetClass.asType()); + } else { + builder.string(THIS_NODE_LOCAL_VAR_NAME); + } } else { builder.string("super"); } @@ -143,8 +147,8 @@ builder.type(targetClass.asType()); } else { ActualParameter parameter = null; - for (ActualParameter searchParameter : target.getParameters()) { - if (!searchParameter.getSpecification().isOptional()) { + for (ActualParameter searchParameter : targetMethod.getParameters()) { + if (searchParameter.getSpecification().isSignature()) { parameter = searchParameter; break; } @@ -172,10 +176,10 @@ builder.string("."); builder.startCall(method.getSimpleName().toString()); - for (ActualParameter targetParameter : castMethod.getParameters()) { + for (ActualParameter targetParameter : targetMethod.getParameters()) { ActualParameter valueParameter = sourceMethod.findParameter(targetParameter.getLocalName()); if (valueParameter == null) { - continue; + valueParameter = targetParameter; } TypeData targetType = targetParameter.getActualTypeData(typeSystem); @@ -257,12 +261,34 @@ body.string(".").startCall(methodName); } - private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean onSpecialization, + private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData sourceSpecialization, SpecializationData targetSpecialization, boolean castValues, CodeTree guardedStatements, CodeTree elseStatements) { + NodeData node = targetSpecialization.getNode(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); - CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, valueSpecialization, guardedSpecialization); - CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, valueSpecialization, guardedSpecialization, onSpecialization); + CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, sourceSpecialization, targetSpecialization); + CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, sourceSpecialization, targetSpecialization); + + Set valuesNeedsCast; + if (castValues) { + // cast all + valuesNeedsCast = null; + } else { + // find out which values needs a cast + valuesNeedsCast = new HashSet<>(); + for (GuardData guard : targetSpecialization.getGuards()) { + for (ActualParameter parameter : guard.getParameters()) { + NodeFieldData field = node.findField(parameter.getSpecification().getName()); + if (field == null) { + continue; + } + TypeData typeData = parameter.getActualTypeData(node.getTypeSystem()); + if (typeData != null && !typeData.isGeneric()) { + valuesNeedsCast.add(parameter.getLocalName()); + } + } + } + } int ifCount = 0; @@ -274,9 +300,7 @@ ifCount++; } - if (explicitGuards != null || !onSpecialization) { - builder.tree(createCasts(parent, valueSpecialization, guardedSpecialization)); - } + builder.tree(createCasts(parent, valuesNeedsCast, sourceSpecialization, targetSpecialization)); if (explicitGuards != null) { builder.startIf(); @@ -302,24 +326,22 @@ return builder.getRoot(); } - private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean onSpecialization) { + private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; if (guardedSpecialization.getGuards().size() > 0) { // Explicitly specified guards - for (SpecializationGuardData guard : guardedSpecialization.getGuards()) { - if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) { - builder.string(andOperator); - builder.tree(createTemplateMethodCall(parent, guard.getGuardDeclaration(), valueSpecialization, guardedSpecialization, null)); - andOperator = " && "; - } + for (GuardData guard : guardedSpecialization.getGuards()) { + builder.string(andOperator); + builder.tree(createTemplateMethodCall(parent, valueSpecialization, guard, null)); + andOperator = " && "; } } return builder.isEmpty() ? null : builder.getRoot(); } - private CodeTree createCasts(CodeTreeBuilder parent, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { + private CodeTree createCasts(CodeTreeBuilder parent, Set castWhiteList, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); // Implict guards based on method signature for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { @@ -329,6 +351,10 @@ } ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName()); + if (castWhiteList != null && !castWhiteList.contains(guardedParam.getLocalName())) { + continue; + } + CodeTree cast = createCast(parent, field, valueParam, guardedParam); if (cast == null) { continue; @@ -945,7 +971,7 @@ CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize"); method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); - addInternalValueParameters(method, node.getGenericSpecialization(), false); + addInternalValueParameters(method, node.getGenericSpecialization(), true); CodeTreeBuilder body = method.createBuilder(); body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); @@ -959,7 +985,7 @@ guarded.string(THIS_NODE_LOCAL_VAR_NAME); guarded.end().end(); - body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, true, guarded.getRoot(), null)); + body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, false, guarded.getRoot(), null)); } body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); @@ -1015,7 +1041,7 @@ addInternalValueParameterNames(nextBuilder, next, null, true, true); nextBuilder.end().end(); - invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, false, invokeMethod, nextBuilder.getRoot()); + invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot()); } builder.tree(invokeMethod); @@ -1034,7 +1060,7 @@ emitEncounteredSynthetic(builder); } else { builder.startReturn(); - builder.tree(createTemplateMethodCall(builder, specialization, specialization.getNode().getGenericSpecialization(), specialization, null)); + builder.tree(createTemplateMethodCall(builder, specialization.getNode().getGenericSpecialization(), specialization, null)); builder.end(); // return } @@ -1204,7 +1230,7 @@ if (next != null) { returnSpecialized = createReturnSpecializeAndExecute(builder, next, null); } - builder.tree(createGuardAndCast(builder, null, specialization, specialization, false, executeNode, returnSpecialized)); + builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized)); } private CodeTree createDeoptimize(CodeTreeBuilder parent) { @@ -1227,7 +1253,7 @@ builder.startCall(factoryClassName(node), "specialize"); builder.string("this"); builder.typeLiteral(builder.findMethod().getEnclosingElement().asType()); - addInternalValueParameterNames(builder, specialization, null, false, true); + addInternalValueParameterNames(builder, specialization, null, true, true); builder.end(); // call replace, call specialize } else { builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); @@ -1265,7 +1291,7 @@ builder.end().end(); } else { builder.startReturn(); - builder.tree(createTemplateMethodCall(builder, specialization, specialization, specialization, null)); + builder.tree(createTemplateMethodCall(builder, specialization, specialization, null)); builder.end(); // return } @@ -1296,7 +1322,7 @@ private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { for (TemplateMethod listener : node.getSpecializationListeners()) { builder.startStatement(); - builder.tree(createTemplateMethodCall(builder, listener, listener, listener, null)); + builder.tree(createTemplateMethodCall(builder, listener, listener, null)); builder.end(); // statement } } @@ -1392,7 +1418,7 @@ builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = "); ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex); - builder.tree(createTemplateMethodCall(builder, shortCircuitData, shortCircuitData, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null)); + builder.tree(createTemplateMethodCall(builder, shortCircuitData, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null)); builder.end(); // statement @@ -1445,7 +1471,7 @@ builder.startStatement(); builder.startCall("replace"); builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState"); - addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false, true); + addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, true, true); builder.end(); builder.end(); // call replace builder.end(); // statement diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Wed Apr 03 14:41:22 2013 +0200 @@ -187,22 +187,11 @@ methods.addAll(getSpecializationListeners()); methods.addAll(getExecutableTypes()); - methods.addAll(getGuards()); methods.addAll(getShortCircuits()); return methods; } - public List findGuards(String name) { - List foundGuards = new ArrayList<>(); - for (GuardData guardData : getGuards()) { - if (guardData.getMethodName().equals(name)) { - foundGuards.add(guardData); - } - } - return foundGuards; - } - public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type) { List types = findGenericExecutableTypes(context); for (ExecutableTypeData availableType : types) { @@ -312,6 +301,7 @@ return null; } + @Override public TypeSystemData getTypeSystem() { return typeSystem; } @@ -323,7 +313,7 @@ private String dump(int level) { String indent = ""; for (int i = 0; i < level; i++) { - indent += " "; + indent += " "; } StringBuilder builder = new StringBuilder(); @@ -334,7 +324,6 @@ dumpProperty(builder, indent, "fields", getFields()); dumpProperty(builder, indent, "executableTypes", getExecutableTypes()); dumpProperty(builder, indent, "specializations", getSpecializations()); - dumpProperty(builder, indent, "guards", getGuards()); dumpProperty(builder, indent, "messages", collectMessages()); if (getDeclaredChildren().size() > 0) { builder.append(String.format("\n%s children = [", indent)); @@ -352,7 +341,7 @@ if (value instanceof List) { List list = (List) value; if (!list.isEmpty()) { - b.append(String.format("\n%s %s = %s", indent, propertyName, dumpList((List) value))); + b.append(String.format("\n%s %s = %s", indent, propertyName, dumpList(indent, (List) value))); } } else { if (value != null) { @@ -361,7 +350,7 @@ } } - private static String dumpList(List array) { + private static String dumpList(String indent, List array) { if (array == null) { return "null"; } @@ -375,12 +364,12 @@ StringBuilder b = new StringBuilder(); b.append("["); for (Object object : array) { - b.append("\n"); - b.append(" "); + b.append("\n "); + b.append(indent); b.append(object); b.append(", "); } - b.append("\n ]"); + b.append("\n ").append(indent).append("]"); return b.toString(); } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java Wed Apr 03 14:41:22 2013 +0200 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.codegen.processor.node; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.node.NodeFieldData.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; + +public abstract class NodeMethodParser extends TemplateMethodParser { + + public NodeMethodParser(ProcessorContext context, NodeData node) { + super(context, node); + } + + public NodeData getNode() { + return template; + } + + protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) { + ParameterSpec spec = new ParameterSpec(valueName, nodeTypeMirrors(nodeData)); + spec.setSignature(true); + return spec; + } + + private static List nodeTypeMirrors(NodeData nodeData) { + Set typeMirrors = new LinkedHashSet<>(); + + for (ExecutableTypeData typeData : nodeData.getExecutableTypes()) { + typeMirrors.add(typeData.getType().getPrimitiveType()); + } + + typeMirrors.add(nodeData.getTypeSystem().getGenericType()); + + return new ArrayList<>(typeMirrors); + } + + protected ParameterSpec createReturnParameterSpec() { + return createValueParameterSpec("operation", getNode()); + } + + @Override + public boolean isParsable(ExecutableElement method) { + return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; + } + + @SuppressWarnings("unused") + protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, String shortCircuitName) { + MethodSpec methodSpec = new MethodSpec(createReturnParameterSpec()); + + if (getNode().supportsFrame()) { + methodSpec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame())); + } + + resolveAndAddImplicitThis(methodSpec, method); + + for (NodeFieldData field : getNode().getFields()) { + if (field.getKind() == FieldKind.FIELD) { + ParameterSpec spec = new ParameterSpec(field.getName(), field.getType()); + spec.setLocal(true); + methodSpec.addOptional(spec); + } + } + + for (NodeFieldData field : getNode().getFields()) { + if (field.getExecutionKind() == ExecutionKind.IGNORE) { + continue; + } + + if (field.getExecutionKind() == ExecutionKind.DEFAULT) { + ParameterSpec spec = createValueParameterSpec(field.getName(), field.getNodeData()); + if (field.getKind() == FieldKind.CHILDREN) { + spec.setCardinality(Cardinality.MULTIPLE); + spec.setIndexed(true); + } + methodSpec.addRequired(spec); + } else if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) { + String valueName = field.getName(); + if (shortCircuitName != null && valueName.equals(shortCircuitName)) { + break; + } + + methodSpec.addRequired(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class))); + methodSpec.addRequired(createValueParameterSpec(valueName, field.getNodeData())); + } else { + assert false; + } + } + + return methodSpec; + } + + protected void resolveAndAddImplicitThis(MethodSpec methodSpec, ExecutableElement method) { + TypeMirror declaredType = Utils.findNearestEnclosingType(method).asType(); + + if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(declaredType, getContext().getTruffleTypes().getNode())) { + methodSpec.addImplicitRequiredType(getNode().getTemplateType().asType()); + } + } + + private static String shortCircuitValueName(String valueName) { + return "has" + Utils.firstLetterUpperCase(valueName); + } + +} diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Wed Apr 03 14:41:22 2013 +0200 @@ -186,7 +186,7 @@ } for (NodeData splittedNode : nodes) { - finalizeSpecializations(splittedNode); + finalizeSpecializations(elements, splittedNode); verifyNode(splittedNode); } @@ -254,7 +254,6 @@ } private void parseMethods(final NodeData node, List elements) { - node.setGuards(new GuardParser(context, node, node.getTypeSystem()).parse(elements)); node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements)); node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements)); List generics = new GenericParser(context, node).parse(elements); @@ -267,13 +266,17 @@ node.setSpecializations(allSpecializations); } - private void finalizeSpecializations(final NodeData node) { + private void finalizeSpecializations(List elements, final NodeData node) { List specializations = new ArrayList<>(node.getSpecializations()); if (specializations.isEmpty()) { return; } + for (SpecializationData specialization : specializations) { + matchGuards(elements, specialization); + } + List generics = new ArrayList<>(); for (SpecializationData spec : specializations) { if (spec.isGeneric()) { @@ -332,13 +335,7 @@ specializations.add(new SpecializationData(uninializedMethod, false, true)); } - Collections.sort(specializations, new Comparator() { - - @Override - public int compare(SpecializationData o1, SpecializationData o2) { - return compareSpecialization(node.getTypeSystem(), o1, o2); - } - }); + Collections.sort(specializations); node.setSpecializations(specializations); @@ -358,6 +355,31 @@ } } + private void matchGuards(List elements, SpecializationData specialization) { + if (specialization.getGuardDefinitions().isEmpty()) { + specialization.setGuards(Collections. emptyList()); + return; + } + + List foundGuards = new ArrayList<>(); + List methods = ElementFilter.methodsIn(elements); + for (String guardDefinition : specialization.getGuardDefinitions()) { + GuardParser parser = new GuardParser(context, specialization, guardDefinition); + List guards = parser.parse(methods); + if (!guards.isEmpty()) { + foundGuards.add(guards.get(0)); + } else { + // error no guard found + MethodSpec spec = parser.createSpecification(specialization.getMethod(), null); + spec.applyTypeDefinitions("types"); + specialization.addError("Guard with method name '%s' not found. Expected signature: %n%s", guardDefinition, spec.toSignatureString("guard")); + } + } + + specialization.setGuards(foundGuards); + + } + private static List calculateSpecializationIds(List specializations) { int lastSize = -1; List> signatureChunks = new ArrayList<>(); @@ -531,17 +553,17 @@ boolean valid = true; int args = -1; for (SpecializationData specializationData : nodeData.getSpecializations()) { - int specializationArgs = 0; + int signatureArgs = 0; for (ActualParameter param : specializationData.getParameters()) { - if (!param.getSpecification().isOptional()) { - specializationArgs++; + if (param.getSpecification().isSignature()) { + signatureArgs++; } } - if (args != -1 && args != specializationArgs) { + if (args != -1 && args != signatureArgs) { valid = false; break; } - args = specializationArgs; + args = signatureArgs; } if (!valid) { for (SpecializationData specialization : nodeData.getSpecializations()) { @@ -717,7 +739,11 @@ NodeFieldData fieldData = new NodeFieldData(var, findAccessElement(var), mirror, kind, execution); if (type != null && mirror != null) { - NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(type)); + TypeElement typeElement = Utils.fromTypeMirror(type); + if (typeElement == null) { + return null; + } + NodeData fieldNodeData = resolveNode(typeElement); fieldData.setNode(fieldNodeData); if (fieldNodeData == null) { @@ -927,14 +953,12 @@ } private static void verifySpecializationOrder(NodeData node) { - TypeSystemData typeSystem = node.getTypeSystem(); List specializations = node.getSpecializations(); - for (int i = 0; i < specializations.size(); i++) { SpecializationData m1 = specializations.get(i); for (int j = i + 1; j < specializations.size(); j++) { SpecializationData m2 = specializations.get(j); - int inferredOrder = compareSpecializationWithoutOrder(typeSystem, m1, m2); + int inferredOrder = m1.compareBySignature(m2); if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { int specOrder = m1.getOrder() - m2.getOrder(); @@ -974,72 +998,6 @@ } } - private static int compareSpecialization(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) { - if (m1 == m2) { - return 0; - } - int result = compareSpecializationWithoutOrder(typeSystem, m1, m2); - if (result == 0) { - if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { - return m1.getOrder() - m2.getOrder(); - } - } - return result; - } - - private static int compareSpecializationWithoutOrder(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) { - if (m1 == m2) { - return 0; - } - - if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { - return m1.getOrder() - m2.getOrder(); - } else if (m1.isUninitialized() && !m2.isUninitialized()) { - return -1; - } else if (!m1.isUninitialized() && m2.isUninitialized()) { - return 1; - } else if (m1.isGeneric() && !m2.isGeneric()) { - return 1; - } else if (!m1.isGeneric() && m2.isGeneric()) { - return -1; - } - - if (m1.getTemplate() != m2.getTemplate()) { - throw new UnsupportedOperationException("Cannot compare two specializations with different templates."); - } - - int result = compareActualParameter(typeSystem, m1.getReturnType(), m2.getReturnType()); - - for (ActualParameter p1 : m1.getParameters()) { - NodeFieldData field = m1.getNode().findField(p1.getSpecification().getName()); - if (field == null) { - continue; - } - ActualParameter p2 = m2.findParameter(p1.getLocalName()); - - if (p1 != null && p2 != null && !Utils.typeEquals(p1.getActualType(), p2.getActualType())) { - int typeResult = compareActualParameter(typeSystem, p1, p2); - if (result == 0) { - result = typeResult; - } else if (Math.signum(result) != Math.signum(typeResult)) { - // We cannot define an order. - return 0; - } - } - } - return result; - } - - private static int compareActualParameter(TypeSystemData typeSystem, ActualParameter p1, ActualParameter p2) { - int index1 = typeSystem.findType(p1.getActualType()); - int index2 = typeSystem.findType(p2.getActualType()); - - assert index1 != index2; - assert !(index1 == -1 ^ index2 == -1); - - return index1 - index2; - } - @Override public Class getAnnotationType() { return null; diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java Wed Apr 03 14:41:22 2013 +0200 @@ -32,7 +32,7 @@ import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind; import com.oracle.truffle.codegen.processor.template.*; -public class ShortCircuitParser extends MethodParser { +public class ShortCircuitParser extends NodeMethodParser { private final Set shortCircuitValues; @@ -54,7 +54,7 @@ @Override protected ParameterSpec createReturnParameterSpec() { - return new ParameterSpec("has", getContext().getType(boolean.class), false); + return new ParameterSpec("has", getContext().getType(boolean.class)); } @Override diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Wed Apr 03 14:41:22 2013 +0200 @@ -28,6 +28,7 @@ import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.node.NodeFieldData.*; import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.typesystem.*; public class SpecializationData extends TemplateMethod { @@ -35,7 +36,8 @@ private final boolean generic; private final boolean uninitialized; private final List exceptions; - private List guards; + private List guardDefinitions = Collections.emptyList(); + private List guards; private List shortCircuits; private boolean useSpecializationsForGeneric = true; private NodeData node; @@ -93,6 +95,31 @@ return false; } + @Override + public int compareBySignature(TemplateMethod other) { + if (this == other) { + return 0; + } else if (!(other instanceof SpecializationData)) { + return super.compareBySignature(other); + } + + SpecializationData m2 = (SpecializationData) other; + + if (getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { + return getOrder() - m2.getOrder(); + } else if (isUninitialized() ^ m2.isUninitialized()) { + return isUninitialized() ? -1 : 1; + } else if (isGeneric() ^ m2.isGeneric()) { + return isGeneric() ? 1 : -1; + } + + if (getTemplate() != m2.getTemplate()) { + throw new UnsupportedOperationException("Cannot compare two specializations with different templates."); + } + + return super.compareBySignature(m2); + } + public NodeData getNode() { return node; } @@ -101,10 +128,14 @@ this.node = node; } - public void setGuards(List guards) { + public void setGuards(List guards) { this.guards = guards; } + public void setGuardDefinitions(List guardDefinitions) { + this.guardDefinitions = guardDefinitions; + } + public int getOrder() { return order; } @@ -121,7 +152,11 @@ return exceptions; } - public List getGuards() { + public List getGuardDefinitions() { + return guardDefinitions; + } + + public List getGuards() { return guards; } @@ -152,12 +187,11 @@ } public boolean hasDynamicGuards() { - for (SpecializationGuardData guard : getGuards()) { - if (guard.isOnExecution()) { - return true; - } - } - return false; + return !getGuards().isEmpty(); } + @Override + public String toString() { + return String.format("%s [id = %s, method = %s, guards = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards()); + } } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java Wed Apr 03 14:41:22 2013 +0200 @@ -30,7 +30,7 @@ import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; -public class SpecializationListenerParser extends MethodParser { +public class SpecializationListenerParser extends NodeMethodParser { public SpecializationListenerParser(ProcessorContext context, NodeData node) { super(context, node); @@ -43,7 +43,7 @@ @Override protected ParameterSpec createReturnParameterSpec() { - return new ParameterSpec("void", getContext().getType(void.class), false); + return new ParameterSpec("void", getContext().getType(void.class)); } @Override diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java Wed Apr 03 14:41:22 2013 +0200 @@ -31,9 +31,8 @@ import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; -import com.oracle.truffle.codegen.processor.typesystem.*; -public class SpecializationMethodParser extends MethodParser { +public class SpecializationMethodParser extends NodeMethodParser { public SpecializationMethodParser(ProcessorContext context, NodeData operation) { super(context, operation); @@ -54,7 +53,7 @@ return Specialization.class; } - private SpecializationData parseSpecialization(TemplateMethod method) { + private static SpecializationData parseSpecialization(TemplateMethod method) { int order = Utils.getAnnotationValue(Integer.class, method.getMarkerAnnotation(), "order"); if (order < 0 && order != Specialization.DEFAULT_ORDER) { method.addError("Invalid order attribute %d. The value must be >= 0 or the default value."); @@ -80,76 +79,10 @@ } }); SpecializationData specialization = new SpecializationData(method, order, exceptionData); - AnnotationValue guardsValue = Utils.getAnnotationValue(method.getMarkerAnnotation(), "guards"); List guardDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards"); - List guardData = new ArrayList<>(guardDefs.size()); - for (int i = 0; i < guardDefs.size(); i++) { - String guardMethod = guardDefs.get(i); - - SpecializationGuardData assignedGuard = new SpecializationGuardData(specialization, guardsValue, guardMethod, true, true); - - guardData.add(assignedGuard); - - GuardData compatibleGuard = matchSpecializationGuard(specialization, assignedGuard); - if (compatibleGuard != null) { - assignedGuard.setGuardDeclaration(compatibleGuard); - } - } - - specialization.setGuards(guardData); + specialization.setGuardDefinitions(guardDefs); return specialization; } - private GuardData matchSpecializationGuard(SpecializationData specialization, SpecializationGuardData specializationGuard) { - List foundGuards = getNode().findGuards(specializationGuard.getGuardMethod()); - - GuardData compatibleGuard = null; - for (GuardData guardData : foundGuards) { - if (isGuardCompatible(specialization, guardData)) { - compatibleGuard = guardData; - break; - } - } - - if (compatibleGuard == null) { - ParameterSpec returnTypeSpec = new ParameterSpec("returnValue", getContext().getType(boolean.class), false); - List expectedParameterSpecs = new ArrayList<>(); - - for (ActualParameter param : specialization.getParameters()) { - ParameterSpec spec = param.getSpecification(); - expectedParameterSpecs.add(new ParameterSpec(spec.getName(), param.getActualType(), false)); - } - List typeDefs = createTypeDefinitions(returnTypeSpec, expectedParameterSpecs); - String expectedSignature = TemplateMethodParser.createExpectedSignature(specializationGuard.getGuardMethod(), returnTypeSpec, expectedParameterSpecs, typeDefs); - specializationGuard.addError("No guard with signature '%s' found in type system.", expectedSignature); - } - - return compatibleGuard; - } - - private static boolean isGuardCompatible(SpecializationData specialization, GuardData guard) { - Iterator guardParameters = guard.getParameters().iterator(); - for (ActualParameter param : specialization.getParameters()) { - if (param.getSpecification().isOptional()) { - continue; - } - if (!guardParameters.hasNext()) { - return false; - } - ActualParameter guardParam = guardParameters.next(); - if (!Utils.typeEquals(guardParam.getActualType(), param.getActualType()) && !guardParam.getSpecification().isOptional()) { - return false; - } - } - while (guardParameters.hasNext()) { - ActualParameter param = guardParameters.next(); - if (!param.getSpecification().isOptional()) { - return false; - } - } - - return true; - } - } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java Wed Apr 03 14:41:22 2013 +0200 @@ -26,33 +26,74 @@ import javax.lang.model.type.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; + public class MethodSpec { - private final List implicitTypes; + private final List implicitRequiredTypes = new ArrayList<>(); private final ParameterSpec returnType; - private final List parameters; + private final List optional = new ArrayList<>(); + private final List required = new ArrayList<>(); + + private boolean variableRequiredArguments; + private List typeDefinitions; - public MethodSpec(List prefixTypes, ParameterSpec returnType, List parameters) { - this.implicitTypes = prefixTypes; + public MethodSpec(ParameterSpec returnType) { this.returnType = returnType; - this.parameters = parameters; + } + + public void setVariableRequiredArguments(boolean variableArguments) { + this.variableRequiredArguments = variableArguments; } - public List getImplicitTypes() { - return implicitTypes; + public boolean isVariableRequiredArguments() { + return variableRequiredArguments; + } + + public void addImplicitRequiredType(TypeMirror type) { + this.implicitRequiredTypes.add(type); + } + + public void addOptional(ParameterSpec spec) { + optional.add(spec); + } + + public void addRequired(ParameterSpec spec) { + required.add(spec); + } + + public List getImplicitRequiredTypes() { + return implicitRequiredTypes; } public ParameterSpec getReturnType() { return returnType; } - public List getParameters() { - return parameters; + public List getRequired() { + return required; + } + + public List getOptional() { + return optional; + } + + public void makeTypeDefinitions() { + + } + + public List getAll() { + List specs = new ArrayList<>(); + specs.add(getReturnType()); + specs.addAll(getOptional()); + specs.addAll(getRequired()); + return specs; } public ParameterSpec findParameterSpec(String name) { - for (ParameterSpec spec : parameters) { + for (ParameterSpec spec : getAll()) { if (spec.getName().equals(name)) { return spec; } @@ -60,4 +101,131 @@ return null; } + public void applyTypeDefinitions(String prefix) { + this.typeDefinitions = createTypeDefinitions(prefix); + } + + private List createTypeDefinitions(String prefix) { + List typeDefs = new ArrayList<>(); + + int defIndex = 0; + for (ParameterSpec spec : getAll()) { + List allowedTypes = spec.getAllowedTypes(); + List types = spec.getAllowedTypes(); + if (types != null && allowedTypes.size() > 1) { + TypeDef foundDef = null; + for (TypeDef def : typeDefs) { + if (allowedTypes.equals(def.getTypes())) { + foundDef = def; + break; + } + } + if (foundDef == null) { + foundDef = new TypeDef(types, prefix + defIndex); + typeDefs.add(foundDef); + defIndex++; + } + + spec.setTypeDefinition(foundDef); + } + } + + return typeDefs; + } + + public String toSignatureString(String methodName) { + StringBuilder b = new StringBuilder(); + b.append(" "); + b.append(createTypeSignature(returnType, true)); + + b.append(" "); + b.append(methodName); + b.append("("); + + String sep = ""; + + for (ParameterSpec optionalSpec : getOptional()) { + b.append(sep); + b.append("["); + b.append(createTypeSignature(optionalSpec, false)); + b.append("]"); + sep = ", "; + } + + for (ParameterSpec requiredSpec : getRequired()) { + b.append(sep); + if (requiredSpec.getCardinality() == Cardinality.MULTIPLE) { + b.append("{"); + } + b.append(createTypeSignature(requiredSpec, false)); + if (requiredSpec.getCardinality() == Cardinality.MULTIPLE) { + b.append("}"); + } + sep = ", "; + } + + b.append(")"); + + if (typeDefinitions != null && !typeDefinitions.isEmpty()) { + b.append("\n\n"); + + String lineSep = ""; + for (TypeDef def : typeDefinitions) { + b.append(lineSep); + b.append(" <").append(def.getName()).append(">"); + b.append(" = {"); + String separator = ""; + for (TypeMirror type : def.getTypes()) { + b.append(separator).append(Utils.getSimpleName(type)); + separator = ", "; + } + b.append("}"); + lineSep = "\n"; + + } + } + return b.toString(); + } + + private static String createTypeSignature(ParameterSpec spec, boolean typeOnly) { + StringBuilder builder = new StringBuilder(); + TypeDef foundTypeDef = spec.getTypeDefinition(); + if (foundTypeDef != null) { + builder.append("<" + foundTypeDef.getName() + ">"); + } else if (spec.getAllowedTypes().size() >= 1) { + builder.append(Utils.getSimpleName(spec.getAllowedTypes().get(0))); + } else { + builder.append("void"); + } + if (!typeOnly) { + builder.append(" "); + builder.append(spec.getName()); + } + return builder.toString(); + } + + @Override + public String toString() { + return toSignatureString("methodName"); + } + + static class TypeDef { + + private final List types; + private final String name; + + public TypeDef(List types, String name) { + this.types = types; + this.name = name; + } + + public List getTypes() { + return types; + } + + public String getName() { + return name; + } + } + } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java Wed Apr 03 14:41:22 2013 +0200 @@ -27,8 +27,7 @@ import javax.lang.model.type.*; import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.node.*; -import com.oracle.truffle.codegen.processor.typesystem.*; +import com.oracle.truffle.codegen.processor.template.MethodSpec.TypeDef; public class ParameterSpec { @@ -38,37 +37,47 @@ private final String name; private final List allowedTypes; - private final boolean optional; - private Cardinality cardinality; + + /** Cardinality one or multiple. */ + private Cardinality cardinality = Cardinality.ONE; + /** Type is part of the method signature. Relevant for comparisons. */ + private boolean signature; + /** Type must be indexed when parsing. */ private boolean indexed; + /** Type is bound to local final variable. */ private boolean local; - public ParameterSpec(String name, List allowedTypes, boolean optional, Cardinality cardinality) { - this.allowedTypes = allowedTypes; - this.name = name; - this.optional = optional; - this.cardinality = cardinality; + private TypeDef typeDefinition; + + public ParameterSpec(String name, TypeMirror... allowedTypes) { + this(name, Arrays.asList(allowedTypes)); } - /** Type constructor. */ - public ParameterSpec(String name, TypeMirror singleFixedType, boolean optional) { - this(name, Arrays.asList(singleFixedType), optional, Cardinality.ONE); + public ParameterSpec(String name, List allowedTypes) { + this.name = name; + this.allowedTypes = allowedTypes; } - /** Type system value constructor. */ - public ParameterSpec(String name, TypeSystemData typeSystem, boolean optional, Cardinality cardinality) { - this(name, typeSystem.getPrimitiveTypeMirrors(), optional, cardinality); + void setTypeDefinition(TypeDef typeDefinition) { + this.typeDefinition = typeDefinition; } - /** Node value constructor. */ - public ParameterSpec(String name, NodeData nodeData, boolean optional, Cardinality cardinality) { - this(name, nodeTypeMirrors(nodeData), optional, cardinality); + TypeDef getTypeDefinition() { + return typeDefinition; + } + + public void setSignature(boolean signature) { + this.signature = signature; } public void setLocal(boolean local) { this.local = local; } + public boolean isSignature() { + return signature; + } + public boolean isLocal() { return local; } @@ -85,27 +94,11 @@ this.cardinality = cardinality; } - private static List nodeTypeMirrors(NodeData nodeData) { - Set typeMirrors = new LinkedHashSet<>(); - - for (ExecutableTypeData typeData : nodeData.getExecutableTypes()) { - typeMirrors.add(typeData.getType().getPrimitiveType()); - } - - typeMirrors.add(nodeData.getTypeSystem().getGenericType()); - - return new ArrayList<>(typeMirrors); - } - - public final String getName() { + public String getName() { return name; } - public final boolean isOptional() { - return optional; - } - - public final Cardinality getCardinality() { + public Cardinality getCardinality() { return cardinality; } @@ -122,4 +115,25 @@ return false; } + @Override + public String toString() { + return toSignatureString(false); + } + + public String toSignatureString(boolean typeOnly) { + StringBuilder builder = new StringBuilder(); + if (typeDefinition != null) { + builder.append("<" + typeDefinition.getName() + ">"); + } else if (getAllowedTypes().size() >= 1) { + builder.append(Utils.getSimpleName(getAllowedTypes().get(0))); + } else { + builder.append("void"); + } + if (!typeOnly) { + builder.append(" "); + builder.append(getName()); + } + return builder.toString(); + } + } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java Wed Apr 03 14:41:22 2013 +0200 @@ -28,6 +28,7 @@ import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.api.element.*; +import com.oracle.truffle.codegen.processor.typesystem.*; public abstract class Template extends MessageContainer { @@ -43,6 +44,8 @@ this.annotation = annotation; } + public abstract TypeSystemData getTypeSystem(); + @Override public Element getMessageElement() { return templateType; diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Wed Apr 03 14:41:22 2013 +0200 @@ -28,8 +28,12 @@ import javax.lang.model.type.*; import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.typesystem.*; -public class TemplateMethod extends MessageContainer { +/** + * Note: this class has a natural ordering that is inconsistent with equals. + */ +public class TemplateMethod extends MessageContainer implements Comparable { private String id; private final Template template; @@ -37,7 +41,7 @@ private final ExecutableElement method; private final AnnotationMirror markerAnnotation; private final ActualParameter returnType; - private final List parameters; + private List parameters; public TemplateMethod(String id, Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, List parameters) { @@ -61,6 +65,10 @@ getMessages().addAll(method.getMessages()); } + public void setParameters(List parameters) { + this.parameters = parameters; + } + @Override public Element getMessageElement() { return method; @@ -96,6 +104,16 @@ return returnType; } + public List getRequiredParameters() { + List requiredParameters = new ArrayList<>(); + for (ActualParameter parameter : getParameters()) { + if (getSpecification().getRequired().contains(parameter.getSpecification())) { + requiredParameters.add(parameter); + } + } + return requiredParameters; + } + public List getParameters() { return parameters; } @@ -116,15 +134,6 @@ return Collections.unmodifiableList(allParameters); } - public ActualParameter findParameter(ParameterSpec spec) { - for (ActualParameter param : getParameters()) { - if (param.getSpecification().getName().equals(spec.getName())) { - return param; - } - } - return null; - } - public boolean canBeAccessedByInstanceOf(TypeMirror type) { TypeMirror methodType = Utils.findNearestEnclosingType(getMethod()).asType(); return Utils.isAssignable(type, methodType) || Utils.isAssignable(methodType, type); @@ -148,7 +157,7 @@ @Override public String toString() { - return "id = " + getId() + ", " + getClass().getSimpleName() + " [method = " + getMethod() + "]"; + return String.format("%s [id = %s, method = %s]", getClass().getSimpleName(), getId(), getMethod()); } public ActualParameter getPreviousParam(ActualParameter searchParam) { @@ -161,4 +170,71 @@ } return prev; } + + public List getSignature(TypeSystemData typeSystem) { + List types = new ArrayList<>(); + for (ActualParameter parameter : getReturnTypeAndParameters()) { + if (!parameter.getSpecification().isSignature()) { + continue; + } + TypeData typeData = parameter.getActualTypeData(typeSystem); + if (typeData != null) { + types.add(typeData); + } + } + return types; + } + + @Override + public int compareTo(TemplateMethod o) { + if (this == o) { + return 0; + } + + int compare = compareBySignature(o); + if (compare == 0) { + // if signature sorting failed sort by id + compare = getId().compareTo(o.getId()); + } + if (compare == 0) { + // if still no difference sort by enclosing type name + TypeElement enclosingType1 = Utils.findNearestEnclosingType(getMethod()); + TypeElement enclosingType2 = Utils.findNearestEnclosingType(o.getMethod()); + compare = enclosingType1.getQualifiedName().toString().compareTo(enclosingType2.getQualifiedName().toString()); + } + return compare; + } + + public int compareBySignature(TemplateMethod compareMethod) { + TypeSystemData typeSystem = getTemplate().getTypeSystem(); + if (typeSystem != compareMethod.getTemplate().getTypeSystem()) { + throw new IllegalStateException("Cannot compare two methods with different type systems."); + } + + List signature1 = getSignature(typeSystem); + List signature2 = compareMethod.getSignature(typeSystem); + if (signature1.size() != signature2.size()) { + return signature2.size() - signature1.size(); + } + + int result = 0; + for (int i = 0; i < signature1.size(); i++) { + int typeResult = compareActualParameter(typeSystem, signature1.get(i), signature2.get(i)); + if (result == 0) { + result = typeResult; + } else if (typeResult != 0 && Math.signum(result) != Math.signum(typeResult)) { + // We cannot define an order. + return 0; + } + } + + return result; + } + + private static int compareActualParameter(TypeSystemData typeSystem, TypeData t1, TypeData t2) { + int index1 = typeSystem.findType(t1); + int index2 = typeSystem.findType(t2); + return index1 - index2; + } + } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java Wed Apr 03 14:41:22 2013 +0200 @@ -110,13 +110,7 @@ valid = false; } } - Collections.sort(parsedMethods, new Comparator() { - - @Override - public int compare(TemplateMethod o1, TemplateMethod o2) { - return o1.getMethodName().compareTo(o2.getMethodName()); - } - }); + Collections.sort(parsedMethods); if (!valid && parseNullOnError) { return null; @@ -130,27 +124,25 @@ return null; } + methodSpecification.applyTypeDefinitions("types"); + String id = method.getSimpleName().toString(); AnnotationMirror idAnnotation = Utils.findAnnotationMirror(context.getEnvironment(), method, NodeId.class); if (idAnnotation != null) { id = Utils.getAnnotationValue(String.class, idAnnotation, "value"); } - List typeDefs = createTypeDefinitions(methodSpecification.getReturnType(), methodSpecification.getParameters()); - ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); - List parameterSpecs = new ArrayList<>(); - parameterSpecs.addAll(methodSpecification.getParameters()); ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, false); if (returnTypeMirror == null) { if (emitErrors) { E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList())); - String expectedReturnType = createTypeSignature(returnTypeSpec, typeDefs, true); + String expectedReturnType = returnTypeSpec.toSignatureString(true); String actualReturnType = Utils.getSimpleName(method.getReturnType()); String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, - createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs)); + methodSpecification.toSignatureString(method.getSimpleName().toString())); invalidMethod.addError(message); return invalidMethod; } else { @@ -163,12 +155,12 @@ parameterTypes.add(var.asType()); } - List parameters = parseParameters(parameterTypes, methodSpecification.getImplicitTypes(), parameterSpecs); + List parameters = parseParameters(methodSpecification, parameterTypes); if (parameters == null) { if (isEmitErrors()) { E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList())); String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(methodSpecification, method), - createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs)); + methodSpecification.toSignatureString(method.getSimpleName().toString())); invalidMethod.addError(message); return invalidMethod; } else { @@ -180,87 +172,95 @@ } private static String createActualSignature(MethodSpec spec, ExecutableElement method) { - List types = new ArrayList<>(); - for (TypeMirror implicitType : spec.getImplicitTypes()) { - types.add("implicit " + Utils.getSimpleName(implicitType)); + StringBuilder b = new StringBuilder("("); + String sep = ""; + for (TypeMirror implicitType : spec.getImplicitRequiredTypes()) { + b.append(sep); + b.append("implicit " + Utils.getSimpleName(implicitType)); + sep = ", "; } for (VariableElement var : method.getParameters()) { - types.add(Utils.getSimpleName(var.asType())); - } - - StringBuilder b = new StringBuilder("("); - for (Iterator iterator = types.iterator(); iterator.hasNext();) { - b.append(iterator.next()); - if (iterator.hasNext()) { - b.append(", "); - } + b.append(sep); + b.append(Utils.getSimpleName(var.asType())); + sep = ", "; } b.append(")"); return b.toString(); } - private List parseParameters(List types, List implicitTypes, List parameterSpecs) { - Iterator parameterIterator = types.iterator(); - Iterator implicitParametersIterator = implicitTypes.iterator(); - Iterator specificationIterator = parameterSpecs.iterator(); + private List parseParameters(MethodSpec spec, List parameterTypes) { + List parsedParams = new ArrayList<>(); + ConsumableListIterator types = new ConsumableListIterator<>(parameterTypes); - TypeMirror parameter = parameterIterator.hasNext() ? parameterIterator.next() : null; - TypeMirror implicitParameter = implicitParametersIterator.hasNext() ? implicitParametersIterator.next() : null; - ParameterSpec specification = specificationIterator.hasNext() ? specificationIterator.next() : null; + // parse optional parameters + ConsumableListIterator optionals = new ConsumableListIterator<>(spec.getOptional()); + for (TypeMirror type : types) { + int oldIndex = types.getIndex(); + int optionalCount = 1; + for (ParameterSpec paramspec : optionals) { + ActualParameter optionalParam = matchParameter(paramspec, type, template, 0, false); + if (optionalParam != null) { + optionals.consume(optionalCount); + types.consume(); + parsedParams.add(optionalParam); + break; + } + optionalCount++; + } + if (oldIndex == types.getIndex()) { + // nothing found anymore skip optional + break; + } + } + + List typesWithImplicit = new ArrayList<>(spec.getImplicitRequiredTypes()); + typesWithImplicit.addAll(types.toList()); + types = new ConsumableListIterator<>(typesWithImplicit); int specificationParameterIndex = 0; - List resolvedParameters = new ArrayList<>(); - while (parameter != null || specification != null || implicitParameter != null) { - if (parameter == null || specification == null) { - if (specification != null && (specification.isOptional() || specification.getCardinality() == Cardinality.MULTIPLE)) { - specification = specificationIterator.hasNext() ? specificationIterator.next() : null; + ConsumableListIterator required = new ConsumableListIterator<>(spec.getRequired()); + while (required.get() != null || types.get() != null) { + if (required.get() == null || types.get() == null) { + if (required.get() != null && required.get().getCardinality() == Cardinality.MULTIPLE) { + required.consume(); specificationParameterIndex = 0; continue; } - return null; + break; } - - ActualParameter resolvedParameter = null; - - boolean implicit = false; - if (implicitParameter != null) { - resolvedParameter = matchParameter(specification, implicitParameter, template, specificationParameterIndex, true); - if (resolvedParameter != null) { - implicit = true; - } - } - - if (resolvedParameter == null) { - resolvedParameter = matchParameter(specification, parameter, template, specificationParameterIndex, false); - } - + boolean implicit = types.getIndex() < spec.getImplicitRequiredTypes().size(); + ActualParameter resolvedParameter = matchParameter(required.get(), types.get(), template, specificationParameterIndex, implicit); if (resolvedParameter == null) { - // mismatch - if (specification.isOptional()) { - specification = specificationIterator.hasNext() ? specificationIterator.next() : null; - specificationParameterIndex = 0; - } else { - return null; + if (required.get().getCardinality() == Cardinality.MULTIPLE) { + required.consume(); + continue; } + // direct mismatch but required -> error + return null; } else { - resolvedParameters.add(resolvedParameter); - - // match - if (implicit) { - implicitParameter = implicitParametersIterator.hasNext() ? implicitParametersIterator.next() : null; - } else { - parameter = parameterIterator.hasNext() ? parameterIterator.next() : null; - } - - if (specification.getCardinality() == Cardinality.ONE) { - specification = specificationIterator.hasNext() ? specificationIterator.next() : null; + parsedParams.add(resolvedParameter); + types.consume(); + if (required.get().getCardinality() == Cardinality.ONE) { + required.consume(); specificationParameterIndex = 0; - } else if (specification.getCardinality() == Cardinality.MULTIPLE) { + } else if (required.get().getCardinality() == Cardinality.MULTIPLE) { specificationParameterIndex++; } } } - return resolvedParameters; + + if (!types.toList().isEmpty()) { + // additional types -> error + return null; + } + + if (!required.toList().isEmpty() && !spec.isVariableRequiredArguments()) { + // additional specifications -> error + return null; + } + + // success! + return parsedParams; } private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template typeSystem, int index, boolean implicit) { @@ -275,143 +275,53 @@ return new ActualParameter(specification, resolvedType, index, implicit); } - protected List createTypeDefinitions(ParameterSpec returnType, List parameters) { - List typeDefs = new ArrayList<>(); + /* Helper class for parsing. */ + private static class ConsumableListIterator implements Iterable { - List allParams = new ArrayList<>(); - allParams.add(returnType); - allParams.addAll(parameters); + private final List data; + private int index; + + public ConsumableListIterator(List data) { + this.data = data; + } - int defIndex = 0; - for (ParameterSpec spec : allParams) { - List allowedTypes = spec.getAllowedTypes(); - List types = spec.getAllowedTypes(); - if (types != null && allowedTypes.size() > 1) { - TypeDef foundDef = null; - for (TypeDef def : typeDefs) { - if (allowedTypes.equals(def.getTypes())) { - foundDef = def; - break; - } - } - if (foundDef == null) { - foundDef = new TypeDef(types, "Types" + defIndex); - typeDefs.add(foundDef); - defIndex++; - } + public E get() { + if (index >= data.size()) { + return null; + } + return data.get(index); + } - foundDef.getParameters().add(spec); + public E consume() { + return consume(1); + } + + public E consume(int count) { + if (index + count <= data.size()) { + index += count; + return get(); + } else { + throw new ArrayIndexOutOfBoundsException(count + 1); } } - return typeDefs; - } - - protected static class TypeDef { - - private final List types; - private final String name; - private final List parameters = new ArrayList<>(); - - public TypeDef(List types, String name) { - this.types = types; - this.name = name; + public int getIndex() { + return index; } - public List getParameters() { - return parameters; - } - - public List getTypes() { - return types; + @Override + public Iterator iterator() { + return toList().iterator(); } - public String getName() { - return name; - } - } - - public static String createExpectedSignature(String methodName, ParameterSpec returnType, List parameters, List typeDefs) { - StringBuilder b = new StringBuilder(); - - b.append(" "); - b.append(createTypeSignature(returnType, typeDefs, true)); - - b.append(" "); - b.append(methodName); - b.append("("); - - for (int i = 0; i < parameters.size(); i++) { - ParameterSpec specification = parameters.get(i); - if (specification.isOptional()) { - b.append("["); + public List toList() { + if (index < data.size()) { + return data.subList(index, data.size()); + } else { + return Collections. emptyList(); } - if (specification.getCardinality() == Cardinality.MULTIPLE) { - b.append("{"); - } - - b.append(createTypeSignature(specification, typeDefs, false)); - - if (specification.isOptional()) { - b.append("]"); - } - - if (specification.getCardinality() == Cardinality.MULTIPLE) { - b.append("}"); - } - - if (i < parameters.size() - 1) { - b.append(", "); - } - } - b.append(")"); - - if (!typeDefs.isEmpty()) { - b.append("\n\n"); - - String lineSep = ""; - for (TypeDef def : typeDefs) { - b.append(lineSep); - b.append(" <").append(def.getName()).append(">"); - b.append(" = {"); - String separator = ""; - for (TypeMirror type : def.getTypes()) { - b.append(separator).append(Utils.getSimpleName(type)); - separator = ", "; - } - b.append("}"); - lineSep = "\n"; - - } - } - return b.toString(); - } - - private static String createTypeSignature(ParameterSpec spec, List typeDefs, boolean typeOnly) { - StringBuilder builder = new StringBuilder(); - if (spec.getAllowedTypes().size() > 1) { - TypeDef foundTypeDef = null; - for (TypeDef typeDef : typeDefs) { - if (typeDef.getParameters().contains(spec)) { - foundTypeDef = typeDef; - break; - } - } - if (foundTypeDef != null) { - builder.append("<" + foundTypeDef.getName() + ">"); - } - } else if (spec.getAllowedTypes().size() == 1) { - builder.append(Utils.getSimpleName(spec.getAllowedTypes().get(0))); - } else { - builder.append("void"); - } - if (!typeOnly) { - builder.append(" "); - builder.append(spec.getName()); - } - return builder.toString(); } } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java Wed Apr 03 14:41:22 2013 +0200 @@ -22,12 +22,20 @@ */ package com.oracle.truffle.codegen.processor.typesystem; +import com.oracle.truffle.codegen.processor.node.*; import com.oracle.truffle.codegen.processor.template.*; public class GuardData extends TemplateMethod { - public GuardData(TemplateMethod method) { + private final SpecializationData specialization; + + public GuardData(TemplateMethod method, SpecializationData specialization) { super(method); + this.specialization = specialization; + } + + public SpecializationData getSpecialization() { + return specialization; } } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java Wed Apr 03 14:41:22 2013 +0200 @@ -26,39 +26,68 @@ import java.util.*; import javax.lang.model.element.*; -import javax.lang.model.type.*; import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.node.*; import com.oracle.truffle.codegen.processor.template.*; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; -public class GuardParser extends TemplateMethodParser { +public class GuardParser extends NodeMethodParser { - private final TypeSystemData typeSystem; + private final SpecializationData specialization; + private final String guardName; - public GuardParser(ProcessorContext context, Template template, TypeSystemData typeSystem) { - super(context, template); - this.typeSystem = typeSystem; + public GuardParser(ProcessorContext context, SpecializationData specialization, String guardName) { + super(context, specialization.getNode()); + this.specialization = specialization; + this.guardName = guardName; setEmitErrors(false); setParseNullOnError(false); } @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - List specs = new ArrayList<>(); - specs.add(new ParameterSpec("valueN", typeSystem, false, Cardinality.MULTIPLE)); - ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false); - return new MethodSpec(Collections. emptyList(), returnTypeSpec, specs); + MethodSpec spec = createDefaultMethodSpec(method, mirror, null); + spec.setVariableRequiredArguments(true); + spec.getRequired().clear(); + + for (ActualParameter parameter : specialization.getRequiredParameters()) { + ParameterSpec paramSpec = new ParameterSpec(parameter.getLocalName(), parameter.getActualType(), getNode().getTypeSystem().getGenericType()); + paramSpec.setSignature(true); + spec.addRequired(paramSpec); + } + + return spec; + } + + @Override + protected ParameterSpec createReturnParameterSpec() { + return new ParameterSpec("returnType", getContext().getType(boolean.class)); } @Override public boolean isParsable(ExecutableElement method) { - return true; + return method.getSimpleName().toString().equals(guardName); } @Override public GuardData create(TemplateMethod method) { - return new GuardData(method); + GuardData guard = new GuardData(method, specialization); + /* + * Update parameters in way that parameter specifications match again the node field names + * etc. + */ + List newParameters = new ArrayList<>(); + for (ActualParameter parameter : guard.getParameters()) { + ActualParameter specializationParameter = specialization.findParameter(parameter.getSpecification().getName()); + if (specializationParameter == null) { + newParameters.add(parameter); + } else { + newParameters.add(new ActualParameter(specializationParameter.getSpecification(), parameter.getActualType(), specializationParameter.getIndex(), parameter.isImplicit())); + } + } + guard.setParameters(newParameters); + + return guard; } @Override diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java Wed Apr 03 14:41:22 2013 +0200 @@ -23,15 +23,12 @@ package com.oracle.truffle.codegen.processor.typesystem; import java.lang.annotation.*; -import java.util.*; import javax.lang.model.element.*; -import javax.lang.model.type.*; import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; class TypeCastParser extends TypeSystemMethodParser { @@ -45,10 +42,8 @@ if (targetType == null) { return null; } - List specs = new ArrayList<>(); - specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE)); - ParameterSpec returnTypeSpec = new ParameterSpec("returnType", targetType.getPrimitiveType(), false); - MethodSpec spec = new MethodSpec(Collections. emptyList(), returnTypeSpec, specs); + MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", targetType.getPrimitiveType())); + spec.addRequired(new ParameterSpec("value", getTypeSystem().getPrimitiveTypeMirrors())); return spec; } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java Wed Apr 03 14:41:22 2013 +0200 @@ -23,15 +23,12 @@ package com.oracle.truffle.codegen.processor.typesystem; import java.lang.annotation.*; -import java.util.*; import javax.lang.model.element.*; -import javax.lang.model.type.*; import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; class TypeCheckParser extends TypeSystemMethodParser { @@ -45,10 +42,8 @@ if (targetType == null) { return null; } - List specs = new ArrayList<>(); - specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE)); - ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false); - MethodSpec spec = new MethodSpec(Collections. emptyList(), returnTypeSpec, specs); + MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", getContext().getType(boolean.class))); + spec.addRequired(new ParameterSpec("value", getTypeSystem().getPrimitiveTypeMirrors())); return spec; } diff -r d343737786fe -r 6d884611d4c1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java Thu Mar 28 17:11:06 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java Wed Apr 03 14:41:22 2013 +0200 @@ -43,6 +43,11 @@ super(templateType, null, annotation); } + @Override + public TypeSystemData getTypeSystem() { + return this; + } + void setTypes(List types) { this.types = types; if (types != null) { diff -r d343737786fe -r 6d884611d4c1 make/build-graal.xml diff -r d343737786fe -r 6d884611d4c1 mx/commands.py --- a/mx/commands.py Thu Mar 28 17:11:06 2013 +0100 +++ b/mx/commands.py Wed Apr 03 14:41:22 2013 +0200 @@ -690,8 +690,8 @@ # Exclude all compiler tests and snippets excludes = ['com.oracle.graal.compiler.tests.*', 'com.oracle.graal.jtt.*'] for p in mx.projects(): - excludes += _find_classes_with_annotations(p, None, ['@Snippet', '@ClassSubstitution', '@Test'], includeInnerClasses=True) - excludes += p.find_classes_with_matching_source_line(None, lambda line: 'JaCoCo Exclude' in line, includeInnerClasses=True) + excludes += _find_classes_with_annotations(p, None, ['@Snippet', '@ClassSubstitution', '@Test'], includeInnerClasses=True).keys() + excludes += p.find_classes_with_matching_source_line(None, lambda line: 'JaCoCo Exclude' in line, includeInnerClasses=True).keys() includes = ['com.oracle.graal.*', 'com.oracle.max.*'] agentOptions = { @@ -732,7 +732,7 @@ classes = [] for p in mx.projects(): - classes += _find_classes_with_annotations(p, None, annotations) + classes += _find_classes_with_annotations(p, None, annotations).keys() if len(pos) != 0: classes = [c for c in classes if containsAny(c, pos)] @@ -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): diff -r d343737786fe -r 6d884611d4c1 mx/projects --- a/mx/projects Thu Mar 28 17:11:06 2013 +0100 +++ b/mx/projects Wed Apr 03 14:41:22 2013 +0200 @@ -23,7 +23,7 @@ library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar distribution@GRAAL@path=graal.jar -distribution@GRAAL@dependencies=com.oracle.graal.hotspot.amd64,com.oracle.graal.hotspot.sparc +distribution@GRAAL@dependencies=com.oracle.graal.hotspot.amd64,com.oracle.graal.hotspot.sparc,com.oracle.graal.hotspot # graal.api.runtime project@com.oracle.graal.api.runtime@subDir=graal @@ -98,7 +98,7 @@ project@com.oracle.graal.hotspot@sourceDirs=src project@com.oracle.graal.hotspot@dependencies=com.oracle.graal.replacements,com.oracle.graal.printer project@com.oracle.graal.hotspot@checkstyle=com.oracle.graal.graph -project@com.oracle.graal.hotspot@annotationProcessors=com.oracle.graal.replacements.verifier +project@com.oracle.graal.hotspot@annotationProcessors=com.oracle.graal.replacements.verifier, com.oracle.graal.service.processor project@com.oracle.graal.hotspot@javaCompliance=1.7 # graal.hotspot.amd64 @@ -437,3 +437,5 @@ project@com.oracle.truffle.sl.test@checkstyle=com.oracle.graal.graph project@com.oracle.truffle.sl.test@javaCompliance=1.7 + + diff -r d343737786fe -r 6d884611d4c1 mxtool/mx.py --- a/mxtool/mx.py Thu Mar 28 17:11:06 2013 +0100 +++ b/mxtool/mx.py Wed Apr 03 14:41:22 2013 +0200 @@ -311,10 +311,10 @@ def find_classes_with_matching_source_line(self, pkgRoot, function, includeInnerClasses=False): """ Scan the sources of this project for Java source files containing a line for which - 'function' returns true. The fully qualified class name of each existing class - corresponding to a matched source file is returned in a list. + 'function' returns true. A map from class name to source file path for each existing class + corresponding to a matched source file is returned. """ - classes = [] + result = dict() pkgDecl = re.compile(r"^package\s+([a-zA-Z_][\w\.]*)\s*;$") for srcDir in self.source_dirs(): outputDir = self.output_dir() @@ -322,7 +322,8 @@ for name in files: if name.endswith('.java') and name != 'package-info.java': matchFound = False - with open(join(root, name)) as f: + source = join(root, name) + with open(source) as f: pkg = None for line in f: if line.startswith("package "): @@ -342,10 +343,12 @@ for e in os.listdir(pkgOutputDir): if includeInnerClasses: if e.endswith('.class') and (e.startswith(basename) or e.startswith(basename + '$')): - classes.append(pkg + '.' + e[:-len('.class')]) + className = pkg + '.' + e[:-len('.class')] + result[className] = source elif e == basename + '.class': - classes.append(pkg + '.' + basename) - return classes + className = pkg + '.' + basename + result[className] = source + return result def _init_packages_and_imports(self): if not hasattr(self, '_defined_java_packages'): @@ -1659,46 +1662,56 @@ d = distribution(dname) fd, tmp = tempfile.mkstemp(suffix='', prefix=basename(d.path) + '.', dir=dirname(d.path)) services = tempfile.mkdtemp(suffix='', prefix=basename(d.path) + '.', dir=dirname(d.path)) - zf = zipfile.ZipFile(tmp, 'w') - for p in sorted_deps(d.deps): - outputDir = p.output_dir() - for root, _, files in os.walk(outputDir): - relpath = root[len(outputDir) + 1:] - if relpath == join('META-INF', 'services'): - for f in files: - with open(join(services, f), 'a') as outfile: - with open(join(root, f), 'r') as infile: - for line in infile: - outfile.write(line) - else: - for f in files: - arcname = join(relpath, f).replace(os.sep, '/') - zf.write(join(root, f), arcname) - for f in os.listdir(services): - arcname = join('META-INF', 'services', f).replace(os.sep, '/') - zf.write(join(services, f), arcname) - zf.close() - os.close(fd) - shutil.rmtree(services) - # Atomic on Unix - shutil.move(tmp, d.path) - #print time.time(), 'move:', tmp, '->', d.path - d.notify_updated() + try: + zf = zipfile.ZipFile(tmp, 'w') + for p in sorted_deps(d.deps): + outputDir = p.output_dir() + for root, _, files in os.walk(outputDir): + relpath = root[len(outputDir) + 1:] + if relpath == join('META-INF', 'services'): + for f in files: + with open(join(services, f), 'a') as outfile: + with open(join(root, f), 'r') as infile: + for line in infile: + outfile.write(line) + else: + for f in files: + arcname = join(relpath, f).replace(os.sep, '/') + zf.write(join(root, f), arcname) + for f in os.listdir(services): + arcname = join('META-INF', 'services', f).replace(os.sep, '/') + zf.write(join(services, f), arcname) + zf.close() + os.close(fd) + shutil.rmtree(services) + # Atomic on Unix + shutil.move(tmp, d.path) + #print time.time(), 'move:', tmp, '->', d.path + d.notify_updated() + finally: + if exists(tmp): + os.remove(tmp) + if exists(services): + shutil.rmtree(services) else: p = project(name) outputDir = p.output_dir() fd, tmp = tempfile.mkstemp(suffix='', prefix=p.name, dir=p.dir) - zf = zipfile.ZipFile(tmp, 'w') - for root, _, files in os.walk(outputDir): - for f in files: - relpath = root[len(outputDir) + 1:] - arcname = join(relpath, f).replace(os.sep, '/') - zf.write(join(root, f), arcname) - zf.close() - os.close(fd) - # Atomic on Unix - shutil.move(tmp, join(p.dir, p.name + '.jar')) + try: + zf = zipfile.ZipFile(tmp, 'w') + for root, _, files in os.walk(outputDir): + for f in files: + relpath = root[len(outputDir) + 1:] + arcname = join(relpath, f).replace(os.sep, '/') + zf.write(join(root, f), arcname) + zf.close() + os.close(fd) + # Atomic on Unix + shutil.move(tmp, join(p.dir, p.name + '.jar')) + finally: + if exists(tmp): + os.remove(tmp) def canonicalizeprojects(args): """process all project files to canonicalize the dependencies diff -r d343737786fe -r 6d884611d4c1 src/cpu/x86/vm/templateInterpreter_x86.hpp --- a/src/cpu/x86/vm/templateInterpreter_x86.hpp Thu Mar 28 17:11:06 2013 +0100 +++ b/src/cpu/x86/vm/templateInterpreter_x86.hpp Wed Apr 03 14:41:22 2013 +0200 @@ -34,7 +34,7 @@ // Run with +PrintInterpreter to get the VM to print out the size. // Max size with JVMTI #ifdef AMD64 - const static int InterpreterCodeSize = 240 * 1024; + const static int InterpreterCodeSize = 224 * 1024; #else const static int InterpreterCodeSize = 168 * 1024; #endif // AMD64 diff -r d343737786fe -r 6d884611d4c1 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Thu Mar 28 17:11:06 2013 +0100 +++ b/src/share/vm/classfile/systemDictionary.hpp Wed Apr 03 14:41:22 2013 +0200 @@ -192,6 +192,7 @@ do_klass(HotSpotResolvedJavaField_klass, com_oracle_graal_hotspot_meta_HotSpotResolvedJavaField, Opt) \ do_klass(HotSpotResolvedJavaMethod_klass, com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod, Opt) \ do_klass(HotSpotResolvedObjectType_klass, com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType, Opt) \ + do_klass(HotSpotMonitorValue_klass, com_oracle_graal_hotspot_meta_HotSpotMonitorValue, Opt) \ do_klass(LocalImpl_klass, com_oracle_graal_hotspot_debug_LocalImpl, Opt) \ /* graal.api.code */ \ do_klass(Assumptions_klass, com_oracle_graal_api_code_Assumptions, Opt) \ @@ -208,7 +209,6 @@ do_klass(CompilationResult_Mark_klass, com_oracle_graal_api_code_CompilationResult_Mark, Opt) \ do_klass(CompilationResult_Safepoint_klass, com_oracle_graal_api_code_CompilationResult_Safepoint, Opt) \ do_klass(CompilationResult_Site_klass, com_oracle_graal_api_code_CompilationResult_Site, Opt) \ - do_klass(code_MonitorValue_klass, com_oracle_graal_api_code_MonitorValue, Opt) \ do_klass(code_Register_klass, com_oracle_graal_api_code_Register, Opt) \ do_klass(RegisterValue_klass, com_oracle_graal_api_code_RegisterValue, Opt) \ do_klass(StackSlot_klass, com_oracle_graal_api_code_StackSlot, Opt) \ diff -r d343737786fe -r 6d884611d4c1 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Thu Mar 28 17:11:06 2013 +0100 +++ b/src/share/vm/classfile/vmSymbols.hpp Wed Apr 03 14:41:22 2013 +0200 @@ -303,6 +303,7 @@ template(com_oracle_graal_hotspot_meta_HotSpotResolvedJavaField, "com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField") \ template(com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethod, "com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod") \ template(com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType, "com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType") \ + template(com_oracle_graal_hotspot_meta_HotSpotMonitorValue, "com/oracle/graal/hotspot/meta/HotSpotMonitorValue") \ template(com_oracle_graal_hotspot_debug_LocalImpl, "com/oracle/graal/hotspot/debug/LocalImpl") \ AMD64_ONLY(template(com_oracle_graal_hotspot_amd64_AMD64HotSpotGraalRuntime,"com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime"))\ /* graal.api.meta */ \ @@ -329,7 +330,6 @@ template(com_oracle_graal_api_code_BytecodeFrame, "com/oracle/graal/api/code/BytecodeFrame") \ template(com_oracle_graal_api_code_BytecodePosition, "com/oracle/graal/api/code/BytecodePosition") \ template(com_oracle_graal_api_code_DebugInfo, "com/oracle/graal/api/code/DebugInfo") \ - template(com_oracle_graal_api_code_MonitorValue, "com/oracle/graal/api/code/MonitorValue") \ template(com_oracle_graal_api_code_Register, "com/oracle/graal/api/code/Register") \ template(com_oracle_graal_api_code_RegisterValue, "com/oracle/graal/api/code/RegisterValue") \ template(com_oracle_graal_api_code_StackSlot, "com/oracle/graal/api/code/StackSlot") \ diff -r d343737786fe -r 6d884611d4c1 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Thu Mar 28 17:11:06 2013 +0100 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Wed Apr 03 14:41:22 2013 +0200 @@ -263,19 +263,19 @@ } static MonitorValue* get_monitor_value(oop value, int total_frame_size, GrowableArray* objects, OopRecorder* oop_recorder) { - guarantee(value->is_a(code_MonitorValue::klass()), "Monitors must be of type MonitorValue"); + guarantee(value->is_a(HotSpotMonitorValue::klass()), "Monitors must be of type MonitorValue"); ScopeValue* second = NULL; - ScopeValue* owner_value = get_hotspot_value(code_MonitorValue::owner(value), total_frame_size, objects, second, oop_recorder); + ScopeValue* owner_value = get_hotspot_value(HotSpotMonitorValue::owner(value), total_frame_size, objects, second, oop_recorder); assert(second == NULL, "monitor cannot occupy two stack slots"); - ScopeValue* lock_data_value = get_hotspot_value(code_MonitorValue::lockData(value), total_frame_size, objects, second, oop_recorder); + ScopeValue* lock_data_value = get_hotspot_value(HotSpotMonitorValue::slot(value), total_frame_size, objects, second, oop_recorder); assert(second == lock_data_value, "monitor is LONG value that occupies two stack slots"); assert(lock_data_value->is_location(), "invalid monitor location"); Location lock_data_loc = ((LocationValue*)lock_data_value)->location(); bool eliminated = false; - if (code_MonitorValue::eliminated(value)) { + if (HotSpotMonitorValue::eliminated(value)) { eliminated = true; } diff -r d343737786fe -r 6d884611d4c1 src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Thu Mar 28 17:11:06 2013 +0100 +++ b/src/share/vm/graal/graalJavaAccess.hpp Wed Apr 03 14:41:22 2013 +0200 @@ -197,10 +197,10 @@ oop_field(VirtualObject, type, "Lcom/oracle/graal/api/meta/ResolvedJavaType;") \ oop_field(VirtualObject, values, "[Lcom/oracle/graal/api/meta/Value;") \ end_class \ - start_class(code_MonitorValue) \ - oop_field(code_MonitorValue, owner, "Lcom/oracle/graal/api/meta/Value;") \ - oop_field(code_MonitorValue, lockData, "Lcom/oracle/graal/api/meta/Value;") \ - boolean_field(code_MonitorValue, eliminated) \ + start_class(HotSpotMonitorValue) \ + oop_field(HotSpotMonitorValue, owner, "Lcom/oracle/graal/api/meta/Value;") \ + oop_field(HotSpotMonitorValue, slot, "Lcom/oracle/graal/api/code/StackSlot;") \ + boolean_field(HotSpotMonitorValue, eliminated) \ end_class \ /* end*/