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 96 public WordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) { 97 this.snippetReflection = snippetReflection; 98 this.wordTypes = wordTypes; 99 this.wordKind = wordTypes.getWordKind(); 100 } 101 102 @Override 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 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 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 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 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 161 public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField staticField) { 162 return handleLoadField(b, null, staticField); 163 } 164 165 @Override 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 180 protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index, GuardingNode boundsCheck) { 181 return new LoadIndexedNode(null, array, index, boundsCheck, wordKind); 182 } 183 184 @Override 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 202 public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) { 203 return handleStoreField(b, null, field, value); 204 } 205 206 @Override 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 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 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 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 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 */ 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 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 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 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 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 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 486 public AddressNode makeAddress(GraphBuilderContext b, ValueNode base, ValueNode offset) { 487 return b.add(new OffsetAddressNode(base, fromSigned(b, offset))); 488 } 489 490 public ValueNode fromUnsigned(GraphBuilderContext b, ValueNode value) { 491 return convert(b, value, wordKind, true); 492 } 493 494 public ValueNode fromSigned(GraphBuilderContext b, ValueNode value) { 495 return convert(b, value, wordKind, false); 496 } 497 498 public ValueNode toUnsigned(GraphBuilderContext b, ValueNode value, JavaKind toKind) { 499 return convert(b, value, toKind, true); 500 } 501 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 521 private static BailoutException bailout(GraphBuilderContext b, String msg) { 522 throw b.bailout(msg + "\nat " + b.getCode().asStackTraceElement(b.bci())); 523 } 524 }