Mercurial > hg > truffle
changeset 9411:0a94f51ed31b
Merge
author | Christos Kotselidis <christos.kotselidis@oracle.com> |
---|---|
date | Sun, 28 Apr 2013 23:27:33 +0200 |
parents | 3270cbd45e03 (diff) 6a2a9eac243a (current diff) |
children | 0097d456ed57 |
files | |
diffstat | 2 files changed, 773 insertions(+), 166 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierVerificationTest.java Sun Apr 28 23:27:33 2013 +0200 @@ -0,0 +1,706 @@ +/* + * 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 org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.hotspot.phases.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.Lowerable.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.*; +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) { + Debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet), new Runnable() { + + public void run() { + 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()); + + 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); + + class State { + + boolean removeBarrier = false; + + } + + // Iterate over all write nodes and remove barriers according to input indices. + NodeIteratorClosure<State> closure = new NodeIteratorClosure<State>() { + + @Override + protected void processNode(FixedNode node, State currentState) { + if (node instanceof WriteNode) { + WriteNode write = (WriteNode) node; + Object obj = write.getLocationIdentities()[0]; + 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)) { + currentState.removeBarrier = true; + } + } + } + } else if (node instanceof SerialWriteBarrier) { + // Remove flagged write barriers. + if (currentState.removeBarrier) { + graph.removeFixed(((SerialWriteBarrier) node)); + currentState.removeBarrier = false; + } + } + } + + 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<LoopExitNode, State> processLoop(LoopBeginNode loop, State initialState) { + return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates; + } + + @Override + protected State merge(MergeNode merge, List<State> states) { + return new State(); + } + + @Override + protected State afterSplit(BeginNode node, State oldState) { + return new State(); + } + }; + + try { + ReentrantNodeIterator.apply(closure, graph.start(), new State(), null); + 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")); + throw new AssertionError(); + } + + } + }); + } +}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java Sun Apr 28 22:58:54 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java Sun Apr 28 23:27:33 2013 +0200 @@ -31,193 +31,94 @@ import com.oracle.graal.nodes.extended.WriteNode.WriteBarrierType; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; -import com.oracle.graal.phases.graph.*; +/** + * Verification phase that checks if, for every write, at least one write barrier is present at all + * paths leading to the previous safepoint. For every write, necessitating a write barrier, a + * bottom-up traversal of the graph is performed up to the previous safepoints via all possible + * paths. If, for a certain path, no write barrier satisfying the processed write is found, an + * assertion is generated. + */ public class WriteBarrierVerificationPhase extends Phase { - private class MemoryMap implements MergeableState<MemoryMap> { - - private IdentityHashMap<Object, LinkedList<LocationNode>> lastMemorySnapshot; - private IdentityHashMap<Object, LinkedList<SerialWriteBarrier>> lastWriteBarrierSnapshot; - - public MemoryMap(MemoryMap memoryMap) { - lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot); - lastWriteBarrierSnapshot = new IdentityHashMap<>(memoryMap.lastWriteBarrierSnapshot); - } - - public MemoryMap() { - lastMemorySnapshot = new IdentityHashMap<>(); - lastWriteBarrierSnapshot = new IdentityHashMap<>(); - } - - @Override - public String toString() { - return "Map=" + lastMemorySnapshot.toString(); - } - - @Override - public boolean merge(MergeNode merge, List<MemoryMap> withStates) { - if (withStates.size() == 0) { - return true; - } + @Override + protected void run(StructuredGraph graph) { + processWrites(graph); + } - for (MemoryMap other : withStates) { - for (Object otherObject : other.lastMemorySnapshot.keySet()) { - LinkedList<LocationNode> currentLocations = lastMemorySnapshot.get(otherObject); - LinkedList<LocationNode> otherLocations = other.lastMemorySnapshot.get(otherObject); - if (otherLocations != null) { - if (currentLocations == null) { - currentLocations = new LinkedList<>(); - } - for (LocationNode location : otherLocations) { - if (!currentLocations.contains(location)) { - currentLocations.add(location); - } - } - } - } - for (Object otherObject : other.lastWriteBarrierSnapshot.keySet()) { - LinkedList<SerialWriteBarrier> currentWriteBarriers = lastWriteBarrierSnapshot.get(otherObject); - LinkedList<SerialWriteBarrier> otherWriteBarriers = other.lastWriteBarrierSnapshot.get(otherObject); - if (otherWriteBarriers != null) { - if (currentWriteBarriers == null) { - currentWriteBarriers = new LinkedList<>(); - } - for (SerialWriteBarrier barrier : otherWriteBarriers) { - if (!currentWriteBarriers.contains(barrier)) { - currentWriteBarriers.add(barrier); - } - } - } - } + private static void processWrites(StructuredGraph graph) { + for (Node node : graph.getNodes()) { + if (isObjectWrite(node)) { + validateWrite(node); } - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List<MemoryMap> loopEndStates) { - } - - @Override - public void afterSplit(BeginNode node) { - } - - @Override - public MemoryMap clone() { - return new MemoryMap(this); } } - @Override - protected void run(StructuredGraph graph) { - new PostOrderNodeIterator<MemoryMap>(graph.start(), new MemoryMap()) { - - @Override - protected void node(FixedNode node) { - processNode(node, state); - } - }.apply(); - } - - private static void processNode(FixedNode node, MemoryMap state) { - if (node instanceof WriteNode) { - processWriteNode((WriteNode) node, state); - } else if (node instanceof CompareAndSwapNode) { - processCASNode((CompareAndSwapNode) node, state); - } else if (node instanceof SerialWriteBarrier) { - processWriteBarrier((SerialWriteBarrier) node, state); - } else if ((node instanceof DeoptimizingNode)) { - if (((DeoptimizingNode) node).canDeoptimize()) { - validateWriteBarriers(state); - processSafepoint(state); + private static void validateWrite(Node write) { + /* + * The currently validated write is checked in order to discover if it has an appropriate + * attached write barrier. + */ + if (hasAttachedBarrier(write)) { + return; + } + NodeFlood frontier = write.graph().createNodeFlood(); + expandFrontier(frontier, write); + Iterator<Node> iterator = frontier.iterator(); + while (iterator.hasNext()) { + Node currentNode = iterator.next(); + assert !isSafepoint(currentNode) : "Write barrier must be present"; + if (!(currentNode instanceof SerialWriteBarrier) || ((currentNode instanceof SerialWriteBarrier) && !validateBarrier(write, (SerialWriteBarrier) currentNode))) { + expandFrontier(frontier, currentNode); } } } - private static void processWriteNode(WriteNode node, MemoryMap state) { - if (node.getWriteBarrierType() != WriteBarrierType.NONE) { - LinkedList<LocationNode> locations = state.lastMemorySnapshot.get(node.object()); - if (locations == null) { - locations = new LinkedList<>(); - locations.add(node.location()); - state.lastMemorySnapshot.put(node.object(), locations); - } else if ((node.getWriteBarrierType() == WriteBarrierType.PRECISE) && !locations.contains(node.location())) { - locations.add(node.location()); - } - } + private static boolean hasAttachedBarrier(Node node) { + return (((FixedWithNextNode) node).next() instanceof SerialWriteBarrier) && validateBarrier(node, (SerialWriteBarrier) ((FixedWithNextNode) node).next()); } - private static void processCASNode(CompareAndSwapNode node, MemoryMap state) { - if (node.getWriteBarrierType() != WriteBarrierType.NONE) { - LinkedList<LocationNode> locations = state.lastMemorySnapshot.get(node.object()); - if (locations == null) { - locations = new LinkedList<>(); - locations.add(node.getLocation()); - state.lastMemorySnapshot.put(node.object(), locations); - } else if ((node.getWriteBarrierType() == WriteBarrierType.PRECISE) && !locations.contains(node.getLocation())) { - locations.add(node.getLocation()); + private static boolean isObjectWrite(Node node) { + if ((node instanceof WriteNode && (((WriteNode) node).getWriteBarrierType() != WriteBarrierType.NONE)) || + (node instanceof CompareAndSwapNode && (((CompareAndSwapNode) node).getWriteBarrierType() != WriteBarrierType.NONE))) { + return true; + } + return false; + } + + private static void expandFrontier(NodeFlood frontier, Node node) { + for (Node previousNode : node.cfgPredecessors()) { + if (previousNode != null) { + frontier.add(previousNode); } } } - private static void processWriteBarrier(SerialWriteBarrier currentBarrier, MemoryMap state) { - LinkedList<SerialWriteBarrier> writeBarriers = state.lastWriteBarrierSnapshot.get(currentBarrier.getObject()); - if (writeBarriers == null) { - writeBarriers = new LinkedList<>(); - writeBarriers.add(currentBarrier); - state.lastWriteBarrierSnapshot.put(currentBarrier.getObject(), writeBarriers); - } else if (currentBarrier.usePrecise()) { - boolean found = false; - for (SerialWriteBarrier barrier : writeBarriers) { - if (barrier.getLocation() == currentBarrier.getLocation()) { - found = true; - break; - } - } - if (!found) { - writeBarriers.add(currentBarrier); - } - } + private static boolean isSafepoint(Node node) { + /* + * LoopBegin nodes are also treated as safepoints since a bottom-up analysis is performed + * and loop safepoints are placed before LoopEnd nodes. Possible elimination of write + * barriers inside loops, derived from writes outside loops, can not be permitted. + */ + return ((node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize()) || (node instanceof LoopBeginNode); } - private static void validateWriteBarriers(MemoryMap state) { - Set<Object> objects = state.lastMemorySnapshot.keySet(); - for (Object write : objects) { - LinkedList<SerialWriteBarrier> writeBarriers = state.lastWriteBarrierSnapshot.get(write); - if (writeBarriers == null) { - throw new GraalInternalError("Failed to find any write barrier at safepoint for written object"); - } - /* - * Check the first write barrier of the object to determine if it is precise or not. If - * it is not, the validation for this object has passed (since we had a hit in the write - * barrier hashmap), otherwise we have to ensure the presence of write barriers for - * every written location. - */ - final boolean precise = writeBarriers.getFirst().usePrecise(); - if (precise) { - LinkedList<LocationNode> locations = state.lastMemorySnapshot.get(write); - for (LocationNode location : locations) { - boolean found = false; - for (SerialWriteBarrier barrier : writeBarriers) { - if (location == barrier.getLocation()) { - found = true; - break; - } - } - if (!found) { - throw new GraalInternalError("Failed to find write barrier at safepoint for precise written object"); - } - } - } + private static boolean validateBarrier(Node write, SerialWriteBarrier barrier) { + ValueNode writtenObject = null; + LocationNode writtenLocation = null; + if (write instanceof WriteNode) { + writtenObject = ((WriteNode) write).object(); + writtenLocation = ((WriteNode) write).location(); + } else if (write instanceof CompareAndSwapNode) { + writtenObject = ((CompareAndSwapNode) write).object(); + writtenLocation = ((CompareAndSwapNode) write).getLocation(); + } else { + assert false : "Node must be of type requiring a write barrier"; } - } - private static void processSafepoint(MemoryMap state) { - state.lastMemorySnapshot.clear(); - state.lastWriteBarrierSnapshot.clear(); + if ((barrier.getObject() == writtenObject) && (!barrier.usePrecise() || (barrier.usePrecise() && barrier.getLocation() == writtenLocation))) { + return true; + } + return false; } }