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