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