# HG changeset patch # User Thomas Wuerthinger # Date 1371829939 -7200 # Node ID 55827d611da7eabad22d2c732c6b9589901e9159 # Parent 0d40e1cf70dbdc1b3bee70c87d31a04747350934# Parent e4dd840a39de94a613a353b382e5e3a15c6e58d9 Merge. diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierAdditionTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierAdditionTest.java Fri Jun 21 17:52:08 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.test; - -import org.junit.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.hotspot.phases.*; -import com.oracle.graal.nodes.HeapAccess.WriteBarrierType; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.Lowerable.LoweringType; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.tiers.*; - -public class WriteBarrierAdditionTest extends GraalCompilerTest { - - public static class Container { - - public Container a; - public Container b; - } - - public static void test1Snippet() { - Container main = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - main.a = temp1; - main.b = temp2; - } - - public static void test2Snippet(boolean test) { - Container main = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - for (int i = 0; i < 10; i++) { - if (test) { - main.a = temp1; - main.b = temp2; - } else { - main.a = temp2; - main.b = temp1; - } - } - } - - public static void test3Snippet() { - Container[] main = new Container[10]; - Container temp1 = new Container(); - Container temp2 = new Container(); - for (int i = 0; i < 10; i++) { - main[i].a = main[i].b = temp1; - } - - for (int i = 0; i < 10; i++) { - main[i].a = main[i].b = temp2; - } - - } - - @Test - public void test1() { - test("test1Snippet", 2); - } - - @Test - public void test2() { - test("test2Snippet", 4); - } - - @Test - public void test3() { - test("test3Snippet", 4); - } - - private void test(final String snippet, final int expectedBarriers) { - Debug.scope("WriteBarrierAditionTest", new DebugDumpScope(snippet), new Runnable() { - - public void run() { - StructuredGraph graph = parse(snippet); - HighTierContext context = new HighTierContext(runtime(), new Assumptions(false), replacements); - new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context); - new WriteBarrierAdditionPhase().apply(graph); - Debug.dump(graph, "After Write Barrier Addition"); - final int barriers = graph.getNodes(SerialWriteBarrier.class).count(); - Assert.assertTrue(barriers == expectedBarriers); - for (WriteNode write : graph.getNodes(WriteNode.class)) { - if (write.getWriteBarrierType() != WriteBarrierType.NONE) { - Assert.assertTrue(write.successors().count() == 1); - Assert.assertTrue(write.next() instanceof SerialWriteBarrier); - } - } - } - }); - } -} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierVerificationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierVerificationTest.java Fri Jun 21 17:52:08 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,712 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.compiler.test; - -import java.util.*; -import java.util.concurrent.*; - -import org.junit.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.internal.*; -import com.oracle.graal.hotspot.phases.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.Lowerable.LoweringType; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.graph.*; -import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; -import com.oracle.graal.phases.tiers.*; - -/** - * The following tests validate the write barrier verification phase. For every tested snippet, an - * array of write barrier indices and the total write barrier number are passed as parameters. The - * indices denote the barriers that will be manually removed. The write barrier verification phase - * runs after the write barrier removal and depending on the result an assertion might be generated. - * The tests anticipate the presence or not of an assertion generated by the verification phase. - */ -public class WriteBarrierVerificationTest extends GraalCompilerTest { - - public static int barrierIndex; - - public static class Container { - - public Container a; - public Container b; - } - - private static native void safepoint(); - - public static void test1Snippet() { - Container main = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - barrierIndex = 0; - safepoint(); - barrierIndex = 1; - main.a = temp1; - safepoint(); - barrierIndex = 2; - main.b = temp2; - safepoint(); - } - - @Test(expected = AssertionError.class) - public void test1() { - test("test1Snippet", 2, new int[]{1}); - } - - @Test(expected = AssertionError.class) - public void test2() { - test("test1Snippet", 2, new int[]{2}); - } - - public static void test2Snippet() { - Container main = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - barrierIndex = 0; - safepoint(); - barrierIndex = 1; - main.a = temp1; - barrierIndex = 2; - main.b = temp2; - safepoint(); - } - - @Test(expected = AssertionError.class) - public void test3() { - test("test2Snippet", 2, new int[]{1}); - } - - @Test - public void test4() { - test("test2Snippet", 2, new int[]{2}); - } - - public static void test3Snippet(boolean test) { - Container main = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - barrierIndex = 0; - safepoint(); - for (int i = 0; i < 10; i++) { - if (test) { - barrierIndex = 1; - main.a = temp1; - barrierIndex = 2; - main.b = temp2; - } else { - barrierIndex = 3; - main.a = temp1; - barrierIndex = 4; - main.b = temp2; - } - } - } - - @Test(expected = AssertionError.class) - public void test5() { - test("test3Snippet", 4, new int[]{1, 2}); - } - - @Test(expected = AssertionError.class) - public void test6() { - test("test3Snippet", 4, new int[]{3, 4}); - } - - @Test(expected = AssertionError.class) - public void test7() { - test("test3Snippet", 4, new int[]{1}); - } - - @Test - public void test8() { - test("test3Snippet", 4, new int[]{2}); - } - - @Test(expected = AssertionError.class) - public void test9() { - test("test3Snippet", 4, new int[]{3}); - } - - @Test - public void test10() { - test("test3Snippet", 4, new int[]{4}); - } - - public static void test4Snippet(boolean test) { - Container main = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - safepoint(); - barrierIndex = 1; - main.a = temp1; - for (int i = 0; i < 10; i++) { - if (test) { - barrierIndex = 2; - main.a = temp1; - barrierIndex = 3; - main.b = temp2; - } else { - barrierIndex = 4; - main.a = temp2; - barrierIndex = 5; - main.b = temp1; - } - } - } - - @Test(expected = AssertionError.class) - public void test11() { - test("test4Snippet", 5, new int[]{2, 3}); - } - - @Test(expected = AssertionError.class) - public void test12() { - test("test4Snippet", 5, new int[]{4, 5}); - } - - @Test(expected = AssertionError.class) - public void test13() { - test("test4Snippet", 5, new int[]{1}); - } - - public static void test5Snippet() { - Container main = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - safepoint(); - barrierIndex = 1; - main.a = temp1; - if (main.a == main.b) { - barrierIndex = 2; - main.a = temp1; - barrierIndex = 3; - main.b = temp2; - } else { - barrierIndex = 4; - main.a = temp2; - barrierIndex = 5; - main.b = temp1; - } - safepoint(); - } - - @Test(expected = AssertionError.class) - public void test14() { - test("test5Snippet", 5, new int[]{1}); - } - - @Test - public void test15() { - test("test5Snippet", 5, new int[]{2}); - } - - @Test - public void test16() { - test("test5Snippet", 5, new int[]{4}); - } - - @Test - public void test17() { - test("test5Snippet", 5, new int[]{3}); - } - - @Test - public void test18() { - test("test5Snippet", 5, new int[]{5}); - } - - @Test - public void test19() { - test("test5Snippet", 5, new int[]{2, 3}); - } - - @Test - public void test20() { - test("test5Snippet", 5, new int[]{4, 5}); - } - - public static void test6Snippet(boolean test) { - Container main = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - safepoint(); - barrierIndex = 1; - main.a = temp1; - if (test) { - barrierIndex = 2; - main.a = temp1; - barrierIndex = 3; - main.b = temp1.a.a; - } else { - barrierIndex = 4; - main.a = temp2; - barrierIndex = 5; - main.b = temp2.a.a; - } - safepoint(); - } - - @Test(expected = AssertionError.class) - public void test21() { - test("test6Snippet", 5, new int[]{1}); - } - - @Test(expected = AssertionError.class) - public void test22() { - test("test6Snippet", 5, new int[]{1, 2}); - } - - @Test(expected = AssertionError.class) - public void test23() { - test("test6Snippet", 5, new int[]{3}); - } - - @Test - public void test24() { - test("test6Snippet", 5, new int[]{4}); - } - - public static void test7Snippet(boolean test) { - Container main = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - safepoint(); - barrierIndex = 1; - main.a = temp1; - if (test) { - barrierIndex = 2; - main.a = temp1; - } - barrierIndex = 3; - main.b = temp2; - safepoint(); - } - - @Test - public void test25() { - test("test7Snippet", 3, new int[]{2}); - } - - @Test - public void test26() { - test("test7Snippet", 3, new int[]{3}); - } - - @Test - public void test27() { - test("test7Snippet", 3, new int[]{2, 3}); - } - - @Test(expected = AssertionError.class) - public void test28() { - test("test7Snippet", 3, new int[]{1}); - } - - public static void test8Snippet(boolean test) { - Container main = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - safepoint(); - if (test) { - barrierIndex = 1; - main.a = temp1; - } - barrierIndex = 2; - main.b = temp2; - safepoint(); - } - - @Test(expected = AssertionError.class) - public void test29() { - test("test8Snippet", 2, new int[]{1}); - } - - @Test(expected = AssertionError.class) - public void test30() { - test("test8Snippet", 2, new int[]{2}); - } - - @Test(expected = AssertionError.class) - public void test31() { - test("test8Snippet", 2, new int[]{1, 2}); - } - - public static void test9Snippet(boolean test) { - Container main1 = new Container(); - Container main2 = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - safepoint(); - if (test) { - barrierIndex = 1; - main1.a = temp1; - } else { - barrierIndex = 2; - main2.a = temp1; - } - barrierIndex = 3; - main1.b = temp2; - barrierIndex = 4; - main2.b = temp2; - safepoint(); - } - - @Test(expected = AssertionError.class) - public void test32() { - test("test9Snippet", 4, new int[]{1}); - } - - @Test(expected = AssertionError.class) - public void test33() { - test("test9Snippet", 4, new int[]{2}); - } - - @Test(expected = AssertionError.class) - public void test34() { - test("test9Snippet", 4, new int[]{3}); - } - - @Test(expected = AssertionError.class) - public void test35() { - test("test9Snippet", 4, new int[]{4}); - } - - @Test(expected = AssertionError.class) - public void test36() { - test("test9Snippet", 4, new int[]{1, 2}); - } - - @Test(expected = AssertionError.class) - public void test37() { - test("test9Snippet", 4, new int[]{3, 4}); - } - - public static void test10Snippet(boolean test) { - Container main1 = new Container(); - Container main2 = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - safepoint(); - if (test) { - barrierIndex = 1; - main1.a = temp1; - barrierIndex = 2; - main2.a = temp2; - } else { - barrierIndex = 3; - main2.a = temp1; - } - barrierIndex = 4; - main1.b = temp2; - barrierIndex = 5; - main2.b = temp2; - safepoint(); - } - - @Test(expected = AssertionError.class) - public void test38() { - test("test10Snippet", 5, new int[]{1}); - } - - @Test(expected = AssertionError.class) - public void test39() { - test("test10Snippet", 5, new int[]{2}); - } - - @Test(expected = AssertionError.class) - public void test40() { - test("test10Snippet", 5, new int[]{3}); - } - - @Test(expected = AssertionError.class) - public void test41() { - test("test10Snippet", 5, new int[]{4}); - } - - @Test - public void test42() { - test("test10Snippet", 5, new int[]{5}); - } - - @Test(expected = AssertionError.class) - public void test43() { - test("test10Snippet", 5, new int[]{1, 2}); - } - - @Test(expected = AssertionError.class) - public void test44() { - test("test10Snippet", 5, new int[]{1, 2, 3}); - } - - @Test(expected = AssertionError.class) - public void test45() { - test("test10Snippet", 5, new int[]{3, 4}); - } - - public static void test11Snippet(boolean test) { - Container main1 = new Container(); - Container main2 = new Container(); - Container main3 = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - safepoint(); - if (test) { - barrierIndex = 1; - main1.a = temp1; - barrierIndex = 2; - main3.a = temp1; - if (!test) { - barrierIndex = 3; - main2.a = temp2; - } else { - barrierIndex = 4; - main1.a = temp2; - barrierIndex = 5; - main3.a = temp2; - } - } else { - barrierIndex = 6; - main1.b = temp2; - for (int i = 0; i < 10; i++) { - barrierIndex = 7; - main3.a = temp1; - } - barrierIndex = 8; - main3.b = temp2; - } - barrierIndex = 9; - main1.b = temp2; - barrierIndex = 10; - main2.b = temp2; - barrierIndex = 11; - main3.b = temp2; - safepoint(); - } - - @Test(expected = AssertionError.class) - public void test46() { - test("test11Snippet", 11, new int[]{1}); - } - - @Test(expected = AssertionError.class) - public void test47() { - test("test11Snippet", 11, new int[]{2}); - } - - @Test(expected = AssertionError.class) - public void test48() { - test("test11Snippet", 11, new int[]{3}); - } - - @Test(expected = AssertionError.class) - public void test49() { - test("test11Snippet", 11, new int[]{6}); - } - - @Test(expected = AssertionError.class) - public void test50() { - test("test11Snippet", 11, new int[]{7}); - } - - @Test(expected = AssertionError.class) - public void test51() { - test("test11Snippet", 11, new int[]{8}); - } - - @Test(expected = AssertionError.class) - public void test52() { - test("test11Snippet", 11, new int[]{9}); - } - - @Test(expected = AssertionError.class) - public void test53() { - test("test11Snippet", 11, new int[]{10}); - } - - @Test - public void test54() { - test("test11Snippet", 11, new int[]{4}); - } - - @Test - public void test55() { - test("test11Snippet", 11, new int[]{5}); - } - - @Test - public void test56() { - test("test11Snippet", 11, new int[]{11}); - } - - public static void test12Snippet(boolean test) { - Container main = new Container(); - Container main1 = new Container(); - Container temp1 = new Container(); - Container temp2 = new Container(); - barrierIndex = 0; - safepoint(); - barrierIndex = 7; - main1.a = temp1; - for (int i = 0; i < 10; i++) { - if (test) { - barrierIndex = 1; - main.a = temp1; - barrierIndex = 2; - main.b = temp2; - } else { - barrierIndex = 3; - main.a = temp1; - barrierIndex = 4; - main.b = temp2; - } - } - barrierIndex = 5; - main.a = temp1; - barrierIndex = 6; - main.b = temp1; - barrierIndex = 8; - main1.b = temp1; - safepoint(); - } - - @Test(expected = AssertionError.class) - public void test57() { - test("test12Snippet", 8, new int[]{5}); - } - - @Test - public void test58() { - test("test12Snippet", 8, new int[]{6}); - } - - @Test(expected = AssertionError.class) - public void test59() { - test("test12Snippet", 8, new int[]{7}); - } - - @Test(expected = AssertionError.class) - public void test60() { - test("test12Snippet", 8, new int[]{8}); - } - - private void test(final String snippet, final int expectedBarriers, final int... removedBarrierIndices) { - - AssertionError expectedError = Debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet), new Callable() { - - public AssertionError call() { - final StructuredGraph graph = parse(snippet); - HighTierContext highTierContext = new HighTierContext(runtime(), new Assumptions(false), replacements); - MidTierContext midTierContext = new MidTierContext(runtime(), new Assumptions(false), replacements, runtime().getTarget(), OptimisticOptimizations.ALL); - - new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, highTierContext); - new GuardLoweringPhase().apply(graph, midTierContext); - new SafepointInsertionPhase().apply(graph); - new WriteBarrierAdditionPhase().apply(graph); - - // First, the total number of expected barriers is checked. - final int barriers = graph.getNodes(SerialWriteBarrier.class).count(); - Assert.assertTrue(expectedBarriers == barriers); - - // Iterate over all write nodes and remove barriers according to input indices. - NodeIteratorClosure closure = new NodeIteratorClosure() { - - @Override - protected Boolean processNode(FixedNode node, Boolean currentState) { - if (node instanceof WriteNode) { - WriteNode write = (WriteNode) node; - LocationIdentity obj = write.getLocationIdentity(); - if (obj instanceof ResolvedJavaField) { - if (((ResolvedJavaField) obj).getName().equals("barrierIndex")) { - /* - * A "barrierIndex" variable was found and is checked against - * the input barrier array. - */ - if (eliminateBarrier(write.value().asConstant().asInt(), removedBarrierIndices)) { - return true; - } - } - } - } else if (node instanceof SerialWriteBarrier) { - // Remove flagged write barriers. - if (currentState) { - graph.removeFixed(((SerialWriteBarrier) node)); - return false; - } - } - return currentState; - } - - private boolean eliminateBarrier(int index, int[] map) { - for (int i = 0; i < map.length; i++) { - if (map[i] == index) { - return true; - } - } - return false; - } - - @Override - protected Map processLoop(LoopBeginNode loop, Boolean initialState) { - return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates; - } - - @Override - protected Boolean merge(MergeNode merge, List states) { - return false; - } - - @Override - protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) { - return false; - } - }; - - DebugConfig config = DebugScope.getConfig(); - try { - ReentrantNodeIterator.apply(closure, graph.start(), false, null); - Debug.setConfig(Debug.fixedConfig(false, false, false, false, config.dumpHandlers(), config.output())); - new WriteBarrierVerificationPhase().apply(graph); - } catch (AssertionError error) { - /* - * Catch assertion, test for expected one and re-throw in order to validate unit - * test. - */ - Assert.assertTrue(error.getMessage().equals("Write barrier must be present")); - return error; - } finally { - Debug.setConfig(config); - } - return null; - } - }); - if (expectedError != null) { - throw expectedError; - } - } -} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java Fri Jun 21 17:52:19 2013 +0200 @@ -37,5 +37,7 @@ appendPhase(new ExpandLogicPhase()); appendPhase(new DeadCodeEliminationPhase()); + + appendPhase(new RemoveValueProxyPhase()); } } diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64TailcallOp.java diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java Fri Jun 21 17:52:19 2013 +0200 @@ -0,0 +1,118 @@ +/* + * 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.test; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.hotspot.phases.*; +import com.oracle.graal.nodes.HeapAccess.WriteBarrierType; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.Lowerable.LoweringType; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; + +public class WriteBarrierAdditionTest extends GraalCompilerTest { + + public static class Container { + + public Container a; + public Container b; + } + + public static void test1Snippet() { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + main.a = temp1; + main.b = temp2; + } + + public static void test2Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + for (int i = 0; i < 10; i++) { + if (test) { + main.a = temp1; + main.b = temp2; + } else { + main.a = temp2; + main.b = temp1; + } + } + } + + public static void test3Snippet() { + Container[] main = new Container[10]; + Container temp1 = new Container(); + Container temp2 = new Container(); + for (int i = 0; i < 10; i++) { + main[i].a = main[i].b = temp1; + } + + for (int i = 0; i < 10; i++) { + main[i].a = main[i].b = temp2; + } + + } + + @Test + public void test1() { + test("test1Snippet", 2); + } + + @Test + public void test2() { + test("test2Snippet", 4); + } + + @Test + public void test3() { + test("test3Snippet", 4); + } + + private void test(final String snippet, final int expectedBarriers) { + Debug.scope("WriteBarrierAditionTest", new DebugDumpScope(snippet), new Runnable() { + + public void run() { + StructuredGraph graph = parse(snippet); + HighTierContext context = new HighTierContext(runtime(), new Assumptions(false), replacements); + new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, context); + new WriteBarrierAdditionPhase().apply(graph); + Debug.dump(graph, "After Write Barrier Addition"); + final int barriers = graph.getNodes(SerialWriteBarrier.class).count(); + Assert.assertTrue(barriers == expectedBarriers); + for (WriteNode write : graph.getNodes(WriteNode.class)) { + if (write.getWriteBarrierType() != WriteBarrierType.NONE) { + Assert.assertTrue(write.successors().count() == 1); + Assert.assertTrue(write.next() instanceof SerialWriteBarrier); + } + } + } + }); + } +} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java Fri Jun 21 17:52:19 2013 +0200 @@ -0,0 +1,713 @@ +/* + * 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.test; + +import java.util.*; +import java.util.concurrent.*; + +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.debug.internal.*; +import com.oracle.graal.hotspot.phases.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.Lowerable.LoweringType; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; +import com.oracle.graal.phases.tiers.*; + +/** + * The following tests validate the write barrier verification phase. For every tested snippet, an + * array of write barrier indices and the total write barrier number are passed as parameters. The + * indices denote the barriers that will be manually removed. The write barrier verification phase + * runs after the write barrier removal and depending on the result an assertion might be generated. + * The tests anticipate the presence or not of an assertion generated by the verification phase. + */ +public class WriteBarrierVerificationTest extends GraalCompilerTest { + + public static int barrierIndex; + + public static class Container { + + public Container a; + public Container b; + } + + private static native void safepoint(); + + public static void test1Snippet() { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + barrierIndex = 0; + safepoint(); + barrierIndex = 1; + main.a = temp1; + safepoint(); + barrierIndex = 2; + main.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test1() { + test("test1Snippet", 2, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test2() { + test("test1Snippet", 2, new int[]{2}); + } + + public static void test2Snippet() { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + barrierIndex = 0; + safepoint(); + barrierIndex = 1; + main.a = temp1; + barrierIndex = 2; + main.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test3() { + test("test2Snippet", 2, new int[]{1}); + } + + @Test + public void test4() { + test("test2Snippet", 2, new int[]{2}); + } + + public static void test3Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + barrierIndex = 0; + safepoint(); + for (int i = 0; i < 10; i++) { + if (test) { + barrierIndex = 1; + main.a = temp1; + barrierIndex = 2; + main.b = temp2; + } else { + barrierIndex = 3; + main.a = temp1; + barrierIndex = 4; + main.b = temp2; + } + } + } + + @Test(expected = AssertionError.class) + public void test5() { + test("test3Snippet", 4, new int[]{1, 2}); + } + + @Test(expected = AssertionError.class) + public void test6() { + test("test3Snippet", 4, new int[]{3, 4}); + } + + @Test(expected = AssertionError.class) + public void test7() { + test("test3Snippet", 4, new int[]{1}); + } + + @Test + public void test8() { + test("test3Snippet", 4, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test9() { + test("test3Snippet", 4, new int[]{3}); + } + + @Test + public void test10() { + test("test3Snippet", 4, new int[]{4}); + } + + public static void test4Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + barrierIndex = 1; + main.a = temp1; + for (int i = 0; i < 10; i++) { + if (test) { + barrierIndex = 2; + main.a = temp1; + barrierIndex = 3; + main.b = temp2; + } else { + barrierIndex = 4; + main.a = temp2; + barrierIndex = 5; + main.b = temp1; + } + } + } + + @Test(expected = AssertionError.class) + public void test11() { + test("test4Snippet", 5, new int[]{2, 3}); + } + + @Test(expected = AssertionError.class) + public void test12() { + test("test4Snippet", 5, new int[]{4, 5}); + } + + @Test(expected = AssertionError.class) + public void test13() { + test("test4Snippet", 5, new int[]{1}); + } + + public static void test5Snippet() { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + barrierIndex = 1; + main.a = temp1; + if (main.a == main.b) { + barrierIndex = 2; + main.a = temp1; + barrierIndex = 3; + main.b = temp2; + } else { + barrierIndex = 4; + main.a = temp2; + barrierIndex = 5; + main.b = temp1; + } + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test14() { + test("test5Snippet", 5, new int[]{1}); + } + + @Test + public void test15() { + test("test5Snippet", 5, new int[]{2}); + } + + @Test + public void test16() { + test("test5Snippet", 5, new int[]{4}); + } + + @Test + public void test17() { + test("test5Snippet", 5, new int[]{3}); + } + + @Test + public void test18() { + test("test5Snippet", 5, new int[]{5}); + } + + @Test + public void test19() { + test("test5Snippet", 5, new int[]{2, 3}); + } + + @Test + public void test20() { + test("test5Snippet", 5, new int[]{4, 5}); + } + + public static void test6Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + barrierIndex = 1; + main.a = temp1; + if (test) { + barrierIndex = 2; + main.a = temp1; + barrierIndex = 3; + main.b = temp1.a.a; + } else { + barrierIndex = 4; + main.a = temp2; + barrierIndex = 5; + main.b = temp2.a.a; + } + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test21() { + test("test6Snippet", 5, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test22() { + test("test6Snippet", 5, new int[]{1, 2}); + } + + @Test(expected = AssertionError.class) + public void test23() { + test("test6Snippet", 5, new int[]{3}); + } + + @Test + public void test24() { + test("test6Snippet", 5, new int[]{4}); + } + + public static void test7Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + barrierIndex = 1; + main.a = temp1; + if (test) { + barrierIndex = 2; + main.a = temp1; + } + barrierIndex = 3; + main.b = temp2; + safepoint(); + } + + @Test + public void test25() { + test("test7Snippet", 3, new int[]{2}); + } + + @Test + public void test26() { + test("test7Snippet", 3, new int[]{3}); + } + + @Test + public void test27() { + test("test7Snippet", 3, new int[]{2, 3}); + } + + @Test(expected = AssertionError.class) + public void test28() { + test("test7Snippet", 3, new int[]{1}); + } + + public static void test8Snippet(boolean test) { + Container main = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + if (test) { + barrierIndex = 1; + main.a = temp1; + } + barrierIndex = 2; + main.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test29() { + test("test8Snippet", 2, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test30() { + test("test8Snippet", 2, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test31() { + test("test8Snippet", 2, new int[]{1, 2}); + } + + public static void test9Snippet(boolean test) { + Container main1 = new Container(); + Container main2 = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + if (test) { + barrierIndex = 1; + main1.a = temp1; + } else { + barrierIndex = 2; + main2.a = temp1; + } + barrierIndex = 3; + main1.b = temp2; + barrierIndex = 4; + main2.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test32() { + test("test9Snippet", 4, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test33() { + test("test9Snippet", 4, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test34() { + test("test9Snippet", 4, new int[]{3}); + } + + @Test(expected = AssertionError.class) + public void test35() { + test("test9Snippet", 4, new int[]{4}); + } + + @Test(expected = AssertionError.class) + public void test36() { + test("test9Snippet", 4, new int[]{1, 2}); + } + + @Test(expected = AssertionError.class) + public void test37() { + test("test9Snippet", 4, new int[]{3, 4}); + } + + public static void test10Snippet(boolean test) { + Container main1 = new Container(); + Container main2 = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + if (test) { + barrierIndex = 1; + main1.a = temp1; + barrierIndex = 2; + main2.a = temp2; + } else { + barrierIndex = 3; + main2.a = temp1; + } + barrierIndex = 4; + main1.b = temp2; + barrierIndex = 5; + main2.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test38() { + test("test10Snippet", 5, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test39() { + test("test10Snippet", 5, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test40() { + test("test10Snippet", 5, new int[]{3}); + } + + @Test(expected = AssertionError.class) + public void test41() { + test("test10Snippet", 5, new int[]{4}); + } + + @Test + public void test42() { + test("test10Snippet", 5, new int[]{5}); + } + + @Test(expected = AssertionError.class) + public void test43() { + test("test10Snippet", 5, new int[]{1, 2}); + } + + @Test(expected = AssertionError.class) + public void test44() { + test("test10Snippet", 5, new int[]{1, 2, 3}); + } + + @Test(expected = AssertionError.class) + public void test45() { + test("test10Snippet", 5, new int[]{3, 4}); + } + + public static void test11Snippet(boolean test) { + Container main1 = new Container(); + Container main2 = new Container(); + Container main3 = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + safepoint(); + if (test) { + barrierIndex = 1; + main1.a = temp1; + barrierIndex = 2; + main3.a = temp1; + if (!test) { + barrierIndex = 3; + main2.a = temp2; + } else { + barrierIndex = 4; + main1.a = temp2; + barrierIndex = 5; + main3.a = temp2; + } + } else { + barrierIndex = 6; + main1.b = temp2; + for (int i = 0; i < 10; i++) { + barrierIndex = 7; + main3.a = temp1; + } + barrierIndex = 8; + main3.b = temp2; + } + barrierIndex = 9; + main1.b = temp2; + barrierIndex = 10; + main2.b = temp2; + barrierIndex = 11; + main3.b = temp2; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test46() { + test("test11Snippet", 11, new int[]{1}); + } + + @Test(expected = AssertionError.class) + public void test47() { + test("test11Snippet", 11, new int[]{2}); + } + + @Test(expected = AssertionError.class) + public void test48() { + test("test11Snippet", 11, new int[]{3}); + } + + @Test(expected = AssertionError.class) + public void test49() { + test("test11Snippet", 11, new int[]{6}); + } + + @Test(expected = AssertionError.class) + public void test50() { + test("test11Snippet", 11, new int[]{7}); + } + + @Test(expected = AssertionError.class) + public void test51() { + test("test11Snippet", 11, new int[]{8}); + } + + @Test(expected = AssertionError.class) + public void test52() { + test("test11Snippet", 11, new int[]{9}); + } + + @Test(expected = AssertionError.class) + public void test53() { + test("test11Snippet", 11, new int[]{10}); + } + + @Test + public void test54() { + test("test11Snippet", 11, new int[]{4}); + } + + @Test + public void test55() { + test("test11Snippet", 11, new int[]{5}); + } + + @Test + public void test56() { + test("test11Snippet", 11, new int[]{11}); + } + + public static void test12Snippet(boolean test) { + Container main = new Container(); + Container main1 = new Container(); + Container temp1 = new Container(); + Container temp2 = new Container(); + barrierIndex = 0; + safepoint(); + barrierIndex = 7; + main1.a = temp1; + for (int i = 0; i < 10; i++) { + if (test) { + barrierIndex = 1; + main.a = temp1; + barrierIndex = 2; + main.b = temp2; + } else { + barrierIndex = 3; + main.a = temp1; + barrierIndex = 4; + main.b = temp2; + } + } + barrierIndex = 5; + main.a = temp1; + barrierIndex = 6; + main.b = temp1; + barrierIndex = 8; + main1.b = temp1; + safepoint(); + } + + @Test(expected = AssertionError.class) + public void test57() { + test("test12Snippet", 8, new int[]{5}); + } + + @Test + public void test58() { + test("test12Snippet", 8, new int[]{6}); + } + + @Test(expected = AssertionError.class) + public void test59() { + test("test12Snippet", 8, new int[]{7}); + } + + @Test(expected = AssertionError.class) + public void test60() { + test("test12Snippet", 8, new int[]{8}); + } + + private void test(final String snippet, final int expectedBarriers, final int... removedBarrierIndices) { + + AssertionError expectedError = Debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet), new Callable() { + + public AssertionError call() { + final StructuredGraph graph = parse(snippet); + HighTierContext highTierContext = new HighTierContext(runtime(), new Assumptions(false), replacements); + MidTierContext midTierContext = new MidTierContext(runtime(), new Assumptions(false), replacements, runtime().getTarget(), OptimisticOptimizations.ALL); + + new LoweringPhase(LoweringType.BEFORE_GUARDS).apply(graph, highTierContext); + new GuardLoweringPhase().apply(graph, midTierContext); + new SafepointInsertionPhase().apply(graph); + new WriteBarrierAdditionPhase().apply(graph); + + // First, the total number of expected barriers is checked. + final int barriers = graph.getNodes(SerialWriteBarrier.class).count(); + Assert.assertTrue(expectedBarriers == barriers); + + // Iterate over all write nodes and remove barriers according to input indices. + NodeIteratorClosure closure = new NodeIteratorClosure() { + + @Override + protected Boolean processNode(FixedNode node, Boolean currentState) { + if (node instanceof WriteNode) { + WriteNode write = (WriteNode) node; + LocationIdentity obj = write.getLocationIdentity(); + if (obj instanceof ResolvedJavaField) { + if (((ResolvedJavaField) obj).getName().equals("barrierIndex")) { + /* + * A "barrierIndex" variable was found and is checked against + * the input barrier array. + */ + if (eliminateBarrier(write.value().asConstant().asInt(), removedBarrierIndices)) { + return true; + } + } + } + } else if (node instanceof SerialWriteBarrier) { + // Remove flagged write barriers. + if (currentState) { + graph.removeFixed(((SerialWriteBarrier) node)); + return false; + } + } + return currentState; + } + + private boolean eliminateBarrier(int index, int[] map) { + for (int i = 0; i < map.length; i++) { + if (map[i] == index) { + return true; + } + } + return false; + } + + @Override + protected Map processLoop(LoopBeginNode loop, Boolean initialState) { + return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates; + } + + @Override + protected Boolean merge(MergeNode merge, List states) { + return false; + } + + @Override + protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) { + return false; + } + }; + + DebugConfig config = DebugScope.getConfig(); + try { + ReentrantNodeIterator.apply(closure, graph.start(), false, null); + Debug.setConfig(Debug.fixedConfig(false, false, false, false, config.dumpHandlers(), config.output())); + new WriteBarrierVerificationPhase().apply(graph); + } catch (AssertionError error) { + /* + * Catch assertion, test for expected one and re-throw in order to validate unit + * test. + */ + Assert.assertTrue(error.getMessage().equals("Write barrier must be present")); + return error; + } finally { + Debug.setConfig(config); + } + return null; + } + }); + if (expectedError != null) { + throw expectedError; + } + } +} diff -r 0d40e1cf70db -r 55827d611da7 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 Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Fri Jun 21 17:52:19 2013 +0200 @@ -51,6 +51,8 @@ import static com.oracle.graal.phases.GraalOptions.*; import static com.oracle.graal.replacements.Log.*; import static com.oracle.graal.replacements.MathSubstitutionsX86.*; +import static com.oracle.graal.hotspot.nodes.G1PostWriteBarrierStubCall.*; +import static com.oracle.graal.hotspot.nodes.G1PreWriteBarrierStubCall.*; import java.lang.reflect.*; import java.util.*; @@ -294,7 +296,8 @@ linkForeignCall(r, THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, PREPEND_THREAD, NOT_REEXECUTABLE, ANY_LOCATION); linkForeignCall(r, VM_ERROR, c.vmErrorAddress, PREPEND_THREAD, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(r, OSR_MIGRATION_END, c.osrMigrationEndAddress, DONT_PREPEND_THREAD, NOT_REEXECUTABLE, NO_LOCATIONS); - + linkForeignCall(r, G1WBPRECALL, c.writeBarrierPreAddress, PREPEND_THREAD, REEXECUTABLE, NO_LOCATIONS); + linkForeignCall(r, G1WBPOSTCALL, c.writeBarrierPostAddress, PREPEND_THREAD, REEXECUTABLE, NO_LOCATIONS); if (IntrinsifyObjectMethods.getValue()) { r.registerSubstitutions(ObjectSubstitutions.class); } @@ -325,6 +328,8 @@ writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, r, graalRuntime.getTarget()); boxingSnippets = new BoxingSnippets.Templates(this, r, graalRuntime.getTarget()); exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, r, graalRuntime.getTarget()); + + r.registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(this, r, graalRuntime.getTarget())); } public HotSpotGraalRuntime getGraalRuntime() { diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrierStubCall.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrierStubCall.java Fri Jun 21 17:52:19 2013 +0200 @@ -0,0 +1,51 @@ +/* + * 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.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.nodes.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.word.*; + +public class G1PostWriteBarrierStubCall extends DeoptimizingStubCall implements LIRGenLowerable { + + @Input private ValueNode cardAddress; + public static final ForeignCallDescriptor G1WBPOSTCALL = new ForeignCallDescriptor("write_barrier_post", void.class, Word.class); + + public G1PostWriteBarrierStubCall(ValueNode cardAddress) { + super(StampFactory.forVoid()); + this.cardAddress = cardAddress; + } + + @Override + public void generate(LIRGenerator gen) { + ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(G1PostWriteBarrierStubCall.G1WBPOSTCALL); + gen.emitForeignCall(linkage, this, gen.operand(cardAddress)); + } + + @NodeIntrinsic + public static native void call(Word cardAddress); +} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrierStubCall.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrierStubCall.java Fri Jun 21 17:52:19 2013 +0200 @@ -0,0 +1,50 @@ +/* + * 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.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.nodes.*; +import com.oracle.graal.nodes.type.*; + +public class G1PreWriteBarrierStubCall extends DeoptimizingStubCall implements LIRGenLowerable { + + @Input private ValueNode object; + public static final ForeignCallDescriptor G1WBPRECALL = new ForeignCallDescriptor("write_barrier_pre", void.class, Object.class); + + public G1PreWriteBarrierStubCall(ValueNode object) { + super(StampFactory.forVoid()); + this.object = object; + } + + @Override + public void generate(LIRGenerator gen) { + ForeignCallLinkage linkage = gen.getRuntime().lookupForeignCall(G1PreWriteBarrierStubCall.G1WBPRECALL); + gen.emitForeignCall(linkage, this, gen.operand(object)); + } + + @NodeIntrinsic + public static native void call(Object hub); +} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Fri Jun 21 17:52:19 2013 +0200 @@ -41,8 +41,10 @@ for (CompareAndSwapNode node : graph.getNodes(CompareAndSwapNode.class)) { addCASBarriers(node, graph); } - for (GenericArrayRangeWriteBarrier node : graph.getNodes(GenericArrayRangeWriteBarrier.class)) { - addArrayRangeBarriers(node, graph); + for (ArrayRangeWriteNode node : graph.getNodes(ArrayRangeWriteNode.class)) { + if (node.isObjectArray()) { + addArrayRangeBarriers(node, graph); + } } } @@ -69,9 +71,9 @@ } } - private static void addArrayRangeBarriers(GenericArrayRangeWriteBarrier node, StructuredGraph graph) { - SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(node.getDstObject(), node.getDstPos(), node.getLength())); - graph.replaceFixedWithFixed(node, serialArrayRangeWriteBarrier); + private static void addArrayRangeBarriers(ArrayRangeWriteNode node, StructuredGraph graph) { + SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); + graph.addAfterFixed(node, serialArrayRangeWriteBarrier); } } diff -r 0d40e1cf70db -r 55827d611da7 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 Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Fri Jun 21 17:52:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -76,35 +76,11 @@ private static final Kind VECTOR_KIND = Kind.Long; private static final long VECTOR_SIZE = arrayIndexScale(Kind.Long); - private static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, Kind baseKind) { + private static void checkedCopy(Object src, int srcPos, Object dest, int destPos, int length, Kind baseKind) { checkNonNull(src); checkNonNull(dest); checkLimits(src, srcPos, dest, destPos, length); - int header = arrayBaseOffset(baseKind); - int elementSize = arrayIndexScale(baseKind); - long byteLength = (long) length * elementSize; - long nonVectorBytes = byteLength % VECTOR_SIZE; - long srcOffset = (long) srcPos * elementSize; - long destOffset = (long) destPos * elementSize; - if (probability(NOT_FREQUENT_PROBABILITY, src == dest) && probability(NOT_FREQUENT_PROBABILITY, srcPos < destPos)) { - // bad aliased case - for (long i = byteLength - elementSize; i >= byteLength - nonVectorBytes; i -= elementSize) { - UnsafeStoreNode.store(dest, header, i + destOffset, UnsafeLoadNode.load(src, header, i + srcOffset, baseKind), baseKind); - } - long vectorLength = byteLength - nonVectorBytes; - for (long i = vectorLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } else { - for (long i = 0; i < nonVectorBytes; i += elementSize) { - UnsafeStoreNode.store(dest, header, i + destOffset, UnsafeLoadNode.load(src, header, i + srcOffset, baseKind), baseKind); - } - for (long i = nonVectorBytes; i < byteLength; i += VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } + UnsafeArrayCopyNode.arraycopy(src, srcPos, dest, destPos, length, baseKind); } public static void checkNonNull(Object obj) { @@ -149,85 +125,49 @@ @Snippet public static void arraycopy(byte[] src, int srcPos, byte[] dest, int destPos, int length) { byteCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Byte); + checkedCopy(src, srcPos, dest, destPos, length, Kind.Byte); } @Snippet public static void arraycopy(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { booleanCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Byte); + checkedCopy(src, srcPos, dest, destPos, length, Kind.Boolean); } @Snippet public static void arraycopy(char[] src, int srcPos, char[] dest, int destPos, int length) { charCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Char); + checkedCopy(src, srcPos, dest, destPos, length, Kind.Char); } @Snippet public static void arraycopy(short[] src, int srcPos, short[] dest, int destPos, int length) { shortCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Short); + checkedCopy(src, srcPos, dest, destPos, length, Kind.Short); } @Snippet public static void arraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) { intCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Int); + checkedCopy(src, srcPos, dest, destPos, length, Kind.Int); } @Snippet public static void arraycopy(float[] src, int srcPos, float[] dest, int destPos, int length) { floatCounter.inc(); - vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Float); + checkedCopy(src, srcPos, dest, destPos, length, Kind.Float); } @Snippet public static void arraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) { longCounter.inc(); - checkNonNull(src); - checkNonNull(dest); - checkLimits(src, srcPos, dest, destPos, length); - Kind baseKind = Kind.Long; - int header = arrayBaseOffset(baseKind); - long byteLength = (long) length * arrayIndexScale(baseKind); - long srcOffset = (long) srcPos * arrayIndexScale(baseKind); - long destOffset = (long) destPos * arrayIndexScale(baseKind); - if (src == dest && srcPos < destPos) { // bad aliased case - for (long i = byteLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } else { - for (long i = 0; i < byteLength; i += VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } + checkedCopy(src, srcPos, dest, destPos, length, Kind.Long); } @Snippet public static void arraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { doubleCounter.inc(); - checkNonNull(src); - checkNonNull(dest); - checkLimits(src, srcPos, dest, destPos, length); - Kind baseKind = Kind.Double; - int header = arrayBaseOffset(baseKind); - long byteLength = (long) length * arrayIndexScale(baseKind); - long srcOffset = (long) srcPos * arrayIndexScale(baseKind); - long destOffset = (long) destPos * arrayIndexScale(baseKind); - if (src == dest && srcPos < destPos) { // bad aliased case - for (long i = byteLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } else { - for (long i = 0; i < byteLength; i += VECTOR_SIZE) { - Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); - UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); - } - } + checkedCopy(src, srcPos, dest, destPos, length, Kind.Double); } @Snippet @@ -239,48 +179,25 @@ @Snippet public static void arrayObjectCopy(Object src, int srcPos, Object dest, int destPos, int length) { objectCounter.inc(); - checkNonNull(src); - checkNonNull(dest); - checkLimits(src, srcPos, dest, destPos, length); - final int scale = arrayIndexScale(Kind.Object); - int header = arrayBaseOffset(Kind.Object); - if (src == dest && srcPos < destPos) { // bad aliased case - long start = (long) (length - 1) * scale; - 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); - } - } else { - long end = (long) length * scale; - 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); - - } - } - if (length > 0) { - GenericArrayRangeWriteBarrier.insertWriteBarrier(dest, destPos, length); - } + checkedCopy(src, srcPos, dest, destPos, length, Kind.Object); } @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 (probability(FAST_PATH_PROBABILITY, srcHub.equal(destHub)) && probability(FAST_PATH_PROBABILITY, src != dest)) { + int layoutHelper = checkArrayType(srcHub); + final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) == 0); - if (probability(FAST_PATH_PROBABILITY, srcHub.equal(destHub)) && probability(FAST_PATH_PROBABILITY, src != dest)) { checkLimits(src, srcPos, dest, destPos, length); if (probability(FAST_PATH_PROBABILITY, isObjectArray)) { genericObjectExactCallCounter.inc(); arrayObjectCopy(src, srcPos, dest, destPos, length); } else { genericPrimitiveCallCounter.inc(); - arraycopyInnerloop(src, srcPos, dest, destPos, length, layoutHelper); + UnsafeArrayCopyNode.arraycopyPrimitive(src, srcPos, dest, destPos, length, layoutHelper); } } else { genericObjectCallCounter.inc(); @@ -288,33 +205,6 @@ } } - public static void arraycopyInnerloop(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) { - int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); - int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); - - Word memory = (Word) Word.fromObject(src); - - Word srcOffset = (Word) Word.fromObject(src).add(headerSize).add(srcPos << log2ElementSize); - Word destOffset = (Word) Word.fromObject(dest).add(headerSize).add(destPos << log2ElementSize); - Word destStart = destOffset; - long sizeInBytes = ((long) length) << log2ElementSize; - Word destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize)); - - int nonVectorBytes = (int) (sizeInBytes % VECTOR_SIZE); - Word destNonVectorEnd = destStart.add(nonVectorBytes); - - while (destOffset.belowThan(destNonVectorEnd)) { - destOffset.writeByte(0, srcOffset.readByte(0, ANY_LOCATION), ANY_LOCATION); - destOffset = destOffset.add(1); - srcOffset = srcOffset.add(1); - } - while (destOffset.belowThan(destEnd)) { - destOffset.writeWord(0, srcOffset.readWord(0, ANY_LOCATION), ANY_LOCATION); - destOffset = destOffset.add(wordSize()); - srcOffset = srcOffset.add(wordSize()); - } - } - private static final SnippetCounter.Group checkCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("System.arraycopy checkInputs") : null; private static final SnippetCounter checkSuccessCounter = new SnippetCounter(checkCounters, "checkSuccess", "checkSuccess"); private static final SnippetCounter checkNPECounter = new SnippetCounter(checkCounters, "checkNPE", "checkNPE"); diff -r 0d40e1cf70db -r 55827d611da7 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 Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Fri Jun 21 17:52:19 2013 +0200 @@ -126,7 +126,7 @@ Word hub = loadWordFromObject(elementType, arrayKlassOffset()); if (hub.equal(Word.zero())) { // the array class is not yet loaded - DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.Unresolved); + DeoptimizeNode.deopt(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved); } int layoutHelper = readLayoutHelper(hub); @@ -143,8 +143,8 @@ // esz is the element size in bytes //@formatter:on - int headerSize = (layoutHelper >> 16) & 0xFF; - int log2ElementSize = layoutHelper & 0xFF; + int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); return allocateArray(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents); diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java Fri Jun 21 17:52:19 2013 +0200 @@ -0,0 +1,122 @@ +/* + * 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 static com.oracle.graal.api.meta.LocationIdentity.*; + +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.replacements.SnippetTemplate.Arguments; + +public final class UnsafeArrayCopyNode extends ArrayRangeWriteNode implements Lowerable, MemoryCheckpoint.Single { + + @Input private ValueNode src; + @Input private ValueNode srcPos; + @Input private ValueNode dest; + @Input private ValueNode destPos; + @Input private ValueNode length; + @Input private ValueNode layoutHelper; + + private Kind elementKind; + + private UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper, Kind elementKind) { + super(StampFactory.forVoid()); + assert layoutHelper == null || elementKind == null; + this.src = src; + this.srcPos = srcPos; + this.dest = dest; + this.destPos = destPos; + this.length = length; + this.layoutHelper = layoutHelper; + this.elementKind = elementKind; + } + + private UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind) { + this(src, srcPos, dest, destPos, length, null, elementKind); + } + + private UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper) { + this(src, srcPos, dest, destPos, length, layoutHelper, null); + } + + @Override + public ValueNode getArray() { + return dest; + } + + @Override + public ValueNode getIndex() { + return destPos; + } + + @Override + public ValueNode getLength() { + return length; + } + + @Override + public boolean isObjectArray() { + return elementKind == Kind.Object; + } + + public Kind getElementKind() { + return elementKind; + } + + @Override + public void lower(LoweringTool tool, LoweringType loweringType) { + if (loweringType == LoweringType.AFTER_GUARDS) { + UnsafeArrayCopySnippets.Templates templates = tool.getReplacements().getSnippetTemplateCache(UnsafeArrayCopySnippets.Templates.class); + templates.lower(this); + } + } + + public void addSnippetArguments(Arguments args) { + args.add("src", src); + args.add("srcPos", srcPos); + args.add("dest", dest); + args.add("destPos", destPos); + args.add("length", length); + if (layoutHelper != null) { + args.add("layoutHelper", layoutHelper); + } + } + + @Override + public LocationIdentity getLocationIdentity() { + if (elementKind == null) { + return ANY_LOCATION; + } else { + return NamedLocationIdentity.getArrayLocation(elementKind); + } + } + + @NodeIntrinsic + public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter Kind elementKind); + + @NodeIntrinsic + public static native void arraycopyPrimitive(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper); +} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopySnippets.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopySnippets.java Fri Jun 21 17:52:19 2013 +0200 @@ -0,0 +1,232 @@ +/* + * 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 static com.oracle.graal.api.meta.LocationIdentity.*; +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; +import static com.oracle.graal.replacements.SnippetTemplate.*; +import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; +import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.word.*; + +public class UnsafeArrayCopySnippets implements Snippets { + + private static final Kind VECTOR_KIND = Kind.Long; + private static final long VECTOR_SIZE = arrayIndexScale(Kind.Long); + + private static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, Kind baseKind) { + int header = arrayBaseOffset(baseKind); + int elementSize = arrayIndexScale(baseKind); + long byteLength = (long) length * elementSize; + long nonVectorBytes = byteLength % VECTOR_SIZE; + long srcOffset = (long) srcPos * elementSize; + long destOffset = (long) destPos * elementSize; + if (probability(NOT_FREQUENT_PROBABILITY, src == dest) && probability(NOT_FREQUENT_PROBABILITY, srcPos < destPos)) { + // bad aliased case + for (long i = byteLength - elementSize; i >= byteLength - nonVectorBytes; i -= elementSize) { + UnsafeStoreNode.store(dest, header, i + destOffset, UnsafeLoadNode.load(src, header, i + srcOffset, baseKind), baseKind); + } + long vectorLength = byteLength - nonVectorBytes; + for (long i = vectorLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } else { + for (long i = 0; i < nonVectorBytes; i += elementSize) { + UnsafeStoreNode.store(dest, header, i + destOffset, UnsafeLoadNode.load(src, header, i + srcOffset, baseKind), baseKind); + } + for (long i = nonVectorBytes; i < byteLength; i += VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } + } + + @Snippet + public static void arraycopyByte(byte[] src, int srcPos, byte[] dest, int destPos, int length) { + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Byte); + } + + @Snippet + public static void arraycopyBoolean(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) { + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Byte); + } + + @Snippet + public static void arraycopyChar(char[] src, int srcPos, char[] dest, int destPos, int length) { + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Char); + } + + @Snippet + public static void arraycopyShort(short[] src, int srcPos, short[] dest, int destPos, int length) { + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Short); + } + + @Snippet + public static void arraycopyInt(int[] src, int srcPos, int[] dest, int destPos, int length) { + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Int); + } + + @Snippet + public static void arraycopyFloat(float[] src, int srcPos, float[] dest, int destPos, int length) { + vectorizedCopy(src, srcPos, dest, destPos, length, Kind.Float); + } + + @Snippet + public static void arraycopyLong(long[] src, int srcPos, long[] dest, int destPos, int length) { + Kind baseKind = Kind.Long; + int header = arrayBaseOffset(baseKind); + long byteLength = (long) length * arrayIndexScale(baseKind); + long srcOffset = (long) srcPos * arrayIndexScale(baseKind); + long destOffset = (long) destPos * arrayIndexScale(baseKind); + if (src == dest && srcPos < destPos) { // bad aliased case + for (long i = byteLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } else { + for (long i = 0; i < byteLength; i += VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } + } + + @Snippet + public static void arraycopyDouble(double[] src, int srcPos, double[] dest, int destPos, int length) { + Kind baseKind = Kind.Double; + int header = arrayBaseOffset(baseKind); + long byteLength = (long) length * arrayIndexScale(baseKind); + long srcOffset = (long) srcPos * arrayIndexScale(baseKind); + long destOffset = (long) destPos * arrayIndexScale(baseKind); + if (src == dest && srcPos < destPos) { // bad aliased case + for (long i = byteLength - VECTOR_SIZE; i >= 0; i -= VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } else { + for (long i = 0; i < byteLength; i += VECTOR_SIZE) { + Long a = UnsafeLoadNode.load(src, header, i + srcOffset, VECTOR_KIND); + UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), VECTOR_KIND); + } + } + } + + /** + * Does NOT perform store checks. + */ + @Snippet + public static void arraycopyObject(Object[] src, int srcPos, Object[] dest, int destPos, int length) { + final int scale = arrayIndexScale(Kind.Object); + int header = arrayBaseOffset(Kind.Object); + if (src == dest && srcPos < destPos) { // bad aliased case + long start = (long) (length - 1) * scale; + 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); + } + } else { + long end = (long) length * scale; + 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); + } + } + } + + @Snippet + public static void arraycopyPrimitive(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) { + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); + int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); + + Word srcOffset = (Word) Word.fromObject(src).add(headerSize).add(srcPos << log2ElementSize); + Word destOffset = (Word) Word.fromObject(dest).add(headerSize).add(destPos << log2ElementSize); + Word destStart = destOffset; + long sizeInBytes = ((long) length) << log2ElementSize; + Word destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize)); + + int nonVectorBytes = (int) (sizeInBytes % VECTOR_SIZE); + Word destNonVectorEnd = destStart.add(nonVectorBytes); + + while (destOffset.belowThan(destNonVectorEnd)) { + destOffset.writeByte(0, srcOffset.readByte(0, ANY_LOCATION), ANY_LOCATION); + destOffset = destOffset.add(1); + srcOffset = srcOffset.add(1); + } + while (destOffset.belowThan(destEnd)) { + destOffset.writeWord(0, srcOffset.readWord(0, ANY_LOCATION), ANY_LOCATION); + destOffset = destOffset.add(wordSize()); + srcOffset = srcOffset.add(wordSize()); + } + } + + public static class Templates extends AbstractTemplates { + + private final SnippetInfo[] arraycopySnippets; + private final SnippetInfo genericPrimitiveSnippet; + + public Templates(MetaAccessProvider runtime, Replacements replacements, TargetDescription target) { + super(runtime, replacements, target); + + arraycopySnippets = new SnippetInfo[Kind.values().length]; + arraycopySnippets[Kind.Boolean.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyBoolean"); + arraycopySnippets[Kind.Byte.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyByte"); + arraycopySnippets[Kind.Short.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyShort"); + arraycopySnippets[Kind.Char.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyChar"); + arraycopySnippets[Kind.Int.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyInt"); + arraycopySnippets[Kind.Long.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyLong"); + arraycopySnippets[Kind.Float.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyFloat"); + arraycopySnippets[Kind.Double.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyDouble"); + arraycopySnippets[Kind.Object.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyObject"); + + genericPrimitiveSnippet = snippet(UnsafeArrayCopySnippets.class, "arraycopyPrimitive"); + } + + public void lower(UnsafeArrayCopyNode node) { + Kind elementKind = node.getElementKind(); + SnippetInfo snippet; + if (elementKind == null) { + // primitive array of unknown kind + snippet = genericPrimitiveSnippet; + } else { + snippet = arraycopySnippets[elementKind.ordinal()]; + assert snippet != null : "arraycopy snippet for " + elementKind.name() + " not found"; + } + + Arguments args = new Arguments(snippet); + node.addSnippetArguments(args); + + SnippetTemplate template = template(args); + template.instantiate(runtime, node, DEFAULT_REPLACER, args); + } + } +} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1PostWriteBarrier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1PostWriteBarrier.java Fri Jun 21 17:52:19 2013 +0200 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes; + +import com.oracle.graal.nodes.extended.*; + +public class G1PostWriteBarrier extends WriteBarrier { + + @Input private ValueNode value; + + public ValueNode getValue() { + return value; + } + + public G1PostWriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise) { + super(object, location, precise); + this.value = value; + } +} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1PreWriteBarrier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/G1PreWriteBarrier.java Fri Jun 21 17:52:19 2013 +0200 @@ -0,0 +1,45 @@ +/* + * 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; + +import com.oracle.graal.nodes.extended.*; + +public class G1PreWriteBarrier extends WriteBarrier { + + @Input private ValueNode expectedObject; + private final boolean doLoad; + + public ValueNode getExpectedObject() { + return expectedObject; + } + + public boolean doLoad() { + return doLoad; + } + + public G1PreWriteBarrier(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad) { + super(object, location, true); + this.doLoad = doLoad; + this.expectedObject = expectedObject; + } +} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GenericArrayRangeWriteBarrier.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GenericArrayRangeWriteBarrier.java Fri Jun 21 17:52:08 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * 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; - -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.type.*; - -public final class GenericArrayRangeWriteBarrier extends FixedWithNextNode implements Node.IterableNodeType { - - @Input private ValueNode dstObject; - @Input private ValueNode dstPos; - @Input private ValueNode length; - - public ValueNode getDstObject() { - return dstObject; - } - - public ValueNode getDstPos() { - return dstPos; - } - - public ValueNode getLength() { - return length; - } - - public GenericArrayRangeWriteBarrier(ValueNode dstObject, ValueNode dstPos, ValueNode length) { - super(StampFactory.forVoid()); - this.dstObject = dstObject; - this.dstPos = dstPos; - this.length = length; - - } - - @NodeIntrinsic - public static native void insertWriteBarrier(Object dstObject, int dstPos, int length); -} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialWriteBarrier.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialWriteBarrier.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialWriteBarrier.java Fri Jun 21 17:52:19 2013 +0200 @@ -22,39 +22,11 @@ */ package com.oracle.graal.nodes; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public final class SerialWriteBarrier extends FixedWithNextNode implements Lowerable, Node.IterableNodeType { - - @Input private ValueNode object; - @Input private LocationNode location; - private final boolean precise; - public ValueNode getObject() { - return object; - } - - public LocationNode getLocation() { - return location; - } - - public boolean usePrecise() { - return precise; - } +public class SerialWriteBarrier extends WriteBarrier { public SerialWriteBarrier(ValueNode object, LocationNode location, boolean precise) { - super(StampFactory.forVoid()); - this.object = object; - this.location = location; - this.precise = precise; - } - - @Override - public void lower(LoweringTool generator, LoweringType loweringType) { - assert loweringType == LoweringType.AFTER_GUARDS; - generator.getRuntime().lower(this, generator); + super(object, location, precise); } } diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/WriteBarrier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/WriteBarrier.java Fri Jun 21 17:52:19 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; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class WriteBarrier extends FixedWithNextNode implements Lowerable, Node.IterableNodeType { + + @Input private ValueNode object; + @Input private LocationNode location; + private final boolean precise; + + public ValueNode getObject() { + return object; + } + + public LocationNode getLocation() { + return location; + } + + public boolean usePrecise() { + return precise; + } + + public WriteBarrier(ValueNode object, LocationNode location, boolean precise) { + super(StampFactory.forVoid()); + this.object = object; + this.location = location; + this.precise = precise; + } + + @Override + public void lower(LoweringTool generator, LoweringType loweringType) { + assert loweringType == LoweringType.AFTER_GUARDS; + generator.getRuntime().lower(this, generator); + } +} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java Fri Jun 21 17:52:19 2013 +0200 @@ -0,0 +1,57 @@ +/* + * 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.extended; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +/** + * Base class for nodes that modify a range of an array. + */ +public abstract class ArrayRangeWriteNode extends AbstractStateSplit implements Node.IterableNodeType { + + protected ArrayRangeWriteNode(Stamp stamp) { + super(stamp); + } + + /** + * The array that is written to. + */ + public abstract ValueNode getArray(); + + /** + * The first modified index. + */ + public abstract ValueNode getIndex(); + + /** + * The length of the modified range. + */ + public abstract ValueNode getLength(); + + /** + * Return true if the written array is an object array, false if it is a primitive array. + */ + public abstract boolean isObjectArray(); +} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.graal.service.processor/src/com/oracle/graal/service/processor/ServiceProviderProcessor.java diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/CreateCast.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/CreateCast.java Fri Jun 21 17:52:19 2013 +0200 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.lang.annotation.*; + +import com.oracle.truffle.api.nodes.*; + +/** + * Specifies a factory method that creates a {@link Node} which is used to cast this child. + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD}) +public @interface CreateCast { + + String[] value(); + +} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/ExecuteChildren.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/ExecuteChildren.java Fri Jun 21 17:52:08 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +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; - -import java.lang.annotation.*; - -@Retention(RetentionPolicy.CLASS) -@Target({ElementType.TYPE}) -public @interface ExecuteChildren { - - String[] value(); - -} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/ExtensionAnnotation.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/ExtensionAnnotation.java Fri Jun 21 17:52:08 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +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; - -import java.lang.annotation.*; - -@Retention(RetentionPolicy.CLASS) -@Target({ElementType.ANNOTATION_TYPE}) -public @interface ExtensionAnnotation { - - String processorClassName(); - -} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java Fri Jun 21 17:52:19 2013 +0200 @@ -26,6 +26,10 @@ import com.oracle.truffle.api.nodes.*; +/** + * A {@link NodeChild} element defines an executable child for the enclosing {@link Node}. A + * {@link Node} contains multiple {@link NodeChildren} specified in linear execution order. + */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.TYPE}) public @interface NodeChild { @@ -35,13 +39,13 @@ Class type() default NodeClass.InheritNode.class; /** - * Executes the {@link NodeChild} with values from other defined {@link NodeChild} elements. - * These referenced children must be defined before the current node in the execution order. The - * current node {@link #type()} attribute must be set to a {@link Node} which supports the - * evaluated execution with the number of {@link #executeWith()} arguments that are defined. For - * example if this child is executed with one argument, the {@link #type()} attribute must - * define a node which publicly declares a method with the signature - * Object execute*(VirtualFrame, Object). + * The {@link #executeWith()} property allows a node to pass the result of one child's + * executable as an input to another child's executable. These referenced children must be + * defined before the current node in the execution order. The current node {@link #type()} + * attribute must be set to a {@link Node} which supports the evaluated execution with the + * number of {@link #executeWith()} arguments that are defined. For example if this child is + * executed with one argument, the {@link #type()} attribute must define a node which publicly + * declares a method with the signature Object execute*(VirtualFrame, Object). */ String[] executeWith() default {}; } diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java Fri Jun 21 17:52:19 2013 +0200 @@ -24,42 +24,56 @@ import java.lang.annotation.*; +import com.oracle.truffle.api.nodes.*; + /** *

