27
28 import java.util.Iterator;
29
30 import org.graalvm.compiler.debug.GraalError;
31 import org.graalvm.compiler.graph.Node;
32 import org.graalvm.compiler.graph.NodeFlood;
33 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
34 import org.graalvm.compiler.hotspot.gc.g1.G1PostWriteBarrier;
35 import org.graalvm.compiler.hotspot.gc.shared.ArrayRangeWriteBarrier;
36 import org.graalvm.compiler.hotspot.gc.shared.ObjectWriteBarrier;
37 import org.graalvm.compiler.hotspot.gc.shared.SerialWriteBarrier;
38 import org.graalvm.compiler.nodeinfo.Verbosity;
39 import org.graalvm.compiler.nodes.DeoptimizingNode;
40 import org.graalvm.compiler.nodes.FixedWithNextNode;
41 import org.graalvm.compiler.nodes.LoopBeginNode;
42 import org.graalvm.compiler.nodes.StructuredGraph;
43 import org.graalvm.compiler.nodes.ValueNode;
44 import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
45 import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
46 import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
47 import org.graalvm.compiler.nodes.memory.FixedAccessNode;
48 import org.graalvm.compiler.nodes.memory.HeapAccess;
49 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
50 import org.graalvm.compiler.nodes.memory.ReadNode;
51 import org.graalvm.compiler.nodes.memory.WriteNode;
52 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
53 import org.graalvm.compiler.nodes.type.StampTool;
54 import org.graalvm.compiler.nodes.util.GraphUtil;
55 import org.graalvm.compiler.phases.Phase;
56
57 /**
58 * Verification phase that checks if, for every write, at least one write barrier is present at all
59 * paths leading to the previous safepoint. For every write, necessitating a write barrier, a
60 * bottom-up traversal of the graph is performed up to the previous safepoints via all possible
61 * paths. If, for a certain path, no write barrier satisfying the processed write is found, an
62 * assertion is generated.
63 */
64 public class WriteBarrierVerificationPhase extends Phase {
65
66 private final GraalHotSpotVMConfig config;
110 }
111 } else {
112 if (!(currentNode instanceof SerialWriteBarrier) || (!validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode)) ||
113 ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode))) {
114 expandFrontier(frontier, currentNode);
115 }
116 }
117 }
118 }
119
120 private boolean useG1GC() {
121 return config.useG1GC;
122 }
123
124 private boolean hasAttachedBarrier(FixedWithNextNode node) {
125 final Node next = node.next();
126 final Node previous = node.predecessor();
127 boolean validatePreBarrier = useG1GC() && (isObjectWrite(node) || !((ArrayRangeWrite) node).isInitialization());
128 if (node instanceof WriteNode) {
129 WriteNode writeNode = (WriteNode) node;
130 if (writeNode.getLocationIdentity().isInit()) {
131 validatePreBarrier = false;
132 }
133 }
134 if (isObjectWrite(node)) {
135 return (isObjectBarrier(node, next) || StampTool.isPointerAlwaysNull(getValueWritten(node))) && (!validatePreBarrier || isObjectBarrier(node, previous));
136 } else if (isObjectArrayRangeWrite(node)) {
137 return (isArrayBarrier(node, next) || StampTool.isPointerAlwaysNull(getValueWritten(node))) && (!validatePreBarrier || isArrayBarrier(node, previous));
138 } else {
139 return true;
140 }
141 }
142
143 private static boolean isObjectBarrier(FixedWithNextNode node, final Node next) {
144 return next instanceof ObjectWriteBarrier && validateBarrier((FixedAccessNode) node, (ObjectWriteBarrier) next);
145 }
146
147 private static boolean isArrayBarrier(FixedWithNextNode node, final Node next) {
148 return (next instanceof ArrayRangeWriteBarrier) && ((ArrayRangeWrite) node).getAddress() == ((ArrayRangeWriteBarrier) next).getAddress();
149 }
174 * LoopBegin nodes are also treated as safepoints since a bottom-up analysis is performed
175 * and loop safepoints are placed before LoopEnd nodes. Possible elimination of write
176 * barriers inside loops, derived from writes outside loops, can not be permitted.
177 */
178 return ((node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize()) || (node instanceof LoopBeginNode);
179 }
180
181 private static ValueNode getValueWritten(FixedWithNextNode write) {
182 if (write instanceof WriteNode) {
183 return ((WriteNode) write).value();
184 } else if (write instanceof LogicCompareAndSwapNode) {
185 return ((LogicCompareAndSwapNode) write).getNewValue();
186 } else if (write instanceof LoweredAtomicReadAndWriteNode) {
187 return ((LoweredAtomicReadAndWriteNode) write).getNewValue();
188 } else {
189 throw GraalError.shouldNotReachHere(String.format("unexpected write node %s", write));
190 }
191 }
192
193 private static boolean validateBarrier(FixedAccessNode write, ObjectWriteBarrier barrier) {
194 assert write instanceof WriteNode || write instanceof LogicCompareAndSwapNode || write instanceof LoweredAtomicReadAndWriteNode : "Node must be of type requiring a write barrier " + write;
195 if (!barrier.usePrecise()) {
196 if (barrier.getAddress() instanceof OffsetAddressNode && write.getAddress() instanceof OffsetAddressNode) {
197 return GraphUtil.unproxify(((OffsetAddressNode) barrier.getAddress()).getBase()) == GraphUtil.unproxify(((OffsetAddressNode) write.getAddress()).getBase());
198 }
199 }
200 return barrier.getAddress() == write.getAddress();
201 }
202 }
|
27
28 import java.util.Iterator;
29
30 import org.graalvm.compiler.debug.GraalError;
31 import org.graalvm.compiler.graph.Node;
32 import org.graalvm.compiler.graph.NodeFlood;
33 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
34 import org.graalvm.compiler.hotspot.gc.g1.G1PostWriteBarrier;
35 import org.graalvm.compiler.hotspot.gc.shared.ArrayRangeWriteBarrier;
36 import org.graalvm.compiler.hotspot.gc.shared.ObjectWriteBarrier;
37 import org.graalvm.compiler.hotspot.gc.shared.SerialWriteBarrier;
38 import org.graalvm.compiler.nodeinfo.Verbosity;
39 import org.graalvm.compiler.nodes.DeoptimizingNode;
40 import org.graalvm.compiler.nodes.FixedWithNextNode;
41 import org.graalvm.compiler.nodes.LoopBeginNode;
42 import org.graalvm.compiler.nodes.StructuredGraph;
43 import org.graalvm.compiler.nodes.ValueNode;
44 import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
45 import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
46 import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
47 import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode;
48 import org.graalvm.compiler.nodes.memory.FixedAccessNode;
49 import org.graalvm.compiler.nodes.memory.HeapAccess;
50 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
51 import org.graalvm.compiler.nodes.memory.ReadNode;
52 import org.graalvm.compiler.nodes.memory.WriteNode;
53 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
54 import org.graalvm.compiler.nodes.type.StampTool;
55 import org.graalvm.compiler.nodes.util.GraphUtil;
56 import org.graalvm.compiler.phases.Phase;
57
58 /**
59 * Verification phase that checks if, for every write, at least one write barrier is present at all
60 * paths leading to the previous safepoint. For every write, necessitating a write barrier, a
61 * bottom-up traversal of the graph is performed up to the previous safepoints via all possible
62 * paths. If, for a certain path, no write barrier satisfying the processed write is found, an
63 * assertion is generated.
64 */
65 public class WriteBarrierVerificationPhase extends Phase {
66
67 private final GraalHotSpotVMConfig config;
111 }
112 } else {
113 if (!(currentNode instanceof SerialWriteBarrier) || (!validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode)) ||
114 ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((FixedAccessNode) write, (ObjectWriteBarrier) currentNode))) {
115 expandFrontier(frontier, currentNode);
116 }
117 }
118 }
119 }
120
121 private boolean useG1GC() {
122 return config.useG1GC;
123 }
124
125 private boolean hasAttachedBarrier(FixedWithNextNode node) {
126 final Node next = node.next();
127 final Node previous = node.predecessor();
128 boolean validatePreBarrier = useG1GC() && (isObjectWrite(node) || !((ArrayRangeWrite) node).isInitialization());
129 if (node instanceof WriteNode) {
130 WriteNode writeNode = (WriteNode) node;
131 if (config.useDeferredInitBarriers && writeNode.getLocationIdentity().isInit()) {
132 return true;
133 }
134 if (writeNode.getLocationIdentity().isInit()) {
135 validatePreBarrier = false;
136 }
137 }
138 if (isObjectWrite(node)) {
139 return (isObjectBarrier(node, next) || StampTool.isPointerAlwaysNull(getValueWritten(node))) && (!validatePreBarrier || isObjectBarrier(node, previous));
140 } else if (isObjectArrayRangeWrite(node)) {
141 return (isArrayBarrier(node, next) || StampTool.isPointerAlwaysNull(getValueWritten(node))) && (!validatePreBarrier || isArrayBarrier(node, previous));
142 } else {
143 return true;
144 }
145 }
146
147 private static boolean isObjectBarrier(FixedWithNextNode node, final Node next) {
148 return next instanceof ObjectWriteBarrier && validateBarrier((FixedAccessNode) node, (ObjectWriteBarrier) next);
149 }
150
151 private static boolean isArrayBarrier(FixedWithNextNode node, final Node next) {
152 return (next instanceof ArrayRangeWriteBarrier) && ((ArrayRangeWrite) node).getAddress() == ((ArrayRangeWriteBarrier) next).getAddress();
153 }
178 * LoopBegin nodes are also treated as safepoints since a bottom-up analysis is performed
179 * and loop safepoints are placed before LoopEnd nodes. Possible elimination of write
180 * barriers inside loops, derived from writes outside loops, can not be permitted.
181 */
182 return ((node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize()) || (node instanceof LoopBeginNode);
183 }
184
185 private static ValueNode getValueWritten(FixedWithNextNode write) {
186 if (write instanceof WriteNode) {
187 return ((WriteNode) write).value();
188 } else if (write instanceof LogicCompareAndSwapNode) {
189 return ((LogicCompareAndSwapNode) write).getNewValue();
190 } else if (write instanceof LoweredAtomicReadAndWriteNode) {
191 return ((LoweredAtomicReadAndWriteNode) write).getNewValue();
192 } else {
193 throw GraalError.shouldNotReachHere(String.format("unexpected write node %s", write));
194 }
195 }
196
197 private static boolean validateBarrier(FixedAccessNode write, ObjectWriteBarrier barrier) {
198 assert write instanceof WriteNode || write instanceof LogicCompareAndSwapNode || write instanceof ValueCompareAndSwapNode ||
199 write instanceof LoweredAtomicReadAndWriteNode : "Node must be of type requiring a write barrier " + write;
200 if (!barrier.usePrecise()) {
201 if (barrier.getAddress() instanceof OffsetAddressNode && write.getAddress() instanceof OffsetAddressNode) {
202 return GraphUtil.unproxify(((OffsetAddressNode) barrier.getAddress()).getBase()) == GraphUtil.unproxify(((OffsetAddressNode) write.getAddress()).getBase());
203 }
204 }
205 return barrier.getAddress() == write.getAddress();
206 }
207 }
|