1 /*
   2  * Copyright (c) 2015, 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.internal.jvmci.hotspot;
  24 
  25 import static jdk.internal.jvmci.inittimer.InitTimer.*;
  26 
  27 import java.util.*;
  28 
  29 import jdk.internal.jvmci.code.*;
  30 import jdk.internal.jvmci.common.*;
  31 import jdk.internal.jvmci.compiler.*;
  32 import jdk.internal.jvmci.compiler.Compiler;
  33 import jdk.internal.jvmci.inittimer.*;
  34 import jdk.internal.jvmci.meta.*;
  35 import jdk.internal.jvmci.runtime.*;
  36 import jdk.internal.jvmci.service.*;
  37 
  38 //JaCoCo Exclude
  39 
  40 public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider, HotSpotProxified {
  41 
  42     /**
  43      * The proper initialization of this class is complex because it's tangled up with the
  44      * initialization of the JVMCI and really should only ever be triggered through
  45      * {@link JVMCI#getRuntime}. However since {@link #runtime} can also be called directly it
  46      * should also trigger proper initialization. To ensure proper ordering, the static initializer
  47      * of this class initializes {@link JVMCI} and then access to {@link DelayedInit#instance}
  48      * triggers the final initialization of the {@link HotSpotJVMCIRuntime}.
  49      */
  50     static {
  51         JVMCI.initialize();
  52     }
  53 
  54     @SuppressWarnings("try")
  55     static class DelayedInit {
  56         private static final HotSpotJVMCIRuntime instance;
  57 
  58         static {
  59             try (InitTimer t0 = timer("HotSpotJVMCIRuntime.<clinit>")) {
  60                 try (InitTimer t = timer("StartupEventListener.beforeJVMCIStartup")) {
  61                     for (StartupEventListener l : Services.load(StartupEventListener.class)) {
  62                         l.beforeJVMCIStartup();
  63                     }
  64                 }
  65 
  66                 try (InitTimer t = timer("HotSpotJVMCIRuntime.<init>")) {
  67                     instance = new HotSpotJVMCIRuntime();
  68                 }
  69 
  70                 try (InitTimer t = timer("HotSpotJVMCIRuntime.completeInitialization")) {
  71                     instance.completeInitialization();
  72                 }
  73             }
  74         }
  75     }
  76 
  77     /**
  78      * Gets the singleton {@link HotSpotJVMCIRuntime} object.
  79      */
  80     public static HotSpotJVMCIRuntime runtime() {
  81         assert DelayedInit.instance != null;
  82         return DelayedInit.instance;
  83     }
  84 
  85     /**
  86      * Do deferred initialization.
  87      */
  88     public void completeInitialization() {
  89         compiler = HotSpotJVMCICompilerConfig.getCompilerFactory().createCompiler(this);
  90         for (HotSpotVMEventListener vmEventListener : vmEventListeners) {
  91             vmEventListener.completeInitialization(this);
  92         }
  93     }
  94 
  95     public static HotSpotJVMCIBackendFactory findFactory(String architecture) {
  96         for (HotSpotJVMCIBackendFactory factory : Services.load(HotSpotJVMCIBackendFactory.class)) {
  97             if (factory.getArchitecture().equalsIgnoreCase(architecture)) {
  98                 return factory;
  99             }
 100         }
 101 
 102         throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture);
 103     }
 104 
 105     /**
 106      * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend.
 107      */
 108     public static JavaKind getHostWordKind() {
 109         return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordKind;
 110     }
 111 
 112     protected final CompilerToVM compilerToVm;
 113 
 114     protected final HotSpotVMConfig config;
 115     private final JVMCIBackend hostBackend;
 116 
 117     private Compiler compiler;
 118     protected final JVMCIMetaAccessContext metaAccessContext;
 119 
 120     private final Map<Class<? extends Architecture>, JVMCIBackend> backends = new HashMap<>();
 121 
 122     private final Iterable<HotSpotVMEventListener> vmEventListeners;
 123 
 124     @SuppressWarnings("try")
 125     private HotSpotJVMCIRuntime() {
 126         compilerToVm = new CompilerToVM();
 127         try (InitTimer t = timer("HotSpotVMConfig<init>")) {
 128             config = new HotSpotVMConfig(compilerToVm);
 129         }
 130 
 131         String hostArchitecture = config.getHostArchitectureName();
 132 
 133         HotSpotJVMCIBackendFactory factory;
 134         try (InitTimer t = timer("find factory:", hostArchitecture)) {
 135             factory = findFactory(hostArchitecture);
 136         }
 137 
 138         CompilerFactory compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory();
 139 
 140         try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) {
 141             hostBackend = registerBackend(factory.createJVMCIBackend(this, compilerFactory, null));
 142         }
 143 
 144         vmEventListeners = Services.load(HotSpotVMEventListener.class);
 145 
 146         JVMCIMetaAccessContext context = null;
 147         for (HotSpotVMEventListener vmEventListener : vmEventListeners) {
 148             context = vmEventListener.createMetaAccessContext(this);
 149             if (context != null) {
 150                 break;
 151             }
 152         }
 153         if (context == null) {
 154             context = new HotSpotJVMCIMetaAccessContext();
 155         }
 156         metaAccessContext = context;
 157     }
 158 
 159     private JVMCIBackend registerBackend(JVMCIBackend backend) {
 160         Class<? extends Architecture> arch = backend.getCodeCache().getTarget().arch.getClass();
 161         JVMCIBackend oldValue = backends.put(arch, backend);
 162         assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName();
 163         return backend;
 164     }
 165 
 166     public ResolvedJavaType fromClass(Class<?> javaClass) {
 167         return metaAccessContext.fromClass(javaClass);
 168     }
 169 
 170     public HotSpotVMConfig getConfig() {
 171         return config;
 172     }
 173 
 174     public CompilerToVM getCompilerToVM() {
 175         return compilerToVm;
 176     }
 177 
 178     public JVMCIMetaAccessContext getMetaAccessContext() {
 179         return metaAccessContext;
 180     }
 181 
 182     public Compiler getCompiler() {
 183         return compiler;
 184     }
 185 
 186     public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) {
 187         Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class");
 188         // If the name represents a primitive type we can short-circuit the lookup.
 189         if (name.length() == 1) {
 190             JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0));
 191             return fromClass(kind.toJavaClass());
 192         }
 193 
 194         // Resolve non-primitive types in the VM.
 195         HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType;
 196         final HotSpotResolvedObjectTypeImpl klass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve);
 197 
 198         if (klass == null) {
 199             assert resolve == false;
 200             return HotSpotUnresolvedJavaType.create(this, name);
 201         }
 202         return klass;
 203     }
 204 
 205     public JVMCIBackend getHostJVMCIBackend() {
 206         return hostBackend;
 207     }
 208 
 209     public <T extends Architecture> JVMCIBackend getJVMCIBackend(Class<T> arch) {
 210         assert arch != Architecture.class;
 211         return backends.get(arch);
 212     }
 213 
 214     public Map<Class<? extends Architecture>, JVMCIBackend> getBackends() {
 215         return Collections.unmodifiableMap(backends);
 216     }
 217 
 218     /**
 219      * Called from the VM.
 220      */
 221     @SuppressWarnings({"unused"})
 222     private void compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id) {
 223         compiler.compileMethod(method, entryBCI, jvmciEnv, id);
 224     }
 225 
 226     /**
 227      * Shuts down the runtime.
 228      *
 229      * Called from the VM.
 230      */
 231     @SuppressWarnings({"unused"})
 232     private void shutdown() throws Exception {
 233         for (HotSpotVMEventListener vmEventListener : vmEventListeners) {
 234             vmEventListener.notifyShutdown();
 235         }
 236     }
 237 
 238     /**
 239      * Shuts down the runtime.
 240      *
 241      * Called from the VM.
 242      *
 243      * @param hotSpotCodeCacheProvider
 244      */
 245     void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompilationResult compResult) {
 246         for (HotSpotVMEventListener vmEventListener : vmEventListeners) {
 247             vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compResult);
 248         }
 249     }
 250 }