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