1 /*
2  * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 
25 package org.graalvm.compiler.hotspot.phases;
26 
27 import org.graalvm.compiler.debug.DebugCloseable;
28 import org.graalvm.compiler.debug.GraalError;
29 import org.graalvm.compiler.graph.Node;
30 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
31 import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier;
32 import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier;
33 import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
34 import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier;
35 import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier;
36 import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier;
37 import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
38 import org.graalvm.compiler.nodes.StructuredGraph;
39 import org.graalvm.compiler.nodes.ValueNode;
40 import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
41 import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
42 import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
43 import org.graalvm.compiler.nodes.memory.FixedAccessNode;
44 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
45 import org.graalvm.compiler.nodes.memory.ReadNode;
46 import org.graalvm.compiler.nodes.memory.WriteNode;
47 import org.graalvm.compiler.nodes.memory.address.AddressNode;
48 import org.graalvm.compiler.nodes.type.StampTool;
49 import org.graalvm.compiler.phases.Phase;
50 
51 public class WriteBarrierAdditionPhase extends Phase {
52 
53     private GraalHotSpotVMConfig config;
54 
WriteBarrierAdditionPhase(GraalHotSpotVMConfig config)55     public WriteBarrierAdditionPhase(GraalHotSpotVMConfig config) {
56         this.config = config;
57     }
58 
59     @SuppressWarnings("try")
60     @Override
run(StructuredGraph graph)61     protected void run(StructuredGraph graph) {
62         for (Node n : graph.getNodes()) {
63             try (DebugCloseable scope = n.graph().withNodeSourcePosition(n)) {
64                 if (n instanceof ReadNode) {
65                     addReadNodeBarriers((ReadNode) n, graph);
66                 } else if (n instanceof WriteNode) {
67                     addWriteNodeBarriers((WriteNode) n, graph);
68                 } else if (n instanceof LoweredAtomicReadAndWriteNode) {
69                     LoweredAtomicReadAndWriteNode loweredAtomicReadAndWriteNode = (LoweredAtomicReadAndWriteNode) n;
70                     addAtomicReadWriteNodeBarriers(loweredAtomicReadAndWriteNode, graph);
71                 } else if (n instanceof AbstractCompareAndSwapNode) {
72                     addCASBarriers((AbstractCompareAndSwapNode) n, graph);
73                 } else if (n instanceof ArrayRangeWrite) {
74                     ArrayRangeWrite node = (ArrayRangeWrite) n;
75                     if (node.writesObjectArray()) {
76                         addArrayRangeBarriers(node, graph);
77                     }
78                 }
79             }
80         }
81     }
82 
addReadNodeBarriers(ReadNode node, StructuredGraph graph)83     private void addReadNodeBarriers(ReadNode node, StructuredGraph graph) {
84         if (node.getBarrierType() == BarrierType.PRECISE) {
85             assert config.useG1GC;
86             G1ReferentFieldReadBarrier barrier = graph.add(new G1ReferentFieldReadBarrier(node.getAddress(), node, false));
87             graph.addAfterFixed(node, barrier);
88         } else {
89             assert node.getBarrierType() == BarrierType.NONE : "Non precise read barrier has been attached to read node.";
90         }
91     }
92 
addG1PreWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean doLoad, boolean nullCheck, StructuredGraph graph)93     protected static void addG1PreWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean doLoad, boolean nullCheck, StructuredGraph graph) {
94         G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(address, value, doLoad, nullCheck));
95         preBarrier.setStateBefore(node.stateBefore());
96         node.setNullCheck(false);
97         node.setStateBefore(null);
98         graph.addBeforeFixed(node, preBarrier);
99     }
100 
addG1PostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph)101     protected void addG1PostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) {
102         final boolean alwaysNull = StampTool.isPointerAlwaysNull(value);
103         graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(address, value, precise, alwaysNull)));
104     }
105 
addSerialPostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph)106     protected void addSerialPostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) {
107         final boolean alwaysNull = StampTool.isPointerAlwaysNull(value);
108         if (alwaysNull) {
109             // Serial barrier isn't needed for null value
110             return;
111         }
112         graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(address, precise)));
113     }
114 
addWriteNodeBarriers(WriteNode node, StructuredGraph graph)115     private void addWriteNodeBarriers(WriteNode node, StructuredGraph graph) {
116         BarrierType barrierType = node.getBarrierType();
117         switch (barrierType) {
118             case NONE:
119                 // nothing to do
120                 break;
121             case IMPRECISE:
122             case PRECISE:
123                 boolean precise = barrierType == BarrierType.PRECISE;
124                 if (config.useG1GC) {
125                     if (!node.getLocationIdentity().isInit()) {
126                         // The pre barrier does nothing if the value being read is null, so it can
127                         // be explicitly skipped when this is an initializing store.
128                         addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph);
129                     }
130                     addG1PostWriteBarrier(node, node.getAddress(), node.value(), precise, graph);
131                 } else {
132                     addSerialPostWriteBarrier(node, node.getAddress(), node.value(), precise, graph);
133                 }
134                 break;
135             default:
136                 throw new GraalError("unexpected barrier type: " + barrierType);
137         }
138     }
139 
addAtomicReadWriteNodeBarriers(LoweredAtomicReadAndWriteNode node, StructuredGraph graph)140     private void addAtomicReadWriteNodeBarriers(LoweredAtomicReadAndWriteNode node, StructuredGraph graph) {
141         BarrierType barrierType = node.getBarrierType();
142         switch (barrierType) {
143             case NONE:
144                 // nothing to do
145                 break;
146             case IMPRECISE:
147             case PRECISE:
148                 boolean precise = barrierType == BarrierType.PRECISE;
149                 if (config.useG1GC) {
150                     addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph);
151                     addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
152                 } else {
153                     addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
154                 }
155                 break;
156             default:
157                 throw new GraalError("unexpected barrier type: " + barrierType);
158         }
159     }
160 
addCASBarriers(AbstractCompareAndSwapNode node, StructuredGraph graph)161     private void addCASBarriers(AbstractCompareAndSwapNode node, StructuredGraph graph) {
162         BarrierType barrierType = node.getBarrierType();
163         switch (barrierType) {
164             case NONE:
165                 // nothing to do
166                 break;
167             case IMPRECISE:
168             case PRECISE:
169                 boolean precise = barrierType == BarrierType.PRECISE;
170                 if (config.useG1GC) {
171                     addG1PreWriteBarrier(node, node.getAddress(), node.getExpectedValue(), false, false, graph);
172                     addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
173                 } else {
174                     addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
175                 }
176                 break;
177             default:
178                 throw new GraalError("unexpected barrier type: " + barrierType);
179         }
180     }
181 
addArrayRangeBarriers(ArrayRangeWrite write, StructuredGraph graph)182     private void addArrayRangeBarriers(ArrayRangeWrite write, StructuredGraph graph) {
183         if (config.useG1GC) {
184             if (!write.isInitialization()) {
185                 // The pre barrier does nothing if the value being read is null, so it can
186                 // be explicitly skipped when this is an initializing store.
187                 G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
188                 graph.addBeforeFixed(write.asNode(), g1ArrayRangePreWriteBarrier);
189             }
190             G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
191             graph.addAfterFixed(write.asNode(), g1ArrayRangePostWriteBarrier);
192         } else {
193             SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
194             graph.addAfterFixed(write.asNode(), serialArrayRangeWriteBarrier);
195         }
196     }
197 
198     @Override
checkContract()199     public boolean checkContract() {
200         return false;
201     }
202 }
203