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