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