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