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