changeset 9394:31dc304507e9

New write barrier verification phase
author Christos Kotselidis <christos.kotselidis@oracle.com>
date Wed, 24 Apr 2013 21:10:20 +0200
parents 159ac409c27a
children b11c3539a1e9
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java
diffstat 1 files changed, 69 insertions(+), 164 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Wed Apr 24 18:53:06 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Wed Apr 24 21:10:20 2013 +0200
@@ -31,193 +31,98 @@
 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.*;
 
 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;
-            }
-
-            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);
-                            }
-                        }
-                    }
-                }
-            }
-            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) {
+        processSafepoints(graph);
     }
 
-    @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 processSafepoints(StructuredGraph graph) {
+        for (Node node : graph.getNodes()) {
+            if (isSafepoint(node)) {
+                verifyWrites(node);
             }
         }
     }
 
-    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 void verifyWrites(Node safepoint) {
+        Deque<Node> frontier = new ArrayDeque<>();
+        List<Node> processedWrites = new LinkedList<>();
+        expandFrontier(frontier, safepoint);
+        while (!frontier.isEmpty()) {
+            Node currentNode = frontier.removeFirst();
+            if (isSafepoint(currentNode)) {
+                continue;
             }
+            if (isObjectWrite(currentNode) && !processedWrites.contains(currentNode)) {
+                validateWrite(currentNode);
+                processedWrites.add(currentNode);
+            }
+            expandFrontier(frontier, currentNode);
         }
+
     }
 
-    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 void validateWrite(Node write) {
+        if (hasCorrectAttachedBarrier(write)) {
+            return;
+        }
+        Deque<Node> frontier = new ArrayDeque<>();
+        expandFrontier(frontier, write);
+        while (!frontier.isEmpty()) {
+            Node currentNode = frontier.removeFirst();
+            assert !isSafepoint(currentNode) : "Write barrier must be present";
+            if (!(currentNode instanceof SerialWriteBarrier) || ((currentNode instanceof SerialWriteBarrier) && !foundCorrectBarrier(write, currentNode))) {
+                expandFrontier(frontier, currentNode);
             }
         }
     }
 
-    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;
+    private static boolean hasCorrectAttachedBarrier(Node node) {
+        return (((FixedWithNextNode) node).next() instanceof SerialWriteBarrier) && foundCorrectBarrier(node, ((FixedWithNextNode) node).next());
+    }
+
+    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(Deque<Node> frontier, Node node) {
+        for (Node previousNode : node.cfgPredecessors()) {
+            if (previousNode != null) {
+                if (previousNode instanceof ControlSplitNode && frontier.contains(previousNode)) {
+                    continue;
                 }
-            }
-            if (!found) {
-                writeBarriers.add(currentBarrier);
+                frontier.addFirst(previousNode);
             }
         }
     }
 
-    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 isSafepoint(Node node) {
+        return (node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize();
     }
 
-    private static void processSafepoint(MemoryMap state) {
-        state.lastMemorySnapshot.clear();
-        state.lastWriteBarrierSnapshot.clear();
+    private static boolean foundCorrectBarrier(Node write, Node barrier) {
+        SerialWriteBarrier barrierNode = (SerialWriteBarrier) barrier;
+        if (write instanceof WriteNode) {
+            WriteNode writeNode = (WriteNode) write;
+            if ((barrierNode.getObject() == writeNode.object()) && (!barrierNode.usePrecise() || (barrierNode.usePrecise() && barrierNode.getLocation() == writeNode.location()))) {
+                return true;
+            }
+            return false;
+        } else if (write instanceof CompareAndSwapNode) {
+            CompareAndSwapNode casNode = (CompareAndSwapNode) write;
+            if ((barrierNode.getObject() == casNode.object()) && (!barrierNode.usePrecise() || (barrierNode.usePrecise() && barrierNode.getLocation() == casNode.getLocation()))) {
+                return true;
+            }
+            return false;
+        }
+        assert false : "Node must be of type requiring a write barrier";
+        return false;
     }
 }