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 package org.graalvm.compiler.hotspot.phases; 24 25 import org.graalvm.compiler.debug.GraalError; 26 import org.graalvm.compiler.graph.Node; 27 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 28 import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier; 29 import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier; 30 import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier; 31 import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier; 32 import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier; 33 import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier; 34 import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier; 35 import org.graalvm.compiler.nodes.StructuredGraph; 36 import org.graalvm.compiler.nodes.ValueNode; 37 import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode; 38 import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode; 39 import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode; 40 import org.graalvm.compiler.nodes.memory.FixedAccessNode; 41 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; 42 import org.graalvm.compiler.nodes.memory.ReadNode; 43 import org.graalvm.compiler.nodes.memory.WriteNode; 44 import org.graalvm.compiler.nodes.memory.address.AddressNode; 45 import org.graalvm.compiler.nodes.type.StampTool; 46 import org.graalvm.compiler.phases.Phase; 47 48 public class WriteBarrierAdditionPhase extends Phase { 49 50 private GraalHotSpotVMConfig config; 51 52 public WriteBarrierAdditionPhase(GraalHotSpotVMConfig config) { 53 this.config = config; 54 } 55 56 @Override 57 protected void run(StructuredGraph graph) { 58 for (Node n : graph.getNodes()) { 59 if (n instanceof ReadNode) { 60 addReadNodeBarriers((ReadNode) n, graph); 61 } else if (n instanceof WriteNode) { 62 addWriteNodeBarriers((WriteNode) n, graph); 63 } else if (n instanceof LoweredAtomicReadAndWriteNode) { 64 LoweredAtomicReadAndWriteNode loweredAtomicReadAndWriteNode = (LoweredAtomicReadAndWriteNode) n; 65 addAtomicReadWriteNodeBarriers(loweredAtomicReadAndWriteNode, graph); 66 } else if (n instanceof AbstractCompareAndSwapNode) { 67 addCASBarriers((AbstractCompareAndSwapNode) n, graph); 68 } else if (n instanceof ArrayRangeWriteNode) { 69 ArrayRangeWriteNode node = (ArrayRangeWriteNode) n; 70 if (node.isObjectArray()) { 71 addArrayRangeBarriers(node, graph); 72 } 73 } 74 } 75 } 76 77 private void addReadNodeBarriers(ReadNode node, StructuredGraph graph) { 78 if (node.getBarrierType() == BarrierType.PRECISE) { 79 assert config.useG1GC; 80 G1ReferentFieldReadBarrier barrier = graph.add(new G1ReferentFieldReadBarrier(node.getAddress(), node, false)); 81 graph.addAfterFixed(node, barrier); 82 } else { 83 assert node.getBarrierType() == BarrierType.NONE : "Non precise read barrier has been attached to read node."; 84 } 85 } 86 87 protected static void addG1PreWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean doLoad, boolean nullCheck, StructuredGraph graph) { 88 G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(address, value, doLoad, nullCheck)); 89 preBarrier.setStateBefore(node.stateBefore()); 90 node.setNullCheck(false); 91 node.setStateBefore(null); 92 graph.addBeforeFixed(node, preBarrier); 93 } 94 95 protected void addG1PostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) { 96 final boolean alwaysNull = StampTool.isPointerAlwaysNull(value); 97 graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(address, value, precise, alwaysNull))); 98 } 99 100 protected void addSerialPostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) { 101 final boolean alwaysNull = StampTool.isPointerAlwaysNull(value); 102 if (alwaysNull) { 103 // Serial barrier isn't needed for null value 104 return; 105 } 106 graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(address, precise))); 107 } 108 109 private void addWriteNodeBarriers(WriteNode node, StructuredGraph graph) { 110 BarrierType barrierType = node.getBarrierType(); 111 switch (barrierType) { 112 case NONE: 113 // nothing to do 114 break; 115 case IMPRECISE: 116 case PRECISE: 117 boolean precise = barrierType == BarrierType.PRECISE; 118 if (config.useG1GC) { 119 if (!node.getLocationIdentity().isInit()) { 120 addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph); 121 } 122 addG1PostWriteBarrier(node, node.getAddress(), node.value(), precise, graph); 123 } else { 124 addSerialPostWriteBarrier(node, node.getAddress(), node.value(), precise, graph); 125 } 126 break; 127 default: 128 throw new GraalError("unexpected barrier type: " + barrierType); 129 } 130 } 131 132 private void addAtomicReadWriteNodeBarriers(LoweredAtomicReadAndWriteNode node, StructuredGraph graph) { 133 BarrierType barrierType = node.getBarrierType(); 134 switch (barrierType) { 135 case NONE: 136 // nothing to do 137 break; 138 case IMPRECISE: 139 case PRECISE: 140 boolean precise = barrierType == BarrierType.PRECISE; 141 if (config.useG1GC) { 142 addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph); 143 addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph); 144 } else { 145 addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph); 146 } 147 break; 148 default: 149 throw new GraalError("unexpected barrier type: " + barrierType); 150 } 151 } 152 153 private void addCASBarriers(AbstractCompareAndSwapNode node, StructuredGraph graph) { 154 BarrierType barrierType = node.getBarrierType(); 155 switch (barrierType) { 156 case NONE: 157 // nothing to do 158 break; 159 case IMPRECISE: 160 case PRECISE: 161 boolean precise = barrierType == BarrierType.PRECISE; 162 if (config.useG1GC) { 163 addG1PreWriteBarrier(node, node.getAddress(), node.getExpectedValue(), false, false, graph); 164 addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph); 165 } else { 166 addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph); 167 } 168 break; 169 default: 170 throw new GraalError("unexpected barrier type: " + barrierType); 171 } 172 } 173 174 private void addArrayRangeBarriers(ArrayRangeWriteNode node, StructuredGraph graph) { 175 if (config.useG1GC) { 176 if (!node.isInitialization()) { 177 G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); 178 graph.addBeforeFixed(node, g1ArrayRangePreWriteBarrier); 179 } 180 G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); 181 graph.addAfterFixed(node, g1ArrayRangePostWriteBarrier); 182 } else { 183 SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); 184 graph.addAfterFixed(node, serialArrayRangeWriteBarrier); 185 } 186 } 187 188 @Override 189 public boolean checkContract() { 190 return false; 191 } 192 }