001/* 002 * Copyright (c) 2011, 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 com.oracle.graal.hotspot; 024 025import static com.oracle.graal.compiler.common.GraalOptions.*; 026import static com.oracle.graal.debug.GraalDebugConfig.*; 027import static com.oracle.graal.hotspot.HotSpotGraalRuntime.Options.*; 028import static jdk.internal.jvmci.common.UnsafeAccess.*; 029import static jdk.internal.jvmci.hotspot.InitTimer.*; 030 031import java.lang.reflect.*; 032import java.util.*; 033 034import jdk.internal.jvmci.code.*; 035import jdk.internal.jvmci.code.stack.*; 036import jdk.internal.jvmci.common.*; 037import jdk.internal.jvmci.hotspot.*; 038import jdk.internal.jvmci.meta.*; 039import jdk.internal.jvmci.options.*; 040import jdk.internal.jvmci.runtime.*; 041import jdk.internal.jvmci.service.*; 042 043import com.oracle.graal.api.collections.*; 044import com.oracle.graal.api.replacements.*; 045import com.oracle.graal.api.runtime.*; 046import com.oracle.graal.compiler.target.*; 047import com.oracle.graal.debug.*; 048import com.oracle.graal.graph.*; 049import com.oracle.graal.hotspot.debug.*; 050import com.oracle.graal.hotspot.logging.*; 051import com.oracle.graal.hotspot.meta.*; 052import com.oracle.graal.replacements.*; 053import com.oracle.graal.runtime.*; 054 055//JaCoCo Exclude 056 057/** 058 * Singleton class holding the instance of the {@link GraalRuntime}. 059 */ 060public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider, HotSpotProxified { 061 062 private static final HotSpotGraalRuntime instance; 063 064 static { 065 try (InitTimer t0 = timer("HotSpotGraalRuntime.<clinit>")) { 066 try (InitTimer t = timer("HotSpotGraalRuntime.<init>")) { 067 instance = new HotSpotGraalRuntime(); 068 } 069 070 try (InitTimer t = timer("HotSpotGraalRuntime.completeInitialization")) { 071 // Why deferred initialization? See comment in completeInitialization(). 072 instance.completeInitialization(); 073 } 074 } 075 } 076 077 /** 078 * Gets the singleton {@link HotSpotGraalRuntime} object. 079 */ 080 public static HotSpotGraalRuntime runtime() { 081 assert instance != null; 082 return instance; 083 } 084 085 @Override 086 public HotSpotJVMCIRuntimeProvider getJVMCIRuntime() { 087 return jvmciRuntime; 088 } 089 090 private boolean checkArrayIndexScaleInvariants() { 091 assert getJVMCIRuntime().getArrayIndexScale(Kind.Byte) == 1; 092 assert getJVMCIRuntime().getArrayIndexScale(Kind.Boolean) == 1; 093 assert getJVMCIRuntime().getArrayIndexScale(Kind.Char) == 2; 094 assert getJVMCIRuntime().getArrayIndexScale(Kind.Short) == 2; 095 assert getJVMCIRuntime().getArrayIndexScale(Kind.Int) == 4; 096 assert getJVMCIRuntime().getArrayIndexScale(Kind.Long) == 8; 097 assert getJVMCIRuntime().getArrayIndexScale(Kind.Float) == 4; 098 assert getJVMCIRuntime().getArrayIndexScale(Kind.Double) == 8; 099 return true; 100 } 101 102 public static class Options { 103 104 // @formatter:off 105 @Option(help = "The runtime configuration to use", type = OptionType.Expert) 106 static final OptionValue<String> GraalRuntime = new OptionValue<>(""); 107 // @formatter:on 108 } 109 110 private static HotSpotBackendFactory findFactory(String architecture) { 111 HotSpotBackendFactory basic = null; 112 HotSpotBackendFactory selected = null; 113 HotSpotBackendFactory nonBasic = null; 114 int nonBasicCount = 0; 115 116 assert GraalRuntime.getValue().equals(HotSpotJVMCIRuntime.Options.JVMCIRuntime.getValue()); 117 118 for (HotSpotBackendFactory factory : Services.load(HotSpotBackendFactory.class)) { 119 if (factory.getArchitecture().equalsIgnoreCase(architecture)) { 120 if (factory.getGraalRuntimeName().equals(GraalRuntime.getValue())) { 121 assert selected == null || checkFactoryOverriding(selected, factory); 122 selected = factory; 123 } 124 if (factory.getGraalRuntimeName().equals("basic")) { 125 assert basic == null || checkFactoryOverriding(basic, factory); 126 basic = factory; 127 } else { 128 nonBasic = factory; 129 nonBasicCount++; 130 } 131 } 132 } 133 134 if (selected != null) { 135 return selected; 136 } else { 137 if (!GraalRuntime.getValue().equals("")) { 138 // Fail fast if a non-default value for GraalRuntime was specified 139 // and the corresponding factory is not available 140 throw new JVMCIError("Specified runtime \"%s\" not available for the %s architecture", GraalRuntime.getValue(), architecture); 141 } else if (nonBasicCount == 1) { 142 // If there is exactly one non-basic runtime, select this one. 143 return nonBasic; 144 } else { 145 return basic; 146 } 147 } 148 } 149 150 /** 151 * Checks that a factory overriding is valid. A factory B can only override/replace a factory A 152 * if the B.getClass() is a subclass of A.getClass(). This models the assumption that B is 153 * extends the behavior of A and has therefore understood the behavior expected of A. 154 * 155 * @param baseFactory 156 * @param overridingFactory 157 */ 158 private static boolean checkFactoryOverriding(HotSpotBackendFactory baseFactory, HotSpotBackendFactory overridingFactory) { 159 return baseFactory.getClass().isAssignableFrom(overridingFactory.getClass()); 160 } 161 162 /** 163 * Gets the kind of a word value on the {@linkplain #getHostBackend() host} backend. 164 */ 165 public static Kind getHostWordKind() { 166 return instance.getHostBackend().getTarget().wordKind; 167 } 168 169 /** 170 * Reads a klass pointer from a constant object. 171 */ 172 public static long unsafeReadKlassPointer(Object object) { 173 return instance.getCompilerToVM().readUnsafeKlassPointer(object); 174 } 175 176 /** 177 * Reads a word value from a given object. 178 */ 179 public static long unsafeReadWord(Object object, long offset) { 180 if (getHostWordKind() == Kind.Long) { 181 return unsafe.getLong(object, offset); 182 } 183 return unsafe.getInt(object, offset) & 0xFFFFFFFFL; 184 } 185 186 private final HotSpotBackend hostBackend; 187 private DebugValuesPrinter debugValuesPrinter; 188 189 /** 190 * Graal mirrors are stored as a {@link ClassValue} associated with the {@link Class} of the 191 * type. This data structure stores both {@link HotSpotResolvedObjectType} and 192 * {@link HotSpotResolvedPrimitiveType} types. 193 */ 194 private final ClassValue<ResolvedJavaType> graalMirrors = new ClassValue<ResolvedJavaType>() { 195 @Override 196 protected ResolvedJavaType computeValue(Class<?> javaClass) { 197 if (javaClass.isPrimitive()) { 198 Kind kind = Kind.fromJavaClass(javaClass); 199 return new HotSpotResolvedPrimitiveType(kind); 200 } else { 201 return new HotSpotResolvedObjectTypeImpl(javaClass); 202 } 203 } 204 }; 205 206 private final Map<Class<? extends Architecture>, HotSpotBackend> backends = new HashMap<>(); 207 208 private final HotSpotJVMCIRuntime jvmciRuntime; 209 210 private HotSpotGraalRuntime() { 211 212 jvmciRuntime = (HotSpotJVMCIRuntime) JVMCI.getRuntime(); 213 214 HotSpotVMConfig config = getConfig(); 215 CompileTheWorld.Options.overrideWithNativeOptions(config); 216 217 // Only set HotSpotPrintInlining if it still has its default value (false). 218 if (HotSpotPrintInlining.getValue() == false) { 219 HotSpotPrintInlining.setValue(config.printInlining); 220 } 221 222 if (Boolean.valueOf(System.getProperty("graal.printconfig"))) { 223 printConfig(config); 224 } 225 226 String hostArchitecture = config.getHostArchitectureName(); 227 228 HotSpotBackendFactory factory; 229 try (InitTimer t = timer("find factory:", hostArchitecture)) { 230 factory = findFactory(hostArchitecture); 231 } 232 try (InitTimer t = timer("create backend:", hostArchitecture)) { 233 hostBackend = registerBackend(factory.createBackend(this, jvmciRuntime.getHostJVMCIBackend(), null)); 234 } 235 236 String[] gpuArchitectures = getGPUArchitectureNames(getCompilerToVM()); 237 for (String arch : gpuArchitectures) { 238 try (InitTimer t = timer("find factory:", arch)) { 239 factory = findFactory(arch); 240 } 241 if (factory == null) { 242 throw new JVMCIError("No backend available for specified GPU architecture \"%s\"", arch); 243 } 244 try (InitTimer t = timer("create backend:", arch)) { 245 registerBackend(factory.createBackend(this, null, hostBackend)); 246 } 247 } 248 } 249 250 /** 251 * Do deferred initialization. 252 */ 253 private void completeInitialization() { 254 255 if (Log.getValue() == null && !areScopedMetricsOrTimersEnabled() && Dump.getValue() == null && Verify.getValue() == null) { 256 if (MethodFilter.getValue() != null) { 257 TTY.println("WARNING: Ignoring MethodFilter option since Log, Meter, Time, TrackMemUse, Dump and Verify options are all null"); 258 } 259 } 260 261 if (Debug.isEnabled()) { 262 DebugEnvironment.initialize(TTY.out); 263 264 String summary = DebugValueSummary.getValue(); 265 if (summary != null) { 266 switch (summary) { 267 case "Name": 268 case "Partial": 269 case "Complete": 270 case "Thread": 271 break; 272 default: 273 throw new JVMCIError("Unsupported value for DebugSummaryValue: %s", summary); 274 } 275 } 276 } 277 278 if (Debug.areUnconditionalMetricsEnabled() || Debug.areUnconditionalTimersEnabled() || (Debug.isEnabled() && areScopedMetricsOrTimersEnabled())) { 279 // This must be created here to avoid loading the DebugValuesPrinter class 280 // during shutdown() which in turn can cause a deadlock 281 debugValuesPrinter = new DebugValuesPrinter(); 282 } 283 284 // Complete initialization of backends 285 try (InitTimer st = timer(hostBackend.getTarget().arch.getName(), ".completeInitialization")) { 286 hostBackend.completeInitialization(); 287 } 288 for (HotSpotBackend backend : backends.values()) { 289 if (backend != hostBackend) { 290 try (InitTimer st = timer(backend.getTarget().arch.getName(), ".completeInitialization")) { 291 backend.completeInitialization(); 292 } 293 } 294 } 295 296 BenchmarkCounters.initialize(getCompilerToVM()); 297 298 assert checkArrayIndexScaleInvariants(); 299 300 runtimeStartTime = System.nanoTime(); 301 } 302 303 private HotSpotBackend registerBackend(HotSpotBackend backend) { 304 Class<? extends Architecture> arch = backend.getTarget().arch.getClass(); 305 HotSpotBackend oldValue = backends.put(arch, backend); 306 assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName(); 307 return backend; 308 } 309 310 public ResolvedJavaType fromClass(Class<?> javaClass) { 311 return graalMirrors.get(javaClass); 312 } 313 314 /** 315 * Gets the names of the supported GPU architectures for the purpose of finding the 316 * corresponding {@linkplain HotSpotBackendFactory backend} objects. 317 */ 318 private static String[] getGPUArchitectureNames(CompilerToVM c2vm) { 319 String gpuList = c2vm.getGPUs(); 320 if (!gpuList.isEmpty()) { 321 String[] gpus = gpuList.split(","); 322 return gpus; 323 } 324 return new String[0]; 325 } 326 327 private static void printConfig(HotSpotVMConfig config) { 328 Field[] fields = config.getClass().getDeclaredFields(); 329 Map<String, Field> sortedFields = new TreeMap<>(); 330 for (Field f : fields) { 331 f.setAccessible(true); 332 sortedFields.put(f.getName(), f); 333 } 334 for (Field f : sortedFields.values()) { 335 try { 336 Logger.info(String.format("%9s %-40s = %s", f.getType().getSimpleName(), f.getName(), Logger.pretty(f.get(config)))); 337 } catch (Exception e) { 338 } 339 } 340 } 341 342 public HotSpotProviders getHostProviders() { 343 return getHostBackend().getProviders(); 344 } 345 346 @Override 347 public String getName() { 348 return getClass().getSimpleName(); 349 } 350 351 private final NodeCollectionsProvider nodeCollectionsProvider = new DefaultNodeCollectionsProvider(); 352 353 @SuppressWarnings("unchecked") 354 @Override 355 public <T> T getCapability(Class<T> clazz) { 356 if (clazz == RuntimeProvider.class) { 357 return (T) this; 358 } else if (clazz == CollectionsProvider.class || clazz == NodeCollectionsProvider.class) { 359 return (T) nodeCollectionsProvider; 360 } else if (clazz == StackIntrospection.class) { 361 return (T) this; 362 } else if (clazz == SnippetReflectionProvider.class) { 363 return (T) getHostProviders().getSnippetReflection(); 364 } 365 return null; 366 } 367 368 public HotSpotBackend getHostBackend() { 369 return hostBackend; 370 } 371 372 public <T extends Architecture> Backend getBackend(Class<T> arch) { 373 assert arch != Architecture.class; 374 return backends.get(arch); 375 } 376 377 public Map<Class<? extends Architecture>, HotSpotBackend> getBackends() { 378 return Collections.unmodifiableMap(backends); 379 } 380 381 @Override 382 public <T> T iterateFrames(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip, InspectedFrameVisitor<T> visitor) { 383 final long[] initialMetaMethods = toMeta(initialMethods); 384 final long[] matchingMetaMethods = toMeta(matchingMethods); 385 386 CompilerToVM compilerToVM = getCompilerToVM(); 387 HotSpotStackFrameReference current = compilerToVM.getNextStackFrame(null, initialMetaMethods, initialSkip); 388 while (current != null) { 389 T result = visitor.visitFrame(current); 390 if (result != null) { 391 return result; 392 } 393 current = compilerToVM.getNextStackFrame(current, matchingMetaMethods, 0); 394 } 395 return null; 396 } 397 398 private static long[] toMeta(ResolvedJavaMethod[] methods) { 399 if (methods == null) { 400 return null; 401 } else { 402 long[] result = new long[methods.length]; 403 for (int i = 0; i < result.length; i++) { 404 result[i] = ((HotSpotResolvedJavaMethodImpl) methods[i]).getMetaspaceMethod(); 405 } 406 return result; 407 } 408 } 409 410 private long runtimeStartTime; 411 412 /** 413 * Take action related to entering a new execution phase. 414 * 415 * @param phase the execution phase being entered 416 */ 417 static void phaseTransition(String phase) { 418 CompilationStatistics.clear(phase); 419 } 420 421 void shutdown() { 422 if (debugValuesPrinter != null) { 423 debugValuesPrinter.printDebugValues(); 424 } 425 phaseTransition("final"); 426 427 SnippetCounter.printGroups(TTY.out().out()); 428 BenchmarkCounters.shutdown(getCompilerToVM(), runtimeStartTime); 429 } 430}