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.vm.ci.hotspot; 24 25 import static jdk.vm.ci.inittimer.InitTimer.timer; 26 27 import java.io.IOException; 28 import java.io.OutputStream; 29 import java.lang.reflect.Array; 30 import java.lang.reflect.Field; 31 import java.lang.reflect.Method; 32 import java.lang.reflect.Modifier; 33 import java.util.Collections; 34 import java.util.HashMap; 35 import java.util.Map; 36 import java.util.Objects; 37 import java.util.TreeMap; 38 39 import jdk.vm.ci.code.Architecture; 40 import jdk.vm.ci.code.CompilationResult; 41 import jdk.vm.ci.code.InstalledCode; 42 import jdk.vm.ci.common.JVMCIError; 43 import jdk.vm.ci.inittimer.InitTimer; 44 import jdk.vm.ci.meta.JVMCIMetaAccessContext; 45 import jdk.vm.ci.meta.JavaKind; 46 import jdk.vm.ci.meta.JavaType; 47 import jdk.vm.ci.meta.ResolvedJavaType; 48 import jdk.vm.ci.runtime.JVMCI; 49 import jdk.vm.ci.runtime.JVMCIBackend; 50 import jdk.vm.ci.runtime.JVMCICompiler; 51 import jdk.vm.ci.service.Services; 52 53 //JaCoCo Exclude 54 55 /** 56 * HotSpot implementation of a JVMCI runtime. 57 * 58 * The initialization of this class is very fragile since it's initialized both through 59 * {@link JVMCI#initialize()} or through calling {@link HotSpotJVMCIRuntime#runtime()} and 60 * {@link HotSpotJVMCIRuntime#runtime()} is also called by {@link JVMCI#initialize()}. So this class 61 * can't have a static initializer and any required initialization must be done as part of 62 * {@link #runtime()}. This allows the initialization to funnel back through 63 * {@link JVMCI#initialize()} without deadlocking. 64 */ 65 public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider, HotSpotProxified { 66 67 @SuppressWarnings("try") 68 static class DelayedInit { 69 private static final HotSpotJVMCIRuntime instance; 70 71 static { 72 try (InitTimer t = timer("HotSpotJVMCIRuntime.<init>")) { 73 instance = new HotSpotJVMCIRuntime(); 74 } 75 } 76 } 77 78 /** 79 * Gets the singleton {@link HotSpotJVMCIRuntime} object. 80 */ 81 public static HotSpotJVMCIRuntime runtime() { 82 JVMCI.initialize(); 83 return DelayedInit.instance; 84 } 85 86 public static HotSpotJVMCIBackendFactory findFactory(String architecture) { 87 for (HotSpotJVMCIBackendFactory factory : Services.load(HotSpotJVMCIBackendFactory.class)) { 88 if (factory.getArchitecture().equalsIgnoreCase(architecture)) { 89 return factory; 90 } 91 } 92 93 throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture); 94 } 95 96 /** 97 * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend. 98 */ 99 public static JavaKind getHostWordKind() { 100 return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordJavaKind; 101 } 102 103 protected final CompilerToVM compilerToVm; 104 105 protected final HotSpotVMConfig config; 106 private final JVMCIBackend hostBackend; 107 108 private volatile JVMCICompiler compiler; 109 protected final JVMCIMetaAccessContext metaAccessContext; 110 111 private final Map<Class<? extends Architecture>, JVMCIBackend> backends = new HashMap<>(); 112 113 private final Iterable<HotSpotVMEventListener> vmEventListeners; 114 115 @SuppressWarnings("unused") private final String[] trivialPrefixes; 116 117 @SuppressWarnings("try") 118 private HotSpotJVMCIRuntime() { 119 compilerToVm = new CompilerToVM(); 120 121 try (InitTimer t = timer("HotSpotVMConfig<init>")) { 122 config = new HotSpotVMConfig(compilerToVm); 123 } 124 125 String hostArchitecture = config.getHostArchitectureName(); 126 127 HotSpotJVMCIBackendFactory factory; 128 try (InitTimer t = timer("find factory:", hostArchitecture)) { 129 factory = findFactory(hostArchitecture); 130 } 131 132 try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) { 133 hostBackend = registerBackend(factory.createJVMCIBackend(this, null)); 134 } 135 136 vmEventListeners = Services.load(HotSpotVMEventListener.class); 137 138 JVMCIMetaAccessContext context = null; 139 for (HotSpotVMEventListener vmEventListener : vmEventListeners) { 140 context = vmEventListener.createMetaAccessContext(this); 141 if (context != null) { 142 break; 143 } 144 } 145 if (context == null) { 146 context = new HotSpotJVMCIMetaAccessContext(); 147 } 148 metaAccessContext = context; 149 150 if (Boolean.valueOf(System.getProperty("jvmci.printconfig"))) { 151 printConfig(config, compilerToVm); 152 } 153 154 trivialPrefixes = HotSpotJVMCICompilerConfig.getCompilerFactory().getTrivialPrefixes(); 155 } 156 157 private JVMCIBackend registerBackend(JVMCIBackend backend) { 158 Class<? extends Architecture> arch = backend.getCodeCache().getTarget().arch.getClass(); 159 JVMCIBackend oldValue = backends.put(arch, backend); 160 assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName(); 161 return backend; 162 } 163 164 public ResolvedJavaType fromClass(Class<?> javaClass) { 165 return metaAccessContext.fromClass(javaClass); 166 } 167 168 public HotSpotVMConfig getConfig() { 169 return config; 170 } 171 172 public CompilerToVM getCompilerToVM() { 173 return compilerToVm; 174 } 175 176 public JVMCIMetaAccessContext getMetaAccessContext() { 177 return metaAccessContext; 178 } 179 180 public JVMCICompiler getCompiler() { 181 if (compiler == null) { 182 synchronized (this) { 183 if (compiler == null) { 184 compiler = HotSpotJVMCICompilerConfig.getCompilerFactory().createCompiler(this); 185 } 186 } 187 } 188 return compiler; 189 } 190 191 public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { 192 Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class"); 193 // If the name represents a primitive type we can short-circuit the lookup. 194 if (name.length() == 1) { 195 JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); 196 return fromClass(kind.toJavaClass()); 197 } 198 199 // Resolve non-primitive types in the VM. 200 HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType; 201 final HotSpotResolvedObjectTypeImpl klass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve); 202 203 if (klass == null) { 204 assert resolve == false; 205 return HotSpotUnresolvedJavaType.create(this, name); 206 } 207 return klass; 208 } 209 210 public JVMCIBackend getHostJVMCIBackend() { 211 return hostBackend; 212 } 213 214 public <T extends Architecture> JVMCIBackend getJVMCIBackend(Class<T> arch) { 215 assert arch != Architecture.class; 216 return backends.get(arch); 217 } 218 219 public Map<Class<? extends Architecture>, JVMCIBackend> getJVMCIBackends() { 220 return Collections.unmodifiableMap(backends); 221 } 222 223 /** 224 * Called from the VM. 225 */ 226 @SuppressWarnings({"unused"}) 227 private void compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id) { 228 getCompiler().compileMethod(new HotSpotCompilationRequest(method, entryBCI, jvmciEnv, id)); 229 } 230 231 /** 232 * Shuts down the runtime. 233 * 234 * Called from the VM. 235 */ 236 @SuppressWarnings({"unused"}) 237 private void shutdown() throws Exception { 238 for (HotSpotVMEventListener vmEventListener : vmEventListeners) { 239 vmEventListener.notifyShutdown(); 240 } 241 } 242 243 /** 244 * Notify on successful install into the CodeCache. 245 * 246 * @param hotSpotCodeCacheProvider 247 * @param installedCode 248 * @param compResult 249 */ 250 void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompilationResult compResult) { 251 for (HotSpotVMEventListener vmEventListener : vmEventListeners) { 252 vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compResult); 253 } 254 } 255 256 private static void printConfig(HotSpotVMConfig config, CompilerToVM vm) { 257 Field[] fields = config.getClass().getDeclaredFields(); 258 Map<String, Field> sortedFields = new TreeMap<>(); 259 for (Field f : fields) { 260 if (!f.isSynthetic() && !Modifier.isStatic(f.getModifiers())) { 261 f.setAccessible(true); 262 sortedFields.put(f.getName(), f); 263 } 264 } 265 for (Field f : sortedFields.values()) { 266 try { 267 String line = String.format("%9s %-40s = %s%n", f.getType().getSimpleName(), f.getName(), pretty(f.get(config))); 268 byte[] lineBytes = line.getBytes(); 269 vm.writeDebugOutput(lineBytes, 0, lineBytes.length); 270 vm.flushDebugOutput(); 271 } catch (Exception e) { 272 } 273 } 274 } 275 276 private static String pretty(Object value) { 277 if (value == null) { 278 return "null"; 279 } 280 281 Class<?> klass = value.getClass(); 282 if (value instanceof String) { 283 return "\"" + value + "\""; 284 } else if (value instanceof Method) { 285 return "method \"" + ((Method) value).getName() + "\""; 286 } else if (value instanceof Class<?>) { 287 return "class \"" + ((Class<?>) value).getSimpleName() + "\""; 288 } else if (value instanceof Integer) { 289 if ((Integer) value < 10) { 290 return value.toString(); 291 } 292 return value + " (0x" + Integer.toHexString((Integer) value) + ")"; 293 } else if (value instanceof Long) { 294 if ((Long) value < 10 && (Long) value > -10) { 295 return value + "l"; 296 } 297 return value + "l (0x" + Long.toHexString((Long) value) + "l)"; 298 } else if (klass.isArray()) { 299 StringBuilder str = new StringBuilder(); 300 int dimensions = 0; 301 while (klass.isArray()) { 302 dimensions++; 303 klass = klass.getComponentType(); 304 } 305 int length = Array.getLength(value); 306 str.append(klass.getSimpleName()).append('[').append(length).append(']'); 307 for (int i = 1; i < dimensions; i++) { 308 str.append("[]"); 309 } 310 str.append(" {"); 311 for (int i = 0; i < length; i++) { 312 str.append(pretty(Array.get(value, i))); 313 if (i < length - 1) { 314 str.append(", "); 315 } 316 } 317 str.append('}'); 318 return str.toString(); 319 } 320 return value.toString(); 321 } 322 323 public OutputStream getLogStream() { 324 return new OutputStream() { 325 326 @Override 327 public void write(byte[] b, int off, int len) throws IOException { 328 if (b == null) { 329 throw new NullPointerException(); 330 } else if (off < 0 || off > b.length || len < 0 || (off + len) > b.length || (off + len) < 0) { 331 throw new IndexOutOfBoundsException(); 332 } else if (len == 0) { 333 return; 334 } 335 compilerToVm.writeDebugOutput(b, off, len); 336 } 337 338 @Override 339 public void write(int b) throws IOException { 340 write(new byte[]{(byte) b}, 0, 1); 341 } 342 343 @Override 344 public void flush() throws IOException { 345 compilerToVm.flushDebugOutput(); 346 } 347 }; 348 } 349 350 /** 351 * Collects the current values of all JVMCI benchmark counters, summed up over all threads. 352 */ 353 public long[] collectCounters() { 354 return compilerToVm.collectCounters(); 355 } 356 }