From 989102d3751029afe40d4d1ca190481a6446a266 Mon Sep 17 00:00:00 2001 From: Thomas Garcia Date: Tue, 18 Mar 2025 17:28:43 +0100 Subject: [PATCH 1/7] Espresso: run guest jdk 25. --- .../espresso/classfile/JavaVersion.java | 19 +- .../espresso/launcher/EspressoLauncher.java | 3 + .../truffle/espresso/libjavavm/Arguments.java | 2 + .../include/jvm.h | 264 ++++++++++-------- .../include/mokapot.h | 24 ++ .../mapfile-vers | 13 +- .../src/mokapot.c | 57 +++- .../shared/resolver/LinkResolver.java | 1 + .../truffle/espresso/EspressoOptions.java | 31 +- .../constantpool/RuntimeConstantPool.java | 3 +- .../espresso/descriptors/EspressoSymbols.java | 12 + .../truffle/espresso/impl/ClassRegistry.java | 2 +- .../oracle/truffle/espresso/impl/Klass.java | 41 +-- .../espresso/impl/LinkedKlassFieldLayout.java | 4 +- .../oracle/truffle/espresso/impl/Method.java | 11 +- .../truffle/espresso/impl/ObjectKlass.java | 5 +- .../oracle/truffle/espresso/jni/JniEnv.java | 2 +- .../truffle/espresso/jni/JniVersion.java | 4 +- .../oracle/truffle/espresso/meta/Meta.java | 98 ++++++- .../espresso/runtime/GuestAllocator.java | 2 +- .../espresso/substitutions/VersionFilter.java | 12 + ...tackStreamFactory_AbstractStackWalker.java | 29 ++ .../standard/Target_java_lang_Thread.java | 5 + ..._java_lang_invoke_MethodHandleNatives.java | 1 + .../standard/Target_sun_misc_Unsafe.java | 2 +- .../oracle/truffle/espresso/vm/StackWalk.java | 111 ++++++-- .../com/oracle/truffle/espresso/vm/VM.java | 55 +++- 27 files changed, 601 insertions(+), 212 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java index 5b37c565444e..3979e320da15 100644 --- a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java @@ -37,7 +37,12 @@ public static final class VersionRange { public static final VersionRange VERSION_19_OR_HIGHER = higher(19); public static final VersionRange VERSION_20_OR_LOWER = lower(20); public static final VersionRange VERSION_21_OR_HIGHER = higher(21); + public static final VersionRange VERSION_21_OR_LOWER = lower(21); + public static final VersionRange VERSION_22_OR_HIGHER = higher(22); + public static final VersionRange VERSION_25_OR_HIGHER = higher(25); + public static final VersionRange ALL = new VersionRange(0, LATEST_SUPPORTED); + public static final VersionRange VERSION_9_TO_21 = new VersionRange(9, 21); private final int low; private final int high; @@ -62,7 +67,7 @@ public boolean contains(JavaVersion version) { public static final JavaVersion HOST_VERSION = forVersion(Runtime.version()); - public static final int LATEST_SUPPORTED = 21; + public static final int LATEST_SUPPORTED = 25; private final int version; @@ -172,6 +177,18 @@ public boolean java21OrLater() { return version >= 21; } + public boolean java21OrEarlier() { + return version <= 21; + } + + public boolean java22OrLater() { + return version >= 22; + } + + public boolean java23OrEarlier() { + return version <= 23; + } + public boolean inRange(int low, int high) { return version >= low && version <= high; } diff --git a/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java b/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java index 6e92f2a5013d..e7f1d4bb1a9f 100644 --- a/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java +++ b/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java @@ -212,6 +212,9 @@ protected List preprocessArguments(List arguments, MapJVM_BeforeHalt(); } + +JNIEXPORT void JNICALL +JVM_ExpandStackFrameInfo(JNIEnv *env, jobject obj) { + IMPLEMENTED(JVM_ExpandStackFrameInfo); + return (*getEnv())->JVM_ExpandStackFrameInfo(env, obj); +} + JNIEXPORT jobject JNICALL JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jint skip_frames, jint frame_count, jint start_index, jobjectArray frames) { @@ -1540,6 +1551,12 @@ JNIEXPORT jboolean JNICALL JVM_IsUseContainerSupport(void) { return JNI_FALSE; } +JNIEXPORT jboolean JNICALL +JVM_IsContainerized(void) { + UNIMPLEMENTED(JVM_IsContainerized); + return JNI_FALSE; +} + JNIEXPORT jobjectArray JNICALL JVM_GetRecordComponents(JNIEnv *env, jclass ofClass) { IMPLEMENTED(JVM_GetRecordComponents); return (*getEnv())->JVM_GetRecordComponents(env, ofClass); @@ -1581,6 +1598,16 @@ JNIEXPORT jboolean JNICALL JVM_IsDumpingClassList(JNIEnv* env) { return (*getEnv())->JVM_IsDumpingClassList(env); } +JNIEXPORT jint JNICALL JVM_GetCDSConfigStatus() { + IMPLEMENTED(JVM_GetCDSConfigStatus); + return (*getEnv())->JVM_GetCDSConfigStatus(); +} + +JNIEXPORT jboolean JNICALL JVM_NeedsClassInitBarrierForCDS(JNIEnv* env, jclass cls) { + UNIMPLEMENTED(JVM_NeedsClassInitBarrierForCDS); + return 0; +} + JNIEXPORT jstring JNICALL JVM_GetExtendedNPEMessage(JNIEnv *env, jthrowable throwable) { IMPLEMENTED(JVM_GetExtendedNPEMessage); return (*getEnv())->JVM_GetExtendedNPEMessage(env, throwable); @@ -1650,24 +1677,24 @@ JNIEXPORT void JNICALL JVM_DumpDynamicArchive(JNIEnv *env, jstring archiveName) UNIMPLEMENTED(JVM_DumpDynamicArchive); } -JNIEXPORT void JNICALL JVM_VirtualThreadMountBegin(JNIEnv* env, jobject vthread, jboolean first_mount) { - UNIMPLEMENTED(JVM_VirtualThreadUnmountBegin); -} - -JNIEXPORT void JNICALL JVM_VirtualThreadMountEnd(JNIEnv* env, jobject vthread, jboolean first_mount) { - UNIMPLEMENTED(JVM_VirtualThreadUnmountEnd); +JNIEXPORT void JNICALL JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide) { + UNIMPLEMENTED(JVM_VirtualThreadHideFrames); } -JNIEXPORT void JNICALL JVM_VirtualThreadUnmountBegin(JNIEnv* env, jobject vthread, jboolean last_unmount) { - UNIMPLEMENTED(JVM_VirtualThreadUnmountBegin); +JNIEXPORT void JNICALL +JVM_VirtualThreadDisableSuspend(JNIEnv* env, jclass clazz, jboolean enter) { + UNIMPLEMENTED(JVM_VirtualThreadDisableSuspend); } -JNIEXPORT void JNICALL JVM_VirtualThreadUnmountEnd(JNIEnv* env, jobject vthread, jboolean last_unmount) { - UNIMPLEMENTED(JVM_VirtualThreadUnmountEnd); +JNIEXPORT void JNICALL +JVM_VirtualThreadPinnedEvent(JNIEnv* env, jclass clazz, jstring op) { + UNIMPLEMENTED(JVM_VirtualThreadPinnedEvent); } -JNIEXPORT void JNICALL JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide) { - UNIMPLEMENTED(JVM_VirtualThreadHideFrames); +JNIEXPORT jobject JNICALL +JVM_TakeVirtualThreadListToUnblock(JNIEnv* env, jclass ignored) { + UNIMPLEMENTED(JVM_TakeVirtualThreadListToUnblock); + return NULL; } JNIEXPORT jint JNICALL JVM_GetClassFileVersion(JNIEnv *env, jclass current) { @@ -1680,6 +1707,12 @@ JNIEXPORT jboolean JNICALL JVM_IsForeignLinkerSupported(void) { return (*getEnv())->JVM_IsForeignLinkerSupported(); } +JNIEXPORT jboolean JNICALL +JVM_IsStaticallyLinked(void) { + UNIMPLEMENTED(JVM_IsStaticallyLinked); + return JNI_FALSE; +} + JNIEXPORT void JNICALL JVM_VirtualThreadStart(JNIEnv* env, jobject vthread) { UNIMPLEMENTED(JVM_VirtualThreadStart); } diff --git a/espresso/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/resolver/LinkResolver.java b/espresso/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/resolver/LinkResolver.java index 3e935b23df99..a847fc940532 100644 --- a/espresso/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/resolver/LinkResolver.java +++ b/espresso/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/resolver/LinkResolver.java @@ -545,6 +545,7 @@ private static , C extends TypeAccess, // version of the class file. if (!resolved.isConstructor()) { if (!symbolicHolder.isInterface() && + currentKlass != null && symbolicHolder != currentKlass && currentKlass.getSuperClass() != null && symbolicHolder != currentKlass.getSuperClass() && diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java index 62afcb08317d..27c37e547835 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java @@ -154,6 +154,16 @@ public List apply(String strings) { usageSyntax = "" + PATH_SEPARATOR_INSERT + "" + PATH_SEPARATOR_INSERT + "...") // public static final OptionKey> EnableNativeAccess = new OptionKey<>(Collections.emptyList(), STRINGS_OPTION_TYPE); + @Option(help = "Allow or deny access to code and data outside the Java runtime " + + "by code in modules for which native access is not explicitly enabled. " + + " is one of `deny`, `warn` or `allow`. The default value is `warn`. " + + "This option will be removed in a future release." + + "\\nEquivalent to '--illegal-native-access='", // + category = OptionCategory.USER, // + stability = OptionStability.STABLE, // + usageSyntax = "warn|deny|allow") // + public static final OptionKey IllegalNativeAccess = new OptionKey<>(""); + @Option(help = "Installation directory for Java Runtime Environment (JRE).", // category = OptionCategory.EXPERT, // stability = OptionStability.STABLE, // @@ -653,17 +663,16 @@ public enum JImageMode { JAVA, } - private static final OptionType JIMAGE_MODE_OPTION_TYPE = new OptionType<>("JImageMode", - new Function() { - @Override - public JImageMode apply(String s) { - try { - return JImageMode.valueOf(s.toUpperCase(Locale.ROOT)); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("JImage: Mode can be 'native', 'java'."); - } - } - }); + private static final OptionType JIMAGE_MODE_OPTION_TYPE = new OptionType<>("JImageMode", new Function() { + @Override + public JImageMode apply(String s) { + try { + return JImageMode.valueOf(s.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("JImage: Mode can be 'native', 'java'."); + } + } + }); @Option(help = "Selects the jimage reader.", // category = OptionCategory.EXPERT, stability = OptionStability.EXPERIMENTAL) // diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/RuntimeConstantPool.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/RuntimeConstantPool.java index ced4da5edb9c..18efa6b43d6e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/RuntimeConstantPool.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/RuntimeConstantPool.java @@ -479,7 +479,8 @@ public static boolean memberCheckAccess(Klass accessingKlass, Klass resolvedKlas return true; } // MagicAccessorImpl marks internal reflection classes that have access to everything. - if (accessingKlass.getMeta().sun_reflect_MagicAccessorImpl.isAssignableFrom(accessingKlass)) { + if (accessingKlass.getJavaVersion().java23OrEarlier() && + accessingKlass.getMeta().sun_reflect_MagicAccessorImpl.isAssignableFrom(accessingKlass)) { return true; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java index b0da0d90786b..2bdee35335b1 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java @@ -379,6 +379,8 @@ public static void ensureInitialized() { public static final Symbol java_lang_StackStreamFactory = SYMBOLS.putType("Ljava/lang/StackStreamFactory;"); public static final Symbol java_lang_StackStreamFactory_AbstractStackWalker = SYMBOLS.putType("Ljava/lang/StackStreamFactory$AbstractStackWalker;"); public static final Symbol java_lang_StackFrameInfo = SYMBOLS.putType("Ljava/lang/StackFrameInfo;"); + public static final Symbol java_lang_ClassFrameInfo = SYMBOLS.putType("Ljava/lang/ClassFrameInfo;"); + public static final Symbol java_lang_invoke_ResolvedMethodName = SYMBOLS.putType("Ljava/lang/invoke/ResolvedMethodName;"); // Special threads public static final Symbol java_lang_ref_Finalizer$FinalizerThread = SYMBOLS.putType("Ljava/lang/ref/Finalizer$FinalizerThread;"); @@ -600,6 +602,7 @@ public static class Names { public static final Symbol classLoader = SYMBOLS.putName("classLoader"); public static final Symbol classRedefinedCount = SYMBOLS.putName("classRedefinedCount"); public static final Symbol componentType = SYMBOLS.putName("componentType"); + public static final Symbol protectionDomain = SYMBOLS.putName("protectionDomain"); // j.l.ClassLoader public static final Symbol addClass = SYMBOLS.putName("addClass"); public static final Symbol findNative = SYMBOLS.putName("findNative"); @@ -683,6 +686,7 @@ public static class Names { public static final Symbol doStackWalk = SYMBOLS.putName("doStackWalk"); public static final Symbol callStackWalk = SYMBOLS.putName("callStackWalk"); // j.l.StackFrameInfo + public static final Symbol classOrMemberName = SYMBOLS.putName("classOrMemberName"); public static final Symbol memberName = SYMBOLS.putName("memberName"); public static final Symbol bci = SYMBOLS.putName("bci"); // io @@ -762,6 +766,9 @@ public static class Names { // MemberName public static final Symbol flags = SYMBOLS.putName("flags"); public static final Symbol form = SYMBOLS.putName("form"); + // ResolvedMethodName + public static final Symbol vmholder = SYMBOLS.putName("vmholder"); + public static final Symbol HIDDEN_VM_METHOD = SYMBOLS.putName("0HIDDEN_VM_METHOD"); // MethodHandle public static final Symbol invoke = SYMBOLS.putName("invoke"); public static final Symbol invokeExact = SYMBOLS.putName("invokeExact"); @@ -1144,6 +1151,8 @@ public static class Signatures { public static final Symbol ByteOrder = SYMBOLS.putSignature(Types.java_nio_ByteOrder); public static final Symbol ByteBuffer_ByteOrder = SYMBOLS.putSignature(Types.java_nio_ByteBuffer, Types.java_nio_ByteOrder); public static final Symbol _long_ClassLoader_String = SYMBOLS.putSignature(Types._long, Types.java_lang_ClassLoader, Types.java_lang_String); + public static final Symbol _long_ClassLoader_Class_String_String = SYMBOLS.putSignature(Types._long, + Types.java_lang_ClassLoader, Types.java_lang_Class, Types.java_lang_String, Types.java_lang_String); public static final Symbol _void_Exception = SYMBOLS.putSignature(Types._void, Types.java_lang_Exception); public static final Symbol _void_String_String_String_int = SYMBOLS.putSignature(Types._void, Types.java_lang_String, Types.java_lang_String, Types.java_lang_String, Types._int); public static final Symbol _void_int = SYMBOLS.putSignature(Types._void, Types._int); @@ -1170,6 +1179,9 @@ public static class Signatures { public static final Symbol Object_long_int_ContinuationScope_Continuation_int_int_Object_array = SYMBOLS.putSignature(Types.java_lang_Object, Types._long, Types._int, Types.jdk_internal_vm_ContinuationScope, Types.jdk_internal_vm_Continuation, Types._int, Types._int, Types.java_lang_Object_array); + public static final Symbol Object_int_int_ContinuationScope_Continuation_int_int_Object_array = SYMBOLS.putSignature(Types.java_lang_Object, Types._int, Types._int, + Types.jdk_internal_vm_ContinuationScope, Types.jdk_internal_vm_Continuation, Types._int, Types._int, + Types.java_lang_Object_array); public static final Symbol _byte_array_String_Class_array_int = SYMBOLS.putSignature(Types._byte_array, Types.java_lang_String, Types.java_lang_Class_array, Types._int); public static final Symbol _byte_array_ClassLoader_String_List_int = SYMBOLS.putSignature(Types._byte_array, Types.java_lang_ClassLoader, Types.java_lang_String, Types.java_util_List, diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java index 5bcb2e11e29c..7cb47b6621dd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java @@ -348,7 +348,7 @@ Klass loadKlass(EspressoContext context, Symbol type, StaticObject protect } assert entry != null; StaticObject classLoader = getClassLoader(); - if (!StaticObject.isNull(classLoader)) { + if (!StaticObject.isNull(classLoader) && context.getJavaVersion().java21OrEarlier()) { entry.checkPackageAccess(env.getMeta(), classLoader, protectionDomain); } return entry.klass(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java index 7ebd57d3e127..361158f5de6e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java @@ -795,22 +795,26 @@ public static boolean checkAccess(Klass klass, ObjectKlass accessingKlass, boole } } - if (ignoreMagicAccessor) { - /* - * Prevents any class inheriting from MagicAccessorImpl to have access to - * MagicAccessorImpl just because it implements MagicAccessorImpl. - * - * Only generated accessors in the {sun|jdk.internal}.reflect package, defined by - * {sun|jdk.internal}.reflect.DelegatingClassLoader(s) have access to MagicAccessorImpl. - */ - ObjectKlass magicAccessorImpl = context.getMeta().sun_reflect_MagicAccessorImpl; - return !StaticObject.isNull(accessingKlass.getDefiningClassLoader()) && - context.getMeta().sun_reflect_DelegatingClassLoader.equals(accessingKlass.getDefiningClassLoader().getKlass()) && - magicAccessorImpl.getRuntimePackage().equals(accessingKlass.getRuntimePackage()) && - magicAccessorImpl.isAssignableFrom(accessingKlass); - } + if (context.getJavaVersion().java21OrEarlier()) { + if (ignoreMagicAccessor) { + /* + * Prevents any class inheriting from MagicAccessorImpl to have access to + * MagicAccessorImpl just because it implements MagicAccessorImpl. + * + * Only generated accessors in the {sun|jdk.internal}.reflect package, defined by + * {sun|jdk.internal}.reflect.DelegatingClassLoader(s) have access to + * MagicAccessorImpl. + */ + ObjectKlass magicAccessorImpl = context.getMeta().sun_reflect_MagicAccessorImpl; + return !StaticObject.isNull(accessingKlass.getDefiningClassLoader()) && + context.getMeta().sun_reflect_DelegatingClassLoader.equals(accessingKlass.getDefiningClassLoader().getKlass()) && + magicAccessorImpl.getRuntimePackage().equals(accessingKlass.getRuntimePackage()) && + magicAccessorImpl.isAssignableFrom(accessingKlass); + } - return (context.getMeta().sun_reflect_MagicAccessorImpl.isAssignableFrom(accessingKlass)); + return (context.getMeta().sun_reflect_MagicAccessorImpl.isAssignableFrom(accessingKlass)); + } + return false; } public static boolean doModuleAccessChecks(Klass klass, ObjectKlass accessingKlass, EspressoContext context) { @@ -1828,7 +1832,7 @@ public boolean nestMembersCheck(Klass k) { } public StaticObject protectionDomain() { - return (StaticObject) getMeta().HIDDEN_PROTECTION_DOMAIN.getHiddenObject(mirror()); + return getMeta().HIDDEN_PROTECTION_DOMAIN.getObject(mirror()); } /** @@ -1913,7 +1917,10 @@ public final Symbol getSymbolicRuntimePackage() { @Override public final boolean isMagicAccessor() { - return getMeta().sun_reflect_MagicAccessorImpl.isAssignableFrom(this); + if (getJavaVersion().java21OrEarlier()) { + return getMeta().sun_reflect_MagicAccessorImpl.isAssignableFrom(this); + } + return false; } @Override diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java index 6cb153a2302a..ebe5925f7455 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlassFieldLayout.java @@ -182,6 +182,9 @@ private static class HiddenField { new HiddenField(Names.HIDDEN_VMTARGET), new HiddenField(Names.HIDDEN_VMINDEX) }), + entry(Types.java_lang_invoke_ResolvedMethodName, new HiddenField[]{ + new HiddenField(Names.HIDDEN_VM_METHOD, Types.java_lang_Object, VersionRange.VERSION_22_OR_HIGHER, NO_ADDITIONAL_FLAGS), + }), entry(Types.java_lang_reflect_Method, new HiddenField[]{ new HiddenField(Names.HIDDEN_METHOD_RUNTIME_VISIBLE_TYPE_ANNOTATIONS), new HiddenField(Names.HIDDEN_METHOD_KEY) @@ -197,7 +200,6 @@ private static class HiddenField { // All references (including strong) get an extra hidden field, this // simplifies the code for weak/soft/phantom/final references. entry(Types.java_lang_ref_Reference, new HiddenField[]{ - new HiddenField(Names.HIDDEN_HOST_REFERENCE) }), entry(Types.java_lang_Throwable, new HiddenField[]{ diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java index 24443dea0ad9..5c811bd1fb5f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java @@ -403,7 +403,16 @@ private CallTarget lookupAgents(String[] lookupNames) { private CallTarget lookupJniCallTarget(Meta meta, String[] lookupNames) { for (String lookupName : lookupNames) { - long handle = (long) meta.java_lang_ClassLoader_findNative.invokeDirectStatic(getDeclaringKlass().getDefiningClassLoader(), meta.toGuestString(lookupName)); + long handle; + if (getJavaVersion().java21OrEarlier()) { + handle = (long) meta.java_lang_ClassLoader_findNative.invokeDirectStatic(getDeclaringKlass().getDefiningClassLoader(), meta.toGuestString(lookupName)); + } else { + handle = (long) meta.java_lang_ClassLoader_findNative.invokeDirectStatic( + getDeclaringKlass().getDefiningClassLoader(), + getDeclaringKlass().mirror(), + meta.toGuestString(lookupName), + meta.toGuestString(getName())); + } if (handle == 0) { // not found continue; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java index cabcf270ef5f..f2c9458e3653 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java @@ -223,7 +223,7 @@ public ObjectKlass(EspressoContext context, LinkedKlass linkedKlass, ObjectKlass if (info.protectionDomain != null && !StaticObject.isNull(info.protectionDomain)) { // Protection domain should not be host null, and will be initialized to guest null on // mirror creation. - getMeta().HIDDEN_PROTECTION_DOMAIN.setHiddenObject(initializeEspressoClass(), info.protectionDomain); + getMeta().HIDDEN_PROTECTION_DOMAIN.setObject(initializeEspressoClass(), info.protectionDomain); } if (info.classData != null) { getMeta().java_lang_Class_classData.setObject(initializeEspressoClass(), info.classData); @@ -698,7 +698,8 @@ private void verifyImpl() { for (ObjectKlass interf : getSuperInterfaces()) { interf.verify(); } - if (meta.sun_reflect_MagicAccessorImpl.isAssignableFrom(this)) { + if (getJavaVersion().java21OrEarlier() && + meta.sun_reflect_MagicAccessorImpl.isAssignableFrom(this)) { /* * Hotspot comment: * diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniEnv.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniEnv.java index ac6590c91c60..da6c5244697d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniEnv.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniEnv.java @@ -2881,7 +2881,7 @@ public void ReleasePrimitiveArrayCritical(@JavaType(Object.class) StaticObject o throw e; } - meta.HIDDEN_PROTECTION_DOMAIN.setHiddenObject(guestClass, protectionDomain); + meta.HIDDEN_PROTECTION_DOMAIN.setObject(guestClass, protectionDomain); // FindClass should initialize the class. guestClass.getMirrorKlass(meta).safeInitialize(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniVersion.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniVersion.java index 6c32446a82bc..e5722d23d8dd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniVersion.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniVersion.java @@ -34,7 +34,9 @@ public enum JniVersion { JNI_VERSION_10(0x000A0000), JNI_VERSION_19(0x00130000), JNI_VERSION_20(0x00140000), - JNI_VERSION_21(0x00150000); + JNI_VERSION_21(0x00150000), + JNI_VERSION_24(0x00180000), + ; private final int version; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java index 95d7c8d5c378..83c776bd41af 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java @@ -29,8 +29,12 @@ import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_19_OR_HIGHER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_20_OR_LOWER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_21_OR_HIGHER; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_21_OR_LOWER; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_22_OR_HIGHER; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_25_OR_HIGHER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_8_OR_LOWER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_9_OR_HIGHER; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_9_TO_21; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.higher; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.lower; import static com.oracle.truffle.espresso.impl.EspressoClassLoadingException.wrapClassNotFoundGuestException; @@ -49,6 +53,7 @@ import com.oracle.truffle.espresso.EspressoOptions; import com.oracle.truffle.espresso.EspressoOptions.SpecComplianceMode; import com.oracle.truffle.espresso.classfile.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaVersion; import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; import com.oracle.truffle.espresso.classfile.descriptors.Name; import com.oracle.truffle.espresso.classfile.descriptors.Symbol; @@ -113,7 +118,10 @@ public Meta(EspressoContext context) { .notRequiredField(java_lang_Class); HIDDEN_MIRROR_KLASS = java_lang_Class.requireHiddenField(Names.HIDDEN_MIRROR_KLASS); HIDDEN_SIGNERS = java_lang_Class.requireHiddenField(Names.HIDDEN_SIGNERS); - HIDDEN_PROTECTION_DOMAIN = java_lang_Class.requireHiddenField(Names.HIDDEN_PROTECTION_DOMAIN); + HIDDEN_PROTECTION_DOMAIN = diff() // + .field(lower(24), Names.HIDDEN_PROTECTION_DOMAIN, Types.java_security_ProtectionDomain) // + .field(VERSION_25_OR_HIGHER, Names.protectionDomain, Types.java_security_ProtectionDomain) // + .maybeHiddenfield(java_lang_Class); if (getJavaVersion().modulesEnabled()) { java_lang_Class_module = java_lang_Class.requireDeclaredField(Names.module, Types.java_lang_Module); @@ -348,8 +356,13 @@ public Meta(EspressoContext context) { .klass(higher(15), Types.jdk_internal_loader_NativeLibraries) // .klass(); java_lang_ClassLoader$NativeLibrary_getFromClass = java_lang_ClassLoader$NativeLibrary.requireDeclaredMethod(Names.getFromClass, Signatures.Class); - java_lang_ClassLoader_checkPackageAccess = java_lang_ClassLoader.requireDeclaredMethod(Names.checkPackageAccess, Signatures.Class_PermissionDomain); - java_lang_ClassLoader_findNative = java_lang_ClassLoader.requireDeclaredMethod(Names.findNative, Signatures._long_ClassLoader_String); + java_lang_ClassLoader_checkPackageAccess = diff() // + .method(VERSION_21_OR_LOWER, Names.checkPackageAccess, Signatures.Class_PermissionDomain) // + .notRequiredMethod(java_lang_ClassLoader); + java_lang_ClassLoader_findNative = diff() // + .method(VERSION_21_OR_LOWER, Names.findNative, Signatures._long_ClassLoader_String) // + .method(VERSION_25_OR_HIGHER, Names.findNative, Signatures._long_ClassLoader_Class_String_String) // + .method(java_lang_ClassLoader); java_lang_ClassLoader_getSystemClassLoader = java_lang_ClassLoader.requireDeclaredMethod(Names.getSystemClassLoader, Signatures.ClassLoader); java_lang_ClassLoader_parent = java_lang_ClassLoader.requireDeclaredField(Names.parent, Types.java_lang_ClassLoader); HIDDEN_CLASS_LOADER_REGISTRY = java_lang_ClassLoader.requireHiddenField(Names.HIDDEN_CLASS_LOADER_REGISTRY); @@ -590,7 +603,9 @@ public Meta(EspressoContext context) { java_lang_Thread_contextClassLoader = java_lang_Thread.requireDeclaredField(Names.contextClassLoader, Types.java_lang_ClassLoader); java_lang_Thread_name = java_lang_Thread.requireDeclaredField(Names.name, java_lang_String.getType()); - java_lang_Thread_inheritedAccessControlContext = java_lang_Thread.requireDeclaredField(Names.inheritedAccessControlContext, Types.java_security_AccessControlContext); + java_lang_Thread_inheritedAccessControlContext = diff()// + .field(VERSION_21_OR_LOWER, Names.inheritedAccessControlContext, Types.java_security_AccessControlContext)// + .notRequiredField(java_lang_Thread); java_lang_Thread_checkAccess = java_lang_Thread.requireDeclaredMethod(Names.checkAccess, Signatures._void); java_lang_Thread_stop = java_lang_Thread.requireDeclaredMethod(Names.stop, Signatures._void); java_lang_ThreadGroup_maxPriority = java_lang_ThreadGroup.requireDeclaredField(Names.maxPriority, Types._int); @@ -604,7 +619,9 @@ public Meta(EspressoContext context) { java_lang_System = knownKlass(Types.java_lang_System); java_lang_System_exit = java_lang_System.requireDeclaredMethod(Names.exit, Signatures._void_int); - java_lang_System_securityManager = java_lang_System.requireDeclaredField(Names.security, Types.java_lang_SecurityManager); + java_lang_System_securityManager = diff() // + .field(VERSION_21_OR_LOWER, Names.security, Types.java_lang_SecurityManager) // + .notRequiredField(java_lang_System); java_lang_System_in = java_lang_System.requireDeclaredField(Names.in, Types.java_io_InputStream); java_lang_System_out = java_lang_System.requireDeclaredField(Names.out, Types.java_io_PrintStream); java_lang_System_err = java_lang_System.requireDeclaredField(Names.err, Types.java_io_PrintStream); @@ -621,9 +638,15 @@ public Meta(EspressoContext context) { java_security_AccessControlContext = knownKlass(Types.java_security_AccessControlContext); java_security_AccessControlContext_context = java_security_AccessControlContext.requireDeclaredField(Names.context, Types.java_security_ProtectionDomain_array); - java_security_AccessControlContext_privilegedContext = java_security_AccessControlContext.requireDeclaredField(Names.privilegedContext, Types.java_security_AccessControlContext); - java_security_AccessControlContext_isPrivileged = java_security_AccessControlContext.requireDeclaredField(Names.isPrivileged, Types._boolean); - java_security_AccessControlContext_isAuthorized = java_security_AccessControlContext.requireDeclaredField(Names.isAuthorized, Types._boolean); + java_security_AccessControlContext_privilegedContext = diff() // + .field(VERSION_21_OR_LOWER, Names.privilegedContext, Types.java_security_AccessControlContext) // + .notRequiredField(java_security_AccessControlContext); + java_security_AccessControlContext_isPrivileged = diff() // + .field(VERSION_21_OR_LOWER, Names.isPrivileged, Types._boolean) // + .notRequiredField(java_security_AccessControlContext); + java_security_AccessControlContext_isAuthorized = diff() // + .field(VERSION_21_OR_LOWER, Names.isAuthorized, Types._boolean) // + .notRequiredField(java_security_AccessControlContext); java_security_AccessController = knownKlass(Types.java_security_AccessController); java_lang_invoke_MethodType = knownKlass(Types.java_lang_invoke_MethodType); @@ -739,10 +762,39 @@ public Meta(EspressoContext context) { java_lang_StackStreamFactory = knownKlass(Types.java_lang_StackStreamFactory); + java_lang_ClassFrameInfo = diff() // + .klass(VERSION_22_OR_HIGHER, Types.java_lang_ClassFrameInfo) // + .notRequiredKlass(); + java_lang_ClassFrameInfo_classOrMemberName = diff() // + .field(VERSION_22_OR_HIGHER, Names.classOrMemberName, Types.java_lang_Object) // + .notRequiredField(java_lang_ClassFrameInfo); + java_lang_ClassFrameInfo_flags = diff() // + .field(VERSION_22_OR_HIGHER, Names.flags, Types._int) // + .notRequiredField(java_lang_ClassFrameInfo); + java_lang_StackFrameInfo = knownKlass(Types.java_lang_StackFrameInfo); - java_lang_StackFrameInfo_memberName = java_lang_StackFrameInfo.requireDeclaredField(Names.memberName, Types.java_lang_Object); + java_lang_StackFrameInfo_memberName = diff() // + .field(JavaVersion.VersionRange.VERSION_9_TO_21, Names.memberName, Types.java_lang_Object) // + .notRequiredField(java_lang_StackFrameInfo); + java_lang_StackFrameInfo_name = diff() // + .field(JavaVersion.VersionRange.VERSION_22_OR_HIGHER, Names.name, Types.java_lang_String) // + .notRequiredField(java_lang_StackFrameInfo); + java_lang_StackFrameInfo_type = diff() // + .field(JavaVersion.VersionRange.VERSION_22_OR_HIGHER, Names.type, Types.java_lang_Object) // + .notRequiredField(java_lang_StackFrameInfo); java_lang_StackFrameInfo_bci = java_lang_StackFrameInfo.requireDeclaredField(Names.bci, Types._int); + java_lang_invoke_ResolvedMethodName = diff() // + .klass(VERSION_22_OR_HIGHER, Types.java_lang_invoke_ResolvedMethodName) // + .notRequiredKlass(); + java_lang_invoke_ResolvedMethodName_vmholder = diff() // + .field(VERSION_22_OR_HIGHER, Names.vmholder, Types.java_lang_Class) // + .notRequiredField(java_lang_invoke_ResolvedMethodName); + + HIDDEN_VM_METHOD = diff() // + .field(VERSION_22_OR_HIGHER, Names.HIDDEN_VM_METHOD, Types.java_lang_Object) // + .maybeHiddenfield(java_lang_invoke_ResolvedMethodName); + java_lang_System_initPhase1 = java_lang_System.requireDeclaredMethod(Names.initPhase1, Signatures._void); java_lang_System_initPhase2 = java_lang_System.requireDeclaredMethod(Names.initPhase2, Signatures._int_boolean_boolean); java_lang_System_initPhase3 = java_lang_System.requireDeclaredMethod(Names.initPhase3, Signatures._void); @@ -757,10 +809,20 @@ public Meta(EspressoContext context) { java_lang_StackStreamFactory = null; + java_lang_ClassFrameInfo = null; + java_lang_ClassFrameInfo_classOrMemberName = null; + java_lang_ClassFrameInfo_flags = null; + java_lang_StackFrameInfo = null; java_lang_StackFrameInfo_memberName = null; + java_lang_StackFrameInfo_name = null; + java_lang_StackFrameInfo_type = null; java_lang_StackFrameInfo_bci = null; + java_lang_invoke_ResolvedMethodName = null; + java_lang_invoke_ResolvedMethodName_vmholder = null; + HIDDEN_VM_METHOD = null; + java_lang_System_initPhase1 = null; java_lang_System_initPhase2 = null; java_lang_System_initPhase3 = null; @@ -819,12 +881,12 @@ public Meta(EspressoContext context) { sun_reflect_MagicAccessorImpl = diff() // .klass(VERSION_8_OR_LOWER, Types.sun_reflect_MagicAccessorImpl) // - .klass(VERSION_9_OR_HIGHER, Types.jdk_internal_reflect_MagicAccessorImpl) // - .klass(); + .klass(VERSION_9_TO_21, Types.jdk_internal_reflect_MagicAccessorImpl) // + .notRequiredKlass(); sun_reflect_DelegatingClassLoader = diff() // .klass(VERSION_8_OR_LOWER, Types.sun_reflect_DelegatingClassLoader) // - .klass(VERSION_9_OR_HIGHER, Types.jdk_internal_reflect_DelegatingClassLoader) // - .klass(); + .klass(VERSION_9_TO_21, Types.jdk_internal_reflect_DelegatingClassLoader) // + .notRequiredKlass(); sun_reflect_MethodAccessorImpl = diff() // .klass(VERSION_8_OR_LOWER, Types.sun_reflect_MethodAccessorImpl) // @@ -1873,10 +1935,20 @@ private DiffVersionLoadHelper diff() { public final ObjectKlass java_lang_StackStreamFactory; public final Method java_lang_StackStreamFactory_AbstractStackWalker_doStackWalk; + public final ObjectKlass java_lang_ClassFrameInfo; + public final Field java_lang_ClassFrameInfo_classOrMemberName; + public final Field java_lang_ClassFrameInfo_flags; + public final ObjectKlass java_lang_StackFrameInfo; public final Field java_lang_StackFrameInfo_memberName; + public final Field java_lang_StackFrameInfo_name; + public final Field java_lang_StackFrameInfo_type; public final Field java_lang_StackFrameInfo_bci; + public final ObjectKlass java_lang_invoke_ResolvedMethodName; + public final Field java_lang_invoke_ResolvedMethodName_vmholder; + public final Field HIDDEN_VM_METHOD; + // Module system public final ObjectKlass jdk_internal_module_ModuleLoaderMap; public final Method jdk_internal_module_ModuleLoaderMap_bootModules; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/GuestAllocator.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/GuestAllocator.java index 9b22fe3bb70b..91ba547d8d4c 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/GuestAllocator.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/GuestAllocator.java @@ -164,7 +164,7 @@ public StaticObject createClass(Klass klass) { klass.getMeta().java_lang_Class_componentType.setObject(newObj, ((ArrayKlass) klass).getComponentType().initializeEspressoClass()); } // Will be overriden if necessary, but should be initialized to non-host null. - klass.getMeta().HIDDEN_PROTECTION_DOMAIN.setHiddenObject(newObj, StaticObject.NULL); + klass.getMeta().HIDDEN_PROTECTION_DOMAIN.setObject(newObj, StaticObject.NULL); // Final hidden field assignment klass.getMeta().HIDDEN_MIRROR_KLASS.setHiddenObject(newObj, klass); return trackAllocation(klass, newObj); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java index 1bafd9a2f24b..39f1a8eaf719 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java @@ -165,4 +165,16 @@ public boolean isValidFor(JavaVersion version) { return version.java21OrLater(); } } + + final class Java22OrLater implements VersionFilter { + public static final Java22OrLater INSTANCE = new Java22OrLater(); + + private Java22OrLater() { + } + + @Override + public boolean isValidFor(JavaVersion version) { + return version.java22OrLater(); + } + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_StackStreamFactory_AbstractStackWalker.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_StackStreamFactory_AbstractStackWalker.java index 8d4b994d3cfb..e08a30fe0009 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_StackStreamFactory_AbstractStackWalker.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_StackStreamFactory_AbstractStackWalker.java @@ -30,6 +30,7 @@ import com.oracle.truffle.espresso.substitutions.JavaType; import com.oracle.truffle.espresso.substitutions.Substitution; import com.oracle.truffle.espresso.substitutions.VersionFilter; +import com.oracle.truffle.espresso.vm.VM; @EspressoSubstitutions(type = "Ljava/lang/StackStreamFactory$AbstractStackWalker;") public final class Target_java_lang_StackStreamFactory_AbstractStackWalker { @@ -53,4 +54,32 @@ private Target_java_lang_StackStreamFactory_AbstractStackWalker() { @Inject Meta meta) { return meta.getContext().getVM().JVM_CallStackWalk19(stackStream, mode, skipframes, contScope, cont, batchSize, startIndex, frames, language, meta); } + + @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java22OrLater.class) + public static @JavaType(Object.class) StaticObject callStackWalk( + @JavaType(internalName = "Ljava/lang/StackStreamFactory$AbstractStackWalker;") StaticObject stackStream, + int mode, int skipframes, + @JavaType(internalName = "Ljdk/internal/vm/ContinuationScope;") StaticObject contScope, + @JavaType(internalName = "Ljdk/internal/vm/Continuation;") StaticObject cont, + int bufferSize, int startIndex, + @JavaType(Object[].class) StaticObject frames, + @Inject EspressoLanguage language, + @Inject Meta meta) { + return meta.getContext().getVM().JVM_CallStackWalk19(stackStream, mode, skipframes, contScope, cont, + bufferSize - startIndex, // Translate to batch size + startIndex, frames, language, meta); + } + + @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java22OrLater.class) + public static int fetchStackFrames( + @JavaType(internalName = "Ljava/lang/StackStreamFactory;") StaticObject stream, + int mode, long anchor, + @SuppressWarnings("unused") int lastBatchFrameCount, + int bufferSize, int startIndex, + @JavaType(Object[].class) StaticObject frames, + @Inject EspressoLanguage lang, + @Inject Meta meta, + @Inject VM vm) { + return vm.JVM_MoreStackWalk(stream, mode, anchor, bufferSize - startIndex, startIndex, frames, lang, meta); + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_Thread.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_Thread.java index ec1c6fadc52e..ae2880b1a984 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_Thread.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_Thread.java @@ -264,6 +264,11 @@ public static void sleep0(long amount, @Inject Meta meta, @Inject SubstitutionPr } } + @Substitution + public static void sleepNanos0(long amount, @Inject Meta meta, @Inject SubstitutionProfiler location) { + sleep0(amount, meta, location); + } + @Substitution public static long getNextThreadIdOffset() { // value should never be used, because we substitute ThreadIdentifiers::next diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_invoke_MethodHandleNatives.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_invoke_MethodHandleNatives.java index 81c7e8f8647f..3373d65316b4 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_invoke_MethodHandleNatives.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_invoke_MethodHandleNatives.java @@ -713,6 +713,7 @@ private Constants() { // @CallerSensitive annotation detected public static final int MN_CALLER_SENSITIVE = 0x00100000; public static final int MN_TRUSTED_FINAL = 0x00200000; // trusted final field + public static final int MN_HIDDEN_MEMBER = 0x00400000; /*- members defined in a hidden class or with @Hidden */ public static final int MN_REFERENCE_KIND_SHIFT = 24; // refKind public static final int MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT; // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers: diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_sun_misc_Unsafe.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_sun_misc_Unsafe.java index fc81bf1acbb3..ddaa913d6809 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_sun_misc_Unsafe.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_sun_misc_Unsafe.java @@ -122,7 +122,7 @@ private Target_sun_misc_Unsafe() { byte[] bytes = data.unwrap(language); ObjectKlass hostKlass = (ObjectKlass) hostClass.getMirrorKlass(meta); - StaticObject pd = (StaticObject) meta.HIDDEN_PROTECTION_DOMAIN.getHiddenObject(hostClass); + StaticObject pd = meta.HIDDEN_PROTECTION_DOMAIN.getObject(hostClass); StaticObject[] patches = StaticObject.isNull(constantPoolPatches) ? null : constantPoolPatches.unwrap(language); // Inherit host class's protection domain. ClassRegistry.ClassDefinitionInfo info = new ClassRegistry.ClassDefinitionInfo(pd, hostKlass, patches); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/StackWalk.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/StackWalk.java index 1e66565b5a8d..aff275ecc69b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/StackWalk.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/StackWalk.java @@ -79,8 +79,12 @@ private static boolean synchronizedConstants(Meta meta) { Klass stackStreamFactory = meta.java_lang_StackStreamFactory; StaticObject statics = stackStreamFactory.tryInitializeAndGetStatics(); assert DEFAULT_MODE == getConstantField(stackStreamFactory, statics, "DEFAULT_MODE", meta); - assert FILL_CLASS_REFS_ONLY == getConstantField(stackStreamFactory, statics, "FILL_CLASS_REFS_ONLY", meta); - assert GET_CALLER_CLASS == getConstantField(stackStreamFactory, statics, "GET_CALLER_CLASS", meta); + if (meta.getJavaVersion().java21OrEarlier()) { + assert FILL_CLASS_REFS_ONLY == getConstantField(stackStreamFactory, statics, "FILL_CLASS_REFS_ONLY", meta); + assert GET_CALLER_CLASS == getConstantField(stackStreamFactory, statics, "GET_CALLER_CLASS", meta); + } else { + assert FILL_CLASS_REFS_ONLY == getConstantField(stackStreamFactory, statics, "CLASS_INFO_ONLY", meta); + } assert SHOW_HIDDEN_FRAMES == getConstantField(stackStreamFactory, statics, "SHOW_HIDDEN_FRAMES", meta); assert FILL_LIVE_STACK_FRAMES == getConstantField(stackStreamFactory, statics, "FILL_LIVE_STACK_FRAMES", meta); return true; @@ -117,7 +121,13 @@ public StackWalk() { throw meta.throwException(meta.java_lang_InternalError); } register(fw); - Object result = meta.java_lang_StackStreamFactory_AbstractStackWalker_doStackWalk.invokeDirectSpecial(stackStream, fw.anchor, skipframes, batchSize, startIndex, startIndex + decoded); + Object result = meta.java_lang_StackStreamFactory_AbstractStackWalker_doStackWalk.invokeDirectSpecial( + stackStream, + fw.anchor, + skipframes, + meta.getJavaVersion().java22OrLater() ? decoded : batchSize, + startIndex, + startIndex + decoded); unAnchor(fw); return (StaticObject) result; } @@ -126,7 +136,11 @@ public StackWalk() { * After {@link #fetchFirstBatch(StaticObject, long, int, int, int, StaticObject, Meta)}, this * method allows to continue frame walking, starting from where the previous calls left off. * - * @return The position in the buffer at the end of fetching. + * @return + *
    + *
  • In Java < 22: The position in the buffer at the end of fetching.
  • + *
  • In Java >= 22: The number of fetched frames.
  • + *
*/ public int fetchNextBatch( @SuppressWarnings("unused") @JavaType(internalName = "Ljava/lang/StackStreamFactory;") StaticObject stackStream, @@ -146,7 +160,11 @@ public int fetchNextBatch( fw.mode(mode); Integer decodedOrNull = fw.doStackWalk(frames); int decoded = decodedOrNull == null ? fw.decoded() : decodedOrNull; - return startIndex + decoded; + if (meta.getJavaVersion().java22OrLater()) { + return decoded; + } else { + return startIndex + decoded; + } } private void register(FrameWalker fw) { @@ -247,7 +265,8 @@ public Integer doStackWalk(StaticObject usedFrames) { } private boolean isFromStackWalkingAPI(Method m) { - return m.getDeclaringKlass() == meta.java_lang_StackWalker || m.getDeclaringKlass() == meta.java_lang_StackStreamFactory_AbstractStackWalker || + return m.getDeclaringKlass() == meta.java_lang_StackWalker || + m.getDeclaringKlass() == meta.java_lang_StackStreamFactory_AbstractStackWalker || m.getDeclaringKlass().getSuperKlass() == meta.java_lang_StackStreamFactory_AbstractStackWalker; } @@ -258,7 +277,13 @@ private boolean isCallStackWalk(Method m) { } private Symbol getCallStackWalkSignature() { - return meta.getJavaVersion().java19OrLater() ? Signatures.Object_long_int_ContinuationScope_Continuation_int_int_Object_array : Signatures.Object_long_int_int_int_Object_array; + if (meta.getJavaVersion().java22OrLater()) { + return Signatures.Object_int_int_ContinuationScope_Continuation_int_int_Object_array; + } else if (meta.getJavaVersion().java19OrLater()) { + return Signatures.Object_long_int_ContinuationScope_Continuation_int_int_Object_array; + } else { + return Signatures.Object_long_int_int_int_Object_array; + } } @SuppressWarnings("fallthrough") @@ -335,16 +360,34 @@ private void tryProcessFrame(FrameInstance frameInstance, Method m, int index) { } private void processFrame(FrameInstance frameInstance, Method m, int index) { - if (liveFrameInfo(mode)) { - fillFrame(frameInstance, m, index); - // TODO: extract stack, locals and monitors from the frame. - throw EspressoError.unimplemented(); - } else if (needMethodInfo(mode)) { - fillFrame(frameInstance, m, index); + if (meta.getJavaVersion().java22OrLater()) { + StaticObject info = frames.get(meta.getLanguage(), index); + if (StaticObject.isNull(info) || !meta.java_lang_ClassFrameInfo.isAssignableFrom(info.getKlass())) { + throw meta.throwException(meta.java_lang_InternalError); + } + int flags = getFlags(meta.java_lang_ClassFrameInfo_flags.getInt(info), m); + meta.java_lang_ClassFrameInfo_flags.setInt(info, flags); + meta.java_lang_ClassFrameInfo_classOrMemberName.setObject(info, m.getDeclaringKlass().mirror()); + if (needMethodInfo(mode)) { + // Will override classOrMemberName + fillFrame(frameInstance, m, info); + } + if (liveFrameInfo(mode)) { + // TODO: extract stack, locals and monitors from the frame. + throw EspressoError.unimplemented("Live frame info for stack walk"); + } } else { - // Only class info is needed. - Klass klass = m.getDeclaringKlass(); - meta.getInterpreterToVM().setArrayObject(klass.getContext().getLanguage(), klass.mirror(), index, frames); + if (liveFrameInfo(mode)) { + fillFrame(frameInstance, m, frames.get(meta.getLanguage(), index)); + // TODO: extract stack, locals and monitors from the frame. + throw EspressoError.unimplemented("Live frame info for stack walk"); + } else if (needMethodInfo(mode)) { + fillFrame(frameInstance, m, frames.get(meta.getLanguage(), index)); + } else { + // Only class info is needed. + Klass klass = m.getDeclaringKlass(); + meta.getInterpreterToVM().setArrayObject(meta.getLanguage(), klass.mirror(), index, frames); + } } } @@ -353,13 +396,39 @@ private void processFrame(FrameInstance frameInstance, Method m, int index) { * {@code index}. This means initializing the associated {@code java.lang.invoke.MemberName} * , and injecting a BCI. */ - private void fillFrame(FrameInstance frameInstance, Method m, int index) { - StaticObject frame = frames.get(meta.getLanguage(), index); - StaticObject memberName = meta.java_lang_StackFrameInfo_memberName.getObject(frame); - Target_java_lang_invoke_MethodHandleNatives.plantResolvedMethod(memberName, m, m.getRefKind(), meta); - meta.java_lang_invoke_MemberName_clazz.setObject(memberName, m.getDeclaringKlass().mirror()); + private void fillFrame(FrameInstance frameInstance, Method m, StaticObject frame) { + if (StaticObject.isNull(frame) || !meta.java_lang_StackFrameInfo.isAssignableFrom(frame.getKlass())) { + throw meta.throwException(meta.java_lang_InternalError); + } + StaticObject memberName; + if (meta.getJavaVersion().java22OrLater()) { + memberName = meta.java_lang_invoke_ResolvedMethodName.allocateInstance(meta.getContext()); + meta.HIDDEN_VM_METHOD.setHiddenObject(memberName, m); + meta.java_lang_invoke_ResolvedMethodName_vmholder.setObject(memberName, m.getDeclaringKlass().mirror()); + meta.java_lang_ClassFrameInfo_classOrMemberName.setObject(frame, memberName); + } else { + memberName = meta.java_lang_StackFrameInfo_memberName.getObject(frame); + Target_java_lang_invoke_MethodHandleNatives.plantResolvedMethod(memberName, m, m.getRefKind(), meta); + meta.java_lang_invoke_MemberName_clazz.setObject(memberName, m.getDeclaringKlass().mirror()); + } EspressoRootNode rootNode = VM.getEspressoRootFromFrame(frameInstance, meta.getContext()); meta.java_lang_StackFrameInfo_bci.setInt(frame, rootNode.readBCI(frameInstance.getFrame(FrameInstance.FrameAccess.READ_ONLY))); } } + + private static int getFlags(int baseFlags, Method m) { + int flags = baseFlags; + if (m.isConstructor()) { + flags |= Target_java_lang_invoke_MethodHandleNatives.Constants.MN_IS_CONSTRUCTOR; + } else { + flags |= Target_java_lang_invoke_MethodHandleNatives.Constants.MN_IS_METHOD; + } + if (m.isHidden()) { + flags |= Target_java_lang_invoke_MethodHandleNatives.Constants.MN_HIDDEN_MEMBER; + } + if (m.isCallerSensitive()) { + flags |= Target_java_lang_invoke_MethodHandleNatives.Constants.MN_CALLER_SENSITIVE; + } + return flags; + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java index 853bfab3ac72..50bcebe573cd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java @@ -454,6 +454,9 @@ public void dispose() { } private StaticObject nonReflectionClassLoader(StaticObject loader) { + if (getJavaVersion().java21OrLater()) { + return loader; + } if (StaticObject.notNull(loader)) { Meta meta = getMeta(); if (meta.sun_reflect_DelegatingClassLoader.isAssignableFrom(loader.getKlass())) { @@ -1388,7 +1391,7 @@ public boolean JVM_AreNestMates(@JavaType(Class.class) StaticObject current, @Ja if (StaticObject.isNull(current)) { return StaticObject.NULL; } - StaticObject pd = (StaticObject) getMeta().HIDDEN_PROTECTION_DOMAIN.getHiddenObject(current); + StaticObject pd = getMeta().HIDDEN_PROTECTION_DOMAIN.getObject(current); return pd == null ? StaticObject.NULL : pd; } @@ -2477,6 +2480,7 @@ private PropertiesMap buildPropertiesMap() { map.setNumberedProperty("jdk.module.addopens.", options.get(EspressoOptions.AddOpens), "AddOpens"); addmodCount = map.setNumberedProperty("jdk.module.addmods.", options.get(EspressoOptions.AddModules), "AddModules"); map.setNumberedProperty("jdk.module.enable.native.access.", options.get(EspressoOptions.EnableNativeAccess), "EnableNativeAccess"); + map.setPropertyIfExists("jdk.module.illegal.native.access", options.get(EspressoOptions.IllegalNativeAccess), "IllegalNativeAccess"); } // Applications expect different formats e.g. 1.8 vs. 11 @@ -2715,7 +2719,7 @@ private boolean isAuthorized(StaticObject context, Klass klass) { /** * Returns the caller frame, 'depth' levels up. If securityStackWalk is true, some Espresso * frames are skipped according to {@link #isIgnoredBySecurityStackWalk}. - * + * * May return null if there is no Java frame on the stack. */ @TruffleBoundary @@ -3853,6 +3857,11 @@ public static boolean JVM_IsCDSDumpingEnabled() { return false; } + @VmImpl(isJni = true) + public static int JVM_GetCDSConfigStatus() { + return 0; + } + @VmImpl(isJni = true) public static boolean JVM_IsSharingEnabled() { return false; @@ -3933,20 +3942,32 @@ private StackWalk getStackWalk() { @VmImpl(isJni = true) @SuppressWarnings("unused") - public static void JVM_InitStackTraceElement(@JavaType(StackTraceElement.class) StaticObject element, @JavaType(internalName = "Ljava/lang/StackFrameInfo;") StaticObject info, + public static void JVM_InitStackTraceElement(@JavaType(StackTraceElement.class) StaticObject element, + @JavaType(internalName = "Ljava/lang/StackFrameInfo;") StaticObject info, @Inject Meta meta) { if (StaticObject.isNull(element) || StaticObject.isNull(info)) { throw meta.throwNullPointerException(); } - StaticObject mname = meta.java_lang_StackFrameInfo_memberName.getObject(info); + Field mnameField = meta.getJavaVersion().java22OrLater() + ? meta.java_lang_ClassFrameInfo_classOrMemberName + : meta.java_lang_StackFrameInfo_memberName; + Field clazzField = meta.getJavaVersion().java22OrLater() + ? meta.java_lang_invoke_ResolvedMethodName_vmholder + : meta.java_lang_invoke_MemberName_clazz; + Field targetField = meta.getJavaVersion().java22OrLater() + ? meta.HIDDEN_VM_METHOD // ResolvedMethodName.vmMethod + : meta.HIDDEN_VMTARGET; // MemberName.vmTarget + assert mnameField != null && clazzField != null && targetField != null; + StaticObject mname = mnameField.getObject(info); if (StaticObject.isNull(mname)) { throw meta.throwExceptionWithMessage(meta.java_lang_InternalError, "uninitialized StackFrameInfo !"); } - StaticObject clazz = meta.java_lang_invoke_MemberName_clazz.getObject(mname); - Method m = (Method) meta.HIDDEN_VMTARGET.getHiddenObject(mname); + StaticObject clazz = clazzField.getObject(mname); + Method m = (Method) targetField.getHiddenObject(mname); if (m == null) { throw meta.throwExceptionWithMessage(meta.java_lang_InternalError, "uninitialized StackFrameInfo !"); } + int bci = meta.java_lang_StackFrameInfo_bci.getInt(info); fillInElement(element, new VM.EspressoStackElement(m, bci), meta); } @@ -4136,6 +4157,28 @@ public int JVM_MoreStackWalk( return getStackWalk().fetchNextBatch(stackStream, mode, anchor, batchSize, startIndex, frames, meta); } + @VmImpl(isJni = true) + @TruffleBoundary + public static void JVM_ExpandStackFrameInfo(@JavaType(internalName = "Ljava/lang/StackFrameInfo;") StaticObject obj, + @Inject Meta meta) { + StaticObject resolvedMethodName = meta.java_lang_ClassFrameInfo_classOrMemberName.getObject(obj); + if (StaticObject.isNull(resolvedMethodName) || resolvedMethodName.getKlass() != meta.java_lang_invoke_ResolvedMethodName) { + return; + } + Method m = (Method) meta.HIDDEN_VM_METHOD.getHiddenObject(resolvedMethodName); + if (m == null) { + return; + } + boolean hasName = !StaticObject.isNull(meta.java_lang_StackFrameInfo_name.getObject(obj)); + boolean hasType = !StaticObject.isNull(meta.java_lang_StackFrameInfo_type.getObject(obj)); + if (!hasName) { + meta.java_lang_StackFrameInfo_name.setObject(obj, meta.toGuestString(m.getName())); + } + if (!hasType) { + meta.java_lang_StackFrameInfo_type.setObject(obj, meta.toGuestString(m.getRawSignature())); + } + } + // endregion stackwalk // Checkstyle: resume method name check From e749c5f28b118a69c9cc951f503e66408e922aba Mon Sep 17 00:00:00 2001 From: Thomas Garcia Date: Mon, 24 Mar 2025 23:35:22 +0100 Subject: [PATCH 2/7] Better handling of missing fields in Meta. Now possible to access Object fields that may be hidden in some Java version, but not in other. --- .../espresso/classfile/JavaVersion.java | 8 +++-- .../espresso/descriptors/EspressoSymbols.java | 1 + .../oracle/truffle/espresso/impl/Field.java | 16 ++++++++++ .../oracle/truffle/espresso/impl/Klass.java | 2 +- .../truffle/espresso/impl/ObjectKlass.java | 2 +- .../oracle/truffle/espresso/jni/JniEnv.java | 2 +- .../espresso/meta/DiffVersionLoadHelper.java | 23 +++++++------- .../oracle/truffle/espresso/meta/Meta.java | 30 +++++++++++-------- .../espresso/runtime/GuestAllocator.java | 2 +- .../standard/Target_sun_misc_Unsafe.java | 2 +- .../com/oracle/truffle/espresso/vm/VM.java | 2 +- 11 files changed, 58 insertions(+), 32 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java index 3979e320da15..84401c88de11 100644 --- a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java @@ -41,8 +41,8 @@ public static final class VersionRange { public static final VersionRange VERSION_22_OR_HIGHER = higher(22); public static final VersionRange VERSION_25_OR_HIGHER = higher(25); - public static final VersionRange ALL = new VersionRange(0, LATEST_SUPPORTED); - public static final VersionRange VERSION_9_TO_21 = new VersionRange(9, 21); + public static final VersionRange ALL = between(0, LATEST_SUPPORTED); + public static final VersionRange VERSION_9_TO_21 = between(9, 21); private final int low; private final int high; @@ -60,6 +60,10 @@ public static VersionRange higher(int version) { return new VersionRange(version, LATEST_SUPPORTED); } + public static VersionRange between(int low, int high) { + return new VersionRange(low, high); + } + public boolean contains(JavaVersion version) { return version.inRange(low, high); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java index 2bdee35335b1..bc8345674dca 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java @@ -1296,6 +1296,7 @@ public static class Signatures { Types.java_lang_invoke_MethodType, Types.java_lang_Object_array); public static final Symbol Field_Object_long_Class = SYMBOLS.putSignature(Types.java_lang_reflect_Field, Types.java_lang_Object, Types._long, Types.java_lang_Class); + public static final Symbol Field_Class_long_Class = SYMBOLS.putSignature(Types.java_lang_reflect_Field, Types.java_lang_Class, Types._long, Types.java_lang_Class); public static final Symbol Thread$State_int = SYMBOLS.putSignature(Types.java_lang_Thread$State, Types._int); public static final Symbol _void_ThreadGroup_String = SYMBOLS.putSignature(Types._void, Types.java_lang_ThreadGroup, Types.java_lang_String); public static final Symbol _void_ThreadGroup_Runnable = SYMBOLS.putSignature(Types._void, Types.java_lang_ThreadGroup, Types.java_lang_Runnable); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Field.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Field.java index fc5f681f4b6a..dae952a16c39 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Field.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Field.java @@ -507,6 +507,22 @@ public final void setHiddenObject(StaticObject obj, Object value, boolean forceV setObjectHelper(obj, value, forceVolatile); } + public final void setMaybeHiddenObject(StaticObject obj, StaticObject value) { + setMaybeHiddenObject(obj, value, false); + } + + public final void setMaybeHiddenObject(StaticObject obj, StaticObject value, boolean forceVolatile) { + setObjectHelper(obj, value, forceVolatile); + } + + public final StaticObject getMaybeHiddenObject(StaticObject obj) { + return getMaybeHiddenObject(obj, false); + } + + public final StaticObject getMaybeHiddenObject(StaticObject obj, boolean forceVolatile) { + return (StaticObject) getObjectHelper(obj, forceVolatile); + } + public Object compareAndExchangeHiddenObject(StaticObject obj, Object before, Object after) { obj.checkNotForeign(); assert isHidden() : this + " is not hidden"; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java index 361158f5de6e..0d8e22977005 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java @@ -1832,7 +1832,7 @@ public boolean nestMembersCheck(Klass k) { } public StaticObject protectionDomain() { - return getMeta().HIDDEN_PROTECTION_DOMAIN.getObject(mirror()); + return getMeta().HIDDEN_PROTECTION_DOMAIN.getMaybeHiddenObject(mirror()); } /** diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java index f2c9458e3653..7b29664d42d4 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java @@ -223,7 +223,7 @@ public ObjectKlass(EspressoContext context, LinkedKlass linkedKlass, ObjectKlass if (info.protectionDomain != null && !StaticObject.isNull(info.protectionDomain)) { // Protection domain should not be host null, and will be initialized to guest null on // mirror creation. - getMeta().HIDDEN_PROTECTION_DOMAIN.setObject(initializeEspressoClass(), info.protectionDomain); + getMeta().HIDDEN_PROTECTION_DOMAIN.setMaybeHiddenObject(initializeEspressoClass(), info.protectionDomain); } if (info.classData != null) { getMeta().java_lang_Class_classData.setObject(initializeEspressoClass(), info.classData); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniEnv.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniEnv.java index da6c5244697d..0a097b849575 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniEnv.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniEnv.java @@ -2881,7 +2881,7 @@ public void ReleasePrimitiveArrayCritical(@JavaType(Object.class) StaticObject o throw e; } - meta.HIDDEN_PROTECTION_DOMAIN.setObject(guestClass, protectionDomain); + meta.HIDDEN_PROTECTION_DOMAIN.setMaybeHiddenObject(guestClass, protectionDomain); // FindClass should initialize the class. guestClass.getMirrorKlass(meta).safeInitialize(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/DiffVersionLoadHelper.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/DiffVersionLoadHelper.java index 1c06b6774f09..281638c03b57 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/DiffVersionLoadHelper.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/DiffVersionLoadHelper.java @@ -83,9 +83,9 @@ Method notRequiredMethod(ObjectKlass klass) { return null; } if (klass == null) { - return null; + throw EspressoError.shouldNotReachHere("Missing klass for method " + name + ":" + signature); } - return klass.lookupDeclaredMethod(name, signature); + return klass.requireDeclaredMethod(name, signature); } DiffVersionLoadHelper field(VersionRange range, Symbol n, Symbol t) { @@ -103,25 +103,24 @@ Field field(ObjectKlass klass) { return klass.requireDeclaredField(name, type); } - Field maybeHiddenfield(ObjectKlass klass) { + Field notRequiredField(ObjectKlass klass) { if (name == null || type == null) { return null; } - Field f = klass.lookupDeclaredField(name, type); - if (f == null) { - return klass.lookupHiddenField(name); + if (klass == null) { + throw EspressoError.shouldNotReachHere("Missing klass for field " + name + ":" + type); } - return f; + return klass.requireDeclaredField(name, type); } - Field notRequiredField(ObjectKlass klass) { + Field maybeHiddenfield(ObjectKlass klass) { if (name == null || type == null) { return null; } - if (klass == null) { - return null; + Field f = klass.lookupDeclaredField(name, type); + if (f != null) { + return f; } - return klass.lookupDeclaredField(name, type); + return klass.requireHiddenField(name); } - } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java index 83c776bd41af..633e7828fb9e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java @@ -35,6 +35,7 @@ import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_8_OR_LOWER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_9_OR_HIGHER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_9_TO_21; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.between; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.higher; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.lower; import static com.oracle.truffle.espresso.impl.EspressoClassLoadingException.wrapClassNotFoundGuestException; @@ -419,8 +420,13 @@ public Meta(EspressoContext context) { java_nio_file_NotDirectoryException = knownKlass(Types.java_nio_file_NotDirectoryException); java_nio_file_NotLinkException = knownKlass(Types.java_nio_file_NotLinkException); - java_util_zip_CRC32 = knownKlass(Types.java_util_zip_CRC32); - HIDDEN_CRC32 = diff().field(ALL, Names.HIDDEN_CRC32, Types._int).maybeHiddenfield(java_util_zip_CRC32); + if (context.getLanguage().useEspressoLibs()) { + java_util_zip_CRC32 = knownKlass(Types.java_util_zip_CRC32); + HIDDEN_CRC32 = diff().field(ALL, Names.HIDDEN_CRC32, Types._int).maybeHiddenfield(java_util_zip_CRC32); + } else { + java_util_zip_CRC32 = null; + HIDDEN_CRC32 = null; + } ObjectKlass nioNativeThreadKlass = knownKlass(Types.sun_nio_ch_NativeThread); sun_nio_ch_NativeThread_init = nioNativeThreadKlass.lookupDeclaredMethod(Names.init, Signatures._void); @@ -685,7 +691,8 @@ public Meta(EspressoContext context) { .klass(higher(14), Types.java_lang_invoke_VarHandles) // .notRequiredKlass(); java_lang_invoke_VarHandles_getStaticFieldFromBaseAndOffset = diff() // - .method(higher(14), Names.getStaticFieldFromBaseAndOffset, Signatures.Field_Object_long_Class) // + .method(between(14, 20), Names.getStaticFieldFromBaseAndOffset, Signatures.Field_Object_long_Class) // + .method(VERSION_21_OR_HIGHER, Names.getStaticFieldFromBaseAndOffset, Signatures.Field_Class_long_Class) // .notRequiredMethod(java_lang_invoke_VarHandles); java_lang_invoke_CallSite = knownKlass(Types.java_lang_invoke_CallSite); @@ -790,7 +797,6 @@ public Meta(EspressoContext context) { java_lang_invoke_ResolvedMethodName_vmholder = diff() // .field(VERSION_22_OR_HIGHER, Names.vmholder, Types.java_lang_Class) // .notRequiredField(java_lang_invoke_ResolvedMethodName); - HIDDEN_VM_METHOD = diff() // .field(VERSION_22_OR_HIGHER, Names.HIDDEN_VM_METHOD, Types.java_lang_Object) // .maybeHiddenfield(java_lang_invoke_ResolvedMethodName); @@ -858,25 +864,25 @@ public Meta(EspressoContext context) { .klass(VERSION_16_OR_HIGHER, Types.java_lang_reflect_RecordComponent) // .notRequiredKlass(); java_lang_reflect_RecordComponent_clazz = diff() // - .field(ALL, Names.clazz, Types.java_lang_Class) // + .field(VERSION_16_OR_HIGHER, Names.clazz, Types.java_lang_Class) // .notRequiredField(java_lang_reflect_RecordComponent); java_lang_reflect_RecordComponent_name = diff() // - .field(ALL, Names.name, Types.java_lang_String) // + .field(VERSION_16_OR_HIGHER, Names.name, Types.java_lang_String) // .notRequiredField(java_lang_reflect_RecordComponent); java_lang_reflect_RecordComponent_type = diff() // - .field(ALL, Names.type, Types.java_lang_Class) // + .field(VERSION_16_OR_HIGHER, Names.type, Types.java_lang_Class) // .notRequiredField(java_lang_reflect_RecordComponent); java_lang_reflect_RecordComponent_accessor = diff() // - .field(ALL, Names.accessor, Types.java_lang_reflect_Method) // + .field(VERSION_16_OR_HIGHER, Names.accessor, Types.java_lang_reflect_Method) // .notRequiredField(java_lang_reflect_RecordComponent); java_lang_reflect_RecordComponent_signature = diff() // - .field(ALL, Names.signature, Types.java_lang_String) // + .field(VERSION_16_OR_HIGHER, Names.signature, Types.java_lang_String) // .notRequiredField(java_lang_reflect_RecordComponent); java_lang_reflect_RecordComponent_annotations = diff() // - .field(ALL, Names.annotations, Types._byte_array) // + .field(VERSION_16_OR_HIGHER, Names.annotations, Types._byte_array) // .notRequiredField(java_lang_reflect_RecordComponent); java_lang_reflect_RecordComponent_typeAnnotations = diff() // - .field(ALL, Names.typeAnnotations, Types._byte_array) // + .field(VERSION_16_OR_HIGHER, Names.typeAnnotations, Types._byte_array) // .notRequiredField(java_lang_reflect_RecordComponent); sun_reflect_MagicAccessorImpl = diff() // @@ -1276,7 +1282,7 @@ public Meta(EspressoContext context) { .klass(VERSION_17_OR_HIGHER, Types.jdk_internal_module_ModuleLoaderMap_Modules) // .notRequiredKlass(); jdk_internal_module_ModuleLoaderMap_Modules_clinit = diff() // - .method(ALL, Names._clinit_, Signatures._void) // + .method(VERSION_17_OR_HIGHER, Names._clinit_, Signatures._void) // .notRequiredMethod(jdk_internal_module_ModuleLoaderMap_Modules); interopDispatch = new InteropKlassesDispatch(this); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/GuestAllocator.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/GuestAllocator.java index 91ba547d8d4c..1ac9287f62c6 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/GuestAllocator.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/GuestAllocator.java @@ -164,7 +164,7 @@ public StaticObject createClass(Klass klass) { klass.getMeta().java_lang_Class_componentType.setObject(newObj, ((ArrayKlass) klass).getComponentType().initializeEspressoClass()); } // Will be overriden if necessary, but should be initialized to non-host null. - klass.getMeta().HIDDEN_PROTECTION_DOMAIN.setObject(newObj, StaticObject.NULL); + klass.getMeta().HIDDEN_PROTECTION_DOMAIN.setMaybeHiddenObject(newObj, StaticObject.NULL); // Final hidden field assignment klass.getMeta().HIDDEN_MIRROR_KLASS.setHiddenObject(newObj, klass); return trackAllocation(klass, newObj); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_sun_misc_Unsafe.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_sun_misc_Unsafe.java index ddaa913d6809..6a0e6a1e9568 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_sun_misc_Unsafe.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_sun_misc_Unsafe.java @@ -122,7 +122,7 @@ private Target_sun_misc_Unsafe() { byte[] bytes = data.unwrap(language); ObjectKlass hostKlass = (ObjectKlass) hostClass.getMirrorKlass(meta); - StaticObject pd = meta.HIDDEN_PROTECTION_DOMAIN.getObject(hostClass); + StaticObject pd = meta.HIDDEN_PROTECTION_DOMAIN.getMaybeHiddenObject(hostClass); StaticObject[] patches = StaticObject.isNull(constantPoolPatches) ? null : constantPoolPatches.unwrap(language); // Inherit host class's protection domain. ClassRegistry.ClassDefinitionInfo info = new ClassRegistry.ClassDefinitionInfo(pd, hostKlass, patches); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java index 50bcebe573cd..e47ea3a0b597 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java @@ -1391,7 +1391,7 @@ public boolean JVM_AreNestMates(@JavaType(Class.class) StaticObject current, @Ja if (StaticObject.isNull(current)) { return StaticObject.NULL; } - StaticObject pd = getMeta().HIDDEN_PROTECTION_DOMAIN.getObject(current); + StaticObject pd = getMeta().HIDDEN_PROTECTION_DOMAIN.getMaybeHiddenObject(current); return pd == null ? StaticObject.NULL : pd; } From bf91a9674bc5ddde6356cf81c269a5347f520751 Mon Sep 17 00:00:00 2001 From: Thomas Garcia Date: Mon, 31 Mar 2025 10:56:24 +0200 Subject: [PATCH 3/7] Additions for new foreign API capabilities in jdk 25: * Foreign API supports passing raw pointers into primitive arrays. * Passed buffers now writes back to the original guest object. * More robust 'stubID <-> stub' mechanisms * Passing a heap pointer is now encoded in the shuffle array. * CloseScope is now implemented as a no-op, warning of this once per context --- .../espresso/launcher/EspressoLauncher.java | 12 +- .../truffle/espresso/libjavavm/Arguments.java | 3 +- .../src/mokapot.c | 2 +- .../truffle/espresso/impl/ClassRegistry.java | 2 +- .../truffle/espresso/jni/RawBuffer.java | 143 ++++++++++++++++++ .../methodhandle/MHLinkToNativeNode.java | 4 +- .../runtime/panama/DowncallStubNode.java | 7 +- .../runtime/panama/DowncallStubs.java | 94 ++++++++++-- .../espresso/runtime/panama/VMStorage.java | 3 + .../panama/aarch64/AArch64StorageType.java | 3 +- .../runtime/panama/x64/X64StorageType.java | 3 +- ..._java_lang_invoke_MethodHandleNatives.java | 4 + ...internal_foreign_abi_NativeEntryPoint.java | 3 + ..._jdk_internal_misc_ScopedMemoryAccess.java | 49 ++++++ 14 files changed, 306 insertions(+), 26 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java b/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java index e7f1d4bb1a9f..22ccf12ffb7a 100644 --- a/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java +++ b/espresso/src/com.oracle.truffle.espresso.launcher/src/com/oracle/truffle/espresso/launcher/EspressoLauncher.java @@ -276,10 +276,6 @@ protected List preprocessArguments(List arguments, Map expanded) { "WhiteBoxAPI", "EnableJVMCI"); + private static final Set ignoredXXOptions = Set.of( + "UseJVMCICompiler", + "EnableDynamicAgentLoading"); + private void handleXXArg(String fullArg, ArrayList unrecognized) { String arg = fullArg.substring("-XX:".length()); String name; @@ -451,6 +451,10 @@ private void handleXXArg(String fullArg, ArrayList unrecognized) { name = arg.substring(0, idx); value = arg.substring(idx + 1); } + if (ignoredXXOptions.contains(name)) { + getError().println("Ignoring " + arg); + return; + } if (knownPassThroughOptions.contains(name)) { espressoOptions.put("java." + name, value); return; diff --git a/espresso/src/com.oracle.truffle.espresso.libjavavm/src/com/oracle/truffle/espresso/libjavavm/Arguments.java b/espresso/src/com.oracle.truffle.espresso.libjavavm/src/com/oracle/truffle/espresso/libjavavm/Arguments.java index 4cd948d522ad..fbe227cef8c7 100644 --- a/espresso/src/com.oracle.truffle.espresso.libjavavm/src/com/oracle/truffle/espresso/libjavavm/Arguments.java +++ b/espresso/src/com.oracle.truffle.espresso.libjavavm/src/com/oracle/truffle/espresso/libjavavm/Arguments.java @@ -77,7 +77,8 @@ private Arguments() { "TieredStopAtLevel", "MaxMetaspaceSize", "HeapDumpOnOutOfMemoryError", - "UseJVMCICompiler"); + "UseJVMCICompiler", + "EnableDynamicAgentLoading"); private static final Map MAPPED_XX_OPTIONS = Map.of( "TieredCompilation", "engine.MultiTier"); diff --git a/espresso/src/com.oracle.truffle.espresso.mokapot/src/mokapot.c b/espresso/src/com.oracle.truffle.espresso.mokapot/src/mokapot.c index 86fb5ecc1041..22d4300d1821 100644 --- a/espresso/src/com.oracle.truffle.espresso.mokapot/src/mokapot.c +++ b/espresso/src/com.oracle.truffle.espresso.mokapot/src/mokapot.c @@ -1419,7 +1419,7 @@ JNIEXPORT void JNICALL JVM_BeforeHalt() { JNIEXPORT void JNICALL JVM_ExpandStackFrameInfo(JNIEnv *env, jobject obj) { IMPLEMENTED(JVM_ExpandStackFrameInfo); - return (*getEnv())->JVM_ExpandStackFrameInfo(env, obj); + (*getEnv())->JVM_ExpandStackFrameInfo(env, obj); } JNIEXPORT jobject JNICALL JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode, diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java index 7cb47b6621dd..d1be9f79b555 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java @@ -348,7 +348,7 @@ Klass loadKlass(EspressoContext context, Symbol type, StaticObject protect } assert entry != null; StaticObject classLoader = getClassLoader(); - if (!StaticObject.isNull(classLoader) && context.getJavaVersion().java21OrEarlier()) { + if (!StaticObject.isNull(classLoader) && context.getJavaVersion().java23OrEarlier()) { entry.checkPackageAccess(env.getMeta(), classLoader, protectionDomain); } return entry.klass(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/RawBuffer.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/RawBuffer.java index 2dcb68fdbf02..4fa20d7255b4 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/RawBuffer.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/RawBuffer.java @@ -27,11 +27,17 @@ import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; import com.oracle.truffle.espresso.ffi.nfi.NativeUtils; +import com.oracle.truffle.espresso.impl.ArrayKlass; import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.runtime.EspressoContext; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; public final class RawBuffer implements AutoCloseable { private ByteBuffer buffer; @@ -86,9 +92,146 @@ public TruffleObject pointer() { return pointer; } + @TruffleBoundary + public static RawBuffer getNativeHeapPointer(StaticObject obj, EspressoContext ctx) { + assert obj.getKlass().isArray(); + JavaKind componentKind = ((ArrayKlass) obj.getKlass()).getComponentType().getJavaKind(); + ByteBuffer bb = NativeUtils.allocateDirect(obj.length(ctx.getLanguage()) * componentKind.getByteCount()); + switch (componentKind) { + case Boolean -> { + boolean[] array = obj.unwrap(ctx.getLanguage()); + for (boolean b : array) { + bb.put((byte) (b ? 1 : 0)); + } + } + case Byte -> { + byte[] array = obj.unwrap(ctx.getLanguage()); + for (byte b : array) { + bb.put(b); + } + } + case Short -> { + short[] array = obj.unwrap(ctx.getLanguage()); + for (short s : array) { + bb.putShort(s); + } + } + case Char -> { + char[] array = obj.unwrap(ctx.getLanguage()); + for (char c : array) { + bb.putChar(c); + } + } + case Int -> { + int[] array = obj.unwrap(ctx.getLanguage()); + for (int i : array) { + bb.putInt(i); + } + } + case Float -> { + float[] array = obj.unwrap(ctx.getLanguage()); + for (float f : array) { + bb.putFloat(f); + } + } + case Long -> { + long[] array = obj.unwrap(ctx.getLanguage()); + for (long l : array) { + bb.putLong(l); + } + } + case Double -> { + double[] array = obj.unwrap(ctx.getLanguage()); + for (double d : array) { + bb.putDouble(d); + } + } + default -> throw ctx.getMeta().throwExceptionWithMessage(ctx.getMeta().java_lang_IllegalArgumentException, "Unsupported java heap access in downcall stub: " + obj.getKlass()); + } + return new RawBuffer(bb, NativeUtils.byteBufferPointer(bb)); + } + + @TruffleBoundary + public void writeBack(StaticObject obj, EspressoContext ctx) { + assert obj.getKlass().isArray(); + JavaKind componentKind = ((ArrayKlass) obj.getKlass()).getComponentType().getJavaKind(); + ByteBuffer bb = buffer.rewind(); + switch (componentKind) { + case Boolean -> { + boolean[] array = obj.unwrap(ctx.getLanguage()); + for (int i = 0; i < array.length; i++) { + array[i] = bb.get() != 0; + } + } + case Byte -> { + byte[] array = obj.unwrap(ctx.getLanguage()); + for (int i = 0; i < array.length; i++) { + array[i] = bb.get(); + } + } + case Short -> { + short[] array = obj.unwrap(ctx.getLanguage()); + for (int i = 0; i < array.length; i++) { + array[i] = bb.getShort(); + } + } + case Char -> { + char[] array = obj.unwrap(ctx.getLanguage()); + for (int i = 0; i < array.length; i++) { + array[i] = bb.getChar(); + } + } + case Int -> { + int[] array = obj.unwrap(ctx.getLanguage()); + for (int i = 0; i < array.length; i++) { + array[i] = bb.getInt(); + } + } + case Float -> { + float[] array = obj.unwrap(ctx.getLanguage()); + for (int i = 0; i < array.length; i++) { + array[i] = bb.getFloat(); + } + } + case Long -> { + long[] array = obj.unwrap(ctx.getLanguage()); + for (int i = 0; i < array.length; i++) { + array[i] = bb.getLong(); + } + } + case Double -> { + double[] array = obj.unwrap(ctx.getLanguage()); + for (int i = 0; i < array.length; i++) { + array[i] = bb.getDouble(); + } + } + default -> throw ctx.getMeta().throwExceptionWithMessage(ctx.getMeta().java_lang_IllegalArgumentException, "Unsupported java heap access in downcall stub: " + obj.getKlass()); + } + } + @Override public void close() { buffer.clear(); this.buffer = null; } + + public static class Buffers { + private final ArrayList buffers = new ArrayList<>(0); + private final ArrayList arrays = new ArrayList<>(0); + + public void writeBack(EspressoContext ctx) { + assert buffers.size() == arrays.size(); + for (int i = 0; i < buffers.size(); i++) { + RawBuffer b = buffers.get(i); + StaticObject target = arrays.get(i); + b.writeBack(target, ctx); + b.close(); + } + } + + public void add(RawBuffer b, StaticObject obj) { + buffers.add(b); + arrays.add(obj); + } + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHLinkToNativeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHLinkToNativeNode.java index d1ec5c2c20ef..443aa46d5b57 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHLinkToNativeNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHLinkToNativeNode.java @@ -69,13 +69,13 @@ protected Object doUncached(Object[] args) { assert args.length == argCount; long downcallStubId = getDowncallStubId(args); EspressoContext context = getContext(); - DowncallStubs.DowncallStub stub = context.getDowncallStubs().getStub(downcallStubId); + DowncallStubs.DowncallStub stub = context.getDowncallStubs().getStub(downcallStubId, context); return stub.uncachedCall(args, context); } protected DowncallStubNode createDowncallStubNode(long downcallStubId) { EspressoContext context = getContext(); - DowncallStubs.DowncallStub stub = context.getDowncallStubs().getStub(downcallStubId); + DowncallStubs.DowncallStub stub = context.getDowncallStubs().getStub(downcallStubId, context); return DowncallStubNode.create(stub, context.getNativeAccess()); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/DowncallStubNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/DowncallStubNode.java index beeab7ab64ba..f1f99ffa325b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/DowncallStubNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/DowncallStubNode.java @@ -30,6 +30,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.espresso.ffi.NativeAccess; import com.oracle.truffle.espresso.ffi.SignatureCallNode; +import com.oracle.truffle.espresso.jni.RawBuffer; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.panama.DowncallStubs.DowncallStub; @@ -51,11 +52,13 @@ public static DowncallStubNode create(DowncallStub stub, NativeAccess access) { return new DowncallStubNode(stub, access.createSignatureCall(stub.signature)); } + @SuppressWarnings("try") // Throwable.addSuppressed blocklisted by SVM. public Object call(Object[] args) { EspressoContext context = EspressoContext.get(this); Object target = downcallStub.getTarget(args, context); + RawBuffer.Buffers bb = new RawBuffer.Buffers(); try { - Object result = signatureCall.call(target, downcallStub.processArgs(args)); + Object result = signatureCall.call(target, downcallStub.processArgs(args, bb, context)); if (downcallStub.hasCapture()) { downcallStub.captureState(args, interop, context); } @@ -63,6 +66,8 @@ public Object call(Object[] args) { } catch (ArityException | UnsupportedTypeException | UnsupportedMessageException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); throw EspressoError.shouldNotReachHere(e); + } finally { + bb.writeBack(context); } } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/DowncallStubs.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/DowncallStubs.java index 8cc508458c24..d5b7235eafa3 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/DowncallStubs.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/DowncallStubs.java @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.EnumSet; +import java.util.concurrent.atomic.AtomicInteger; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; @@ -40,16 +41,20 @@ import com.oracle.truffle.espresso.ffi.NativeSignature; import com.oracle.truffle.espresso.ffi.NativeType; import com.oracle.truffle.espresso.impl.Klass; +import com.oracle.truffle.espresso.jni.RawBuffer; import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.OS; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; public final class DowncallStubs { private static final TruffleLogger LOGGER = TruffleLogger.getLogger(EspressoLanguage.ID, DowncallStubs.class); public static final int MAX_STUB_COUNT = Integer.MAX_VALUE - 8; + private final Platform platform; private DowncallStub[] stubs; - private int nextId = 0; + private final AtomicInteger nextId = new AtomicInteger(1); // 0 is reserved for null stub. public DowncallStubs(Platform platform) { this.platform = platform; @@ -57,15 +62,12 @@ public DowncallStubs(Platform platform) { @TruffleBoundary public long makeStub(Klass[] pTypes, Klass rType, VMStorage[] inputRegs, VMStorage[] outRegs, boolean needsReturnBuffer, int capturedStateMask, boolean needsTransition) { - int id; - synchronized (this) { - id = nextId++; - } + int id = nextId.getAndIncrement(); DowncallStub stub = create(pTypes, rType, inputRegs, outRegs, needsReturnBuffer, capturedStateMask, needsTransition); synchronized (this) { if (stubs == null) { - assert id == 0; + assert id == 1; stubs = new DowncallStub[8]; } else if (id >= stubs.length) { long newSize = stubs.length * 2L; @@ -133,6 +135,9 @@ private DowncallStub create(Klass[] pTypes, Klass rType, VMStorage[] inputRegs, for (int i = 0; i < pTypes.length; i++) { Klass pType = pTypes[i]; VMStorage inputReg = inputRegs[i]; + if (inputReg == null) { + continue; + } StorageType regType = inputReg.type(platform); if (regType.isPlaceholder()) { switch (inputReg.getStubLocation(platform)) { @@ -155,8 +160,9 @@ private DowncallStub create(Klass[] pTypes, Klass rType, VMStorage[] inputRegs, } int index = argsCalc.getNextInputIndex(inputReg, pType, nextInputReg, nextPType); if (index >= 0) { - shuffle[nativeIndex] = i; - nativeParamTypes[nativeIndex] = inputReg.asNativeType(platform, pType); + NativeType nativeType = inputReg.asNativeType(platform, pType); + nativeParamTypes[nativeIndex] = nativeType; + shuffle[nativeIndex] = Shuffle.encode(i, nativeType); nativeIndex++; } else if (index != ArgumentsCalculator.SKIP && !platform.ignoreDownCallArgument(inputReg)) { throw EspressoError.shouldNotReachHere("Cannot understand argument " + i + " in downcall: " + inputReg + " for type " + pType + " calc: " + argsCalc); @@ -208,6 +214,11 @@ private static boolean validCapturableState(EnumSet states, OS public boolean freeStub(long downcallStub) { // TODO maybe trim this when possible. int id = Math.toIntExact(downcallStub); + if (id <= 0 || id >= stubs.length) { + LOGGER.warning(() -> "Unknown Stub handle in free downcall stub: " + id); + // JDK will throw InternalError when we return false. + return false; + } if (stubs[id] == null) { return false; } @@ -215,14 +226,49 @@ public boolean freeStub(long downcallStub) { return true; } - public DowncallStub getStub(long downcallStub) { + public DowncallStub getStub(long downcallStub, EspressoContext ctx) { int id = Math.toIntExact(downcallStub); - return stubs[id]; + DowncallStub stub; + if (id <= 0 || id >= stubs.length) { + stub = null; + } else { + stub = stubs[id]; + } + if (stub == null) { + // We don't expect to recover. + CompilerDirectives.transferToInterpreterAndInvalidate(); + Meta meta = ctx.getMeta(); + throw meta.throwExceptionWithMessage(meta.java_lang_InternalError, "Unable to locate downcall stub with id: " + id); + } + return stub; + } + + public static final class Shuffle { + private static final int POINTER_ARG_FLAG = 1 << 31; + private static final int INDEX_ARG_MASK = 0x8FFF_FFFF; + + private static int encode(int idx, NativeType type) { + int res = idx; + assert res == (res & INDEX_ARG_MASK); + if (type == NativeType.POINTER) { + res |= POINTER_ARG_FLAG; + } + return res; + } + + private static int decodeIndex(int encoded) { + return encoded & INDEX_ARG_MASK; + } + + private static boolean decodeFlag(int encoded, int flag) { + return (encoded & flag) != 0; + } } public static final class DowncallStub { private final int targetIndex; - @CompilationFinal(dimensions = 1) private final int[] shuffle; + @CompilationFinal(dimensions = 1) // + private final int[] shuffle; final NativeSignature signature; private final int captureIndex; private final int captureMask; @@ -247,14 +293,30 @@ public long getCaptureAddress(Object[] args) { } @ExplodeLoop - public Object[] processArgs(Object[] args) { + public Object[] processArgs(Object[] args, RawBuffer.Buffers buffers, EspressoContext ctx) { Object[] nativeArgs = new Object[shuffle.length]; for (int i = 0; i < shuffle.length; i++) { - nativeArgs[i] = args[shuffle[i]]; + int encoded = shuffle[i]; + Object arg = args[Shuffle.decodeIndex(encoded)]; + if (Shuffle.decodeFlag(encoded, Shuffle.POINTER_ARG_FLAG)) { + assert arg instanceof StaticObject; + arg = handlePointerArg(buffers, ctx, (StaticObject) arg); + } + nativeArgs[i] = arg; } return nativeArgs; } + private static Object handlePointerArg(RawBuffer.Buffers buffers, EspressoContext ctx, StaticObject obj) { + if (!obj.isArray()) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw ctx.getMeta().throwExceptionWithMessage(ctx.getMeta().java_lang_InternalError, "Unsupported java heap access in downcall stub: " + obj.getKlass()); + } + RawBuffer buffer = RawBuffer.getNativeHeapPointer(obj, ctx); + buffers.add(buffer, obj); + return buffer.pointer(); + } + @TruffleBoundary public static TruffleObject resolveTarget(long targetHandle, EspressoContext context) { return context.getVM().getFunction(targetHandle); @@ -306,11 +368,13 @@ public boolean hasCapture() { return captureIndex >= 0; } + @SuppressWarnings("try") // Throwable.addSuppressed blocklisted by SVM. public Object uncachedCall(Object[] args, EspressoContext context) { TruffleObject target = getTarget(args, context); NativeAccess access = context.getNativeAccess(); + RawBuffer.Buffers bb = new RawBuffer.Buffers(); try { - Object result = access.callSignature(getCallableSignature(access, access.isFallbackSymbol(target)), target, processArgs(args)); + Object result = access.callSignature(getCallableSignature(access, access.isFallbackSymbol(target)), target, processArgs(args, bb, context)); if (hasCapture()) { captureState(args, InteropLibrary.getUncached(), context); } @@ -318,6 +382,8 @@ public Object uncachedCall(Object[] args, EspressoContext context) { } catch (ArityException | UnsupportedTypeException | UnsupportedMessageException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); throw EspressoError.shouldNotReachHere(e); + } finally { + bb.writeBack(context); } } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/VMStorage.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/VMStorage.java index 5972e647c3a2..a27bd159db1d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/VMStorage.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/VMStorage.java @@ -64,6 +64,9 @@ public static StubLocation get(int id) { } public static VMStorage fromGuest(StaticObject guestVmStorage, Meta meta) { + if (StaticObject.isNull(guestVmStorage)) { + return null; + } return new VMStorage( meta.jdk_internal_foreign_abi_VMStorage_type.getByte(guestVmStorage), meta.jdk_internal_foreign_abi_VMStorage_segmentMaskOrSize.getShort(guestVmStorage), diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/aarch64/AArch64StorageType.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/aarch64/AArch64StorageType.java index 5b77fef5da21..69726a22d43c 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/aarch64/AArch64StorageType.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/aarch64/AArch64StorageType.java @@ -72,8 +72,9 @@ public NativeType asNativeType(short maskOrSize, Klass type) { yield switch (type.getJavaKind()) { case Int -> NativeType.INT; case Long -> NativeType.LONG; + case Object -> NativeType.POINTER; case Char, Short, Byte, Boolean -> throw EspressoError.shouldNotReachHere("Unexpected sub-word in INTEGER: " + type); - case Double, Float, Object, Void, ReturnAddress, Illegal -> throw EspressoError.shouldNotReachHere("Unexpected kind in INTEGER: " + type); + case Double, Float, Void, ReturnAddress, Illegal -> throw EspressoError.shouldNotReachHere("Unexpected kind in INTEGER: " + type); }; } case VECTOR -> { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/x64/X64StorageType.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/x64/X64StorageType.java index f2244aea2b44..313b0d3192f3 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/x64/X64StorageType.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/panama/x64/X64StorageType.java @@ -74,8 +74,9 @@ public NativeType asNativeType(short maskOrSize, Klass type) { yield switch (type.getJavaKind()) { case Int -> NativeType.INT; case Long -> NativeType.LONG; + case Object -> NativeType.POINTER; case Char, Short, Byte, Boolean -> throw EspressoError.shouldNotReachHere("Unexpected sub-word in INTEGER: " + type); - case Double, Float, Object, Void, ReturnAddress, Illegal -> throw EspressoError.shouldNotReachHere("Unexpected kind in INTEGER: " + type); + case Double, Float, Void, ReturnAddress, Illegal -> throw EspressoError.shouldNotReachHere("Unexpected kind in INTEGER: " + type); }; } case VECTOR -> { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_invoke_MethodHandleNatives.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_invoke_MethodHandleNatives.java index 3373d65316b4..7d45e6fd9244 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_invoke_MethodHandleNatives.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_invoke_MethodHandleNatives.java @@ -41,6 +41,7 @@ import static com.oracle.truffle.espresso.substitutions.standard.Target_java_lang_invoke_MethodHandleNatives.Constants.CONSTANTS_BEFORE_16; import static com.oracle.truffle.espresso.substitutions.standard.Target_java_lang_invoke_MethodHandleNatives.Constants.LM_UNCONDITIONAL; import static com.oracle.truffle.espresso.substitutions.standard.Target_java_lang_invoke_MethodHandleNatives.Constants.MN_CALLER_SENSITIVE; +import static com.oracle.truffle.espresso.substitutions.standard.Target_java_lang_invoke_MethodHandleNatives.Constants.MN_HIDDEN_MEMBER; import static com.oracle.truffle.espresso.substitutions.standard.Target_java_lang_invoke_MethodHandleNatives.Constants.MN_IS_CONSTRUCTOR; import static com.oracle.truffle.espresso.substitutions.standard.Target_java_lang_invoke_MethodHandleNatives.Constants.MN_IS_FIELD; import static com.oracle.truffle.espresso.substitutions.standard.Target_java_lang_invoke_MethodHandleNatives.Constants.MN_IS_METHOD; @@ -639,6 +640,9 @@ private static int getMethodFlags(Method target, int refKind) { if (target.isCallerSensitive()) { res |= MN_CALLER_SENSITIVE; } + if (target.isHidden()) { + res |= MN_HIDDEN_MEMBER; + } return res; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_jdk_internal_foreign_abi_NativeEntryPoint.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_jdk_internal_foreign_abi_NativeEntryPoint.java index 3837ec3b5341..d5e324f4280c 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_jdk_internal_foreign_abi_NativeEntryPoint.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_jdk_internal_foreign_abi_NativeEntryPoint.java @@ -51,6 +51,9 @@ public static long makeDowncallStub(@JavaType(MethodType.class) StaticObject met int capturedStateMask, boolean needsTransition, @Inject EspressoContext context, @Inject Meta meta) { + if (StaticObject.isNull(methodType) || StaticObject.isNull(encArgMoves) || StaticObject.isNull(encRetMoves)) { + throw meta.throwNullPointerException(); + } Klass[] pTypes = getPTypes(methodType, meta); Klass rType = meta.java_lang_invoke_MethodType_rtype.getObject(methodType).getMirrorKlass(meta); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_jdk_internal_misc_ScopedMemoryAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_jdk_internal_misc_ScopedMemoryAccess.java index 9d8fc5c5446b..a1ea1c4096b5 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_jdk_internal_misc_ScopedMemoryAccess.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_jdk_internal_misc_ScopedMemoryAccess.java @@ -26,11 +26,16 @@ import java.util.concurrent.Future; import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.ThreadLocalAction; import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.api.TruffleSafepoint; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.FrameInstance; import com.oracle.truffle.api.frame.FrameInstanceVisitor; @@ -47,6 +52,7 @@ import com.oracle.truffle.espresso.substitutions.Inject; import com.oracle.truffle.espresso.substitutions.JavaType; import com.oracle.truffle.espresso.substitutions.Substitution; +import com.oracle.truffle.espresso.substitutions.SubstitutionNode; @EspressoSubstitutions public final class Target_jdk_internal_misc_ScopedMemoryAccess { @@ -70,6 +76,49 @@ public static void registerNatives() { return !action.found; } + @Substitution + abstract static class CloseScope0 extends SubstitutionNode { + abstract void execute(@JavaType(internalName = "Ljdk/internal/foreign/MemorySessionImpl;") StaticObject session, + @JavaType(internalName = "Ljdk/internal/misc/ScopedMemoryAccess$ScopedAccessError;") StaticObject error); + + @Specialization + @SuppressWarnings("unused") + static void doCloseScope(StaticObject session, StaticObject err, + @Cached Once warn) { + // GR-65277 + if (warn.once()) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + TruffleLogger logger = EspressoContext.get(null).getLogger(); + logger.warning("ScopedMemoryAccess.closeScope() not supported in this Java version, and is currently a no-op."); + } + } + + } + + static final class Once { + private Once() { + } + + @CompilationFinal private volatile boolean valid = true; + + public boolean once() { + if (valid) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + synchronized (this) { + if (valid) { + valid = false; + return true; + } + } + } + return false; + } + + public static Once create() { + return new Once(); + } + } + private static final class CloseScopedMemoryAction extends ThreadLocalAction { static final int MAX_CRITICAL_STACK_DEPTH = 10; final StaticObject value; From 9fb3b2199539135fe14b655d5a62916063ffab32 Mon Sep 17 00:00:00 2001 From: Thomas Garcia Date: Tue, 22 Apr 2025 19:17:31 +0200 Subject: [PATCH 4/7] Use new j.l.Class fields, and removed substitutions for methods now implemented in guest JDK. --- .../espresso/classfile/JavaVersion.java | 9 ++++ .../espresso/descriptors/EspressoSymbols.java | 3 ++ .../oracle/truffle/espresso/meta/Meta.java | 13 +++++- .../espresso/runtime/EspressoContext.java | 4 +- .../espresso/runtime/GuestAllocator.java | 25 ++++++++--- .../espresso/substitutions/VersionFilter.java | 24 +++++++++++ .../standard/Target_java_lang_Class.java | 43 ++++++++++--------- .../com/oracle/truffle/espresso/vm/VM.java | 2 + 8 files changed, 93 insertions(+), 30 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java index 84401c88de11..221f5fff35c2 100644 --- a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java @@ -39,6 +39,7 @@ public static final class VersionRange { public static final VersionRange VERSION_21_OR_HIGHER = higher(21); public static final VersionRange VERSION_21_OR_LOWER = lower(21); public static final VersionRange VERSION_22_OR_HIGHER = higher(22); + public static final VersionRange VERSION_24_OR_LOWER = lower(24); public static final VersionRange VERSION_25_OR_HIGHER = higher(25); public static final VersionRange ALL = between(0, LATEST_SUPPORTED); @@ -193,6 +194,14 @@ public boolean java23OrEarlier() { return version <= 23; } + public boolean java24OrEarlier() { + return version <= 24; + } + + public boolean java25OrLater() { + return version >= 25; + } + public boolean inRange(int low, int high) { return version >= low && version <= high; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java index bc8345674dca..b0fd022e584a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java @@ -603,6 +603,9 @@ public static class Names { public static final Symbol classRedefinedCount = SYMBOLS.putName("classRedefinedCount"); public static final Symbol componentType = SYMBOLS.putName("componentType"); public static final Symbol protectionDomain = SYMBOLS.putName("protectionDomain"); + public static final Symbol modifiers = SYMBOLS.putName("modifiers"); + public static final Symbol primitive = SYMBOLS.putName("primitive"); + public static final Symbol signers = SYMBOLS.putName("signers"); // j.l.ClassLoader public static final Symbol addClass = SYMBOLS.putName("addClass"); public static final Symbol findNative = SYMBOLS.putName("findNative"); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java index 633e7828fb9e..8f8eb5497c41 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java @@ -31,6 +31,7 @@ import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_21_OR_HIGHER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_21_OR_LOWER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_22_OR_HIGHER; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_24_OR_LOWER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_25_OR_HIGHER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_8_OR_LOWER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_9_OR_HIGHER; @@ -111,6 +112,12 @@ public Meta(EspressoContext context) { java_lang_Class_classRedefinedCount = java_lang_Class.requireDeclaredField(Names.classRedefinedCount, Types._int); java_lang_Class_name = java_lang_Class.requireDeclaredField(Names.name, Types.java_lang_String); java_lang_Class_classLoader = java_lang_Class.requireDeclaredField(Names.classLoader, Types.java_lang_ClassLoader); + java_lang_Class_modifiers = diff() // + .field(VERSION_25_OR_HIGHER, Names.modifiers, Types._char) // + .notRequiredField(java_lang_Class); + java_lang_Class_primitive = diff() // + .field(VERSION_25_OR_HIGHER, Names.primitive, Types._boolean) // + .notRequiredField(java_lang_Class); java_lang_Class_componentType = diff() // .field(VERSION_9_OR_HIGHER, Names.componentType, Types.java_lang_Class)// .notRequiredField(java_lang_Class); @@ -118,7 +125,9 @@ public Meta(EspressoContext context) { .field(higher(15), Names.classData, Types.java_lang_Object)// .notRequiredField(java_lang_Class); HIDDEN_MIRROR_KLASS = java_lang_Class.requireHiddenField(Names.HIDDEN_MIRROR_KLASS); - HIDDEN_SIGNERS = java_lang_Class.requireHiddenField(Names.HIDDEN_SIGNERS); + HIDDEN_SIGNERS = diff() // + .field(VERSION_24_OR_LOWER, Names.HIDDEN_SIGNERS, Types.java_lang_Object_array) // + .maybeHiddenfield(java_lang_Class); HIDDEN_PROTECTION_DOMAIN = diff() // .field(lower(24), Names.HIDDEN_PROTECTION_DOMAIN, Types.java_security_ProtectionDomain) // .field(VERSION_25_OR_HIGHER, Names.protectionDomain, Types.java_security_ProtectionDomain) // @@ -1453,6 +1462,8 @@ private DiffVersionLoadHelper diff() { public final Field HIDDEN_SIGNERS; public final Field java_lang_Class_module; public final Field java_lang_Class_classLoader; + public final Field java_lang_Class_modifiers; + public final Field java_lang_Class_primitive; public final Field sun_reflect_ConstantPool_constantPoolOop; public final ArrayKlass java_lang_Class_array; public final Method java_lang_Class_getName; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java index 2e6c36881c56..a34920b320cb 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java @@ -503,9 +503,11 @@ private void spawnVM() throws ContextPatchingException { Types.java_lang_invoke_MethodHandle, Types.java_lang_invoke_MemberName, Types.java_lang_invoke_MethodHandleNatives)) { - // Types.java_lang_invoke_ResolvedMethodName is not used atm initializeKnownClass(type); } + if (getJavaVersion().java25OrLater()) { + initializeKnownClass(Types.java_lang_invoke_ResolvedMethodName); + } int e = (int) meta.java_lang_System_initPhase2.invokeDirectStatic(false, logger.isLoggable(Level.FINE)); if (e != 0) { throw EspressoError.shouldNotReachHere(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/GuestAllocator.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/GuestAllocator.java index 1ac9287f62c6..95d0edb8836c 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/GuestAllocator.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/GuestAllocator.java @@ -151,22 +151,33 @@ public StaticObject copy(StaticObject toCopy) { public StaticObject createClass(Klass klass) { assert klass != null; CompilerAsserts.neverPartOfCompilation(); - ObjectKlass guestClass = klass.getMeta().java_lang_Class; + EspressoContext ctx = klass.getContext(); + Meta meta = ctx.getMeta(); + EspressoLanguage lang = ctx.getLanguage(); + + ObjectKlass guestClass = meta.java_lang_Class; StaticObject newObj = guestClass.getLinkedKlass().getShape(false).getFactory().create(guestClass); + initInstanceFields(newObj, guestClass); - klass.getMeta().java_lang_Class_classLoader.setObject(newObj, klass.getDefiningClassLoader()); - if (klass.getContext().getJavaVersion().modulesEnabled()) { + meta.java_lang_Class_classLoader.setObject(newObj, klass.getDefiningClassLoader()); + if (ctx.getJavaVersion().modulesEnabled()) { setModule(newObj, klass); } // The Class.componentType field is only available on 9+. - if (klass.isArray() && klass.getMeta().java_lang_Class_componentType != null) { - klass.getMeta().java_lang_Class_componentType.setObject(newObj, ((ArrayKlass) klass).getComponentType().initializeEspressoClass()); + if (klass.isArray() && meta.java_lang_Class_componentType != null) { + meta.java_lang_Class_componentType.setObject(newObj, ((ArrayKlass) klass).getComponentType().initializeEspressoClass()); } // Will be overriden if necessary, but should be initialized to non-host null. - klass.getMeta().HIDDEN_PROTECTION_DOMAIN.setMaybeHiddenObject(newObj, StaticObject.NULL); + meta.HIDDEN_PROTECTION_DOMAIN.setMaybeHiddenObject(newObj, StaticObject.NULL); // Final hidden field assignment - klass.getMeta().HIDDEN_MIRROR_KLASS.setHiddenObject(newObj, klass); + meta.HIDDEN_MIRROR_KLASS.setHiddenObject(newObj, klass); + + if (lang.getJavaVersion().java25OrLater()) { + assert meta.java_lang_Class_modifiers != null && meta.java_lang_Class_primitive != null; + meta.java_lang_Class_modifiers.setChar(newObj, (char) klass.getClassModifiers()); + meta.java_lang_Class_primitive.setBoolean(newObj, klass.isPrimitive()); + } return trackAllocation(klass, newObj); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java index 39f1a8eaf719..a56f4647126b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java @@ -177,4 +177,28 @@ public boolean isValidFor(JavaVersion version) { return version.java22OrLater(); } } + + final class Java24OrEarlier implements VersionFilter { + public static final Java24OrEarlier INSTANCE = new Java24OrEarlier(); + + private Java24OrEarlier() { + } + + @Override + public boolean isValidFor(JavaVersion version) { + return version.java24OrEarlier(); + } + } + + final class Java25OrLater implements VersionFilter { + public static final Java25OrLater INSTANCE = new Java25OrLater(); + + private Java25OrLater() { + } + + @Override + public boolean isValidFor(JavaVersion version) { + return version.java25OrLater(); + } + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_Class.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_Class.java index 4043eca496a2..126d55a58e25 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_Class.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_java_lang_Class.java @@ -33,6 +33,7 @@ import com.oracle.truffle.espresso.substitutions.JavaType; import com.oracle.truffle.espresso.substitutions.Substitution; import com.oracle.truffle.espresso.substitutions.SubstitutionNode; +import com.oracle.truffle.espresso.substitutions.VersionFilter; /** * These substitutions are provided for performance concerns. @@ -106,24 +107,6 @@ protected static boolean isNull(StaticObject obj) { } } - @Substitution(hasReceiver = true) - public static boolean isInterface(@JavaType(Class.class) StaticObject self, - @Inject Meta meta) { - return meta.getVM().JVM_IsInterface(self); - } - - @Substitution(hasReceiver = true) - public static boolean isPrimitive(@JavaType(Class.class) StaticObject self, - @Inject Meta meta) { - return meta.getVM().JVM_IsPrimitiveClass(self); - } - - @Substitution(hasReceiver = true) - public static boolean isArray(@JavaType(Class.class) StaticObject self, - @Inject Meta meta) { - return meta.getVM().JVM_IsArrayClass(self); - } - @Substitution(hasReceiver = true) public static boolean isHidden(@JavaType(Class.class) StaticObject self, @Inject Meta meta) { @@ -144,11 +127,29 @@ public static boolean isHidden(@JavaType(Class.class) StaticObject self, return superclass.mirror(); } - @Substitution(hasReceiver = true) + // These methods are implemented in the guest in 25+ + + @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java24OrEarlier.class) + public static boolean isInterface(@JavaType(Class.class) StaticObject self, + @Inject Meta meta) { + return meta.getVM().JVM_IsInterface(self); + } + + @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java24OrEarlier.class) + public static boolean isPrimitive(@JavaType(Class.class) StaticObject self, + @Inject Meta meta) { + return meta.getVM().JVM_IsPrimitiveClass(self); + } + + @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java24OrEarlier.class) + public static boolean isArray(@JavaType(Class.class) StaticObject self, + @Inject Meta meta) { + return meta.getVM().JVM_IsArrayClass(self); + } + + @Substitution(hasReceiver = true, languageFilter = VersionFilter.Java24OrEarlier.class) public static int getModifiers(@JavaType(Class.class) StaticObject self, @Inject Meta meta) { return meta.getVM().JVM_GetClassModifiers(self); } - - // endregion perf substitutions } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java index e47ea3a0b597..7fd03d4bf060 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java @@ -938,6 +938,7 @@ public boolean JVM_IsInterface(@JavaType(Class.class) StaticObject self) { if (klass.isPrimitive()) { return StaticObject.NULL; } + assert getMeta().HIDDEN_SIGNERS != null; StaticObject signersArray = (StaticObject) getMeta().HIDDEN_SIGNERS.getHiddenObject(self); if (signersArray == null || StaticObject.isNull(signersArray)) { return StaticObject.NULL; @@ -949,6 +950,7 @@ public boolean JVM_IsInterface(@JavaType(Class.class) StaticObject self) { public void JVM_SetClassSigners(@JavaType(Class.class) StaticObject self, @JavaType(Object[].class) StaticObject signers) { Klass klass = self.getMirrorKlass(getMeta()); if (!klass.isPrimitive() && !klass.isArray()) { + assert getMeta().HIDDEN_SIGNERS != null; getMeta().HIDDEN_SIGNERS.setHiddenObject(self, signers); } } From 489f516d67eeeccf855768e9931e85003410d19f Mon Sep 17 00:00:00 2001 From: Thomas Garcia Date: Mon, 28 Apr 2025 15:30:36 +0200 Subject: [PATCH 5/7] Update Changelog and ci files. --- espresso/CHANGELOG.md | 1 + espresso/ci/ci_common/common.jsonnet | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/espresso/CHANGELOG.md b/espresso/CHANGELOG.md index c0699a192986..7c990fa33ef3 100644 --- a/espresso/CHANGELOG.md +++ b/espresso/CHANGELOG.md @@ -4,6 +4,7 @@ ### User-visible changes * Added experimental support for JVMCI. It can be enabled with the `java.EnableJVMCI` option. * Added experimentation support for `-javaagent`. It can also be enabled from the polyglot API with `java.JavaAgent.$i` option set to `/path/to/jar=agent-options` where `$i` starts at 0 and increments by 1 for each extra java agent. +* Added support for guest Java version 25. ## Version 24.2.0 ### User-visible changes diff --git a/espresso/ci/ci_common/common.jsonnet b/espresso/ci/ci_common/common.jsonnet index 875b6b7057c8..d5819d54e479 100644 --- a/espresso/ci/ci_common/common.jsonnet +++ b/espresso/ci/ci_common/common.jsonnet @@ -118,6 +118,8 @@ local benchmark_suites = ['dacapo', 'renaissance', 'scala-dacapo']; linux_amd64_graalvm21: self.espresso_jdk_21 + graal_common.graalvmee21 + self.espresso_jdk_21_llvm + self.linux_amd64, + linux_amd64_latest:graal_common.labsjdkLatest + self.linux_amd64, + // precise targets and capabilities jdk21_gate_linux_amd64 : self.gate + self.linux_amd64_21, jdk21_gate_linux_aarch64 : self.gate + self.linux_aarch64_21, @@ -158,7 +160,8 @@ local benchmark_suites = ['dacapo', 'renaissance', 'scala-dacapo']; jdk21_on_demand_bench_linux : self.onDemandBench + self.linux_amd64_21 + self.x52, jdk21_on_demand_bench_darwin : self.onDemandBench + self.darwin_amd64_21, jdk21_on_demand_bench_windows : self.onDemandBench + self.windows_21, - + jdkLatest_weekly_linux_amd64 : self.weekly + self.linux_amd64_latest, + // shared snippets eclipse: graal_common.deps.eclipse, From 92550e03d5cf3cf9c665ebdc006d6e4d992b07f1 Mon Sep 17 00:00:00 2001 From: Thomas Garcia Date: Fri, 16 May 2025 17:14:12 +0200 Subject: [PATCH 6/7] [GR-65064] Improve handling of the magic accessor across Espresso. --- .../constantpool/RuntimeConstantPool.java | 11 ++-- .../espresso/descriptors/EspressoSymbols.java | 3 ++ .../espresso/impl/ClassLoadingEnv.java | 27 +++++++++- .../truffle/espresso/impl/ClassRegistry.java | 53 ++++++++++++------- .../oracle/truffle/espresso/impl/Klass.java | 25 ++------- .../truffle/espresso/impl/ObjectKlass.java | 3 +- .../oracle/truffle/espresso/meta/Meta.java | 2 +- 7 files changed, 73 insertions(+), 51 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/RuntimeConstantPool.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/RuntimeConstantPool.java index 18efa6b43d6e..ebb573b968f5 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/RuntimeConstantPool.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/RuntimeConstantPool.java @@ -361,7 +361,7 @@ public ResolvedClassConstant resolveClassConstant(int classIndex, ObjectKlass ac Symbol type = context.getTypes().fromClassNameEntry(klassName); Klass klass = context.getMeta().resolveSymbolOrFail(type, accessingKlass.getDefiningClassLoader(), accessingKlass.protectionDomain()); Klass checkedKlass = klass.getElementalType(); - if (!Klass.checkAccess(checkedKlass, accessingKlass, false)) { + if (!Klass.checkAccess(checkedKlass, accessingKlass)) { Meta meta = context.getMeta(); context.getLogger().log(Level.FINE, "Access check of: " + checkedKlass.getType() + " from " + accessingKlass.getType() + " throws IllegalAccessError"); @@ -372,13 +372,13 @@ public ResolvedClassConstant resolveClassConstant(int classIndex, ObjectKlass ac if (accessingKlass.module() == checkedKlass.module()) { errorMessage.append(checkedKlass.getExternalName()); errorMessage.append(" and "); - ClassRegistry.classInModuleOfLoader(accessingKlass, true, errorMessage, meta); + ClassRegistry.classInModuleOfLoader(context.getClassLoadingEnv(), accessingKlass, true, errorMessage, meta); } else { // checkedKlass is not an array type (getElementalType) nor a // primitive type (it would have passed the access checks) - ClassRegistry.classInModuleOfLoader((ObjectKlass) checkedKlass, false, errorMessage, meta); + ClassRegistry.classInModuleOfLoader(context.getClassLoadingEnv(), (ObjectKlass) checkedKlass, false, errorMessage, meta); errorMessage.append("; "); - ClassRegistry.classInModuleOfLoader(accessingKlass, false, errorMessage, meta); + ClassRegistry.classInModuleOfLoader(context.getClassLoadingEnv(), accessingKlass, false, errorMessage, meta); } errorMessage.append(")"); } @@ -479,8 +479,7 @@ public static boolean memberCheckAccess(Klass accessingKlass, Klass resolvedKlas return true; } // MagicAccessorImpl marks internal reflection classes that have access to everything. - if (accessingKlass.getJavaVersion().java23OrEarlier() && - accessingKlass.getMeta().sun_reflect_MagicAccessorImpl.isAssignableFrom(accessingKlass)) { + if (accessingKlass.isMagicAccessor()) { return true; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java index b0fd022e584a..85808bbcb725 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/EspressoSymbols.java @@ -279,6 +279,7 @@ public static void ensureInitialized() { // MagicAccessorImpl is not public. public static final Symbol sun_reflect_MagicAccessorImpl = SYMBOLS.putType("Lsun/reflect/MagicAccessorImpl;"); public static final Symbol jdk_internal_reflect_MagicAccessorImpl = SYMBOLS.putType("Ljdk/internal/reflect/MagicAccessorImpl;"); + public static final Symbol jdk_internal_reflect_SerializationConstructorAccessorImpl = SYMBOLS.putType("Ljdk/internal/reflect/SerializationConstructorAccessorImpl;"); // DelegatingClassLoader is not public. public static final Symbol sun_reflect_DelegatingClassLoader = SYMBOLS.putType("Lsun/reflect/DelegatingClassLoader;"); public static final Symbol jdk_internal_reflect_DelegatingClassLoader = SYMBOLS.putType("Ljdk/internal/reflect/DelegatingClassLoader;"); @@ -574,6 +575,8 @@ public static class Names { public static final Symbol main = SYMBOLS.putName("main"); // Reflection + public static final Symbol jdk_internal_reflect = SYMBOLS.putName("jdk/internal/reflect"); + public static final Symbol sun_reflect = SYMBOLS.putName("sun/reflect"); public static final Symbol clazz = SYMBOLS.putName("clazz"); public static final Symbol getParameterTypes = SYMBOLS.putName("getParameterTypes"); public static final Symbol override = SYMBOLS.putName("override"); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassLoadingEnv.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassLoadingEnv.java index 193004f0af97..8bb61d67742c 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassLoadingEnv.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassLoadingEnv.java @@ -39,6 +39,7 @@ import com.oracle.truffle.espresso.classfile.descriptors.Type; import com.oracle.truffle.espresso.classfile.descriptors.TypeSymbols; import com.oracle.truffle.espresso.classfile.perf.TimerCollection; +import com.oracle.truffle.espresso.descriptors.EspressoSymbols; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; @@ -94,16 +95,38 @@ public boolean shouldCacheClass(ClassRegistry.ClassDefinitionInfo info, StaticOb (loaderIsBootOrPlatform(loader) || loaderIsAppLoader(loader)); } + public boolean isReflectPackage(Symbol pkg) { + /* + * Note: This class is created too early in the init process to make this variable a final + * field. + */ + Symbol reflectPackage = getLanguage().getJavaVersion().java8OrEarlier() + ? EspressoSymbols.Names.sun_reflect + : EspressoSymbols.Names.jdk_internal_reflect; + return pkg == reflectPackage; + } + + @SuppressWarnings("static-method") + public boolean loaderIsBoot(StaticObject loader) { + return StaticObject.isNull(loader); + } + public boolean loaderIsBootOrPlatform(StaticObject loader) { - return StaticObject.isNull(loader) || + return loaderIsBoot(loader) || (language.getJavaVersion().java9OrLater() && meta.jdk_internal_loader_ClassLoaders$PlatformClassLoader.isAssignableFrom(loader.getKlass())); } public boolean loaderIsAppLoader(StaticObject loader) { - return !StaticObject.isNull(loader) && + return !loaderIsBoot(loader) && (meta.jdk_internal_loader_ClassLoaders$AppClassLoader.isAssignableFrom(loader.getKlass())); } + public boolean loaderIsReflection(StaticObject loader) { + return meta.sun_reflect_DelegatingClassLoader != null && + !loaderIsBoot(loader) && + meta.sun_reflect_DelegatingClassLoader.isAssignableFrom(loader.getKlass()); + } + public long getNewKlassId() { long id = klassIdProvider.getAndIncrement(); if (id < 0) { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java index d1be9f79b555..94aefea5a05e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java @@ -576,9 +576,24 @@ private ObjectKlass createKlass(EspressoContext context, ParserKlass parserKlass } if (superKlass != null) { - if (!Klass.checkAccess(superKlass, klass, true)) { + /* + * These checks ensure that only classes defined in the boot or reflection class loader + * can declare a superclass in the 'jdk.internal.reflect' package. + * + * In turn, this ensures that only these classes may be magic accessors. + */ + if (!env.loaderIsBoot(getClassLoader()) && + env.isReflectPackage(superKlass.getRuntimePackage()) && + !env.loaderIsReflection(getClassLoader())) { + throw EspressoClassLoadingException.illegalAccessError( + String.format("class %s loaded by %s cannot access reflection superclass %s", + klass.getExternalName(), + loaderDesc(env, context.getMeta(), getClassLoader()), + superKlass.getExternalName())); + } + if (!Klass.checkAccess(superKlass, klass)) { StringBuilder sb = new StringBuilder().append("class ").append(klass.getExternalName()).append(" cannot access its superclass ").append(superKlass.getExternalName()); - superTypeAccessMessage(klass, superKlass, sb, context); + superTypeAccessMessage(env, klass, superKlass, sb, context); throw EspressoClassLoadingException.illegalAccessError(sb.toString()); } if (!superKlass.permittedSubclassCheck(klass)) { @@ -588,9 +603,9 @@ private ObjectKlass createKlass(EspressoContext context, ParserKlass parserKlass for (ObjectKlass interf : superInterfaces) { if (interf != null) { - if (!Klass.checkAccess(interf, klass, true)) { + if (!Klass.checkAccess(interf, klass)) { StringBuilder sb = new StringBuilder().append("class ").append(klass.getExternalName()).append(" cannot access its superinterface ").append(interf.getExternalName()); - superTypeAccessMessage(klass, interf, sb, context); + superTypeAccessMessage(env, klass, interf, sb, context); throw EspressoClassLoadingException.illegalAccessError(sb.toString()); } if (!interf.permittedSubclassCheck(klass)) { @@ -602,24 +617,24 @@ private ObjectKlass createKlass(EspressoContext context, ParserKlass parserKlass return klass; } - private static void superTypeAccessMessage(ObjectKlass sub, ObjectKlass sup, StringBuilder sb, EspressoContext context) { + private static void superTypeAccessMessage(ClassLoadingEnv env, ObjectKlass sub, ObjectKlass sup, StringBuilder sb, EspressoContext context) { if (context.getJavaVersion().modulesEnabled()) { sb.append(" ("); Meta meta = context.getMeta(); if (sup.module() == sub.module()) { sb.append(sub.getExternalName()); sb.append(" and "); - classInModuleOfLoader(sup, true, sb, meta); + classInModuleOfLoader(env, sup, true, sb, meta); } else { - classInModuleOfLoader(sub, false, sb, meta); + classInModuleOfLoader(env, sub, false, sb, meta); sb.append("; "); - classInModuleOfLoader(sup, false, sb, meta); + classInModuleOfLoader(env, sup, false, sb, meta); } sb.append(")"); } } - public static void classInModuleOfLoader(ObjectKlass klass, boolean plural, StringBuilder sb, Meta meta) { + public static void classInModuleOfLoader(ClassLoadingEnv env, ObjectKlass klass, boolean plural, StringBuilder sb, Meta meta) { assert meta.getJavaVersion().modulesEnabled() && meta.java_lang_ClassLoader_nameAndId != null; sb.append(klass.getExternalName()); if (plural) { @@ -635,16 +650,18 @@ public static void classInModuleOfLoader(ObjectKlass klass, boolean plural, Stri sb.append("unnamed module"); } sb.append(" of loader "); - StaticObject loader = klass.getDefiningClassLoader(); - if (StaticObject.isNull(loader)) { - sb.append("bootstrap"); + sb.append(loaderDesc(env, meta, klass.getDefiningClassLoader())); + } + + private static String loaderDesc(ClassLoadingEnv env, Meta meta, StaticObject loader) { + if (env.loaderIsBoot(loader)) { + return "bootstrap"; + } + StaticObject nameAndId = meta.java_lang_ClassLoader_nameAndId.getObject(loader); + if (StaticObject.isNull(nameAndId)) { + return loader.getKlass().getExternalName(); } else { - StaticObject nameAndId = meta.java_lang_ClassLoader_nameAndId.getObject(loader); - if (StaticObject.isNull(nameAndId)) { - sb.append(loader.getKlass().getExternalName()); - } else { - sb.append(meta.toHostString(nameAndId)); - } + return meta.toHostString(nameAndId); } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java index 0d8e22977005..6bbefdc22733 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java @@ -769,7 +769,7 @@ protected static boolean hasFinalInstanceField(Class clazz) { *
  • C is not public, and C and D are members of the same run-time package. * */ - public static boolean checkAccess(Klass klass, ObjectKlass accessingKlass, boolean ignoreMagicAccessor) { + public static boolean checkAccess(Klass klass, ObjectKlass accessingKlass) { if (accessingKlass == null) { return true; } @@ -795,26 +795,7 @@ public static boolean checkAccess(Klass klass, ObjectKlass accessingKlass, boole } } - if (context.getJavaVersion().java21OrEarlier()) { - if (ignoreMagicAccessor) { - /* - * Prevents any class inheriting from MagicAccessorImpl to have access to - * MagicAccessorImpl just because it implements MagicAccessorImpl. - * - * Only generated accessors in the {sun|jdk.internal}.reflect package, defined by - * {sun|jdk.internal}.reflect.DelegatingClassLoader(s) have access to - * MagicAccessorImpl. - */ - ObjectKlass magicAccessorImpl = context.getMeta().sun_reflect_MagicAccessorImpl; - return !StaticObject.isNull(accessingKlass.getDefiningClassLoader()) && - context.getMeta().sun_reflect_DelegatingClassLoader.equals(accessingKlass.getDefiningClassLoader().getKlass()) && - magicAccessorImpl.getRuntimePackage().equals(accessingKlass.getRuntimePackage()) && - magicAccessorImpl.isAssignableFrom(accessingKlass); - } - - return (context.getMeta().sun_reflect_MagicAccessorImpl.isAssignableFrom(accessingKlass)); - } - return false; + return accessingKlass.isMagicAccessor(); } public static boolean doModuleAccessChecks(Klass klass, ObjectKlass accessingKlass, EspressoContext context) { @@ -1917,7 +1898,7 @@ public final Symbol getSymbolicRuntimePackage() { @Override public final boolean isMagicAccessor() { - if (getJavaVersion().java21OrEarlier()) { + if (getMeta().sun_reflect_MagicAccessorImpl != null) { return getMeta().sun_reflect_MagicAccessorImpl.isAssignableFrom(this); } return false; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java index 7b29664d42d4..47828ce648bb 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java @@ -698,8 +698,7 @@ private void verifyImpl() { for (ObjectKlass interf : getSuperInterfaces()) { interf.verify(); } - if (getJavaVersion().java21OrEarlier() && - meta.sun_reflect_MagicAccessorImpl.isAssignableFrom(this)) { + if (isMagicAccessor()) { /* * Hotspot comment: * diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java index 8f8eb5497c41..677f763a0b4e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java @@ -2975,7 +2975,7 @@ public Klass resolveSymbolOrFail(Symbol type, @JavaType(ClassLoader.class) public Klass resolveSymbolAndAccessCheck(Symbol type, ObjectKlass accessingKlass) { assert accessingKlass != null; Klass klass = resolveSymbolOrFail(type, accessingKlass.getDefiningClassLoader(), accessingKlass.protectionDomain()); - if (!Klass.checkAccess(klass.getElementalType(), accessingKlass, false)) { + if (!Klass.checkAccess(klass.getElementalType(), accessingKlass)) { throw throwException(java_lang_IllegalAccessError); } return klass; From 566a5c4fc5dee3c885c86db5d66eac940653447d Mon Sep 17 00:00:00 2001 From: Thomas Garcia Date: Fri, 16 May 2025 17:17:04 +0200 Subject: [PATCH 7/7] Magic accessor no longer exists from JDK23 onwards. --- .../espresso/classfile/JavaVersion.java | 2 ++ .../truffle/espresso/impl/ClassRegistry.java | 18 ++++++++++-------- .../oracle/truffle/espresso/impl/Klass.java | 3 ++- .../com/oracle/truffle/espresso/meta/Meta.java | 5 ++++- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java index 221f5fff35c2..63f6c6958cd2 100644 --- a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java @@ -44,6 +44,8 @@ public static final class VersionRange { public static final VersionRange ALL = between(0, LATEST_SUPPORTED); public static final VersionRange VERSION_9_TO_21 = between(9, 21); + public static final VersionRange VERSION_9_TO_23 = between(9, 23); + public static final VersionRange VERSION_22_TO_23 = between(22, 23); private final int low; private final int high; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java index 94aefea5a05e..7ef449f3a1ce 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistry.java @@ -582,14 +582,16 @@ private ObjectKlass createKlass(EspressoContext context, ParserKlass parserKlass * * In turn, this ensures that only these classes may be magic accessors. */ - if (!env.loaderIsBoot(getClassLoader()) && - env.isReflectPackage(superKlass.getRuntimePackage()) && - !env.loaderIsReflection(getClassLoader())) { - throw EspressoClassLoadingException.illegalAccessError( - String.format("class %s loaded by %s cannot access reflection superclass %s", - klass.getExternalName(), - loaderDesc(env, context.getMeta(), getClassLoader()), - superKlass.getExternalName())); + if (context.getJavaVersion().java23OrEarlier()) { + if (!env.loaderIsBoot(getClassLoader()) && + env.isReflectPackage(superKlass.getRuntimePackage()) && + !env.loaderIsReflection(getClassLoader())) { + throw EspressoClassLoadingException.illegalAccessError( + String.format("class %s loaded by %s cannot access reflection superclass %s", + klass.getExternalName(), + loaderDesc(env, context.getMeta(), getClassLoader()), + superKlass.getExternalName())); + } } if (!Klass.checkAccess(superKlass, klass)) { StringBuilder sb = new StringBuilder().append("class ").append(klass.getExternalName()).append(" cannot access its superclass ").append(superKlass.getExternalName()); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java index 6bbefdc22733..9c2816d711f7 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java @@ -1898,7 +1898,8 @@ public final Symbol getSymbolicRuntimePackage() { @Override public final boolean isMagicAccessor() { - if (getMeta().sun_reflect_MagicAccessorImpl != null) { + if (getJavaVersion().java23OrEarlier()) { + assert getMeta().sun_reflect_MagicAccessorImpl != null; return getMeta().sun_reflect_MagicAccessorImpl.isAssignableFrom(this); } return false; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java index 677f763a0b4e..4584ed96f08d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java @@ -31,11 +31,13 @@ import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_21_OR_HIGHER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_21_OR_LOWER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_22_OR_HIGHER; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_22_TO_23; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_24_OR_LOWER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_25_OR_HIGHER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_8_OR_LOWER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_9_OR_HIGHER; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_9_TO_21; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_9_TO_23; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.between; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.higher; import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.lower; @@ -897,10 +899,11 @@ public Meta(EspressoContext context) { sun_reflect_MagicAccessorImpl = diff() // .klass(VERSION_8_OR_LOWER, Types.sun_reflect_MagicAccessorImpl) // .klass(VERSION_9_TO_21, Types.jdk_internal_reflect_MagicAccessorImpl) // + .klass(VERSION_22_TO_23, Types.jdk_internal_reflect_SerializationConstructorAccessorImpl) // .notRequiredKlass(); sun_reflect_DelegatingClassLoader = diff() // .klass(VERSION_8_OR_LOWER, Types.sun_reflect_DelegatingClassLoader) // - .klass(VERSION_9_TO_21, Types.jdk_internal_reflect_DelegatingClassLoader) // + .klass(VERSION_9_TO_23, Types.jdk_internal_reflect_DelegatingClassLoader) // .notRequiredKlass(); sun_reflect_MethodAccessorImpl = diff() //