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