21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 package jdk.vm.ci.hotspot; |
23 package jdk.vm.ci.hotspot; |
24 |
24 |
25 import static jdk.vm.ci.common.InitTimer.timer; |
25 import static jdk.vm.ci.common.InitTimer.timer; |
|
26 import static jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory.CompilationLevelAdjustment.None; |
|
27 import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; |
|
28 import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; |
26 |
29 |
27 import java.io.IOException; |
30 import java.io.IOException; |
28 import java.io.OutputStream; |
31 import java.io.OutputStream; |
29 import java.io.PrintStream; |
32 import java.io.PrintStream; |
|
33 import java.io.Serializable; |
|
34 |
|
35 import java.lang.invoke.CallSite; |
|
36 import java.lang.invoke.ConstantCallSite; |
|
37 import java.lang.invoke.MethodHandle; |
30 import java.lang.module.ModuleDescriptor.Requires; |
38 import java.lang.module.ModuleDescriptor.Requires; |
|
39 import java.lang.ref.WeakReference; |
|
40 |
|
41 import java.util.ArrayList; |
31 import java.util.Collections; |
42 import java.util.Collections; |
32 import java.util.HashMap; |
43 import java.util.HashMap; |
33 import java.util.HashSet; |
44 import java.util.HashSet; |
34 import java.util.List; |
45 import java.util.List; |
35 import java.util.Map; |
46 import java.util.Map; |
36 import java.util.Objects; |
47 import java.util.Objects; |
37 import java.util.ServiceLoader; |
48 import java.util.ServiceLoader; |
38 import java.util.Set; |
49 import java.util.TreeMap; |
39 import java.util.function.Predicate; |
50 import java.util.function.Predicate; |
40 |
51 |
41 import jdk.internal.misc.VM; |
|
42 import jdk.internal.misc.Unsafe; |
52 import jdk.internal.misc.Unsafe; |
|
53 |
43 import jdk.vm.ci.code.Architecture; |
54 import jdk.vm.ci.code.Architecture; |
44 import jdk.vm.ci.code.CompilationRequestResult; |
55 import jdk.vm.ci.code.CompilationRequestResult; |
45 import jdk.vm.ci.code.CompiledCode; |
56 import jdk.vm.ci.code.CompiledCode; |
46 import jdk.vm.ci.code.InstalledCode; |
57 import jdk.vm.ci.code.InstalledCode; |
47 import jdk.vm.ci.common.InitTimer; |
58 import jdk.vm.ci.common.InitTimer; |
55 import jdk.vm.ci.runtime.JVMCIBackend; |
66 import jdk.vm.ci.runtime.JVMCIBackend; |
56 import jdk.vm.ci.runtime.JVMCICompiler; |
67 import jdk.vm.ci.runtime.JVMCICompiler; |
57 import jdk.vm.ci.runtime.JVMCICompilerFactory; |
68 import jdk.vm.ci.runtime.JVMCICompilerFactory; |
58 import jdk.vm.ci.runtime.JVMCIRuntime; |
69 import jdk.vm.ci.runtime.JVMCIRuntime; |
59 import jdk.vm.ci.services.JVMCIServiceLocator; |
70 import jdk.vm.ci.services.JVMCIServiceLocator; |
60 |
71 import jdk.vm.ci.services.Services; |
61 import static jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory.CompilationLevelAdjustment.None; |
|
62 |
72 |
63 /** |
73 /** |
64 * HotSpot implementation of a JVMCI runtime. |
74 * HotSpot implementation of a JVMCI runtime. |
65 * |
|
66 * The initialization of this class is very fragile since it's initialized both through |
|
67 * {@link JVMCI#initialize()} or through calling {@link HotSpotJVMCIRuntime#runtime()} and |
|
68 * {@link HotSpotJVMCIRuntime#runtime()} is also called by {@link JVMCI#initialize()}. So this class |
|
69 * can't have a static initializer and any required initialization must be done as part of |
|
70 * {@link #runtime()}. This allows the initialization to funnel back through |
|
71 * {@link JVMCI#initialize()} without deadlocking. |
|
72 */ |
75 */ |
73 public final class HotSpotJVMCIRuntime implements JVMCIRuntime { |
76 public final class HotSpotJVMCIRuntime implements JVMCIRuntime { |
74 |
77 |
|
78 /** |
|
79 * Singleton instance lazily initialized via double-checked locking. |
|
80 */ |
|
81 @NativeImageReinitialize private static volatile HotSpotJVMCIRuntime instance; |
|
82 |
|
83 private HotSpotResolvedObjectTypeImpl javaLangObject; |
|
84 private HotSpotResolvedObjectTypeImpl javaLangInvokeMethodHandle; |
|
85 private HotSpotResolvedObjectTypeImpl constantCallSiteType; |
|
86 private HotSpotResolvedObjectTypeImpl callSiteType; |
|
87 private HotSpotResolvedObjectTypeImpl javaLangString; |
|
88 private HotSpotResolvedObjectTypeImpl javaLangClass; |
|
89 private HotSpotResolvedObjectTypeImpl throwableType; |
|
90 private HotSpotResolvedObjectTypeImpl serializableType; |
|
91 private HotSpotResolvedObjectTypeImpl cloneableType; |
|
92 private HotSpotResolvedObjectTypeImpl enumType; |
|
93 |
|
94 HotSpotResolvedObjectTypeImpl getJavaLangObject() { |
|
95 if (javaLangObject == null) { |
|
96 javaLangObject = (HotSpotResolvedObjectTypeImpl) fromClass(Object.class); |
|
97 } |
|
98 return javaLangObject; |
|
99 } |
|
100 |
|
101 HotSpotResolvedObjectTypeImpl getJavaLangString() { |
|
102 if (javaLangString == null) { |
|
103 javaLangString = (HotSpotResolvedObjectTypeImpl) fromClass(String.class); |
|
104 } |
|
105 return javaLangString; |
|
106 } |
|
107 |
|
108 HotSpotResolvedObjectTypeImpl getJavaLangClass() { |
|
109 if (javaLangClass == null) { |
|
110 javaLangClass = (HotSpotResolvedObjectTypeImpl) fromClass(Class.class); |
|
111 } |
|
112 return javaLangClass; |
|
113 } |
|
114 |
|
115 HotSpotResolvedObjectTypeImpl getJavaLangCloneable() { |
|
116 if (cloneableType == null) { |
|
117 cloneableType = (HotSpotResolvedObjectTypeImpl) fromClass(Cloneable.class); |
|
118 } |
|
119 return cloneableType; |
|
120 } |
|
121 |
|
122 HotSpotResolvedObjectTypeImpl getJavaLangSerializable() { |
|
123 if (serializableType == null) { |
|
124 serializableType = (HotSpotResolvedObjectTypeImpl) fromClass(Serializable.class); |
|
125 } |
|
126 return serializableType; |
|
127 } |
|
128 |
|
129 HotSpotResolvedObjectTypeImpl getJavaLangThrowable() { |
|
130 if (throwableType == null) { |
|
131 throwableType = (HotSpotResolvedObjectTypeImpl) fromClass(Throwable.class); |
|
132 } |
|
133 return throwableType; |
|
134 } |
|
135 |
|
136 HotSpotResolvedObjectTypeImpl getJavaLangEnum() { |
|
137 if (enumType == null) { |
|
138 enumType = (HotSpotResolvedObjectTypeImpl) fromClass(Enum.class); |
|
139 } |
|
140 return enumType; |
|
141 } |
|
142 |
|
143 HotSpotResolvedObjectTypeImpl getConstantCallSite() { |
|
144 if (constantCallSiteType == null) { |
|
145 constantCallSiteType = (HotSpotResolvedObjectTypeImpl) fromClass(ConstantCallSite.class); |
|
146 } |
|
147 return constantCallSiteType; |
|
148 } |
|
149 |
|
150 HotSpotResolvedObjectTypeImpl getCallSite() { |
|
151 if (callSiteType == null) { |
|
152 callSiteType = (HotSpotResolvedObjectTypeImpl) fromClass(CallSite.class); |
|
153 } |
|
154 return callSiteType; |
|
155 } |
|
156 |
|
157 HotSpotResolvedObjectType getMethodHandleClass() { |
|
158 if (javaLangInvokeMethodHandle == null) { |
|
159 javaLangInvokeMethodHandle = (HotSpotResolvedObjectTypeImpl) fromClass(MethodHandle.class); |
|
160 } |
|
161 return javaLangInvokeMethodHandle; |
|
162 } |
|
163 |
|
164 /** |
|
165 * Gets the singleton {@link HotSpotJVMCIRuntime} object. |
|
166 */ |
|
167 @VMEntryPoint |
75 @SuppressWarnings("try") |
168 @SuppressWarnings("try") |
76 static class DelayedInit { |
169 public static HotSpotJVMCIRuntime runtime() { |
77 private static final HotSpotJVMCIRuntime instance; |
170 HotSpotJVMCIRuntime result = instance; |
78 |
171 if (result == null) { |
79 static { |
172 // Synchronize on JVMCI.class to avoid deadlock |
80 try (InitTimer t = timer("HotSpotJVMCIRuntime.<init>")) { |
173 // between the two JVMCI initialization paths: |
81 instance = new HotSpotJVMCIRuntime(); |
174 // HotSpotJVMCIRuntime.runtime() and JVMCI.getRuntime(). |
82 |
175 synchronized (JVMCI.class) { |
83 // Can only do eager initialization of the JVMCI compiler |
176 result = instance; |
84 // once the singleton instance is available. |
177 if (result == null) { |
85 if (instance.config.getFlag("EagerJVMCI", Boolean.class)) { |
178 try (InitTimer t = timer("HotSpotJVMCIRuntime.<init>")) { |
86 instance.getCompiler(); |
179 instance = result = new HotSpotJVMCIRuntime(); |
|
180 |
|
181 // Can only do eager initialization of the JVMCI compiler |
|
182 // once the singleton instance is available. |
|
183 if (instance.config.getFlag("EagerJVMCI", Boolean.class)) { |
|
184 instance.getCompiler(); |
|
185 } |
|
186 } |
|
187 // Ensures JVMCIRuntime::_HotSpotJVMCIRuntime_instance is |
|
188 // initialized. |
|
189 JVMCI.getRuntime(); |
87 } |
190 } |
88 } |
191 } |
89 } |
192 } |
90 } |
193 return result; |
91 |
194 } |
92 /** |
195 |
93 * Gets the singleton {@link HotSpotJVMCIRuntime} object. |
196 @VMEntryPoint |
94 */ |
197 static Throwable decodeThrowable(String encodedThrowable) throws Throwable { |
95 public static HotSpotJVMCIRuntime runtime() { |
198 return TranslatedException.decodeThrowable(encodedThrowable); |
96 JVMCI.initialize(); |
199 } |
97 return DelayedInit.instance; |
200 |
|
201 @VMEntryPoint |
|
202 static String encodeThrowable(Throwable throwable) throws Throwable { |
|
203 return TranslatedException.encodeThrowable(throwable); |
|
204 } |
|
205 |
|
206 @VMEntryPoint |
|
207 static String callToString(Object o) { |
|
208 return o.toString(); |
98 } |
209 } |
99 |
210 |
100 /** |
211 /** |
101 * A list of all supported JVMCI options. |
212 * A list of all supported JVMCI options. |
102 */ |
213 */ |
103 public enum Option { |
214 public enum Option { |
104 // @formatter:off |
215 // @formatter:off |
105 Compiler(String.class, null, "Selects the system compiler. This must match the getCompilerName() value returned " + |
216 Compiler(String.class, null, "Selects the system compiler. This must match the getCompilerName() value returned " + |
106 "by a jdk.vm.ci.runtime.JVMCICompilerFactory provider. " + |
217 "by a jdk.vm.ci.runtime.JVMCICompilerFactory provider. " + |
107 "An empty string or the value \"null\" selects a compiler " + |
218 "An empty string or the value \"null\" selects a compiler " + |
108 "that will raise an exception upon receiving a compilation request."), |
219 "that will raise an exception upon receiving a compilation request."), |
109 // Note: The following one is not used (see InitTimer.ENABLED). It is added here |
220 // Note: The following one is not used (see InitTimer.ENABLED). It is added here |
110 // so that -XX:+JVMCIPrintProperties shows the option. |
221 // so that -XX:+JVMCIPrintProperties shows the option. |
111 InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."), |
222 InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."), |
112 PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."), |
223 PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."), |
113 TraceMethodDataFilter(String.class, null, |
224 TraceMethodDataFilter(String.class, null, |
114 "Enables tracing of profiling info when read by JVMCI.", |
225 "Enables tracing of profiling info when read by JVMCI.", |
115 "Empty value: trace all methods", |
226 "Empty value: trace all methods", |
116 "Non-empty value: trace methods whose fully qualified name contains the value."), |
227 "Non-empty value: trace methods whose fully qualified name contains the value."), |
117 UseProfilingInformation(Boolean.class, true, ""); |
228 UseProfilingInformation(Boolean.class, true, ""); |
118 // @formatter:on |
229 // @formatter:on |
119 |
230 |
120 /** |
231 /** |
121 * The prefix for system properties that are JVMCI options. |
232 * The prefix for system properties that are JVMCI options. |
122 */ |
233 */ |
123 private static final String JVMCI_OPTION_PROPERTY_PREFIX = "jvmci."; |
234 private static final String JVMCI_OPTION_PROPERTY_PREFIX = "jvmci."; |
124 |
235 |
125 /** |
236 /** |
126 * Marker for uninitialized flags. |
237 * Sentinel for value initialized to {@code null} since {@code null} means uninitialized. |
127 */ |
238 */ |
128 private static final String UNINITIALIZED = "UNINITIALIZED"; |
239 private static final String NULL_VALUE = "NULL"; |
129 |
240 |
130 private final Class<?> type; |
241 private final Class<?> type; |
131 private Object value; |
242 @NativeImageReinitialize private Object value; |
132 private final Object defaultValue; |
243 private final Object defaultValue; |
133 private boolean isDefault; |
244 private boolean isDefault; |
134 private final String[] helpLines; |
245 private final String[] helpLines; |
135 |
246 |
136 Option(Class<?> type, Object defaultValue, String... helpLines) { |
247 Option(Class<?> type, Object defaultValue, String... helpLines) { |
137 assert Character.isUpperCase(name().charAt(0)) : "Option name must start with upper-case letter: " + name(); |
248 assert Character.isUpperCase(name().charAt(0)) : "Option name must start with upper-case letter: " + name(); |
138 this.type = type; |
249 this.type = type; |
139 this.value = UNINITIALIZED; |
|
140 this.defaultValue = defaultValue; |
250 this.defaultValue = defaultValue; |
141 this.helpLines = helpLines; |
251 this.helpLines = helpLines; |
142 } |
252 } |
143 |
253 |
144 @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum") |
254 @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum") |
145 private Object getValue() { |
255 private Object getValue() { |
146 if (value == UNINITIALIZED) { |
256 if (value == null) { |
147 String propertyValue = VM.getSavedProperty(getPropertyName()); |
257 String propertyValue = Services.getSavedProperty(getPropertyName()); |
148 if (propertyValue == null) { |
258 if (propertyValue == null) { |
149 this.value = defaultValue; |
259 this.value = defaultValue == null ? NULL_VALUE : defaultValue; |
150 this.isDefault = true; |
260 this.isDefault = true; |
151 } else { |
261 } else { |
152 if (type == Boolean.class) { |
262 if (type == Boolean.class) { |
153 this.value = Boolean.parseBoolean(propertyValue); |
263 this.value = Boolean.parseBoolean(propertyValue); |
154 } else if (type == String.class) { |
264 } else if (type == String.class) { |
222 } |
330 } |
223 } |
331 } |
224 } |
332 } |
225 } |
333 } |
226 |
334 |
227 static HotSpotJVMCIBackendFactory findFactory(String architecture) { |
335 private static HotSpotJVMCIBackendFactory findFactory(String architecture) { |
228 for (HotSpotJVMCIBackendFactory factory : ServiceLoader.load(HotSpotJVMCIBackendFactory.class, ClassLoader.getSystemClassLoader())) { |
336 Iterable<HotSpotJVMCIBackendFactory> factories = getHotSpotJVMCIBackendFactories(); |
|
337 assert factories != null : "sanity"; |
|
338 for (HotSpotJVMCIBackendFactory factory : factories) { |
229 if (factory.getArchitecture().equalsIgnoreCase(architecture)) { |
339 if (factory.getArchitecture().equalsIgnoreCase(architecture)) { |
230 return factory; |
340 return factory; |
231 } |
341 } |
232 } |
342 } |
233 |
343 |
234 throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture); |
344 throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture); |
235 } |
345 } |
236 |
346 |
|
347 private static volatile List<HotSpotJVMCIBackendFactory> cachedHotSpotJVMCIBackendFactories; |
|
348 |
|
349 @SuppressFBWarnings(value = "LI_LAZY_INIT_UPDATE_STATIC", justification = "not sure about this") |
|
350 private static Iterable<HotSpotJVMCIBackendFactory> getHotSpotJVMCIBackendFactories() { |
|
351 if (IS_IN_NATIVE_IMAGE || cachedHotSpotJVMCIBackendFactories != null) { |
|
352 return cachedHotSpotJVMCIBackendFactories; |
|
353 } |
|
354 Iterable<HotSpotJVMCIBackendFactory> result = ServiceLoader.load(HotSpotJVMCIBackendFactory.class, ClassLoader.getSystemClassLoader()); |
|
355 if (IS_BUILDING_NATIVE_IMAGE) { |
|
356 cachedHotSpotJVMCIBackendFactories = new ArrayList<>(); |
|
357 for (HotSpotJVMCIBackendFactory factory : result) { |
|
358 cachedHotSpotJVMCIBackendFactories.add(factory); |
|
359 } |
|
360 } |
|
361 return result; |
|
362 } |
|
363 |
237 /** |
364 /** |
238 * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend. |
365 * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend. |
239 */ |
366 */ |
240 public static JavaKind getHostWordKind() { |
367 public static JavaKind getHostWordKind() { |
241 return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordJavaKind; |
368 return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordJavaKind; |
242 } |
369 } |
243 |
370 |
244 final CompilerToVM compilerToVm; |
371 protected final CompilerToVM compilerToVm; |
245 |
372 |
246 protected final HotSpotVMConfigStore configStore; |
373 protected final HotSpotVMConfigStore configStore; |
247 private final HotSpotVMConfig config; |
374 protected final HotSpotVMConfig config; |
248 private final JVMCIBackend hostBackend; |
375 private final JVMCIBackend hostBackend; |
249 |
376 |
250 private final JVMCICompilerFactory compilerFactory; |
377 private final JVMCICompilerFactory compilerFactory; |
251 private final HotSpotJVMCICompilerFactory hsCompilerFactory; |
378 private final HotSpotJVMCICompilerFactory hsCompilerFactory; |
252 private volatile JVMCICompiler compiler; |
379 private volatile JVMCICompiler compiler; |
253 final HotSpotJVMCIMetaAccessContext metaAccessContext; |
380 protected final HotSpotJVMCIReflection reflection; |
|
381 |
|
382 @NativeImageReinitialize private volatile boolean creatingCompiler; |
|
383 |
|
384 /** |
|
385 * Cache for speeding up {@link #fromClass(Class)}. |
|
386 */ |
|
387 @NativeImageReinitialize private volatile ClassValue<WeakReference<HotSpotResolvedJavaType>> resolvedJavaType; |
|
388 |
|
389 @NativeImageReinitialize private HashMap<Long, WeakReference<ResolvedJavaType>> resolvedJavaTypes; |
254 |
390 |
255 /** |
391 /** |
256 * Stores the value set by {@link #excludeFromJVMCICompilation(Module...)} so that it can |
392 * Stores the value set by {@link #excludeFromJVMCICompilation(Module...)} so that it can |
257 * be read from the VM. |
393 * be read from the VM. |
258 */ |
394 */ |
259 @SuppressWarnings("unused") @NativeImageReinitialize private Module[] excludeFromJVMCICompilation; |
395 @SuppressWarnings("unused")// |
|
396 @NativeImageReinitialize private Module[] excludeFromJVMCICompilation; |
260 |
397 |
261 |
398 |
262 private final Map<Class<? extends Architecture>, JVMCIBackend> backends = new HashMap<>(); |
399 private final Map<Class<? extends Architecture>, JVMCIBackend> backends = new HashMap<>(); |
263 |
400 |
264 private volatile List<HotSpotVMEventListener> vmEventListeners; |
401 private volatile List<HotSpotVMEventListener> vmEventListeners; |
308 } else { |
453 } else { |
309 hsCompilerFactory = null; |
454 hsCompilerFactory = null; |
310 } |
455 } |
311 |
456 |
312 if (config.getFlag("JVMCIPrintProperties", Boolean.class)) { |
457 if (config.getFlag("JVMCIPrintProperties", Boolean.class)) { |
313 PrintStream out = new PrintStream(getLogStream()); |
458 if (vmLogStream == null) { |
314 Option.printProperties(out); |
459 vmLogStream = new PrintStream(getLogStream()); |
315 compilerFactory.printProperties(out); |
460 } |
|
461 Option.printProperties(vmLogStream); |
|
462 compilerFactory.printProperties(vmLogStream); |
316 System.exit(0); |
463 System.exit(0); |
317 } |
464 } |
318 |
465 |
319 if (Option.PrintConfig.getBoolean()) { |
466 if (Option.PrintConfig.getBoolean()) { |
320 configStore.printConfig(); |
467 printConfig(configStore, compilerToVm); |
321 } |
468 } |
|
469 } |
|
470 |
|
471 HotSpotResolvedJavaType createClass(Class<?> javaClass) { |
|
472 if (javaClass.isPrimitive()) { |
|
473 return HotSpotResolvedPrimitiveType.forKind(JavaKind.fromJavaClass(javaClass)); |
|
474 } |
|
475 if (IS_IN_NATIVE_IMAGE) { |
|
476 try { |
|
477 return compilerToVm.lookupType(javaClass.getName().replace('.', '/'), null, true); |
|
478 } catch (ClassNotFoundException e) { |
|
479 throw new JVMCIError(e); |
|
480 } |
|
481 } |
|
482 return compilerToVm.lookupClass(javaClass); |
|
483 } |
|
484 |
|
485 private HotSpotResolvedJavaType fromClass0(Class<?> javaClass) { |
|
486 if (resolvedJavaType == null) { |
|
487 synchronized (this) { |
|
488 if (resolvedJavaType == null) { |
|
489 resolvedJavaType = new ClassValue<WeakReference<HotSpotResolvedJavaType>>() { |
|
490 @Override |
|
491 protected WeakReference<HotSpotResolvedJavaType> computeValue(Class<?> type) { |
|
492 return new WeakReference<>(createClass(type)); |
|
493 } |
|
494 }; |
|
495 } |
|
496 } |
|
497 } |
|
498 HotSpotResolvedJavaType javaType = null; |
|
499 while (javaType == null) { |
|
500 WeakReference<HotSpotResolvedJavaType> type = resolvedJavaType.get(javaClass); |
|
501 javaType = type.get(); |
|
502 if (javaType == null) { |
|
503 /* |
|
504 * If the referent has become null, clear out the current value and let computeValue |
|
505 * above create a new value. Reload the value in a loop because in theory the |
|
506 * WeakReference referent can be reclaimed at any point. |
|
507 */ |
|
508 resolvedJavaType.remove(javaClass); |
|
509 } |
|
510 } |
|
511 return javaType; |
|
512 } |
|
513 |
|
514 /** |
|
515 * Gets the JVMCI mirror for a {@link Class} object. |
|
516 * |
|
517 * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} |
|
518 */ |
|
519 HotSpotResolvedJavaType fromClass(Class<?> javaClass) { |
|
520 if (javaClass == null) { |
|
521 return null; |
|
522 } |
|
523 return fromClass0(javaClass); |
|
524 } |
|
525 |
|
526 synchronized HotSpotResolvedObjectTypeImpl fromMetaspace(long klassPointer, String signature) { |
|
527 if (resolvedJavaTypes == null) { |
|
528 resolvedJavaTypes = new HashMap<>(); |
|
529 } |
|
530 assert klassPointer != 0; |
|
531 WeakReference<ResolvedJavaType> klassReference = resolvedJavaTypes.get(klassPointer); |
|
532 HotSpotResolvedObjectTypeImpl javaType = null; |
|
533 if (klassReference != null) { |
|
534 javaType = (HotSpotResolvedObjectTypeImpl) klassReference.get(); |
|
535 } |
|
536 if (javaType == null) { |
|
537 javaType = new HotSpotResolvedObjectTypeImpl(klassPointer, signature); |
|
538 resolvedJavaTypes.put(klassPointer, new WeakReference<>(javaType)); |
|
539 } |
|
540 return javaType; |
322 } |
541 } |
323 |
542 |
324 private JVMCIBackend registerBackend(JVMCIBackend backend) { |
543 private JVMCIBackend registerBackend(JVMCIBackend backend) { |
325 Class<? extends Architecture> arch = backend.getCodeCache().getTarget().arch.getClass(); |
544 Class<? extends Architecture> arch = backend.getCodeCache().getTarget().arch.getClass(); |
326 JVMCIBackend oldValue = backends.put(arch, backend); |
545 JVMCIBackend oldValue = backends.put(arch, backend); |
327 assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName(); |
546 assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName(); |
328 return backend; |
547 return backend; |
329 } |
548 } |
330 |
549 |
331 ResolvedJavaType fromClass(Class<?> javaClass) { |
|
332 return metaAccessContext.fromClass(javaClass); |
|
333 } |
|
334 |
|
335 public HotSpotVMConfigStore getConfigStore() { |
550 public HotSpotVMConfigStore getConfigStore() { |
336 return configStore; |
551 return configStore; |
337 } |
552 } |
338 |
553 |
339 HotSpotVMConfig getConfig() { |
554 public HotSpotVMConfig getConfig() { |
340 return config; |
555 return config; |
341 } |
556 } |
342 |
557 |
343 CompilerToVM getCompilerToVM() { |
558 public CompilerToVM getCompilerToVM() { |
344 return compilerToVm; |
559 return compilerToVm; |
345 } |
560 } |
346 |
561 |
347 // Non-volatile since multi-initialization is harmless |
562 HotSpotJVMCIReflection getReflection() { |
348 private Predicate<ResolvedJavaType> intrinsificationTrustPredicate; |
563 return reflection; |
|
564 } |
349 |
565 |
350 /** |
566 /** |
351 * Gets a predicate that determines if a given type can be considered trusted for the purpose of |
567 * Gets a predicate that determines if a given type can be considered trusted for the purpose of |
352 * intrinsifying methods it declares. |
568 * intrinsifying methods it declares. |
353 * |
569 * |
354 * @param compilerLeafClasses classes in the leaves of the module graph comprising the JVMCI |
570 * @param compilerLeafClasses classes in the leaves of the module graph comprising the JVMCI |
355 * compiler. |
571 * compiler. |
356 */ |
572 */ |
357 public Predicate<ResolvedJavaType> getIntrinsificationTrustPredicate(Class<?>... compilerLeafClasses) { |
573 public Predicate<ResolvedJavaType> getIntrinsificationTrustPredicate(Class<?>... compilerLeafClasses) { |
358 if (intrinsificationTrustPredicate == null) { |
574 return new Predicate<ResolvedJavaType>() { |
359 intrinsificationTrustPredicate = new Predicate<>() { |
575 @Override |
360 @Override |
576 public boolean test(ResolvedJavaType type) { |
361 public boolean test(ResolvedJavaType type) { |
577 if (type instanceof HotSpotResolvedObjectTypeImpl) { |
362 if (type instanceof HotSpotResolvedJavaType) { |
578 HotSpotResolvedObjectTypeImpl hsType = (HotSpotResolvedObjectTypeImpl) type; |
363 Class<?> mirror = getMirror(type); |
579 return compilerToVm.isTrustedForIntrinsics(hsType); |
364 Module module = mirror.getModule(); |
580 } else { |
365 return getTrustedModules().contains(module); |
581 return false; |
366 } else { |
|
367 return false; |
|
368 } |
|
369 } |
582 } |
370 |
583 } |
371 private volatile Set<Module> trustedModules; |
584 }; |
372 |
|
373 private Set<Module> getTrustedModules() { |
|
374 Set<Module> modules = trustedModules; |
|
375 if (modules == null) { |
|
376 modules = new HashSet<>(); |
|
377 for (Class<?> compilerConfiguration : compilerLeafClasses) { |
|
378 Module compilerConfigurationModule = compilerConfiguration.getModule(); |
|
379 if (compilerConfigurationModule.getDescriptor().isAutomatic()) { |
|
380 throw new IllegalArgumentException(String.format("The module '%s' defining the Graal compiler configuration class '%s' must not be an automatic module", |
|
381 compilerConfigurationModule.getName(), compilerConfiguration.getClass().getName())); |
|
382 } |
|
383 modules.add(compilerConfigurationModule); |
|
384 for (Requires require : compilerConfigurationModule.getDescriptor().requires()) { |
|
385 for (Module module : compilerConfigurationModule.getLayer().modules()) { |
|
386 if (module.getName().equals(require.name())) { |
|
387 modules.add(module); |
|
388 } |
|
389 } |
|
390 } |
|
391 } |
|
392 trustedModules = modules; |
|
393 } |
|
394 return modules; |
|
395 } |
|
396 }; |
|
397 } |
|
398 return intrinsificationTrustPredicate; |
|
399 } |
585 } |
400 |
586 |
401 /** |
587 /** |
402 * Get the {@link Class} corresponding to {@code type}. |
588 * Get the {@link Class} corresponding to {@code type}. |
403 * |
589 * |
404 * @param type the type for which a {@link Class} is requested |
590 * @param type the type for which a {@link Class} is requested |
405 * @return the original Java class corresponding to {@code type} or {@code null} if this runtime |
591 * @return the original Java class corresponding to {@code type} or {@code null} if this runtime |
406 * does not support mapping {@link ResolvedJavaType} instances to {@link Class} |
592 * does not support mapping {@link ResolvedJavaType} instances to {@link Class} |
407 * instances |
593 * instances |
408 */ |
594 */ |
409 @SuppressWarnings("static-method") |
|
410 public Class<?> getMirror(ResolvedJavaType type) { |
595 public Class<?> getMirror(ResolvedJavaType type) { |
411 return ((HotSpotResolvedJavaType) type).mirror(); |
596 if (type instanceof HotSpotResolvedJavaType && reflection instanceof HotSpotJDKReflection) { |
|
597 return ((HotSpotJDKReflection) reflection).getMirror((HotSpotResolvedJavaType) type); |
|
598 } |
|
599 return null; |
412 } |
600 } |
413 |
601 |
414 @Override |
602 @Override |
415 public JVMCICompiler getCompiler() { |
603 public JVMCICompiler getCompiler() { |
416 if (compiler == null) { |
604 if (compiler == null) { |
417 synchronized (this) { |
605 synchronized (this) { |
418 if (compiler == null) { |
606 if (compiler == null) { |
|
607 assert !creatingCompiler : "recursive compiler creation"; |
|
608 creatingCompiler = true; |
419 compiler = compilerFactory.createCompiler(this); |
609 compiler = compilerFactory.createCompiler(this); |
|
610 creatingCompiler = false; |
420 } |
611 } |
421 } |
612 } |
422 } |
613 } |
423 return compiler; |
614 return compiler; |
424 } |
615 } |
436 * @throws LinkageError if {@code resolve == true} and the resolution failed |
627 * @throws LinkageError if {@code resolve == true} and the resolution failed |
437 * @throws NullPointerException if {@code accessingClass} is {@code null} |
628 * @throws NullPointerException if {@code accessingClass} is {@code null} |
438 */ |
629 */ |
439 public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { |
630 public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { |
440 Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class"); |
631 Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class"); |
|
632 return lookupTypeInternal(name, accessingType, resolve); |
|
633 } |
|
634 |
|
635 JavaType lookupTypeInternal(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { |
441 // If the name represents a primitive type we can short-circuit the lookup. |
636 // If the name represents a primitive type we can short-circuit the lookup. |
442 if (name.length() == 1) { |
637 if (name.length() == 1) { |
443 JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); |
638 JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); |
444 return fromClass(kind.toJavaClass()); |
639 return HotSpotResolvedPrimitiveType.forKind(kind); |
445 } |
640 } |
446 |
641 |
447 // Resolve non-primitive types in the VM. |
642 // Resolve non-primitive types in the VM. |
448 HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType; |
643 HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType; |
449 try { |
644 try { |
450 final HotSpotResolvedObjectTypeImpl klass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve); |
645 final HotSpotResolvedJavaType klass = compilerToVm.lookupType(name, hsAccessingType, resolve); |
451 |
646 |
452 if (klass == null) { |
647 if (klass == null) { |
453 assert resolve == false; |
648 assert resolve == false : name; |
454 return UnresolvedJavaType.create(name); |
649 return UnresolvedJavaType.create(name); |
455 } |
650 } |
456 return klass; |
651 return klass; |
457 } catch (ClassNotFoundException e) { |
652 } catch (ClassNotFoundException e) { |
458 throw (NoClassDefFoundError) new NoClassDefFoundError().initCause(e); |
653 throw (NoClassDefFoundError) new NoClassDefFoundError().initCause(e); |
530 * @param compiledCode |
722 * @param compiledCode |
531 */ |
723 */ |
532 void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompiledCode compiledCode) { |
724 void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompiledCode compiledCode) { |
533 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { |
725 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { |
534 vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compiledCode); |
726 vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compiledCode); |
|
727 } |
|
728 } |
|
729 |
|
730 @SuppressFBWarnings(value = "DM_DEFAULT_ENCODING", justification = "no localization here please!") |
|
731 private static void printConfigLine(CompilerToVM vm, String format, Object... args) { |
|
732 String line = String.format(format, args); |
|
733 byte[] lineBytes = line.getBytes(); |
|
734 vm.writeDebugOutput(lineBytes, 0, lineBytes.length); |
|
735 vm.flushDebugOutput(); |
|
736 } |
|
737 |
|
738 private static void printConfig(HotSpotVMConfigStore store, CompilerToVM vm) { |
|
739 TreeMap<String, VMField> fields = new TreeMap<>(store.getFields()); |
|
740 for (VMField field : fields.values()) { |
|
741 if (!field.isStatic()) { |
|
742 printConfigLine(vm, "[vmconfig:instance field] %s %s {offset=%d[0x%x]}%n", field.type, field.name, field.offset, field.offset); |
|
743 } else { |
|
744 String value = field.value == null ? "null" : field.value instanceof Boolean ? field.value.toString() : String.format("%d[0x%x]", field.value, field.value); |
|
745 printConfigLine(vm, "[vmconfig:static field] %s %s = %s {address=0x%x}%n", field.type, field.name, value, field.address); |
|
746 } |
|
747 } |
|
748 TreeMap<String, VMFlag> flags = new TreeMap<>(store.getFlags()); |
|
749 for (VMFlag flag : flags.values()) { |
|
750 printConfigLine(vm, "[vmconfig:flag] %s %s = %s%n", flag.type, flag.name, flag.value); |
|
751 } |
|
752 TreeMap<String, Long> addresses = new TreeMap<>(store.getAddresses()); |
|
753 for (Map.Entry<String, Long> e : addresses.entrySet()) { |
|
754 printConfigLine(vm, "[vmconfig:address] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue()); |
|
755 } |
|
756 TreeMap<String, Long> constants = new TreeMap<>(store.getConstants()); |
|
757 for (Map.Entry<String, Long> e : constants.entrySet()) { |
|
758 printConfigLine(vm, "[vmconfig:constant] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue()); |
|
759 } |
|
760 for (VMIntrinsicMethod e : store.getIntrinsics()) { |
|
761 printConfigLine(vm, "[vmconfig:intrinsic] %d = %s.%s %s%n", e.id, e.declaringClass, e.name, e.descriptor); |
535 } |
762 } |
536 } |
763 } |
537 |
764 |
538 /** |
765 /** |
539 * Gets an output stream that writes to HotSpot's {@code tty} stream. |
766 * Gets an output stream that writes to HotSpot's {@code tty} stream. |
663 * private static long getHandle(Method method) { ... } |
888 * private static long getHandle(Method method) { ... } |
664 * private static char[] convertToCharArray(String[] a) { ... } |
889 * private static char[] convertToCharArray(String[] a) { ... } |
665 * } |
890 * } |
666 * </pre> |
891 * </pre> |
667 * |
892 * |
668 * The implementation of the native {@code JCompile.compile0} method would be in the SVM library |
893 * The implementation of the native {@code JCompile.compile0} method would be in the JVMCI |
669 * that contains the bulk of the JVMCI compiler. The {@code JCompile.compile0} implementation |
894 * shared library that contains the bulk of the JVMCI compiler. The {@code JCompile.compile0} |
670 * will be exported as the following JNI-compliant symbol: |
895 * implementation will be exported as the following JNI-compatible symbol: |
671 * |
896 * |
672 * <pre> |
897 * <pre> |
673 * Java_com_jcompile_JCompile_compile0 |
898 * Java_com_jcompile_JCompile_compile0 |
674 * </pre> |
899 * </pre> |
675 * |
900 * |
676 * How the JVMCI compiler SVM library is built is outside the scope of this document. |
901 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names" |
677 * |
902 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#creating_the_vm" |
678 * @see "https://docs.oracle.com/javase/10/docs/specs/jni/design.html#resolving-native-method-names" |
903 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#invocation_api_functions" |
679 * |
904 * |
|
905 * |
|
906 * @return an array of 4 longs where the first value is the {@code JavaVM*} value representing |
|
907 * the Java VM in the JVMCI shared library, and the remaining values are the first 3 |
|
908 * pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface}) |
680 * @throws NullPointerException if {@code clazz == null} |
909 * @throws NullPointerException if {@code clazz == null} |
681 * @throws IllegalArgumentException if the current execution context is SVM or if {@code clazz} |
910 * @throws IllegalArgumentException if the current execution context is the JVMCI shared library |
682 * is {@link Class#isPrimitive()} |
911 * or if {@code clazz} is {@link Class#isPrimitive()} |
683 * @throws UnsatisfiedLinkError if the JVMCI SVM library is not available, a native method in |
912 * @throws UnsatisfiedLinkError if the JVMCI shared library is not available, a native method in |
684 * {@code clazz} is already linked or the SVM JVMCI library does not contain a |
913 * {@code clazz} is already linked or the JVMCI shared library does not contain a |
685 * JNI-compliant symbol for a native method in {@code clazz} |
914 * JNI-compatible symbol for a native method in {@code clazz} |
686 */ |
915 */ |
687 @SuppressWarnings({"static-method", "unused"}) |
916 public long[] registerNativeMethods(Class<?> clazz) { |
688 public void registerNativeMethods(Class<?> clazz) { |
917 return compilerToVm.registerNativeMethods(clazz); |
689 throw new UnsatisfiedLinkError("SVM library is not available"); |
918 } |
|
919 |
|
920 /** |
|
921 * Creates or retrieves an object in the peer runtime that mirrors {@code obj}. The types whose |
|
922 * objects can be translated are: |
|
923 * <ul> |
|
924 * <li>{@link HotSpotResolvedJavaMethodImpl},</li> |
|
925 * <li>{@link HotSpotResolvedObjectTypeImpl},</li> |
|
926 * <li>{@link HotSpotResolvedPrimitiveType},</li> |
|
927 * <li>{@link IndirectHotSpotObjectConstantImpl},</li> |
|
928 * <li>{@link DirectHotSpotObjectConstantImpl} and</li> |
|
929 * <li>{@link HotSpotNmethod}</li> |
|
930 * </ul> |
|
931 * |
|
932 * This mechanism can be used to pass and return values between the HotSpot and JVMCI shared |
|
933 * library runtimes. In the receiving runtime, the value can be converted back to an object with |
|
934 * {@link #unhand(Class, long)}. |
|
935 * |
|
936 * @param obj an object for which an equivalent instance in the peer runtime is requested |
|
937 * @return a JNI global reference to the mirror of {@code obj} in the peer runtime |
|
938 * @throws IllegalArgumentException if {@code obj} is not of a translatable type |
|
939 * |
|
940 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" |
|
941 */ |
|
942 public long translate(Object obj) { |
|
943 return compilerToVm.translate(obj); |
|
944 } |
|
945 |
|
946 /** |
|
947 * Dereferences and returns the object referred to by the JNI global reference {@code handle}. |
|
948 * The global reference is deleted prior to returning. Any further use of {@code handle} is |
|
949 * invalid. |
|
950 * |
|
951 * @param handle a JNI global reference to an object in the current runtime |
|
952 * @return the object referred to by {@code handle} |
|
953 * @throws ClassCastException if the returned object cannot be case to {@code type} |
|
954 * |
|
955 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" |
|
956 * |
|
957 */ |
|
958 public <T> T unhand(Class<T> type, long handle) { |
|
959 return type.cast(compilerToVm.unhand(handle)); |
690 } |
960 } |
691 |
961 |
692 /** |
962 /** |
693 * Informs HotSpot that no method whose module is in {@code modules} is to be compiled |
963 * Informs HotSpot that no method whose module is in {@code modules} is to be compiled |
694 * with {@link #compileMethod}. |
964 * with {@link #compileMethod}. |