- * Annotates a type system class that represents type information for a node. Generates code for - * converting and managing types. Methods contained in the type system may be annotated with - * {@link TypeCast} or {@link TypeCheck}. These methods alter the default behavior of the type - * system. + * Each {@link Node} has one {@link TypeSystem} at its root to define the types that can be used + * throughout the system. Multiple {@link TypeSystem}s are allowed, but they cannot be mixed inside + * a single {@link Node} hierarchy. A {@link TypeSystem} defines a list of types as its child + * elements, in which every type precedes its super types.The latter condition ensures that the most + * concrete type is found first when searching the list sequentially for the type of a given generic + * value. *

* - * - * Example: *

- * Shows a @TypeSystem definition with three types. In this example BigIntegers can be - * also treated as integers if their bit width is less than 32. + * Each {@link #value()} is represented as a java type. A type can specify two annotations: + * {@link TypeCheck} and {@link TypeCast}. The {@link TypeCheck} checks whether a given generic + * value matches to the current type. The {@link TypeCast} casts a generic type value to the current + * type. If the {@link TypeCheck} and {@link TypeCast} annotations are not declared in the + * {@link TypeSystem} the a default implementation is provided. The default implementation of + * {@link TypeCheck} returns true only on an exact type match and {@link TypeCast} is + * only a cast to this type. Specified methods with {@link TypeCheck} and {@link TypeCast} may be + * used to extend the definition of a type in the language. In our example, the + * isInteger and asInteger methods are defined in a way so that they + * accept also {@link Integer} values, implicitly converting them to {@link Double} . This example + * points out how we express implicit type conversions. *

* + *

+ * Example: The {@link TypeSystem} contains the types {@link Boolean}, {@link Integer}, and + * {@link Double}. The type {@link Object} is always used implicitly as the generic type represent + * all values. + * *

  * 
- * {@literal @}TypeSystem(types = {int.class, BigInteger.class, String.class}, nodeBaseClass = TypedNode.class)
- * public abstract class Types {
+ * {@literal @}TypeSystem(types = {boolean.class, int.class, double.class})
+ * public abstract class ExampleTypeSystem {
  * 
  *     {@literal @}TypeCheck
  *     public boolean isInteger(Object value) {
- *         return value instanceof Integer || (value instanceof BigInteger && ((BigInteger) value).bitLength() < Integer.SIZE);
+ *         return value instanceof Integer || value instanceof Double;
  *     }
  * 
  *     {@literal @}TypeCast
- *     public int asInteger(Object value) {
- *         if (value instanceof Integer) {
- *             return (int) value;
- *         } else {
- *             return ((BigInteger) value).intValue();
- *         }
+ *     public double asInteger(Object value) {
+ *         return ((Number)value).doubleValue();
  *     }
  * }
  * 
* + *

+ * * @see TypeCast * @see TypeCheck */ @@ -68,8 +82,7 @@ public @interface TypeSystem { /** - * Sets the types contained by this type system. The order of types also determines the order of - * specialization. + * The list of types as child elements of the {@link TypeSystem}. Each precedes its super type. */ Class[] value(); diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystemReference.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystemReference.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystemReference.java Fri Jun 21 17:52:19 2013 +0200 @@ -24,10 +24,20 @@ import java.lang.annotation.*; +import com.oracle.truffle.api.nodes.*; + +/** + * References a {@link TypeSystem} on a node. Must be applied on a {@link Node} class. At least one + * {@link TypeSystem} must be referenced in a {@link Node}'s type hierarchy. + * + * @see TypeSystem + * @see Node + */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.TYPE}) public @interface TypeSystemReference { + /** The {@link TypeSystem} java type. */ Class value(); } diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Fri Jun 21 17:52:19 2013 +0200 @@ -583,8 +583,13 @@ List values = getAnnotationValue(List.class, mirror, name); List result = new ArrayList<>(); - for (AnnotationValue value : values) { - result.add(resolveAnnotationValue(expectedListType, value)); + if (values != null) { + for (AnnotationValue value : values) { + T annotationValue = resolveAnnotationValue(expectedListType, value); + if (annotationValue != null) { + result.add(annotationValue); + } + } } return result; } @@ -595,6 +600,10 @@ @SuppressWarnings({"unchecked"}) private static T resolveAnnotationValue(Class expectedType, AnnotationValue value) { + if (value == null) { + return null; + } + Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null); if (unboxedValue != null) { if (expectedType == TypeMirror.class && unboxedValue instanceof String) { diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Fri Jun 21 17:52:19 2013 +0200 @@ -563,7 +563,7 @@ public ExecutableElement findMethod() { Element element = currentElement; - while (element != null && (element.getKind() != ElementKind.METHOD)) { + while (element != null && (element.getKind() != ElementKind.METHOD && (element.getKind() != ElementKind.CONSTRUCTOR))) { element = element.getEnclosingElement(); } ExecutableElement found = element != null ? (ExecutableElement) element : null; diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionCodeElementFactory.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionCodeElementFactory.java Fri Jun 21 17:52:08 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.codegen.processor.ext; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.api.element.*; -import com.oracle.truffle.codegen.processor.ast.*; - -final class ExtensionCodeElementFactory implements WritableElementFactory { - - private final ProcessorContext context; - - Element generatorElement; - AnnotationMirror generatorAnnotationMirror; - - public ExtensionCodeElementFactory(ProcessorContext context) { - this.context = context; - } - - @Override - public WritableExecutableElement cloneExecutableElement(ExecutableElement method) { - return updateGenerators(CodeExecutableElement.clone(context.getEnvironment(), method)); - } - - @Override - public WritableVariableElement cloneVariableElement(VariableElement var) { - return updateGenerators(CodeVariableElement.clone(var)); - } - - @Override - public WritableAnnotationMirror cloneAnnotationMirror(AnnotationMirror mirror) { - return CodeAnnotationMirror.clone(mirror); - } - - @Override - public WritableVariableElement createParameter(TypeMirror type, String simpleName) { - return updateGenerators(new CodeVariableElement(Utils.modifiers(), type, simpleName)); - } - - @Override - public WritableExecutableElement createExecutableElement(TypeMirror returnType, String methodName) { - return updateGenerators(new CodeExecutableElement(returnType, methodName)); - } - - @Override - public TypeMirror createTypeMirror(Class javaClass) { - return context.getType(javaClass); - } - - @Override - public WritableAnnotationMirror createAnnotationMirror(DeclaredType typeMirror) { - return new CodeAnnotationMirror(typeMirror); - } - - @Override - public Name createName(String name) { - return CodeNames.of(name); - } - - @Override - public AnnotationValue createAnnotationValue(Object value) { - return new CodeAnnotationValue(value); - } - - private E updateGenerators(E element) { - element.setGeneratorElement(generatorElement); - element.setGeneratorAnnotationMirror(generatorAnnotationMirror); - return element; - } - -} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionContextImpl.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionContextImpl.java Fri Jun 21 17:52:08 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.codegen.processor.ext; - -import java.util.*; - -import javax.annotation.processing.*; - -import com.oracle.truffle.codegen.processor.api.*; -import com.oracle.truffle.codegen.processor.api.element.*; - -public class ExtensionContextImpl implements ExtensionContext { - - private final ProcessingEnvironment env; - private final RoundEnvironment round; - private final WritableElementFactory factory; - - private final List elements = new ArrayList<>(); - - public ExtensionContextImpl(ProcessingEnvironment env, RoundEnvironment round, WritableElementFactory factory) { - this.env = env; - this.round = round; - this.factory = factory; - } - - List returnElements() { - List returnElements = new ArrayList<>(this.elements); - this.elements.clear(); - return returnElements; - } - - @Override - public ProcessingEnvironment getProcessingEnvironment() { - return env; - } - - @Override - public RoundEnvironment getRoundEnvironment() { - return round; - } - - @Override - public WritableElementFactory getElementFactory() { - return factory; - } - - @Override - public void addGeneratedElement(WritableElement element) { - elements.add(element); - } - - @Override - public void removeGeneratedElement(WritableElement element) { - elements.remove(element); - } - -} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java Fri Jun 21 17:52:08 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.codegen.processor.ext; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.util.*; - -import com.oracle.truffle.api.codegen.*; -import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.api.*; -import com.oracle.truffle.codegen.processor.api.element.*; -import com.oracle.truffle.codegen.processor.template.*; - -public class ExtensionParser { - - private final Map extensions = new HashMap<>(); - private final ProcessorContext context; - private final ExtensionCodeElementFactory factory; - private final ExtensionContextImpl extensionContext; - - public ExtensionParser(ProcessorContext context) { - this.context = context; - this.factory = new ExtensionCodeElementFactory(context); - this.extensionContext = new ExtensionContextImpl(context.getEnvironment(), null, factory); - } - - public List parseAll(Template template, List elements) { - List generatedMethods = new ArrayList<>(); - parseElement(template, generatedMethods, template.getTemplateType()); - - List methods = ElementFilter.methodsIn(elements); - for (ExecutableElement method : methods) { - for (VariableElement var : method.getParameters()) { - parseElement(template, generatedMethods, var); - } - parseElement(template, generatedMethods, method); - } - - return generatedMethods; - } - - private void parseElement(Template template, List elements, Element element) { - List mirrors = element.getAnnotationMirrors(); - for (AnnotationMirror mirror : mirrors) { - ExtensionProcessor processor = findProcessor(template, mirror); - if (processor != null) { - try { - factory.generatorAnnotationMirror = mirror; - factory.generatorElement = element; - processor.process(extensionContext, mirror, element); - elements.addAll(extensionContext.returnElements()); - } catch (Throwable e) { - template.addError("Processor for '%s' failed with exception: \n\n%s.", Utils.getQualifiedName(mirror.getAnnotationType()), Utils.printException(e)); - } finally { - factory.generatorAnnotationMirror = null; - factory.generatorElement = null; - } - } - } - } - - private ExtensionProcessor findProcessor(Template template, AnnotationMirror mirror) { - String processorName = Utils.getQualifiedName(mirror.getAnnotationType()); - ExtensionProcessor processor = null; - if (extensions.containsKey(processorName)) { - processor = extensions.get(processorName); - } else { - AnnotationMirror foundExtension = Utils.findAnnotationMirror(context.getEnvironment(), mirror.getAnnotationType().asElement(), ExtensionAnnotation.class); - if (foundExtension != null) { - String className = Utils.getAnnotationValue(String.class, foundExtension, "processorClassName"); - Class processorClass; - try { - processorClass = Class.forName(className); - } catch (ClassNotFoundException e) { - template.addError("Could not find processor class '%s' configured in '@%s'.", className, processorName); - return null; - } - try { - processor = (ExtensionProcessor) processorClass.newInstance(); - } catch (InstantiationException e) { - template.addError("Could not instantiate processor class '%s' configured in '@%s'.", className, processorName); - return null; - } catch (IllegalAccessException e) { - template.addError("Could not access processor class '%s' configured in '@%s'.", className, processorName); - return null; - } catch (ClassCastException e) { - template.addError("Processor class '%s' configured in '@%s' does not implement '%s'.", className, processorName, ExtensionProcessor.class.getName()); - return null; - } - } - extensions.put(processorName, processor); - } - return processor; - } - -} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/CreateCastData.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/CreateCastData.java Fri Jun 21 17:52:19 2013 +0200 @@ -0,0 +1,42 @@ +/* + * 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 com.oracle.truffle.codegen.processor.template.*; + +public class CreateCastData extends TemplateMethod { + + private final List childNames; + + public CreateCastData(TemplateMethod method, List childNames) { + super(method); + this.childNames = childNames; + } + + public List getChildNames() { + return childNames; + } + +} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/CreateCastParser.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/CreateCastParser.java Fri Jun 21 17:52:19 2013 +0200 @@ -0,0 +1,113 @@ +/* + * 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.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.*; + +public class CreateCastParser extends NodeMethodParser { + + public CreateCastParser(ProcessorContext context, NodeData operation) { + super(context, operation); + } + + @Override + public Class getAnnotationType() { + return CreateCast.class; + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + List childNames = Utils.getAnnotationValueList(String.class, mirror, "value"); + TypeMirror baseType = getContext().getTruffleTypes().getNode(); + for (String childName : childNames) { + NodeChildData child = getNode().findChild(childName); + if (child != null) { + baseType = child.getOriginalType(); + break; + } + } + MethodSpec spec = new MethodSpec(new InheritsParameterSpec(getContext(), "child", baseType)); + addDefaultFieldMethodSpec(method, spec); + spec.addRequired(new ParameterSpec("castedChild", baseType)).setSignature(true); + return spec; + } + + @Override + public CreateCastData create(TemplateMethod method) { + AnnotationMirror mirror = method.getMarkerAnnotation(); + List childNames = Utils.getAnnotationValueList(String.class, mirror, "value"); + CreateCastData cast = new CreateCastData(method, childNames); + AnnotationValue value = Utils.getAnnotationValue(mirror, "value"); + TypeMirror type = null; + if (childNames == null || childNames.isEmpty()) { + cast.addError(value, "No value specified but required."); + return cast; + } + + for (String childName : childNames) { + NodeChildData child = getNode().findChild(childName); + if (child == null) { + // error + cast.addError(value, "Specified child '%s' not found.", childName); + continue; + } + if (type == null) { + type = child.getNodeType(); + } else if (!Utils.typeEquals(type, child.getNodeType())) { + cast.addError(value, "All child nodes for a cast must have the same node type."); + continue; + } + } + return cast; + } + + private static class InheritsParameterSpec extends ParameterSpec { + + private final ProcessorContext context; + + public InheritsParameterSpec(ProcessorContext context, String name, TypeMirror... allowedTypes) { + super(name, Arrays.asList(allowedTypes)); + this.context = context; + } + + @Override + public boolean matches(TypeMirror actualType) { + boolean found = false; + for (TypeMirror specType : getAllowedTypes()) { + if (Utils.isAssignable(context, actualType, specType)) { + found = true; + break; + } + } + return found; + } + } +} diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java Fri Jun 21 17:52:19 2013 +0200 @@ -54,6 +54,7 @@ private final String name; private final TypeMirror type; + private final TypeMirror originalType; private final Element accessElement; private final Cardinality cardinality; @@ -63,11 +64,13 @@ private NodeData nodeData; - public NodeChildData(Element sourceElement, AnnotationMirror sourceMirror, String name, TypeMirror nodeType, Element accessElement, Cardinality cardinality, ExecutionKind executionKind) { + public NodeChildData(Element sourceElement, AnnotationMirror sourceMirror, String name, TypeMirror nodeType, TypeMirror originalNodeType, Element accessElement, Cardinality cardinality, + ExecutionKind executionKind) { this.sourceElement = sourceElement; this.sourceAnnotationMirror = sourceMirror; this.name = name; this.type = nodeType; + this.originalType = originalNodeType; this.accessElement = accessElement; this.cardinality = cardinality; this.executionKind = executionKind; @@ -101,6 +104,10 @@ return nodeData.getExecutableTypes(getExecuteWith().size()); } + public TypeMirror getOriginalType() { + return originalType; + } + @Override public Element getMessageElement() { return sourceElement; diff -r 0d40e1cf70db -r 55827d611da7 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 Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Fri Jun 21 17:52:19 2013 +0200 @@ -143,7 +143,8 @@ } } - private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) { + private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName, + String... customSignatureValueNames) { CodeTreeBuilder builder = parent.create(); boolean castedValues = sourceMethod != targetMethod; @@ -199,8 +200,13 @@ } builder.startCall(method.getSimpleName().toString()); + int signatureIndex = 0; + for (ActualParameter targetParameter : targetMethod.getParameters()) { - ActualParameter valueParameter = sourceMethod.findParameter(targetParameter.getLocalName()); + ActualParameter valueParameter = null; + if (sourceMethod != null) { + valueParameter = sourceMethod.findParameter(targetParameter.getLocalName()); + } if (valueParameter == null) { valueParameter = targetParameter; } @@ -215,7 +221,10 @@ valueType = valueParameter.getTypeSystemType(); } - if (targetParameter.getSpecification().isLocal()) { + if (signatureIndex < customSignatureValueNames.length && targetParameter.getSpecification().isSignature()) { + builder.string(customSignatureValueNames[signatureIndex]); + signatureIndex++; + } else if (targetParameter.getSpecification().isLocal()) { builder.startGroup(); if (builder.findMethod().getModifiers().contains(Modifier.STATIC)) { builder.string(THIS_NODE_LOCAL_VAR_NAME).string("."); @@ -522,8 +531,25 @@ return builder.getRoot(); } - private void emitEncounteredSynthetic(CodeTreeBuilder builder) { - builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end(); + private void emitEncounteredSynthetic(CodeTreeBuilder builder, SpecializationData current) { + builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)); + builder.startGroup(); + String sep = null; + for (ActualParameter parameters : current.getParameters()) { + if (parameters.getSpecification().isSignature()) { + if (sep == null) { + builder.doubleQuote("Unsupported values: " + parameters.getLocalName() + " = "); + sep = ", "; + } else { + builder.string(" + "); + builder.doubleQuote(sep + parameters.getLocalName() + " = "); + } + builder.string(" + "); + builder.string(parameters.getLocalName()); + } + } + builder.end(); + builder.end().end(); } private static List findUserConstructors(TypeMirror nodeType) { @@ -669,7 +695,12 @@ } for (VariableElement var : type.getFields()) { - method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString())); + NodeChildData child = getModel().findChild(var.getSimpleName().toString()); + if (child != null) { + method.getParameters().add(new CodeVariableElement(child.getOriginalType(), child.getName())); + } else { + method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString())); + } } if (superConstructor != null) { @@ -682,14 +713,25 @@ for (VariableElement var : type.getFields()) { builder.startStatement(); - String varName = var.getSimpleName().toString(); - builder.string("this.").string(varName); + String fieldName = var.getSimpleName().toString(); + + CodeTree fieldInit = CodeTreeBuilder.singleString(var.getSimpleName().toString()); + builder.string("this.").string(var.getSimpleName().toString()); + + NodeChildData child = getModel().findChild(fieldName); + if (child != null) { + CreateCastData createCast = getModel().findCast(child.getName()); + if (createCast != null) { + fieldInit = createTemplateMethodCall(builder, null, getModel().getGenericSpecialization(), createCast, null, child.getName()); + } + } + if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { - builder.string(" = adoptChild(").string(varName).string(")"); + builder.string(" = adoptChild(").tree(fieldInit).string(")"); } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { - builder.string(" = adoptChildren(").string(varName).string(")"); + builder.string(" = adoptChildren(").tree(fieldInit).string(")"); } else { - builder.string(" = ").string(varName); + builder.string(" = ").tree(fieldInit); } builder.end(); } @@ -832,7 +874,7 @@ unreachableSpecializations.add(specialization); } else { filteredSpecializations.add(specialization); - if (!specialization.isUninitialized() && !specialization.hasRewrite(getContext())) { + if (!specialization.isUninitialized() && specialization.isGenericSpecialization(getContext())) { unreachable = true; } } @@ -877,7 +919,7 @@ } if (specialize && executeCall == null && !current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { - emitEncounteredSynthetic(builder); + emitEncounteredSynthetic(builder, current); } else if (specialize) { if (current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { @@ -890,7 +932,7 @@ } builder.statement("resultIsSet = true"); } else { - emitEncounteredSynthetic(builder); + emitEncounteredSynthetic(builder, current); } builder.end(); } @@ -922,7 +964,7 @@ } } else { if (executeCall == null) { - emitEncounteredSynthetic(builder); + emitEncounteredSynthetic(builder, current); } else { builder.startReturn().tree(executeCall).end(); } @@ -1165,7 +1207,7 @@ CodeTreeBuilder builder = method.createBuilder(); if (!node.needsRewrites(getContext())) { - builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end(); + builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).doubleQuote("No specialized version.").end().end(); } else { builder.startIf(); builder.string("types.length == 1"); @@ -1668,7 +1710,7 @@ returnBuilder.doubleQuote("Uninitialized"); returnBuilder.end(); } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { - emitEncounteredSynthetic(builder); + emitEncounteredSynthetic(builder, specialization); } else if (specialization.isGeneric()) { returnBuilder.startCall("super", EXECUTE_GENERIC_NAME); addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); diff -r 0d40e1cf70db -r 55827d611da7 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 Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Fri Jun 21 17:52:19 2013 +0200 @@ -50,6 +50,7 @@ private Map> executableTypes; private List shortCircuits; private List assumptions; + private List casts; private String shortName; @@ -74,6 +75,14 @@ this.assumptions = splitSource.assumptions; } + public List getCasts() { + return casts; + } + + void setCasts(List casts) { + this.casts = casts; + } + void setShortName(String shortName) { this.shortName = shortName; } @@ -133,6 +142,9 @@ if (fields != null) { containerChildren.addAll(fields); } + if (casts != null) { + containerChildren.addAll(casts); + } return containerChildren; } @@ -230,6 +242,9 @@ methods.addAll(getSpecializationListeners()); methods.addAll(getExecutableTypes()); methods.addAll(getShortCircuits()); + if (getCasts() != null) { + methods.addAll(getCasts()); + } return methods; } @@ -367,6 +382,7 @@ dumpProperty(builder, indent, "executableTypes", getExecutableTypes()); dumpProperty(builder, indent, "specializations", getSpecializations()); dumpProperty(builder, indent, "assumptions", getAssumptions()); + dumpProperty(builder, indent, "casts", getCasts()); dumpProperty(builder, indent, "messages", collectMessages()); if (getDeclaredNodes().size() > 0) { builder.append(String.format("\n%s children = [", indent)); @@ -489,4 +505,15 @@ return getClass().getSimpleName() + "[" + getNodeId() + "]"; } + public CreateCastData findCast(String name) { + if (getCasts() != null) { + for (CreateCastData cast : getCasts()) { + if (cast.getChildNames().contains(name)) { + return cast; + } + } + } + return null; + } + } diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java Fri Jun 21 17:52:19 2013 +0200 @@ -78,20 +78,15 @@ protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, boolean shortCircuitsEnabled, String shortCircuitName) { MethodSpec methodSpec = new MethodSpec(createReturnParameterSpec()); - if (getNode().supportsFrame()) { - methodSpec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame())); - } - - resolveAndAddImplicitThis(methodSpec, method); + addDefaultFrame(methodSpec); + addDefaultImplicitThis(method, methodSpec); + addDefaultFieldMethodSpec(method, methodSpec); + addDefaultChildren(shortCircuitsEnabled, shortCircuitName, methodSpec); - for (NodeFieldData field : getNode().getFields()) { - if (!Utils.isFieldAccessible(method, field.getVariable())) { - ParameterSpec spec = new ParameterSpec(field.getName(), field.getType()); - spec.setLocal(true); - methodSpec.addOptional(spec); - } - } + return methodSpec; + } + private void addDefaultChildren(boolean shortCircuitsEnabled, String shortCircuitName, MethodSpec methodSpec) { // children are null when parsing executable types if (getNode().getChildren() != null) { for (NodeChildData child : getNode().getChildren()) { @@ -117,11 +112,25 @@ } } } + } - return methodSpec; + private void addDefaultFrame(MethodSpec methodSpec) { + if (getNode().supportsFrame()) { + methodSpec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame())); + } } - protected void resolveAndAddImplicitThis(MethodSpec methodSpec, ExecutableElement method) { + protected void addDefaultFieldMethodSpec(ExecutableElement method, MethodSpec methodSpec) { + for (NodeFieldData field : getNode().getFields()) { + if (!Utils.isFieldAccessible(method, field.getVariable())) { + ParameterSpec spec = new ParameterSpec(field.getName(), field.getType()); + spec.setLocal(true); + methodSpec.addOptional(spec); + } + } + } + + protected void addDefaultImplicitThis(ExecutableElement method, MethodSpec methodSpec) { TypeMirror declaredType = Utils.findNearestEnclosingType(method).asType(); if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(getContext(), declaredType, getContext().getTruffleTypes().getNode())) { diff -r 0d40e1cf70db -r 55827d611da7 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 Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Fri Jun 21 17:52:19 2013 +0200 @@ -42,7 +42,7 @@ public class NodeParser extends TemplateParser { public static final List> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class, - ExecuteChildren.class, NodeClass.class, NodeChild.class, NodeChildren.class, NodeId.class); + NodeClass.class, NodeChild.class, NodeChildren.class, NodeId.class); private Map parsedNodes; @@ -211,6 +211,7 @@ private static List splitNodeData(NodeData node) { SortedMap> groupedSpecializations = groupByNodeId(node.getSpecializations()); SortedMap> groupedListeners = groupByNodeId(node.getSpecializationListeners()); + SortedMap> groupedCasts = groupByNodeId(node.getCasts()); Set ids = new TreeSet<>(); ids.addAll(groupedSpecializations.keySet()); @@ -220,6 +221,7 @@ for (String id : ids) { List specializations = groupedSpecializations.get(id); List listeners = groupedListeners.get(id); + List casts = groupedCasts.get(id); if (specializations == null) { specializations = new ArrayList<>(); @@ -238,12 +240,14 @@ copy.setSpecializations(specializations); copy.setSpecializationListeners(listeners); + copy.setCasts(casts); splitted.add(copy); } node.setSpecializations(new ArrayList()); node.setSpecializationListeners(new ArrayList()); + node.setCasts(new ArrayList()); return splitted; } @@ -266,6 +270,7 @@ node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements)); List generics = new GenericParser(context, node).parse(elements); List specializations = new SpecializationMethodParser(context, node).parse(elements); + node.setCasts(new CreateCastParser(context, node).parse(elements)); List allSpecializations = new ArrayList<>(); allSpecializations.addAll(generics); @@ -736,6 +741,18 @@ shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); } } + Map castNodeTypes = new HashMap<>(); + for (ExecutableElement method : ElementFilter.methodsIn(elements)) { + AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, CreateCast.class); + if (mirror != null) { + List children = (Utils.getAnnotationValueList(String.class, mirror, "value")); + if (children != null) { + for (String child : children) { + castNodeTypes.put(child, method.getReturnType()); + } + } + } + } List parsedChildren = new ArrayList<>(); List typeHierarchyReversed = new ArrayList<>(typeHierarchy); @@ -754,8 +771,12 @@ } List children = Utils.collectAnnotations(context, nodeChildrenMirror, "value", type, NodeChild.class); + int index = 0; for (AnnotationMirror childMirror : children) { String name = Utils.getAnnotationValue(String.class, childMirror, "value"); + if (name.equals("")) { + name = "child" + index; + } Cardinality cardinality = Cardinality.ONE; @@ -764,6 +785,12 @@ cardinality = Cardinality.MANY; } + TypeMirror originalChildType = childType; + TypeMirror castNodeType = castNodeTypes.get(name); + if (castNodeType != null) { + childType = castNodeType; + } + Element getter = findGetter(elements, name, childType); ExecutionKind kind = ExecutionKind.DEFAULT; @@ -771,7 +798,7 @@ kind = ExecutionKind.SHORT_CIRCUIT; } - NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, getter, cardinality, kind); + NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, originalChildType, getter, cardinality, kind); parsedChildren.add(nodeChild); @@ -785,7 +812,9 @@ if (fieldNodeData == null) { nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(childType)); } + } + index++; } List filteredChildren = new ArrayList<>(); @@ -877,7 +906,7 @@ } for (ExecutableElement method : ElementFilter.methodsIn(elements)) { - if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && Utils.typeEquals(method.getReturnType(), type)) { + if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && Utils.isAssignable(context, type, method.getReturnType())) { return method; } } diff -r 0d40e1cf70db -r 55827d611da7 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 Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Fri Jun 21 17:52:19 2013 +0200 @@ -74,6 +74,24 @@ return sinks; } + public boolean isGenericSpecialization(ProcessorContext context) { + if (hasRewrite(context)) { + return false; + } + + for (ActualParameter parameter : getParameters()) { + NodeChildData child = getNode().findChild(parameter.getSpecification().getName()); + if (child == null) { + continue; + } + if (!parameter.getTypeSystemType().isGeneric()) { + return false; + } + } + + return true; + } + public boolean hasRewrite(ProcessorContext context) { if (!getExceptions().isEmpty()) { return true; diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java Fri Jun 21 17:52:19 2013 +0200 @@ -28,19 +28,11 @@ import javax.lang.model.util.*; import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.ext.*; public abstract class TemplateParser extends AbstractParser { - private final ExtensionParser extensionParser; - public TemplateParser(ProcessorContext c) { super(c); - extensionParser = new ExtensionParser(c); - } - - public ExtensionParser getExtensionParser() { - return extensionParser; } protected void verifyExclusiveMethodAnnotation(Template template, Class... annotationTypes) { diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java Fri Jun 21 17:52:19 2013 +0200 @@ -103,8 +103,6 @@ } } - clazz.getEnclosedElements().addAll(typeSystem.getExtensionElements()); - return clazz; } diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java Fri Jun 21 17:52:19 2013 +0200 @@ -84,10 +84,6 @@ verifyExclusiveMethodAnnotation(typeSystem, TypeCast.class, TypeCheck.class); List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(templateType)); - typeSystem.setExtensionElements(getExtensionParser().parseAll(typeSystem, elements)); - if (typeSystem.getExtensionElements() != null) { - elements.addAll(typeSystem.getExtensionElements()); - } List casts = new TypeCastParser(context, typeSystem).parse(elements); List checks = new TypeCheckParser(context, typeSystem).parse(elements); diff -r 0d40e1cf70db -r 55827d611da7 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/PrintNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/PrintNode.java Fri Jun 21 17:52:08 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/PrintNode.java Fri Jun 21 17:52:19 2013 +0200 @@ -26,7 +26,7 @@ import com.oracle.truffle.api.codegen.*; -@NodeChild(value = "expression", type = TypedNode.class) +@NodeChild(type = TypedNode.class) public abstract class PrintNode extends StatementNode { private final PrintStream output; diff -r 0d40e1cf70db -r 55827d611da7 mx/commands.py --- a/mx/commands.py Fri Jun 21 17:52:08 2013 +0200 +++ b/mx/commands.py Fri Jun 21 17:52:19 2013 +0200 @@ -54,6 +54,8 @@ _jacoco = 'off' +_workdir = None + _native_dbg = None _make_eclipse_launch = False @@ -645,6 +647,11 @@ if vm is None: vm = _vm + if cwd is None: + cwd = _workdir + elif _workdir is not None: + mx.abort("conflicting working directories: do not set --workdir for this command") + build = vmbuild if vmbuild is not None else _vmbuild if _vmSourcesAvailable else 'product' jdk = _jdk(build, vmToCheck=vm) mx.expand_project_in_args(args) @@ -1267,7 +1274,6 @@ '--dot-output-base', 'projects'] + args) def mx_init(): - _vmbuild = 'product' commands = { 'build': [build, '[-options]'], 'buildvars': [buildvars, ''], @@ -1298,6 +1304,7 @@ } mx.add_argument('--jacoco', help='instruments com.oracle.* classes using JaCoCo', default='off', choices=['off', 'on', 'append']) + mx.add_argument('--workdir', help='runs the VM in the given directory', default=None) if (_vmSourcesAvailable): mx.add_argument('--vm', action='store', dest='vm', default='graal', choices=_vmChoices, help='the VM to build/run (default: ' + _vmChoices[0] + ')') @@ -1330,6 +1337,8 @@ _make_eclipse_launch = getattr(opts, 'make_eclipse_launch', False) global _jacoco _jacoco = opts.jacoco + global _workdir + _workdir = opts.workdir global _native_dbg _native_dbg = opts.native_dbg diff -r 0d40e1cf70db -r 55827d611da7 mx/projects --- a/mx/projects Fri Jun 21 17:52:08 2013 +0200 +++ b/mx/projects Fri Jun 21 17:52:19 2013 +0200 @@ -141,7 +141,7 @@ # graal.hotspot.test project@com.oracle.graal.hotspot.test@subDir=graal project@com.oracle.graal.hotspot.test@sourceDirs=src -project@com.oracle.graal.hotspot.test@dependencies=com.oracle.graal.replacements.test +project@com.oracle.graal.hotspot.test@dependencies=com.oracle.graal.replacements.test,com.oracle.graal.hotspot project@com.oracle.graal.hotspot.test@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot.test@javaCompliance=1.7 project@com.oracle.graal.hotspot.test@workingSets=Graal,HotSpot,Test @@ -260,7 +260,7 @@ # graal.replacements.test project@com.oracle.graal.replacements.test@subDir=graal project@com.oracle.graal.replacements.test@sourceDirs=src -project@com.oracle.graal.replacements.test@dependencies=com.oracle.graal.compiler.test +project@com.oracle.graal.replacements.test@dependencies=com.oracle.graal.compiler.test,com.oracle.graal.replacements project@com.oracle.graal.replacements.test@checkstyle=com.oracle.graal.graph project@com.oracle.graal.replacements.test@javaCompliance=1.7 project@com.oracle.graal.replacements.test@workingSets=Graal,Replacements,Test @@ -404,7 +404,7 @@ # graal.compiler.test project@com.oracle.graal.compiler.test@subDir=graal project@com.oracle.graal.compiler.test@sourceDirs=src -project@com.oracle.graal.compiler.test@dependencies=com.oracle.graal.test,com.oracle.graal.hotspot +project@com.oracle.graal.compiler.test@dependencies=com.oracle.graal.test,com.oracle.graal.printer project@com.oracle.graal.compiler.test@checkstyle=com.oracle.graal.graph project@com.oracle.graal.compiler.test@javaCompliance=1.7 project@com.oracle.graal.compiler.test@workingSets=Graal,Test diff -r 0d40e1cf70db -r 55827d611da7 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Fri Jun 21 17:52:08 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Fri Jun 21 17:52:19 2013 +0200 @@ -871,6 +871,8 @@ set_int("g1SATBQueueMarkingOffset", in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active())); set_int("g1SATBQueueIndexOffset", in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_index())); set_int("g1SATBQueueBufferOffset", in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_buf())); + set_address("writeBarrierPreAddress", GraalRuntime::write_barrier_pre); + set_address("writeBarrierPostAddress", GraalRuntime::write_barrier_post); BarrierSet* bs = Universe::heap()->barrier_set(); switch (bs->kind()) { diff -r 0d40e1cf70db -r 55827d611da7 src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Fri Jun 21 17:52:08 2013 +0200 +++ b/src/share/vm/graal/graalRuntime.cpp Fri Jun 21 17:52:19 2013 +0200 @@ -358,6 +358,14 @@ } JRT_END +JRT_LEAF(void, GraalRuntime::write_barrier_pre(JavaThread* thread, oopDesc* obj)) + thread->satb_mark_queue().enqueue(obj); +JRT_END + +JRT_LEAF(void, GraalRuntime::write_barrier_post(JavaThread* thread, void* card_addr)) + thread->dirty_card_queue().enqueue(card_addr); +JRT_END + JRT_ENTRY(void, GraalRuntime::vm_error(JavaThread* thread, oop where, oop format, jlong value)) ResourceMark rm; assert(where == NULL || java_lang_String::is_instance(where), "must be"); diff -r 0d40e1cf70db -r 55827d611da7 src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Fri Jun 21 17:52:08 2013 +0200 +++ b/src/share/vm/graal/graalRuntime.hpp Fri Jun 21 17:52:19 2013 +0200 @@ -52,6 +52,8 @@ LOG_OBJECT_ADDRESS = 0x04 }; static void log_object(JavaThread* thread, oop msg, jint flags); + static void write_barrier_pre(JavaThread* thread, oopDesc* obj); + static void write_barrier_post(JavaThread* thread, void* card); }; #endif // SHARE_VM_GRAAL_GRAAL_RUNTIME_HPP