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