1 /* 2 * Copyright (c) 2011, 2012, 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 com.oracle.graal.hotspot.meta; 24 25 import static com.oracle.graal.api.code.CallingConvention.Type.*; 26 import static com.oracle.graal.api.code.DeoptimizationAction.*; 27 import static com.oracle.graal.api.code.MemoryBarriers.*; 28 import static com.oracle.graal.api.code.Register.RegisterFlag.*; 29 import static com.oracle.graal.api.meta.DeoptimizationReason.*; 30 import static com.oracle.graal.api.meta.Value.*; 31 import static com.oracle.graal.graph.UnsafeAccess.*; 32 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; 33 import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*; 34 import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*; 35 import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*; 36 import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*; 37 import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*; 38 import static com.oracle.graal.replacements.Log.*; 39 import static com.oracle.graal.replacements.MathSubstitutionsX86.*; 40 41 import java.lang.reflect.*; 42 import java.util.*; 43 44 import sun.misc.*; 45 46 import com.oracle.graal.api.code.*; 47 import com.oracle.graal.api.code.CodeUtil.RefMapFormatter; 48 import com.oracle.graal.api.code.CompilationResult.Call; 49 import com.oracle.graal.api.code.CompilationResult.DataPatch; 50 import com.oracle.graal.api.code.CompilationResult.Mark; 51 import com.oracle.graal.api.code.CompilationResult.Infopoint; 52 import com.oracle.graal.api.code.Register.RegisterFlag; 53 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; 54 import com.oracle.graal.api.meta.*; 55 import com.oracle.graal.graph.*; 56 import com.oracle.graal.hotspot.*; 57 import com.oracle.graal.hotspot.bridge.*; 58 import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult; 59 import com.oracle.graal.hotspot.nodes.*; 60 import com.oracle.graal.hotspot.phases.*; 61 import com.oracle.graal.hotspot.replacements.*; 62 import com.oracle.graal.hotspot.stubs.*; 63 import com.oracle.graal.java.*; 64 import com.oracle.graal.nodes.*; 65 import com.oracle.graal.nodes.calc.*; 66 import com.oracle.graal.nodes.extended.*; 67 import com.oracle.graal.nodes.extended.WriteNode.WriteBarrierType; 68 import com.oracle.graal.nodes.java.*; 69 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; 70 import com.oracle.graal.nodes.spi.*; 71 import com.oracle.graal.nodes.type.*; 72 import com.oracle.graal.phases.*; 73 import com.oracle.graal.printer.*; 74 import com.oracle.graal.replacements.*; 75 import com.oracle.graal.word.*; 76 77 /** 78 * HotSpot implementation of {@link GraalCodeCacheProvider}. 79 */ 80 public abstract class HotSpotRuntime implements GraalCodeCacheProvider, DisassemblerProvider, BytecodeDisassemblerProvider { 81 82 public final HotSpotVMConfig config; 83 84 protected final RegisterConfig regConfig; 85 protected final RegisterConfig globalStubRegConfig; 86 protected final HotSpotGraalRuntime graalRuntime; 87 88 private CheckCastSnippets.Templates checkcastSnippets; 89 private InstanceOfSnippets.Templates instanceofSnippets; 90 private NewObjectSnippets.Templates newObjectSnippets; 91 private MonitorSnippets.Templates monitorSnippets; 92 private WriteBarrierSnippets.Templates writeBarrierSnippets; 93 private BoxingSnippets.Templates boxingSnippets; 94 private LoadExceptionObjectSnippets.Templates exceptionObjectSnippets; 95 96 private final Map<Descriptor, HotSpotRuntimeCallTarget> runtimeCalls = new HashMap<>(); 97 private final Map<ResolvedJavaMethod, Stub> stubs = new HashMap<>(); 98 99 /** 100 * Holds onto objects that will be embedded in compiled code. HotSpot treats oops embedded in 101 * code as weak references so without an external strong root, such an embedded oop will quickly 102 * die. This in turn will cause the nmethod to be unloaded. 103 */ 104 private final Map<Object, Object> gcRoots = new HashMap<>(); 105 106 /** 107 * The offset from the origin of an array to the first element. 108 * 109 * @return the offset in bytes 110 */ 111 public static int getArrayBaseOffset(Kind kind) { 112 switch (kind) { 113 case Boolean: 114 return Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; 115 case Byte: 116 return Unsafe.ARRAY_BYTE_BASE_OFFSET; 117 case Char: 118 return Unsafe.ARRAY_CHAR_BASE_OFFSET; 119 case Short: 120 return Unsafe.ARRAY_SHORT_BASE_OFFSET; 121 case Int: 122 return Unsafe.ARRAY_INT_BASE_OFFSET; 123 case Long: 124 return Unsafe.ARRAY_LONG_BASE_OFFSET; 125 case Float: 126 return Unsafe.ARRAY_FLOAT_BASE_OFFSET; 127 case Double: 128 return Unsafe.ARRAY_DOUBLE_BASE_OFFSET; 129 case Object: 130 return Unsafe.ARRAY_OBJECT_BASE_OFFSET; 131 default: 132 throw GraalInternalError.shouldNotReachHere(); 133 } 134 } 135 136 /** 137 * The scale used for the index when accessing elements of an array of this kind. 138 * 139 * @return the scale in order to convert the index into a byte offset 140 */ 141 public static int getArrayIndexScale(Kind kind) { 142 switch (kind) { 143 case Boolean: 144 return Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; 145 case Byte: 146 return Unsafe.ARRAY_BYTE_INDEX_SCALE; 147 case Char: 148 return Unsafe.ARRAY_CHAR_INDEX_SCALE; 149 case Short: 150 return Unsafe.ARRAY_SHORT_INDEX_SCALE; 151 case Int: 152 return Unsafe.ARRAY_INT_INDEX_SCALE; 153 case Long: 154 return Unsafe.ARRAY_LONG_INDEX_SCALE; 155 case Float: 156 return Unsafe.ARRAY_FLOAT_INDEX_SCALE; 157 case Double: 158 return Unsafe.ARRAY_DOUBLE_INDEX_SCALE; 159 case Object: 160 return Unsafe.ARRAY_OBJECT_INDEX_SCALE; 161 default: 162 throw GraalInternalError.shouldNotReachHere(); 163 } 164 } 165 166 protected Value ret(Kind kind) { 167 if (kind == Kind.Void) { 168 return ILLEGAL; 169 } 170 return globalStubRegConfig.getReturnRegister(kind).asValue(kind); 171 } 172 173 protected Value[] javaCallingConvention(Kind... arguments) { 174 return callingConvention(arguments, RuntimeCall); 175 } 176 177 protected Value[] nativeCallingConvention(Kind... arguments) { 178 return callingConvention(arguments, NativeCall); 179 } 180 181 private Value[] callingConvention(Kind[] arguments, CallingConvention.Type type) { 182 Value[] result = new Value[arguments.length]; 183 184 TargetDescription target = graalRuntime.getTarget(); 185 int currentStackOffset = 0; 186 for (int i = 0; i < arguments.length; i++) { 187 Kind kind = arguments[i]; 188 RegisterFlag flag = kind == Kind.Float || kind == Kind.Double ? FPU : CPU; 189 Register[] ccRegs = globalStubRegConfig.getCallingConventionRegisters(type, flag); 190 if (i < ccRegs.length) { 191 result[i] = ccRegs[i].asValue(kind); 192 } else { 193 result[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, false); 194 currentStackOffset += Math.max(target.sizeInBytes(kind), target.wordSize); 195 } 196 } 197 return result; 198 } 199 200 public HotSpotRuntime(HotSpotVMConfig config, HotSpotGraalRuntime graalRuntime) { 201 this.config = config; 202 this.graalRuntime = graalRuntime; 203 regConfig = createRegisterConfig(false); 204 globalStubRegConfig = createRegisterConfig(true); 205 206 // @formatter:off 207 208 addRuntimeCall(OnStackReplacementPhase.OSR_MIGRATION_END, config.osrMigrationEndStub, 209 /* temps */ null, 210 /* ret */ ret(Kind.Void), 211 /* arg0: long */ javaCallingConvention(Kind.Long)); 212 213 addRuntimeCall(REGISTER_FINALIZER, config.registerFinalizerStub, 214 /* temps */ null, 215 /* ret */ ret(Kind.Void), 216 /* arg0: object */ javaCallingConvention(Kind.Object)); 217 218 addRuntimeCall(CREATE_NULL_POINTER_EXCEPTION, config.createNullPointerExceptionStub, 219 /* temps */ null, 220 /* ret */ ret(Kind.Object)); 221 222 addRuntimeCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, config.createOutOfBoundsExceptionStub, 223 /* temps */ null, 224 /* ret */ ret(Kind.Object), 225 /* arg0: index */ javaCallingConvention(Kind.Int)); 226 227 addRuntimeCall(JAVA_TIME_MILLIS, config.javaTimeMillisStub, 228 /* temps */ this.regConfig.getCallerSaveRegisters(), 229 /* ret */ ret(Kind.Long)); 230 231 addRuntimeCall(JAVA_TIME_NANOS, config.javaTimeNanosStub, 232 /* temps */ this.regConfig.getCallerSaveRegisters(), 233 /* ret */ ret(Kind.Long)); 234 235 addRuntimeCall(ARITHMETIC_SIN, config.arithmeticSinStub, 236 /* temps */ this.regConfig.getCallerSaveRegisters(), 237 /* ret */ ret(Kind.Double), 238 /* arg0: index */ javaCallingConvention(Kind.Double)); 239 240 addRuntimeCall(ARITHMETIC_COS, config.arithmeticCosStub, 241 /* temps */ this.regConfig.getCallerSaveRegisters(), 242 /* ret */ ret(Kind.Double), 243 /* arg0: index */ javaCallingConvention(Kind.Double)); 244 245 addRuntimeCall(ARITHMETIC_TAN, config.arithmeticTanStub, 246 /* temps */ this.regConfig.getCallerSaveRegisters(), 247 /* ret */ ret(Kind.Double), 248 /* arg0: index */ javaCallingConvention(Kind.Double)); 249 250 addRuntimeCall(LOG_PRIMITIVE, config.logPrimitiveStub, 251 /* temps */ null, 252 /* ret */ ret(Kind.Void), 253 /* arg0: typeChar */ javaCallingConvention(Kind.Int, 254 /* arg1: value */ Kind.Long, 255 /* arg2: newline */ Kind.Boolean)); 256 257 addRuntimeCall(LOG_PRINTF, config.logPrintfStub, 258 /* temps */ null, 259 /* ret */ ret(Kind.Void), 260 /* arg0: format */ javaCallingConvention(Kind.Object, 261 /* arg1: value */ Kind.Long, 262 /* arg2: value */ Kind.Long, 263 /* arg3: value */ Kind.Long)); 264 265 addRuntimeCall(Stub.STUB_PRINTF, config.stubPrintfStub, 266 /* temps */ null, 267 /* ret */ ret(Kind.Void), 268 /* arg0: format */ javaCallingConvention(Kind.Long, 269 /* arg1: value */ Kind.Long, 270 /* arg2: value */ Kind.Long, 271 /* arg3: value */ Kind.Long)); 272 273 addRuntimeCall(LOG_OBJECT, config.logObjectStub, 274 /* temps */ null, 275 /* ret */ ret(Kind.Void), 276 /* arg0: object */ javaCallingConvention(Kind.Object, 277 /* arg1: flags */ Kind.Int)); 278 // @formatter:on 279 } 280 281 /** 282 * Registers the details for linking a call to a compiled {@link Stub}. 283 * 284 * @param descriptor name and signature of the call 285 * @param ret where the call returns its result 286 * @param args where arguments are passed to the call 287 */ 288 protected RuntimeCallTarget addStubCall(Descriptor descriptor, Value ret, Value... args) { 289 return addRuntimeCall(descriptor, 0L, null, ret, args); 290 } 291 292 /** 293 * Registers the details for linking a runtime call. 294 * 295 * @param descriptor name and signature of the call 296 * @param address target address of the call 297 * @param tempRegs temporary registers used (and killed) by the call (null if none) 298 * @param ret where the call returns its result 299 * @param args where arguments are passed to the call 300 */ 301 protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, Value ret, Value... args) { 302 Value[] temps = tempRegs == null || tempRegs.length == 0 ? Value.NONE : new Value[tempRegs.length]; 303 for (int i = 0; i < temps.length; i++) { 304 temps[i] = tempRegs[i].asValue(); 305 } 306 assert checkAssignable(descriptor.getResultType(), ret) : descriptor + " incompatible with result location " + ret; 307 Class[] argTypes = descriptor.getArgumentTypes(); 308 assert argTypes.length == args.length : descriptor + " incompatible with number of argument locations: " + args.length; 309 for (int i = 0; i < argTypes.length; i++) { 310 assert checkAssignable(argTypes[i], args[i]) : descriptor + " incompatible with argument location " + i + ": " + args[i]; 311 } 312 HotSpotRuntimeCallTarget runtimeCall = new HotSpotRuntimeCallTarget(descriptor, address, new CallingConvention(temps, 0, ret, args), graalRuntime.getCompilerToVM()); 313 runtimeCalls.put(descriptor, runtimeCall); 314 return runtimeCall; 315 } 316 317 private boolean checkAssignable(Class spec, Value value) { 318 Kind kind = value.getKind(); 319 if (kind == Kind.Illegal) { 320 kind = Kind.Void; 321 } 322 if (WordBase.class.isAssignableFrom(spec)) { 323 return kind == graalRuntime.getTarget().wordKind; 324 } 325 return kind == Kind.fromJavaClass(spec); 326 } 327 328 protected abstract RegisterConfig createRegisterConfig(boolean globalStubConfig); 329 330 public void registerReplacements(Replacements replacements) { 331 if (GraalOptions.IntrinsifyObjectMethods) { 332 replacements.registerSubstitutions(ObjectSubstitutions.class); 333 } 334 if (GraalOptions.IntrinsifySystemMethods) { 335 replacements.registerSubstitutions(SystemSubstitutions.class); 336 } 337 if (GraalOptions.IntrinsifyThreadMethods) { 338 replacements.registerSubstitutions(ThreadSubstitutions.class); 339 } 340 if (GraalOptions.IntrinsifyUnsafeMethods) { 341 replacements.registerSubstitutions(UnsafeSubstitutions.class); 342 } 343 if (GraalOptions.IntrinsifyClassMethods) { 344 replacements.registerSubstitutions(ClassSubstitutions.class); 345 } 346 if (GraalOptions.IntrinsifyAESMethods) { 347 replacements.registerSubstitutions(AESCryptSubstitutions.class); 348 replacements.registerSubstitutions(CipherBlockChainingSubstitutions.class); 349 } 350 if (GraalOptions.IntrinsifyReflectionMethods) { 351 replacements.registerSubstitutions(ReflectionSubstitutions.class); 352 } 353 354 checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, graalRuntime.getTarget()); 355 instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, graalRuntime.getTarget()); 356 newObjectSnippets = new NewObjectSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useTLAB); 357 monitorSnippets = new MonitorSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useFastLocking); 358 writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, replacements, graalRuntime.getTarget()); 359 boxingSnippets = new BoxingSnippets.Templates(this, replacements, graalRuntime.getTarget()); 360 exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, replacements, graalRuntime.getTarget()); 361 362 registerStub(new NewInstanceStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_INSTANCE))); 363 registerStub(new NewArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_ARRAY))); 364 } 365 366 private void registerStub(Stub stub) { 367 stub.getLinkage().setStub(stub); 368 stubs.put(stub.getMethod(), stub); 369 } 370 371 public HotSpotGraalRuntime getGraalRuntime() { 372 return graalRuntime; 373 } 374 375 /** 376 * Gets the register holding the current thread. 377 */ 378 public abstract Register threadRegister(); 379 380 /** 381 * Gets the stack pointer register. 382 */ 383 public abstract Register stackPointerRegister(); 384 385 @Override 386 public String disassemble(CompilationResult compResult, InstalledCode installedCode) { 387 byte[] code = installedCode == null ? Arrays.copyOf(compResult.getTargetCode(), compResult.getTargetCodeSize()) : installedCode.getCode(); 388 long start = installedCode == null ? 0L : installedCode.getStart(); 389 TargetDescription target = graalRuntime.getTarget(); 390 HexCodeFile hcf = new HexCodeFile(code, start, target.arch.getName(), target.wordSize * 8); 391 if (compResult != null) { 392 HexCodeFile.addAnnotations(hcf, compResult.getAnnotations()); 393 addExceptionHandlersComment(compResult, hcf); 394 Register fp = regConfig.getFrameRegister(); 395 RefMapFormatter slotFormatter = new RefMapFormatter(target.arch, target.wordSize, fp, 0); 396 for (Infopoint infopoint : compResult.getInfopoints()) { 397 if (infopoint instanceof Call) { 398 Call call = (Call) infopoint; 399 if (call.debugInfo != null) { 400 hcf.addComment(call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString()); 401 } 402 addOperandComment(hcf, call.pcOffset, "{" + getTargetName(call) + "}"); 403 } else { 404 if (infopoint.debugInfo != null) { 405 hcf.addComment(infopoint.pcOffset, CodeUtil.append(new StringBuilder(100), infopoint.debugInfo, slotFormatter).toString()); 406 } 407 addOperandComment(hcf, infopoint.pcOffset, "{infopoint: " + infopoint.reason + "}"); 408 } 409 } 410 for (DataPatch site : compResult.getDataReferences()) { 411 hcf.addOperandComment(site.pcOffset, "{" + site.constant + "}"); 412 } 413 for (Mark mark : compResult.getMarks()) { 414 hcf.addComment(mark.pcOffset, getMarkName(mark)); 415 } 416 } 417 return hcf.toEmbeddedString(); 418 } 419 420 /** 421 * Decodes a call target to a mnemonic if possible. 422 */ 423 private String getTargetName(Call call) { 424 Field[] fields = config.getClass().getDeclaredFields(); 425 for (Field f : fields) { 426 if (f.getName().endsWith("Stub")) { 427 f.setAccessible(true); 428 try { 429 Object address = f.get(config); 430 if (address.equals(call.target)) { 431 return f.getName() + ":0x" + Long.toHexString((Long) address); 432 } 433 } catch (Exception e) { 434 } 435 } 436 } 437 return String.valueOf(call.target); 438 } 439 440 /** 441 * Decodes a mark to a mnemonic if possible. 442 */ 443 private static String getMarkName(Mark mark) { 444 Field[] fields = Marks.class.getDeclaredFields(); 445 for (Field f : fields) { 446 if (Modifier.isStatic(f.getModifiers()) && f.getName().startsWith("MARK_")) { 447 f.setAccessible(true); 448 try { 449 if (f.get(null).equals(mark.id)) { 450 return f.getName(); 451 } 452 } catch (Exception e) { 453 } 454 } 455 } 456 return "MARK:" + mark.id; 457 } 458 459 private static void addExceptionHandlersComment(CompilationResult tm, HexCodeFile hcf) { 460 if (!tm.getExceptionHandlers().isEmpty()) { 461 String nl = HexCodeFile.NEW_LINE; 462 StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl); 463 for (CompilationResult.ExceptionHandler e : tm.getExceptionHandlers()) { 464 buf.append(" ").append(e.pcOffset).append(" -> ").append(e.handlerPos).append(nl); 465 hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]"); 466 hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]"); 467 } 468 hcf.addComment(0, buf.toString()); 469 } 470 } 471 472 private static void addOperandComment(HexCodeFile hcf, int pos, String comment) { 473 String oldValue = hcf.addOperandComment(pos, comment); 474 assert oldValue == null : "multiple comments for operand of instruction at " + pos + ": " + comment + ", " + oldValue; 475 } 476 477 @Override 478 public ResolvedJavaType lookupJavaType(Constant constant) { 479 if (constant.getKind() != Kind.Object || constant.isNull()) { 480 return null; 481 } 482 Object o = constant.asObject(); 483 return HotSpotResolvedObjectType.fromClass(o.getClass()); 484 } 485 486 @Override 487 public Signature parseMethodDescriptor(String signature) { 488 return new HotSpotSignature(signature); 489 } 490 491 @Override 492 public boolean constantEquals(Constant x, Constant y) { 493 return x.equals(y); 494 } 495 496 @Override 497 public RegisterConfig lookupRegisterConfig() { 498 return regConfig; 499 } 500 501 @Override 502 public int getMinimumOutgoingSize() { 503 return config.runtimeCallStackSize; 504 } 505 506 @Override 507 public int lookupArrayLength(Constant array) { 508 if (array.getKind() != Kind.Object || array.isNull() || !array.asObject().getClass().isArray()) { 509 throw new IllegalArgumentException(array + " is not an array"); 510 } 511 return Array.getLength(array.asObject()); 512 } 513 514 @Override 515 public void lower(Node n, LoweringTool tool) { 516 StructuredGraph graph = (StructuredGraph) n.graph(); 517 Kind wordKind = graalRuntime.getTarget().wordKind; 518 if (n instanceof ArrayLengthNode) { 519 ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n; 520 ValueNode array = arrayLengthNode.array(); 521 ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt())); 522 arrayLengthRead.dependencies().add(tool.createNullCheckGuard(array)); 523 graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead); 524 } else if (n instanceof Invoke) { 525 Invoke invoke = (Invoke) n; 526 if (invoke.callTarget() instanceof MethodCallTargetNode) { 527 MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); 528 NodeInputList<ValueNode> parameters = callTarget.arguments(); 529 ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); 530 if (!callTarget.isStatic() && receiver.kind() == Kind.Object && !receiver.objectStamp().nonNull()) { 531 invoke.asNode().dependencies().add(tool.createNullCheckGuard(receiver)); 532 } 533 JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass()); 534 535 LoweredCallTargetNode loweredCallTarget = null; 536 if (callTarget.invokeKind() == InvokeKind.Virtual && GraalOptions.InlineVTableStubs && (GraalOptions.AlwaysInlineVTableStubs || invoke.isPolymorphic())) { 537 538 HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); 539 if (!hsMethod.getDeclaringClass().isInterface()) { 540 int vtableEntryOffset = hsMethod.vtableEntryOffset(); 541 if (vtableEntryOffset > 0) { 542 // We use LocationNode.ANY_LOCATION for the reads that access the vtable 543 // entry and the compiled code entry 544 // as HotSpot does not guarantee they are final values. 545 assert vtableEntryOffset > 0; 546 LoadHubNode hub = graph.add(new LoadHubNode(receiver, wordKind)); 547 ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph), 548 StampFactory.forKind(wordKind()))); 549 ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph), 550 StampFactory.forKind(wordKind()))); 551 552 loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), 553 CallingConvention.Type.JavaCall)); 554 555 graph.addBeforeFixed(invoke.asNode(), hub); 556 graph.addAfterFixed(hub, metaspaceMethod); 557 graph.addAfterFixed(metaspaceMethod, compiledEntry); 558 } 559 } 560 } 561 562 if (loweredCallTarget == null) { 563 loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall, 564 callTarget.invokeKind())); 565 } 566 callTarget.replaceAndDelete(loweredCallTarget); 567 } 568 } else if (n instanceof LoadFieldNode) { 569 LoadFieldNode loadField = (LoadFieldNode) n; 570 HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field(); 571 ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object(); 572 assert loadField.kind() != Kind.Illegal; 573 ReadNode memoryRead = graph.add(new ReadNode(object, ConstantLocationNode.create(field, field.getKind(), field.offset(), graph), loadField.stamp())); 574 memoryRead.dependencies().add(tool.createNullCheckGuard(object)); 575 576 graph.replaceFixedWithFixed(loadField, memoryRead); 577 578 if (loadField.isVolatile()) { 579 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ)); 580 graph.addBeforeFixed(memoryRead, preMembar); 581 MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ)); 582 graph.addAfterFixed(memoryRead, postMembar); 583 } 584 } else if (n instanceof StoreFieldNode) { 585 StoreFieldNode storeField = (StoreFieldNode) n; 586 HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field(); 587 ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : storeField.object(); 588 LocationNode location = ConstantLocationNode.create(field, field.getKind(), field.offset(), graph); 589 WriteBarrierType barrierType = getFieldStoreBarrierType(storeField); 590 WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), location, barrierType)); 591 memoryWrite.dependencies().add(tool.createNullCheckGuard(object)); 592 memoryWrite.setStateAfter(storeField.stateAfter()); 593 graph.replaceFixedWithFixed(storeField, memoryWrite); 594 FixedWithNextNode last = memoryWrite; 595 FixedWithNextNode first = memoryWrite; 596 597 if (storeField.isVolatile()) { 598 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); 599 graph.addBeforeFixed(first, preMembar); 600 MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE)); 601 graph.addAfterFixed(last, postMembar); 602 } 603 } else if (n instanceof CompareAndSwapNode) { 604 // Separate out GC barrier semantics 605 CompareAndSwapNode cas = (CompareAndSwapNode) n; 606 LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1); 607 cas.setLocation(location); 608 cas.setWriteBarrierType(getCompareAndSwapBarrier(cas)); 609 } else if (n instanceof LoadIndexedNode) { 610 LoadIndexedNode loadIndexed = (LoadIndexedNode) n; 611 ValueNode boundsCheck = createBoundsCheck(loadIndexed, tool); 612 Kind elementKind = loadIndexed.elementKind(); 613 LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index()); 614 ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp())); 615 memoryRead.dependencies().add(boundsCheck); 616 graph.replaceFixedWithFixed(loadIndexed, memoryRead); 617 } else if (n instanceof StoreIndexedNode) { 618 StoreIndexedNode storeIndexed = (StoreIndexedNode) n; 619 ValueNode boundsCheck = createBoundsCheck(storeIndexed, tool); 620 Kind elementKind = storeIndexed.elementKind(); 621 LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index()); 622 ValueNode value = storeIndexed.value(); 623 ValueNode array = storeIndexed.array(); 624 if (elementKind == Kind.Object && !value.objectStamp().alwaysNull()) { 625 // Store check! 626 ResolvedJavaType arrayType = array.objectStamp().type(); 627 if (arrayType != null && array.objectStamp().isExactType()) { 628 ResolvedJavaType elementType = arrayType.getComponentType(); 629 if (!MetaUtil.isJavaLangObject(elementType)) { 630 CheckCastNode checkcast = graph.add(new CheckCastNode(elementType, value, null)); 631 graph.addBeforeFixed(storeIndexed, checkcast); 632 value = checkcast; 633 } 634 } else { 635 LoadHubNode arrayClass = graph.add(new LoadHubNode(array, wordKind)); 636 LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph); 637 FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind()))); 638 CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value)); 639 graph.addBeforeFixed(storeIndexed, checkcast); 640 graph.addBeforeFixed(checkcast, arrayClass); 641 value = checkcast; 642 } 643 } 644 WriteBarrierType barrierType = getArrayStoreBarrierType(storeIndexed); 645 WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType)); 646 memoryWrite.dependencies().add(boundsCheck); 647 memoryWrite.setStateAfter(storeIndexed.stateAfter()); 648 graph.replaceFixedWithFixed(storeIndexed, memoryWrite); 649 650 } else if (n instanceof UnsafeLoadNode) { 651 UnsafeLoadNode load = (UnsafeLoadNode) n; 652 assert load.kind() != Kind.Illegal; 653 IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.accessKind(), load.displacement(), load.offset(), graph, 1); 654 ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp())); 655 // An unsafe read must not floating outside its block as may float above an explicit 656 // null check on its object. 657 memoryRead.dependencies().add(BeginNode.prevBegin(load)); 658 graph.replaceFixedWithFixed(load, memoryRead); 659 } else if (n instanceof UnsafeStoreNode) { 660 UnsafeStoreNode store = (UnsafeStoreNode) n; 661 IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, store.accessKind(), store.displacement(), store.offset(), graph, 1); 662 ValueNode object = store.object(); 663 WriteBarrierType barrierType = getUnsafeStoreBarrierType(store); 664 WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType)); 665 write.setStateAfter(store.stateAfter()); 666 graph.replaceFixedWithFixed(store, write); 667 668 } else if (n instanceof LoadHubNode) { 669 LoadHubNode loadHub = (LoadHubNode) n; 670 assert loadHub.kind() == wordKind; 671 LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph); 672 ValueNode object = loadHub.object(); 673 assert !object.isConstant() || object.asConstant().isNull(); 674 ValueNode guard = tool.createNullCheckGuard(object); 675 ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind()))); 676 hub.dependencies().add(guard); 677 graph.replaceFixed(loadHub, hub); 678 } else if (n instanceof FixedGuardNode) { 679 FixedGuardNode node = (FixedGuardNode) n; 680 ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated()))); 681 graph.replaceFixedWithFixed(node, newAnchor); 682 } else if (n instanceof CheckCastNode) { 683 checkcastSnippets.lower((CheckCastNode) n, tool); 684 } else if (n instanceof CheckCastDynamicNode) { 685 checkcastSnippets.lower((CheckCastDynamicNode) n); 686 } else if (n instanceof InstanceOfNode) { 687 instanceofSnippets.lower((InstanceOfNode) n, tool); 688 } else if (n instanceof InstanceOfDynamicNode) { 689 instanceofSnippets.lower((InstanceOfDynamicNode) n, tool); 690 } else if (n instanceof NewInstanceNode) { 691 newObjectSnippets.lower((NewInstanceNode) n, tool); 692 } else if (n instanceof NewArrayNode) { 693 newObjectSnippets.lower((NewArrayNode) n, tool); 694 } else if (n instanceof MonitorEnterNode) { 695 monitorSnippets.lower((MonitorEnterNode) n, tool); 696 } else if (n instanceof MonitorExitNode) { 697 monitorSnippets.lower((MonitorExitNode) n, tool); 698 } else if (n instanceof SerialWriteBarrier) { 699 writeBarrierSnippets.lower((SerialWriteBarrier) n, tool); 700 } else if (n instanceof SerialArrayRangeWriteBarrier) { 701 writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool); 702 } else if (n instanceof TLABAllocateNode) { 703 newObjectSnippets.lower((TLABAllocateNode) n, tool); 704 } else if (n instanceof InitializeObjectNode) { 705 newObjectSnippets.lower((InitializeObjectNode) n, tool); 706 } else if (n instanceof InitializeArrayNode) { 707 newObjectSnippets.lower((InitializeArrayNode) n, tool); 708 } else if (n instanceof NewMultiArrayNode) { 709 newObjectSnippets.lower((NewMultiArrayNode) n, tool); 710 } else if (n instanceof LoadExceptionObjectNode) { 711 exceptionObjectSnippets.lower((LoadExceptionObjectNode) n); 712 } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) { 713 // Nothing to do for division nodes. The HotSpot signal handler catches divisions by 714 // zero and the MIN_VALUE / -1 cases. 715 } else if (n instanceof UnwindNode || n instanceof DeoptimizeNode) { 716 // Nothing to do, using direct LIR lowering for these nodes. 717 } else if (n instanceof BoxNode) { 718 boxingSnippets.lower((BoxNode) n); 719 } else if (n instanceof UnboxNode) { 720 boxingSnippets.lower((UnboxNode) n); 721 } else { 722 assert false : "Node implementing Lowerable not handled: " + n; 723 throw GraalInternalError.shouldNotReachHere(); 724 } 725 } 726 727 private static WriteBarrierType getFieldStoreBarrierType(StoreFieldNode storeField) { 728 WriteBarrierType barrierType = WriteBarrierType.NONE; 729 if (storeField.field().getKind() == Kind.Object && !storeField.value().objectStamp().alwaysNull()) { 730 barrierType = WriteBarrierType.IMPRECISE; 731 } 732 return barrierType; 733 } 734 735 private static WriteBarrierType getArrayStoreBarrierType(StoreIndexedNode store) { 736 WriteBarrierType barrierType = WriteBarrierType.NONE; 737 if (store.elementKind() == Kind.Object && !store.value().objectStamp().alwaysNull()) { 738 barrierType = WriteBarrierType.PRECISE; 739 } 740 return barrierType; 741 } 742 743 private static WriteBarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) { 744 WriteBarrierType barrierType = WriteBarrierType.NONE; 745 if (store.value().kind() == Kind.Object && !store.value().objectStamp().alwaysNull()) { 746 ResolvedJavaType type = store.object().objectStamp().type(); 747 if (type != null && type.isArray()) { 748 barrierType = WriteBarrierType.PRECISE; 749 } else { 750 barrierType = WriteBarrierType.IMPRECISE; 751 } 752 } 753 return barrierType; 754 } 755 756 private static WriteBarrierType getCompareAndSwapBarrier(CompareAndSwapNode cas) { 757 WriteBarrierType barrierType = WriteBarrierType.NONE; 758 if (cas.expected().kind() == Kind.Object && !cas.newValue().objectStamp().alwaysNull()) { 759 ResolvedJavaType type = cas.object().objectStamp().type(); 760 if (type != null && type.isArray()) { 761 barrierType = WriteBarrierType.PRECISE; 762 } else { 763 barrierType = WriteBarrierType.IMPRECISE; 764 } 765 } 766 return barrierType; 767 } 768 769 private IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) { 770 int scale = this.graalRuntime.getTarget().sizeInBytes(elementKind); 771 return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale); 772 } 773 774 private static ValueNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) { 775 StructuredGraph graph = (StructuredGraph) n.graph(); 776 ArrayLengthNode arrayLength = graph.add(new ArrayLengthNode(n.array())); 777 ValueNode guard = tool.createGuard(graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile); 778 779 graph.addBeforeFixed(n, arrayLength); 780 return guard; 781 } 782 783 public ResolvedJavaType lookupJavaType(Class<?> clazz) { 784 return HotSpotResolvedObjectType.fromClass(clazz); 785 } 786 787 /** 788 * Gets the stub corresponding to a given method. 789 * 790 * @return the stub {@linkplain Stub#getMethod() implemented} by {@code method} or null if 791 * {@code method} does not implement a stub 792 */ 793 public Stub asStub(ResolvedJavaMethod method) { 794 return stubs.get(method); 795 } 796 797 public HotSpotRuntimeCallTarget lookupRuntimeCall(Descriptor descriptor) { 798 HotSpotRuntimeCallTarget callTarget = runtimeCalls.get(descriptor); 799 assert runtimeCalls != null : descriptor; 800 callTarget.finalizeAddress(graalRuntime.getBackend()); 801 return callTarget; 802 } 803 804 public ResolvedJavaMethod lookupJavaMethod(Method reflectionMethod) { 805 CompilerToVM c2vm = graalRuntime.getCompilerToVM(); 806 HotSpotResolvedObjectType[] resultHolder = {null}; 807 long metaspaceMethod = c2vm.getMetaspaceMethod(reflectionMethod, resultHolder); 808 assert metaspaceMethod != 0L; 809 return resultHolder[0].createMethod(metaspaceMethod); 810 } 811 812 public ResolvedJavaMethod lookupJavaConstructor(Constructor reflectionConstructor) { 813 CompilerToVM c2vm = graalRuntime.getCompilerToVM(); 814 HotSpotResolvedObjectType[] resultHolder = {null}; 815 long metaspaceMethod = c2vm.getMetaspaceConstructor(reflectionConstructor, resultHolder); 816 assert metaspaceMethod != 0L; 817 return resultHolder[0].createMethod(metaspaceMethod); 818 } 819 820 public ResolvedJavaField lookupJavaField(Field reflectionField) { 821 return graalRuntime.getCompilerToVM().getJavaField(reflectionField); 822 } 823 824 public HotSpotInstalledCode installMethod(HotSpotResolvedJavaMethod method, Graph graph, int entryBCI, CompilationResult compResult) { 825 HotSpotInstalledCode installedCode = new HotSpotInstalledCode(method, graph, true); 826 graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(method, entryBCI, compResult), installedCode, method.getSpeculationLog()); 827 return installedCode; 828 } 829 830 @Override 831 public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult) { 832 return addMethod(method, compResult, null); 833 } 834 835 @Override 836 public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, Graph graph) { 837 HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; 838 HotSpotInstalledCode code = new HotSpotInstalledCode(hotspotMethod, graph, false); 839 CodeInstallResult result = graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(hotspotMethod, -1, compResult), code, null); 840 if (result != CodeInstallResult.OK) { 841 return null; 842 } 843 return code; 844 } 845 846 @Override 847 public int encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason) { 848 final int actionShift = 0; 849 final int reasonShift = 3; 850 851 int actionValue = convertDeoptAction(action); 852 int reasonValue = convertDeoptReason(reason); 853 return (~(((reasonValue) << reasonShift) + ((actionValue) << actionShift))); 854 } 855 856 public int convertDeoptAction(DeoptimizationAction action) { 857 switch (action) { 858 case None: 859 return config.deoptActionNone; 860 case RecompileIfTooManyDeopts: 861 return config.deoptActionMaybeRecompile; 862 case InvalidateReprofile: 863 return config.deoptActionReinterpret; 864 case InvalidateRecompile: 865 return config.deoptActionMakeNotEntrant; 866 case InvalidateStopCompiling: 867 return config.deoptActionMakeNotCompilable; 868 default: 869 throw GraalInternalError.shouldNotReachHere(); 870 } 871 } 872 873 public int convertDeoptReason(DeoptimizationReason reason) { 874 switch (reason) { 875 case None: 876 return config.deoptReasonNone; 877 case NullCheckException: 878 return config.deoptReasonNullCheck; 879 case BoundsCheckException: 880 return config.deoptReasonRangeCheck; 881 case ClassCastException: 882 return config.deoptReasonClassCheck; 883 case ArrayStoreException: 884 return config.deoptReasonArrayCheck; 885 case UnreachedCode: 886 return config.deoptReasonUnreached0; 887 case TypeCheckedInliningViolated: 888 return config.deoptReasonTypeCheckInlining; 889 case OptimizedTypeCheckViolated: 890 return config.deoptReasonOptimizedTypeCheck; 891 case NotCompiledExceptionHandler: 892 return config.deoptReasonNotCompiledExceptionHandler; 893 case Unresolved: 894 return config.deoptReasonUnresolved; 895 case JavaSubroutineMismatch: 896 return config.deoptReasonJsrMismatch; 897 case ArithmeticException: 898 return config.deoptReasonDiv0Check; 899 case RuntimeConstraint: 900 return config.deoptReasonConstraint; 901 default: 902 throw GraalInternalError.shouldNotReachHere(); 903 } 904 } 905 906 public boolean needsDataPatch(Constant constant) { 907 return constant.getPrimitiveAnnotation() != null; 908 } 909 910 /** 911 * Registers an object created by the compiler and referenced by some generated code. HotSpot 912 * treats oops embedded in code as weak references so without an external strong root, such an 913 * embedded oop will quickly die. This in turn will cause the nmethod to be unloaded. 914 */ 915 public synchronized Object registerGCRoot(Object object) { 916 Object existing = gcRoots.get(object); 917 if (existing != null) { 918 return existing; 919 } 920 gcRoots.put(object, object); 921 return object; 922 } 923 924 @Override 925 public Constant readUnsafeConstant(Kind kind, Object base, long displacement) { 926 switch (kind) { 927 case Boolean: 928 return Constant.forBoolean(base == null ? unsafe.getByte(displacement) != 0 : unsafe.getBoolean(base, displacement)); 929 case Byte: 930 return Constant.forByte(base == null ? unsafe.getByte(displacement) : unsafe.getByte(base, displacement)); 931 case Char: 932 return Constant.forChar(base == null ? unsafe.getChar(displacement) : unsafe.getChar(base, displacement)); 933 case Short: 934 return Constant.forShort(base == null ? unsafe.getShort(displacement) : unsafe.getShort(base, displacement)); 935 case Int: 936 return Constant.forInt(base == null ? unsafe.getInt(displacement) : unsafe.getInt(base, displacement)); 937 case Long: 938 return Constant.forLong(base == null ? unsafe.getLong(displacement) : unsafe.getLong(base, displacement)); 939 case Float: 940 return Constant.forFloat(base == null ? unsafe.getFloat(displacement) : unsafe.getFloat(base, displacement)); 941 case Double: 942 return Constant.forDouble(base == null ? unsafe.getDouble(displacement) : unsafe.getDouble(base, displacement)); 943 case Object: 944 return Constant.forObject(unsafe.getObject(base, displacement)); 945 default: 946 throw GraalInternalError.shouldNotReachHere(); 947 } 948 } 949 950 @Override 951 public TargetDescription getTarget() { 952 return graalRuntime.getTarget(); 953 } 954 955 public String disassemble(InstalledCode code) { 956 if (code.isValid()) { 957 long nmethod = ((HotSpotInstalledCode) code).getMethodAddress(); 958 return graalRuntime.getCompilerToVM().disassembleNMethod(nmethod); 959 } 960 return null; 961 } 962 963 public String disassemble(ResolvedJavaMethod method) { 964 return new BytecodeDisassembler().disassemble(method); 965 } 966 }