1 /*
2 * Copyright (c) 2015, 2019, 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.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;
29
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.io.PrintStream;
33 import java.io.Serializable;
34 import java.lang.invoke.CallSite;
35 import java.lang.invoke.ConstantCallSite;
36 import java.lang.invoke.MethodHandle;
37 import java.lang.ref.WeakReference;
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Objects;
44 import java.util.ServiceLoader;
45 import java.util.function.Predicate;
46
47 import jdk.vm.ci.code.Architecture;
48 import jdk.vm.ci.code.CompilationRequestResult;
49 import jdk.vm.ci.code.CompiledCode;
50 import jdk.vm.ci.code.InstalledCode;
51 import jdk.vm.ci.common.InitTimer;
52 import jdk.vm.ci.common.JVMCIError;
53 import jdk.vm.ci.common.NativeImageReinitialize;
54 import jdk.vm.ci.meta.JavaKind;
55 import jdk.vm.ci.meta.JavaType;
56 import jdk.vm.ci.meta.ResolvedJavaType;
57 import jdk.vm.ci.meta.UnresolvedJavaType;
58 import jdk.vm.ci.runtime.JVMCI;
59 import jdk.vm.ci.runtime.JVMCIBackend;
194 }
195 return result;
196 }
197
198 @VMEntryPoint
199 static Throwable decodeThrowable(String encodedThrowable) throws Throwable {
200 return TranslatedException.decodeThrowable(encodedThrowable);
201 }
202
203 @VMEntryPoint
204 static String encodeThrowable(Throwable throwable) throws Throwable {
205 return TranslatedException.encodeThrowable(throwable);
206 }
207
208 @VMEntryPoint
209 static String callToString(Object o) {
210 return o.toString();
211 }
212
213 /**
214 * A list of all supported JVMCI options.
215 */
216 public enum Option {
217 // @formatter:off
218 Compiler(String.class, null, "Selects the system compiler. This must match the getCompilerName() value returned " +
219 "by a jdk.vm.ci.runtime.JVMCICompilerFactory provider. " +
220 "An empty string or the value \"null\" selects a compiler " +
221 "that will raise an exception upon receiving a compilation request."),
222 // Note: The following one is not used (see InitTimer.ENABLED). It is added here
223 // so that -XX:+JVMCIPrintProperties shows the option.
224 InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."),
225 PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."),
226 AuditHandles(Boolean.class, false, "Record stack trace along with scoped foreign object reference wrappers " +
227 "to debug issue with a wrapper being used after its scope has closed."),
228 TraceMethodDataFilter(String.class, null,
229 "Enables tracing of profiling info when read by JVMCI.",
230 "Empty value: trace all methods",
231 "Non-empty value: trace methods whose fully qualified name contains the value."),
232 UseProfilingInformation(Boolean.class, true, "");
233 // @formatter:on
234
235 /**
236 * The prefix for system properties that are JVMCI options.
237 */
238 private static final String JVMCI_OPTION_PROPERTY_PREFIX = "jvmci.";
239
240 /**
241 * Sentinel for value initialized to {@code null} since {@code null} means uninitialized.
242 */
243 private static final String NULL_VALUE = "NULL";
244
245 private final Class<?> type;
246 @NativeImageReinitialize private Object value;
247 private final Object defaultValue;
248 private boolean isDefault;
249 private final String[] helpLines;
250
251 Option(Class<?> type, Object defaultValue, String... helpLines) {
252 assert Character.isUpperCase(name().charAt(0)) : "Option name must start with upper-case letter: " + name();
253 this.type = type;
254 this.defaultValue = defaultValue;
255 this.helpLines = helpLines;
256 }
257
258 @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum")
259 private Object getValue() {
260 if (value == null) {
261 String propertyValue = Services.getSavedProperty(getPropertyName());
262 if (propertyValue == null) {
263 this.value = defaultValue == null ? NULL_VALUE : defaultValue;
264 this.isDefault = true;
265 } else {
266 if (type == Boolean.class) {
267 this.value = Boolean.parseBoolean(propertyValue);
268 } else if (type == String.class) {
269 this.value = propertyValue;
270 } else {
271 throw new JVMCIError("Unexpected option type " + type);
272 }
273 this.isDefault = false;
274 }
275 }
276 return value == NULL_VALUE ? null : value;
277 }
278
279 /**
280 * Gets the name of system property from which this option gets its value.
281 */
282 public String getPropertyName() {
283 return JVMCI_OPTION_PROPERTY_PREFIX + name();
284 }
285
286 /**
287 * Returns the option's value as boolean.
288 *
289 * @return option's value
290 */
291 public boolean getBoolean() {
292 return (boolean) getValue();
293 }
294
295 /**
296 * Returns the option's value as String.
317 if (value instanceof String) {
318 value = '"' + String.valueOf(value) + '"';
319 }
320
321 String name = option.getPropertyName();
322 String assign = option.isDefault ? "=" : ":=";
323 String typeName = option.type.getSimpleName();
324 String linePrefix = String.format("%s %s %s ", name, assign, value);
325 int typeStartPos = PROPERTY_LINE_WIDTH - typeName.length();
326 int linePad = typeStartPos - linePrefix.length();
327 if (linePad > 0) {
328 out.printf("%s%-" + linePad + "s[%s]%n", linePrefix, "", typeName);
329 } else {
330 out.printf("%s[%s]%n", linePrefix, typeName);
331 }
332 for (String line : option.helpLines) {
333 out.printf("%" + PROPERTY_HELP_INDENT + "s%s%n", "", line);
334 }
335 }
336 }
337 }
338
339 private static HotSpotJVMCIBackendFactory findFactory(String architecture) {
340 Iterable<HotSpotJVMCIBackendFactory> factories = getHotSpotJVMCIBackendFactories();
341 assert factories != null : "sanity";
342 for (HotSpotJVMCIBackendFactory factory : factories) {
343 if (factory.getArchitecture().equalsIgnoreCase(architecture)) {
344 return factory;
345 }
346 }
347
348 throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture);
349 }
350
351 private static volatile List<HotSpotJVMCIBackendFactory> cachedHotSpotJVMCIBackendFactories;
352
353 @SuppressFBWarnings(value = "LI_LAZY_INIT_UPDATE_STATIC", justification = "not sure about this")
354 private static Iterable<HotSpotJVMCIBackendFactory> getHotSpotJVMCIBackendFactories() {
355 if (IS_IN_NATIVE_IMAGE || cachedHotSpotJVMCIBackendFactories != null) {
356 return cachedHotSpotJVMCIBackendFactories;
437
438 @SuppressWarnings("try")
439 private HotSpotJVMCIRuntime() {
440 compilerToVm = new CompilerToVM();
441
442 try (InitTimer t = timer("HotSpotVMConfig<init>")) {
443 configStore = new HotSpotVMConfigStore(compilerToVm);
444 config = new HotSpotVMConfig(configStore);
445 }
446
447 reflection = IS_IN_NATIVE_IMAGE ? new SharedLibraryJVMCIReflection() : new HotSpotJDKReflection();
448
449 PrintStream vmLogStream = null;
450 if (IS_IN_NATIVE_IMAGE) {
451 // Redirect System.out and System.err to HotSpot's TTY stream
452 vmLogStream = new PrintStream(getLogStream());
453 System.setOut(vmLogStream);
454 System.setErr(vmLogStream);
455 }
456
457 String hostArchitecture = config.getHostArchitectureName();
458
459 HotSpotJVMCIBackendFactory factory;
460 try (InitTimer t = timer("find factory:", hostArchitecture)) {
461 factory = findFactory(hostArchitecture);
462 }
463
464 try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) {
465 hostBackend = registerBackend(factory.createJVMCIBackend(this, null));
466 }
467
468 compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory();
469 if (compilerFactory instanceof HotSpotJVMCICompilerFactory) {
470 hsCompilerFactory = (HotSpotJVMCICompilerFactory) compilerFactory;
471 if (hsCompilerFactory.getCompilationLevelAdjustment() != None) {
472 String name = HotSpotJVMCICompilerFactory.class.getName();
473 String msg = String.format("%s.getCompilationLevelAdjustment() is no longer supported. " +
474 "Use %s.excludeFromJVMCICompilation() instead.", name, name);
475 throw new UnsupportedOperationException(msg);
476 }
696 HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, compileState, id);
697 CompilationRequestResult result = getCompiler().compileMethod(request);
698 assert result != null : "compileMethod must always return something";
699 HotSpotCompilationRequestResult hsResult;
700 if (result instanceof HotSpotCompilationRequestResult) {
701 hsResult = (HotSpotCompilationRequestResult) result;
702 } else {
703 Object failure = result.getFailure();
704 if (failure != null) {
705 boolean retry = false; // Be conservative with unknown compiler
706 hsResult = HotSpotCompilationRequestResult.failure(failure.toString(), retry);
707 } else {
708 int inlinedBytecodes = -1;
709 hsResult = HotSpotCompilationRequestResult.success(inlinedBytecodes);
710 }
711 }
712 return hsResult;
713 }
714
715 /**
716 * Shuts down the runtime.
717 */
718 @VMEntryPoint
719 private void shutdown() throws Exception {
720 // Cleaners are normally only processed when a new Cleaner is
721 // instantiated so process all remaining cleaners now.
722 Cleaner.clean();
723
724 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) {
725 vmEventListener.notifyShutdown();
726 }
727 }
728
729 /**
730 * Notify on completion of a bootstrap.
731 */
732 @VMEntryPoint
733 private void bootstrapFinished() throws Exception {
734 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) {
735 vmEventListener.notifyBootstrapFinished();
736 }
737 }
738
739 /**
740 * Notify on successful install into the CodeCache.
741 *
742 * @param hotSpotCodeCacheProvider
743 * @param installedCode
744 * @param compiledCode
745 */
746 void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompiledCode compiledCode) {
747 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) {
898 * import java.lang.reflect.Method;
899 *
900 * public static class JCompile {
901 * static {
902 * HotSpotJVMCIRuntime.runtime().registerNativeMethods(JCompile.class);
903 * }
904 * public static boolean compile(Method method, String[] options) {
905 * // Convert to simpler data types for passing/serializing across native interface
906 * long metaspaceMethodHandle = getHandle(method);
907 * char[] opts = convertToCharArray(options);
908 * return compile(metaspaceMethodHandle, opts);
909 * }
910 * private static native boolean compile0(long metaspaceMethodHandle, char[] options);
911 *
912 * private static long getHandle(Method method) { ... }
913 * private static char[] convertToCharArray(String[] a) { ... }
914 * }
915 * </pre>
916 *
917 * The implementation of the native {@code JCompile.compile0} method would be in the JVMCI
918 * shared library that contains the bulk of the JVMCI compiler. The {@code JCompile.compile0}
919 * implementation will be exported as the following JNI-compatible symbol:
920 *
921 * <pre>
922 * Java_com_jcompile_JCompile_compile0
923 * </pre>
924 *
925 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names"
926 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#creating_the_vm"
927 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#invocation_api_functions"
928 *
929 *
930 * @return an array of 4 longs where the first value is the {@code JavaVM*} value representing
931 * the Java VM in the JVMCI shared library, and the remaining values are the first 3
932 * pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface})
933 * @throws NullPointerException if {@code clazz == null}
934 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
935 * {@code -XX:-UseJVMCINativeLibrary})
936 * @throws IllegalStateException if the current execution context is the JVMCI shared library
937 * @throws IllegalArgumentException if {@code clazz} is {@link Class#isPrimitive()}
938 * @throws UnsatisfiedLinkError if there's a problem linking a native method in {@code clazz}
939 * (no matching JNI symbol or the native method is already linked to a different
940 * address)
941 */
942 public long[] registerNativeMethods(Class<?> clazz) {
943 return compilerToVm.registerNativeMethods(clazz);
944 }
945
946 /**
947 * Creates or retrieves an object in the peer runtime that mirrors {@code obj}. The types whose
948 * objects can be translated are:
949 * <ul>
950 * <li>{@link HotSpotResolvedJavaMethodImpl},</li>
951 * <li>{@link HotSpotResolvedObjectTypeImpl},</li>
952 * <li>{@link HotSpotResolvedPrimitiveType},</li>
1001 }
1002
1003 /**
1004 * Gets the address of the HotSpot {@code JavaThread} C++ object for the current thread. This
1005 * will return {@code 0} if called from an unattached JVMCI shared library thread.
1006 */
1007 public long getCurrentJavaThread() {
1008 return compilerToVm.getCurrentJavaThread();
1009 }
1010
1011 /**
1012 * Ensures the current thread is attached to the peer runtime.
1013 *
1014 * @param asDaemon if the thread is not yet attached, should it be attached as a daemon
1015 * @return {@code true} if this call attached the current thread, {@code false} if the current
1016 * thread was already attached
1017 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
1018 * {@code -XX:-UseJVMCINativeLibrary})
1019 * @throws IllegalStateException if the peer runtime has not been initialized or there is an
1020 * error while trying to attach the thread
1021 */
1022 public boolean attachCurrentThread(boolean asDaemon) {
1023 return compilerToVm.attachCurrentThread(asDaemon);
1024 }
1025
1026 /**
1027 * Detaches the current thread from the peer runtime.
1028 *
1029 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
1030 * {@code -XX:-UseJVMCINativeLibrary})
1031 * @throws IllegalStateException if the peer runtime has not been initialized or if the current
1032 * thread is not attached or if there is an error while trying to detach the thread
1033 */
1034 public void detachCurrentThread() {
1035 compilerToVm.detachCurrentThread();
1036 }
1037
1038 /**
1039 * Informs HotSpot that no method whose module is in {@code modules} is to be compiled
1040 * with {@link #compileMethod}.
|
1 /*
2 * Copyright (c) 2015, 2020, 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.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;
29
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.io.PrintStream;
33 import java.io.Serializable;
34 import java.lang.invoke.CallSite;
35 import java.lang.invoke.ConstantCallSite;
36 import java.lang.invoke.MethodHandle;
37 import java.lang.ref.WeakReference;
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.Formatter;
41 import java.util.HashMap;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Objects;
45 import java.util.ServiceLoader;
46 import java.util.function.Predicate;
47
48 import jdk.vm.ci.code.Architecture;
49 import jdk.vm.ci.code.CompilationRequestResult;
50 import jdk.vm.ci.code.CompiledCode;
51 import jdk.vm.ci.code.InstalledCode;
52 import jdk.vm.ci.common.InitTimer;
53 import jdk.vm.ci.common.JVMCIError;
54 import jdk.vm.ci.common.NativeImageReinitialize;
55 import jdk.vm.ci.meta.JavaKind;
56 import jdk.vm.ci.meta.JavaType;
57 import jdk.vm.ci.meta.ResolvedJavaType;
58 import jdk.vm.ci.meta.UnresolvedJavaType;
59 import jdk.vm.ci.runtime.JVMCI;
60 import jdk.vm.ci.runtime.JVMCIBackend;
195 }
196 return result;
197 }
198
199 @VMEntryPoint
200 static Throwable decodeThrowable(String encodedThrowable) throws Throwable {
201 return TranslatedException.decodeThrowable(encodedThrowable);
202 }
203
204 @VMEntryPoint
205 static String encodeThrowable(Throwable throwable) throws Throwable {
206 return TranslatedException.encodeThrowable(throwable);
207 }
208
209 @VMEntryPoint
210 static String callToString(Object o) {
211 return o.toString();
212 }
213
214 /**
215 * Set of recognized {@code "jvmci.*"} system properties. Entries not associated with an
216 * {@link Option} have this object as their value.
217 */
218 static final Map<String, Object> options = new HashMap<>();
219 static {
220 options.put("jvmci.class.path.append", options);
221 }
222
223 /**
224 * A list of all supported JVMCI options.
225 */
226 public enum Option {
227 // @formatter:off
228 Compiler(String.class, null, "Selects the system compiler. This must match the getCompilerName() value returned " +
229 "by a jdk.vm.ci.runtime.JVMCICompilerFactory provider. " +
230 "An empty string or the value \"null\" selects a compiler " +
231 "that will raise an exception upon receiving a compilation request."),
232 // Note: The following one is not used (see InitTimer.ENABLED). It is added here
233 // so that -XX:+JVMCIPrintProperties shows the option.
234 InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."),
235 PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."),
236 AuditHandles(Boolean.class, false, "Record stack trace along with scoped foreign object reference wrappers " +
237 "to debug issue with a wrapper being used after its scope has closed."),
238 TraceMethodDataFilter(String.class, null,
239 "Enables tracing of profiling info when read by JVMCI.",
240 "Empty value: trace all methods",
241 "Non-empty value: trace methods whose fully qualified name contains the value."),
242 UseProfilingInformation(Boolean.class, true, "");
243 // @formatter:on
244
245 /**
246 * The prefix for system properties that are JVMCI options.
247 */
248 private static final String JVMCI_OPTION_PROPERTY_PREFIX = "jvmci.";
249
250 /**
251 * Sentinel for value initialized to {@code null} since {@code null} means uninitialized.
252 */
253 private static final String NULL_VALUE = "NULL";
254
255 private final Class<?> type;
256 @NativeImageReinitialize private Object value;
257 private final Object defaultValue;
258 private boolean isDefault = true;
259 private final String[] helpLines;
260
261 Option(Class<?> type, Object defaultValue, String... helpLines) {
262 assert Character.isUpperCase(name().charAt(0)) : "Option name must start with upper-case letter: " + name();
263 this.type = type;
264 this.defaultValue = defaultValue;
265 this.helpLines = helpLines;
266 Object existing = options.put(getPropertyName(), this);
267 assert existing == null : getPropertyName();
268 }
269
270 @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum")
271 private void init(String propertyValue) {
272 assert value == null : "cannot re-initialize " + name();
273 if (propertyValue == null) {
274 this.value = defaultValue == null ? NULL_VALUE : defaultValue;
275 this.isDefault = true;
276 } else {
277 if (type == Boolean.class) {
278 this.value = Boolean.parseBoolean(propertyValue);
279 } else if (type == String.class) {
280 this.value = propertyValue;
281 } else {
282 throw new JVMCIError("Unexpected option type " + type);
283 }
284 this.isDefault = false;
285 }
286 }
287
288 @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum")
289 private Object getValue() {
290 if (value == NULL_VALUE) {
291 return null;
292 }
293 if (value == null) {
294 return defaultValue;
295 }
296 return value;
297 }
298
299 /**
300 * Gets the name of system property from which this option gets its value.
301 */
302 public String getPropertyName() {
303 return JVMCI_OPTION_PROPERTY_PREFIX + name();
304 }
305
306 /**
307 * Returns the option's value as boolean.
308 *
309 * @return option's value
310 */
311 public boolean getBoolean() {
312 return (boolean) getValue();
313 }
314
315 /**
316 * Returns the option's value as String.
337 if (value instanceof String) {
338 value = '"' + String.valueOf(value) + '"';
339 }
340
341 String name = option.getPropertyName();
342 String assign = option.isDefault ? "=" : ":=";
343 String typeName = option.type.getSimpleName();
344 String linePrefix = String.format("%s %s %s ", name, assign, value);
345 int typeStartPos = PROPERTY_LINE_WIDTH - typeName.length();
346 int linePad = typeStartPos - linePrefix.length();
347 if (linePad > 0) {
348 out.printf("%s%-" + linePad + "s[%s]%n", linePrefix, "", typeName);
349 } else {
350 out.printf("%s[%s]%n", linePrefix, typeName);
351 }
352 for (String line : option.helpLines) {
353 out.printf("%" + PROPERTY_HELP_INDENT + "s%s%n", "", line);
354 }
355 }
356 }
357
358 /**
359 * Compute string similarity based on Dice's coefficient.
360 *
361 * Ported from str_similar() in globals.cpp.
362 */
363 static float stringSimiliarity(String str1, String str2) {
364 int hit = 0;
365 for (int i = 0; i < str1.length() - 1; ++i) {
366 for (int j = 0; j < str2.length() - 1; ++j) {
367 if ((str1.charAt(i) == str2.charAt(j)) && (str1.charAt(i + 1) == str2.charAt(j + 1))) {
368 ++hit;
369 break;
370 }
371 }
372 }
373 return 2.0f * hit / (str1.length() + str2.length());
374 }
375
376 private static final float FUZZY_MATCH_THRESHOLD = 0.7F;
377
378 /**
379 * Parses all system properties starting with {@value #JVMCI_OPTION_PROPERTY_PREFIX} and
380 * initializes the options based on their values.
381 */
382 static void parse() {
383 Map<String, String> savedProps = jdk.vm.ci.services.Services.getSavedProperties();
384 for (Map.Entry<String, String> e : savedProps.entrySet()) {
385 String name = e.getKey();
386 if (name.startsWith(Option.JVMCI_OPTION_PROPERTY_PREFIX)) {
387 Object value = options.get(name);
388 if (value == null) {
389 List<String> matches = new ArrayList<>();
390 for (String pn : options.keySet()) {
391 float score = stringSimiliarity(pn, name);
392 if (score >= FUZZY_MATCH_THRESHOLD) {
393 matches.add(pn);
394 }
395 }
396 Formatter msg = new Formatter();
397 msg.format("Could not find option %s", name);
398 if (!matches.isEmpty()) {
399 msg.format("%nDid you mean one of the following?");
400 for (String match : matches) {
401 msg.format("%n %s=<value>", match);
402 }
403 }
404 throw new IllegalArgumentException(msg.toString());
405 } else if (value instanceof Option) {
406 Option option = (Option) value;
407 option.init(e.getValue());
408 }
409 }
410 }
411 }
412 }
413
414 private static HotSpotJVMCIBackendFactory findFactory(String architecture) {
415 Iterable<HotSpotJVMCIBackendFactory> factories = getHotSpotJVMCIBackendFactories();
416 assert factories != null : "sanity";
417 for (HotSpotJVMCIBackendFactory factory : factories) {
418 if (factory.getArchitecture().equalsIgnoreCase(architecture)) {
419 return factory;
420 }
421 }
422
423 throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture);
424 }
425
426 private static volatile List<HotSpotJVMCIBackendFactory> cachedHotSpotJVMCIBackendFactories;
427
428 @SuppressFBWarnings(value = "LI_LAZY_INIT_UPDATE_STATIC", justification = "not sure about this")
429 private static Iterable<HotSpotJVMCIBackendFactory> getHotSpotJVMCIBackendFactories() {
430 if (IS_IN_NATIVE_IMAGE || cachedHotSpotJVMCIBackendFactories != null) {
431 return cachedHotSpotJVMCIBackendFactories;
512
513 @SuppressWarnings("try")
514 private HotSpotJVMCIRuntime() {
515 compilerToVm = new CompilerToVM();
516
517 try (InitTimer t = timer("HotSpotVMConfig<init>")) {
518 configStore = new HotSpotVMConfigStore(compilerToVm);
519 config = new HotSpotVMConfig(configStore);
520 }
521
522 reflection = IS_IN_NATIVE_IMAGE ? new SharedLibraryJVMCIReflection() : new HotSpotJDKReflection();
523
524 PrintStream vmLogStream = null;
525 if (IS_IN_NATIVE_IMAGE) {
526 // Redirect System.out and System.err to HotSpot's TTY stream
527 vmLogStream = new PrintStream(getLogStream());
528 System.setOut(vmLogStream);
529 System.setErr(vmLogStream);
530 }
531
532 // Initialize the Option values.
533 Option.parse();
534
535 String hostArchitecture = config.getHostArchitectureName();
536
537 HotSpotJVMCIBackendFactory factory;
538 try (InitTimer t = timer("find factory:", hostArchitecture)) {
539 factory = findFactory(hostArchitecture);
540 }
541
542 try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) {
543 hostBackend = registerBackend(factory.createJVMCIBackend(this, null));
544 }
545
546 compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory();
547 if (compilerFactory instanceof HotSpotJVMCICompilerFactory) {
548 hsCompilerFactory = (HotSpotJVMCICompilerFactory) compilerFactory;
549 if (hsCompilerFactory.getCompilationLevelAdjustment() != None) {
550 String name = HotSpotJVMCICompilerFactory.class.getName();
551 String msg = String.format("%s.getCompilationLevelAdjustment() is no longer supported. " +
552 "Use %s.excludeFromJVMCICompilation() instead.", name, name);
553 throw new UnsupportedOperationException(msg);
554 }
774 HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, compileState, id);
775 CompilationRequestResult result = getCompiler().compileMethod(request);
776 assert result != null : "compileMethod must always return something";
777 HotSpotCompilationRequestResult hsResult;
778 if (result instanceof HotSpotCompilationRequestResult) {
779 hsResult = (HotSpotCompilationRequestResult) result;
780 } else {
781 Object failure = result.getFailure();
782 if (failure != null) {
783 boolean retry = false; // Be conservative with unknown compiler
784 hsResult = HotSpotCompilationRequestResult.failure(failure.toString(), retry);
785 } else {
786 int inlinedBytecodes = -1;
787 hsResult = HotSpotCompilationRequestResult.success(inlinedBytecodes);
788 }
789 }
790 return hsResult;
791 }
792
793 /**
794 * Guard to ensure shut down actions are performed at most once.
795 */
796 private boolean isShutdown;
797
798 /**
799 * Shuts down the runtime.
800 */
801 @VMEntryPoint
802 private synchronized void shutdown() throws Exception {
803 if (!isShutdown) {
804 isShutdown = true;
805 // Cleaners are normally only processed when a new Cleaner is
806 // instantiated so process all remaining cleaners now.
807 Cleaner.clean();
808
809 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) {
810 vmEventListener.notifyShutdown();
811 }
812 }
813 }
814
815 /**
816 * Notify on completion of a bootstrap.
817 */
818 @VMEntryPoint
819 private void bootstrapFinished() throws Exception {
820 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) {
821 vmEventListener.notifyBootstrapFinished();
822 }
823 }
824
825 /**
826 * Notify on successful install into the CodeCache.
827 *
828 * @param hotSpotCodeCacheProvider
829 * @param installedCode
830 * @param compiledCode
831 */
832 void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompiledCode compiledCode) {
833 for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) {
984 * import java.lang.reflect.Method;
985 *
986 * public static class JCompile {
987 * static {
988 * HotSpotJVMCIRuntime.runtime().registerNativeMethods(JCompile.class);
989 * }
990 * public static boolean compile(Method method, String[] options) {
991 * // Convert to simpler data types for passing/serializing across native interface
992 * long metaspaceMethodHandle = getHandle(method);
993 * char[] opts = convertToCharArray(options);
994 * return compile(metaspaceMethodHandle, opts);
995 * }
996 * private static native boolean compile0(long metaspaceMethodHandle, char[] options);
997 *
998 * private static long getHandle(Method method) { ... }
999 * private static char[] convertToCharArray(String[] a) { ... }
1000 * }
1001 * </pre>
1002 *
1003 * The implementation of the native {@code JCompile.compile0} method would be in the JVMCI
1004 * shared library that contains the JVMCI compiler. The {@code JCompile.compile0} implementation
1005 * must be exported as the following JNI-compatible symbol:
1006 *
1007 * <pre>
1008 * Java_com_jcompile_JCompile_compile0
1009 * </pre>
1010 *
1011 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names"
1012 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#creating_the_vm"
1013 * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#invocation_api_functions"
1014 *
1015 *
1016 * @return info about the Java VM in the JVMCI shared library {@code JavaVM*}. The info is
1017 * encoded in a long array as follows:
1018 *
1019 * <pre>
1020 * long[] info = {
1021 * javaVM, // the {@code JavaVM*} value
1022 * javaVM->functions->reserved0,
1023 * javaVM->functions->reserved1,
1024 * javaVM->functions->reserved2
1025 * }
1026 * </pre>
1027 *
1028 * @throws NullPointerException if {@code clazz == null}
1029 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
1030 * {@code -XX:-UseJVMCINativeLibrary})
1031 * @throws IllegalStateException if the current execution context is the JVMCI shared library
1032 * @throws IllegalArgumentException if {@code clazz} is {@link Class#isPrimitive()}
1033 * @throws UnsatisfiedLinkError if there's a problem linking a native method in {@code clazz}
1034 * (no matching JNI symbol or the native method is already linked to a different
1035 * address)
1036 */
1037 public long[] registerNativeMethods(Class<?> clazz) {
1038 return compilerToVm.registerNativeMethods(clazz);
1039 }
1040
1041 /**
1042 * Creates or retrieves an object in the peer runtime that mirrors {@code obj}. The types whose
1043 * objects can be translated are:
1044 * <ul>
1045 * <li>{@link HotSpotResolvedJavaMethodImpl},</li>
1046 * <li>{@link HotSpotResolvedObjectTypeImpl},</li>
1047 * <li>{@link HotSpotResolvedPrimitiveType},</li>
1096 }
1097
1098 /**
1099 * Gets the address of the HotSpot {@code JavaThread} C++ object for the current thread. This
1100 * will return {@code 0} if called from an unattached JVMCI shared library thread.
1101 */
1102 public long getCurrentJavaThread() {
1103 return compilerToVm.getCurrentJavaThread();
1104 }
1105
1106 /**
1107 * Ensures the current thread is attached to the peer runtime.
1108 *
1109 * @param asDaemon if the thread is not yet attached, should it be attached as a daemon
1110 * @return {@code true} if this call attached the current thread, {@code false} if the current
1111 * thread was already attached
1112 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
1113 * {@code -XX:-UseJVMCINativeLibrary})
1114 * @throws IllegalStateException if the peer runtime has not been initialized or there is an
1115 * error while trying to attach the thread
1116 * @throws ArrayIndexOutOfBoundsException if {@code javaVMInfo} is non-null and is shorter than
1117 * the length of the array returned by {@link #registerNativeMethods}
1118 */
1119 public boolean attachCurrentThread(boolean asDaemon) {
1120 return compilerToVm.attachCurrentThread(asDaemon);
1121 }
1122
1123 /**
1124 * Detaches the current thread from the peer runtime.
1125 *
1126 * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
1127 * {@code -XX:-UseJVMCINativeLibrary})
1128 * @throws IllegalStateException if the peer runtime has not been initialized or if the current
1129 * thread is not attached or if there is an error while trying to detach the thread
1130 */
1131 public void detachCurrentThread() {
1132 compilerToVm.detachCurrentThread();
1133 }
1134
1135 /**
1136 * Informs HotSpot that no method whose module is in {@code modules} is to be compiled
1137 * with {@link #compileMethod}.
|