1 /* 2 * Copyright (c) 2015, 2018, 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.word; 26 27 import static org.graalvm.compiler.nodes.ConstantNode.forInt; 28 import static org.graalvm.compiler.nodes.ConstantNode.forIntegerKind; 29 import static jdk.internal.vm.compiler.word.LocationIdentity.any; 30 31 import java.lang.reflect.Constructor; 32 import java.util.Arrays; 33 34 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; 35 import org.graalvm.compiler.bytecode.BridgeMethodUtils; 36 import org.graalvm.compiler.core.common.calc.CanonicalCondition; 37 import org.graalvm.compiler.core.common.calc.Condition; 38 import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition; 39 import org.graalvm.compiler.core.common.type.Stamp; 40 import org.graalvm.compiler.core.common.type.StampFactory; 41 import org.graalvm.compiler.core.common.type.StampPair; 42 import org.graalvm.compiler.core.common.type.TypeReference; 43 import org.graalvm.compiler.debug.GraalError; 44 import org.graalvm.compiler.nodes.ConstantNode; 45 import org.graalvm.compiler.nodes.Invoke; 46 import org.graalvm.compiler.nodes.ValueNode; 47 import org.graalvm.compiler.nodes.calc.CompareNode; 48 import org.graalvm.compiler.nodes.calc.ConditionalNode; 49 import org.graalvm.compiler.nodes.calc.IntegerBelowNode; 50 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; 51 import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; 52 import org.graalvm.compiler.nodes.calc.NarrowNode; 53 import org.graalvm.compiler.nodes.calc.SignExtendNode; 54 import org.graalvm.compiler.nodes.calc.XorNode; 55 import org.graalvm.compiler.nodes.calc.ZeroExtendNode; 56 import org.graalvm.compiler.nodes.extended.GuardingNode; 57 import org.graalvm.compiler.nodes.extended.JavaReadNode; 58 import org.graalvm.compiler.nodes.extended.JavaWriteNode; 59 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; 60 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool; 61 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; 62 import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; 63 import org.graalvm.compiler.nodes.graphbuilderconf.TypePlugin; 64 import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode; 65 import org.graalvm.compiler.nodes.java.LoadFieldNode; 66 import org.graalvm.compiler.nodes.java.LoadIndexedNode; 67 import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode; 68 import org.graalvm.compiler.nodes.java.StoreIndexedNode; 69 import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode; 70 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; 71 import org.graalvm.compiler.nodes.memory.address.AddressNode; 72 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; 73 import org.graalvm.compiler.nodes.type.StampTool; 74 import org.graalvm.compiler.word.Word.Opcode; 75 import org.graalvm.compiler.word.Word.Operation; 76 import jdk.internal.vm.compiler.word.LocationIdentity; 77 import jdk.internal.vm.compiler.word.impl.WordFactoryOperation; 78 79 import jdk.vm.ci.code.BailoutException; 80 import jdk.vm.ci.meta.JavaKind; 81 import jdk.vm.ci.meta.JavaType; 82 import jdk.vm.ci.meta.JavaTypeProfile; 83 import jdk.vm.ci.meta.ResolvedJavaField; 84 import jdk.vm.ci.meta.ResolvedJavaMethod; 85 import jdk.vm.ci.meta.ResolvedJavaType; 86 87 /** 88 * A plugin for calls to {@linkplain Operation word operations}, as well as all other nodes that 89 * need special handling for {@link Word} types. 90 */ 91 public class WordOperationPlugin implements NodePlugin, TypePlugin, InlineInvokePlugin { 92 protected final WordTypes wordTypes; 93 protected final JavaKind wordKind; 94 protected final SnippetReflectionProvider snippetReflection; 95 WordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes)96 public WordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) { 97 this.snippetReflection = snippetReflection; 98 this.wordTypes = wordTypes; 99 this.wordKind = wordTypes.getWordKind(); 100 } 101 102 @Override canChangeStackKind(GraphBuilderContext b)103 public boolean canChangeStackKind(GraphBuilderContext b) { 104 return true; 105 } 106 107 /** 108 * Processes a call to a method if it is annotated as a word operation by adding nodes to the 109 * graph being built that implement the denoted operation. 110 * 111 * @return {@code true} iff {@code method} is annotated with {@link Operation} (and was thus 112 * processed by this method) 113 */ 114 @Override handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args)115 public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { 116 if (!wordTypes.isWordOperation(method)) { 117 return false; 118 } 119 processWordOperation(b, args, wordTypes.getWordOperation(method, b.getMethod().getDeclaringClass())); 120 return true; 121 } 122 123 @Override interceptType(GraphBuilderTool b, JavaType declaredType, boolean nonNull)124 public StampPair interceptType(GraphBuilderTool b, JavaType declaredType, boolean nonNull) { 125 Stamp wordStamp = null; 126 if (declaredType instanceof ResolvedJavaType) { 127 ResolvedJavaType resolved = (ResolvedJavaType) declaredType; 128 if (wordTypes.isWord(resolved)) { 129 wordStamp = wordTypes.getWordStamp(resolved); 130 } else if (resolved.isArray() && wordTypes.isWord(resolved.getElementalType())) { 131 TypeReference trusted = TypeReference.createTrustedWithoutAssumptions(resolved); 132 wordStamp = StampFactory.object(trusted, nonNull); 133 } 134 } 135 if (wordStamp != null) { 136 return StampPair.createSingle(wordStamp); 137 } else { 138 return null; 139 } 140 } 141 142 @Override notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke)143 public void notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) { 144 if (wordTypes.isWord(invoke.asNode())) { 145 invoke.asNode().setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(invoke.asNode()))); 146 } 147 } 148 149 @Override handleLoadField(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field)150 public boolean handleLoadField(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) { 151 StampPair wordStamp = interceptType(b, field.getType(), false); 152 if (wordStamp != null) { 153 LoadFieldNode loadFieldNode = LoadFieldNode.createOverrideStamp(wordStamp, receiver, field); 154 b.addPush(field.getJavaKind(), loadFieldNode); 155 return true; 156 } 157 return false; 158 } 159 160 @Override handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField staticField)161 public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField staticField) { 162 return handleLoadField(b, null, staticField); 163 } 164 165 @Override handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind elementKind)166 public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind elementKind) { 167 ResolvedJavaType arrayType = StampTool.typeOrNull(array); 168 /* 169 * There are cases where the array does not have a known type yet, i.e., the type is null. 170 * In that case we assume it is not a word type. 171 */ 172 if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) { 173 assert elementKind == JavaKind.Object; 174 b.addPush(elementKind, createLoadIndexedNode(array, index, boundsCheck)); 175 return true; 176 } 177 return false; 178 } 179 createLoadIndexedNode(ValueNode array, ValueNode index, GuardingNode boundsCheck)180 protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index, GuardingNode boundsCheck) { 181 return new LoadIndexedNode(null, array, index, boundsCheck, wordKind); 182 } 183 184 @Override handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value)185 public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) { 186 if (field.getJavaKind() == JavaKind.Object) { 187 boolean isWordField = wordTypes.isWord(field.getType()); 188 boolean isWordValue = value.getStackKind() == wordKind; 189 190 if (isWordField && !isWordValue) { 191 throw bailout(b, "Cannot store a non-word value into a word field: " + field.format("%H.%n")); 192 } else if (!isWordField && isWordValue) { 193 throw bailout(b, "Cannot store a word value into a non-word field: " + field.format("%H.%n")); 194 } 195 } 196 197 /* We never need to intercept the field store. */ 198 return false; 199 } 200 201 @Override handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value)202 public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) { 203 return handleStoreField(b, null, field, value); 204 } 205 206 @Override handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, GuardingNode storeCheck, JavaKind elementKind, ValueNode value)207 public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, GuardingNode storeCheck, JavaKind elementKind, ValueNode value) { 208 ResolvedJavaType arrayType = StampTool.typeOrNull(array); 209 if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) { 210 assert elementKind == JavaKind.Object; 211 if (value.getStackKind() != wordKind) { 212 throw bailout(b, "Cannot store a non-word value into a word array: " + arrayType.toJavaName(true)); 213 } 214 GraalError.guarantee(storeCheck == null, "Word array stores are primitive stores and therefore do not require a store check"); 215 b.add(createStoreIndexedNode(array, index, boundsCheck, value)); 216 return true; 217 } 218 if (elementKind == JavaKind.Object && value.getStackKind() == wordKind) { 219 throw bailout(b, "Cannot store a word value into a non-word array: " + arrayType.toJavaName(true)); 220 } 221 return false; 222 } 223 createStoreIndexedNode(ValueNode array, ValueNode index, GuardingNode boundsCheck, ValueNode value)224 protected StoreIndexedNode createStoreIndexedNode(ValueNode array, ValueNode index, GuardingNode boundsCheck, ValueNode value) { 225 return new StoreIndexedNode(array, index, boundsCheck, null, wordKind, value); 226 } 227 228 @Override handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile)229 public boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { 230 if (!wordTypes.isWord(type)) { 231 if (object.getStackKind() != JavaKind.Object) { 232 throw bailout(b, "Cannot cast a word value to a non-word type: " + type.toJavaName(true)); 233 } 234 return false; 235 } 236 237 if (object.getStackKind() != wordKind) { 238 throw bailout(b, "Cannot cast a non-word value to a word type: " + type.toJavaName(true)); 239 } 240 b.push(JavaKind.Object, object); 241 return true; 242 } 243 244 @Override handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile)245 public boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) { 246 if (wordTypes.isWord(type)) { 247 throw bailout(b, "Cannot use instanceof for word a type: " + type.toJavaName(true)); 248 } else if (object.getStackKind() != JavaKind.Object) { 249 throw bailout(b, "Cannot use instanceof on a word value: " + type.toJavaName(true)); 250 } 251 return false; 252 } 253 processWordOperation(GraphBuilderContext b, ValueNode[] args, ResolvedJavaMethod wordMethod)254 protected void processWordOperation(GraphBuilderContext b, ValueNode[] args, ResolvedJavaMethod wordMethod) throws GraalError { 255 JavaKind returnKind = wordMethod.getSignature().getReturnKind(); 256 WordFactoryOperation factoryOperation = BridgeMethodUtils.getAnnotation(WordFactoryOperation.class, wordMethod); 257 if (factoryOperation != null) { 258 switch (factoryOperation.opcode()) { 259 case ZERO: 260 assert args.length == 0; 261 b.addPush(returnKind, forIntegerKind(wordKind, 0L)); 262 return; 263 264 case FROM_UNSIGNED: 265 assert args.length == 1; 266 b.push(returnKind, fromUnsigned(b, args[0])); 267 return; 268 269 case FROM_SIGNED: 270 assert args.length == 1; 271 b.push(returnKind, fromSigned(b, args[0])); 272 return; 273 } 274 } 275 276 Word.Operation operation = BridgeMethodUtils.getAnnotation(Word.Operation.class, wordMethod); 277 if (operation == null) { 278 throw bailout(b, "Cannot call method on a word value: " + wordMethod.format("%H.%n(%p)")); 279 } 280 switch (operation.opcode()) { 281 case NODE_CLASS: 282 case NODE_CLASS_WITH_GUARD: 283 assert args.length == 2; 284 ValueNode left = args[0]; 285 ValueNode right = operation.rightOperandIsInt() ? toUnsigned(b, args[1], JavaKind.Int) : fromSigned(b, args[1]); 286 287 b.addPush(returnKind, createBinaryNodeInstance(operation.node(), left, right, operation.opcode() == Opcode.NODE_CLASS_WITH_GUARD)); 288 break; 289 290 case COMPARISON: 291 assert args.length == 2; 292 b.push(returnKind, comparisonOp(b, operation.condition(), args[0], fromSigned(b, args[1]))); 293 break; 294 295 case IS_NULL: 296 assert args.length == 1; 297 b.push(returnKind, comparisonOp(b, Condition.EQ, args[0], ConstantNode.forIntegerKind(wordKind, 0L))); 298 break; 299 300 case IS_NON_NULL: 301 assert args.length == 1; 302 b.push(returnKind, comparisonOp(b, Condition.NE, args[0], ConstantNode.forIntegerKind(wordKind, 0L))); 303 break; 304 305 case NOT: 306 assert args.length == 1; 307 b.addPush(returnKind, new XorNode(args[0], b.add(forIntegerKind(wordKind, -1)))); 308 break; 309 310 case READ_POINTER: 311 case READ_OBJECT: 312 case READ_BARRIERED: { 313 assert args.length == 2 || args.length == 3; 314 JavaKind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass())); 315 AddressNode address = makeAddress(b, args[0], args[1]); 316 LocationIdentity location; 317 if (args.length == 2) { 318 location = any(); 319 } else { 320 assert args[2].isConstant() : args[2]; 321 location = snippetReflection.asObject(LocationIdentity.class, args[2].asJavaConstant()); 322 assert location != null : snippetReflection.asObject(Object.class, args[2].asJavaConstant()); 323 } 324 b.push(returnKind, readOp(b, readKind, address, location, operation.opcode())); 325 break; 326 } 327 case READ_HEAP: { 328 assert args.length == 3; 329 JavaKind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass())); 330 AddressNode address = makeAddress(b, args[0], args[1]); 331 BarrierType barrierType = snippetReflection.asObject(BarrierType.class, args[2].asJavaConstant()); 332 b.push(returnKind, readOp(b, readKind, address, any(), barrierType, true)); 333 break; 334 } 335 case WRITE_POINTER: 336 case WRITE_OBJECT: 337 case WRITE_BARRIERED: 338 case INITIALIZE: { 339 assert args.length == 3 || args.length == 4; 340 JavaKind writeKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(wordMethod.isStatic() ? 2 : 1, wordMethod.getDeclaringClass())); 341 AddressNode address = makeAddress(b, args[0], args[1]); 342 LocationIdentity location; 343 if (args.length == 3) { 344 location = any(); 345 } else { 346 assert args[3].isConstant(); 347 location = snippetReflection.asObject(LocationIdentity.class, args[3].asJavaConstant()); 348 } 349 writeOp(b, writeKind, address, location, args[2], operation.opcode()); 350 break; 351 } 352 353 case TO_RAW_VALUE: 354 assert args.length == 1; 355 b.push(returnKind, toUnsigned(b, args[0], JavaKind.Long)); 356 break; 357 358 case OBJECT_TO_TRACKED: 359 assert args.length == 1; 360 WordCastNode objectToTracked = b.add(WordCastNode.objectToTrackedPointer(args[0], wordKind)); 361 b.push(returnKind, objectToTracked); 362 break; 363 364 case OBJECT_TO_UNTRACKED: 365 assert args.length == 1; 366 WordCastNode objectToUntracked = b.add(WordCastNode.objectToUntrackedPointer(args[0], wordKind)); 367 b.push(returnKind, objectToUntracked); 368 break; 369 370 case FROM_ADDRESS: 371 assert args.length == 1; 372 WordCastNode addressToWord = b.add(WordCastNode.addressToWord(args[0], wordKind)); 373 b.push(returnKind, addressToWord); 374 break; 375 376 case TO_OBJECT: 377 assert args.length == 1; 378 WordCastNode wordToObject = b.add(WordCastNode.wordToObject(args[0], wordKind)); 379 b.push(returnKind, wordToObject); 380 break; 381 382 case TO_OBJECT_NON_NULL: 383 assert args.length == 1; 384 WordCastNode wordToObjectNonNull = b.add(WordCastNode.wordToObjectNonNull(args[0], wordKind)); 385 b.push(returnKind, wordToObjectNonNull); 386 break; 387 388 case CAS_POINTER: 389 assert args.length == 5; 390 AddressNode address = makeAddress(b, args[0], args[1]); 391 JavaKind valueKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(1, wordMethod.getDeclaringClass())); 392 assert valueKind.equals(wordTypes.asKind(wordMethod.getSignature().getParameterType(2, wordMethod.getDeclaringClass()))) : wordMethod.getSignature(); 393 assert args[4].isConstant() : Arrays.toString(args); 394 LocationIdentity location = snippetReflection.asObject(LocationIdentity.class, args[4].asJavaConstant()); 395 JavaType returnType = wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()); 396 b.addPush(returnKind, casOp(valueKind, wordTypes.asKind(returnType), address, location, args[2], args[3])); 397 break; 398 default: 399 throw new GraalError("Unknown opcode: %s", operation.opcode()); 400 } 401 } 402 403 /** 404 * Create an instance of a binary node which is used to lower {@link Word} operations. This 405 * method is called for all {@link Word} operations which are annotated with @Operation(node = 406 * ...) and encapsulates the reflective allocation of the node. 407 */ createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right, boolean withGuardingNode)408 private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right, boolean withGuardingNode) { 409 try { 410 Class<?>[] parameterTypes = withGuardingNode ? new Class<?>[]{ValueNode.class, ValueNode.class, GuardingNode.class} : new Class<?>[]{ValueNode.class, ValueNode.class}; 411 Constructor<?> cons = nodeClass.getDeclaredConstructor(parameterTypes); 412 Object[] initargs = withGuardingNode ? new Object[]{left, right, null} : new Object[]{left, right}; 413 return (ValueNode) cons.newInstance(initargs); 414 } catch (Throwable ex) { 415 throw new GraalError(ex).addContext(nodeClass.getName()); 416 } 417 } 418 comparisonOp(GraphBuilderContext graph, Condition condition, ValueNode left, ValueNode right)419 private ValueNode comparisonOp(GraphBuilderContext graph, Condition condition, ValueNode left, ValueNode right) { 420 assert left.getStackKind() == wordKind && right.getStackKind() == wordKind; 421 422 CanonicalizedCondition canonical = condition.canonicalize(); 423 424 ValueNode a = canonical.mustMirror() ? right : left; 425 ValueNode b = canonical.mustMirror() ? left : right; 426 427 CompareNode comparison; 428 if (canonical.getCanonicalCondition() == CanonicalCondition.EQ) { 429 comparison = new IntegerEqualsNode(a, b); 430 } else if (canonical.getCanonicalCondition() == CanonicalCondition.BT) { 431 comparison = new IntegerBelowNode(a, b); 432 } else { 433 assert canonical.getCanonicalCondition() == CanonicalCondition.LT; 434 comparison = new IntegerLessThanNode(a, b); 435 } 436 437 ConstantNode trueValue = graph.add(forInt(1)); 438 ConstantNode falseValue = graph.add(forInt(0)); 439 440 if (canonical.mustNegate()) { 441 ConstantNode temp = trueValue; 442 trueValue = falseValue; 443 falseValue = temp; 444 } 445 return graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue)); 446 } 447 readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, Opcode op)448 protected ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, Opcode op) { 449 assert op == Opcode.READ_POINTER || op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED; 450 final BarrierType barrier = (op == Opcode.READ_BARRIERED ? BarrierType.UNKNOWN : BarrierType.NONE); 451 final boolean compressible = (op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED); 452 453 return readOp(b, readKind, address, location, barrier, compressible); 454 } 455 readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, BarrierType barrierType, boolean compressible)456 public static ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, BarrierType barrierType, boolean compressible) { 457 /* 458 * A JavaReadNode lowered to a ReadNode that will not float. This means it cannot float 459 * above an explicit zero check on its base address or any other test that ensures the read 460 * is safe. 461 */ 462 JavaReadNode read = b.add(new JavaReadNode(readKind, address, location, barrierType, compressible)); 463 return read; 464 } 465 writeOp(GraphBuilderContext b, JavaKind writeKind, AddressNode address, LocationIdentity location, ValueNode value, Opcode op)466 protected void writeOp(GraphBuilderContext b, JavaKind writeKind, AddressNode address, LocationIdentity location, ValueNode value, Opcode op) { 467 assert op == Opcode.WRITE_POINTER || op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED || op == Opcode.INITIALIZE; 468 final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.UNKNOWN : BarrierType.NONE); 469 final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED); 470 assert op != Opcode.INITIALIZE || location.isInit() : "must use init location for initializing"; 471 b.add(new JavaWriteNode(writeKind, address, location, value, barrier, compressible)); 472 } 473 casOp(JavaKind writeKind, JavaKind returnKind, AddressNode address, LocationIdentity location, ValueNode expectedValue, ValueNode newValue)474 protected AbstractCompareAndSwapNode casOp(JavaKind writeKind, JavaKind returnKind, AddressNode address, LocationIdentity location, ValueNode expectedValue, ValueNode newValue) { 475 boolean isLogic = returnKind == JavaKind.Boolean; 476 assert isLogic || writeKind == returnKind : writeKind + " != " + returnKind; 477 AbstractCompareAndSwapNode cas; 478 if (isLogic) { 479 cas = new LogicCompareAndSwapNode(address, expectedValue, newValue, location); 480 } else { 481 cas = new ValueCompareAndSwapNode(address, expectedValue, newValue, location); 482 } 483 return cas; 484 } 485 makeAddress(GraphBuilderContext b, ValueNode base, ValueNode offset)486 public AddressNode makeAddress(GraphBuilderContext b, ValueNode base, ValueNode offset) { 487 return b.add(new OffsetAddressNode(base, fromSigned(b, offset))); 488 } 489 fromUnsigned(GraphBuilderContext b, ValueNode value)490 public ValueNode fromUnsigned(GraphBuilderContext b, ValueNode value) { 491 return convert(b, value, wordKind, true); 492 } 493 fromSigned(GraphBuilderContext b, ValueNode value)494 public ValueNode fromSigned(GraphBuilderContext b, ValueNode value) { 495 return convert(b, value, wordKind, false); 496 } 497 toUnsigned(GraphBuilderContext b, ValueNode value, JavaKind toKind)498 public ValueNode toUnsigned(GraphBuilderContext b, ValueNode value, JavaKind toKind) { 499 return convert(b, value, toKind, true); 500 } 501 convert(GraphBuilderContext b, ValueNode value, JavaKind toKind, boolean unsigned)502 public ValueNode convert(GraphBuilderContext b, ValueNode value, JavaKind toKind, boolean unsigned) { 503 if (value.getStackKind() == toKind) { 504 return value; 505 } 506 507 if (toKind == JavaKind.Int) { 508 assert value.getStackKind() == JavaKind.Long; 509 return b.add(new NarrowNode(value, 32)); 510 } else { 511 assert toKind == JavaKind.Long; 512 assert value.getStackKind() == JavaKind.Int; 513 if (unsigned) { 514 return b.add(new ZeroExtendNode(value, 64)); 515 } else { 516 return b.add(new SignExtendNode(value, 64)); 517 } 518 } 519 } 520 bailout(GraphBuilderContext b, String msg)521 private static BailoutException bailout(GraphBuilderContext b, String msg) { 522 throw b.bailout(msg + "\nat " + b.getCode().asStackTraceElement(b.bci())); 523 } 524 } 525