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<WeakReferenceHolder<HotSpotResolvedJavaType>> resolvedJavaType; 387 388 /** 389 * To avoid calling ClassValue.remove to refresh the weak reference, which 390 * under certain circumstances can lead to an infinite loop, we use a 391 * permanent holder with a mutable field that we refresh. 392 */ 393 private static class WeakReferenceHolder<T> { 394 private volatile WeakReference<T> ref; 395 WeakReferenceHolder(T value) { 396 set(value); 397 } 398 void set(T value) { 399 ref = new WeakReference<T>(value); 400 } 401 T get() { 402 return ref.get(); 403 } 404 }; 405 406 @NativeImageReinitialize private HashMap<Long, WeakReference<ResolvedJavaType>> resolvedJavaTypes; 407 408 /** 409 * Stores the value set by {@link #excludeFromJVMCICompilation(Module...)} so that it can 410 * be read from the VM. 411 */ 412 @SuppressWarnings("unused")// 413 @NativeImageReinitialize private Module[] excludeFromJVMCICompilation; 414 415 416 private final Map<Class<? extends Architecture>, JVMCIBackend> backends = new HashMap<>(); 417 418 private volatile List<HotSpotVMEventListener> vmEventListeners; 419 420 private Iterable<HotSpotVMEventListener> getVmEventListeners() { 421 if (vmEventListeners == null) { 422 synchronized (this) { 423 if (vmEventListeners == null) { 424 vmEventListeners = JVMCIServiceLocator.getProviders(HotSpotVMEventListener.class); 425 } 426 } 427 } 428 return vmEventListeners; 429 } 430 431 @SuppressWarnings("try") 432 private HotSpotJVMCIRuntime() { 433 compilerToVm = new CompilerToVM(); 434 435 try (InitTimer t = timer("HotSpotVMConfig<init>")) { 436 configStore = new HotSpotVMConfigStore(compilerToVm); 437 config = new HotSpotVMConfig(configStore); 438 } 439 440 reflection = IS_IN_NATIVE_IMAGE ? new SharedLibraryJVMCIReflection() : new HotSpotJDKReflection(); 441 442 PrintStream vmLogStream = null; 443 if (IS_IN_NATIVE_IMAGE) { 444 // Redirect System.out and System.err to HotSpot's TTY stream 445 vmLogStream = new PrintStream(getLogStream()); 446 System.setOut(vmLogStream); 447 System.setErr(vmLogStream); 448 } 449 450 String hostArchitecture = config.getHostArchitectureName(); 451 452 HotSpotJVMCIBackendFactory factory; 453 try (InitTimer t = timer("find factory:", hostArchitecture)) { 454 factory = findFactory(hostArchitecture); 455 } 456 457 try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) { 458 hostBackend = registerBackend(factory.createJVMCIBackend(this, null)); 459 } 460 461 compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory(); 462 if (compilerFactory instanceof HotSpotJVMCICompilerFactory) { 463 hsCompilerFactory = (HotSpotJVMCICompilerFactory) compilerFactory; 464 if (hsCompilerFactory.getCompilationLevelAdjustment() != None) { 465 String name = HotSpotJVMCICompilerFactory.class.getName(); 466 String msg = String.format("%s.getCompilationLevelAdjustment() is no longer supported. " + 467 "Use %s.excludeFromJVMCICompilation() instead.", name, name); 468 throw new UnsupportedOperationException(msg); 469 } 470 } else { 471 hsCompilerFactory = null; 472 } 473 474 if (config.getFlag("JVMCIPrintProperties", Boolean.class)) { 475 if (vmLogStream == null) { 476 vmLogStream = new PrintStream(getLogStream()); 477 } 478 Option.printProperties(vmLogStream); 479 compilerFactory.printProperties(vmLogStream); 480 System.exit(0); 481 } 482 483 if (Option.PrintConfig.getBoolean()) { 484 configStore.printConfig(); 485 } 486 } 487 488 HotSpotResolvedJavaType createClass(Class<?> javaClass) { 489 if (javaClass.isPrimitive()) { 490 return HotSpotResolvedPrimitiveType.forKind(JavaKind.fromJavaClass(javaClass)); 491 } 492 if (IS_IN_NATIVE_IMAGE) { 493 try { 494 return compilerToVm.lookupType(javaClass.getName().replace('.', '/'), null, true); 495 } catch (ClassNotFoundException e) { 496 throw new JVMCIError(e); 497 } 498 } 499 return compilerToVm.lookupClass(javaClass); 500 } 501 502 private HotSpotResolvedJavaType fromClass0(Class<?> javaClass) { 503 if (resolvedJavaType == null) { 504 synchronized (this) { 505 if (resolvedJavaType == null) { 506 resolvedJavaType = new ClassValue<WeakReferenceHolder<HotSpotResolvedJavaType>>() { 507 @Override 508 protected WeakReferenceHolder<HotSpotResolvedJavaType> computeValue(Class<?> type) { 509 return new WeakReferenceHolder<>(createClass(type)); 510 } 511 }; 512 } 513 } 514 } 515 516 WeakReferenceHolder<HotSpotResolvedJavaType> ref = resolvedJavaType.get(javaClass); 517 HotSpotResolvedJavaType javaType = ref.get(); 518 if (javaType == null) { 519 /* 520 * If the referent has become null, create a new value and 521 * update cached weak reference. 522 */ 523 javaType = createClass(javaClass); 524 ref.set(javaType); 525 } 526 return javaType; 527 } 528 529 /** 530 * Gets the JVMCI mirror for a {@link Class} object. 531 * 532 * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} 533 */ 534 HotSpotResolvedJavaType fromClass(Class<?> javaClass) { 535 if (javaClass == null) { 536 return null; 537 } 538 return fromClass0(javaClass); 539 } 540 541 synchronized HotSpotResolvedObjectTypeImpl fromMetaspace(long klassPointer, String signature) { 542 if (resolvedJavaTypes == null) { 543 resolvedJavaTypes = new HashMap<>(); 544 } 545 assert klassPointer != 0; 546 WeakReference<ResolvedJavaType> klassReference = resolvedJavaTypes.get(klassPointer); 547 HotSpotResolvedObjectTypeImpl javaType = null; 548 if (klassReference != null) { 549 javaType = (HotSpotResolvedObjectTypeImpl) klassReference.get(); 550 } 551 if (javaType == null) { 552 javaType = new HotSpotResolvedObjectTypeImpl(klassPointer, signature); 553 resolvedJavaTypes.put(klassPointer, new WeakReference<>(javaType)); 554 } 555 return javaType; 556 } 557 558 private JVMCIBackend registerBackend(JVMCIBackend backend) { 559 Class<? extends Architecture> arch = backend.getCodeCache().getTarget().arch.getClass(); 560 JVMCIBackend oldValue = backends.put(arch, backend); 561 assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName(); 562 return backend; 563 } 564 565 public HotSpotVMConfigStore getConfigStore() { 566 return configStore; 567 } 568 569 public HotSpotVMConfig getConfig() { 570 return config; 571 } 572 573 public CompilerToVM getCompilerToVM() { 574 return compilerToVm; 575 } 576 577 HotSpotJVMCIReflection getReflection() { 578 return reflection; 579 } 580 581 /** 582 * Gets a predicate that determines if a given type can be considered trusted for the purpose of 583 * intrinsifying methods it declares. 584 * 585 * @param compilerLeafClasses classes in the leaves of the module graph comprising the JVMCI 586 * compiler. 587 */ 588 public Predicate<ResolvedJavaType> getIntrinsificationTrustPredicate(Class<?>... compilerLeafClasses) { 589 return new Predicate<ResolvedJavaType>() { 590 @Override 591 public boolean test(ResolvedJavaType type) { 592 if (type instanceof HotSpotResolvedObjectTypeImpl) { 593 HotSpotResolvedObjectTypeImpl hsType = (HotSpotResolvedObjectTypeImpl) type; 594 return compilerToVm.isTrustedForIntrinsics(hsType); 595 } else { 596 return false; 597 } 598 } 599 }; 600 } 601 602 /** 603 * Get the {@link Class} corresponding to {@code type}. 604 * 605 * @param type the type for which a {@link Class} is requested 606 * @return the original Java class corresponding to {@code type} or {@code null} if this runtime 607 * does not support mapping {@link ResolvedJavaType} instances to {@link Class} 608 * instances 609 */ 610 public Class<?> getMirror(ResolvedJavaType type) { 611 if (type instanceof HotSpotResolvedJavaType && reflection instanceof HotSpotJDKReflection) { 612 return ((HotSpotJDKReflection) reflection).getMirror((HotSpotResolvedJavaType) type); 613 } 614 return null; 615 } 616 617 @Override 618 public JVMCICompiler getCompiler() { 619 if (compiler == null) { 620 synchronized (this) { 621 if (compiler == null) { 622 assert !creatingCompiler : "recursive compiler creation"; 623 creatingCompiler = true; 624 compiler = compilerFactory.createCompiler(this); 625 creatingCompiler = false; 626 } 627 } 628 } 629 return compiler; 630 } 631 632 /** 633 * Converts a name to a Java type. This method attempts to resolve {@code name} to a 634 * {@link ResolvedJavaType}. 635 * 636 * @param name a well formed Java type in {@linkplain JavaType#getName() internal} format 637 * @param accessingType the context of resolution which must be non-null 638 * @param resolve specifies whether resolution failure results in an unresolved type being 639 * return or a {@link LinkageError} being thrown 640 * @return a Java type for {@code name} which is guaranteed to be of type 641 * {@link ResolvedJavaType} if {@code resolve == true} 642 * @throws LinkageError if {@code resolve == true} and the resolution failed 643 * @throws NullPointerException if {@code accessingClass} is {@code null} 644 */ 645 public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { 646 Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class"); 647 return lookupTypeInternal(name, accessingType, resolve); 648 } 649 650 JavaType lookupTypeInternal(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { 651 // If the name represents a primitive type we can short-circuit the lookup. 652 if (name.length() == 1) { 653 JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); 654 return HotSpotResolvedPrimitiveType.forKind(kind); 655 } 656 657 // Resolve non-primitive types in the VM. 658 HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType; 659 try { 660 final HotSpotResolvedJavaType klass = compilerToVm.lookupType(name, hsAccessingType, resolve); 661 662 if (klass == null) { 663 assert resolve == false : name; 664 return UnresolvedJavaType.create(name); 665 } 666 return klass; 667 } catch (ClassNotFoundException e) { 668 throw (NoClassDefFoundError) new NoClassDefFoundError().initCause(e); 669 } 670 } 671 672 @Override 673 public JVMCIBackend getHostJVMCIBackend() { 674 return hostBackend; 675 } 676 677 @Override 678 public <T extends Architecture> JVMCIBackend getJVMCIBackend(Class<T> arch) { 679 assert arch != Architecture.class; 680 return backends.get(arch); 681 } 682 683 public Map<Class<? extends Architecture>, JVMCIBackend> getJVMCIBackends() { 684 return Collections.unmodifiableMap(backends); 685 } 686 687 @VMEntryPoint 688 private HotSpotCompilationRequestResult compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long compileState, int id) { 689 CompilationRequestResult result = getCompiler().compileMethod(new HotSpotCompilationRequest(method, entryBCI, compileState, id)); 690 assert result != null : "compileMethod must always return something"; 691 HotSpotCompilationRequestResult hsResult; 692 if (result instanceof HotSpotCompilationRequestResult) { 693 hsResult = (HotSpotCompilationRequestResult) result; 694 } else { 695 Object failure = result.getFailure(); 696 if (failure != null) { 697 boolean retry = false; // Be conservative with unknown compiler 698 hsResult = HotSpotCompilationRequestResult.failure(failure.toString(), retry); 699 } else { 700 int inlinedBytecodes = -1; 701 hsResult = HotSpotCompilationRequestResult.success(inlinedBytecodes); 702 } 703 } 704 705 return hsResult; 706 } 707 708 /** 709 * Shuts down the runtime. 710 */ 711 @VMEntryPoint 712 private void shutdown() throws Exception { 713 // Cleaners are normally only processed when a new Cleaner is 714 // instantiated so process all remaining cleaners now. 715 Cleaner.clean(); 716 717 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { 718 vmEventListener.notifyShutdown(); 719 } 720 } 721 722 /** 723 * Notify on completion of a bootstrap. 724 */ 725 @VMEntryPoint 726 private void bootstrapFinished() throws Exception { 727 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { 728 vmEventListener.notifyBootstrapFinished(); 729 } 730 } 731 732 /** 733 * Notify on successful install into the CodeCache. 734 * 735 * @param hotSpotCodeCacheProvider 736 * @param installedCode 737 * @param compiledCode 738 */ 739 void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompiledCode compiledCode) { 740 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { 741 vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compiledCode); 742 } 743 } 744 745 /** 746 * Writes {@code length} bytes from {@code bytes} starting at offset {@code offset} to HotSpot's 747 * log stream. 748 * 749 * @param flush specifies if the log stream should be flushed after writing 750 * @param canThrow specifies if an error in the {@code bytes}, {@code offset} or {@code length} 751 * arguments should result in an exception or a negative return value. If 752 * {@code false}, this call will not perform any heap allocation 753 * @return 0 on success, -1 if {@code bytes == null && !canThrow}, -2 if {@code !canThrow} and 754 * copying would cause access of data outside array bounds 755 * @throws NullPointerException if {@code bytes == null} 756 * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds 757 */ 758 public int writeDebugOutput(byte[] bytes, int offset, int length, boolean flush, boolean canThrow) { 759 return compilerToVm.writeDebugOutput(bytes, offset, length, flush, canThrow); 760 } 761 762 /** 763 * Gets an output stream that writes to HotSpot's {@code tty} stream. 764 */ 765 public OutputStream getLogStream() { 766 return new OutputStream() { 767 768 @Override 769 public void write(byte[] b, int off, int len) throws IOException { 770 if (b == null) { 771 throw new NullPointerException(); 772 } else if (off < 0 || off > b.length || len < 0 || (off + len) > b.length || (off + len) < 0) { 773 throw new IndexOutOfBoundsException(); 774 } else if (len == 0) { 775 return; 776 } 777 compilerToVm.writeDebugOutput(b, off, len, false, true); 778 } 779 780 @Override 781 public void write(int b) throws IOException { 782 write(new byte[]{(byte) b}, 0, 1); 783 } 784 785 @Override 786 public void flush() throws IOException { 787 compilerToVm.flushDebugOutput(); 788 } 789 }; 790 } 791 792 /** 793 * Collects the current values of all JVMCI benchmark counters, summed up over all threads. 794 */ 795 public long[] collectCounters() { 796 return compilerToVm.collectCounters(); 797 } 798 799 /** 800 * @return the current number of per thread counters. May be set through 801 * {@code -XX:JVMCICompilerSize=} command line option or the 802 * {@link #setCountersSize(int)} call. 803 */ 804 public int getCountersSize() { 805 return compilerToVm.getCountersSize(); 806 } 807 808 /** 809 * Attempt to enlarge the number of per thread counters available. Requires a safepoint so 810 * resizing should be rare to avoid performance effects. 811 * 812 * @param newSize 813 * @return false if the resizing failed 814 */ 815 public boolean setCountersSize(int newSize) { 816 return compilerToVm.setCountersSize(newSize); 817 } 818 819 /** 820 * The offset from the origin of an array to the first element. 821 * 822 * @return the offset in bytes 823 */ 824 public int getArrayBaseOffset(JavaKind kind) { 825 switch (kind) { 826 case Boolean: 827 return compilerToVm.ARRAY_BOOLEAN_BASE_OFFSET; 828 case Byte: 829 return compilerToVm.ARRAY_BYTE_BASE_OFFSET; 830 case Char: 831 return compilerToVm.ARRAY_CHAR_BASE_OFFSET; 832 case Short: 833 return compilerToVm.ARRAY_SHORT_BASE_OFFSET; 834 case Int: 835 return compilerToVm.ARRAY_INT_BASE_OFFSET; 836 case Long: 837 return compilerToVm.ARRAY_LONG_BASE_OFFSET; 838 case Float: 839 return compilerToVm.ARRAY_FLOAT_BASE_OFFSET; 840 case Double: 841 return compilerToVm.ARRAY_DOUBLE_BASE_OFFSET; 842 case Object: 843 return compilerToVm.ARRAY_OBJECT_BASE_OFFSET; 844 default: 845 throw new JVMCIError("%s", kind); 846 } 847 848 } 849 850 /** 851 * The scale used for the index when accessing elements of an array of this kind. 852 * 853 * @return the scale in order to convert the index into a byte offset 854 */ 855 public int getArrayIndexScale(JavaKind kind) { 856 switch (kind) { 857 case Boolean: 858 return compilerToVm.ARRAY_BOOLEAN_INDEX_SCALE; 859 case Byte: 860 return compilerToVm.ARRAY_BYTE_INDEX_SCALE; 861 case Char: 862 return compilerToVm.ARRAY_CHAR_INDEX_SCALE; 863 case Short: 864 return compilerToVm.ARRAY_SHORT_INDEX_SCALE; 865 case Int: 866 return compilerToVm.ARRAY_INT_INDEX_SCALE; 867 case Long: 868 return compilerToVm.ARRAY_LONG_INDEX_SCALE; 869 case Float: 870 return compilerToVm.ARRAY_FLOAT_INDEX_SCALE; 871 case Double: 872 return compilerToVm.ARRAY_DOUBLE_INDEX_SCALE; 873 case Object: 874 return compilerToVm.ARRAY_OBJECT_INDEX_SCALE; 875 default: 876 throw new JVMCIError("%s", kind); 877 878 } 879 } 880 881 /** 882 * Links each native method in {@code clazz} to an implementation in the JVMCI shared library. 883 * <p> 884 * A use case for this is a JVMCI compiler implementation that offers an API to Java code 885 * executing in HotSpot to exercise functionality (mostly) in the JVMCI shared library. For 886 * example: 887 * 888 * <pre> 889 * package com.jcompile; 890 * 891 * import java.lang.reflect.Method; 892 * 893 * public static class JCompile { 894 * static { 895 * HotSpotJVMCIRuntime.runtime().registerNativeMethods(JCompile.class); 896 * } 897 * public static boolean compile(Method method, String[] options) { 898 * // Convert to simpler data types for passing/serializing across native interface 899 * long metaspaceMethodHandle = getHandle(method); 900 * char[] opts = convertToCharArray(options); 901 * return compile(metaspaceMethodHandle, opts); 902 * } 903 * private static native boolean compile0(long metaspaceMethodHandle, char[] options); 904 * 905 * private static long getHandle(Method method) { ... } 906 * private static char[] convertToCharArray(String[] a) { ... } 907 * } 908 * </pre> 909 * 910 * The implementation of the native {@code JCompile.compile0} method would be in the JVMCI 911 * shared library that contains the bulk of the JVMCI compiler. The {@code JCompile.compile0} 912 * implementation will be exported as the following JNI-compatible symbol: 913 * 914 * <pre> 915 * Java_com_jcompile_JCompile_compile0 916 * </pre> 917 * 918 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names" 919 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#creating_the_vm" 920 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#invocation_api_functions" 921 * 922 * 923 * @return an array of 4 longs where the first value is the {@code JavaVM*} value representing 924 * the Java VM in the JVMCI shared library, and the remaining values are the first 3 925 * pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface}) 926 * @throws NullPointerException if {@code clazz == null} 927 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. 928 * {@code -XX:-UseJVMCINativeLibrary}) 929 * @throws IllegalStateException if the current execution context is the JVMCI shared library 930 * @throws IllegalArgumentException if {@code clazz} is {@link Class#isPrimitive()} 931 * @throws UnsatisfiedLinkError if there's a problem linking a native method in {@code clazz} 932 * (no matching JNI symbol or the native method is already linked to a different 933 * address) 934 */ 935 public long[] registerNativeMethods(Class<?> clazz) { 936 return compilerToVm.registerNativeMethods(clazz); 937 } 938 939 /** 940 * Creates or retrieves an object in the peer runtime that mirrors {@code obj}. The types whose 941 * objects can be translated are: 942 * <ul> 943 * <li>{@link HotSpotResolvedJavaMethodImpl},</li> 944 * <li>{@link HotSpotResolvedObjectTypeImpl},</li> 945 * <li>{@link HotSpotResolvedPrimitiveType},</li> 946 * <li>{@link IndirectHotSpotObjectConstantImpl},</li> 947 * <li>{@link DirectHotSpotObjectConstantImpl} and</li> 948 * <li>{@link HotSpotNmethod}</li> 949 * </ul> 950 * 951 * This mechanism can be used to pass and return values between the HotSpot and JVMCI shared 952 * library runtimes. In the receiving runtime, the value can be converted back to an object with 953 * {@link #unhand(Class, long)}. 954 * 955 * @param obj an object for which an equivalent instance in the peer runtime is requested 956 * @return a JNI global reference to the mirror of {@code obj} in the peer runtime 957 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. 958 * {@code -XX:-UseJVMCINativeLibrary}) 959 * @throws IllegalArgumentException if {@code obj} is not of a translatable type 960 * 961 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" 962 */ 963 public long translate(Object obj) { 964 return compilerToVm.translate(obj); 965 } 966 967 /** 968 * Dereferences and returns the object referred to by the JNI global reference {@code handle}. 969 * The global reference is deleted prior to returning. Any further use of {@code handle} is 970 * invalid. 971 * 972 * @param handle a JNI global reference to an object in the current runtime 973 * @return the object referred to by {@code handle} 974 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. 975 * {@code -XX:-UseJVMCINativeLibrary}) 976 * @throws ClassCastException if the returned object cannot be cast to {@code type} 977 * 978 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" 979 * 980 */ 981 public <T> T unhand(Class<T> type, long handle) { 982 return type.cast(compilerToVm.unhand(handle)); 983 } 984 985 /** 986 * Determines if the current thread is attached to the peer runtime. 987 * 988 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. 989 * {@code -XX:-UseJVMCINativeLibrary}) 990 * @throws IllegalStateException if the peer runtime has not been initialized 991 */ 992 public boolean isCurrentThreadAttached() { 993 return compilerToVm.isCurrentThreadAttached(); 994 } 995 996 /** 997 * Ensures the current thread is attached to the peer runtime. 998 * 999 * @param asDaemon if the thread is not yet attached, should it be attached as a daemon 1000 * @return {@code true} if this call attached the current thread, {@code false} if the current 1001 * thread was already attached 1002 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. 1003 * {@code -XX:-UseJVMCINativeLibrary}) 1004 * @throws IllegalStateException if the peer runtime has not been initialized or there is an 1005 * error while trying to attach the thread 1006 */ 1007 public boolean attachCurrentThread(boolean asDaemon) { 1008 return compilerToVm.attachCurrentThread(asDaemon); 1009 } 1010 1011 /** 1012 * Detaches the current thread from the peer runtime. 1013 * 1014 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. 1015 * {@code -XX:-UseJVMCINativeLibrary}) 1016 * @throws IllegalStateException if the peer runtime has not been initialized or if the current 1017 * thread is not attached or if there is an error while trying to detach the thread 1018 */ 1019 public void detachCurrentThread() { 1020 compilerToVm.detachCurrentThread(); 1021 } 1022 1023 /** 1024 * Informs HotSpot that no method whose module is in {@code modules} is to be compiled 1025 * with {@link #compileMethod}. 1026 * 1027 * @param modules the set of modules containing JVMCI compiler classes 1028 */ 1029 public void excludeFromJVMCICompilation(Module...modules) { 1030 this.excludeFromJVMCICompilation = modules.clone(); 1031 } 1032 }