1 /* 2 * Copyright (c) 2015, 2019, 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 jdk.vm.ci.hotspot; 24 25 import static jdk.vm.ci.common.InitTimer.timer; 26 import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; 27 import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; 28 29 import java.io.IOException; 30 import java.io.OutputStream; 31 import java.io.PrintStream; 32 import java.io.Serializable; 33 34 import java.lang.invoke.CallSite; 35 import java.lang.invoke.ConstantCallSite; 36 import java.lang.invoke.MethodHandle; 37 import java.lang.module.ModuleDescriptor.Requires; 38 import java.lang.ref.WeakReference; 39 40 import java.util.ArrayList; 41 import java.util.Collections; 42 import java.util.HashMap; 43 import java.util.HashSet; 44 import java.util.List; 45 import java.util.Map; 46 import java.util.Objects; 47 import java.util.ServiceLoader; 48 import java.util.TreeMap; 49 import java.util.function.Predicate; 50 51 import jdk.internal.misc.Unsafe; 52 53 import jdk.vm.ci.code.Architecture; 54 import jdk.vm.ci.code.CompilationRequestResult; 55 import jdk.vm.ci.code.CompiledCode; 56 import jdk.vm.ci.code.InstalledCode; 57 import jdk.vm.ci.common.InitTimer; 58 import jdk.vm.ci.common.JVMCIError; 59 import jdk.vm.ci.common.NativeImageReinitialize; 60 import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory.CompilationLevel; 61 import jdk.vm.ci.meta.JavaKind; 62 import jdk.vm.ci.meta.JavaType; 63 import jdk.vm.ci.meta.ResolvedJavaType; 64 import jdk.vm.ci.meta.UnresolvedJavaType; 65 import jdk.vm.ci.runtime.JVMCI; 66 import jdk.vm.ci.runtime.JVMCIBackend; 67 import jdk.vm.ci.runtime.JVMCICompiler; 68 import jdk.vm.ci.runtime.JVMCICompilerFactory; 69 import jdk.vm.ci.runtime.JVMCIRuntime; 70 import jdk.vm.ci.services.JVMCIServiceLocator; 71 import jdk.vm.ci.services.Services; 72 73 /** 74 * HotSpot implementation of a JVMCI runtime. 75 */ 76 public final class HotSpotJVMCIRuntime implements JVMCIRuntime { 77 78 /** 79 * Singleton instance lazily initialized via double-checked locking. 80 */ 81 @NativeImageReinitialize private static volatile HotSpotJVMCIRuntime instance; 82 83 private HotSpotResolvedObjectTypeImpl javaLangObject; 84 private HotSpotResolvedObjectTypeImpl javaLangInvokeMethodHandle; 85 private HotSpotResolvedObjectTypeImpl constantCallSiteType; 86 private HotSpotResolvedObjectTypeImpl callSiteType; 87 private HotSpotResolvedObjectTypeImpl javaLangString; 88 private HotSpotResolvedObjectTypeImpl javaLangClass; 89 private HotSpotResolvedObjectTypeImpl throwableType; 90 private HotSpotResolvedObjectTypeImpl serializableType; 91 private HotSpotResolvedObjectTypeImpl cloneableType; 92 private HotSpotResolvedObjectTypeImpl enumType; 93 94 HotSpotResolvedObjectTypeImpl getJavaLangObject() { 95 if (javaLangObject == null) { 96 javaLangObject = (HotSpotResolvedObjectTypeImpl) fromClass(Object.class); 97 } 98 return javaLangObject; 99 } 100 101 HotSpotResolvedObjectTypeImpl getJavaLangString() { 102 if (javaLangString == null) { 103 javaLangString = (HotSpotResolvedObjectTypeImpl) fromClass(String.class); 104 } 105 return javaLangString; 106 } 107 108 HotSpotResolvedObjectTypeImpl getJavaLangClass() { 109 if (javaLangClass == null) { 110 javaLangClass = (HotSpotResolvedObjectTypeImpl) fromClass(Class.class); 111 } 112 return javaLangClass; 113 } 114 115 HotSpotResolvedObjectTypeImpl getJavaLangCloneable() { 116 if (cloneableType == null) { 117 cloneableType = (HotSpotResolvedObjectTypeImpl) fromClass(Cloneable.class); 118 } 119 return cloneableType; 120 } 121 122 HotSpotResolvedObjectTypeImpl getJavaLangSerializable() { 123 if (serializableType == null) { 124 serializableType = (HotSpotResolvedObjectTypeImpl) fromClass(Serializable.class); 125 } 126 return serializableType; 127 } 128 129 HotSpotResolvedObjectTypeImpl getJavaLangThrowable() { 130 if (throwableType == null) { 131 throwableType = (HotSpotResolvedObjectTypeImpl) fromClass(Throwable.class); 132 } 133 return throwableType; 134 } 135 136 HotSpotResolvedObjectTypeImpl getJavaLangEnum() { 137 if (enumType == null) { 138 enumType = (HotSpotResolvedObjectTypeImpl) fromClass(Enum.class); 139 } 140 return enumType; 141 } 142 143 HotSpotResolvedObjectTypeImpl getConstantCallSite() { 144 if (constantCallSiteType == null) { 145 constantCallSiteType = (HotSpotResolvedObjectTypeImpl) fromClass(ConstantCallSite.class); 146 } 147 return constantCallSiteType; 148 } 149 150 HotSpotResolvedObjectTypeImpl getCallSite() { 151 if (callSiteType == null) { 152 callSiteType = (HotSpotResolvedObjectTypeImpl) fromClass(CallSite.class); 153 } 154 return callSiteType; 155 } 156 157 HotSpotResolvedObjectType getMethodHandleClass() { 158 if (javaLangInvokeMethodHandle == null) { 159 javaLangInvokeMethodHandle = (HotSpotResolvedObjectTypeImpl) fromClass(MethodHandle.class); 160 } 161 return javaLangInvokeMethodHandle; 162 } 163 164 /** 165 * Gets the singleton {@link HotSpotJVMCIRuntime} object. 166 */ 167 @VMEntryPoint 168 @SuppressWarnings("try") 169 public static HotSpotJVMCIRuntime runtime() { 170 HotSpotJVMCIRuntime result = instance; 171 if (result == null) { 172 // Synchronize on JVMCI.class to avoid deadlock 173 // between the two JVMCI initialization paths: 174 // HotSpotJVMCIRuntime.runtime() and JVMCI.getRuntime(). 175 synchronized (JVMCI.class) { 176 result = instance; 177 if (result == null) { 178 try (InitTimer t = timer("HotSpotJVMCIRuntime.<init>")) { 179 instance = result = new HotSpotJVMCIRuntime(); 180 181 // Can only do eager initialization of the JVMCI compiler 182 // once the singleton instance is available. 183 if (instance.config.getFlag("EagerJVMCI", Boolean.class)) { 184 instance.getCompiler(); 185 } 186 } 187 // Ensures JVMCIRuntime::_HotSpotJVMCIRuntime_instance is 188 // initialized. 189 JVMCI.getRuntime(); 190 } 191 } 192 } 193 return result; 194 } 195 196 @VMEntryPoint 197 static Throwable decodeThrowable(String encodedThrowable) throws Throwable { 198 return TranslatedException.decodeThrowable(encodedThrowable); 199 } 200 201 @VMEntryPoint 202 static String encodeThrowable(Throwable throwable) throws Throwable { 203 return TranslatedException.encodeThrowable(throwable); 204 } 205 206 @VMEntryPoint 207 static String callToString(Object o) { 208 return o.toString(); 209 } 210 211 /** 212 * A list of all supported JVMCI options. 213 */ 214 public enum Option { 215 // @formatter:off 216 Compiler(String.class, null, "Selects the system compiler. This must match the getCompilerName() value returned " + 217 "by a jdk.vm.ci.runtime.JVMCICompilerFactory provider. " + 218 "An empty string or the value \"null\" selects a compiler " + 219 "that will raise an exception upon receiving a compilation request."), 220 // Note: The following one is not used (see InitTimer.ENABLED). It is added here 221 // so that -XX:+JVMCIPrintProperties shows the option. 222 InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."), 223 PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."), 224 TraceMethodDataFilter(String.class, null, 225 "Enables tracing of profiling info when read by JVMCI.", 226 "Empty value: trace all methods", 227 "Non-empty value: trace methods whose fully qualified name contains the value."), 228 UseProfilingInformation(Boolean.class, true, ""); 229 // @formatter:on 230 231 /** 232 * The prefix for system properties that are JVMCI options. 233 */ 234 private static final String JVMCI_OPTION_PROPERTY_PREFIX = "jvmci."; 235 236 /** 237 * Sentinel for value initialized to {@code null} since {@code null} means uninitialized. 238 */ 239 private static final String NULL_VALUE = "NULL"; 240 241 private final Class<?> type; 242 @NativeImageReinitialize private Object value; 243 private final Object defaultValue; 244 private boolean isDefault; 245 private final String[] helpLines; 246 247 Option(Class<?> type, Object defaultValue, String... helpLines) { 248 assert Character.isUpperCase(name().charAt(0)) : "Option name must start with upper-case letter: " + name(); 249 this.type = type; 250 this.defaultValue = defaultValue; 251 this.helpLines = helpLines; 252 } 253 254 @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum") 255 private Object getValue() { 256 if (value == null) { 257 String propertyValue = Services.getSavedProperty(getPropertyName()); 258 if (propertyValue == null) { 259 this.value = defaultValue == null ? NULL_VALUE : defaultValue; 260 this.isDefault = true; 261 } else { 262 if (type == Boolean.class) { 263 this.value = Boolean.parseBoolean(propertyValue); 264 } else if (type == String.class) { 265 this.value = propertyValue; 266 } else { 267 throw new JVMCIError("Unexpected option type " + type); 268 } 269 this.isDefault = false; 270 } 271 } 272 return value == NULL_VALUE ? null : value; 273 } 274 275 /** 276 * Gets the name of system property from which this option gets its value. 277 */ 278 public String getPropertyName() { 279 return JVMCI_OPTION_PROPERTY_PREFIX + name(); 280 } 281 282 /** 283 * Returns the option's value as boolean. 284 * 285 * @return option's value 286 */ 287 public boolean getBoolean() { 288 return (boolean) getValue(); 289 } 290 291 /** 292 * Returns the option's value as String. 293 * 294 * @return option's value 295 */ 296 public String getString() { 297 return (String) getValue(); 298 } 299 300 private static final int PROPERTY_LINE_WIDTH = 80; 301 private static final int PROPERTY_HELP_INDENT = 10; 302 303 /** 304 * Prints a description of the properties used to configure shared JVMCI code. 305 * 306 * @param out stream to print to 307 */ 308 public static void printProperties(PrintStream out) { 309 out.println("[JVMCI properties]"); 310 Option[] values = values(); 311 for (Option option : values) { 312 Object value = option.getValue(); 313 if (value instanceof String) { 314 value = '"' + String.valueOf(value) + '"'; 315 } 316 317 String name = option.getPropertyName(); 318 String assign = option.isDefault ? "=" : ":="; 319 String typeName = option.type.getSimpleName(); 320 String linePrefix = String.format("%s %s %s ", name, assign, value); 321 int typeStartPos = PROPERTY_LINE_WIDTH - typeName.length(); 322 int linePad = typeStartPos - linePrefix.length(); 323 if (linePad > 0) { 324 out.printf("%s%-" + linePad + "s[%s]%n", linePrefix, "", typeName); 325 } else { 326 out.printf("%s[%s]%n", linePrefix, typeName); 327 } 328 for (String line : option.helpLines) { 329 out.printf("%" + PROPERTY_HELP_INDENT + "s%s%n", "", line); 330 } 331 } 332 } 333 } 334 335 private static HotSpotJVMCIBackendFactory findFactory(String architecture) { 336 Iterable<HotSpotJVMCIBackendFactory> factories = getHotSpotJVMCIBackendFactories(); 337 assert factories != null : "sanity"; 338 for (HotSpotJVMCIBackendFactory factory : factories) { 339 if (factory.getArchitecture().equalsIgnoreCase(architecture)) { 340 return factory; 341 } 342 } 343 344 throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture); 345 } 346 347 private static volatile List<HotSpotJVMCIBackendFactory> cachedHotSpotJVMCIBackendFactories; 348 349 @SuppressFBWarnings(value = "LI_LAZY_INIT_UPDATE_STATIC", justification = "not sure about this") 350 private static Iterable<HotSpotJVMCIBackendFactory> getHotSpotJVMCIBackendFactories() { 351 if (IS_IN_NATIVE_IMAGE || cachedHotSpotJVMCIBackendFactories != null) { 352 return cachedHotSpotJVMCIBackendFactories; 353 } 354 Iterable<HotSpotJVMCIBackendFactory> result = Services.load(HotSpotJVMCIBackendFactory.class); 355 if (IS_BUILDING_NATIVE_IMAGE) { 356 cachedHotSpotJVMCIBackendFactories = new ArrayList<>(); 357 for (HotSpotJVMCIBackendFactory factory : result) { 358 cachedHotSpotJVMCIBackendFactories.add(factory); 359 } 360 } 361 return result; 362 } 363 364 /** 365 * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend. 366 */ 367 public static JavaKind getHostWordKind() { 368 return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordJavaKind; 369 } 370 371 protected final CompilerToVM compilerToVm; 372 373 protected final HotSpotVMConfigStore configStore; 374 protected final HotSpotVMConfig config; 375 private final JVMCIBackend hostBackend; 376 377 private final JVMCICompilerFactory compilerFactory; 378 private final HotSpotJVMCICompilerFactory hsCompilerFactory; 379 private volatile JVMCICompiler compiler; 380 protected final HotSpotJVMCIReflection reflection; 381 382 @NativeImageReinitialize private volatile boolean creatingCompiler; 383 384 /** 385 * Cache for speeding up {@link #fromClass(Class)}. 386 */ 387 @NativeImageReinitialize private volatile ClassValue<WeakReference<HotSpotResolvedJavaType>> resolvedJavaType; 388 389 @NativeImageReinitialize private HashMap<Long, WeakReference<ResolvedJavaType>> resolvedJavaTypes; 390 391 /** 392 * Stores the result of {@link HotSpotJVMCICompilerFactory#getCompilationLevelAdjustment} so 393 * that it can be read from the VM. 394 */ 395 @SuppressWarnings("unused") private final int compilationLevelAdjustment; 396 397 private final Map<Class<? extends Architecture>, JVMCIBackend> backends = new HashMap<>(); 398 399 private volatile List<HotSpotVMEventListener> vmEventListeners; 400 401 private Iterable<HotSpotVMEventListener> getVmEventListeners() { 402 if (vmEventListeners == null) { 403 synchronized (this) { 404 if (vmEventListeners == null) { 405 vmEventListeners = JVMCIServiceLocator.getProviders(HotSpotVMEventListener.class); 406 } 407 } 408 } 409 return vmEventListeners; 410 } 411 412 @SuppressWarnings("try") 413 private HotSpotJVMCIRuntime() { 414 compilerToVm = new CompilerToVM(); 415 416 try (InitTimer t = timer("HotSpotVMConfig<init>")) { 417 configStore = new HotSpotVMConfigStore(compilerToVm); 418 config = new HotSpotVMConfig(configStore); 419 } 420 421 reflection = IS_IN_NATIVE_IMAGE ? new SharedLibraryJVMCIReflection() : new HotSpotJDKReflection(); 422 423 PrintStream vmLogStream = null; 424 if (IS_IN_NATIVE_IMAGE) { 425 // Redirect System.out and System.err to HotSpot's TTY stream 426 vmLogStream = new PrintStream(getLogStream()); 427 System.setOut(vmLogStream); 428 System.setErr(vmLogStream); 429 } 430 431 String hostArchitecture = config.getHostArchitectureName(); 432 433 HotSpotJVMCIBackendFactory factory; 434 try (InitTimer t = timer("find factory:", hostArchitecture)) { 435 factory = findFactory(hostArchitecture); 436 } 437 438 try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) { 439 hostBackend = registerBackend(factory.createJVMCIBackend(this, null)); 440 } 441 442 compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory(); 443 if (compilerFactory instanceof HotSpotJVMCICompilerFactory) { 444 hsCompilerFactory = (HotSpotJVMCICompilerFactory) compilerFactory; 445 switch (hsCompilerFactory.getCompilationLevelAdjustment()) { 446 case None: 447 compilationLevelAdjustment = config.compLevelAdjustmentNone; 448 break; 449 case ByHolder: 450 compilationLevelAdjustment = config.compLevelAdjustmentByHolder; 451 break; 452 case ByFullSignature: 453 compilationLevelAdjustment = config.compLevelAdjustmentByFullSignature; 454 break; 455 default: 456 compilationLevelAdjustment = config.compLevelAdjustmentNone; 457 break; 458 } 459 } else { 460 hsCompilerFactory = null; 461 compilationLevelAdjustment = config.compLevelAdjustmentNone; 462 } 463 464 if (config.getFlag("JVMCIPrintProperties", Boolean.class)) { 465 if (vmLogStream == null) { 466 vmLogStream = new PrintStream(getLogStream()); 467 } 468 Option.printProperties(vmLogStream); 469 compilerFactory.printProperties(vmLogStream); 470 System.exit(0); 471 } 472 473 if (Option.PrintConfig.getBoolean()) { 474 printConfig(configStore, compilerToVm); 475 } 476 } 477 478 HotSpotResolvedJavaType createClass(Class<?> javaClass) { 479 if (javaClass.isPrimitive()) { 480 return HotSpotResolvedPrimitiveType.forKind(JavaKind.fromJavaClass(javaClass)); 481 } 482 if (IS_IN_NATIVE_IMAGE) { 483 try { 484 return compilerToVm.lookupType(javaClass.getName().replace('.', '/'), null, true); 485 } catch (ClassNotFoundException e) { 486 throw new JVMCIError(e); 487 } 488 } 489 return compilerToVm.lookupClass(javaClass); 490 } 491 492 private HotSpotResolvedJavaType fromClass0(Class<?> javaClass) { 493 if (resolvedJavaType == null) { 494 synchronized (this) { 495 if (resolvedJavaType == null) { 496 resolvedJavaType = new ClassValue<WeakReference<HotSpotResolvedJavaType>>() { 497 @Override 498 protected WeakReference<HotSpotResolvedJavaType> computeValue(Class<?> type) { 499 return new WeakReference<>(createClass(type)); 500 } 501 }; 502 } 503 } 504 } 505 HotSpotResolvedJavaType javaType = null; 506 while (javaType == null) { 507 WeakReference<HotSpotResolvedJavaType> type = resolvedJavaType.get(javaClass); 508 javaType = type.get(); 509 if (javaType == null) { 510 /* 511 * If the referent has become null, clear out the current value and let computeValue 512 * above create a new value. Reload the value in a loop because in theory the 513 * WeakReference referent can be reclaimed at any point. 514 */ 515 resolvedJavaType.remove(javaClass); 516 } 517 } 518 return javaType; 519 } 520 521 /** 522 * Gets the JVMCI mirror for a {@link Class} object. 523 * 524 * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} 525 */ 526 HotSpotResolvedJavaType fromClass(Class<?> javaClass) { 527 if (javaClass == null) { 528 return null; 529 } 530 return fromClass0(javaClass); 531 } 532 533 synchronized HotSpotResolvedObjectTypeImpl fromMetaspace(long klassPointer, String signature) { 534 if (resolvedJavaTypes == null) { 535 resolvedJavaTypes = new HashMap<>(); 536 } 537 assert klassPointer != 0; 538 WeakReference<ResolvedJavaType> klassReference = resolvedJavaTypes.get(klassPointer); 539 HotSpotResolvedObjectTypeImpl javaType = null; 540 if (klassReference != null) { 541 javaType = (HotSpotResolvedObjectTypeImpl) klassReference.get(); 542 } 543 if (javaType == null) { 544 javaType = new HotSpotResolvedObjectTypeImpl(klassPointer, signature); 545 resolvedJavaTypes.put(klassPointer, new WeakReference<>(javaType)); 546 } 547 return javaType; 548 } 549 550 private JVMCIBackend registerBackend(JVMCIBackend backend) { 551 Class<? extends Architecture> arch = backend.getCodeCache().getTarget().arch.getClass(); 552 JVMCIBackend oldValue = backends.put(arch, backend); 553 assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName(); 554 return backend; 555 } 556 557 public HotSpotVMConfigStore getConfigStore() { 558 return configStore; 559 } 560 561 public HotSpotVMConfig getConfig() { 562 return config; 563 } 564 565 public CompilerToVM getCompilerToVM() { 566 return compilerToVm; 567 } 568 569 HotSpotJVMCIReflection getReflection() { 570 return reflection; 571 } 572 573 /** 574 * Gets a predicate that determines if a given type can be considered trusted for the purpose of 575 * intrinsifying methods it declares. 576 * 577 * @param compilerLeafClasses classes in the leaves of the module graph comprising the JVMCI 578 * compiler. 579 */ 580 public Predicate<ResolvedJavaType> getIntrinsificationTrustPredicate(Class<?>... compilerLeafClasses) { 581 return new Predicate<ResolvedJavaType>() { 582 @Override 583 public boolean test(ResolvedJavaType type) { 584 if (type instanceof HotSpotResolvedObjectTypeImpl) { 585 HotSpotResolvedObjectTypeImpl hsType = (HotSpotResolvedObjectTypeImpl) type; 586 return compilerToVm.isTrustedForIntrinsics(hsType); 587 } else { 588 return false; 589 } 590 } 591 }; 592 } 593 594 /** 595 * Get the {@link Class} corresponding to {@code type}. 596 * 597 * @param type the type for which a {@link Class} is requested 598 * @return the original Java class corresponding to {@code type} or {@code null} if this runtime 599 * does not support mapping {@link ResolvedJavaType} instances to {@link Class} 600 * instances 601 */ 602 public Class<?> getMirror(ResolvedJavaType type) { 603 if (type instanceof HotSpotResolvedJavaType && reflection instanceof HotSpotJDKReflection) { 604 return ((HotSpotJDKReflection) reflection).getMirror((HotSpotResolvedJavaType) type); 605 } 606 return null; 607 } 608 609 @Override 610 public JVMCICompiler getCompiler() { 611 if (compiler == null) { 612 synchronized (this) { 613 if (compiler == null) { 614 assert !creatingCompiler : "recursive compiler creation"; 615 creatingCompiler = true; 616 compiler = compilerFactory.createCompiler(this); 617 creatingCompiler = false; 618 } 619 } 620 } 621 return compiler; 622 } 623 624 /** 625 * Converts a name to a Java type. This method attempts to resolve {@code name} to a 626 * {@link ResolvedJavaType}. 627 * 628 * @param name a well formed Java type in {@linkplain JavaType#getName() internal} format 629 * @param accessingType the context of resolution which must be non-null 630 * @param resolve specifies whether resolution failure results in an unresolved type being 631 * return or a {@link LinkageError} being thrown 632 * @return a Java type for {@code name} which is guaranteed to be of type 633 * {@link ResolvedJavaType} if {@code resolve == true} 634 * @throws LinkageError if {@code resolve == true} and the resolution failed 635 * @throws NullPointerException if {@code accessingClass} is {@code null} 636 */ 637 public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { 638 Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class"); 639 return lookupTypeInternal(name, accessingType, resolve); 640 } 641 642 JavaType lookupTypeInternal(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { 643 // If the name represents a primitive type we can short-circuit the lookup. 644 if (name.length() == 1) { 645 JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); 646 return HotSpotResolvedPrimitiveType.forKind(kind); 647 } 648 649 // Resolve non-primitive types in the VM. 650 HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType; 651 try { 652 final HotSpotResolvedJavaType klass = compilerToVm.lookupType(name, hsAccessingType, resolve); 653 654 if (klass == null) { 655 assert resolve == false : name; 656 return UnresolvedJavaType.create(name); 657 } 658 return klass; 659 } catch (ClassNotFoundException e) { 660 throw (NoClassDefFoundError) new NoClassDefFoundError().initCause(e); 661 } 662 } 663 664 @Override 665 public JVMCIBackend getHostJVMCIBackend() { 666 return hostBackend; 667 } 668 669 @Override 670 public <T extends Architecture> JVMCIBackend getJVMCIBackend(Class<T> arch) { 671 assert arch != Architecture.class; 672 return backends.get(arch); 673 } 674 675 public Map<Class<? extends Architecture>, JVMCIBackend> getJVMCIBackends() { 676 return Collections.unmodifiableMap(backends); 677 } 678 679 @VMEntryPoint 680 private int adjustCompilationLevel(Object declaringClass, String name, String signature, boolean isOsr, int level) { 681 CompilationLevel curLevel; 682 if (level == config.compilationLevelNone) { 683 curLevel = CompilationLevel.None; 684 } else if (level == config.compilationLevelSimple) { 685 curLevel = CompilationLevel.Simple; 686 } else if (level == config.compilationLevelLimitedProfile) { 687 curLevel = CompilationLevel.LimitedProfile; 688 } else if (level == config.compilationLevelFullProfile) { 689 curLevel = CompilationLevel.FullProfile; 690 } else if (level == config.compilationLevelFullOptimization) { 691 curLevel = CompilationLevel.FullOptimization; 692 } else { 693 throw JVMCIError.shouldNotReachHere(); 694 } 695 696 switch (hsCompilerFactory.adjustCompilationLevel(declaringClass, name, signature, isOsr, curLevel)) { 697 case None: 698 return config.compilationLevelNone; 699 case Simple: 700 return config.compilationLevelSimple; 701 case LimitedProfile: 702 return config.compilationLevelLimitedProfile; 703 case FullProfile: 704 return config.compilationLevelFullProfile; 705 case FullOptimization: 706 return config.compilationLevelFullOptimization; 707 default: 708 return level; 709 } 710 } 711 712 @VMEntryPoint 713 private HotSpotCompilationRequestResult compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long compileState, int id) { 714 CompilationRequestResult result = getCompiler().compileMethod(new HotSpotCompilationRequest(method, entryBCI, compileState, id)); 715 assert result != null : "compileMethod must always return something"; 716 HotSpotCompilationRequestResult hsResult; 717 if (result instanceof HotSpotCompilationRequestResult) { 718 hsResult = (HotSpotCompilationRequestResult) result; 719 } else { 720 Object failure = result.getFailure(); 721 if (failure != null) { 722 boolean retry = false; // Be conservative with unknown compiler 723 hsResult = HotSpotCompilationRequestResult.failure(failure.toString(), retry); 724 } else { 725 int inlinedBytecodes = -1; 726 hsResult = HotSpotCompilationRequestResult.success(inlinedBytecodes); 727 } 728 } 729 730 return hsResult; 731 } 732 733 /** 734 * Shuts down the runtime. 735 */ 736 @VMEntryPoint 737 private void shutdown() throws Exception { 738 // Cleaners are normally only processed when a new Cleaner is 739 // instantiated so process all remaining cleaners now. 740 Cleaner.clean(); 741 742 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { 743 vmEventListener.notifyShutdown(); 744 } 745 } 746 747 /** 748 * Notify on completion of a bootstrap. 749 */ 750 @VMEntryPoint 751 private void bootstrapFinished() throws Exception { 752 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { 753 vmEventListener.notifyBootstrapFinished(); 754 } 755 } 756 757 /** 758 * Notify on successful install into the CodeCache. 759 * 760 * @param hotSpotCodeCacheProvider 761 * @param installedCode 762 * @param compiledCode 763 */ 764 void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompiledCode compiledCode) { 765 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { 766 vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compiledCode); 767 } 768 } 769 770 @SuppressFBWarnings(value = "DM_DEFAULT_ENCODING", justification = "no localization here please!") 771 private static void printConfigLine(CompilerToVM vm, String format, Object... args) { 772 String line = String.format(format, args); 773 byte[] lineBytes = line.getBytes(); 774 vm.writeDebugOutput(lineBytes, 0, lineBytes.length); 775 vm.flushDebugOutput(); 776 } 777 778 private static void printConfig(HotSpotVMConfigStore store, CompilerToVM vm) { 779 TreeMap<String, VMField> fields = new TreeMap<>(store.getFields()); 780 for (VMField field : fields.values()) { 781 if (!field.isStatic()) { 782 printConfigLine(vm, "[vmconfig:instance field] %s %s {offset=%d[0x%x]}%n", field.type, field.name, field.offset, field.offset); 783 } else { 784 String value = field.value == null ? "null" : field.value instanceof Boolean ? field.value.toString() : String.format("%d[0x%x]", field.value, field.value); 785 printConfigLine(vm, "[vmconfig:static field] %s %s = %s {address=0x%x}%n", field.type, field.name, value, field.address); 786 } 787 } 788 TreeMap<String, VMFlag> flags = new TreeMap<>(store.getFlags()); 789 for (VMFlag flag : flags.values()) { 790 printConfigLine(vm, "[vmconfig:flag] %s %s = %s%n", flag.type, flag.name, flag.value); 791 } 792 TreeMap<String, Long> addresses = new TreeMap<>(store.getAddresses()); 793 for (Map.Entry<String, Long> e : addresses.entrySet()) { 794 printConfigLine(vm, "[vmconfig:address] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue()); 795 } 796 TreeMap<String, Long> constants = new TreeMap<>(store.getConstants()); 797 for (Map.Entry<String, Long> e : constants.entrySet()) { 798 printConfigLine(vm, "[vmconfig:constant] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue()); 799 } 800 for (VMIntrinsicMethod e : store.getIntrinsics()) { 801 printConfigLine(vm, "[vmconfig:intrinsic] %d = %s.%s %s%n", e.id, e.declaringClass, e.name, e.descriptor); 802 } 803 } 804 805 /** 806 * Gets an output stream that writes to HotSpot's {@code tty} stream. 807 */ 808 public OutputStream getLogStream() { 809 return new OutputStream() { 810 811 @Override 812 public void write(byte[] b, int off, int len) throws IOException { 813 if (b == null) { 814 throw new NullPointerException(); 815 } else if (off < 0 || off > b.length || len < 0 || (off + len) > b.length || (off + len) < 0) { 816 throw new IndexOutOfBoundsException(); 817 } else if (len == 0) { 818 return; 819 } 820 compilerToVm.writeDebugOutput(b, off, len); 821 } 822 823 @Override 824 public void write(int b) throws IOException { 825 write(new byte[]{(byte) b}, 0, 1); 826 } 827 828 @Override 829 public void flush() throws IOException { 830 compilerToVm.flushDebugOutput(); 831 } 832 }; 833 } 834 835 /** 836 * Collects the current values of all JVMCI benchmark counters, summed up over all threads. 837 */ 838 public long[] collectCounters() { 839 return compilerToVm.collectCounters(); 840 } 841 842 /** 843 * The offset from the origin of an array to the first element. 844 * 845 * @return the offset in bytes 846 */ 847 public int getArrayBaseOffset(JavaKind kind) { 848 switch (kind) { 849 case Boolean: 850 return compilerToVm.ARRAY_BOOLEAN_BASE_OFFSET; 851 case Byte: 852 return compilerToVm.ARRAY_BYTE_BASE_OFFSET; 853 case Char: 854 return compilerToVm.ARRAY_CHAR_BASE_OFFSET; 855 case Short: 856 return compilerToVm.ARRAY_SHORT_BASE_OFFSET; 857 case Int: 858 return compilerToVm.ARRAY_INT_BASE_OFFSET; 859 case Long: 860 return compilerToVm.ARRAY_LONG_BASE_OFFSET; 861 case Float: 862 return compilerToVm.ARRAY_FLOAT_BASE_OFFSET; 863 case Double: 864 return compilerToVm.ARRAY_DOUBLE_BASE_OFFSET; 865 case Object: 866 return compilerToVm.ARRAY_OBJECT_BASE_OFFSET; 867 default: 868 throw new JVMCIError("%s", kind); 869 } 870 871 } 872 873 /** 874 * The scale used for the index when accessing elements of an array of this kind. 875 * 876 * @return the scale in order to convert the index into a byte offset 877 */ 878 public int getArrayIndexScale(JavaKind kind) { 879 switch (kind) { 880 case Boolean: 881 return compilerToVm.ARRAY_BOOLEAN_INDEX_SCALE; 882 case Byte: 883 return compilerToVm.ARRAY_BYTE_INDEX_SCALE; 884 case Char: 885 return compilerToVm.ARRAY_CHAR_INDEX_SCALE; 886 case Short: 887 return compilerToVm.ARRAY_SHORT_INDEX_SCALE; 888 case Int: 889 return compilerToVm.ARRAY_INT_INDEX_SCALE; 890 case Long: 891 return compilerToVm.ARRAY_LONG_INDEX_SCALE; 892 case Float: 893 return compilerToVm.ARRAY_FLOAT_INDEX_SCALE; 894 case Double: 895 return compilerToVm.ARRAY_DOUBLE_INDEX_SCALE; 896 case Object: 897 return compilerToVm.ARRAY_OBJECT_INDEX_SCALE; 898 default: 899 throw new JVMCIError("%s", kind); 900 901 } 902 } 903 904 /** 905 * Links each native method in {@code clazz} to an implementation in the JVMCI shared library. 906 * <p> 907 * A use case for this is a JVMCI compiler implementation that offers an API to Java code 908 * executing in HotSpot to exercise functionality (mostly) in the JVMCI shared library. For 909 * example: 910 * 911 * <pre> 912 * package com.jcompile; 913 * 914 * import java.lang.reflect.Method; 915 * 916 * public static class JCompile { 917 * static { 918 * HotSpotJVMCIRuntime.runtime().registerNativeMethods(JCompile.class); 919 * } 920 * public static boolean compile(Method method, String[] options) { 921 * // Convert to simpler data types for passing/serializing across native interface 922 * long metaspaceMethodHandle = getHandle(method); 923 * char[] opts = convertToCharArray(options); 924 * return compile(metaspaceMethodHandle, opts); 925 * } 926 * private static native boolean compile0(long metaspaceMethodHandle, char[] options); 927 * 928 * private static long getHandle(Method method) { ... } 929 * private static char[] convertToCharArray(String[] a) { ... } 930 * } 931 * </pre> 932 * 933 * The implementation of the native {@code JCompile.compile0} method would be in the JVMCI 934 * shared library that contains the bulk of the JVMCI compiler. The {@code JCompile.compile0} 935 * implementation will be exported as the following JNI-compatible symbol: 936 * 937 * <pre> 938 * Java_com_jcompile_JCompile_compile0 939 * </pre> 940 * 941 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names" 942 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#creating_the_vm" 943 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#invocation_api_functions" 944 * 945 * 946 * @return an array of 4 longs where the first value is the {@code JavaVM*} value representing 947 * the Java VM in the JVMCI shared library, and the remaining values are the first 3 948 * pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface}) 949 * @throws NullPointerException if {@code clazz == null} 950 * @throws IllegalArgumentException if the current execution context is the JVMCI shared library 951 * or if {@code clazz} is {@link Class#isPrimitive()} 952 * @throws UnsatisfiedLinkError if the JVMCI shared library is not available, a native method in 953 * {@code clazz} is already linked or the JVMCI shared library does not contain a 954 * JNI-compatible symbol for a native method in {@code clazz} 955 */ 956 public long[] registerNativeMethods(Class<?> clazz) { 957 return compilerToVm.registerNativeMethods(clazz); 958 } 959 960 /** 961 * Creates or retrieves an object in the peer runtime that mirrors {@code obj}. The types whose 962 * objects can be translated are: 963 * <ul> 964 * <li>{@link HotSpotResolvedJavaMethodImpl},</li> 965 * <li>{@link HotSpotResolvedObjectTypeImpl},</li> 966 * <li>{@link HotSpotResolvedPrimitiveType},</li> 967 * <li>{@link IndirectHotSpotObjectConstantImpl},</li> 968 * <li>{@link DirectHotSpotObjectConstantImpl} and</li> 969 * <li>{@link HotSpotNmethod}</li> 970 * </ul> 971 * 972 * This mechanism can be used to pass and return values between the HotSpot and JVMCI shared 973 * library runtimes. In the receiving runtime, the value can be converted back to an object with 974 * {@link #unhand(Class, long)}. 975 * 976 * @param obj an object for which an equivalent instance in the peer runtime is requested 977 * @return a JNI global reference to the mirror of {@code obj} in the peer runtime 978 * @throws IllegalArgumentException if {@code obj} is not of a translatable type 979 * 980 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" 981 */ 982 public long translate(Object obj) { 983 return compilerToVm.translate(obj); 984 } 985 986 /** 987 * Dereferences and returns the object referred to by the JNI global reference {@code handle}. 988 * The global reference is deleted prior to returning. Any further use of {@code handle} is 989 * invalid. 990 * 991 * @param handle a JNI global reference to an object in the current runtime 992 * @return the object referred to by {@code handle} 993 * @throws ClassCastException if the returned object cannot be case to {@code type} 994 * 995 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" 996 * 997 */ 998 public <T> T unhand(Class<T> type, long handle) { 999 return type.cast(compilerToVm.unhand(handle)); 1000 } 1001 }