# HG changeset patch # User Christos Kotselidis # Date 1371807694 -7200 # Node ID a46c3180faed26025920232a2cd2e4e804479e26 # Parent 34444b095a51731b193937b2f24ea80561b29c31# Parent 6447890af1bf4832457adbffe7301a2a4f6dd333 Merge diff -r 34444b095a51 -r a46c3180faed 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 11:34:17 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 34444b095a51 -r a46c3180faed 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 11:34:17 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 34444b095a51 -r a46c3180faed 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 11:34:17 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java Fri Jun 21 11:41:34 2013 +0200 @@ -37,5 +37,7 @@ appendPhase(new ExpandLogicPhase()); appendPhase(new DeadCodeEliminationPhase()); + + appendPhase(new RemoveValueProxyPhase()); } } diff -r 34444b095a51 -r a46c3180faed 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 11:41:34 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 34444b095a51 -r a46c3180faed 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 11:41:34 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 34444b095a51 -r a46c3180faed 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 11:34:17 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Fri Jun 21 11:41:34 2013 +0200 @@ -328,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 34444b095a51 -r a46c3180faed 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 11:34:17 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Fri Jun 21 11:41:34 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 34444b095a51 -r a46c3180faed 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 11:34:17 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Fri Jun 21 11:41:34 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 34444b095a51 -r a46c3180faed 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 11:41:34 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 34444b095a51 -r a46c3180faed 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 11:41:34 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 34444b095a51 -r a46c3180faed 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 11:34:17 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 34444b095a51 -r a46c3180faed 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 11:41:34 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 34444b095a51 -r a46c3180faed mx/projects --- a/mx/projects Fri Jun 21 11:34:17 2013 +0200 +++ b/mx/projects Fri Jun 21 11:41:34 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