001/* 002 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package jdk.internal.jvmci.hotspot; 024 025import static jdk.internal.jvmci.common.UnsafeAccess.*; 026import static jdk.internal.jvmci.hotspot.InitTimer.*; 027 028import java.util.*; 029 030import jdk.internal.jvmci.code.*; 031import jdk.internal.jvmci.common.*; 032import jdk.internal.jvmci.meta.*; 033import jdk.internal.jvmci.options.*; 034import jdk.internal.jvmci.runtime.*; 035import jdk.internal.jvmci.service.*; 036 037//JaCoCo Exclude 038 039public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider, HotSpotProxified { 040 041 private static final HotSpotJVMCIRuntime instance; 042 043 static { 044 try (InitTimer t0 = timer("HotSpotJVMCIRuntime.<clinit>")) { 045 try (InitTimer t = timer("HotSpotJVMCIRuntime.<init>")) { 046 instance = new HotSpotJVMCIRuntime(); 047 } 048 049 try (InitTimer t = timer("HotSpotJVMCIRuntime.completeInitialization")) { 050 // Why deferred initialization? See comment in completeInitialization(). 051 instance.completeInitialization(); 052 } 053 } 054 } 055 056 /** 057 * Gets the singleton {@link HotSpotJVMCIRuntime} object. 058 */ 059 public static HotSpotJVMCIRuntime runtime() { 060 assert instance != null; 061 return instance; 062 } 063 064 /** 065 * Do deferred initialization. 066 */ 067 public void completeInitialization() { 068 069 // Proxies for the VM/Compiler interfaces cannot be initialized 070 // in the constructor as proxy creation causes static 071 // initializers to be executed for all the types involved in the 072 // proxied methods. Some of these static initializers (e.g. in 073 // HotSpotMethodData) rely on the static 'instance' field being set 074 // to retrieve configuration details. 075 CompilerToVM toVM = this.compilerToVm; 076 077 for (HotSpotVMEventListener vmEventListener : vmEventListeners) { 078 toVM = vmEventListener.completeInitialization(this, toVM); 079 } 080 081 this.compilerToVm = toVM; 082 } 083 084 public static class Options { 085 086 // @formatter:off 087 @Option(help = "The JVMCI runtime configuration to use", type = OptionType.Expert) 088 public static final OptionValue<String> JVMCIRuntime = new OptionValue<>(""); 089 090 @Option(help = "File to which logging is sent. A %p in the name will be replaced with a string identifying the process, usually the process id.", type = OptionType.Expert) 091 public static final PrintStreamOption LogFile = new PrintStreamOption(); 092 // @formatter:on 093 } 094 095 public static HotSpotJVMCIBackendFactory findFactory(String architecture) { 096 HotSpotJVMCIBackendFactory basic = null; 097 HotSpotJVMCIBackendFactory selected = null; 098 HotSpotJVMCIBackendFactory nonBasic = null; 099 int nonBasicCount = 0; 100 101 for (HotSpotJVMCIBackendFactory factory : Services.load(HotSpotJVMCIBackendFactory.class)) { 102 if (factory.getArchitecture().equalsIgnoreCase(architecture)) { 103 if (factory.getJVMCIRuntimeName().equals(Options.JVMCIRuntime.getValue())) { 104 assert selected == null || checkFactoryOverriding(selected, factory); 105 selected = factory; 106 } 107 if (factory.getJVMCIRuntimeName().equals("basic")) { 108 assert basic == null || checkFactoryOverriding(basic, factory); 109 basic = factory; 110 } else { 111 nonBasic = factory; 112 nonBasicCount++; 113 } 114 } 115 } 116 117 if (selected != null) { 118 return selected; 119 } else { 120 if (!Options.JVMCIRuntime.getValue().equals("")) { 121 // Fail fast if a non-default value for JVMCIRuntime was specified 122 // and the corresponding factory is not available 123 throw new JVMCIError("Specified runtime \"%s\" not available for the %s architecture", Options.JVMCIRuntime.getValue(), architecture); 124 } else if (nonBasicCount == 1) { 125 // If there is exactly one non-basic runtime, select this one. 126 return nonBasic; 127 } else { 128 return basic; 129 } 130 } 131 } 132 133 /** 134 * Checks that a factory overriding is valid. A factory B can only override/replace a factory A 135 * if the B.getClass() is a subclass of A.getClass(). This models the assumption that B is 136 * extends the behavior of A and has therefore understood the behavior expected of A. 137 * 138 * @param baseFactory 139 * @param overridingFactory 140 */ 141 private static boolean checkFactoryOverriding(HotSpotJVMCIBackendFactory baseFactory, HotSpotJVMCIBackendFactory overridingFactory) { 142 return baseFactory.getClass().isAssignableFrom(overridingFactory.getClass()); 143 } 144 145 /** 146 * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend. 147 */ 148 public static Kind getHostWordKind() { 149 return instance.getHostJVMCIBackend().getCodeCache().getTarget().wordKind; 150 } 151 152 /** 153 * Reads a klass pointer from a constant object. 154 */ 155 public static long unsafeReadKlassPointer(Object object) { 156 return instance.getCompilerToVM().readUnsafeKlassPointer(object); 157 } 158 159 /** 160 * Reads a word value from a given object. 161 */ 162 public static long unsafeReadWord(Object object, long offset) { 163 if (getHostWordKind() == Kind.Long) { 164 return unsafe.getLong(object, offset); 165 } 166 return unsafe.getInt(object, offset) & 0xFFFFFFFFL; 167 } 168 169 protected/* final */CompilerToVM compilerToVm; 170 171 protected final HotSpotVMConfig config; 172 private final JVMCIBackend hostBackend; 173 174 /** 175 * JVMCI mirrors are stored as a {@link ClassValue} associated with the {@link Class} of the 176 * type. This data structure stores both {@link HotSpotResolvedObjectType} and 177 * {@link HotSpotResolvedPrimitiveType} types. 178 */ 179 private final ClassValue<ResolvedJavaType> jvmciMirrors = new ClassValue<ResolvedJavaType>() { 180 @Override 181 protected ResolvedJavaType computeValue(Class<?> javaClass) { 182 if (javaClass.isPrimitive()) { 183 Kind kind = Kind.fromJavaClass(javaClass); 184 return new HotSpotResolvedPrimitiveType(kind); 185 } else { 186 return new HotSpotResolvedObjectTypeImpl(javaClass); 187 } 188 } 189 }; 190 191 private final Map<Class<? extends Architecture>, JVMCIBackend> backends = new HashMap<>(); 192 193 private final Iterable<HotSpotVMEventListener> vmEventListeners; 194 195 private HotSpotJVMCIRuntime() { 196 CompilerToVM toVM = new CompilerToVMImpl(); 197 compilerToVm = toVM; 198 try (InitTimer t = timer("HotSpotVMConfig<init>")) { 199 config = new HotSpotVMConfig(compilerToVm); 200 } 201 202 String hostArchitecture = config.getHostArchitectureName(); 203 204 HotSpotJVMCIBackendFactory factory; 205 try (InitTimer t = timer("find factory:", hostArchitecture)) { 206 factory = findFactory(hostArchitecture); 207 } 208 try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) { 209 hostBackend = registerBackend(factory.createJVMCIBackend(this, null)); 210 } 211 212 Iterable<HotSpotVMEventListener> listeners = Services.load(HotSpotVMEventListener.class); 213 if (!listeners.iterator().hasNext()) { 214 listeners = Arrays.asList(new HotSpotVMEventListener() { 215 }); 216 } 217 vmEventListeners = listeners; 218 } 219 220 private JVMCIBackend registerBackend(JVMCIBackend backend) { 221 Class<? extends Architecture> arch = backend.getCodeCache().getTarget().arch.getClass(); 222 JVMCIBackend oldValue = backends.put(arch, backend); 223 assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName(); 224 return backend; 225 } 226 227 public ResolvedJavaType fromClass(Class<?> javaClass) { 228 return jvmciMirrors.get(javaClass); 229 } 230 231 public HotSpotVMConfig getConfig() { 232 return config; 233 } 234 235 public CompilerToVM getCompilerToVM() { 236 return compilerToVm; 237 } 238 239 public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { 240 Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class"); 241 // If the name represents a primitive type we can short-circuit the lookup. 242 if (name.length() == 1) { 243 Kind kind = Kind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); 244 return fromClass(kind.toJavaClass()); 245 } 246 247 // Resolve non-primitive types in the VM. 248 HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType; 249 final long metaspaceKlass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve); 250 251 if (metaspaceKlass == 0L) { 252 assert resolve == false; 253 return HotSpotUnresolvedJavaType.create(this, name); 254 } 255 return HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspaceKlass); 256 } 257 258 public JVMCIBackend getHostJVMCIBackend() { 259 return hostBackend; 260 } 261 262 public <T extends Architecture> JVMCIBackend getJVMCIBackend(Class<T> arch) { 263 assert arch != Architecture.class; 264 return backends.get(arch); 265 } 266 267 public Map<Class<? extends Architecture>, JVMCIBackend> getBackends() { 268 return Collections.unmodifiableMap(backends); 269 } 270 271 /** 272 * Called from the VM. 273 */ 274 @SuppressWarnings({"unused"}) 275 private void compileMetaspaceMethod(long metaspaceMethod, int entryBCI, long jvmciEnv, int id) { 276 for (HotSpotVMEventListener vmEventListener : vmEventListeners) { 277 vmEventListener.compileMetaspaceMethod(metaspaceMethod, entryBCI, jvmciEnv, id); 278 } 279 } 280 281 /** 282 * Called from the VM. 283 */ 284 @SuppressWarnings({"unused"}) 285 private void compileTheWorld() throws Throwable { 286 for (HotSpotVMEventListener vmEventListener : vmEventListeners) { 287 vmEventListener.notifyCompileTheWorld(); 288 } 289 } 290 291 /** 292 * Shuts down the runtime. 293 * 294 * Called from the VM. 295 */ 296 @SuppressWarnings({"unused"}) 297 private void shutdown() throws Exception { 298 for (HotSpotVMEventListener vmEventListener : vmEventListeners) { 299 vmEventListener.notifyShutdown(); 300 } 301 } 302 303 /** 304 * Shuts down the runtime. 305 * 306 * Called from the VM. 307 * 308 * @param hotSpotCodeCacheProvider 309 */ 310 void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompilationResult compResult) { 311 for (HotSpotVMEventListener vmEventListener : vmEventListeners) { 312 vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compResult); 313 } 314 } 315}