# HG changeset patch # User Christos Kotselidis # Date 1366243518 -7200 # Node ID 642e04f1ea93fd04f652811d2cc4bdc2978dd399 # Parent 34eba4e78a0a81a22555d50c529bd7d3436004cd Add write barrier verification phase diff -r 34eba4e78a0a -r 642e04f1ea93 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu Apr 18 01:23:58 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu Apr 18 02:05:18 2013 +0200 @@ -740,6 +740,10 @@ phasePlan.addPhase(PhasePosition.AFTER_PARSING, new OnStackReplacementPhase()); } phasePlan.addPhase(PhasePosition.LOW_LEVEL, new WriteBarrierAdditionPhase()); + if (GraalOptions.VerifyPhases) { + phasePlan.addPhase(PhasePosition.LOW_LEVEL, new WriteBarrierVerificationPhase()); + + } return phasePlan; } diff -r 34eba4e78a0a -r 642e04f1ea93 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java Thu Apr 18 02:05:18 2013 +0200 @@ -0,0 +1,223 @@ +/* + * 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.phases; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +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 { + + private IdentityHashMap> lastMemorySnapshot; + private IdentityHashMap> 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 withStates) { + if (withStates.size() == 0) { + return true; + } + + for (MemoryMap other : withStates) { + for (Object otherObject : other.lastMemorySnapshot.keySet()) { + LinkedList currentLocations = lastMemorySnapshot.get(otherObject); + LinkedList 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 currentWriteBarriers = lastWriteBarrierSnapshot.get(otherObject); + LinkedList 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 loopEndStates) { + } + + @Override + public void afterSplit(BeginNode node) { + } + + @Override + public MemoryMap clone() { + return new MemoryMap(this); + } + } + + @Override + protected void run(StructuredGraph graph) { + new PostOrderNodeIterator(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 processWriteNode(WriteNode node, MemoryMap state) { + if (node.getWriteBarrierType() != WriteBarrierType.NONE) { + LinkedList 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 processCASNode(CompareAndSwapNode node, MemoryMap state) { + if (node.getWriteBarrierType() != WriteBarrierType.NONE) { + LinkedList 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 processWriteBarrier(SerialWriteBarrier currentBarrier, MemoryMap state) { + LinkedList 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 void validateWriteBarriers(MemoryMap state) { + Set objects = state.lastMemorySnapshot.keySet(); + for (Object write : objects) { + LinkedList 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 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 void processSafepoint(MemoryMap state) { + state.lastMemorySnapshot.clear(); + state.lastWriteBarrierSnapshot.clear(); + } +}