1 /* 2 * Copyright (c) 2015, 2016, 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(); 321 location = snippetReflection.asObject(LocationIdentity.class, args[2].asJavaConstant()); 322 } 323 b.push(returnKind, readOp(b, readKind, address, location, operation.opcode())); 324 break; 325 } 326 case READ_HEAP: { 327 assert args.length == 3; 328 JavaKind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass())); 329 AddressNode address = makeAddress(b, args[0], args[1]); 330 BarrierType barrierType = snippetReflection.asObject(BarrierType.class, args[2].asJavaConstant()); 331 b.push(returnKind, readOp(b, readKind, address, any(), barrierType, true)); 332 break; 333 } 334 case WRITE_POINTER: 335 case WRITE_OBJECT: 336 case WRITE_BARRIERED: 337 case INITIALIZE: { 338 assert args.length == 3 || args.length == 4; 339 JavaKind writeKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(wordMethod.isStatic() ? 2 : 1, wordMethod.getDeclaringClass())); 340 AddressNode address = makeAddress(b, args[0], args[1]); 341 LocationIdentity location; 342 if (args.length == 3) { 343 location = any(); 344 } else { 345 assert args[3].isConstant(); 346 location = snippetReflection.asObject(LocationIdentity.class, args[3].asJavaConstant()); 347 } 348 writeOp(b, writeKind, address, location, args[2], operation.opcode()); 349 break; 350 } 351 352 case TO_RAW_VALUE: 353 assert args.length == 1; 354 b.push(returnKind, toUnsigned(b, args[0], JavaKind.Long)); 355 break; 356 357 case OBJECT_TO_TRACKED: 358 assert args.length == 1; 359 WordCastNode objectToTracked = b.add(WordCastNode.objectToTrackedPointer(args[0], wordKind)); 360 b.push(returnKind, objectToTracked); 361 break; 362 363 case OBJECT_TO_UNTRACKED: 364 assert args.length == 1; 365 WordCastNode objectToUntracked = b.add(WordCastNode.objectToUntrackedPointer(args[0], wordKind)); 366 b.push(returnKind, objectToUntracked); 367 break; 368 369 case FROM_ADDRESS: 370 assert args.length == 1; 371 WordCastNode addressToWord = b.add(WordCastNode.addressToWord(args[0], wordKind)); 372 b.push(returnKind, addressToWord); 373 break; 374 375 case TO_OBJECT: 376 assert args.length == 1; 377 WordCastNode wordToObject = b.add(WordCastNode.wordToObject(args[0], wordKind)); 378 b.push(returnKind, wordToObject); 379 break; 380 381 case TO_OBJECT_NON_NULL: 382 assert args.length == 1; 383 WordCastNode wordToObjectNonNull = b.add(WordCastNode.wordToObjectNonNull(args[0], wordKind)); 384 b.push(returnKind, wordToObjectNonNull); 385 break; 386 387 case CAS_POINTER: 388 assert args.length == 5; 389 AddressNode address = makeAddress(b, args[0], args[1]); 390 JavaKind valueKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(1, wordMethod.getDeclaringClass())); 391 assert valueKind.equals(wordTypes.asKind(wordMethod.getSignature().getParameterType(2, wordMethod.getDeclaringClass()))) : wordMethod.getSignature(); 392 assert args[4].isConstant() : Arrays.toString(args); 393 LocationIdentity location = snippetReflection.asObject(LocationIdentity.class, args[4].asJavaConstant()); 394 JavaType returnType = wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()); 395 b.addPush(returnKind, casOp(valueKind, wordTypes.asKind(returnType), address, location, args[2], args[3])); 396 break; 397 default: 398 throw new GraalError("Unknown opcode: %s", operation.opcode()); 399 } 400 } 401 402 /** 403 * Create an instance of a binary node which is used to lower {@link Word} operations. This 404 * method is called for all {@link Word} operations which are annotated with @Operation(node = 405 * ...) and encapsulates the reflective allocation of the node. 406 */ 407 private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right, boolean withGuardingNode) { 408 try { 409 Class<?>[] parameterTypes = withGuardingNode ? new Class<?>[]{ValueNode.class, ValueNode.class, GuardingNode.class} : new Class<?>[]{ValueNode.class, ValueNode.class}; 410 Constructor<?> cons = nodeClass.getDeclaredConstructor(parameterTypes); 411 Object[] initargs = withGuardingNode ? new Object[]{left, right, null} : new Object[]{left, right}; 412 return (ValueNode) cons.newInstance(initargs); 413 } catch (Throwable ex) { 414 throw new GraalError(ex).addContext(nodeClass.getName()); 415 } 416 } 417 418 private ValueNode comparisonOp(GraphBuilderContext graph, Condition condition, ValueNode left, ValueNode right) { 419 assert left.getStackKind() == wordKind && right.getStackKind() == wordKind; 420 421 CanonicalizedCondition canonical = condition.canonicalize(); 422 423 ValueNode a = canonical.mustMirror() ? right : left; 424 ValueNode b = canonical.mustMirror() ? left : right; 425 426 CompareNode comparison; 427 if (canonical.getCanonicalCondition() == CanonicalCondition.EQ) { 428 comparison = new IntegerEqualsNode(a, b); 429 } else if (canonical.getCanonicalCondition() == CanonicalCondition.BT) { 430 comparison = new IntegerBelowNode(a, b); 431 } else { 432 assert canonical.getCanonicalCondition() == CanonicalCondition.LT; 433 comparison = new IntegerLessThanNode(a, b); 434 } 435 436 ConstantNode trueValue = graph.add(forInt(1)); 437 ConstantNode falseValue = graph.add(forInt(0)); 438 439 if (canonical.mustNegate()) { 440 ConstantNode temp = trueValue; 441 trueValue = falseValue; 442 falseValue = temp; 443 } 444 return graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue)); 445 } 446 447 protected ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, Opcode op) { 448 assert op == Opcode.READ_POINTER || op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED; 449 final BarrierType barrier = (op == Opcode.READ_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE); 450 final boolean compressible = (op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED); 451 452 return readOp(b, readKind, address, location, barrier, compressible); 453 } 454 455 public static ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, BarrierType barrierType, boolean compressible) { 456 /* 457 * A JavaReadNode lowered to a ReadNode that will not float. This means it cannot float 458 * above an explicit zero check on its base address or any other test that ensures the read 459 * is safe. 460 */ 461 JavaReadNode read = b.add(new JavaReadNode(readKind, address, location, barrierType, compressible)); 462 return read; 463 } 464 465 protected void writeOp(GraphBuilderContext b, JavaKind writeKind, AddressNode address, LocationIdentity location, ValueNode value, Opcode op) { 466 assert op == Opcode.WRITE_POINTER || op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED || op == Opcode.INITIALIZE; 467 final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE); 468 final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED); 469 assert op != Opcode.INITIALIZE || location.isInit() : "must use init location for initializing"; 470 b.add(new JavaWriteNode(writeKind, address, location, value, barrier, compressible)); 471 } 472 473 protected AbstractCompareAndSwapNode casOp(JavaKind writeKind, JavaKind returnKind, AddressNode address, LocationIdentity location, ValueNode expectedValue, ValueNode newValue) { 474 boolean isLogic = returnKind == JavaKind.Boolean; 475 assert isLogic || writeKind == returnKind : writeKind + " != " + returnKind; 476 AbstractCompareAndSwapNode cas; 477 if (isLogic) { 478 cas = new LogicCompareAndSwapNode(address, expectedValue, newValue, location); 479 } else { 480 cas = new ValueCompareAndSwapNode(address, expectedValue, newValue, location); 481 } 482 return cas; 483 } 484 485 public AddressNode makeAddress(GraphBuilderContext b, ValueNode base, ValueNode offset) { 486 return b.add(new OffsetAddressNode(base, fromSigned(b, offset))); 487 } 488 489 public ValueNode fromUnsigned(GraphBuilderContext b, ValueNode value) { 490 return convert(b, value, wordKind, true); 491 } 492 493 public ValueNode fromSigned(GraphBuilderContext b, ValueNode value) { 494 return convert(b, value, wordKind, false); 495 } 496 497 public ValueNode toUnsigned(GraphBuilderContext b, ValueNode value, JavaKind toKind) { 498 return convert(b, value, toKind, true); 499 } 500 501 public ValueNode convert(GraphBuilderContext b, ValueNode value, JavaKind toKind, boolean unsigned) { 502 if (value.getStackKind() == toKind) { 503 return value; 504 } 505 506 if (toKind == JavaKind.Int) { 507 assert value.getStackKind() == JavaKind.Long; 508 return b.add(new NarrowNode(value, 32)); 509 } else { 510 assert toKind == JavaKind.Long; 511 assert value.getStackKind() == JavaKind.Int; 512 if (unsigned) { 513 return b.add(new ZeroExtendNode(value, 64)); 514 } else { 515 return b.add(new SignExtendNode(value, 64)); 516 } 517 } 518 } 519 520 private static BailoutException bailout(GraphBuilderContext b, String msg) { 521 throw b.bailout(msg + "\nat " + b.getCode().asStackTraceElement(b.bci())); 522 } 523 }