# HG changeset patch # User Christian Humer # Date 1383127680 -3600 # Node ID 50aca0c0dff409b573d829dd909a0aae70e33bf5 # Parent 02f844c76626ff78564f4db5404839a41047ac80# Parent 321229a79f7aa2c8d7e7e39bdd40287664947829 Merge. diff -r 02f844c76626 -r 50aca0c0dff4 .hgignore --- a/.hgignore Tue Oct 29 16:55:42 2013 +0100 +++ b/.hgignore Wed Oct 30 11:08:00 2013 +0100 @@ -16,6 +16,7 @@ \.checkstyle$ \.classpath \.factorypath +\.currentAnnotationProcessors \.externalToolBuilders \.project \.settings/ diff -r 02f844c76626 -r 50aca0c0dff4 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EAMergingTest.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/EAMergingTest.java Wed Oct 30 11:08:00 2013 +0100 @@ -0,0 +1,53 @@ +/* + * 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.compiler.test.ea; + +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.graal.nodes.*; + +public class EAMergingTest extends EATestBase { + + @Test + public void testSimpleMerge() { + testEscapeAnalysis("simpleMergeSnippet", null, false); + assertTrue(returnNode.result() instanceof PhiNode); + PhiNode phi = (PhiNode) returnNode.result(); + assertTrue(phi.valueAt(0) instanceof LocalNode); + assertTrue(phi.valueAt(1) instanceof LocalNode); + } + + public static int simpleMergeSnippet(boolean b, int u, int v) { + TestClassInt obj; + if (b) { + obj = new TestClassInt(u, 0); + notInlineable(); + } else { + obj = new TestClassInt(v, 0); + notInlineable(); + } + return obj.x; + } +} diff -r 02f844c76626 -r 50aca0c0dff4 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.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/EATestBase.java Wed Oct 30 11:08:00 2013 +0100 @@ -0,0 +1,162 @@ +/* + * 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.compiler.test.ea; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.virtual.phases.ea.*; + +//JaCoCo Exclude + +/** + * This base class for all Escape Analysis tests does not contain tests itself, therefore it is not + * automatically excluded from JaCoCo. Since it includes code that is used in the test snippets, it + * needs to be excluded manually. + */ +public class EATestBase extends GraalCompilerTest { + + public static class TestClassInt { + public int x; + public int y; + + public TestClassInt() { + this(0, 0); + } + + public TestClassInt(int x) { + this(x, 0); + } + + public TestClassInt(int x, int y) { + this.x = x; + this.y = y; + } + + @Override + public boolean equals(Object obj) { + TestClassInt other = (TestClassInt) obj; + return x == other.x && y == other.y; + } + + @Override + public String toString() { + return "{" + x + "," + y + "}"; + } + + @Override + public int hashCode() { + return x + 13 * y; + } + } + + public static class TestClassObject { + public Object x; + public Object y; + + public TestClassObject() { + this(null, null); + } + + public TestClassObject(Object x) { + this(x, null); + } + + public TestClassObject(Object x, Object y) { + this.x = x; + this.y = y; + } + + @Override + public boolean equals(Object obj) { + TestClassObject other = (TestClassObject) obj; + return x == other.x && y == other.y; + } + + @Override + public String toString() { + return "{" + x + "," + y + "}"; + } + + @Override + public int hashCode() { + return (x == null ? 0 : x.hashCode()) + 13 * (y == null ? 0 : y.hashCode()); + } + } + + protected static native void notInlineable(); + + protected StructuredGraph graph; + protected HighTierContext context; + protected ReturnNode returnNode; + + /** + * Runs Escape Analysis on the given snippet and makes sure that no allocations remain in the + * graph. + * + * @param snippet the name of the method whose graph should be processed + * @param expectedConstantResult if this is non-null, the resulting graph needs to have the + * given constant return value + * @param iterativeEscapeAnalysis true if escape analysis should be run for more than one + * iteration + */ + protected void testEscapeAnalysis(String snippet, final Constant expectedConstantResult, final boolean iterativeEscapeAnalysis) { + prepareGraph(snippet, iterativeEscapeAnalysis); + if (expectedConstantResult != null) { + Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant()); + Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant()); + } + int newInstanceCount = graph.getNodes().filter(NewInstanceNode.class).count() + graph.getNodes().filter(NewArrayNode.class).count() + + graph.getNodes().filter(CommitAllocationNode.class).count(); + Assert.assertEquals(0, newInstanceCount); + } + + protected void prepareGraph(String snippet, final boolean iterativeEscapeAnalysis) { + ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(getMethod(snippet)); + graph = new StructuredGraph(method); + Debug.scope(getClass().getSimpleName(), new Object[]{graph, method, getCodeCache()}, new Runnable() { + + public void run() { + new GraphBuilderPhase(getMetaAccess(), getForeignCalls(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); + Assumptions assumptions = new Assumptions(false); + context = new HighTierContext(getProviders(), assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL); + new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); + new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase(true).apply(graph, context); + new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(true)).apply(graph, context); + Assert.assertEquals(1, graph.getNodes().filter(ReturnNode.class).count()); + returnNode = graph.getNodes().filter(ReturnNode.class).first(); + } + }); + } +} diff -r 02f844c76626 -r 50aca0c0dff4 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 Tue Oct 29 16:55:42 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Wed Oct 30 11:08:00 2013 +0100 @@ -24,28 +24,20 @@ import org.junit.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.java.*; import com.oracle.graal.loop.phases.*; -import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.schedule.*; -import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.phases.ea.*; /** * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct * values. */ -public class EscapeAnalysisTest extends GraalCompilerTest { +public class EscapeAnalysisTest extends EATestBase { @Test public void test1() { @@ -82,8 +74,6 @@ testEscapeAnalysis("testMonitorSnippet", Constant.forInt(0), false); } - private static native void notInlineable(); - public static int testMonitorSnippet() { Integer x = new Integer(0); Double y = new Double(0); @@ -126,19 +116,8 @@ testEscapeAnalysis("testMerge1Snippet", Constant.forInt(0), true); } - public static class TestObject { - - int x; - int y; - - public TestObject(int x, int y) { - this.x = x; - this.y = y; - } - } - public static int testMerge1Snippet(int a) { - TestObject obj = new TestObject(1, 0); + TestClassInt obj = new TestClassInt(1, 0); if (a < 0) { obj.x = obj.x + 1; } else { @@ -157,7 +136,7 @@ } public int testSimpleLoopSnippet(int a) { - TestObject obj = new TestObject(1, 2); + TestClassInt obj = new TestClassInt(1, 2); for (int i = 0; i < a; i++) { notInlineable(); } @@ -170,7 +149,7 @@ } public int testModifyingLoopSnippet(int a) { - TestObject obj = new TestObject(1, 2); + TestClassInt obj = new TestClassInt(1, 2); for (int i = 0; i < a; i++) { obj.x = 3; notInlineable(); @@ -178,24 +157,15 @@ return obj.x <= 3 ? 1 : 0; } - public static class TestObject2 { - - Object o; - - public TestObject2(Object o) { - this.o = o; - } - } - @Test public void testCheckCast() { - testEscapeAnalysis("testCheckCastSnippet", Constant.forObject(TestObject2.class), false); + testEscapeAnalysis("testCheckCastSnippet", Constant.forObject(TestClassObject.class), false); } public Object testCheckCastSnippet() { - TestObject2 obj = new TestObject2(TestObject2.class); - TestObject2 obj2 = new TestObject2(obj); - return ((TestObject2) obj2.o).o; + TestClassObject obj = new TestClassObject(TestClassObject.class); + TestClassObject obj2 = new TestClassObject(obj); + return ((TestClassObject) obj2.x).x; } @Test @@ -204,9 +174,9 @@ } public boolean testInstanceOfSnippet() { - TestObject2 obj = new TestObject2(TestObject2.class); - TestObject2 obj2 = new TestObject2(obj); - return obj2.o instanceof TestObject2; + TestClassObject obj = new TestClassObject(TestClassObject.class); + TestClassObject obj2 = new TestClassObject(obj); + return obj2.x instanceof TestClassObject; } @SuppressWarnings("unused") @@ -223,98 +193,56 @@ testEscapeAnalysis("testNewNodeSnippet", null, false); } - private static final TestObject2 staticObj = new TestObject2(null); + private static final TestClassObject staticObj = new TestClassObject(); public static Object testFullyUnrolledLoopSnippet() { /* * This tests a case that can appear if PEA is performed both before and after loop - * unrolling/peeling: If the VirtualInstanceNode is not anchored correctly to stay within - * the loop, it will not be duplicated, and therefore the resulting object will reference - * itself, and not a second (different) object. + * unrolling/peeling: If the VirtualInstanceNode is not duplicated correctly with the loop, + * the resulting object will reference itself, and not a second (different) object. */ - TestObject2 obj = staticObj; + TestClassObject obj = staticObj; for (int i = 0; i < 2; i++) { - obj = new TestObject2(obj); + obj = new TestClassObject(obj); } - return obj.o; + return obj.x; } @Test public void testFullyUnrolledLoop() { - testEscapeAnalysisUnrolled("testFullyUnrolledLoopSnippet"); + prepareGraph("testFullyUnrolledLoopSnippet", false); + new LoopFullUnrollPhase(new CanonicalizerPhase(true)).apply(graph, context); + new PartialEscapePhase(false, new CanonicalizerPhase(true)).apply(graph, context); + Assert.assertTrue(returnNode.result() instanceof AllocatedObjectNode); + CommitAllocationNode commit = ((AllocatedObjectNode) returnNode.result()).getCommit(); + Assert.assertEquals(2, commit.getValues().size()); + Assert.assertEquals(1, commit.getVirtualObjects().size()); + Assert.assertTrue("non-cyclic data structure expected", commit.getVirtualObjects().get(0) != commit.getValues().get(0)); } - private static Object staticField; + @SuppressWarnings("unused") private static Object staticField; - private static TestObject2 inlinedPart(TestObject2 obj) { - TestObject2 ret = new TestObject2(obj); + private static TestClassObject inlinedPart(TestClassObject obj) { + TestClassObject ret = new TestClassObject(obj); staticField = null; return ret; } public static Object testPeeledLoopSnippet() { - TestObject2 obj = staticObj; + TestClassObject obj = staticObj; int i = 0; do { obj = inlinedPart(obj); } while (i++ < 10); staticField = obj; - return obj.o; + return obj.x; } @Test public void testPeeledLoop() { - testEscapeAnalysisPeeled("testPeeledLoopSnippet"); - } - - private StructuredGraph graph; - private HighTierContext context; - private ReturnNode returnNode; - - private void testEscapeAnalysis(String snippet, final Constant expectedConstantResult, final boolean iterativeEscapeAnalysis) { - prepareGraph(snippet, iterativeEscapeAnalysis); - if (expectedConstantResult != null) { - Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant()); - Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant()); - } - int newInstanceCount = graph.getNodes().filter(NewInstanceNode.class).count() + graph.getNodes().filter(NewArrayNode.class).count() + - graph.getNodes().filter(CommitAllocationNode.class).count(); - Assert.assertEquals(0, newInstanceCount); - } - - private void testEscapeAnalysisUnrolled(String snippet) { - prepareGraph(snippet, false); - new LoopFullUnrollPhase(new CanonicalizerPhase(true)).apply(graph, context); - new PartialEscapePhase(false, new CanonicalizerPhase(true)).apply(graph, context); - Assert.assertTrue(returnNode.result() instanceof AllocatedObjectNode); - CommitAllocationNode commit = ((AllocatedObjectNode) returnNode.result()).getCommit(); - Assert.assertEquals(1, commit.getValues().size()); - Assert.assertEquals(1, commit.getVirtualObjects().size()); - Assert.assertTrue("non-cyclic data structure expected", commit.getVirtualObjects().get(0) != commit.getValues().get(0)); - } - - private void testEscapeAnalysisPeeled(String snippet) { - prepareGraph(snippet, false); + prepareGraph("testPeeledLoopSnippet", false); new LoopTransformHighPhase().apply(graph); new LoopTransformLowPhase().apply(graph); new SchedulePhase().apply(graph); } - - private void prepareGraph(String snippet, final boolean iterativeEscapeAnalysis) { - graph = new StructuredGraph(getMetaAccess().lookupJavaMethod(getMethod(snippet))); - Debug.scope("GraalCompiler", new Object[]{graph, getMetaAccess().lookupJavaMethod(getMethod(snippet)), getCodeCache()}, new Runnable() { - - public void run() { - new GraphBuilderPhase(getMetaAccess(), getForeignCalls(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); - Assumptions assumptions = new Assumptions(false); - context = new HighTierContext(getProviders(), assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL); - new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); - new DeadCodeEliminationPhase().apply(graph); - new CanonicalizerPhase(true).apply(graph, context); - new PartialEscapePhase(iterativeEscapeAnalysis, new CanonicalizerPhase(true)).apply(graph, context); - Assert.assertEquals(1, graph.getNodes().filter(ReturnNode.class).count()); - returnNode = graph.getNodes().filter(ReturnNode.class).first(); - } - }); - } } diff -r 02f844c76626 -r 50aca0c0dff4 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java Tue Oct 29 16:55:42 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java Wed Oct 30 11:08:00 2013 +0100 @@ -30,6 +30,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.test.*; +import com.oracle.graal.compiler.test.ea.EATestBase.TestClassInt; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; @@ -50,14 +51,10 @@ } } - public static class TestInt implements Callable { - - public int x; - public int y; + public static class TestInt extends TestClassInt implements Callable { public TestInt(int x, int y) { - this.x = x; - this.y = y; + super(x, y); } @Override diff -r 02f844c76626 -r 50aca0c0dff4 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Tue Oct 29 16:55:42 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Wed Oct 30 11:08:00 2013 +0100 @@ -23,29 +23,23 @@ package com.oracle.graal.compiler.test.ea; import java.lang.ref.*; -import java.util.concurrent.*; import org.junit.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.test.*; -import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.graph.*; -import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.virtual.phases.ea.*; /** * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct * values. */ -public class PartialEscapeAnalysisTest extends GraalCompilerTest { +public class PartialEscapeAnalysisTest extends EATestBase { public static class TestObject { @@ -71,7 +65,7 @@ @Test public void test1() { - testMaterialize("test1Snippet", 0.25, 1); + testPartialEscapeAnalysis("test1Snippet", 0.25, 1); } @SuppressWarnings("all") @@ -90,7 +84,7 @@ @Test public void test2() { - testMaterialize("test2Snippet", 1.5, 3, LoadIndexedNode.class); + testPartialEscapeAnalysis("test2Snippet", 1.5, 3, LoadIndexedNode.class); } public static Object test2Snippet(int a, Object x, Object y, Object z) { @@ -109,7 +103,7 @@ @Test public void test3() { - testMaterialize("test3Snippet", 0.5, 1, StoreFieldNode.class, LoadFieldNode.class); + testPartialEscapeAnalysis("test3Snippet", 0.5, 1, StoreFieldNode.class, LoadFieldNode.class); } public static Object test3Snippet(int a) { @@ -127,7 +121,7 @@ @Test public void testCache() { - testMaterialize("testCacheSnippet", 0.75, 1); + testPartialEscapeAnalysis("testCacheSnippet", 0.75, 1); } public static class CacheKey { @@ -175,57 +169,40 @@ @Test public void testReference1() { - assertEquals(1, processMethod("testReference1Snippet").getNodes().filter(NewInstanceNode.class).count()); + prepareGraph("testReference1Snippet", false); + assertEquals(1, graph.getNodes().filter(NewInstanceNode.class).count()); } @SafeVarargs - final void testMaterialize(final String snippet, double expectedProbability, int expectedCount, Class... invalidNodeClasses) { - StructuredGraph result = processMethod(snippet); + protected final void testPartialEscapeAnalysis(final String snippet, double expectedProbability, int expectedCount, Class... invalidNodeClasses) { + prepareGraph(snippet, false); + for (MergeNode merge : graph.getNodes(MergeNode.class)) { + merge.setStateAfter(null); + } + new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase(true).apply(graph, context); try { - Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", result.getNodes().filter(NewInstanceNode.class).isEmpty()); - Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", result.getNodes().filter(NewArrayNode.class).isEmpty()); + Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", graph.getNodes().filter(NewInstanceNode.class).isEmpty()); + Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", graph.getNodes().filter(NewArrayNode.class).isEmpty()); - NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(result).apply(); + NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply(); double probabilitySum = 0; int materializeCount = 0; - for (CommitAllocationNode materialize : result.getNodes().filter(CommitAllocationNode.class)) { + for (CommitAllocationNode materialize : graph.getNodes().filter(CommitAllocationNode.class)) { probabilitySum += nodeProbabilities.get(materialize) * materialize.getVirtualObjects().size(); materializeCount += materialize.getVirtualObjects().size(); } Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount); Assert.assertEquals("unexpected probability of MaterializeObjectNodes", expectedProbability, probabilitySum, 0.01); - for (Node node : result.getNodes()) { + for (Node node : graph.getNodes()) { for (Class clazz : invalidNodeClasses) { Assert.assertFalse("instance of invalid class: " + clazz.getSimpleName(), clazz.isInstance(node) && node.usages().isNotEmpty()); } } } catch (AssertionError e) { - TypeSystemTest.outputGraph(result, snippet + ": " + e.getMessage()); + TypeSystemTest.outputGraph(graph, snippet + ": " + e.getMessage()); throw e; } } - private StructuredGraph processMethod(final String snippet) { - return Debug.scope("PartialEscapeAnalysisTest " + snippet, new DebugDumpScope(snippet), new Callable() { - - @Override - public StructuredGraph call() { - StructuredGraph graph = parse(snippet); - - Assumptions assumptions = new Assumptions(false); - HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL); - new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); - new DeadCodeEliminationPhase().apply(graph); - new CanonicalizerPhase(true).apply(graph, context); - new PartialEscapePhase(false, new CanonicalizerPhase(true)).apply(graph, context); - - for (MergeNode merge : graph.getNodes(MergeNode.class)) { - merge.setStateAfter(null); - } - new DeadCodeEliminationPhase().apply(graph); - new CanonicalizerPhase(true).apply(graph, context); - return graph; - } - }); - } } diff -r 02f844c76626 -r 50aca0c0dff4 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/UnsafeEATest.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/UnsafeEATest.java Wed Oct 30 11:08:00 2013 +0100 @@ -0,0 +1,191 @@ +/* + * 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.compiler.test.ea; + +import org.junit.*; + +import sun.misc.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; + +public class UnsafeEATest extends EATestBase { + + public static int zero = 0; + + private static final Unsafe unsafe; + private static final long fieldOffsetX; + private static final long fieldOffsetY; + + static { + unsafe = UnsafeAccess.unsafe; + try { + fieldOffsetX = unsafe.objectFieldOffset(TestClassInt.class.getField("x")); + fieldOffsetY = unsafe.objectFieldOffset(TestClassInt.class.getField("y")); + assert fieldOffsetY == fieldOffsetX + 4; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Test + public void testSimpleInt() { + testEscapeAnalysis("testSimpleIntSnippet", Constant.forInt(101), false); + } + + public static int testSimpleIntSnippet() { + TestClassInt x = new TestClassInt(); + unsafe.putInt(x, fieldOffsetX, 101); + return unsafe.getInt(x, fieldOffsetX); + } + + @Test + public void testMaterializedInt() { + test("testMaterializedIntSnippet"); + } + + public static TestClassInt testMaterializedIntSnippet() { + TestClassInt x = new TestClassInt(); + unsafe.putInt(x, fieldOffsetX, 101); + return x; + } + + @Test + public void testSimpleDouble() { + testEscapeAnalysis("testSimpleDoubleSnippet", Constant.forDouble(10.1), false); + } + + public static double testSimpleDoubleSnippet() { + TestClassInt x = new TestClassInt(); + unsafe.putDouble(x, fieldOffsetX, 10.1); + return unsafe.getDouble(x, fieldOffsetX); + } + + @Test + public void testMergedDouble() { + testEscapeAnalysis("testMergedDoubleSnippet", null, false); + Assert.assertTrue(returnNode.result() instanceof PhiNode); + PhiNode phi = (PhiNode) returnNode.result(); + Assert.assertTrue(phi.valueAt(0) instanceof LoadFieldNode); + Assert.assertTrue(phi.valueAt(1) instanceof LoadFieldNode); + } + + public static double testMergedDoubleSnippet(boolean a) { + TestClassInt x; + if (a) { + x = new TestClassInt(0, 0); + unsafe.putDouble(x, fieldOffsetX, doubleField); + } else { + x = new TestClassInt(); + unsafe.putDouble(x, fieldOffsetX, doubleField2); + } + return unsafe.getDouble(x, fieldOffsetX); + } + + @Test + public void testMaterializedDouble() { + test("testMaterializedDoubleSnippet"); + } + + public static TestClassInt testMaterializedDoubleSnippet() { + TestClassInt x = new TestClassInt(); + unsafe.putDouble(x, fieldOffsetX, 10.1); + return x; + } + + @Test + public void testDeoptDoubleVar() { + test("testDeoptDoubleVarSnippet"); + } + + public static double doubleField = 10.1e99; + public static double doubleField2; + + public static TestClassInt testDeoptDoubleVarSnippet() { + TestClassInt x = new TestClassInt(); + unsafe.putDouble(x, fieldOffsetX, doubleField); + doubleField2 = 123; + try { + doubleField = ((int) unsafe.getDouble(x, fieldOffsetX)) / zero; + } catch (RuntimeException e) { + return x; + } + return x; + } + + @Test + public void testDeoptDoubleConstant() { + test("testDeoptDoubleConstantSnippet"); + } + + public static TestClassInt testDeoptDoubleConstantSnippet() { + TestClassInt x = new TestClassInt(); + unsafe.putDouble(x, fieldOffsetX, 10.123); + doubleField2 = 123; + try { + doubleField = ((int) unsafe.getDouble(x, fieldOffsetX)) / zero; + } catch (RuntimeException e) { + return x; + } + return x; + } + + @Test + public void testDeoptLongVar() { + test("testDeoptLongVarSnippet"); + } + + public static long longField = 0x133443218aaaffffL; + public static long longField2; + + public static TestClassInt testDeoptLongVarSnippet() { + TestClassInt x = new TestClassInt(); + unsafe.putLong(x, fieldOffsetX, longField); + longField2 = 123; + try { + longField = unsafe.getLong(x, fieldOffsetX) / zero; + } catch (RuntimeException e) { + return x; + } + return x; + } + + @Test + public void testDeoptLongConstant() { + test("testDeoptLongConstantSnippet"); + } + + public static TestClassInt testDeoptLongConstantSnippet() { + TestClassInt x = new TestClassInt(); + unsafe.putLong(x, fieldOffsetX, 0x2222222210123L); + longField2 = 123; + try { + longField = unsafe.getLong(x, fieldOffsetX) / zero; + } catch (RuntimeException e) { + return x; + } + return x; + } +} diff -r 02f844c76626 -r 50aca0c0dff4 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java Tue Oct 29 16:55:42 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java Wed Oct 30 11:08:00 2013 +0100 @@ -350,9 +350,12 @@ // Constant.illegal is always the defaultForKind, so it is skipped Kind componentKind = element.getKind(); Kind accessKind; - if (value.kind().getStackKind() != componentKind.getStackKind()) { - assert value.kind() == Kind.Long || value.kind() == Kind.Double; - accessKind = value.kind(); + Kind valueKind = value.kind(); + if (valueKind.getStackKind() != componentKind.getStackKind()) { + // Given how Truffle uses unsafe, it can happen that + // valueKind is Kind.Int + // assert valueKind == Kind.Long || valueKind == Kind.Double; + accessKind = valueKind; } else { accessKind = componentKind; } diff -r 02f844c76626 -r 50aca0c0dff4 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Tue Oct 29 16:55:42 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Wed Oct 30 11:08:00 2013 +0100 @@ -194,28 +194,41 @@ */ assert !Modifier.isStatic(flags); Object object = receiver.asObject(); - if (Modifier.isFinal(getModifiers())) { - Constant value = readValue(receiver); - if (assumeNonStaticFinalFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) { - return value; - } - } else if (isStable()) { - Constant value = readValue(receiver); - if (assumeDefaultStableFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) { - return value; - } - } else { - Class clazz = object.getClass(); - if (StableOptionValue.class.isAssignableFrom(clazz)) { - assert getName().equals("value") : "Unexpected field in " + StableOptionValue.class.getName() + " hierarchy:" + this; - StableOptionValue option = (StableOptionValue) object; - return Constant.forObject(option.getValue()); + + // Canonicalization may attempt to process an unsafe read before + // processing a guard (e.g. a type check) for this read + // so we need to type check the object being read + if (isInObject(object)) { + if (Modifier.isFinal(getModifiers())) { + Constant value = readValue(receiver); + if (assumeNonStaticFinalFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) { + return value; + } + } else if (isStable()) { + Constant value = readValue(receiver); + if (assumeDefaultStableFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) { + return value; + } + } else { + Class clazz = object.getClass(); + if (StableOptionValue.class.isAssignableFrom(clazz)) { + assert getName().equals("value") : "Unexpected field in " + StableOptionValue.class.getName() + " hierarchy:" + this; + StableOptionValue option = (StableOptionValue) object; + return Constant.forObject(option.getValue()); + } } } } return null; } + /** + * Determines if a given object contains this field. + */ + public boolean isInObject(Object object) { + return getDeclaringClass().isAssignableFrom(HotSpotResolvedObjectType.fromClass(object.getClass())); + } + @Override public Constant readValue(Constant receiver) { if (receiver == null) { @@ -226,7 +239,9 @@ return null; } else { assert !Modifier.isStatic(flags); - return runtime().getHostProviders().getConstantReflection().readUnsafeConstant(getKind(), receiver.asObject(), offset, getKind() == Kind.Object); + Object object = receiver.asObject(); + assert object != null && isInObject(object); + return runtime().getHostProviders().getConstantReflection().readUnsafeConstant(getKind(), object, offset, getKind() == Kind.Object); } } diff -r 02f844c76626 -r 50aca0c0dff4 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 Tue Oct 29 16:55:42 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Wed Oct 30 11:08:00 2013 +0100 @@ -24,22 +24,24 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; /** - * The {@code MonitorEnterNode} represents a monitor release. + * The {@code MonitorExitNode} represents a monitor release. If it is the release of the monitor of + * a synchronized method, then the return value of the method will be referenced, so that it will be + * materialized before releasing the monitor. */ -public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorExit, MemoryCheckpoint.Single, MonitorReference { +public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Simplifiable, Lowerable, IterableNodeType, MonitorExit, MemoryCheckpoint.Single, MonitorReference { + + @Input private ValueNode escapedReturnValue; private int lockDepth; - @Input private ValueNode escapedReturnValue; /** * Creates a new MonitorExitNode. - * - * @param object the instruction produces the object value */ public MonitorExitNode(ValueNode object, ValueNode escapedReturnValue, int lockDepth) { super(object); @@ -58,6 +60,15 @@ } @Override + public void simplify(SimplifierTool tool) { + if (escapedReturnValue != null && stateAfter().bci != FrameState.AFTER_BCI) { + ValueNode returnValue = escapedReturnValue; + setEscapedReturnValue(null); + tool.removeIfUnused(returnValue); + } + } + + @Override public void lower(LoweringTool tool) { tool.getLowerer().lower(this, tool); } @@ -72,20 +83,13 @@ @Override public void virtualize(VirtualizerTool tool) { - /* - * The last MonitorExitNode of a synchronized method cannot be removed anyway, and we need - * it to materialize the return value. - * - * TODO: replace this with correct handling of AFTER_BCI frame states in the runtime. - */ - if (stateAfter().bci != FrameState.AFTER_BCI) { - setEscapedReturnValue(null); - State state = tool.getObjectState(object()); - if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) { - int removedLock = state.removeLock(); - assert removedLock == getLockDepth(); - tool.delete(); - } + State state = tool.getObjectState(object()); + // the monitor exit for a synchronized method should never be virtualized + assert stateAfter().bci != FrameState.AFTER_BCI || state == null; + if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().hasIdentity()) { + int removedLock = state.removeLock(); + assert removedLock == getLockDepth(); + tool.delete(); } } } diff -r 02f844c76626 -r 50aca0c0dff4 graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java --- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Tue Oct 29 16:55:42 2013 +0100 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Wed Oct 30 11:08:00 2013 +0100 @@ -167,20 +167,13 @@ StructuredGraph graph = convert.graph(); - // Insert a unique placeholder node in place of the Convert node so that the - // Convert node can be used as an input to the snippet. All usage of the - // Convert node are replaced by the placeholder which in turn is replaced by the - // snippet. - - LocalNode replacee = graph.addWithoutUnique(new LocalNode(Integer.MAX_VALUE, convert.stamp())); - convert.replaceAtUsages(replacee); Arguments args = new Arguments(key, graph.getGuardsStage()); args.add("input", convert.value()); - args.add("result", convert.graph().unique(new AMD64ConvertNode(convert.opcode, convert.value()))); + args.add("result", graph.unique(new AMD64ConvertNode(convert.opcode, convert.value()))); SnippetTemplate template = template(args); Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.opcode, graph, convert, template, args); - template.instantiate(providers.getMetaAccess(), replacee, DEFAULT_REPLACER, tool, args); + template.instantiate(providers.getMetaAccess(), convert, DEFAULT_REPLACER, tool, args); graph.removeFloating(convert); } } diff -r 02f844c76626 -r 50aca0c0dff4 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java Tue Oct 29 16:55:42 2013 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetCounter.java Wed Oct 30 11:08:00 2013 +0100 @@ -134,7 +134,8 @@ */ public void inc() { if (group != null) { - // TODO: instead of ANY_LOCATION we should actually use the location for the field "value". + // TODO: instead of ANY_LOCATION we should actually + // use the location for the field "value". DirectObjectStoreNode.storeLong(this, countOffset(), 0, value + 1, LocationIdentity.ANY_LOCATION); } } diff -r 02f844c76626 -r 50aca0c0dff4 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Tue Oct 29 16:55:42 2013 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Wed Oct 30 11:08:00 2013 +0100 @@ -104,7 +104,7 @@ final StructuredGraph graph = new StructuredGraph(executeHelperMethod); - Debug.scope("createGraph", new Runnable() { + Debug.scope("createGraph", graph, new Runnable() { @Override public void run() { diff -r 02f844c76626 -r 50aca0c0dff4 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Tue Oct 29 16:55:42 2013 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Wed Oct 30 11:08:00 2013 +0100 @@ -217,7 +217,7 @@ @Override public CompilationResult call() { try (TimerCloseable a = CompilationTime.start()) { - return Debug.scope("GraalCompiler", new Object[]{providers.getCodeCache()}, new Callable() { + return Debug.scope("GraalCompiler", new Object[]{graph, providers.getCodeCache()}, new Callable() { public CompilationResult call() { CodeCacheProvider codeCache = providers.getCodeCache(); CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false); diff -r 02f844c76626 -r 50aca0c0dff4 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 Tue Oct 29 16:55:42 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Wed Oct 30 11:08:00 2013 +0100 @@ -425,7 +425,7 @@ // skip the next entry valueIndex++; } else { - assert entryKind.getStackKind() == otherKind.getStackKind() : entryKind + " vs " + otherKind; + assert entryKind.getStackKind() == otherKind.getStackKind() || entryKind.getBitCount() >= otherKind.getBitCount() : entryKind + " vs " + otherKind; } valueIndex++; } diff -r 02f844c76626 -r 50aca0c0dff4 make/bsd/makefiles/gcc.make --- a/make/bsd/makefiles/gcc.make Tue Oct 29 16:55:42 2013 +0100 +++ b/make/bsd/makefiles/gcc.make Wed Oct 30 11:08:00 2013 +0100 @@ -144,7 +144,8 @@ PCH_FLAG/sharedRuntimeTrig.o = $(PCH_FLAG/NO_PCH) PCH_FLAG/sharedRuntimeTrans.o = $(PCH_FLAG/NO_PCH) PCH_FLAG/unsafe.o = $(PCH_FLAG/NO_PCH) - + PCH_FLAG/graalCompilerToVM.o = $(PCH_FLAG/NO_PCH) + endif else # ($(USE_CLANG), true) # check for precompiled headers support @@ -309,17 +310,16 @@ # Work around some compiler bugs. ifeq ($(USE_CLANG), true) + # Clang 4.2 ifeq ($(shell expr $(CC_VER_MAJOR) = 4 \& $(CC_VER_MINOR) = 2), 1) OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT) OPT_CFLAGS/unsafe.o += -O1 endif # Clang 5.0 ifeq ($(shell expr $(CC_VER_MAJOR) = 5 \& $(CC_VER_MINOR) = 0), 1) - OPT_CFLAGS/graalCompilerToVM.o += -O1 + OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT) OPT_CFLAGS/unsafe.o += -O1 - # Specific optimization level plus precompiled headers produces: - # error: __OPTIMIZE_SIZE__ predefined macro was enabled in PCH file but is currently disabled - USE_PRECOMPILED_HEADER = 0 + OPT_CFLAGS/graalCompilerToVM.o += -O1 endif else # 6835796. Problem in GCC 4.3.0 with mulnode.o optimized compilation. @@ -328,6 +328,14 @@ endif endif +# We want to use libc++ on Clang 5.0 +ifeq ($(USE_CLANG), true) + # Clang 5.0 + ifeq ($(shell expr $(CC_VER_MAJOR) = 5 \& $(CC_VER_MINOR) = 0), 1) + CFLAGS += -stdlib=libc++ + endif +endif + # Flags for generating make dependency flags. DEPFLAGS = -MMD -MP -MF $(DEP_DIR)/$(@:%=%.d) ifeq ($(USE_CLANG),) diff -r 02f844c76626 -r 50aca0c0dff4 mx/projects --- a/mx/projects Tue Oct 29 16:55:42 2013 +0100 +++ b/mx/projects Wed Oct 30 11:08:00 2013 +0100 @@ -138,6 +138,7 @@ project@com.oracle.graal.hotspot.sparc@sourceDirs=src project@com.oracle.graal.hotspot.sparc@dependencies=com.oracle.graal.compiler.sparc project@com.oracle.graal.hotspot.sparc@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.hotspot.sparc@annotationProcessors=com.oracle.graal.service.processor project@com.oracle.graal.hotspot.sparc@javaCompliance=1.7 project@com.oracle.graal.hotspot.sparc@workingSets=Graal,HotSpot,SPARC diff -r 02f844c76626 -r 50aca0c0dff4 mxtool/mx.py --- a/mxtool/mx.py Tue Oct 29 16:55:42 2013 +0100 +++ b/mxtool/mx.py Wed Oct 30 11:08:00 2013 +0100 @@ -326,6 +326,24 @@ self._annotationProcessors = list(ap) return self._annotationProcessors + def update_current_annotation_processors_file(self): + aps = self.annotation_processors() + outOfDate = False + currentApsFile = join(self.dir, '.currentAnnotationProcessors') + if exists(currentApsFile): + with open(currentApsFile) as fp: + currentAps = [l.strip() for l in fp.readlines()] + if currentAps != aps: + outOfDate = True + else: + outOfDate = True + if outOfDate: + with open(currentApsFile, 'w') as fp: + for ap in aps: + print >> fp, ap + return outOfDate + + class Library(Dependency): def __init__(self, suite, name, path, mustExist, urls, sourcePath, sourceUrls): Dependency.__init__(self, suite, name) @@ -769,7 +787,7 @@ abort('Missing "suite=" in ' + projectsFile) def _commands_name(self): - return 'mx_' + self.name.replace('-', '_') + return 'mx_' + self.name.replace('-','_') def _find_commands(self, name): commandsPath = join(self.mxDir, name + '.py') @@ -804,6 +822,12 @@ mod.mx_init(self) self.commands = mod + def _imports_file(self): + return join(self.mxDir, 'imports') + + def import_timestamp(self): + return TimeStampFile(self._imports_file()) + def visit_imports(self, visitor, **extra_args): """ Visitor support for the imports file. @@ -817,7 +841,7 @@ as this function only visits the imports of a single suite. If a (recursive) visitor function wishes to visit a suite exactly once, it must manage that through extra_args. """ - importsFile = join(self.mxDir, 'imports') + importsFile = self._imports_file() if exists(importsFile): update_versions = extra_args.has_key('update_versions') and extra_args['update_versions'] out = StringIO.StringIO() if update_versions else None @@ -1847,6 +1871,22 @@ if args.java: ideinit([], refreshOnly=True, buildProcessorJars=False) + def prepareOutputDirs(p, clean): + outputDir = p.output_dir() + if exists(outputDir): + if clean: + log('Cleaning {0}...'.format(outputDir)) + shutil.rmtree(outputDir) + os.mkdir(outputDir) + else: + os.mkdir(outputDir) + genDir = p.source_gen_dir() + if genDir != '' and exists(genDir) and clean: + log('Cleaning {0}...'.format(genDir)) + for f in os.listdir(genDir): + shutil.rmtree(join(genDir, f)) + return outputDir + for p in sortedProjects: if p.native: if args.native: @@ -1869,14 +1909,7 @@ log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, p.javaCompliance)) continue - outputDir = p.output_dir() - if exists(outputDir): - if args.clean: - log('Cleaning {0}...'.format(outputDir)) - shutil.rmtree(outputDir) - os.mkdir(outputDir) - else: - os.mkdir(outputDir) + outputDir = prepareOutputDirs(p, args.clean) cp = classpath(p.name, includeSelf=True) sourceDirs = p.source_dirs() @@ -1886,6 +1919,7 @@ if dep.name in built: mustBuild = True + jasminAvailable = None javafilelist = [] for sourceDir in sourceDirs: @@ -1935,11 +1969,17 @@ if not mustBuild: for javafile in javafiles: - classfile = outputDir + javafile[len(sourceDir):-len('java')] + 'class' - if not exists(classfile) or os.path.getmtime(javafile) > os.path.getmtime(classfile): + classfile = TimeStampFile(outputDir + javafile[len(sourceDir):-len('java')] + 'class') + if not classfile.exists() or classfile.isOlderThan(javafile): mustBuild = True break + aps = p.annotation_processors() + apsOutOfDate = p.update_current_annotation_processors_file() + if apsOutOfDate: + logv('[annotation processors for {0} changed]'.format(p.name)) + mustBuild = True + if not mustBuild: logv('[all class files for {0} are up to date - skipping]'.format(p.name)) continue @@ -1948,6 +1988,9 @@ logv('[no Java sources for {0} - skipping]'.format(p.name)) continue + # Ensure that the output directories are clean + prepareOutputDirs(p, True) + built.add(p.name) argfileName = join(p.dir, 'javafilelist.txt') @@ -1957,9 +2000,8 @@ processorArgs = [] - ap = p.annotation_processors() - if len(ap) > 0: - processorPath = classpath(ap, resolve=True) + if len(aps) > 0: + processorPath = classpath(aps, resolve=True) genDir = p.source_gen_dir() if exists(genDir): shutil.rmtree(genDir) @@ -2132,13 +2174,17 @@ return 0 def processorjars(): - + for s in suites(True): + _processorjars_suite(s) + +def _processorjars_suite(s): projs = set() - for p in sorted_deps(): + candidates = sorted_project_deps(s.projects) + for p in candidates: if _isAnnotationProcessorDependency(p): projs.add(p) - if len(projs) < 0: + if len(projs) <= 0: return pnames = [p.name for p in projs] @@ -2378,7 +2424,12 @@ def isOlderThan(self, arg): if not self.timestamp: return True - if isinstance(arg, types.ListType): + if isinstance(arg, TimeStampFile): + if arg.timestamp is None: + return False + else: + return arg.timestamp > self.timestamp + elif isinstance(arg, types.ListType): files = arg else: files = [arg] @@ -2641,16 +2692,15 @@ igv.close('graph') igv.close('group') igv.close('graphDocument') - + if args.igv: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', 4444)) s.send(igv.xml()) else: - print igv.xml(indent=' ', newl='\n'); + print igv.xml(indent=' ', newl='\n') return - - + print 'digraph projects {' print 'rankdir=BT;' print 'node [shape=rect];' @@ -2787,20 +2837,26 @@ generate_eclipse_workingsets() +def _check_ide_timestamp(suite, timestamp): + """return True if and only if the projects file, imports file, and mx itself are all older than timestamp""" + projectsFile = join(suite.mxDir, 'projects') + projectsFileOlder = not timestamp.isOlderThan(projectsFile) + importsFileOlder = not timestamp.isOlderThan(suite.import_timestamp()) + # Assume that any mx change might imply changes to the generated IDE files + mxOlder = not timestamp.isOlderThan(__file__) + return projectsFileOlder and importsFileOlder and mxOlder def _eclipseinit_suite(args, suite, buildProcessorJars=True, refreshOnly=False): - projectsFile = join(suite.mxDir, 'projects') timestamp = TimeStampFile(join(suite.mxDir, 'eclipseinit.timestamp')) if refreshOnly and not timestamp.exists(): return - if not timestamp.isOlderThan(projectsFile) and not TimeStampFile(projectsFile).isOlderThan(__file__): + if _check_ide_timestamp(suite, timestamp): logv('[Eclipse configurations are up to date - skipping]') return if buildProcessorJars: - # todo suite specific - processorjars() + _processorjars_suite(suite) projToDist = dict() for dist in _dists.values(): @@ -3199,12 +3255,11 @@ _netbeansinit_suite(args, suite, refreshOnly, buildProcessorJars) def _netbeansinit_suite(args, suite, refreshOnly=False, buildProcessorJars=True): - projectsFile = join(suite.mxDir, 'projects') timestamp = TimeStampFile(join(suite.mxDir, 'netbeansinit.timestamp')) if refreshOnly and not timestamp.exists(): return - if not timestamp.isOlderThan(projectsFile) and not TimeStampFile(projectsFile).isOlderThan(__file__): + if _check_ide_timestamp(suite, timestamp): logv('[NetBeans configurations are up to date - skipping]') return