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;
     }
 }