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 87 HotSpotResolvedObjectTypeImpl getJavaLangObject() { 88 if (javaLangObject == null) { 89 javaLangObject = (HotSpotResolvedObjectTypeImpl) fromClass(Object.class); 90 } 91 return javaLangObject; 92 } 93 94 HotSpotResolvedObjectTypeImpl getJavaLangString() { 95 if (javaLangString == null) { 96 javaLangString = (HotSpotResolvedObjectTypeImpl) fromClass(String.class); 97 } 98 return javaLangString; 99 } 100 101 HotSpotResolvedObjectTypeImpl getJavaLangClass() { 102 if (javaLangClass == null) { 103 javaLangClass = (HotSpotResolvedObjectTypeImpl) fromClass(Class.class); 104 } 105 return javaLangClass; 106 } 107 108 HotSpotResolvedObjectTypeImpl getJavaLangCloneable() { 109 if (cloneableType == null) { 110 cloneableType = (HotSpotResolvedObjectTypeImpl) fromClass(Cloneable.class); 111 } 112 return cloneableType; 113 } 114 115 HotSpotResolvedObjectTypeImpl getJavaLangSerializable() { 116 if (serializableType == null) { 117 serializableType = (HotSpotResolvedObjectTypeImpl) fromClass(Serializable.class); 118 } 119 return serializableType; 120 } 121 122 HotSpotResolvedObjectTypeImpl getJavaLangThrowable() { 123 if (throwableType == null) { 124 throwableType = (HotSpotResolvedObjectTypeImpl) fromClass(Throwable.class); 125 } 126 return throwableType; 127 } 128 129 HotSpotResolvedObjectTypeImpl getJavaLangEnum() { 130 if (enumType == null) { 131 enumType = (HotSpotResolvedObjectTypeImpl) fromClass(Enum.class); 132 } 133 return enumType; 134 } 135 136 HotSpotResolvedObjectTypeImpl getConstantCallSite() { 137 if (constantCallSiteType == null) { 138 constantCallSiteType = (HotSpotResolvedObjectTypeImpl) fromClass(ConstantCallSite.class); 139 } 140 return constantCallSiteType; 141 } 142 143 HotSpotResolvedObjectTypeImpl getCallSite() { 144 if (callSiteType == null) { 145 callSiteType = (HotSpotResolvedObjectTypeImpl) fromClass(CallSite.class); 146 } 147 return callSiteType; 148 } 149 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") 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 199 static Throwable decodeThrowable(String encodedThrowable) throws Throwable { 200 return TranslatedException.decodeThrowable(encodedThrowable); 201 } 202 203 @VMEntryPoint 204 static String encodeThrowable(Throwable throwable) throws Throwable { 205 return TranslatedException.encodeThrowable(throwable); 206 } 207 208 @VMEntryPoint 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 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") 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 */ 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 */ 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 */ 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 */ 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 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") 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 */ 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 401 WeakReferenceHolder(T value) { 402 set(value); 403 } 404 405 void set(T value) { 406 ref = new WeakReference<>(value); 407 } 408 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 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") 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 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 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 */ 540 HotSpotResolvedJavaType fromClass(Class<?> javaClass) { 541 if (javaClass == null) { 542 return null; 543 } 544 return fromClass0(javaClass); 545 } 546 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 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 571 public HotSpotVMConfigStore getConfigStore() { 572 return configStore; 573 } 574 575 public HotSpotVMConfig getConfig() { 576 return config; 577 } 578 579 public CompilerToVM getCompilerToVM() { 580 return compilerToVm; 581 } 582 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 */ 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 * Attempt to 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 * @return false if the resizing failed 821 */ 822 public boolean setCountersSize(int newSize) { 823 return compilerToVm.setCountersSize(newSize); 824 } 825 826 /** 827 * The offset from the origin of an array to the first element. 828 * 829 * @return the offset in bytes 830 */ 831 public int getArrayBaseOffset(JavaKind kind) { 832 switch (kind) { 833 case Boolean: 834 return compilerToVm.ARRAY_BOOLEAN_BASE_OFFSET; 835 case Byte: 836 return compilerToVm.ARRAY_BYTE_BASE_OFFSET; 837 case Char: 838 return compilerToVm.ARRAY_CHAR_BASE_OFFSET; 839 case Short: 840 return compilerToVm.ARRAY_SHORT_BASE_OFFSET; 841 case Int: 842 return compilerToVm.ARRAY_INT_BASE_OFFSET; 843 case Long: 844 return compilerToVm.ARRAY_LONG_BASE_OFFSET; 845 case Float: 846 return compilerToVm.ARRAY_FLOAT_BASE_OFFSET; 847 case Double: 848 return compilerToVm.ARRAY_DOUBLE_BASE_OFFSET; 849 case Object: 850 return compilerToVm.ARRAY_OBJECT_BASE_OFFSET; 851 default: 852 throw new JVMCIError("%s", kind); 853 } 854 855 } 856 857 /** 858 * The scale used for the index when accessing elements of an array of this kind. 859 * 860 * @return the scale in order to convert the index into a byte offset 861 */ 862 public int getArrayIndexScale(JavaKind kind) { 863 switch (kind) { 864 case Boolean: 865 return compilerToVm.ARRAY_BOOLEAN_INDEX_SCALE; 866 case Byte: 867 return compilerToVm.ARRAY_BYTE_INDEX_SCALE; 868 case Char: 869 return compilerToVm.ARRAY_CHAR_INDEX_SCALE; 870 case Short: 871 return compilerToVm.ARRAY_SHORT_INDEX_SCALE; 872 case Int: 873 return compilerToVm.ARRAY_INT_INDEX_SCALE; 874 case Long: 875 return compilerToVm.ARRAY_LONG_INDEX_SCALE; 876 case Float: 877 return compilerToVm.ARRAY_FLOAT_INDEX_SCALE; 878 case Double: 879 return compilerToVm.ARRAY_DOUBLE_INDEX_SCALE; 880 case Object: 881 return compilerToVm.ARRAY_OBJECT_INDEX_SCALE; 882 default: 883 throw new JVMCIError("%s", kind); 884 885 } 886 } 887 888 /** 889 * Links each native method in {@code clazz} to an implementation in the JVMCI shared library. 890 * <p> 891 * A use case for this is a JVMCI compiler implementation that offers an API to Java code 892 * executing in HotSpot to exercise functionality (mostly) in the JVMCI shared library. For 893 * example: 894 * 895 * <pre> 896 * package com.jcompile; 897 * 898 * import java.lang.reflect.Method; 899 * 900 * public static class JCompile { 901 * static { 902 * HotSpotJVMCIRuntime.runtime().registerNativeMethods(JCompile.class); 903 * } 904 * public static boolean compile(Method method, String[] options) { 905 * // Convert to simpler data types for passing/serializing across native interface 906 * long metaspaceMethodHandle = getHandle(method); 907 * char[] opts = convertToCharArray(options); 908 * return compile(metaspaceMethodHandle, opts); 909 * } 910 * private static native boolean compile0(long metaspaceMethodHandle, char[] options); 911 * 912 * private static long getHandle(Method method) { ... } 913 * private static char[] convertToCharArray(String[] a) { ... } 914 * } 915 * </pre> 916 * 917 * The implementation of the native {@code JCompile.compile0} method would be in the JVMCI 918 * shared library that contains the bulk of the JVMCI compiler. The {@code JCompile.compile0} 919 * implementation will be exported as the following JNI-compatible symbol: 920 * 921 * <pre> 922 * Java_com_jcompile_JCompile_compile0 923 * </pre> 924 * 925 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names" 926 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#creating_the_vm" 927 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#invocation_api_functions" 928 * 929 * 930 * @return an array of 4 longs where the first value is the {@code JavaVM*} value representing 931 * the Java VM in the JVMCI shared library, and the remaining values are the first 3 932 * pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface}) 933 * @throws NullPointerException if {@code clazz == null} 934 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. 935 * {@code -XX:-UseJVMCINativeLibrary}) 936 * @throws IllegalStateException if the current execution context is the JVMCI shared library 937 * @throws IllegalArgumentException if {@code clazz} is {@link Class#isPrimitive()} 938 * @throws UnsatisfiedLinkError if there's a problem linking a native method in {@code clazz} 939 * (no matching JNI symbol or the native method is already linked to a different 940 * address) 941 */ 942 public long[] registerNativeMethods(Class<?> clazz) { 943 return compilerToVm.registerNativeMethods(clazz); 944 } 945 946 /** 947 * Creates or retrieves an object in the peer runtime that mirrors {@code obj}. The types whose 948 * objects can be translated are: 949 * <ul> 950 * <li>{@link HotSpotResolvedJavaMethodImpl},</li> 951 * <li>{@link HotSpotResolvedObjectTypeImpl},</li> 952 * <li>{@link HotSpotResolvedPrimitiveType},</li> 953 * <li>{@link IndirectHotSpotObjectConstantImpl},</li> 954 * <li>{@link DirectHotSpotObjectConstantImpl} and</li> 955 * <li>{@link HotSpotNmethod}</li> 956 * </ul> 957 * 958 * This mechanism can be used to pass and return values between the HotSpot and JVMCI shared 959 * library runtimes. In the receiving runtime, the value can be converted back to an object with 960 * {@link #unhand(Class, long)}. 961 * 962 * @param obj an object for which an equivalent instance in the peer runtime is requested 963 * @return a JNI global reference to the mirror of {@code obj} in the peer runtime 964 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. 965 * {@code -XX:-UseJVMCINativeLibrary}) 966 * @throws IllegalArgumentException if {@code obj} is not of a translatable type 967 * 968 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" 969 */ 970 public long translate(Object obj) { 971 return compilerToVm.translate(obj); 972 } 973 974 /** 975 * Dereferences and returns the object referred to by the JNI global reference {@code handle}. 976 * The global reference is deleted prior to returning. Any further use of {@code handle} is 977 * invalid. 978 * 979 * @param handle a JNI global reference to an object in the current runtime 980 * @return the object referred to by {@code handle} 981 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. 982 * {@code -XX:-UseJVMCINativeLibrary}) 983 * @throws ClassCastException if the returned object cannot be cast to {@code type} 984 * 985 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" 986 * 987 */ 988 public <T> T unhand(Class<T> type, long handle) { 989 return type.cast(compilerToVm.unhand(handle)); 990 } 991 992 /** 993 * Determines if the current thread is attached to the peer runtime. 994 * 995 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. 996 * {@code -XX:-UseJVMCINativeLibrary}) 997 * @throws IllegalStateException if the peer runtime has not been initialized 998 */ 999 public boolean isCurrentThreadAttached() { 1000 return compilerToVm.isCurrentThreadAttached(); 1001 } 1002 1003 /** 1004 * Gets the address of the HotSpot {@code JavaThread} C++ object for the current thread. This 1005 * will return {@code 0} if called from an unattached JVMCI shared library thread. 1006 */ 1007 public long getCurrentJavaThread() { 1008 return compilerToVm.getCurrentJavaThread(); 1009 } 1010 1011 /** 1012 * Ensures the current thread is attached to the peer runtime. 1013 * 1014 * @param asDaemon if the thread is not yet attached, should it be attached as a daemon 1015 * @return {@code true} if this call attached the current thread, {@code false} if the current 1016 * thread was already attached 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 there is an 1020 * error while trying to attach the thread 1021 */ 1022 public boolean attachCurrentThread(boolean asDaemon) { 1023 return compilerToVm.attachCurrentThread(asDaemon); 1024 } 1025 1026 /** 1027 * Detaches the current thread from the peer runtime. 1028 * 1029 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. 1030 * {@code -XX:-UseJVMCINativeLibrary}) 1031 * @throws IllegalStateException if the peer runtime has not been initialized or if the current 1032 * thread is not attached or if there is an error while trying to detach the thread 1033 */ 1034 public void detachCurrentThread() { 1035 compilerToVm.detachCurrentThread(); 1036 } 1037 1038 /** 1039 * Informs HotSpot that no method whose module is in {@code modules} is to be compiled 1040 * with {@link #compileMethod}. 1041 * 1042 * @param modules the set of modules containing JVMCI compiler classes 1043 */ 1044 public void excludeFromJVMCICompilation(Module...modules) { 1045 this.excludeFromJVMCICompilation = modules.clone(); 1046 } 1047 1048 /** 1049 * Calls {@link System#exit(int)} in HotSpot's runtime. 1050 */ 1051 public void exitHotSpot(int status) { 1052 if (!IS_IN_NATIVE_IMAGE) { 1053 System.exit(status); 1054 } 1055 compilerToVm.callSystemExit(status); 1056 } 1057 } --- EOF ---