From 4c7eacdc8ffcb4442d6ad0e15f36f8470da6649b Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 12 Sep 2024 16:13:00 +0200 Subject: [PATCH 001/105] [GR-57817] Prepare JNI and Unsafe usage for JDK 24. --- .../src/launcher.cc | 6 +- truffle/mx.truffle/mx_truffle.py | 6 +- truffle/mx.truffle/suite.py | 18 +- .../oracle/truffle/api/TruffleLanguage.java | 8 + .../com/oracle/truffle/api/impl/Accessor.java | 43 ++ .../src/truffle_attach.c | 2 +- .../nfi/backend/libffi/LibFFILanguage.java | 2 +- .../nfi/backend/panama/PanamaNFILanguage.java | 2 +- .../truffle/polyglot/EngineAccessor.java | 5 + .../truffle/polyglot/LanguageCache.java | 3 + .../oracle/truffle/polyglot/ModuleUtils.java | 488 +++++++++++++++++- .../runtime/LibTruffleAttachResource.java | 79 --- .../truffle/runtime/ModulesAccessor.java | 331 ------------ .../truffle/runtime/ModulesSupport.java | 60 +-- .../hotspot/HotSpotTruffleRuntimeAccess.java | 2 + 15 files changed, 566 insertions(+), 489 deletions(-) rename truffle/src/{com.oracle.truffle.runtime.attach => com.oracle.truffle.attach}/src/truffle_attach.c (97%) delete mode 100644 truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/LibTruffleAttachResource.java delete mode 100644 truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesAccessor.java diff --git a/sdk/src/org.graalvm.launcher.native/src/launcher.cc b/sdk/src/org.graalvm.launcher.native/src/launcher.cc index 5c45c5f13464..94b5e7c9a72e 100644 --- a/sdk/src/org.graalvm.launcher.native/src/launcher.cc +++ b/sdk/src/org.graalvm.launcher.native/src/launcher.cc @@ -558,10 +558,6 @@ static void parse_vm_options(int argc, char **argv, std::string exeDir, JavaVMIn /* Allow Truffle NFI Panama to use Linker#{downcallHandle,upcallStub} without warnings. */ vmArgs.push_back("--enable-native-access=org.graalvm.truffle"); -#if LAUNCHER_JDK_VERSION > 21 - /* Ignore illegal native access until is GR-57817 fixed. */ - vmArgs.push_back("--illegal-native-access=allow"); -#endif } jint nOptions = jvmMode ? vmArgs.size() : 1 + vmArgs.size(); @@ -857,7 +853,7 @@ static int jvm_main_thread(int argc, char *argv[], std::string exeDir, bool jvmM std::cerr << "Error in GetObjectArrayElement:" << std::endl; env->ExceptionDescribe(); return -1; - } + } const char *vmArg = env->GetStringUTFChars(vmArgString, NULL); if (env->ExceptionCheck()) { std::cerr << "Error in GetStringUTFChars:" << std::endl; diff --git a/truffle/mx.truffle/mx_truffle.py b/truffle/mx.truffle/mx_truffle.py index d4050dd5a6dc..479303156f06 100644 --- a/truffle/mx.truffle/mx_truffle.py +++ b/truffle/mx.truffle/mx_truffle.py @@ -227,10 +227,8 @@ def apply(self, config): # Disable VirtualThread warning vmArgs = vmArgs + ['-Dpolyglot.engine.WarnVirtualThreadSupport=false'] - if mx.get_jdk().javaCompliance > '23': - # Ignore illegal native access until is GR-57817 fixed. - vmArgs = vmArgs + ['--illegal-native-access=allow'] - + # Enable native access to Truffle, truffle delegates native access to languages + vmArgs = vmArgs + ['--enable-native-access=org.graalvm.truffle'] return (vmArgs, mainClass, mainClassArgs) diff --git a/truffle/mx.truffle/suite.py b/truffle/mx.truffle/suite.py index 531fb5798d70..ace5ce7fdc66 100644 --- a/truffle/mx.truffle/suite.py +++ b/truffle/mx.truffle/suite.py @@ -290,12 +290,19 @@ "sdk:POLYGLOT", "com.oracle.truffle.api.instrumentation", "com.oracle.truffle.api.exception", + "com.oracle.truffle.api.impl.asm", ], "requires" : [ "java.logging", "jdk.management", "jdk.unsupported", # sun.misc.Unsafe ], + "requiresConcealed" : { + "java.base" : [ + "jdk.internal.module", + "jdk.internal.access", + ], + }, "annotationProcessors" : ["TRUFFLE_DSL_PROCESSOR"], "checkstyle" : "com.oracle.truffle.api", "javaCompliance" : "17+", @@ -324,7 +331,6 @@ "jdk.vm.ci.code.stack", ], "java.base" : [ - "jdk.internal.module", "jdk.internal.access", ], }, @@ -1285,7 +1291,7 @@ "graalCompilerSourceEdition": "ignore", }, - "com.oracle.truffle.runtime.attach" : { + "com.oracle.truffle.attach" : { "subDir" : "src", "native" : "shared_lib", "deliverable" : "truffleattach", @@ -1646,7 +1652,6 @@ "javaCompliance" : "17+", "dependencies" : [ "com.oracle.truffle.runtime", - "TRUFFLE_RUNTIME_ATTACH_RESOURCES", ], "distDependencies" : [ "sdk:JNIUTILS", @@ -1762,6 +1767,7 @@ "com.oracle.truffle.host", "com.oracle.truffle.api.staticobject", "TRUFFLE_API_VERSION", + "TRUFFLE_ATTACH_RESOURCES", ], "distDependencies" : [ "sdk:COLLECTIONS", @@ -1786,7 +1792,7 @@ #} }, - "TRUFFLE_RUNTIME_ATTACH_RESOURCES" : { + "TRUFFLE_ATTACH_RESOURCES" : { "type" : "dir", "platformDependent" : True, "hashEntry" : "META-INF/resources/engine/libtruffleattach///sha256", @@ -1800,9 +1806,9 @@ "windows-aarch64", ], "layout" : { - "META-INF/resources/engine/libtruffleattach///bin/" : "dependency:com.oracle.truffle.runtime.attach", + "META-INF/resources/engine/libtruffleattach///bin/" : "dependency:com.oracle.truffle.attach", }, - "description" : "Contains a library to provide access for the Truffle runtime to JVMCI.", + "description" : "Contains a library to provide access for the Truffle to JDK internal classes.", "maven": False, "graalCompilerSourceEdition": "ignore", }, diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java index 166f768065c2..52b707e50a2b 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java @@ -540,6 +540,14 @@ String[] dependentLanguages() default { * @since 23.1 */ Class[] internalResources() default {}; + + /** + * Indicates whether the language requires native access, as determined by {@link Module#isNativeAccessEnabled()}. + * If {@code true}, Truffle will delegate the necessary native access privileges to the language. + * + * @since 24.2 + */ + boolean enableNativeAccess() default false; } /** diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java index edd7d0c79781..28ef6a380a3e 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java @@ -788,6 +788,8 @@ public abstract Iterator mergeHostGuestFrames(Object polyglotEngine, S public abstract Object getEngineData(Object polyglotEngine); public abstract long getEngineId(Object polyglotEngine); + + public abstract ModulesAccessor getModulesAccessor(); } public abstract static class LanguageSupport extends Support { @@ -1348,6 +1350,47 @@ protected DynamicObjectSupport() { } + /* + * We want to avoid exporting {@code jdk.internal.module} and {@code jdk.internal.access} to all + * classes in the unnamed module. So instead we load it in an isolated class loader and own + * module layer. + */ + public abstract static class ModulesAccessor { + + /** + * See {@code jdk.internal.module.Modules#addExports(Module, String, Module)}. + */ + public abstract void addExports(Module base, String p, Module target); + + /** + * See {@code jdk.internal.module.Modules#addExportsToAllUnnamed(Module, String)}. + */ + public abstract void addExportsToAllUnnamed(Module base, String p); + + /** + * See {@code jdk.internal.module.Modules#addOpens(Module, String, Module)}. + */ + public abstract void addOpens(Module base, String p, Module target); + + /** + * See {@code jdk.internal.module.Modules#addOpensToAllUnnamed(Module, String)}. + */ + public abstract void addOpensToAllUnnamed(Module base, String p); + + /** + * See {@code jdk.internal.access.JavaLangAccess#enableNativeAccess(Module)}. + */ + public abstract void addEnableNativeAccess(Module module); + + /** + * See {@code jdk.internal.access.JavaLangAccess#addEnableNativeAccessToAllUnnamed()}. + */ + public abstract void addEnableNativeAccessToAllUnnamed(); + + public abstract Module getTargetModule(); + + } + public final void transferOSRFrameStaticSlot(FrameWithoutBoxing sourceFrame, FrameWithoutBoxing targetFrame, int slot) { sourceFrame.transferOSRStaticSlot(targetFrame, slot); } diff --git a/truffle/src/com.oracle.truffle.runtime.attach/src/truffle_attach.c b/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c similarity index 97% rename from truffle/src/com.oracle.truffle.runtime.attach/src/truffle_attach.c rename to truffle/src/com.oracle.truffle.attach/src/truffle_attach.c index ec68318a8905..5e43eb7b1bec 100644 --- a/truffle/src/com.oracle.truffle.runtime.attach/src/truffle_attach.c +++ b/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c @@ -47,7 +47,7 @@ // Library entry points -JNIEXPORT void JNICALL Java_com_oracle_truffle_runtime_ModulesSupport_addExports0(JNIEnv *env, jclass clz, jobject m1, jobject pn, jobject m2) { +JNIEXPORT void JNICALL Java_com_oracle_truffle_polyglot_ModuleUtils_addExports0(JNIEnv *env, jclass clz, jobject m1, jobject pn, jobject m2) { jclass modulesClass = (*env)->FindClass(env, "jdk/internal/module/Modules"); EXCEPTION_CHECK(env); jmethodID addExports = (*env)->GetStaticMethodID(env, modulesClass, "addExports", "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V"); diff --git a/truffle/src/com.oracle.truffle.nfi.backend.libffi/src/com/oracle/truffle/nfi/backend/libffi/LibFFILanguage.java b/truffle/src/com.oracle.truffle.nfi.backend.libffi/src/com/oracle/truffle/nfi/backend/libffi/LibFFILanguage.java index 556e3fc89df4..08f8c2f0ffc2 100644 --- a/truffle/src/com.oracle.truffle.nfi.backend.libffi/src/com/oracle/truffle/nfi/backend/libffi/LibFFILanguage.java +++ b/truffle/src/com.oracle.truffle.nfi.backend.libffi/src/com/oracle/truffle/nfi/backend/libffi/LibFFILanguage.java @@ -58,7 +58,7 @@ import com.oracle.truffle.nfi.backend.spi.types.NativeSimpleType; @TruffleLanguage.Registration(id = "internal/nfi-native", name = "nfi-native", version = "0.1", characterMimeTypes = LibFFILanguage.MIME_TYPE, internal = true, // - services = NFIBackendFactory.class, contextPolicy = ContextPolicy.SHARED, internalResources = LibNFIResource.class) + services = NFIBackendFactory.class, contextPolicy = ContextPolicy.SHARED, internalResources = LibNFIResource.class, enableNativeAccess = true) public class LibFFILanguage extends TruffleLanguage { public static final String MIME_TYPE = "trufflenfi/native"; diff --git a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaNFILanguage.java b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaNFILanguage.java index 9ad094e402c0..7502e51f08e7 100644 --- a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaNFILanguage.java +++ b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaNFILanguage.java @@ -56,7 +56,7 @@ import com.oracle.truffle.nfi.backend.spi.NFIBackendFactory; import com.oracle.truffle.nfi.backend.spi.NFIState; -@TruffleLanguage.Registration(id = "internal/nfi-panama", name = "nfi-panama", version = "0.1", characterMimeTypes = PanamaNFILanguage.MIME_TYPE, internal = true, services = NFIBackendFactory.class, contextPolicy = ContextPolicy.SHARED) +@TruffleLanguage.Registration(id = "internal/nfi-panama", name = "nfi-panama", version = "0.1", characterMimeTypes = PanamaNFILanguage.MIME_TYPE, internal = true, services = NFIBackendFactory.class, contextPolicy = ContextPolicy.SHARED, enableNativeAccess = true) public class PanamaNFILanguage extends TruffleLanguage { public static final String MIME_TYPE = "trufflenfi/panama"; diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java index 31a82d470c5e..0e80abc75447 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java @@ -2195,6 +2195,11 @@ public Object getEngineData(Object polyglotEngine) { public long getEngineId(Object polyglotEngine) { return ((PolyglotEngineImpl) polyglotEngine).engineId; } + + @Override + public ModulesAccessor getModulesAccessor() { + return ModuleUtils.getModulesAccessor(); + } } abstract static class AbstractClassLoaderSupplier implements Supplier { diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java index b776ea90e5be..91345c6de07d 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java @@ -328,6 +328,9 @@ private static void loadLanguageImpl(ProviderAdapter providerAdapter, List= 21) { + try { + Class langAccessClass = Class.forName("jdk.internal.access.JavaLangAccess"); + ADD_ENABLE_NATIVE_ACCESS = langAccessClass.getDeclaredMethod("addEnableNativeAccess", Module.class); + ADD_ENABLE_NATIVE_ACCESS_TO_ALL_UNNAMED = langAccessClass.getDeclaredMethod("addEnableNativeAccessToAllUnnamed"); + } catch (ReflectiveOperationException re) { + throw new InternalError(re); + } + } else { + // On JDK-17 do nothing + ADD_ENABLE_NATIVE_ACCESS = null; + ADD_ENABLE_NATIVE_ACCESS_TO_ALL_UNNAMED = null; + } + } + + private static volatile Accessor.ModulesAccessor modulesAccessor; + + + private ModuleUtils() { + } + static void exportTo(Module clientModule) { if (!isExportedTo(clientModule)) { exportFromTo(clientModule); @@ -68,9 +120,61 @@ static void exportTransitivelyTo(Module clientModule) { if (isExportedTo(clientModule)) { return; } - - ModuleLayer layer = clientModule.getLayer(); Module truffleModule = Truffle.class.getModule(); + forEach(clientModule, EnumSet.of(Edge.READS, Edge.USES), (m) -> m != truffleModule && m.canRead(truffleModule), ModuleUtils::exportFromTo); + } + + static void enableNativeAccess(Module clientModule) { + forEach(clientModule, EnumSet.of(Edge.READS), (m) -> true, (m) -> { + if (m.isNamed()) { + getModulesAccessor().addEnableNativeAccess(m); + } else { + getModulesAccessor().addEnableNativeAccessToAllUnnamed(); + } + }); + } + + @SuppressWarnings("restricted") + static Accessor.ModulesAccessor getModulesAccessor() { + Accessor.ModulesAccessor result = modulesAccessor; + if (result == null) { + synchronized (ModuleUtils.class) { + result = modulesAccessor; + if (result == null) { + String attachLibPath = System.getProperty("truffle.attach.library"); + if (attachLibPath == null) { + try { + Path truffleAttachRoot = InternalResourceCache.installRuntimeResource(new LibTruffleAttachResource()); + Path libAttach = truffleAttachRoot.resolve("bin").resolve(System.mapLibraryName("truffleattach")); + attachLibPath = libAttach.toString(); + } catch (IOException ioe) { + throw new InternalError(ioe); + } + } + System.load(attachLibPath); + if (Accessor.ModulesAccessor.class.getModule().isNamed()) { + result = new DirectImpl(Accessor.ModulesAccessor.class); + } else { + try { + result = new IsolatedImpl(Accessor.ModulesAccessor.class); + } catch (ReflectiveOperationException e) { + throw new InternalError(e); + } + } + Module javaBase = ModuleLayer.boot().findModule("java.base").orElseThrow(); + addExports0(javaBase, "jdk.internal.module", result.getTargetModule()); + result.addExports(javaBase, "jdk.internal.access", result.getTargetModule()); + modulesAccessor = result; + } + } + } + return result; + } + + private static native void addExports0(Module m1, String pn, Module m2); + + private static void forEach(Module rootModule, Set edges, Predicate filter, Consumer action) { + ModuleLayer layer = rootModule.getLayer(); Set targetModules = new HashSet<>(); Deque todo = new ArrayDeque<>(); /* @@ -78,11 +182,11 @@ static void exportTransitivelyTo(Module clientModule) { * visited modules to detect cycles. */ Set visited = new HashSet<>(); - todo.add(clientModule); + todo.add(rootModule); Map> serviceDictionary = null; while (!todo.isEmpty()) { Module module = todo.removeFirst(); - if (visited.add(module) && Objects.equals(module.getLayer(), layer) && readsTruffleModule(truffleModule, module)) { + if (visited.add(module) && Objects.equals(module.getLayer(), layer) && filter.test(module)) { targetModules.add(module); ModuleDescriptor descriptor = module.getDescriptor(); if (descriptor == null) { @@ -105,37 +209,37 @@ static void exportTransitivelyTo(Module clientModule) { * Named module with a module descriptor: Export transitively to all modules * required by the named module. */ - for (ModuleDescriptor.Requires requires : descriptor.requires()) { - Module requiredModule = findModule(layer, requires); - if (requiredModule != null) { - todo.add(requiredModule); + if (edges.contains(Edge.READS)) { + for (ModuleDescriptor.Requires requires : descriptor.requires()) { + Module requiredModule = findModule(layer, requires); + if (requiredModule != null) { + todo.add(requiredModule); + } } } - // Open also to modules providing a service consumed by the module. - Set usedServices = descriptor.uses(); - if (!usedServices.isEmpty()) { - if (serviceDictionary == null) { - serviceDictionary = new HashMap<>(); - for (Module m : layer.modules()) { - if (readsTruffleModule(truffleModule, m)) { - for (ModuleDescriptor.Provides provides : m.getDescriptor().provides()) { - serviceDictionary.computeIfAbsent(provides.service(), (k) -> new HashSet<>()).add(m); + if (edges.contains(Edge.USES)) { + // Open also to modules providing a service consumed by the module. + Set usedServices = descriptor.uses(); + if (!usedServices.isEmpty()) { + if (serviceDictionary == null) { + serviceDictionary = new HashMap<>(); + for (Module m : layer.modules()) { + if (filter.test(m)) { + for (ModuleDescriptor.Provides provides : m.getDescriptor().provides()) { + serviceDictionary.computeIfAbsent(provides.service(), (k) -> new HashSet<>()).add(m); + } } } } - } - for (String service : usedServices) { - todo.addAll(serviceDictionary.getOrDefault(service, Set.of())); + for (String service : usedServices) { + todo.addAll(serviceDictionary.getOrDefault(service, Set.of())); + } } } } } } - targetModules.forEach(ModuleUtils::exportFromTo); - } - - private static boolean readsTruffleModule(Module truffleModule, Module otherModule) { - return otherModule != truffleModule && otherModule.canRead(truffleModule); + targetModules.forEach(action); } private static Module findModule(ModuleLayer layer, ModuleDescriptor.Requires requires) { @@ -173,4 +277,338 @@ private static void exportFromTo(Module clientModule) { } } + private enum Edge { + READS, + USES + } + + /* + * When using a named module we do not need to do anything and we can just call the Modules + * class. We used a qualified export to export it to this class. + */ + private static final class DirectImpl extends Accessor.ModulesAccessor { + + private final Class baseClass; + + DirectImpl(Class baseClass) { + if (!baseClass.getModule().isNamed()) { + throw new IllegalStateException(""); + } + this.baseClass = baseClass; + } + + @Override + public void addExports(Module base, String p, Module target) { + Modules.addExports(base, p, target); + } + + @Override + public void addExportsToAllUnnamed(Module base, String p) { + Modules.addExportsToAllUnnamed(base, p); + } + + @Override + public void addOpens(Module base, String p, Module target) { + Modules.addOpens(base, p, target); + } + + @Override + public void addOpensToAllUnnamed(Module base, String p) { + Modules.addOpensToAllUnnamed(base, p); + } + + @Override + public void addEnableNativeAccess(Module module) { + if (ADD_ENABLE_NATIVE_ACCESS != null) { + try { + ADD_ENABLE_NATIVE_ACCESS.invoke(SharedSecrets.getJavaLangAccess(), module); + } catch (ReflectiveOperationException re) { + throw new InternalError(re); + } + } + } + + @Override + public void addEnableNativeAccessToAllUnnamed() { + if (ADD_ENABLE_NATIVE_ACCESS_TO_ALL_UNNAMED != null) { + try { + ADD_ENABLE_NATIVE_ACCESS_TO_ALL_UNNAMED.invoke(SharedSecrets.getJavaLangAccess()); + } catch (ReflectiveOperationException re) { + throw new InternalError(re); + } + } + } + + @Override + public Module getTargetModule() { + return baseClass.getModule(); + } + } + + /* + * When using a named module we do not need to do anything and we can just call the Modules + * class. We used a qualified export to export it to this class. + */ + private static final class IsolatedImpl extends Accessor.ModulesAccessor { + + private final MethodHandle addExports; + private final MethodHandle addExportsToAllUnnamed; + private final MethodHandle addOpens; + private final MethodHandle addOpensToAllUnnamed; + private final MethodHandle addEnableNativeAccess; + private final MethodHandle addEnableNativeAccessToAllUnnamed; + private final Module targetModule; + + IsolatedImpl(Class baseClass) throws ReflectiveOperationException { + final String moduleName = "org.graalvm.truffle.generated"; + final String targetPackage = baseClass.getPackageName() + ".generated"; + final String className = targetPackage + ".GeneratedModules"; + final String binaryClassName = className.replace('.', '/'); + + ClassWriter cw = new ClassWriter(0); + cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, binaryClassName, null, "java/lang/Object", null); + + MethodVisitor constructor = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); + constructor.visitCode(); + constructor.visitVarInsn(Opcodes.ALOAD, 0); + constructor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false); + constructor.visitInsn(Opcodes.RETURN); + constructor.visitMaxs(1, 1); + constructor.visitEnd(); + + MethodVisitor mv1 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addExports", + "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", null, null); + mv1.visitCode(); + mv1.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module base) + mv1.visitVarInsn(Opcodes.ALOAD, 1); // Load second argument (String p) + mv1.visitVarInsn(Opcodes.ALOAD, 2); // Load third argument (Module target) + mv1.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/module/Modules", "addExports", + "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", false); + mv1.visitInsn(Opcodes.RETURN); + mv1.visitMaxs(3, 3); + mv1.visitEnd(); + + MethodVisitor mv2 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addExportsToAllUnnamed", + "(Ljava/lang/Module;Ljava/lang/String;)V", null, null); + mv2.visitCode(); + mv2.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module target) + mv2.visitVarInsn(Opcodes.ALOAD, 1); // Load second argument (String p) + mv2.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/module/Modules", "addExportsToAllUnnamed", + "(Ljava/lang/Module;Ljava/lang/String;)V", false); + mv2.visitInsn(Opcodes.RETURN); + mv2.visitMaxs(2, 2); + mv2.visitEnd(); + + MethodVisitor mv3 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addOpens", + "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", null, null); + mv3.visitCode(); + mv3.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module base) + mv3.visitVarInsn(Opcodes.ALOAD, 1); // Load second argument (String p) + mv3.visitVarInsn(Opcodes.ALOAD, 2); // Load third argument (Module target) + mv3.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/module/Modules", "addOpens", + "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", false); + mv3.visitInsn(Opcodes.RETURN); + mv3.visitMaxs(3, 3); + mv3.visitEnd(); + + MethodVisitor mv4 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addOpensToAllUnnamed", + "(Ljava/lang/Module;Ljava/lang/String;)V", null, null); + mv4.visitCode(); + mv4.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module target) + mv4.visitVarInsn(Opcodes.ALOAD, 1); // Load second argument (String p) + mv4.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/module/Modules", "addOpensToAllUnnamed", + "(Ljava/lang/Module;Ljava/lang/String;)V", false); + mv4.visitInsn(Opcodes.RETURN); + mv4.visitMaxs(2, 2); + mv4.visitEnd(); + + MethodVisitor mv5 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addEnableNativeAccess", + "(Ljava/lang/Module;)V", null, null); + mv5.visitCode(); + if (ADD_ENABLE_NATIVE_ACCESS != null) { + mv5.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/access/SharedSecrets", "getJavaLangAccess", + "()Ljdk/internal/access/JavaLangAccess;", false); + mv5.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module module) + mv5.visitMethodInsn(Opcodes.INVOKEINTERFACE, "jdk/internal/access/JavaLangAccess", "addEnableNativeAccess", + "(Ljava/lang/Module;)Ljava/lang/Module;", true); + } + mv5.visitInsn(Opcodes.RETURN); + mv5.visitMaxs(2, 2); + mv5.visitEnd(); + + MethodVisitor mv6 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addEnableNativeAccessToAllUnnamed", + "()V", null, null); + mv6.visitCode(); + if (ADD_ENABLE_NATIVE_ACCESS_TO_ALL_UNNAMED != null) { + mv6.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/access/SharedSecrets", "getJavaLangAccess", + "()Ljdk/internal/access/JavaLangAccess;", false); + mv6.visitMethodInsn(Opcodes.INVOKEINTERFACE, "jdk/internal/access/JavaLangAccess", "addEnableNativeAccessToAllUnnamed", + "()V", true); + } + mv6.visitInsn(Opcodes.RETURN); + mv6.visitMaxs(1, 1); + mv6.visitEnd(); + + cw.visitEnd(); + + byte[] classBytes = cw.toByteArray(); + + // Create a ModuleDescriptor for the new module + ModuleDescriptor descriptor = ModuleDescriptor.newModule(moduleName).exports(targetPackage).build(); + + // Create a ModuleFinder that finds the module and class + ModuleFinder finder = new ModuleFinder() { + + public Optional find(String name) { + if (name.equals(moduleName)) { + return Optional.of(new ModuleReference(descriptor, null) { + @Override + @SuppressWarnings("hiding") + public ModuleReader open() throws IOException { + return new ModuleReader() { + @Override + public Optional read(String name) throws IOException { + if (name.equals(binaryClassName + ".class")) { + return Optional.of(ByteBuffer.wrap(classBytes)); + } + return Optional.empty(); + } + + @Override + public void close() throws IOException { + } + + public Optional find(String name) throws IOException { + return Optional.empty(); + } + + public Stream list() throws IOException { + return Stream.empty(); + } + }; + } + }); + } + return Optional.empty(); + } + + @Override + public Set findAll() { + return Collections.singleton(find(moduleName).get()); + } + }; + + // Resolve the configuration for the new module layer based on the boot layer + ModuleLayer bootLayer = ModuleLayer.boot(); + Configuration cf = bootLayer.configuration().resolve(finder, ModuleFinder.of(), Collections.singleton(moduleName)); + + // Define a new module layer with the correct parent layer and class loader + ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, ClassLoader.getSystemClassLoader()); + + // Load the class from the module layer + Class generatedClass = layer.findLoader(moduleName).loadClass(className); + this.targetModule = generatedClass.getModule(); + + MethodHandles.Lookup l = MethodHandles.lookup(); + l.accessClass(generatedClass); + this.addExports = l.findStatic(generatedClass, "addExports", MethodType.methodType(void.class, Module.class, String.class, Module.class)); + this.addExportsToAllUnnamed = l.findStatic(generatedClass, "addExportsToAllUnnamed", MethodType.methodType(void.class, Module.class, String.class)); + this.addOpens = l.findStatic(generatedClass, "addOpens", MethodType.methodType(void.class, Module.class, String.class, Module.class)); + this.addOpensToAllUnnamed = l.findStatic(generatedClass, "addOpensToAllUnnamed", MethodType.methodType(void.class, Module.class, String.class)); + this.addEnableNativeAccess = l.findStatic(generatedClass, "addEnableNativeAccess", MethodType.methodType(void.class, Module.class)); + this.addEnableNativeAccessToAllUnnamed = l.findStatic(generatedClass, "addEnableNativeAccessToAllUnnamed", MethodType.methodType(void.class)); + } + + @Override + public Module getTargetModule() { + return targetModule; + } + + @Override + public void addExports(Module base, String p, Module target) { + try { + addExports.invokeExact(base, p, target); + } catch (Throwable e) { + throw new InternalError(e); + } + } + + @Override + public void addExportsToAllUnnamed(Module base, String p) { + try { + addExportsToAllUnnamed.invokeExact(base, p); + } catch (Throwable e) { + throw new InternalError(e); + } + } + + @Override + public void addOpens(Module base, String p, Module target) { + try { + addOpens.invokeExact(base, p, target); + } catch (Throwable e) { + throw new InternalError(e); + } + } + + @Override + public void addOpensToAllUnnamed(Module base, String p) { + try { + addOpensToAllUnnamed.invokeExact(base, p); + } catch (Throwable e) { + throw new InternalError(e); + } + } + + @Override + public void addEnableNativeAccess(Module module) { + try { + addEnableNativeAccess.invokeExact(module); + } catch (Throwable e) { + throw new InternalError(e); + } + } + + @Override + public void addEnableNativeAccessToAllUnnamed() { + try { + addEnableNativeAccessToAllUnnamed.invokeExact(); + } catch (Throwable e) { + throw new InternalError(e); + } + } + } + + @InternalResource.Id(value = LibTruffleAttachResource.ID, componentId = "engine", optional = true) + final static class LibTruffleAttachResource implements InternalResource { + + static final String ID = "libtruffleattach"; + + LibTruffleAttachResource() { + } + + @Override + public void unpackFiles(Env env, Path targetDirectory) throws IOException { + if (env.inNativeImageBuild() && !env.inContextPreinitialization()) { + // The truffleattach library is not needed in native-image. + return; + } + Path base = basePath(env); + env.unpackResourceFiles(base.resolve("files"), targetDirectory, base); + } + + @Override + public String versionHash(Env env) { + try { + Path base = basePath(env); + return env.readResourceLines(base.resolve("sha256")).get(0); + } catch (IOException ioe) { + throw new InternalError(ioe); + } + } + + private static Path basePath(Env env) { + return Path.of("META-INF", "resources", "engine", ID, env.getOS().toString(), env.getCPUArchitecture().toString()); + } + } } diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/LibTruffleAttachResource.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/LibTruffleAttachResource.java deleted file mode 100644 index 95c62595f357..000000000000 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/LibTruffleAttachResource.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.runtime; - -import com.oracle.truffle.api.InternalResource; - -import java.io.IOException; -import java.nio.file.Path; - -@InternalResource.Id(value = LibTruffleAttachResource.ID, componentId = "engine", optional = true) -final class LibTruffleAttachResource implements InternalResource { - - static final String ID = "libtruffleattach"; - - LibTruffleAttachResource() { - } - - @Override - public void unpackFiles(Env env, Path targetDirectory) throws IOException { - if (env.inNativeImageBuild() && !env.inContextPreinitialization()) { - // The truffleattach library is not needed in native-image. - return; - } - Path base = basePath(env); - env.unpackResourceFiles(base.resolve("files"), targetDirectory, base); - } - - @Override - public String versionHash(Env env) { - try { - Path base = basePath(env); - return env.readResourceLines(base.resolve("sha256")).get(0); - } catch (IOException ioe) { - throw new InternalError(ioe); - } - } - - private static Path basePath(Env env) { - return Path.of("META-INF", "resources", "engine", ID, env.getOS().toString(), env.getCPUArchitecture().toString()); - } -} diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesAccessor.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesAccessor.java deleted file mode 100644 index 84339beba9c6..000000000000 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesAccessor.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.runtime; - -import java.io.IOException; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; -import java.lang.invoke.MethodType; -import java.lang.module.Configuration; -import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleFinder; -import java.lang.module.ModuleReader; -import java.lang.module.ModuleReference; -import java.net.URI; -import java.nio.ByteBuffer; -import java.util.Collections; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Stream; - -import com.oracle.truffle.api.impl.asm.ClassWriter; -import com.oracle.truffle.api.impl.asm.MethodVisitor; -import com.oracle.truffle.api.impl.asm.Opcodes; - -import jdk.internal.module.Modules; - -/* - * We want to avoid exporting the Modules class to all classes in the unnamed module. So instead we - * load it in an isolated class loader and module layer. - */ -abstract sealed class ModulesAccessor permits ModulesAccessor.DirectImpl, ModulesAccessor.IsolatedImpl { - - /** - * @see Modules#addExports(Module, String, Module) - */ - abstract void addExports(Module base, String p, Module target); - - /** - * @see Modules#addExportsToAllUnnamed(Module, String) - */ - abstract void addExportsToAllUnnamed(Module base, String p); - - /** - * @see Modules#addOpens(Module, String, Module) - */ - abstract void addOpens(Module base, String p, Module target); - - /** - * @see Modules#addOpensToAllUnnamed(Module, String) - */ - abstract void addOpensToAllUnnamed(Module base, String p); - - abstract Module getTargetModule(); - - static ModulesAccessor create(Class accessingClass) { - if (accessingClass.getModule().isNamed()) { - return new DirectImpl(accessingClass); - } else { - try { - return new IsolatedImpl(accessingClass); - } catch (ReflectiveOperationException e) { - throw new InternalError(e); - } - } - } - - /* - * When using a named module we do not need to do anything and we can just call the Modules - * class. We used a qualified export to export it to this class. - */ - static final class DirectImpl extends ModulesAccessor { - - private final Class baseClass; - - DirectImpl(Class baseClass) { - if (!baseClass.getModule().isNamed()) { - throw new IllegalStateException(""); - } - this.baseClass = baseClass; - } - - @Override - void addExports(Module base, String p, Module target) { - Modules.addExports(base, p, target); - } - - @Override - void addExportsToAllUnnamed(Module base, String p) { - Modules.addExportsToAllUnnamed(base, p); - } - - @Override - void addOpens(Module base, String p, Module target) { - Modules.addOpens(base, p, target); - } - - @Override - void addOpensToAllUnnamed(Module base, String p) { - Modules.addOpensToAllUnnamed(base, p); - } - - @Override - Module getTargetModule() { - return baseClass.getModule(); - } - } - - /* - * When using a named module we do not need to do anything and we can just call the Modules - * class. We used a qualified export to export it to this class. - */ - static final class IsolatedImpl extends ModulesAccessor { - - private final MethodHandle addExports; - private final MethodHandle addExportsToAllUnnamed; - private final MethodHandle addOpens; - private final MethodHandle addOpensToAllUnnamed; - private final Module targetModule; - - IsolatedImpl(Class baseClass) throws ReflectiveOperationException { - final String moduleName = "org.graalvm.truffle.runtime.generated"; - final String targetPackage = baseClass.getPackageName() + ".generated"; - final String className = targetPackage + ".GeneratedModules"; - final String binaryClassName = className.replace('.', '/'); - - ClassWriter cw = new ClassWriter(0); - cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, binaryClassName, null, "java/lang/Object", null); - - MethodVisitor constructor = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); - constructor.visitCode(); - constructor.visitVarInsn(Opcodes.ALOAD, 0); - constructor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false); - constructor.visitInsn(Opcodes.RETURN); - constructor.visitMaxs(1, 1); - constructor.visitEnd(); - - MethodVisitor mv1 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addExports", - "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", null, null); - mv1.visitCode(); - mv1.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module base) - mv1.visitVarInsn(Opcodes.ALOAD, 1); // Load second argument (String p) - mv1.visitVarInsn(Opcodes.ALOAD, 2); // Load third argument (Module target) - mv1.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/module/Modules", "addExports", - "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", false); - mv1.visitInsn(Opcodes.RETURN); - mv1.visitMaxs(3, 3); - mv1.visitEnd(); - - MethodVisitor mv2 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addExportsToAllUnnamed", - "(Ljava/lang/Module;Ljava/lang/String;)V", null, null); - mv2.visitCode(); - mv2.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module target) - mv2.visitVarInsn(Opcodes.ALOAD, 1); // Load second argument (String p) - mv2.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/module/Modules", "addExportsToAllUnnamed", - "(Ljava/lang/Module;Ljava/lang/String;)V", false); - mv2.visitInsn(Opcodes.RETURN); - mv2.visitMaxs(2, 2); - mv2.visitEnd(); - - MethodVisitor mv3 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addOpens", - "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", null, null); - mv3.visitCode(); - mv3.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module base) - mv3.visitVarInsn(Opcodes.ALOAD, 1); // Load second argument (String p) - mv3.visitVarInsn(Opcodes.ALOAD, 2); // Load third argument (Module target) - mv3.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/module/Modules", "addOpens", - "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", false); - mv3.visitInsn(Opcodes.RETURN); - mv3.visitMaxs(3, 3); - mv3.visitEnd(); - - MethodVisitor mv4 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addOpensToAllUnnamed", - "(Ljava/lang/Module;Ljava/lang/String;)V", null, null); - mv4.visitCode(); - mv4.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module target) - mv4.visitVarInsn(Opcodes.ALOAD, 1); // Load second argument (String p) - mv4.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/module/Modules", "addOpensToAllUnnamed", - "(Ljava/lang/Module;Ljava/lang/String;)V", false); - mv4.visitInsn(Opcodes.RETURN); - mv4.visitMaxs(2, 2); - mv4.visitEnd(); - - cw.visitEnd(); - - byte[] classBytes = cw.toByteArray(); - - // Create a ModuleDescriptor for the new module - ModuleDescriptor descriptor = ModuleDescriptor.newModule(moduleName).exports(targetPackage).build(); - - // Create a ModuleFinder that finds the module and class - ModuleFinder finder = new ModuleFinder() { - - public Optional find(String name) { - if (name.equals(moduleName)) { - return Optional.of(new ModuleReference(descriptor, null) { - @Override - @SuppressWarnings("hiding") - public ModuleReader open() throws IOException { - return new ModuleReader() { - @Override - public Optional read(String name) throws IOException { - if (name.equals(binaryClassName + ".class")) { - return Optional.of(ByteBuffer.wrap(classBytes)); - } - return Optional.empty(); - } - - @Override - public void close() throws IOException { - } - - public Optional find(String name) throws IOException { - return Optional.empty(); - } - - public Stream list() throws IOException { - return Stream.empty(); - } - }; - } - }); - } - return Optional.empty(); - } - - @Override - public Set findAll() { - return Collections.singleton(find(moduleName).get()); - } - }; - - // Resolve the configuration for the new module layer based on the boot layer - ModuleLayer bootLayer = ModuleLayer.boot(); - Configuration cf = bootLayer.configuration().resolve(finder, ModuleFinder.of(), Collections.singleton(moduleName)); - - // Define a new module layer with the correct parent layer and class loader - ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, ClassLoader.getSystemClassLoader()); - - // Load the class from the module layer - Class generatedClass = layer.findLoader(moduleName).loadClass(className); - this.targetModule = generatedClass.getModule(); - - Lookup l = MethodHandles.lookup(); - l.accessClass(generatedClass); - this.addExports = l.findStatic(generatedClass, "addExports", MethodType.methodType(void.class, Module.class, String.class, Module.class)); - this.addExportsToAllUnnamed = l.findStatic(generatedClass, "addExportsToAllUnnamed", MethodType.methodType(void.class, Module.class, String.class)); - this.addOpens = l.findStatic(generatedClass, "addOpens", MethodType.methodType(void.class, Module.class, String.class, Module.class)); - this.addOpensToAllUnnamed = l.findStatic(generatedClass, "addOpensToAllUnnamed", MethodType.methodType(void.class, Module.class, String.class)); - } - - @Override - Module getTargetModule() { - return targetModule; - } - - @Override - public void addExports(Module base, String p, Module target) { - try { - addExports.invokeExact(base, p, target); - } catch (Throwable e) { - throw new InternalError(e); - } - } - - @Override - public void addExportsToAllUnnamed(Module base, String p) { - try { - addExportsToAllUnnamed.invokeExact(base, p); - } catch (Throwable e) { - throw new InternalError(e); - } - } - - @Override - void addOpens(Module base, String p, Module target) { - try { - addOpens.invokeExact(base, p, target); - } catch (Throwable e) { - throw new InternalError(e); - } - } - - @Override - void addOpensToAllUnnamed(Module base, String p) { - try { - addOpensToAllUnnamed.invokeExact(base, p); - } catch (Throwable e) { - throw new InternalError(e); - } - } - } -} diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java index 60bf26039a7b..2e930dcdcfda 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java @@ -43,29 +43,17 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Requires; import java.lang.reflect.Method; -import java.nio.file.Path; import java.util.HashSet; import java.util.Set; -import com.oracle.truffle.api.InternalResource; import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.TruffleRuntime; +import com.oracle.truffle.api.impl.Accessor; +import com.oracle.truffle.api.impl.Accessor.ModulesAccessor; public final class ModulesSupport { - private static final boolean ATTACH_AVAILABLE; - private static final ModulesAccessor ACCESSOR; - - static { - ATTACH_AVAILABLE = loadModulesSupportLibrary(); - if (ATTACH_AVAILABLE) { - // this is the only access we really need to request natively using JNI. - // after that we can access through the Modules class - ACCESSOR = ModulesAccessor.create(ModulesSupport.class); - addExports0(ModuleLayer.boot().findModule("java.base").orElseThrow(), "jdk.internal.module", ACCESSOR.getTargetModule()); - } else { - ACCESSOR = null; - } - } + private static final ModulesAccessor ACCESSOR = getModulesAccessor(); private ModulesSupport() { } @@ -105,10 +93,6 @@ private static String exportJVMCI(Module module, Set seenModules) { // jvmci not found -> fallback to default runtime return "JVMCI is not enabled for this JVM. Enable JVMCI using -XX:+EnableJVMCI."; } - - if (!ATTACH_AVAILABLE) { - return "The Truffle attach library is not available."; - } addExportsRecursive(layer, jvmciModule, module, seenModules); return null; } @@ -153,25 +137,29 @@ public static void addOpens(Module base, String p, Module target) { } } - @SuppressWarnings("restricted") - private static boolean loadModulesSupportLibrary() { - String attachLibPath = System.getProperty("truffle.attach.library"); + public static void enableNativeAccess(Module module) { + if (module.isNamed()) { + ACCESSOR.addEnableNativeAccess(module); + } else { + ACCESSOR.addEnableNativeAccessToAllUnnamed(); + } + } + + /** + * Gets {@code ModulesAccessor} reflectively. + *

+ * The {@code ModulesSupport} class is initialized before {@link TruffleRuntime} is created, so + * we cannot use {@link Accessor.EngineSupport#getModulesAccessor()}. + *

+ */ + private static ModulesAccessor getModulesAccessor() { try { - if (attachLibPath == null) { - Class resourceCacheClass = Class.forName("com.oracle.truffle.polyglot.InternalResourceCache", false, ModulesSupport.class.getClassLoader()); - Method installRuntimeResource = resourceCacheClass.getDeclaredMethod("installRuntimeResource", InternalResource.class); - installRuntimeResource.setAccessible(true); - Path root = (Path) installRuntimeResource.invoke(null, new LibTruffleAttachResource()); - Path libAttach = root.resolve("bin").resolve(System.mapLibraryName("truffleattach")); - attachLibPath = libAttach.toString(); - } - System.load(attachLibPath); - return true; + Class resourceCacheClass = Class.forName("com.oracle.truffle.polyglot.ModuleUtils", false, ModulesSupport.class.getClassLoader()); + Method getModulesAccessor = resourceCacheClass.getDeclaredMethod("getModulesAccessor"); + getModulesAccessor.setAccessible(true); + return (ModulesAccessor) getModulesAccessor.invoke(null); } catch (Throwable throwable) { throw new InternalError(throwable); } } - - private static native void addExports0(Module m1, String pn, Module m2); - } diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java index 3c5f2cba3423..bc071cf2c355 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java @@ -142,6 +142,8 @@ protected static TruffleRuntime createRuntime() { // For SharedSecrets.getJavaLangAccess().currentCarrierThread() ModulesSupport.addExports(javaBase, "jdk.internal.access", runtimeModule); + // HotSpotVirtualThreadHooks has a native method to register JVMTI hook + ModulesSupport.enableNativeAccess(runtimeModule); TruffleCompilationSupport compilationSupport; if (LibGraal.isAvailable()) { From 9cc52d503e46b5cdb675bea2b91f6b6861b8afbe Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Tue, 17 Sep 2024 18:20:19 +0200 Subject: [PATCH 002/105] [GR-57817] Clean up of existing module support classes. --- .../oracle/truffle/api/TruffleLanguage.java | 5 +- .../src/truffle_attach.c | 2 +- .../truffle/polyglot/EngineAccessor.java | 6 +- .../truffle/polyglot/InstrumentCache.java | 4 +- .../polyglot/InternalResourceCache.java | 2 +- .../truffle/polyglot/LanguageCache.java | 6 +- .../{ModuleUtils.java => ModulesSupport.java} | 43 ++++++------- .../oracle/truffle/polyglot/PolyglotImpl.java | 2 +- .../oracle/truffle/runtime/ModuleUtil.java | 64 ------------------- .../truffle/runtime/ModulesSupport.java | 16 ++++- .../runtime/OptimizedTruffleRuntime.java | 2 +- .../truffle/runtime/debug/JFRListener.java | 4 +- 12 files changed, 53 insertions(+), 103 deletions(-) rename truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/{ModuleUtils.java => ModulesSupport.java} (94%) delete mode 100644 truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModuleUtil.java diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java index 52b707e50a2b..9ea2cee0711a 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java @@ -542,8 +542,9 @@ String[] dependentLanguages() default { Class[] internalResources() default {}; /** - * Indicates whether the language requires native access, as determined by {@link Module#isNativeAccessEnabled()}. - * If {@code true}, Truffle will delegate the necessary native access privileges to the language. + * Indicates whether the language requires native access, as determined by + * {@link Module#isNativeAccessEnabled()}. If {@code true}, Truffle will delegate the + * necessary native access privileges to the language. * * @since 24.2 */ diff --git a/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c b/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c index 5e43eb7b1bec..1e3ddba4e6cc 100644 --- a/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c +++ b/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c @@ -47,7 +47,7 @@ // Library entry points -JNIEXPORT void JNICALL Java_com_oracle_truffle_polyglot_ModuleUtils_addExports0(JNIEnv *env, jclass clz, jobject m1, jobject pn, jobject m2) { +JNIEXPORT void JNICALL Java_com_oracle_truffle_polyglot_ModulesSupport_addExports0(JNIEnv *env, jclass clz, jobject m1, jobject pn, jobject m2) { jclass modulesClass = (*env)->FindClass(env, "jdk/internal/module/Modules"); EXCEPTION_CHECK(env); jmethodID addExports = (*env)->GetStaticMethodID(env, modulesClass, "addExports", "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V"); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java index 0e80abc75447..64c0756fdc32 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java @@ -340,14 +340,14 @@ public Iterable loadServices(Class type) { // 2) Lookup implementations of a module aware interface for (T service : ServiceLoader.load(type, loader)) { if (loaderSupplier.accepts(service.getClass())) { - ModuleUtils.exportTransitivelyTo(service.getClass().getModule()); + ModulesSupport.exportTransitivelyTo(service.getClass().getModule()); found.putIfAbsent(service.getClass(), service); } } // 3) Lookup implementations of a legacy interface // GR-46293 Remove the deprecated service interface lookup. if (legacyInterface != null && loaderSupplier.supportsLegacyProviders()) { - ModuleUtils.exportToUnnamedModuleOf(loader); + ModulesSupport.exportToUnnamedModuleOf(loader); for (T service : ServiceLoader.load(legacyInterface, loader)) { if (loaderSupplier.accepts(service.getClass())) { found.putIfAbsent(service.getClass(), service); @@ -2198,7 +2198,7 @@ public long getEngineId(Object polyglotEngine) { @Override public ModulesAccessor getModulesAccessor() { - return ModuleUtils.getModulesAccessor(); + return ModulesSupport.getModulesAccessor(); } } diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java index 37ad9b16dab5..57041d5f1caf 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java @@ -197,7 +197,7 @@ static List doLoad(List suppliers) @SuppressWarnings("deprecation") private static Stream loadLegacyProviders(ClassLoader loader) { - ModuleUtils.exportToUnnamedModuleOf(loader); + ModulesSupport.exportToUnnamedModuleOf(loader); return StreamSupport.stream(ServiceLoader.load(TruffleInstrument.Provider.class, loader).spliterator(), false).map(LegacyProvider::new); } @@ -209,7 +209,7 @@ private static void loadInstrumentImpl(ProviderAdapter providerAdapter, List>> optionalResources) { Class providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); - ModuleUtils.exportTransitivelyTo(providerModule); + ModulesSupport.exportTransitivelyTo(providerModule); Registration reg = providerClass.getAnnotation(Registration.class); if (reg == null) { emitWarning("Warning Truffle instrument ignored: Provider %s is missing @Registration annotation.", providerClass); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java index fd7d760e71d2..a5e3598d6fe4 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java @@ -411,7 +411,7 @@ private static Map>> collect continue; } StreamSupport.stream(ServiceLoader.load(InternalResourceProvider.class, loader).spliterator(), false).filter((p) -> supplier.accepts(p.getClass())).forEach((p) -> { - ModuleUtils.exportTransitivelyTo(p.getClass().getModule()); + ModulesSupport.exportTransitivelyTo(p.getClass().getModule()); String componentId = EngineAccessor.LANGUAGE_PROVIDER.getInternalResourceComponentId(p); String resourceId = EngineAccessor.LANGUAGE_PROVIDER.getInternalResourceId(p); var componentOptionalResources = cache.computeIfAbsent(componentId, (k) -> new HashMap<>()); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java index 91345c6de07d..f0f282218692 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java @@ -306,7 +306,7 @@ private static synchronized Map createLanguages(List loadLegacyProviders(ClassLoader loader) { - ModuleUtils.exportToUnnamedModuleOf(loader); + ModulesSupport.exportToUnnamedModuleOf(loader); return StreamSupport.stream(ServiceLoader.load(TruffleLanguage.Provider.class, loader).spliterator(), false).map(LegacyProvider::new); } @@ -322,14 +322,14 @@ private static boolean hasSameCodeSource(LanguageCache first, LanguageCache seco private static void loadLanguageImpl(ProviderAdapter providerAdapter, List into, Map>> optionalResources) { Class providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); - ModuleUtils.exportTransitivelyTo(providerModule); + ModulesSupport.exportTransitivelyTo(providerModule); Registration reg = providerClass.getAnnotation(Registration.class); if (reg == null) { emitWarning("Warning Truffle language ignored: Provider %s is missing @Registration annotation.", providerClass); return; } if (reg.enableNativeAccess()) { - ModuleUtils.enableNativeAccess(providerModule); + ModulesSupport.enableNativeAccess(providerModule); } String className = providerAdapter.getLanguageClassName(); String name = reg.name(); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModuleUtils.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java similarity index 94% rename from truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModuleUtils.java rename to truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java index 7133a1be0e48..16f5d36accaa 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModuleUtils.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java @@ -76,11 +76,11 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.module.Modules; -final class ModuleUtils { +final class ModulesSupport { /* - * We use reflective access to addEnableAccess and addEnableNativeAccessToAllUnnamed - * to make Truffle compilable on JDK-17. + * We use reflective access to addEnableAccess and addEnableNativeAccessToAllUnnamed to make + * Truffle compilable on JDK-17. */ private static final Method ADD_ENABLE_NATIVE_ACCESS; private static final Method ADD_ENABLE_NATIVE_ACCESS_TO_ALL_UNNAMED; @@ -102,8 +102,7 @@ final class ModuleUtils { private static volatile Accessor.ModulesAccessor modulesAccessor; - - private ModuleUtils() { + private ModulesSupport() { } static void exportTo(Module clientModule) { @@ -121,7 +120,7 @@ static void exportTransitivelyTo(Module clientModule) { return; } Module truffleModule = Truffle.class.getModule(); - forEach(clientModule, EnumSet.of(Edge.READS, Edge.USES), (m) -> m != truffleModule && m.canRead(truffleModule), ModuleUtils::exportFromTo); + forEach(clientModule, EnumSet.of(Edge.READS, Edge.USES), (m) -> m != truffleModule && m.canRead(truffleModule), ModulesSupport::exportFromTo); } static void enableNativeAccess(Module clientModule) { @@ -138,7 +137,7 @@ static void enableNativeAccess(Module clientModule) { static Accessor.ModulesAccessor getModulesAccessor() { Accessor.ModulesAccessor result = modulesAccessor; if (result == null) { - synchronized (ModuleUtils.class) { + synchronized (ModulesSupport.class) { result = modulesAccessor; if (result == null) { String attachLibPath = System.getProperty("truffle.attach.library"); @@ -377,73 +376,73 @@ private static final class IsolatedImpl extends Accessor.ModulesAccessor { constructor.visitEnd(); MethodVisitor mv1 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addExports", - "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", null, null); + "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", null, null); mv1.visitCode(); mv1.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module base) mv1.visitVarInsn(Opcodes.ALOAD, 1); // Load second argument (String p) mv1.visitVarInsn(Opcodes.ALOAD, 2); // Load third argument (Module target) mv1.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/module/Modules", "addExports", - "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", false); + "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", false); mv1.visitInsn(Opcodes.RETURN); mv1.visitMaxs(3, 3); mv1.visitEnd(); MethodVisitor mv2 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addExportsToAllUnnamed", - "(Ljava/lang/Module;Ljava/lang/String;)V", null, null); + "(Ljava/lang/Module;Ljava/lang/String;)V", null, null); mv2.visitCode(); mv2.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module target) mv2.visitVarInsn(Opcodes.ALOAD, 1); // Load second argument (String p) mv2.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/module/Modules", "addExportsToAllUnnamed", - "(Ljava/lang/Module;Ljava/lang/String;)V", false); + "(Ljava/lang/Module;Ljava/lang/String;)V", false); mv2.visitInsn(Opcodes.RETURN); mv2.visitMaxs(2, 2); mv2.visitEnd(); MethodVisitor mv3 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addOpens", - "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", null, null); + "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", null, null); mv3.visitCode(); mv3.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module base) mv3.visitVarInsn(Opcodes.ALOAD, 1); // Load second argument (String p) mv3.visitVarInsn(Opcodes.ALOAD, 2); // Load third argument (Module target) mv3.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/module/Modules", "addOpens", - "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", false); + "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V", false); mv3.visitInsn(Opcodes.RETURN); mv3.visitMaxs(3, 3); mv3.visitEnd(); MethodVisitor mv4 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addOpensToAllUnnamed", - "(Ljava/lang/Module;Ljava/lang/String;)V", null, null); + "(Ljava/lang/Module;Ljava/lang/String;)V", null, null); mv4.visitCode(); mv4.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module target) mv4.visitVarInsn(Opcodes.ALOAD, 1); // Load second argument (String p) mv4.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/module/Modules", "addOpensToAllUnnamed", - "(Ljava/lang/Module;Ljava/lang/String;)V", false); + "(Ljava/lang/Module;Ljava/lang/String;)V", false); mv4.visitInsn(Opcodes.RETURN); mv4.visitMaxs(2, 2); mv4.visitEnd(); MethodVisitor mv5 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addEnableNativeAccess", - "(Ljava/lang/Module;)V", null, null); + "(Ljava/lang/Module;)V", null, null); mv5.visitCode(); if (ADD_ENABLE_NATIVE_ACCESS != null) { mv5.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/access/SharedSecrets", "getJavaLangAccess", - "()Ljdk/internal/access/JavaLangAccess;", false); + "()Ljdk/internal/access/JavaLangAccess;", false); mv5.visitVarInsn(Opcodes.ALOAD, 0); // Load first argument (Module module) mv5.visitMethodInsn(Opcodes.INVOKEINTERFACE, "jdk/internal/access/JavaLangAccess", "addEnableNativeAccess", - "(Ljava/lang/Module;)Ljava/lang/Module;", true); + "(Ljava/lang/Module;)Ljava/lang/Module;", true); } mv5.visitInsn(Opcodes.RETURN); mv5.visitMaxs(2, 2); mv5.visitEnd(); MethodVisitor mv6 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "addEnableNativeAccessToAllUnnamed", - "()V", null, null); + "()V", null, null); mv6.visitCode(); if (ADD_ENABLE_NATIVE_ACCESS_TO_ALL_UNNAMED != null) { mv6.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/access/SharedSecrets", "getJavaLangAccess", - "()Ljdk/internal/access/JavaLangAccess;", false); + "()Ljdk/internal/access/JavaLangAccess;", false); mv6.visitMethodInsn(Opcodes.INVOKEINTERFACE, "jdk/internal/access/JavaLangAccess", "addEnableNativeAccessToAllUnnamed", - "()V", true); + "()V", true); } mv6.visitInsn(Opcodes.RETURN); mv6.visitMaxs(1, 1); @@ -580,7 +579,7 @@ public void addEnableNativeAccessToAllUnnamed() { } @InternalResource.Id(value = LibTruffleAttachResource.ID, componentId = "engine", optional = true) - final static class LibTruffleAttachResource implements InternalResource { + static final class LibTruffleAttachResource implements InternalResource { static final String ID = "libtruffleattach"; diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java index 3c99ca496398..fcf6155c50e6 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java @@ -487,7 +487,7 @@ public Class loadLanguageClass(String className) { Class clazz = loader.loadClass(className); if (supplier.accepts(clazz)) { Module clazzModule = clazz.getModule(); - ModuleUtils.exportTransitivelyTo(clazzModule); + ModulesSupport.exportTransitivelyTo(clazzModule); return clazz; } } catch (ClassNotFoundException e) { diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModuleUtil.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModuleUtil.java deleted file mode 100644 index 7a6c6161756e..000000000000 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModuleUtil.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.runtime; - -import java.util.Set; - -public final class ModuleUtil { - - public static void exportTo(Class client) { - Module truffleModule = ModuleUtil.class.getModule(); - exportFromTo(truffleModule, client.getModule()); - } - - private static void exportFromTo(Module truffleModule, Module clientModule) { - if (truffleModule != clientModule) { - Set packages = truffleModule.getPackages(); - for (String pkg : packages) { - boolean exported = truffleModule.isExported(pkg, clientModule); - if (!exported) { - truffleModule.addExports(pkg, clientModule); - } - } - } - } - -} diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java index 2e930dcdcfda..9ec79f537fab 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java @@ -145,6 +145,20 @@ public static void enableNativeAccess(Module module) { } } + public static void exportTruffleRuntimeTo(Class client) { + Module truffleModule = ModulesSupport.class.getModule(); + Module clientModule = client.getModule(); + if (truffleModule != clientModule) { + Set packages = truffleModule.getPackages(); + for (String pkg : packages) { + boolean exported = truffleModule.isExported(pkg, clientModule); + if (!exported) { + truffleModule.addExports(pkg, clientModule); + } + } + } + } + /** * Gets {@code ModulesAccessor} reflectively. *

@@ -154,7 +168,7 @@ public static void enableNativeAccess(Module module) { */ private static ModulesAccessor getModulesAccessor() { try { - Class resourceCacheClass = Class.forName("com.oracle.truffle.polyglot.ModuleUtils", false, ModulesSupport.class.getClassLoader()); + Class resourceCacheClass = Class.forName("com.oracle.truffle.polyglot.ModulesSupport", false, ModulesSupport.class.getClassLoader()); Method getModulesAccessor = resourceCacheClass.getDeclaredMethod("getModulesAccessor"); getModulesAccessor.setAccessible(true); return (ModulesAccessor) getModulesAccessor.invoke(null); diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java index 7b4f3bbef627..0564811b06db 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java @@ -804,7 +804,7 @@ public T getCapability(Class capability) { return capability.cast(tvmci); } else if (capability == com.oracle.truffle.api.object.LayoutFactory.class) { com.oracle.truffle.api.object.LayoutFactory layoutFactory = loadObjectLayoutFactory(); - ModuleUtil.exportTo(layoutFactory.getClass()); + ModulesSupport.exportTruffleRuntimeTo(layoutFactory.getClass()); return capability.cast(layoutFactory); } else if (capability == TVMCI.Test.class) { return capability.cast(getTestTvmci()); diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/debug/JFRListener.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/debug/JFRListener.java index 353ddaa92fc2..5cd044e8999c 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/debug/JFRListener.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/debug/JFRListener.java @@ -47,6 +47,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; +import com.oracle.truffle.runtime.ModulesSupport; import org.graalvm.nativeimage.ImageInfo; import org.graalvm.nativeimage.ImageSingletons; @@ -55,7 +56,6 @@ import com.oracle.truffle.compiler.TruffleCompilerListener.GraphInfo; import com.oracle.truffle.runtime.AbstractCompilationTask; import com.oracle.truffle.runtime.AbstractGraalTruffleRuntimeListener; -import com.oracle.truffle.runtime.ModuleUtil; import com.oracle.truffle.runtime.OptimizedCallTarget; import com.oracle.truffle.runtime.OptimizedTruffleRuntime; import com.oracle.truffle.runtime.jfr.CompilationEvent; @@ -254,7 +254,7 @@ private static EventFactory lookupFactory() { Iterator it = TruffleRuntimeServices.load(EventFactory.Provider.class).iterator(); EventFactory.Provider provider = it.hasNext() ? it.next() : null; if (provider != null) { - ModuleUtil.exportTo(provider.getClass()); + ModulesSupport.exportTruffleRuntimeTo(provider.getClass()); return provider.getEventFactory(); } else { return null; From 0e392e3141379e65973dcc61b96fc4ac435bc489 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 19 Sep 2024 14:23:23 +0200 Subject: [PATCH 003/105] [GR-57817] Removed unneeded ForeignSupport. --- truffle/mx.truffle/suite.py | 19 --- .../truffle/api/foreign/ForeignUtil.java | 81 ----------- .../api/foreign/ForeignSupportImpl.java | 133 ------------------ .../truffle/api/foreign/ForeignUtil.java | 83 ----------- .../com/oracle/truffle/api/impl/Accessor.java | 28 +--- .../nfi/backend/panama/ErrorContext.java | 13 +- .../truffle/nfi/backend/panama/NFIError.java | 4 +- .../nfi/backend/panama/NFIPanamaAccessor.java | 52 ------- .../nfi/backend/panama/PanamaNFIBackend.java | 4 +- .../nfi/backend/panama/PanamaSignature.java | 9 +- 10 files changed, 17 insertions(+), 409 deletions(-) delete mode 100644 truffle/src/com.oracle.truffle.api.jdk22/src/com/oracle/truffle/api/foreign/ForeignUtil.java delete mode 100644 truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/foreign/ForeignSupportImpl.java delete mode 100644 truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/foreign/ForeignUtil.java delete mode 100644 truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/NFIPanamaAccessor.java diff --git a/truffle/mx.truffle/suite.py b/truffle/mx.truffle/suite.py index ace5ce7fdc66..0987dc9cc7f1 100644 --- a/truffle/mx.truffle/suite.py +++ b/truffle/mx.truffle/suite.py @@ -238,25 +238,6 @@ "graalCompilerSourceEdition": "ignore", }, - "com.oracle.truffle.api.jdk22" : { - "subDir" : "src", - "sourceDirs" : ["src"], - "dependencies" : [ - ], - "requires" : [ - ], - "overlayTarget" : "com.oracle.truffle.api", - "checkPackagePrefix" : "false", - "multiReleaseJarVersion" : "22", - "javaCompliance" : "22+", - "forceJavac": True, - "checkstyle" : "com.oracle.truffle.api", - "workingSets" : "API,Truffle", - "graalCompilerSourceEdition": "ignore", - # disable SpotBugs as long JDK 22 is unsupported [GR-49566] - "spotbugs" : "false", - }, - "com.oracle.truffle.api.jdk21" : { "subDir" : "src", "sourceDirs" : ["src"], diff --git a/truffle/src/com.oracle.truffle.api.jdk22/src/com/oracle/truffle/api/foreign/ForeignUtil.java b/truffle/src/com.oracle.truffle.api.jdk22/src/com/oracle/truffle/api/foreign/ForeignUtil.java deleted file mode 100644 index affcb22e0c18..000000000000 --- a/truffle/src/com.oracle.truffle.api.jdk22/src/com/oracle/truffle/api/foreign/ForeignUtil.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.api.foreign; - -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SymbolLookup; -import java.lang.invoke.MethodHandle; - -final class ForeignUtil { - - private ForeignUtil() { - } - - @SuppressWarnings("restricted") - public static Object libraryLookup(String libraryName, Object arena) { - return SymbolLookup.libraryLookup(libraryName, (Arena) arena); - } - - @SuppressWarnings("restricted") - public static MethodHandle downcallHandle(String symbolName, Object functionDescriptor) { - Linker linker = Linker.nativeLinker(); - MemorySegment addr = linker.defaultLookup().findOrThrow(symbolName); - return linker.downcallHandle(addr, (FunctionDescriptor) functionDescriptor); - } - - @SuppressWarnings("restricted") - public static MethodHandle downcallHandle(Object functionDescriptor) { - return Linker.nativeLinker().downcallHandle((FunctionDescriptor) functionDescriptor); - } - - @SuppressWarnings("restricted") - public static Object upcallStub(MethodHandle methodHandle, Object functionDescriptor, Object arena) { - return Linker.nativeLinker().upcallStub(methodHandle, (FunctionDescriptor) functionDescriptor, (Arena) arena); - } - - @SuppressWarnings("restricted") - public static Object reinterpret(Object memorySegment, long newSize) { - return ((MemorySegment) memorySegment).reinterpret(newSize); - } -} diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/foreign/ForeignSupportImpl.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/foreign/ForeignSupportImpl.java deleted file mode 100644 index 8d8ecc5f2572..000000000000 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/foreign/ForeignSupportImpl.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.api.foreign; - -import com.oracle.truffle.api.impl.Accessor.ForeignSupport; - -import java.lang.invoke.MethodHandle; - -/** - * Encapsulates access to restricted {@code java.lang.foreign} functions. The motivation for this is - * to pass native access from implementation modules like NFI Panama to the Truffle API module. The - * embedder needs to enable native access only for Truffle API, which then re-exports the restricted - * functions to known friendly modules. We cannot use {@code java.lang.foreign} types in method - * signatures because Truffle API still supports JDK 17. - */ -final class ForeignSupportImpl extends ForeignSupport { - - /** - * Loads a library with the given name (if not already loaded) and creates a symbol lookup for - * symbols in that library. - * - * @throws IllegalStateException if {@code arena.scope().isAlive() == false} - * @throws WrongThreadException if {@code arena} is a confined arena, and this method is called - * from a thread {@code T}, other than the arena's owner thread - * @throws IllegalArgumentException if {@code name} does not identify a valid library - * @throws IllegalCallerException if Truffle module {@code org.graalvm.truffle} does not have - * native access enabled - */ - @Override - public Object libraryLookup(String libraryName, Object arena) { - return ForeignUtil.libraryLookup(libraryName, arena); - } - - /** - * Creates a method handle that is used to call a foreign function with {@code symbolName} and - * {@code functionDescriptor} signature. - * - * @throws java.util.NoSuchElementException if no symbol address can be found for - * {@code symbolName} - * @throws IllegalArgumentException if {@code functionDescriptor} is not supported - * @throws IllegalCallerException if Truffle module {@code org.graalvm.truffle} does not have - * native access enabled - */ - @Override - public MethodHandle downcallHandle(String symbolName, Object functionDescriptor) { - return ForeignUtil.downcallHandle(symbolName, functionDescriptor); - } - - /** - * Creates a method handle that is used to call a foreign function with - * {@code functionDescriptor} signature. - * - * @throws IllegalArgumentException if {@code functionDescriptor} is not supported - * @throws IllegalCallerException if Truffle module {@code org.graalvm.truffle} does not have - * native access enabled - */ - @Override - public MethodHandle downcallHandle(Object functionDescriptor) { - return ForeignUtil.downcallHandle(functionDescriptor); - } - - /** - * Creates an upcall stub which can be passed to other foreign functions as a function pointer, - * associated with the given arena. Calling such a function pointer from foreign code will - * result in the execution of the provided method handle. - * - * @throws IllegalArgumentException if {@code functionDescriptor} is not supported. If the type - * of {@code methodHandle} is incompatible with the type {@code functionDescriptor}. - * If it is determined that the target method handle can throw an exception. - * @throws IllegalStateException if {@code arena.scope().isAlive() == false} - * @throws WrongThreadException if {@code arena} is a confined arena, and this method is called - * from a thread {@code T}, other than the arena's owner thread - * @throws IllegalCallerException if Truffle module {@code org.graalvm.truffle} does not have - * native access enabled - */ - @Override - public Object upcallStub(MethodHandle methodHandle, Object functionDescriptor, Object arena) { - return ForeignUtil.upcallStub(methodHandle, functionDescriptor, arena); - } - - /** - * Returns a new memory segment that has the same address and scope as this segment, but with - * the provided size. - * - * @throws IllegalArgumentException if {@code newSize < 0} - * @throws UnsupportedOperationException if this segment is not a {@linkplain #isNative() - * native} segment - * @throws IllegalCallerException if Truffle module {@code org.graalvm.truffle} does not have - * native access enabled - */ - @Override - public Object reinterpret(Object memorySegment, long newSize) { - return ForeignUtil.reinterpret(memorySegment, newSize); - } -} diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/foreign/ForeignUtil.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/foreign/ForeignUtil.java deleted file mode 100644 index 2020a1ea3223..000000000000 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/foreign/ForeignUtil.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.api.foreign; - -import java.lang.invoke.MethodHandle; - -/** - * Support for foreign function linking. The implementation resides in the - * {@code com.oracle.truffle.api.jdk22} project and is added as an overlay into the multi-version - * JAR. - */ -final class ForeignUtil { - - private ForeignUtil() { - } - - @SuppressWarnings("unused") - public static Object libraryLookup(String libraryName, Object arena) { - throw unsupported(); - } - - @SuppressWarnings("unused") - public static MethodHandle downcallHandle(String symbolName, Object functionDescriptor) { - throw unsupported(); - } - - @SuppressWarnings("unused") - public static MethodHandle downcallHandle(Object functionDescriptor) { - throw unsupported(); - } - - @SuppressWarnings("unused") - public static Object upcallStub(MethodHandle methodHandle, Object functionDescriptor, Object arena) { - throw unsupported(); - } - - @SuppressWarnings("unused") - public static Object reinterpret(Object memorySegment, long newSize) { - throw unsupported(); - } - - private static RuntimeException unsupported() { - throw new UnsupportedOperationException("Foreign access is not supported on JDK < 22."); - } -} diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java index 28ef6a380a3e..a63c307feada 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java @@ -45,7 +45,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles.Lookup; import java.lang.reflect.Constructor; import java.lang.reflect.Type; @@ -1111,24 +1110,6 @@ protected IOSupport() { public abstract TruffleProcessBuilder createProcessBuilder(Object polylgotLanguageContext, FileSystem fileSystem, List command); } - public abstract static class ForeignSupport extends Support { - static final String IMPL_CLASS_NAME = "com.oracle.truffle.api.foreign.ForeignSupportImpl"; - - protected ForeignSupport() { - super(IMPL_CLASS_NAME); - } - - public abstract Object libraryLookup(String libraryName, Object arena); - - public abstract MethodHandle downcallHandle(String symbolName, Object functionDescriptor); - - public abstract MethodHandle downcallHandle(Object functionDescriptor); - - public abstract Object upcallStub(MethodHandle methodHandle, Object functionDescriptor, Object arena); - - public abstract Object reinterpret(Object memorySegment, long newSize); - } - public abstract static class SomSupport extends Support { static final String IMPL_CLASS_NAME = "com.oracle.truffle.api.staticobject.SomAccessor"; @@ -1416,7 +1397,6 @@ private static class Constants { private static final Accessor.RuntimeSupport RUNTIME; private static final Accessor.LanguageProviderSupport LANGUAGE_PROVIDER; private static final Accessor.InstrumentProviderSupport INSTRUMENT_PROVIDER; - private static final Accessor.ForeignSupport FOREIGN; private static final DynamicObjectSupport DYNAMIC_OBJECT; static { @@ -1435,7 +1415,6 @@ private static class Constants { RUNTIME = getTVMCI().createRuntimeSupport(RuntimeSupport.PERMISSION); LANGUAGE_PROVIDER = loadSupport(LanguageProviderSupport.IMPL_CLASS_NAME); INSTRUMENT_PROVIDER = loadSupport(InstrumentProviderSupport.IMPL_CLASS_NAME); - FOREIGN = loadSupport(ForeignSupport.IMPL_CLASS_NAME); DYNAMIC_OBJECT = loadSupport(DynamicObjectSupport.IMPL_CLASS_NAME); } @@ -1481,8 +1460,7 @@ protected Accessor() { "com.oracle.truffle.polyglot.enterprise.EnterpriseEngineAccessor".equals(thisClassName) || "com.oracle.truffle.polyglot.enterprise.test.EnterpriseDispatchTestAccessor".equals(thisClassName) || "com.oracle.truffle.api.staticobject.SomAccessor".equals(thisClassName) || - "com.oracle.truffle.api.strings.TStringAccessor".equals(thisClassName) || - "com.oracle.truffle.nfi.backend.panama.NFIPanamaAccessor".equals(thisClassName)) { + "com.oracle.truffle.api.strings.TStringAccessor".equals(thisClassName)) { // OK, classes allowed to use accessors } else { throw new IllegalStateException(thisClassName); @@ -1541,10 +1519,6 @@ public final InstrumentProviderSupport instrumentProviderSupport() { return Constants.INSTRUMENT_PROVIDER; } - public final ForeignSupport foreignSupport() { - return Constants.FOREIGN; - } - public final DynamicObjectSupport dynamicObjectSupport() { return Constants.DYNAMIC_OBJECT; } diff --git a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/ErrorContext.java b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/ErrorContext.java index 1c3de1dfa4cc..30dcc6876bbf 100644 --- a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/ErrorContext.java +++ b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/ErrorContext.java @@ -41,6 +41,7 @@ package com.oracle.truffle.nfi.backend.panama; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; @@ -75,18 +76,18 @@ public void setNativeErrno(int nativeErrno) { this.nativeErrno = nativeErrno; } - @SuppressWarnings({"preview"}) + @SuppressWarnings({"preview", "restricted"}) MemorySegment lookupErrnoLocation() { - FunctionDescriptor desc = FunctionDescriptor.of(ValueLayout.JAVA_LONG); try { - MethodHandle handle = NFIPanamaAccessor.FOREIGN.downcallHandle(ERRNO_LOCATION, desc); - MemorySegment errnoAddress; + Linker linker = Linker.nativeLinker(); + FunctionDescriptor desc = FunctionDescriptor.of(ValueLayout.JAVA_LONG); + MemorySegment sym = linker.defaultLookup().find(ERRNO_LOCATION).orElseThrow(); + MethodHandle handle = linker.downcallHandle(desc); try { - errnoAddress = MemorySegment.ofAddress((long) handle.invokeExact()); + return MemorySegment.ofAddress((long) handle.invokeExact(sym)).reinterpret(4); } catch (Throwable e) { throw new RuntimeException(e); } - return (MemorySegment) NFIPanamaAccessor.FOREIGN.reinterpret(errnoAddress, 4); } catch (IllegalCallerException ic) { throw NFIError.illegalNativeAccess(null); } diff --git a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/NFIError.java b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/NFIError.java index 66749d1313ed..672254ebdafc 100644 --- a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/NFIError.java +++ b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/NFIError.java @@ -40,8 +40,8 @@ */ package com.oracle.truffle.nfi.backend.panama; +import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.exception.AbstractTruffleException; -import com.oracle.truffle.api.impl.Accessor.ForeignSupport; import com.oracle.truffle.api.nodes.EncapsulatingNodeReference; import com.oracle.truffle.api.nodes.Node; @@ -65,7 +65,7 @@ private static Node resolveLocation(Node node) { } static NFIError illegalNativeAccess(Node location) { - Module truffleModule = ForeignSupport.class.getModule(); + Module truffleModule = Truffle.class.getModule(); String targetModule; String error; if (truffleModule.isNamed()) { diff --git a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/NFIPanamaAccessor.java b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/NFIPanamaAccessor.java deleted file mode 100644 index 26c78ad13890..000000000000 --- a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/NFIPanamaAccessor.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.nfi.backend.panama; - -import com.oracle.truffle.api.impl.Accessor; - -final class NFIPanamaAccessor extends Accessor { - - private static final NFIPanamaAccessor ACCESSOR = new NFIPanamaAccessor(); - static final ForeignSupport FOREIGN = ACCESSOR.foreignSupport(); - - private NFIPanamaAccessor() { - } -} diff --git a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaNFIBackend.java b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaNFIBackend.java index 17579fd67dc4..e09f39561253 100644 --- a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaNFIBackend.java +++ b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaNFIBackend.java @@ -110,11 +110,11 @@ protected LoadLibraryNode(PanamaNFILanguage language, String name) { } @TruffleBoundary - @SuppressWarnings({"preview"}) + @SuppressWarnings({"preview", "restricted"}) private SymbolLookup doLoad() { PanamaNFIContext ctx = PanamaNFIContext.get(this); try { - return (SymbolLookup) NFIPanamaAccessor.FOREIGN.libraryLookup(name, ctx.getContextArena()); + return SymbolLookup.libraryLookup(name, ctx.getContextArena()); } catch (IllegalArgumentException ex) { throw new NFIError("Library lookup returned null. Library likely does not exist on the provided location.", this); } catch (IllegalCallerException ic) { diff --git a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaSignature.java b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaSignature.java index a5e06d6fd8d0..95ec9b04c853 100644 --- a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaSignature.java +++ b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaSignature.java @@ -70,6 +70,7 @@ import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; import java.lang.foreign.MemorySegment; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; @@ -146,13 +147,13 @@ MethodType getUpcallMethodType() { } @TruffleBoundary - @SuppressWarnings({"preview"}) + @SuppressWarnings({"preview", "restricted"}) MemorySegment bind(MethodHandle cachedHandle, Object receiver, Node location) { MethodHandle bound = cachedHandle.bindTo(receiver); @SuppressWarnings("preview") Arena arena = PanamaNFIContext.get(null).getContextArena(); try { - return (MemorySegment) NFIPanamaAccessor.FOREIGN.upcallStub(bound, functionDescriptor, arena); + return Linker.nativeLinker().upcallStub(bound, functionDescriptor, arena); } catch (IllegalCallerException ic) { throw NFIError.illegalNativeAccess(location); } @@ -319,8 +320,8 @@ public static CachedSignatureInfo prepareSignatureInfo(PanamaType retType, ArgsS static MethodHandle createDowncallHandle(@SuppressWarnings("preview") FunctionDescriptor descriptor, Node location) { int parameterCount = descriptor.argumentLayouts().size(); try { - @SuppressWarnings({"preview"}) - MethodHandle handle = NFIPanamaAccessor.FOREIGN.downcallHandle(descriptor).asSpreader(Object[].class, parameterCount).asType( + @SuppressWarnings({"preview", "restricted"}) + MethodHandle handle = Linker.nativeLinker().downcallHandle(descriptor).asSpreader(Object[].class, parameterCount).asType( MethodType.methodType(Object.class, new Class[]{MemorySegment.class, Object[].class})); return handle; } catch (IllegalCallerException ic) { From 10a434ddb6d678a6ae859b56c4d9c2613f85efb9 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 19 Sep 2024 16:11:44 +0200 Subject: [PATCH 004/105] [GR-57817] Removed workarounds from labsjdk-24+13-jvmci-b01 update. --- sulong/mx.sulong/mx_sulong_unittest.py | 9 ++++---- .../tests/util/ProcessHarnessManager.java | 7 +++++-- truffle/mx.truffle/mx_truffle.py | 21 ++++++++++++------- vm/tests/all/agentscript/agent-dumparray.test | 4 ++-- vm/tests/all/agentscript/agent-dumpheap.test | 6 +++--- .../agentscript/agent-embedding-symlinks.test | 2 +- vm/tests/all/agentscript/agent-embedding.test | 14 ++++++------- vm/tests/all/agentscript/agent-lli.test | 2 +- vm/tests/all/agentscript/agent-python.test | 4 ++-- vm/tests/all/agentscript/agent-r.test | 8 +++---- vm/tests/all/agentscript/agent-ruby-dump.test | 6 +++--- vm/tests/all/agentscript/agent-ruby.test | 2 +- 12 files changed, 48 insertions(+), 37 deletions(-) diff --git a/sulong/mx.sulong/mx_sulong_unittest.py b/sulong/mx.sulong/mx_sulong_unittest.py index 99391cd7940a..0693cf5ec43a 100644 --- a/sulong/mx.sulong/mx_sulong_unittest.py +++ b/sulong/mx.sulong/mx_sulong_unittest.py @@ -93,10 +93,11 @@ def apply(self, config, overrideSulongConfig=None): vmArgs += [f'-Dsulongtest.path.{d.name}={d.get_output()}' for d in _get_test_distributions(cfg.nativeTestDistFrom)] vmArgs += [f'-Dsulongtest.configRoot={cfg.configRoot}'] vmArgs += [f'-Dsulongtest.config={cfg.name}'] - if mx.get_jdk().javaCompliance > '21': - # Ignore illegal native access until is GR-57817 fixed. - vmArgs += ['--illegal-native-access=allow'] - + if '-p' in vmArgs or '--module-path' in vmArgs: + native_access_target_module = 'org.graalvm.truffle' + else: + native_access_target_module = 'ALL-UNNAMED' + vmArgs += [f'--enable-native-access={native_access_target_module}'] if mx.get_opts().use_llvm_standalone is not None: vmArgs += [f'-Dsulongtest.testAOTImage={mx_sulong.get_lli_path()}'] else: diff --git a/sulong/tests/com.oracle.truffle.llvm.tests/src/com/oracle/truffle/llvm/tests/util/ProcessHarnessManager.java b/sulong/tests/com.oracle.truffle.llvm.tests/src/com/oracle/truffle/llvm/tests/util/ProcessHarnessManager.java index 922ea0dce431..22a122e6a600 100644 --- a/sulong/tests/com.oracle.truffle.llvm.tests/src/com/oracle/truffle/llvm/tests/util/ProcessHarnessManager.java +++ b/sulong/tests/com.oracle.truffle.llvm.tests/src/com/oracle/truffle/llvm/tests/util/ProcessHarnessManager.java @@ -259,8 +259,11 @@ private ProcessHarnessInstance startInstance() throws IOException { } Collections.addAll(commandArgs, "-Xss56m", "-Xms4g", "-Xmx4g", "-esa", "-ea", "-Djava.awt.headless=true", "-cp", classpath, "-p", modulepath, "--add-modules", "org.graalvm.polyglot"); - if (Runtime.version().feature() > 21) { - commandArgs.add("--illegal-native-access=allow"); + + if (ModuleLayer.boot().findModule("org.graalvm.truffle").isPresent()) { + commandArgs.add("--enable-native-access=org.graalvm.truffle"); + } else { + commandArgs.add("--enable-native-access=ALL-UNNAMED"); } copyProperty(commandArgs, "polyglot.engine.WarnInterpreterOnly"); diff --git a/truffle/mx.truffle/mx_truffle.py b/truffle/mx.truffle/mx_truffle.py index 479303156f06..963c73b73515 100644 --- a/truffle/mx.truffle/mx_truffle.py +++ b/truffle/mx.truffle/mx_truffle.py @@ -228,7 +228,11 @@ def apply(self, config): # Disable VirtualThread warning vmArgs = vmArgs + ['-Dpolyglot.engine.WarnVirtualThreadSupport=false'] # Enable native access to Truffle, truffle delegates native access to languages - vmArgs = vmArgs + ['--enable-native-access=org.graalvm.truffle'] + if '-p' in vmArgs or '--module-path' in vmArgs: + native_access_target_module = 'org.graalvm.truffle' + else: + native_access_target_module = 'ALL-UNNAMED' + vmArgs = vmArgs + [f'--enable-native-access={native_access_target_module}'] return (vmArgs, mainClass, mainClassArgs) @@ -367,12 +371,10 @@ def _sl_command(jdk, vm_args, sl_args, use_optimized_runtime=True, use_enterpris else: main_class = ["--module", "org.graalvm.sl_launcher/com.oracle.truffle.sl.launcher.SLMain"] - if use_optimized_runtime and jdk.javaCompliance > '21': - if force_cp: - vm_args += ["--enable-native-access=ALL-UNNAMED"] - else: - # revisit once GR-57817 is fixed - vm_args += ["--enable-native-access=org.graalvm.truffle.runtime"] + if force_cp: + vm_args += ["--enable-native-access=ALL-UNNAMED"] + else: + vm_args += ["--enable-native-access=org.graalvm.truffle"] return [jdk.java] + jdk.processArgs(vm_args + mx.get_runtime_jvm_args(names=dist_names, force_cp=force_cp) + main_class + sl_args) @@ -407,6 +409,10 @@ def _native_image_sl(jdk, vm_args, target_dir, use_optimized_runtime=True, use_e if hosted_assertions: native_image_args += ["-J-ea", "-J-esa"] + # Even when Truffle is on the classpath, it is loaded as a named module due to + # the ForceOnModulePath option in its native-image.properties + native_image_args += ["--enable-native-access=org.graalvm.truffle"] + native_image_args += mx.get_runtime_jvm_args(names=dist_names, force_cp=force_cp) if force_cp: native_image_args += ["com.oracle.truffle.sl.launcher.SLMain"] @@ -818,6 +824,7 @@ def truffle_native_unit_tests_gate(use_optimized_runtime=True, quick_build=False '-H:+AddAllCharsets', '--add-exports=org.graalvm.polyglot/org.graalvm.polyglot.impl=ALL-UNNAMED', '--add-exports=org.graalvm.truffle/com.oracle.truffle.api.impl.asm=ALL-UNNAMED', + '--enable-native-access=org.graalvm.truffle', ] run_args = run_truffle_runtime_args + [ mx_subst.path_substitutions.substitute('-Dnative.test.path='), diff --git a/vm/tests/all/agentscript/agent-dumparray.test b/vm/tests/all/agentscript/agent-dumparray.test index e39668035237..0462c4326ae3 100644 --- a/vm/tests/all/agentscript/agent-dumparray.test +++ b/vm/tests/all/agentscript/agent-dumparray.test @@ -27,7 +27,7 @@ >[??] rm -rf ${TMP_DIR}/array.hprof* >[7?] js --insight=sieveArrayInsight.js --heap.dump=${TMP_DIR}/array.hprof sieveArray.js # a JavaScript heap has been generated ->[0] java --enable-native-access=org.graalvm.truffle.runtime -cp $CP HeapQuery ${TMP_DIR}/array.hprof -e 'heap.forEachObject((arr) => print(arr.length), "java.lang.Object[]");' +>[0] java --enable-native-access=org.graalvm.truffle -cp $CP HeapQuery ${TMP_DIR}/array.hprof -e 'heap.forEachObject((arr) => print(arr.length), "java.lang.Object[]");' 50000 ->[0] java --enable-native-access=org.graalvm.truffle.runtime -cp $CP HeapQuery ${TMP_DIR}/array.hprof -e 'var max = 0; heap.forEachObject((arr) => { for (let i = 0; i < arr.length; i++) { let p = arr[i].value; if (p > max) max = p; } }, "java.lang.Object[]"); print("Maximal number is " + max);' +>[0] java --enable-native-access=org.graalvm.truffle -cp $CP HeapQuery ${TMP_DIR}/array.hprof -e 'var max = 0; heap.forEachObject((arr) => { for (let i = 0; i < arr.length; i++) { let p = arr[i].value; if (p > max) max = p; } }, "java.lang.Object[]"); print("Maximal number is " + max);' Maximal number is 611953 diff --git a/vm/tests/all/agentscript/agent-dumpheap.test b/vm/tests/all/agentscript/agent-dumpheap.test index 77c3544f1c2c..923c9c6d0207 100644 --- a/vm/tests/all/agentscript/agent-dumpheap.test +++ b/vm/tests/all/agentscript/agent-dumpheap.test @@ -27,9 +27,9 @@ >[??] rm -rf ${TMP_DIR}/sample.hprof* >[7?] js --insight=agent-dump.js --heap.dump=${TMP_DIR}/sample.hprof agent-fib.js # a JavaScript heap has been generated ->[0] java --enable-native-access=org.graalvm.truffle.runtime -cp $CP HeapQuery ${TMP_DIR}/sample.hprof -e 'heap.forEachClass((c) => c.name.startsWith("frame:") && print(c.name))' +>[0] java --enable-native-access=org.graalvm.truffle -cp $CP HeapQuery ${TMP_DIR}/sample.hprof -e 'heap.forEachClass((c) => c.name.startsWith("frame:") && print(c.name))' frame:minusTwo ->[0] java --enable-native-access=org.graalvm.truffle.runtime -cp $CP HeapQuery ${TMP_DIR}/sample.hprof -e 'let arr = []; heap.forEachObject((frame) => { for (let p in frame) { arr.push(p); } }, "frame:minusTwo"); arr.sort(); print(arr);' +>[0] java --enable-native-access=org.graalvm.truffle -cp $CP HeapQuery ${TMP_DIR}/sample.hprof -e 'let arr = []; heap.forEachObject((frame) => { for (let p in frame) { arr.push(p); } }, "frame:minusTwo"); arr.sort(); print(arr);' ["n", "this"] ->[0] java --enable-native-access=org.graalvm.truffle.runtime -cp $CP HeapQuery ${TMP_DIR}/sample.hprof -e 'heap.forEachObject((frame) => print(frame.n.value), "frame:minusTwo");' +>[0] java --enable-native-access=org.graalvm.truffle -cp $CP HeapQuery ${TMP_DIR}/sample.hprof -e 'heap.forEachObject((frame) => print(frame.n.value), "frame:minusTwo");' 2 diff --git a/vm/tests/all/agentscript/agent-embedding-symlinks.test b/vm/tests/all/agentscript/agent-embedding-symlinks.test index 95d8b82f494c..88fd86832e5b 100644 --- a/vm/tests/all/agentscript/agent-embedding-symlinks.test +++ b/vm/tests/all/agentscript/agent-embedding-symlinks.test @@ -22,7 +22,7 @@ # questions. # >[0] javac EmbeddingSymlinks*.java -d ${TMP_DIR} ->[0] java --enable-native-access=org.graalvm.truffle.runtime -ea -cp ${TMP_DIR} EmbeddingSymlinks ${TMP_DIR} +>[0] java --enable-native-access=org.graalvm.truffle -ea -cp ${TMP_DIR} EmbeddingSymlinks ${TMP_DIR} loaded source named (?:fooMain\.js from truffle:[0-9a-f]+/fooMain\.js|foo from file:.*/baz\.mjs) loaded source named (?:fooMain\.js from truffle:[0-9a-f]+/fooMain\.js|foo from file:.*/baz\.mjs) computed add at foo from file:.*/baz\.mjs with value 42 diff --git a/vm/tests/all/agentscript/agent-embedding.test b/vm/tests/all/agentscript/agent-embedding.test index 2272f13b1d74..902796470fd7 100644 --- a/vm/tests/all/agentscript/agent-embedding.test +++ b/vm/tests/all/agentscript/agent-embedding.test @@ -22,11 +22,11 @@ # questions. # >[0] javac Embedding*.java -d ${TMP_DIR} ->[0] java --enable-native-access=org.graalvm.truffle.runtime -ea -cp .:${TMP_DIR} Embedding +>[0] java --enable-native-access=org.graalvm.truffle -ea -cp .:${TMP_DIR} Embedding Everything is OK! ->[0] java --enable-native-access=org.graalvm.truffle.runtime -ea -cp ${TMP_DIR} EmbeddingDoubled +>[0] java --enable-native-access=org.graalvm.truffle -ea -cp ${TMP_DIR} EmbeddingDoubled Everything is OK! ->[0] java --enable-native-access=org.graalvm.truffle.runtime -ea -cp .:${TMP_DIR} EmbeddingMoreContexts 2 +>[0] java --enable-native-access=org.graalvm.truffle -ea -cp .:${TMP_DIR} EmbeddingMoreContexts 2 calling fib with 11 result is 89 calling fib with 12 @@ -46,7 +46,7 @@ OK 2 times! # ################################################################## # Register instrument using deprecated -Dtruffle.class.path.append # ################################################################## ->[1] java --enable-native-access=org.graalvm.truffle.runtime -ea -Dtruffle.class.path.append=${TMP_DIR}/instrument.jar -cp ${TMP_DIR} EmbeddingRegisterSymbols primitives +>[1] java --enable-native-access=org.graalvm.truffle -ea -Dtruffle.class.path.append=${TMP_DIR}/instrument.jar -cp ${TMP_DIR} EmbeddingRegisterSymbols primitives \[engine\] The internal option -Dtruffle\.class\.path\.append option is deprecated.* Exception in thread "main" Stop: 0 @@ -61,7 +61,7 @@ Exception in thread "main" Stop: 0 .*at.*org.graalvm.polyglot.Value.execute.* .*at.*EmbeddingRegisterSymbols.exportAndTest.* .*at.*EmbeddingRegisterSymbols.main.* ->[1] java --enable-native-access=org.graalvm.truffle.runtime -ea -Dtruffle.class.path.append=${TMP_DIR}/instrument.jar -cp ${TMP_DIR} EmbeddingRegisterSymbols object +>[1] java --enable-native-access=org.graalvm.truffle -ea -Dtruffle.class.path.append=${TMP_DIR}/instrument.jar -cp ${TMP_DIR} EmbeddingRegisterSymbols object \[engine\] The internal option -Dtruffle\.class\.path\.append option is deprecated.* Exception in thread "main" Stop: 0 @@ -79,7 +79,7 @@ Exception in thread "main" Stop: 0 # ################################################################## # Register instrument using module-path # ################################################################## ->[1] java --enable-native-access=org.graalvm.truffle.runtime -ea --module-path ${TMP_DIR}/instrument.jar:${GRAALVM_HOME}/tools/insight -cp ${TMP_DIR} EmbeddingRegisterSymbols primitives +>[1] java --enable-native-access=org.graalvm.truffle -ea --module-path ${TMP_DIR}/instrument.jar:${GRAALVM_HOME}/tools/insight -cp ${TMP_DIR} EmbeddingRegisterSymbols primitives Exception in thread "main" Stop: 0 .*at.*js.*insight.js.* @@ -93,7 +93,7 @@ Exception in thread "main" Stop: 0 .*at.*org.graalvm.polyglot.Value.execute.* .*at.*EmbeddingRegisterSymbols.exportAndTest.* .*at.*EmbeddingRegisterSymbols.main.* ->[1] java --enable-native-access=org.graalvm.truffle.runtime -ea --module-path ${TMP_DIR}/instrument.jar:${GRAALVM_HOME}/tools/insight -cp ${TMP_DIR} EmbeddingRegisterSymbols object +>[1] java --enable-native-access=org.graalvm.truffle -ea --module-path ${TMP_DIR}/instrument.jar:${GRAALVM_HOME}/tools/insight -cp ${TMP_DIR} EmbeddingRegisterSymbols object Exception in thread "main" Stop: 0 .*at.*js.*insight.js.* diff --git a/vm/tests/all/agentscript/agent-lli.test b/vm/tests/all/agentscript/agent-lli.test index af40197c8854..cda52b88218f 100644 --- a/vm/tests/all/agentscript/agent-lli.test +++ b/vm/tests/all/agentscript/agent-lli.test @@ -23,7 +23,7 @@ # >[0?] export TOOLCHAIN_PATH=`lli --print-toolchain-path` >[0?] ${TOOLCHAIN_PATH}/clang agent-sieve.c -g -O0 -lm -o ${TMP_DIR}/sieve ->[1] lli --vm.-enable-native-access=org.graalvm.truffle.runtime,ALL-UNNAMED --polyglot --insight=agent-limit.js --experimental-options ${TMP_DIR}/sieve +>[1] lli --vm.-enable-native-access=org.graalvm.truffle --polyglot --insight=agent-limit.js --experimental-options ${TMP_DIR}/sieve found new prime number (|2) found new prime number (|3) found new prime number (|5) diff --git a/vm/tests/all/agentscript/agent-python.test b/vm/tests/all/agentscript/agent-python.test index a3b4cd3ba272..597173b1ed44 100644 --- a/vm/tests/all/agentscript/agent-python.test +++ b/vm/tests/all/agentscript/agent-python.test @@ -23,12 +23,12 @@ # > cat > ${TMP_DIR}/test.py < print('Ahoj') -> graalpy --vm.-enable-native-access=org.graalvm.truffle.runtime --insight=agent-python.py --experimental-options ${TMP_DIR}/test.py +> graalpy --vm.-enable-native-access=org.graalvm.truffle --insight=agent-python.py --experimental-options ${TMP_DIR}/test.py Python: Insight version 1.2 is launching Python: Hooks are ready! Python: observed loading of test.py Ahoj -> js --vm.-enable-native-access=org.graalvm.truffle.runtime --polyglot --insight=agent-python.py --experimental-options agent-fib.js +> js --vm.-enable-native-access=org.graalvm.truffle --polyglot --insight=agent-python.py --experimental-options agent-fib.js Python: Insight version 1.2 is launching Python: Hooks are ready! Python: observed loading of agent-fib.js diff --git a/vm/tests/all/agentscript/agent-r.test b/vm/tests/all/agentscript/agent-r.test index 798e42d6d95c..3a8ced3bbb10 100644 --- a/vm/tests/all/agentscript/agent-r.test +++ b/vm/tests/all/agentscript/agent-r.test @@ -53,7 +53,7 @@ Ahoj 2 calls to cat 2 calls to stdout =================== -> Rscript --vm.-enable-native-access=org.graalvm.truffle.runtime,ALL-UNNAMED --polyglot --insight=agent-histogram.js ${TMP_DIR}/fib.R +> Rscript --vm.-enable-native-access=org.graalvm.truffle --polyglot --insight=agent-histogram.js ${TMP_DIR}/fib.R 8 ==== Histogram ==== 15 calls to fib @@ -63,18 +63,18 @@ Ahoj =================== > cat > ${TMP_DIR}/test.js < print('hi js!') -> polyglot --vm.-enable-native-access=org.graalvm.truffle.runtime,ALL-UNNAMED --jvm --agentscript=agent-r.R --experimental-options ${TMP_DIR}/test.js +> polyglot --vm.-enable-native-access=org.graalvm.truffle --jvm --agentscript=agent-r.R --experimental-options ${TMP_DIR}/test.js Warning.*agentscript.*deprecated.*insight.* R: Initializing GraalVM Insight script R: Hooks are ready! R: observed loading of.*test.js hi js! -> polyglot --vm.-enable-native-access=org.graalvm.truffle.runtime,ALL-UNNAMED --jvm --insight=agent-r.R ${TMP_DIR}/test.js +> polyglot --vm.-enable-native-access=org.graalvm.truffle --jvm --insight=agent-r.R ${TMP_DIR}/test.js R: Initializing GraalVM Insight script R: Hooks are ready! R: observed loading of.*test.js hi js! -> polyglot --vm.-enable-native-access=org.graalvm.truffle.runtime,ALL-UNNAMED --insight=agent-r.R ${TMP_DIR}/test.js +> polyglot --vm.-enable-native-access=org.graalvm.truffle --insight=agent-r.R ${TMP_DIR}/test.js R: Initializing GraalVM Insight script R: Hooks are ready! R: observed loading of.*test.js diff --git a/vm/tests/all/agentscript/agent-ruby-dump.test b/vm/tests/all/agentscript/agent-ruby-dump.test index 07ccf28586f7..60360f119194 100644 --- a/vm/tests/all/agentscript/agent-ruby-dump.test +++ b/vm/tests/all/agentscript/agent-ruby-dump.test @@ -25,12 +25,12 @@ >[0] javac -cp $CP HeapQuery.java #> export TMP_DIR=/tmp > rm -rf /tmp/ruby*hprof* -> truffleruby --vm.-enable-native-access=org.graalvm.truffle.runtime,ALL-UNNAMED --polyglot --heap.dump=$TMP_DIR/ruby.hprof --insight=agent-ruby-dump.js hello-world.rb +> truffleruby --vm.-enable-native-access=org.graalvm.truffle --polyglot --heap.dump=$TMP_DIR/ruby.hprof --insight=agent-ruby-dump.js hello-world.rb dumping state of Ruby memory when executing Welcome#welcome Hello World! # check one frame was captured ->[0] java --enable-native-access=org.graalvm.truffle.runtime -cp $CP HeapQuery ${TMP_DIR}/ruby.hprof -e 'heap.forEachClass((c) => c.name.startsWith("frame:") && print(c.name))' +>[0] java --enable-native-access=org.graalvm.truffle -cp $CP HeapQuery ${TMP_DIR}/ruby.hprof -e 'heap.forEachClass((c) => c.name.startsWith("frame:") && print(c.name))' frame:Welcome#welcome # check the h and w variable in the frame ->[0] java --enable-native-access=org.graalvm.truffle.runtime -cp $CP HeapQuery ${TMP_DIR}/ruby.hprof -e 'heap.forEachObject((frame) => print(frame.self["@h"].toString() + " " + frame.w.toString() + "!"), "frame:Welcome#welcome")' +>[0] java --enable-native-access=org.graalvm.truffle -cp $CP HeapQuery ${TMP_DIR}/ruby.hprof -e 'heap.forEachObject((frame) => print(frame.self["@h"].toString() + " " + frame.w.toString() + "!"), "frame:Welcome#welcome")' Hello World! diff --git a/vm/tests/all/agentscript/agent-ruby.test b/vm/tests/all/agentscript/agent-ruby.test index b5cc1ef2395a..0fd6df488d68 100644 --- a/vm/tests/all/agentscript/agent-ruby.test +++ b/vm/tests/all/agentscript/agent-ruby.test @@ -28,7 +28,7 @@ Ruby: Insight version 1.2 is launching Ruby: Hooks are ready! Ruby: observed loading of .*test.rb Ahoj -> js --vm.-enable-native-access=org.graalvm.truffle.runtime,ALL-UNNAMED --polyglot --insight=agent-ruby.rb --experimental-options agent-fib.js +> js --vm.-enable-native-access=org.graalvm.truffle --polyglot --insight=agent-ruby.rb --experimental-options agent-fib.js Ruby: Insight version 1.2 is launching Ruby: Hooks are ready! Ruby: observed loading of agent-fib.js From affbc8d96c7cb5359cf39393fb0d5325d2bd439f Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 20 Sep 2024 10:47:58 +0200 Subject: [PATCH 005/105] [GR-57817] Unconditional delegation of enable-native-access policy. --- .../src/com/oracle/truffle/api/TruffleLanguage.java | 9 --------- .../truffle/nfi/backend/libffi/LibFFILanguage.java | 2 +- .../truffle/nfi/backend/panama/PanamaNFILanguage.java | 2 +- .../src/com/oracle/truffle/polyglot/InstrumentCache.java | 1 + .../src/com/oracle/truffle/polyglot/LanguageCache.java | 4 +--- 5 files changed, 4 insertions(+), 14 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java index 9ea2cee0711a..166f768065c2 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java @@ -540,15 +540,6 @@ String[] dependentLanguages() default { * @since 23.1 */ Class[] internalResources() default {}; - - /** - * Indicates whether the language requires native access, as determined by - * {@link Module#isNativeAccessEnabled()}. If {@code true}, Truffle will delegate the - * necessary native access privileges to the language. - * - * @since 24.2 - */ - boolean enableNativeAccess() default false; } /** diff --git a/truffle/src/com.oracle.truffle.nfi.backend.libffi/src/com/oracle/truffle/nfi/backend/libffi/LibFFILanguage.java b/truffle/src/com.oracle.truffle.nfi.backend.libffi/src/com/oracle/truffle/nfi/backend/libffi/LibFFILanguage.java index 08f8c2f0ffc2..556e3fc89df4 100644 --- a/truffle/src/com.oracle.truffle.nfi.backend.libffi/src/com/oracle/truffle/nfi/backend/libffi/LibFFILanguage.java +++ b/truffle/src/com.oracle.truffle.nfi.backend.libffi/src/com/oracle/truffle/nfi/backend/libffi/LibFFILanguage.java @@ -58,7 +58,7 @@ import com.oracle.truffle.nfi.backend.spi.types.NativeSimpleType; @TruffleLanguage.Registration(id = "internal/nfi-native", name = "nfi-native", version = "0.1", characterMimeTypes = LibFFILanguage.MIME_TYPE, internal = true, // - services = NFIBackendFactory.class, contextPolicy = ContextPolicy.SHARED, internalResources = LibNFIResource.class, enableNativeAccess = true) + services = NFIBackendFactory.class, contextPolicy = ContextPolicy.SHARED, internalResources = LibNFIResource.class) public class LibFFILanguage extends TruffleLanguage { public static final String MIME_TYPE = "trufflenfi/native"; diff --git a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaNFILanguage.java b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaNFILanguage.java index 7502e51f08e7..9ad094e402c0 100644 --- a/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaNFILanguage.java +++ b/truffle/src/com.oracle.truffle.nfi.backend.panama/src/com/oracle/truffle/nfi/backend/panama/PanamaNFILanguage.java @@ -56,7 +56,7 @@ import com.oracle.truffle.nfi.backend.spi.NFIBackendFactory; import com.oracle.truffle.nfi.backend.spi.NFIState; -@TruffleLanguage.Registration(id = "internal/nfi-panama", name = "nfi-panama", version = "0.1", characterMimeTypes = PanamaNFILanguage.MIME_TYPE, internal = true, services = NFIBackendFactory.class, contextPolicy = ContextPolicy.SHARED, enableNativeAccess = true) +@TruffleLanguage.Registration(id = "internal/nfi-panama", name = "nfi-panama", version = "0.1", characterMimeTypes = PanamaNFILanguage.MIME_TYPE, internal = true, services = NFIBackendFactory.class, contextPolicy = ContextPolicy.SHARED) public class PanamaNFILanguage extends TruffleLanguage { public static final String MIME_TYPE = "trufflenfi/panama"; diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java index 57041d5f1caf..2ba2e346628e 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java @@ -210,6 +210,7 @@ private static void loadInstrumentImpl(ProviderAdapter providerAdapter, List providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); ModulesSupport.exportTransitivelyTo(providerModule); + ModulesSupport.enableNativeAccess(providerModule); Registration reg = providerClass.getAnnotation(Registration.class); if (reg == null) { emitWarning("Warning Truffle instrument ignored: Provider %s is missing @Registration annotation.", providerClass); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java index f0f282218692..b874f2e1d402 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java @@ -323,14 +323,12 @@ private static void loadLanguageImpl(ProviderAdapter providerAdapter, List providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); ModulesSupport.exportTransitivelyTo(providerModule); + ModulesSupport.enableNativeAccess(providerModule); Registration reg = providerClass.getAnnotation(Registration.class); if (reg == null) { emitWarning("Warning Truffle language ignored: Provider %s is missing @Registration annotation.", providerClass); return; } - if (reg.enableNativeAccess()) { - ModulesSupport.enableNativeAccess(providerModule); - } String className = providerAdapter.getLanguageClassName(); String name = reg.name(); String id = reg.id(); From df41eb29f8491e02fdc190920096c3d300ec8261 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 20 Sep 2024 15:22:37 +0200 Subject: [PATCH 006/105] [GR-57817] Moved virtual thread support. --- .../com/oracle/truffle/api/impl/Accessor.java | 42 ++++++++++ .../src/truffle_attach.c | 4 +- .../truffle/polyglot/ModulesSupport.java | 75 +++++++++++++++++- .../truffle/runtime/ModulesSupport.java | 13 ++-- .../hotspot/HotSpotThreadLocalHandshake.java | 6 +- .../hotspot/HotSpotTruffleRuntime.java | 6 +- .../hotspot/HotSpotTruffleRuntimeAccess.java | 25 ++++-- .../hotspot/HotSpotVirtualThreadHooks.java | 76 ------------------- 8 files changed, 144 insertions(+), 103 deletions(-) delete mode 100644 truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotVirtualThreadHooks.java diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java index a63c307feada..5ae2c23d58ea 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java @@ -1370,6 +1370,48 @@ public abstract static class ModulesAccessor { public abstract Module getTargetModule(); + public abstract JavaLangAccessor getJavaLangAccessor(); + + } + + public abstract static class JavaLangAccessor { + + private static volatile Consumer onMountCallBack; + private static volatile Consumer onUnmountCallBack; + + public final void registerVirtualThreadMountHooks(Consumer onMount, Consumer onUnmount) { + if (onMountCallBack != null) { + throw new IllegalStateException("OnMount callback is already set"); + } + if (onUnmountCallBack != null) { + throw new IllegalStateException("OnUnmount callback is already set"); + } + onMountCallBack = onMount; + onUnmountCallBack = onUnmount; + registerJVMTIHook(); + } + + public abstract Thread currentCarrierThread(); + + private static native void registerJVMTIHook(); + + /** Called from a JVMTI VirtualThreadMount hook. */ + @SuppressWarnings("unused") + private static void mountHook(Thread currentThread) { + if (Thread.currentThread() != currentThread) { + throw CompilerDirectives.shouldNotReachHere("Thread.currentThread() not matching"); + } + onMountCallBack.accept(currentThread); + } + + /** Called from a JVMTI VirtualThreadUnmount hook. */ + @SuppressWarnings("unused") + private static void unmountHook(Thread currentThread) { + if (Thread.currentThread() != currentThread) { + throw CompilerDirectives.shouldNotReachHere("Thread.currentThread() not matching"); + } + onUnmountCallBack.accept(currentThread); + } } public final void transferOSRFrameStaticSlot(FrameWithoutBoxing sourceFrame, FrameWithoutBoxing targetFrame, int slot) { diff --git a/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c b/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c index 1e3ddba4e6cc..f0563839eb5f 100644 --- a/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c +++ b/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c @@ -102,9 +102,7 @@ static void JNICALL unmount_callback(jvmtiEnv *jvmti, ...) { } } -JNIEXPORT void JNICALL Java_com_oracle_truffle_runtime_hotspot_HotSpotVirtualThreadHooks_registerJVMTIHook(JNIEnv *env, jclass clz, - jobject handshakeClass, - jobject threadLocalClass) { +JNIEXPORT void JNICALL Java_com_oracle_truffle_api_impl_Accessor_00024JavaLangAccessor_registerJVMTIHook(JNIEnv *env, jclass clz) { virtualThreadHooksClass = (*env)->NewGlobalRef(env, clz); EXCEPTION_CHECK(env); CHECK_NONZERO(virtualThreadHooksClass); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java index 16f5d36accaa..3babcb7e6476 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java @@ -70,9 +70,13 @@ import com.oracle.truffle.api.InternalResource; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.impl.Accessor; +import com.oracle.truffle.api.impl.Accessor.JavaLangAccessor; +import com.oracle.truffle.api.impl.Accessor.ModulesAccessor; import com.oracle.truffle.api.impl.asm.ClassWriter; +import com.oracle.truffle.api.impl.asm.FieldVisitor; import com.oracle.truffle.api.impl.asm.MethodVisitor; import com.oracle.truffle.api.impl.asm.Opcodes; +import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.module.Modules; @@ -100,7 +104,7 @@ final class ModulesSupport { } } - private static volatile Accessor.ModulesAccessor modulesAccessor; + private static volatile ModulesAccessor modulesAccessor; private ModulesSupport() { } @@ -134,8 +138,8 @@ static void enableNativeAccess(Module clientModule) { } @SuppressWarnings("restricted") - static Accessor.ModulesAccessor getModulesAccessor() { - Accessor.ModulesAccessor result = modulesAccessor; + static ModulesAccessor getModulesAccessor() { + ModulesAccessor result = modulesAccessor; if (result == null) { synchronized (ModulesSupport.class) { result = modulesAccessor; @@ -162,7 +166,7 @@ static Accessor.ModulesAccessor getModulesAccessor() { } Module javaBase = ModuleLayer.boot().findModule("java.base").orElseThrow(); addExports0(javaBase, "jdk.internal.module", result.getTargetModule()); - result.addExports(javaBase, "jdk.internal.access", result.getTargetModule()); + addExports0(javaBase, "jdk.internal.access", result.getTargetModule()); modulesAccessor = result; } } @@ -288,6 +292,11 @@ private enum Edge { private static final class DirectImpl extends Accessor.ModulesAccessor { private final Class baseClass; + /** + * {@code javaLangAccessor} needs to be initialized lazily when the + * {@code jdk.internal.access} package is already open. + */ + private volatile JavaLangAccessor javaLangAccessor; DirectImpl(Class baseClass) { if (!baseClass.getModule().isNamed()) { @@ -342,6 +351,25 @@ public void addEnableNativeAccessToAllUnnamed() { public Module getTargetModule() { return baseClass.getModule(); } + + @Override + public JavaLangAccessor getJavaLangAccessor() { + JavaLangAccessor res = javaLangAccessor; + if (res == null) { + res = new JavaLangAccessor() { + + private final JavaLangAccess javaLang = SharedSecrets.getJavaLangAccess(); + + @Override + public Thread currentCarrierThread() { + return javaLang.currentCarrierThread(); + } + }; + + javaLangAccessor = res; + } + return res; + } } /* @@ -356,7 +384,9 @@ private static final class IsolatedImpl extends Accessor.ModulesAccessor { private final MethodHandle addOpensToAllUnnamed; private final MethodHandle addEnableNativeAccess; private final MethodHandle addEnableNativeAccessToAllUnnamed; + private final MethodHandle currentCarrierThread; private final Module targetModule; + private final JavaLangAccessor javaLangAccessor; IsolatedImpl(Class baseClass) throws ReflectiveOperationException { final String moduleName = "org.graalvm.truffle.generated"; @@ -367,6 +397,17 @@ private static final class IsolatedImpl extends Accessor.ModulesAccessor { ClassWriter cw = new ClassWriter(0); cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, binaryClassName, null, "java/lang/Object", null); + FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "javaLangAccess", "Ljdk/internal/access/JavaLangAccess;", null, null); + fv.visitEnd(); + + MethodVisitor clinit = cw.visitMethod(Opcodes.ACC_STATIC, "", "()V", null, null); + clinit.visitCode(); + clinit.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/internal/access/SharedSecrets", "getJavaLangAccess", "()Ljdk/internal/access/JavaLangAccess;", false); + clinit.visitFieldInsn(Opcodes.PUTSTATIC, binaryClassName, "javaLangAccess", "Ljdk/internal/access/JavaLangAccess;"); + clinit.visitInsn(Opcodes.RETURN); + clinit.visitMaxs(1, 0); + clinit.visitEnd(); + MethodVisitor constructor = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); constructor.visitCode(); constructor.visitVarInsn(Opcodes.ALOAD, 0); @@ -448,6 +489,15 @@ private static final class IsolatedImpl extends Accessor.ModulesAccessor { mv6.visitMaxs(1, 1); mv6.visitEnd(); + MethodVisitor mv7 = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "currentCarrierThread", + "()Ljava/lang/Thread;", null, null); + mv7.visitCode(); + mv7.visitFieldInsn(Opcodes.GETSTATIC, binaryClassName, "javaLangAccess", "Ljdk/internal/access/JavaLangAccess;"); + mv7.visitMethodInsn(Opcodes.INVOKEINTERFACE, "jdk/internal/access/JavaLangAccess", "currentCarrierThread", "()Ljava/lang/Thread;", true); + mv7.visitInsn(Opcodes.ARETURN); + mv7.visitMaxs(1, 0); + mv7.visitEnd(); + cw.visitEnd(); byte[] classBytes = cw.toByteArray(); @@ -516,6 +566,18 @@ public Set findAll() { this.addOpensToAllUnnamed = l.findStatic(generatedClass, "addOpensToAllUnnamed", MethodType.methodType(void.class, Module.class, String.class)); this.addEnableNativeAccess = l.findStatic(generatedClass, "addEnableNativeAccess", MethodType.methodType(void.class, Module.class)); this.addEnableNativeAccessToAllUnnamed = l.findStatic(generatedClass, "addEnableNativeAccessToAllUnnamed", MethodType.methodType(void.class)); + this.currentCarrierThread = l.findStatic(generatedClass, "currentCarrierThread", MethodType.methodType(Thread.class)); + this.javaLangAccessor = new JavaLangAccessor() { + + @Override + public Thread currentCarrierThread() { + try { + return (Thread) currentCarrierThread.invokeExact(); + } catch (Throwable e) { + throw new InternalError(e); + } + } + }; } @Override @@ -576,6 +638,11 @@ public void addEnableNativeAccessToAllUnnamed() { throw new InternalError(e); } } + + @Override + public JavaLangAccessor getJavaLangAccessor() { + return javaLangAccessor; + } } @InternalResource.Id(value = LibTruffleAttachResource.ID, componentId = "engine", optional = true) diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java index 9ec79f537fab..206deb061aff 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java @@ -49,6 +49,7 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleRuntime; import com.oracle.truffle.api.impl.Accessor; +import com.oracle.truffle.api.impl.Accessor.JavaLangAccessor; import com.oracle.truffle.api.impl.Accessor.ModulesAccessor; public final class ModulesSupport { @@ -137,14 +138,6 @@ public static void addOpens(Module base, String p, Module target) { } } - public static void enableNativeAccess(Module module) { - if (module.isNamed()) { - ACCESSOR.addEnableNativeAccess(module); - } else { - ACCESSOR.addEnableNativeAccessToAllUnnamed(); - } - } - public static void exportTruffleRuntimeTo(Class client) { Module truffleModule = ModulesSupport.class.getModule(); Module clientModule = client.getModule(); @@ -159,6 +152,10 @@ public static void exportTruffleRuntimeTo(Class client) { } } + public static JavaLangAccessor getJavaLangAccessor() { + return ACCESSOR.getJavaLangAccessor(); + } + /** * Gets {@code ModulesAccessor} reflectively. *

diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java index ba9a18c3a488..5e2749acacd2 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java @@ -42,15 +42,15 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.impl.Accessor.JavaLangAccessor; import com.oracle.truffle.api.impl.ThreadLocalHandshake; import com.oracle.truffle.api.nodes.Node; -import jdk.internal.access.JavaLangAccess; -import jdk.internal.access.SharedSecrets; +import com.oracle.truffle.runtime.ModulesSupport; final class HotSpotThreadLocalHandshake extends ThreadLocalHandshake { private static final sun.misc.Unsafe UNSAFE = HotSpotTruffleRuntime.UNSAFE; - private static final JavaLangAccess JAVA_LANG_ACCESS = SharedSecrets.getJavaLangAccess(); + private static final JavaLangAccessor JAVA_LANG_ACCESS = ModulesSupport.getJavaLangAccessor(); static final HotSpotThreadLocalHandshake SINGLETON = new HotSpotThreadLocalHandshake(); private static final ThreadLocal STATE = new ThreadLocal<>(); diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java index 0c7b5e975a30..682eb066e42d 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java @@ -54,6 +54,7 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameInstance; import com.oracle.truffle.api.impl.AbstractFastThreadLocal; +import com.oracle.truffle.api.impl.Accessor.JavaLangAccessor; import com.oracle.truffle.api.impl.ThreadLocalHandshake; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.compiler.TruffleCompilable; @@ -63,14 +64,13 @@ import com.oracle.truffle.runtime.BackgroundCompileQueue; import com.oracle.truffle.runtime.CompilationTask; import com.oracle.truffle.runtime.EngineData; +import com.oracle.truffle.runtime.ModulesSupport; import com.oracle.truffle.runtime.OptimizedCallTarget; import com.oracle.truffle.runtime.OptimizedOSRLoopNode; import com.oracle.truffle.runtime.OptimizedTruffleRuntime; import com.oracle.truffle.runtime.TruffleCallBoundary; import com.oracle.truffle.runtime.hotspot.libgraal.LibGraalTruffleCompilationSupport; -import jdk.internal.access.JavaLangAccess; -import jdk.internal.access.SharedSecrets; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.code.stack.StackIntrospection; import jdk.vm.ci.common.JVMCIError; @@ -103,7 +103,7 @@ public final class HotSpotTruffleRuntime extends OptimizedTruffleRuntime { static final int JAVA_SPEC = Runtime.version().feature(); static final sun.misc.Unsafe UNSAFE = getUnsafe(); - private static final JavaLangAccess JAVA_LANG_ACCESS = SharedSecrets.getJavaLangAccess(); + private static final JavaLangAccessor JAVA_LANG_ACCESS = ModulesSupport.getJavaLangAccessor(); private static final long THREAD_EETOP_OFFSET; static { try { diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java index bc071cf2c355..a716c283b744 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java @@ -48,6 +48,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Set; +import java.util.function.Consumer; import org.graalvm.home.Version; @@ -140,11 +141,6 @@ protected static TruffleRuntime createRuntime() { } } - // For SharedSecrets.getJavaLangAccess().currentCarrierThread() - ModulesSupport.addExports(javaBase, "jdk.internal.access", runtimeModule); - // HotSpotVirtualThreadHooks has a native method to register JVMTI hook - ModulesSupport.enableNativeAccess(runtimeModule); - TruffleCompilationSupport compilationSupport; if (LibGraal.isAvailable()) { // try LibGraal @@ -206,11 +202,28 @@ protected static TruffleRuntime createRuntime() { } } HotSpotTruffleRuntime rt = new HotSpotTruffleRuntime(compilationSupport); - HotSpotVirtualThreadHooks.ensureLoaded(); + registerVirtualThreadSupport(); compilationSupport.registerRuntime(rt); return rt; } + private static void registerVirtualThreadSupport() { + // Ensure that HotSpotThreadLocalHandshake and HotSpotFastThreadLocal are loaded before the + // hooks are called + try { + Class.forName(HotSpotThreadLocalHandshake.class.getName(), false, HotSpotTruffleRuntimeAccess.class.getClassLoader()); + Class.forName(HotSpotFastThreadLocal.class.getName(), false, HotSpotTruffleRuntimeAccess.class.getClassLoader()); + } catch (ClassNotFoundException cnf) { + throw new InternalError(cnf); + } + Consumer onMount = (t) -> { + HotSpotFastThreadLocal.mount(); + HotSpotThreadLocalHandshake.setPendingFlagForVirtualThread(); + }; + Consumer onUmount = (t) -> HotSpotFastThreadLocal.unmount(); + ModulesSupport.getJavaLangAccessor().registerVirtualThreadMountHooks(onMount, onUmount); + } + private static RuntimeException throwVersionError(String errorFormat, Object... args) { StringBuilder errorMessage = new StringBuilder("Polyglot version compatibility check failed.\n"); errorMessage.append(String.format(errorFormat, args)); diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotVirtualThreadHooks.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotVirtualThreadHooks.java deleted file mode 100644 index 6c9d417fbf60..000000000000 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotVirtualThreadHooks.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.runtime.hotspot; - -import com.oracle.truffle.api.CompilerDirectives; - -final class HotSpotVirtualThreadHooks { - - static { - // We pass both classes here to ensure they are loaded before the hooks are called - registerJVMTIHook(HotSpotThreadLocalHandshake.class, HotSpotFastThreadLocal.class); - } - - private static native void registerJVMTIHook(Class hotSpotThreadLocalHandshakeClass, Class hotSpotFastThreadLocalClass); - - static void ensureLoaded() { - } - - /** Called from a JVMTI VirtualThreadUnmount hook. */ - @SuppressWarnings("unused") - private static void unmountHook(Thread currentThread) { - if (Thread.currentThread() != currentThread) { - throw CompilerDirectives.shouldNotReachHere("Thread.currentThread() not matching"); - } - HotSpotFastThreadLocal.unmount(); - } - - /** Called from a JVMTI VirtualThreadMount hook. */ - @SuppressWarnings("unused") - private static void mountHook(Thread currentThread) { - if (Thread.currentThread() != currentThread) { - throw CompilerDirectives.shouldNotReachHere("Thread.currentThread() not matching"); - } - HotSpotFastThreadLocal.mount(); - HotSpotThreadLocalHandshake.setPendingFlagForVirtualThread(); - } - -} From 45aa57f82b6bf9a58f5d50ce3f4c6dd2cce2e348 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Tue, 24 Sep 2024 14:08:10 +0200 Subject: [PATCH 007/105] [GR-57817] Possibility to disable enable-native-access delegation. --- .../polyglot/SeparatedClassLoadersTest.java | 1 - .../truffle/polyglot/InstrumentCache.java | 15 ++++-- .../truffle/polyglot/LanguageCache.java | 16 ++++-- .../truffle/polyglot/ModulesSupport.java | 50 ++++++++++++------- .../truffle/runtime/ModulesSupport.java | 3 ++ 5 files changed, 56 insertions(+), 29 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/SeparatedClassLoadersTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/SeparatedClassLoadersTest.java index 745b0aafc1b6..fe34e9aa1db0 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/SeparatedClassLoadersTest.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/SeparatedClassLoadersTest.java @@ -101,7 +101,6 @@ public void sdkAndTruffleAPIInSeparateClassLoaders() throws Exception { Class engineClass = sdkLoader.loadClass(Engine.class.getName()); Object engine = engineClass.getMethod("create").invoke(null); - assertNotNull("Engine has been created", engine); } diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java index 2ba2e346628e..6c362400cc82 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java @@ -66,6 +66,8 @@ import com.oracle.truffle.polyglot.EngineAccessor.StrongClassLoaderSupplier; import org.graalvm.polyglot.SandboxPolicy; +import static com.oracle.truffle.polyglot.LanguageCache.isEnableNativeAccess; + final class InstrumentCache { private static final List nativeImageCache = TruffleOptions.AOT ? new ArrayList<>() : null; private static Map, List> runtimeCaches = new HashMap<>(); @@ -167,6 +169,7 @@ static List doLoad(List suppliers) Set classNamesUsed = new HashSet<>(); ClassLoader truffleClassLoader = InstrumentCache.class.getClassLoader(); boolean usesTruffleClassLoader = false; + boolean enableNativeAccess = isEnableNativeAccess(); Map>> optionalResources = InternalResourceCache.loadOptionalInternalResources(suppliers); for (AbstractClassLoaderSupplier supplier : suppliers) { ClassLoader loader = supplier.get(); @@ -174,9 +177,9 @@ static List doLoad(List suppliers) continue; } usesTruffleClassLoader |= truffleClassLoader == loader; - loadProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadInstrumentImpl(p, list, classNamesUsed, optionalResources)); + loadProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadInstrumentImpl(p, list, classNamesUsed, optionalResources, enableNativeAccess)); if (supplier.supportsLegacyProviders()) { - loadLegacyProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadInstrumentImpl(p, list, classNamesUsed, optionalResources)); + loadLegacyProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadInstrumentImpl(p, list, classNamesUsed, optionalResources, enableNativeAccess)); } } /* @@ -189,7 +192,7 @@ static List doLoad(List suppliers) Module truffleModule = InstrumentCache.class.getModule(); loadProviders(truffleClassLoader).// filter((p) -> p.getProviderClass().getModule().equals(truffleModule)).// - forEach((p) -> loadInstrumentImpl(p, list, classNamesUsed, optionalResources)); + forEach((p) -> loadInstrumentImpl(p, list, classNamesUsed, optionalResources, enableNativeAccess)); } list.sort(Comparator.comparing(InstrumentCache::getId)); return list; @@ -206,11 +209,13 @@ private static Stream loadProviders(ClassLoader loade } private static void loadInstrumentImpl(ProviderAdapter providerAdapter, List list, Set classNamesUsed, - Map>> optionalResources) { + Map>> optionalResources, boolean enableNativeAccess) { Class providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); ModulesSupport.exportTransitivelyTo(providerModule); - ModulesSupport.enableNativeAccess(providerModule); + if (enableNativeAccess) { + ModulesSupport.enableNativeAccess(providerModule); + } Registration reg = providerClass.getAnnotation(Registration.class); if (reg == null) { emitWarning("Warning Truffle instrument ignored: Provider %s is missing @Registration annotation.", providerClass); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java index b874f2e1d402..28abce966407 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java @@ -270,14 +270,15 @@ static Map loadLanguages(List createLanguages(List suppliers) { List caches = new ArrayList<>(); Map>> optionalResources = InternalResourceCache.loadOptionalInternalResources(suppliers); + boolean enableNativeAccess = isEnableNativeAccess(); for (AbstractClassLoaderSupplier supplier : suppliers) { ClassLoader loader = supplier.get(); if (loader == null) { continue; } - loadProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadLanguageImpl(p, caches, optionalResources)); + loadProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadLanguageImpl(p, caches, optionalResources, enableNativeAccess)); if (supplier.supportsLegacyProviders()) { - loadLegacyProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadLanguageImpl(p, caches, optionalResources)); + loadLegacyProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadLanguageImpl(p, caches, optionalResources, enableNativeAccess)); } } @@ -319,11 +320,14 @@ private static boolean hasSameCodeSource(LanguageCache first, LanguageCache seco } @SuppressWarnings("deprecation") - private static void loadLanguageImpl(ProviderAdapter providerAdapter, List into, Map>> optionalResources) { + private static void loadLanguageImpl(ProviderAdapter providerAdapter, List into, Map>> optionalResources, + boolean enableNativeAccess) { Class providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); ModulesSupport.exportTransitivelyTo(providerModule); - ModulesSupport.enableNativeAccess(providerModule); + if (enableNativeAccess) { + ModulesSupport.enableNativeAccess(providerModule); + } Registration reg = providerClass.getAnnotation(Registration.class); if (reg == null) { emitWarning("Warning Truffle language ignored: Provider %s is missing @Registration annotation.", providerClass); @@ -663,6 +667,10 @@ SandboxPolicy getSandboxPolicy() { return sandboxPolicy; } + static boolean isEnableNativeAccess() { + return !Boolean.FALSE.toString().equals(System.getProperty("truffle.DelegateEnableNativeAccess")); + } + private static void emitWarning(String message, Object... args) { PrintStream out = System.err; out.printf(message + "%n", args); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java index 3babcb7e6476..49b1536e2bf5 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java @@ -103,8 +103,9 @@ final class ModulesSupport { ADD_ENABLE_NATIVE_ACCESS_TO_ALL_UNNAMED = null; } } + private static final Object INVALID_MODULES_ACCESSOR = new Object(); - private static volatile ModulesAccessor modulesAccessor; + private static volatile Object modulesAccessor; private ModulesSupport() { } @@ -129,17 +130,25 @@ static void exportTransitivelyTo(Module clientModule) { static void enableNativeAccess(Module clientModule) { forEach(clientModule, EnumSet.of(Edge.READS), (m) -> true, (m) -> { - if (m.isNamed()) { - getModulesAccessor().addEnableNativeAccess(m); - } else { - getModulesAccessor().addEnableNativeAccessToAllUnnamed(); + ModulesAccessor accessor = getModulesAccessor(); + /* + * The accessor is null if libtruffleattach cannot be loaded, such as when Truffle with + * a fallback runtime is loaded by multiple class loaders. In this case, we do not + * delegate enable-native-access and let the JDK emit native access warnings. + */ + if (accessor != null) { + if (m.isNamed()) { + getModulesAccessor().addEnableNativeAccess(m); + } else { + getModulesAccessor().addEnableNativeAccessToAllUnnamed(); + } } }); } @SuppressWarnings("restricted") static ModulesAccessor getModulesAccessor() { - ModulesAccessor result = modulesAccessor; + Object result = modulesAccessor; if (result == null) { synchronized (ModulesSupport.class) { result = modulesAccessor; @@ -154,24 +163,27 @@ static ModulesAccessor getModulesAccessor() { throw new InternalError(ioe); } } - System.load(attachLibPath); - if (Accessor.ModulesAccessor.class.getModule().isNamed()) { - result = new DirectImpl(Accessor.ModulesAccessor.class); - } else { - try { - result = new IsolatedImpl(Accessor.ModulesAccessor.class); - } catch (ReflectiveOperationException e) { - throw new InternalError(e); + try { + System.load(attachLibPath); + ModulesAccessor accessor; + if (ModulesAccessor.class.getModule().isNamed()) { + accessor = new DirectImpl(Accessor.ModulesAccessor.class); + } else { + accessor = new IsolatedImpl(Accessor.ModulesAccessor.class); } + Module javaBase = ModuleLayer.boot().findModule("java.base").orElseThrow(); + addExports0(javaBase, "jdk.internal.module", accessor.getTargetModule()); + addExports0(javaBase, "jdk.internal.access", accessor.getTargetModule()); + modulesAccessor = result = accessor; + } catch (UnsatisfiedLinkError failedToLoad) { + modulesAccessor = result = INVALID_MODULES_ACCESSOR; + } catch (ReflectiveOperationException re) { + throw new InternalError(re); } - Module javaBase = ModuleLayer.boot().findModule("java.base").orElseThrow(); - addExports0(javaBase, "jdk.internal.module", result.getTargetModule()); - addExports0(javaBase, "jdk.internal.access", result.getTargetModule()); - modulesAccessor = result; } } } - return result; + return result == INVALID_MODULES_ACCESSOR ? null : (ModulesAccessor) result; } private static native void addExports0(Module m1, String pn, Module m2); diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java index 206deb061aff..c4b03a454aff 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java @@ -94,6 +94,9 @@ private static String exportJVMCI(Module module, Set seenModules) { // jvmci not found -> fallback to default runtime return "JVMCI is not enabled for this JVM. Enable JVMCI using -XX:+EnableJVMCI."; } + if (ACCESSOR == null) { + return "The Truffle attach library is not available or cannot be loaded."; + } addExportsRecursive(layer, jvmciModule, module, seenModules); return null; } From fe8d0a2def79f640d65862a65190218eab952f90 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Wed, 25 Sep 2024 12:26:47 +0200 Subject: [PATCH 008/105] [GR-57817] Resolved review comments. --- .../src/truffle_attach.c | 2 +- .../truffle/polyglot/EngineAccessor.java | 6 +- .../truffle/polyglot/InstrumentCache.java | 6 +- .../polyglot/InternalResourceCache.java | 9 +-- .../{ModulesSupport.java => JDKSupport.java} | 81 +++++++++++-------- .../truffle/polyglot/LanguageCache.java | 6 +- .../oracle/truffle/polyglot/PolyglotImpl.java | 2 +- .../truffle/runtime/ModulesSupport.java | 2 +- .../hotspot/HotSpotTruffleRuntimeAccess.java | 17 ++-- 9 files changed, 75 insertions(+), 56 deletions(-) rename truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/{ModulesSupport.java => JDKSupport.java} (93%) diff --git a/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c b/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c index f0563839eb5f..ce99d7913c78 100644 --- a/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c +++ b/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c @@ -47,7 +47,7 @@ // Library entry points -JNIEXPORT void JNICALL Java_com_oracle_truffle_polyglot_ModulesSupport_addExports0(JNIEnv *env, jclass clz, jobject m1, jobject pn, jobject m2) { +JNIEXPORT void JNICALL Java_com_oracle_truffle_polyglot_JDKSupport_addExports0(JNIEnv *env, jclass clz, jobject m1, jobject pn, jobject m2) { jclass modulesClass = (*env)->FindClass(env, "jdk/internal/module/Modules"); EXCEPTION_CHECK(env); jmethodID addExports = (*env)->GetStaticMethodID(env, modulesClass, "addExports", "(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V"); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java index 64c0756fdc32..81f6f675cfcb 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/EngineAccessor.java @@ -340,14 +340,14 @@ public Iterable loadServices(Class type) { // 2) Lookup implementations of a module aware interface for (T service : ServiceLoader.load(type, loader)) { if (loaderSupplier.accepts(service.getClass())) { - ModulesSupport.exportTransitivelyTo(service.getClass().getModule()); + JDKSupport.exportTransitivelyTo(service.getClass().getModule()); found.putIfAbsent(service.getClass(), service); } } // 3) Lookup implementations of a legacy interface // GR-46293 Remove the deprecated service interface lookup. if (legacyInterface != null && loaderSupplier.supportsLegacyProviders()) { - ModulesSupport.exportToUnnamedModuleOf(loader); + JDKSupport.exportToUnnamedModuleOf(loader); for (T service : ServiceLoader.load(legacyInterface, loader)) { if (loaderSupplier.accepts(service.getClass())) { found.putIfAbsent(service.getClass(), service); @@ -2198,7 +2198,7 @@ public long getEngineId(Object polyglotEngine) { @Override public ModulesAccessor getModulesAccessor() { - return ModulesSupport.getModulesAccessor(); + return JDKSupport.getModulesAccessor(); } } diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java index 6c362400cc82..bc18de9f85e1 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java @@ -200,7 +200,7 @@ static List doLoad(List suppliers) @SuppressWarnings("deprecation") private static Stream loadLegacyProviders(ClassLoader loader) { - ModulesSupport.exportToUnnamedModuleOf(loader); + JDKSupport.exportToUnnamedModuleOf(loader); return StreamSupport.stream(ServiceLoader.load(TruffleInstrument.Provider.class, loader).spliterator(), false).map(LegacyProvider::new); } @@ -212,9 +212,9 @@ private static void loadInstrumentImpl(ProviderAdapter providerAdapter, List>> optionalResources, boolean enableNativeAccess) { Class providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); - ModulesSupport.exportTransitivelyTo(providerModule); + JDKSupport.exportTransitivelyTo(providerModule); if (enableNativeAccess) { - ModulesSupport.enableNativeAccess(providerModule); + JDKSupport.enableNativeAccess(providerModule); } Registration reg = providerClass.getAnnotation(Registration.class); if (reg == null) { diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java index a5e3598d6fe4..bfbbe94dcea5 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InternalResourceCache.java @@ -177,10 +177,9 @@ void clearCache() { /** * Installs truffleattach library. Used reflectively by - * {@code com.oracle.truffle.runtime.ModulesSupport}. The {@code ModulesSupport} is initialized - * before the Truffle runtime is created and accessor classes are initialized. For this reason, - * it cannot use {@code EngineSupport} to call this method, nor can this method use any - * accessor. + * {@code com.oracle.truffle.runtime.JDKSupport}. The {@code JDKSupport} is initialized before + * the Truffle runtime is created and accessor classes are initialized. For this reason, it + * cannot use {@code EngineSupport} to call this method, nor can this method use any accessor. */ static Path installRuntimeResource(InternalResource resource) throws IOException { InternalResourceCache cache = createRuntimeResourceCache(resource); @@ -411,7 +410,7 @@ private static Map>> collect continue; } StreamSupport.stream(ServiceLoader.load(InternalResourceProvider.class, loader).spliterator(), false).filter((p) -> supplier.accepts(p.getClass())).forEach((p) -> { - ModulesSupport.exportTransitivelyTo(p.getClass().getModule()); + JDKSupport.exportTransitivelyTo(p.getClass().getModule()); String componentId = EngineAccessor.LANGUAGE_PROVIDER.getInternalResourceComponentId(p); String resourceId = EngineAccessor.LANGUAGE_PROVIDER.getInternalResourceId(p); var componentOptionalResources = cache.computeIfAbsent(componentId, (k) -> new HashMap<>()); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java similarity index 93% rename from truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java rename to truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java index 49b1536e2bf5..5c3ea3a0298c 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/ModulesSupport.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java @@ -80,7 +80,7 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.module.Modules; -final class ModulesSupport { +final class JDKSupport { /* * We use reflective access to addEnableAccess and addEnableNativeAccessToAllUnnamed to make @@ -107,7 +107,7 @@ final class ModulesSupport { private static volatile Object modulesAccessor; - private ModulesSupport() { + private JDKSupport() { } static void exportTo(Module clientModule) { @@ -125,7 +125,7 @@ static void exportTransitivelyTo(Module clientModule) { return; } Module truffleModule = Truffle.class.getModule(); - forEach(clientModule, EnumSet.of(Edge.READS, Edge.USES), (m) -> m != truffleModule && m.canRead(truffleModule), ModulesSupport::exportFromTo); + forEach(clientModule, EnumSet.of(Edge.READS, Edge.USES), (m) -> m != truffleModule && m.canRead(truffleModule), JDKSupport::exportFromTo); } static void enableNativeAccess(Module clientModule) { @@ -150,7 +150,7 @@ static void enableNativeAccess(Module clientModule) { static ModulesAccessor getModulesAccessor() { Object result = modulesAccessor; if (result == null) { - synchronized (ModulesSupport.class) { + synchronized (JDKSupport.class) { result = modulesAccessor; if (result == null) { String attachLibPath = System.getProperty("truffle.attach.library"); @@ -304,11 +304,6 @@ private enum Edge { private static final class DirectImpl extends Accessor.ModulesAccessor { private final Class baseClass; - /** - * {@code javaLangAccessor} needs to be initialized lazily when the - * {@code jdk.internal.access} package is already open. - */ - private volatile JavaLangAccessor javaLangAccessor; DirectImpl(Class baseClass) { if (!baseClass.getModule().isNamed()) { @@ -366,21 +361,21 @@ public Module getTargetModule() { @Override public JavaLangAccessor getJavaLangAccessor() { - JavaLangAccessor res = javaLangAccessor; - if (res == null) { - res = new JavaLangAccessor() { + return JavaLangAccessorImpl.INSTANCE; + } - private final JavaLangAccess javaLang = SharedSecrets.getJavaLangAccess(); + private static final class JavaLangAccessorImpl extends JavaLangAccessor { - @Override - public Thread currentCarrierThread() { - return javaLang.currentCarrierThread(); - } - }; + private static final JavaLangAccess JAVA_LANG_ACCESS = SharedSecrets.getJavaLangAccess(); + static final JavaLangAccessor INSTANCE = new JavaLangAccessorImpl(); - javaLangAccessor = res; + private JavaLangAccessorImpl() { + } + + @Override + public Thread currentCarrierThread() { + return JAVA_LANG_ACCESS.currentCarrierThread(); } - return res; } } @@ -398,7 +393,6 @@ private static final class IsolatedImpl extends Accessor.ModulesAccessor { private final MethodHandle addEnableNativeAccessToAllUnnamed; private final MethodHandle currentCarrierThread; private final Module targetModule; - private final JavaLangAccessor javaLangAccessor; IsolatedImpl(Class baseClass) throws ReflectiveOperationException { final String moduleName = "org.graalvm.truffle.generated"; @@ -579,17 +573,6 @@ public Set findAll() { this.addEnableNativeAccess = l.findStatic(generatedClass, "addEnableNativeAccess", MethodType.methodType(void.class, Module.class)); this.addEnableNativeAccessToAllUnnamed = l.findStatic(generatedClass, "addEnableNativeAccessToAllUnnamed", MethodType.methodType(void.class)); this.currentCarrierThread = l.findStatic(generatedClass, "currentCarrierThread", MethodType.methodType(Thread.class)); - this.javaLangAccessor = new JavaLangAccessor() { - - @Override - public Thread currentCarrierThread() { - try { - return (Thread) currentCarrierThread.invokeExact(); - } catch (Throwable e) { - throw new InternalError(e); - } - } - }; } @Override @@ -653,7 +636,39 @@ public void addEnableNativeAccessToAllUnnamed() { @Override public JavaLangAccessor getJavaLangAccessor() { - return javaLangAccessor; + return JavaLangAccessorImpl.INSTANCE; + } + + private static final class JavaLangAccessorImpl extends JavaLangAccessor { + + /* + * For performance reasons, it is necessary for CURRENT_CARRIER_THREAD to be declared as + * static final. + */ + private static final MethodHandle CURRENT_CARRIER_THREAD; + static { + if (JDKSupport.modulesAccessor == null) { + throw new IllegalStateException("JavaLangAccessorImpl initialized before JDKSupport.modulesAccessor was set"); + } else if (!(JDKSupport.modulesAccessor instanceof IsolatedImpl)) { + throw new IllegalStateException("JDKSupport.modulesAccessor initialized with wrong type " + JDKSupport.modulesAccessor.getClass()); + } else { + CURRENT_CARRIER_THREAD = ((IsolatedImpl) JDKSupport.modulesAccessor).currentCarrierThread; + } + } + + private static final JavaLangAccessor INSTANCE = new JavaLangAccessorImpl(); + + private JavaLangAccessorImpl() { + } + + @Override + public Thread currentCarrierThread() { + try { + return (Thread) CURRENT_CARRIER_THREAD.invokeExact(); + } catch (Throwable e) { + throw new InternalError(e); + } + } } } diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java index 28abce966407..2a44d3f5304c 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java @@ -307,7 +307,7 @@ private static synchronized Map createLanguages(List loadLegacyProviders(ClassLoader loader) { - ModulesSupport.exportToUnnamedModuleOf(loader); + JDKSupport.exportToUnnamedModuleOf(loader); return StreamSupport.stream(ServiceLoader.load(TruffleLanguage.Provider.class, loader).spliterator(), false).map(LegacyProvider::new); } @@ -324,9 +324,9 @@ private static void loadLanguageImpl(ProviderAdapter providerAdapter, List providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); - ModulesSupport.exportTransitivelyTo(providerModule); + JDKSupport.exportTransitivelyTo(providerModule); if (enableNativeAccess) { - ModulesSupport.enableNativeAccess(providerModule); + JDKSupport.enableNativeAccess(providerModule); } Registration reg = providerClass.getAnnotation(Registration.class); if (reg == null) { diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java index fcf6155c50e6..6700ec964796 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotImpl.java @@ -487,7 +487,7 @@ public Class loadLanguageClass(String className) { Class clazz = loader.loadClass(className); if (supplier.accepts(clazz)) { Module clazzModule = clazz.getModule(); - ModulesSupport.exportTransitivelyTo(clazzModule); + JDKSupport.exportTransitivelyTo(clazzModule); return clazz; } } catch (ClassNotFoundException e) { diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java index c4b03a454aff..933fc9dcf8b4 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java @@ -168,7 +168,7 @@ public static JavaLangAccessor getJavaLangAccessor() { */ private static ModulesAccessor getModulesAccessor() { try { - Class resourceCacheClass = Class.forName("com.oracle.truffle.polyglot.ModulesSupport", false, ModulesSupport.class.getClassLoader()); + Class resourceCacheClass = Class.forName("com.oracle.truffle.polyglot.JDKSupport", false, ModulesSupport.class.getClassLoader()); Method getModulesAccessor = resourceCacheClass.getDeclaredMethod("getModulesAccessor"); getModulesAccessor.setAccessible(true); return (ModulesAccessor) getModulesAccessor.invoke(null); diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java index a716c283b744..35b82df6cea7 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java @@ -45,6 +45,8 @@ import static com.oracle.truffle.runtime.OptimizedTruffleRuntime.MIN_JDK_VERSION; import static com.oracle.truffle.runtime.OptimizedTruffleRuntime.NEXT_VERSION_UPDATE; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Set; @@ -208,13 +210,16 @@ protected static TruffleRuntime createRuntime() { } private static void registerVirtualThreadSupport() { - // Ensure that HotSpotThreadLocalHandshake and HotSpotFastThreadLocal are loaded before the - // hooks are called + /* + * Ensure that HotSpotThreadLocalHandshake and HotSpotFastThreadLocal are loaded before the + * hooks are called + */ try { - Class.forName(HotSpotThreadLocalHandshake.class.getName(), false, HotSpotTruffleRuntimeAccess.class.getClassLoader()); - Class.forName(HotSpotFastThreadLocal.class.getName(), false, HotSpotTruffleRuntimeAccess.class.getClassLoader()); - } catch (ClassNotFoundException cnf) { - throw new InternalError(cnf); + Lookup lkp = MethodHandles.lookup(); + lkp.accessClass(HotSpotThreadLocalHandshake.class); + lkp.accessClass(HotSpotFastThreadLocal.class); + } catch (IllegalAccessException ia) { + throw new AssertionError(ia); } Consumer onMount = (t) -> { HotSpotFastThreadLocal.mount(); From 3418cad1f445d447b545cac7c99e9f09bde782ed Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Mon, 30 Sep 2024 12:43:02 +0200 Subject: [PATCH 009/105] [GR-57817] Fixed gates. --- sdk/mx.sdk/mx_sdk_vm_impl.py | 2 +- sulong/mx.sulong/mx_sulong_unittest.py | 4 +++- .../truffle/llvm/tests/util/ProcessHarnessManager.java | 6 +++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index ecbde93749c1..9538f5227f9a 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -3088,7 +3088,7 @@ def pre_extracted_lib_description(comp): 'name': 'truffle.attach.library', 'layout_dict': { 'source_type': 'extracted-dependency', - 'dependency': 'truffle:TRUFFLE_RUNTIME', + 'dependency': 'truffle:TRUFFLE_API', 'exclude': [], 'path': 'META-INF/resources/engine/libtruffleattach///bin/', }, diff --git a/sulong/mx.sulong/mx_sulong_unittest.py b/sulong/mx.sulong/mx_sulong_unittest.py index 0693cf5ec43a..fa658b764010 100644 --- a/sulong/mx.sulong/mx_sulong_unittest.py +++ b/sulong/mx.sulong/mx_sulong_unittest.py @@ -94,7 +94,9 @@ def apply(self, config, overrideSulongConfig=None): vmArgs += [f'-Dsulongtest.configRoot={cfg.configRoot}'] vmArgs += [f'-Dsulongtest.config={cfg.name}'] if '-p' in vmArgs or '--module-path' in vmArgs: - native_access_target_module = 'org.graalvm.truffle' + # ALL-UNNAMED for native methods in + # com.oracle.truffle.llvm.tests.pipe.CaptureNativeOutput + native_access_target_module = 'org.graalvm.truffle,ALL-UNNAMED' else: native_access_target_module = 'ALL-UNNAMED' vmArgs += [f'--enable-native-access={native_access_target_module}'] diff --git a/sulong/tests/com.oracle.truffle.llvm.tests/src/com/oracle/truffle/llvm/tests/util/ProcessHarnessManager.java b/sulong/tests/com.oracle.truffle.llvm.tests/src/com/oracle/truffle/llvm/tests/util/ProcessHarnessManager.java index 22a122e6a600..b5532c8c3e1a 100644 --- a/sulong/tests/com.oracle.truffle.llvm.tests/src/com/oracle/truffle/llvm/tests/util/ProcessHarnessManager.java +++ b/sulong/tests/com.oracle.truffle.llvm.tests/src/com/oracle/truffle/llvm/tests/util/ProcessHarnessManager.java @@ -261,7 +261,11 @@ private ProcessHarnessInstance startInstance() throws IOException { "-cp", classpath, "-p", modulepath, "--add-modules", "org.graalvm.polyglot"); if (ModuleLayer.boot().findModule("org.graalvm.truffle").isPresent()) { - commandArgs.add("--enable-native-access=org.graalvm.truffle"); + /* + * ALL-UNNAMED for native methods in + * com.oracle.truffle.llvm.tests.pipe.CaptureNativeOutput + */ + commandArgs.add("--enable-native-access=org.graalvm.truffle,ALL-UNNAMED"); } else { commandArgs.add("--enable-native-access=ALL-UNNAMED"); } From 165fd5e93d0e93458e267c83f3b9697db727a5fb Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Mon, 30 Sep 2024 19:46:49 +0200 Subject: [PATCH 010/105] [GR-57817] Eagerly initializing safepoint mechanism classes. --- .../oracle/truffle/polyglot/JDKSupport.java | 6 ++++ .../hotspot/HotSpotThreadLocalHandshake.java | 2 +- .../hotspot/HotSpotTruffleRuntime.java | 28 +++++++++---------- .../hotspot/HotSpotTruffleRuntimeAccess.java | 4 +-- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java index 5c3ea3a0298c..3da831bff753 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java @@ -659,6 +659,12 @@ private static final class JavaLangAccessorImpl extends JavaLangAccessor { private static final JavaLangAccessor INSTANCE = new JavaLangAccessorImpl(); private JavaLangAccessorImpl() { + /* + * Ensure the CURRENT_CARRIER_THREAD method handle is initialized by invoking it. + * This prevents the interpreter from triggering class initialization during the + * HotSpotThreadLocalHandshake's operation. + */ + currentCarrierThread(); } @Override diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java index 5e2749acacd2..1326b9a6b547 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java @@ -55,7 +55,7 @@ final class HotSpotThreadLocalHandshake extends ThreadLocalHandshake { static final HotSpotThreadLocalHandshake SINGLETON = new HotSpotThreadLocalHandshake(); private static final ThreadLocal STATE = new ThreadLocal<>(); - private static final int PENDING_OFFSET = HotSpotTruffleRuntime.getRuntime().getJVMCIReservedLongOffset0(); + private static final int PENDING_OFFSET = HotSpotTruffleRuntime.readJVMCIReservedLongOffset0(); private static final long THREAD_EETOP_OFFSET; private static final long THREAD_CARRIER_THREAD_OFFSET; static { diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java index 682eb066e42d..b17a4a234cb5 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java @@ -172,7 +172,6 @@ private Lazy lazy() { private volatile Throwable truffleCompilerInitializationException; private final HotSpotVMConfigAccess vmConfigAccess; - private final int jvmciReservedLongOffset0; public HotSpotTruffleRuntime(TruffleCompilationSupport compilationSupport) { super(compilationSupport, Arrays.asList(HotSpotOptimizedCallTarget.class, InstalledCode.class, HotSpotThreadLocalHandshake.class, HotSpotTruffleRuntime.class)); @@ -180,15 +179,25 @@ public HotSpotTruffleRuntime(TruffleCompilationSupport compilationSupport) { this.vmConfigAccess = new HotSpotVMConfigAccess(HotSpotJVMCIRuntime.runtime().getConfigStore()); + int jvmciReservedReference0Offset = vmConfigAccess.getFieldOffset("JavaThread::_jvmci_reserved_oop0", Integer.class, "oop", -1); + if (jvmciReservedReference0Offset == -1) { + throw CompilerDirectives.shouldNotReachHere("This JDK does not have JavaThread::_jvmci_reserved_oop0"); + } + + installReservedOopMethods(null); + } + + static int readJVMCIReservedLongOffset0() { + HotSpotVMConfigAccess access = new HotSpotVMConfigAccess(HotSpotJVMCIRuntime.runtime().getConfigStore()); int longOffset; try { - longOffset = vmConfigAccess.getFieldOffset("JavaThread::_jvmci_reserved0", Integer.class, "jlong", -1); + longOffset = access.getFieldOffset("JavaThread::_jvmci_reserved0", Integer.class, "jlong", -1); } catch (NoSuchMethodError error) { throw CompilerDirectives.shouldNotReachHere("This JDK does not have JavaThread::_jvmci_reserved0", error); } catch (JVMCIError error) { try { // the type of the jvmci reserved field might still be old. - longOffset = vmConfigAccess.getFieldOffset("JavaThread::_jvmci_reserved0", Integer.class, "intptr_t*", -1); + longOffset = access.getFieldOffset("JavaThread::_jvmci_reserved0", Integer.class, "intptr_t*", -1); } catch (NoSuchMethodError e) { e.initCause(error); throw CompilerDirectives.shouldNotReachHere("This JDK does not have JavaThread::_jvmci_reserved0", e); @@ -197,18 +206,7 @@ public HotSpotTruffleRuntime(TruffleCompilationSupport compilationSupport) { if (longOffset == -1) { throw CompilerDirectives.shouldNotReachHere("This JDK does not have JavaThread::_jvmci_reserved0"); } - this.jvmciReservedLongOffset0 = longOffset; - - int jvmciReservedReference0Offset = vmConfigAccess.getFieldOffset("JavaThread::_jvmci_reserved_oop0", Integer.class, "oop", -1); - if (jvmciReservedReference0Offset == -1) { - throw CompilerDirectives.shouldNotReachHere("This JDK does not have JavaThread::_jvmci_reserved_oop0"); - } - - installReservedOopMethods(null); - } - - public int getJVMCIReservedLongOffset0() { - return jvmciReservedLongOffset0; + return longOffset; } @Override diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java index 35b82df6cea7..9c731c9c5d8a 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java @@ -216,8 +216,8 @@ private static void registerVirtualThreadSupport() { */ try { Lookup lkp = MethodHandles.lookup(); - lkp.accessClass(HotSpotThreadLocalHandshake.class); - lkp.accessClass(HotSpotFastThreadLocal.class); + lkp.ensureInitialized(HotSpotThreadLocalHandshake.class); + lkp.ensureInitialized(HotSpotFastThreadLocal.class); } catch (IllegalAccessException ia) { throw new AssertionError(ia); } From 7de1cf6e264635552c7d12cbd0c2e78f688b8503 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 4 Oct 2024 12:31:48 +0200 Subject: [PATCH 011/105] [GR-57817] Resolved review comments. --- sdk/CHANGELOG.md | 1 + truffle/CHANGELOG.md | 1 + .../truffle/polyglot/InstrumentCache.java | 15 +-- .../oracle/truffle/polyglot/JDKSupport.java | 126 +++++++++++------- .../truffle/polyglot/LanguageCache.java | 16 +-- .../truffle/runtime/ModulesSupport.java | 8 +- .../hotspot/HotSpotFastThreadLocal.java | 2 + .../hotspot/HotSpotThreadLocalHandshake.java | 29 +++- .../hotspot/HotSpotTruffleRuntime.java | 22 --- .../hotspot/HotSpotTruffleRuntimeAccess.java | 14 +- vm/tests/all/agentscript/agent-lli.test | 2 +- vm/tests/all/agentscript/agent-python.test | 4 +- vm/tests/all/agentscript/agent-r.test | 8 +- vm/tests/all/agentscript/agent-ruby-dump.test | 2 +- vm/tests/all/agentscript/agent-ruby.test | 2 +- 15 files changed, 139 insertions(+), 113 deletions(-) diff --git a/sdk/CHANGELOG.md b/sdk/CHANGELOG.md index ac58ec13b715..c38d994154ac 100644 --- a/sdk/CHANGELOG.md +++ b/sdk/CHANGELOG.md @@ -5,6 +5,7 @@ This changelog summarizes major changes between GraalVM SDK versions. The main f ## Version 24.2.0 * GR-54905 When using Truffle NFI with the Panama backend, native access must now be granted to the Truffle module instead of the NFI Panama module. Use the `--enable-native-access=org.graalvm.truffle` Java command line option to enable the native access for the NFI Panama backend. * GR-57681 Added the ability to use `Value#as(byte[].class)` to copy the contents of a guest language byte buffer (`Value#hasBufferElements()`) to a new byte array. The new functionality has precedence over accessing the guest object as array (`Value#hasArrayElements()`) if both ways are available. +* GR-57817 Starting with JDK 24 users now need to pass `--enable-native-access=org.graalvm.truffle` or `--enable-native-access=ALL-UNNAMED` to grant Truffle the ability to compile to optimized native code. If native access is denied by the JDK using `--illegal-native-access=deny` then loading the optimizing runtime will fail and the fallback runtime will be used. ## Version 24.1.0 * GR-51177 Enable random offsets of runtime compiled function entry points for the UNTRUSTED polyglot sandbox policy. diff --git a/truffle/CHANGELOG.md b/truffle/CHANGELOG.md index 174dcaf05554..50ef6cfb3c58 100644 --- a/truffle/CHANGELOG.md +++ b/truffle/CHANGELOG.md @@ -7,6 +7,7 @@ This changelog summarizes major changes between Truffle versions relevant to lan * GR-57164 Added support for reading unaligned ints, shorts and long to `ByteArraySupport`. * GR-57164 `RootNode.translateStackTraceElement()` is now always consulted for polyglot and debugger stack traces. Stack traces now use the source section, the executable name, the name of the declared meta-object to build `StackTraceElement` instances. * GR-57322 Added `TruffleLanguage.Env.getHostLanguage()` returning the host language info. This allows languages to lookup the top scope of the host language using `Env.getScopeInternal(LanguageInfo)`. +* GR-57817 Native access for all languages and tools is now provided by Truffle. ## Version 24.1.0 diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java index bc18de9f85e1..0891ebfec48f 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java @@ -66,8 +66,6 @@ import com.oracle.truffle.polyglot.EngineAccessor.StrongClassLoaderSupplier; import org.graalvm.polyglot.SandboxPolicy; -import static com.oracle.truffle.polyglot.LanguageCache.isEnableNativeAccess; - final class InstrumentCache { private static final List nativeImageCache = TruffleOptions.AOT ? new ArrayList<>() : null; private static Map, List> runtimeCaches = new HashMap<>(); @@ -169,7 +167,6 @@ static List doLoad(List suppliers) Set classNamesUsed = new HashSet<>(); ClassLoader truffleClassLoader = InstrumentCache.class.getClassLoader(); boolean usesTruffleClassLoader = false; - boolean enableNativeAccess = isEnableNativeAccess(); Map>> optionalResources = InternalResourceCache.loadOptionalInternalResources(suppliers); for (AbstractClassLoaderSupplier supplier : suppliers) { ClassLoader loader = supplier.get(); @@ -177,9 +174,9 @@ static List doLoad(List suppliers) continue; } usesTruffleClassLoader |= truffleClassLoader == loader; - loadProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadInstrumentImpl(p, list, classNamesUsed, optionalResources, enableNativeAccess)); + loadProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadInstrumentImpl(p, list, classNamesUsed, optionalResources)); if (supplier.supportsLegacyProviders()) { - loadLegacyProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadInstrumentImpl(p, list, classNamesUsed, optionalResources, enableNativeAccess)); + loadLegacyProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadInstrumentImpl(p, list, classNamesUsed, optionalResources)); } } /* @@ -192,7 +189,7 @@ static List doLoad(List suppliers) Module truffleModule = InstrumentCache.class.getModule(); loadProviders(truffleClassLoader).// filter((p) -> p.getProviderClass().getModule().equals(truffleModule)).// - forEach((p) -> loadInstrumentImpl(p, list, classNamesUsed, optionalResources, enableNativeAccess)); + forEach((p) -> loadInstrumentImpl(p, list, classNamesUsed, optionalResources)); } list.sort(Comparator.comparing(InstrumentCache::getId)); return list; @@ -209,13 +206,11 @@ private static Stream loadProviders(ClassLoader loade } private static void loadInstrumentImpl(ProviderAdapter providerAdapter, List list, Set classNamesUsed, - Map>> optionalResources, boolean enableNativeAccess) { + Map>> optionalResources) { Class providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); JDKSupport.exportTransitivelyTo(providerModule); - if (enableNativeAccess) { - JDKSupport.enableNativeAccess(providerModule); - } + JDKSupport.enableNativeAccess(providerModule); Registration reg = providerClass.getAnnotation(Registration.class); if (reg == null) { emitWarning("Warning Truffle instrument ignored: Provider %s is missing @Registration annotation.", providerClass); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java index 3da831bff753..8528ca0e8264 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java @@ -41,6 +41,7 @@ package com.oracle.truffle.polyglot; import java.io.IOException; +import java.io.PrintStream; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -103,9 +104,78 @@ final class JDKSupport { ADD_ENABLE_NATIVE_ACCESS_TO_ALL_UNNAMED = null; } } - private static final Object INVALID_MODULES_ACCESSOR = new Object(); - private static volatile Object modulesAccessor; + private static final ModulesAccessor MODULES_ACCESSOR = initializeModuleAccessor(); + + @SuppressWarnings("restricted") + private static ModulesAccessor initializeModuleAccessor() { + String attachLibPath = System.getProperty("truffle.attach.library"); + if (attachLibPath == null) { + try { + Path truffleAttachRoot = InternalResourceCache.installRuntimeResource(new LibTruffleAttachResource()); + Path libAttach = truffleAttachRoot.resolve("bin").resolve(System.mapLibraryName("truffleattach")); + attachLibPath = libAttach.toString(); + } catch (IOException ioe) { + warnTruffleAttachLoadFailure("The Truffle API JAR is missing the 'truffleattach' resource, likely due to issues when repackaged into a fat JAR.", ioe); + return null; + } + } + try { + try { + System.load(attachLibPath); + } catch (UnsatisfiedLinkError | IllegalCallerException failedToLoad) { + warnTruffleAttachLoadFailure("Unable to load the TruffleAttach library.", failedToLoad); + return null; + } + ModulesAccessor accessor; + if (ModulesAccessor.class.getModule().isNamed()) { + accessor = new DirectImpl(Accessor.ModulesAccessor.class); + } else { + accessor = new IsolatedImpl(Accessor.ModulesAccessor.class); + } + Module javaBase = ModuleLayer.boot().findModule("java.base").orElseThrow(); + addExports0(javaBase, "jdk.internal.module", accessor.getTargetModule()); + addExports0(javaBase, "jdk.internal.access", accessor.getTargetModule()); + return accessor; + } catch (ReflectiveOperationException re) { + throw new InternalError(re); + } + } + + private static native void addExports0(Module m1, String pn, Module m2); + + private static void warnTruffleAttachLoadFailure(String reason, Throwable t) { + String action = System.getProperty("polyglotimpl.AttachLibraryFailureAction", "warn"); + switch (action) { + case "ignore" -> { + } + case "warn" -> { + PrintStream err = System.err; + err.println(formatErrorMessage(reason)); + } + case "diagnose" -> { + PrintStream err = System.err; + err.println(formatErrorMessage(reason)); + t.printStackTrace(err); + } + case "throw" -> throw new InternalError(formatErrorMessage(reason), t); + default -> throw new IllegalArgumentException("Invalid polyglotimpl.AttachLibraryFailureAction system property value. Supported values are ignore, warn, diagnose, throw"); + } + } + + private static String formatErrorMessage(String reason) { + return String.format( + """ + [engine] WARNING: %s + As a result, the optimized Truffle runtime is unavailable, and Truffle cannot provide native access to languages and tools. + To customize the behavior of this warning, use the 'polyglotimpl.AttachLibraryFailureAction' system property. + Allowed values are: + - ignore: Do not print this warning. + - warn: Print this warning (default value). + - diagnose: Print this warning along with the exception cause. + - throw: Throw an exception instead of printing this warning. + """, reason); + } private JDKSupport() { } @@ -148,46 +218,9 @@ static void enableNativeAccess(Module clientModule) { @SuppressWarnings("restricted") static ModulesAccessor getModulesAccessor() { - Object result = modulesAccessor; - if (result == null) { - synchronized (JDKSupport.class) { - result = modulesAccessor; - if (result == null) { - String attachLibPath = System.getProperty("truffle.attach.library"); - if (attachLibPath == null) { - try { - Path truffleAttachRoot = InternalResourceCache.installRuntimeResource(new LibTruffleAttachResource()); - Path libAttach = truffleAttachRoot.resolve("bin").resolve(System.mapLibraryName("truffleattach")); - attachLibPath = libAttach.toString(); - } catch (IOException ioe) { - throw new InternalError(ioe); - } - } - try { - System.load(attachLibPath); - ModulesAccessor accessor; - if (ModulesAccessor.class.getModule().isNamed()) { - accessor = new DirectImpl(Accessor.ModulesAccessor.class); - } else { - accessor = new IsolatedImpl(Accessor.ModulesAccessor.class); - } - Module javaBase = ModuleLayer.boot().findModule("java.base").orElseThrow(); - addExports0(javaBase, "jdk.internal.module", accessor.getTargetModule()); - addExports0(javaBase, "jdk.internal.access", accessor.getTargetModule()); - modulesAccessor = result = accessor; - } catch (UnsatisfiedLinkError failedToLoad) { - modulesAccessor = result = INVALID_MODULES_ACCESSOR; - } catch (ReflectiveOperationException re) { - throw new InternalError(re); - } - } - } - } - return result == INVALID_MODULES_ACCESSOR ? null : (ModulesAccessor) result; + return MODULES_ACCESSOR; } - private static native void addExports0(Module m1, String pn, Module m2); - private static void forEach(Module rootModule, Set edges, Predicate filter, Consumer action) { ModuleLayer layer = rootModule.getLayer(); Set targetModules = new HashSet<>(); @@ -647,12 +680,12 @@ private static final class JavaLangAccessorImpl extends JavaLangAccessor { */ private static final MethodHandle CURRENT_CARRIER_THREAD; static { - if (JDKSupport.modulesAccessor == null) { - throw new IllegalStateException("JavaLangAccessorImpl initialized before JDKSupport.modulesAccessor was set"); - } else if (!(JDKSupport.modulesAccessor instanceof IsolatedImpl)) { - throw new IllegalStateException("JDKSupport.modulesAccessor initialized with wrong type " + JDKSupport.modulesAccessor.getClass()); + if (JDKSupport.MODULES_ACCESSOR == null) { + throw new IllegalStateException("JavaLangAccessorImpl initialized before JDKSupport."); + } else if (!(JDKSupport.MODULES_ACCESSOR instanceof IsolatedImpl)) { + throw new IllegalStateException("JDKSupport.MODULES_ACCESSOR initialized with wrong type " + JDKSupport.MODULES_ACCESSOR.getClass()); } else { - CURRENT_CARRIER_THREAD = ((IsolatedImpl) JDKSupport.modulesAccessor).currentCarrierThread; + CURRENT_CARRIER_THREAD = ((IsolatedImpl) JDKSupport.MODULES_ACCESSOR).currentCarrierThread; } } @@ -662,7 +695,8 @@ private JavaLangAccessorImpl() { /* * Ensure the CURRENT_CARRIER_THREAD method handle is initialized by invoking it. * This prevents the interpreter from triggering class initialization during the - * HotSpotThreadLocalHandshake's operation. + * virtual thread hooks which must not trigger class loading or suspend the + * VirtualThread. */ currentCarrierThread(); } diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java index 2a44d3f5304c..d3ed9792739b 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java @@ -270,15 +270,14 @@ static Map loadLanguages(List createLanguages(List suppliers) { List caches = new ArrayList<>(); Map>> optionalResources = InternalResourceCache.loadOptionalInternalResources(suppliers); - boolean enableNativeAccess = isEnableNativeAccess(); for (AbstractClassLoaderSupplier supplier : suppliers) { ClassLoader loader = supplier.get(); if (loader == null) { continue; } - loadProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadLanguageImpl(p, caches, optionalResources, enableNativeAccess)); + loadProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadLanguageImpl(p, caches, optionalResources)); if (supplier.supportsLegacyProviders()) { - loadLegacyProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadLanguageImpl(p, caches, optionalResources, enableNativeAccess)); + loadLegacyProviders(loader).filter((p) -> supplier.accepts(p.getProviderClass())).forEach((p) -> loadLanguageImpl(p, caches, optionalResources)); } } @@ -320,14 +319,11 @@ private static boolean hasSameCodeSource(LanguageCache first, LanguageCache seco } @SuppressWarnings("deprecation") - private static void loadLanguageImpl(ProviderAdapter providerAdapter, List into, Map>> optionalResources, - boolean enableNativeAccess) { + private static void loadLanguageImpl(ProviderAdapter providerAdapter, List into, Map>> optionalResources) { Class providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); JDKSupport.exportTransitivelyTo(providerModule); - if (enableNativeAccess) { - JDKSupport.enableNativeAccess(providerModule); - } + JDKSupport.enableNativeAccess(providerModule); Registration reg = providerClass.getAnnotation(Registration.class); if (reg == null) { emitWarning("Warning Truffle language ignored: Provider %s is missing @Registration annotation.", providerClass); @@ -667,10 +663,6 @@ SandboxPolicy getSandboxPolicy() { return sandboxPolicy; } - static boolean isEnableNativeAccess() { - return !Boolean.FALSE.toString().equals(System.getProperty("truffle.DelegateEnableNativeAccess")); - } - private static void emitWarning(String message, Object... args) { PrintStream out = System.err; out.printf(message + "%n", args); diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java index 933fc9dcf8b4..ad4c98c84261 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java @@ -54,7 +54,7 @@ public final class ModulesSupport { - private static final ModulesAccessor ACCESSOR = getModulesAccessor(); + private static final ModulesAccessor ACCESSOR = initializeModulesAccessor(); private ModulesSupport() { } @@ -95,7 +95,8 @@ private static String exportJVMCI(Module module, Set seenModules) { return "JVMCI is not enabled for this JVM. Enable JVMCI using -XX:+EnableJVMCI."; } if (ACCESSOR == null) { - return "The Truffle attach library is not available or cannot be loaded."; + return "The Truffle attach library is not available or cannot be loaded. " + + "This can happen if the Truffle jar files are invalid or if Truffle is loaded multiple times in separate class loaders."; } addExportsRecursive(layer, jvmciModule, module, seenModules); return null; @@ -166,7 +167,8 @@ public static JavaLangAccessor getJavaLangAccessor() { * we cannot use {@link Accessor.EngineSupport#getModulesAccessor()}. *

*/ - private static ModulesAccessor getModulesAccessor() { + private static ModulesAccessor initializeModulesAccessor() { + // TODO: GR-58671 Make Accessor usable before TruffleRuntime is created. try { Class resourceCacheClass = Class.forName("com.oracle.truffle.polyglot.JDKSupport", false, ModulesSupport.class.getClassLoader()); Method getModulesAccessor = resourceCacheClass.getDeclaredMethod("getModulesAccessor"); diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotFastThreadLocal.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotFastThreadLocal.java index 1a9d18b1a53e..e493f92d79a6 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotFastThreadLocal.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotFastThreadLocal.java @@ -137,4 +137,6 @@ static void mount() { RUNTIME.setThreadLocalObject(0, threadLocals); } + static void ensureLoaded() { + } } diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java index 1326b9a6b547..e28415f775b6 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java @@ -46,6 +46,9 @@ import com.oracle.truffle.api.impl.ThreadLocalHandshake; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.runtime.ModulesSupport; +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; final class HotSpotThreadLocalHandshake extends ThreadLocalHandshake { @@ -55,7 +58,7 @@ final class HotSpotThreadLocalHandshake extends ThreadLocalHandshake { static final HotSpotThreadLocalHandshake SINGLETON = new HotSpotThreadLocalHandshake(); private static final ThreadLocal STATE = new ThreadLocal<>(); - private static final int PENDING_OFFSET = HotSpotTruffleRuntime.readJVMCIReservedLongOffset0(); + private static final int PENDING_OFFSET = resolveJVMCIReservedLongOffset0(); private static final long THREAD_EETOP_OFFSET; private static final long THREAD_CARRIER_THREAD_OFFSET; static { @@ -189,4 +192,28 @@ static void setPendingFlagForVirtualThread() { } } + static void initializePendingOffset() { + if (PENDING_OFFSET == -1) { + throw CompilerDirectives.shouldNotReachHere("This JDK does not have JavaThread::_jvmci_reserved0"); + } + } + + private static int resolveJVMCIReservedLongOffset0() { + HotSpotVMConfigAccess access = new HotSpotVMConfigAccess(HotSpotJVMCIRuntime.runtime().getConfigStore()); + int longOffset; + try { + longOffset = access.getFieldOffset("JavaThread::_jvmci_reserved0", Integer.class, "jlong", -1); + } catch (NoSuchMethodError error) { + return -1; + } catch (JVMCIError error) { + try { + // the type of the jvmci reserved field might still be old. + longOffset = access.getFieldOffset("JavaThread::_jvmci_reserved0", Integer.class, "intptr_t*", -1); + } catch (NoSuchMethodError e) { + return -1; + } + } + return longOffset; + } + } diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java index b17a4a234cb5..a7005e6a6308 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java @@ -187,28 +187,6 @@ public HotSpotTruffleRuntime(TruffleCompilationSupport compilationSupport) { installReservedOopMethods(null); } - static int readJVMCIReservedLongOffset0() { - HotSpotVMConfigAccess access = new HotSpotVMConfigAccess(HotSpotJVMCIRuntime.runtime().getConfigStore()); - int longOffset; - try { - longOffset = access.getFieldOffset("JavaThread::_jvmci_reserved0", Integer.class, "jlong", -1); - } catch (NoSuchMethodError error) { - throw CompilerDirectives.shouldNotReachHere("This JDK does not have JavaThread::_jvmci_reserved0", error); - } catch (JVMCIError error) { - try { - // the type of the jvmci reserved field might still be old. - longOffset = access.getFieldOffset("JavaThread::_jvmci_reserved0", Integer.class, "intptr_t*", -1); - } catch (NoSuchMethodError e) { - e.initCause(error); - throw CompilerDirectives.shouldNotReachHere("This JDK does not have JavaThread::_jvmci_reserved0", e); - } - } - if (longOffset == -1) { - throw CompilerDirectives.shouldNotReachHere("This JDK does not have JavaThread::_jvmci_reserved0"); - } - return longOffset; - } - @Override public ThreadLocalHandshake getThreadLocalHandshake() { return HotSpotThreadLocalHandshake.SINGLETON; diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java index 9c731c9c5d8a..0b628ec7b064 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java @@ -45,8 +45,6 @@ import static com.oracle.truffle.runtime.OptimizedTruffleRuntime.MIN_JDK_VERSION; import static com.oracle.truffle.runtime.OptimizedTruffleRuntime.NEXT_VERSION_UPDATE; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Set; @@ -212,15 +210,11 @@ protected static TruffleRuntime createRuntime() { private static void registerVirtualThreadSupport() { /* * Ensure that HotSpotThreadLocalHandshake and HotSpotFastThreadLocal are loaded before the - * hooks are called + * hooks are called. This prevents class initialization during the virtual thread hooks + * which must not trigger class loading or suspend the VirtualThread. */ - try { - Lookup lkp = MethodHandles.lookup(); - lkp.ensureInitialized(HotSpotThreadLocalHandshake.class); - lkp.ensureInitialized(HotSpotFastThreadLocal.class); - } catch (IllegalAccessException ia) { - throw new AssertionError(ia); - } + HotSpotThreadLocalHandshake.initializePendingOffset(); + HotSpotFastThreadLocal.ensureLoaded(); Consumer onMount = (t) -> { HotSpotFastThreadLocal.mount(); HotSpotThreadLocalHandshake.setPendingFlagForVirtualThread(); diff --git a/vm/tests/all/agentscript/agent-lli.test b/vm/tests/all/agentscript/agent-lli.test index cda52b88218f..e400e33c1166 100644 --- a/vm/tests/all/agentscript/agent-lli.test +++ b/vm/tests/all/agentscript/agent-lli.test @@ -23,7 +23,7 @@ # >[0?] export TOOLCHAIN_PATH=`lli --print-toolchain-path` >[0?] ${TOOLCHAIN_PATH}/clang agent-sieve.c -g -O0 -lm -o ${TMP_DIR}/sieve ->[1] lli --vm.-enable-native-access=org.graalvm.truffle --polyglot --insight=agent-limit.js --experimental-options ${TMP_DIR}/sieve +>[1] lli --polyglot --insight=agent-limit.js --experimental-options ${TMP_DIR}/sieve found new prime number (|2) found new prime number (|3) found new prime number (|5) diff --git a/vm/tests/all/agentscript/agent-python.test b/vm/tests/all/agentscript/agent-python.test index 597173b1ed44..d64a7574117c 100644 --- a/vm/tests/all/agentscript/agent-python.test +++ b/vm/tests/all/agentscript/agent-python.test @@ -23,12 +23,12 @@ # > cat > ${TMP_DIR}/test.py < print('Ahoj') -> graalpy --vm.-enable-native-access=org.graalvm.truffle --insight=agent-python.py --experimental-options ${TMP_DIR}/test.py +> graalpy --insight=agent-python.py --experimental-options ${TMP_DIR}/test.py Python: Insight version 1.2 is launching Python: Hooks are ready! Python: observed loading of test.py Ahoj -> js --vm.-enable-native-access=org.graalvm.truffle --polyglot --insight=agent-python.py --experimental-options agent-fib.js +> js --polyglot --insight=agent-python.py --experimental-options agent-fib.js Python: Insight version 1.2 is launching Python: Hooks are ready! Python: observed loading of agent-fib.js diff --git a/vm/tests/all/agentscript/agent-r.test b/vm/tests/all/agentscript/agent-r.test index 3a8ced3bbb10..c1eb4f5cb36d 100644 --- a/vm/tests/all/agentscript/agent-r.test +++ b/vm/tests/all/agentscript/agent-r.test @@ -53,7 +53,7 @@ Ahoj 2 calls to cat 2 calls to stdout =================== -> Rscript --vm.-enable-native-access=org.graalvm.truffle --polyglot --insight=agent-histogram.js ${TMP_DIR}/fib.R +> Rscript --polyglot --insight=agent-histogram.js ${TMP_DIR}/fib.R 8 ==== Histogram ==== 15 calls to fib @@ -63,18 +63,18 @@ Ahoj =================== > cat > ${TMP_DIR}/test.js < print('hi js!') -> polyglot --vm.-enable-native-access=org.graalvm.truffle --jvm --agentscript=agent-r.R --experimental-options ${TMP_DIR}/test.js +> polyglot --jvm --agentscript=agent-r.R --experimental-options ${TMP_DIR}/test.js Warning.*agentscript.*deprecated.*insight.* R: Initializing GraalVM Insight script R: Hooks are ready! R: observed loading of.*test.js hi js! -> polyglot --vm.-enable-native-access=org.graalvm.truffle --jvm --insight=agent-r.R ${TMP_DIR}/test.js +> polyglot --jvm --insight=agent-r.R ${TMP_DIR}/test.js R: Initializing GraalVM Insight script R: Hooks are ready! R: observed loading of.*test.js hi js! -> polyglot --vm.-enable-native-access=org.graalvm.truffle --insight=agent-r.R ${TMP_DIR}/test.js +> polyglot --insight=agent-r.R ${TMP_DIR}/test.js R: Initializing GraalVM Insight script R: Hooks are ready! R: observed loading of.*test.js diff --git a/vm/tests/all/agentscript/agent-ruby-dump.test b/vm/tests/all/agentscript/agent-ruby-dump.test index 60360f119194..2f157fb64851 100644 --- a/vm/tests/all/agentscript/agent-ruby-dump.test +++ b/vm/tests/all/agentscript/agent-ruby-dump.test @@ -25,7 +25,7 @@ >[0] javac -cp $CP HeapQuery.java #> export TMP_DIR=/tmp > rm -rf /tmp/ruby*hprof* -> truffleruby --vm.-enable-native-access=org.graalvm.truffle --polyglot --heap.dump=$TMP_DIR/ruby.hprof --insight=agent-ruby-dump.js hello-world.rb +> truffleruby --polyglot --heap.dump=$TMP_DIR/ruby.hprof --insight=agent-ruby-dump.js hello-world.rb dumping state of Ruby memory when executing Welcome#welcome Hello World! # check one frame was captured diff --git a/vm/tests/all/agentscript/agent-ruby.test b/vm/tests/all/agentscript/agent-ruby.test index 0fd6df488d68..7d7f035b5b68 100644 --- a/vm/tests/all/agentscript/agent-ruby.test +++ b/vm/tests/all/agentscript/agent-ruby.test @@ -28,7 +28,7 @@ Ruby: Insight version 1.2 is launching Ruby: Hooks are ready! Ruby: observed loading of .*test.rb Ahoj -> js --vm.-enable-native-access=org.graalvm.truffle --polyglot --insight=agent-ruby.rb --experimental-options agent-fib.js +> js --polyglot --insight=agent-ruby.rb --experimental-options agent-fib.js Ruby: Insight version 1.2 is launching Ruby: Hooks are ready! Ruby: observed loading of agent-fib.js From c2a2fd6892e251d3909688fa7bc4900ed5b73d21 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Mon, 7 Oct 2024 20:43:28 +0200 Subject: [PATCH 012/105] [GR-57817] Fixed bash launchers. --- sdk/mx.sdk/vm/launcher_template.cmd | 2 +- sdk/mx.sdk/vm/launcher_template.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/mx.sdk/vm/launcher_template.cmd b/sdk/mx.sdk/vm/launcher_template.cmd index fcf38c325f51..a07f2429cbd4 100644 --- a/sdk/mx.sdk/vm/launcher_template.cmd +++ b/sdk/mx.sdk/vm/launcher_template.cmd @@ -51,7 +51,7 @@ for /f "delims=" %%i in ("%relcp:;=!newline!%") do ( ) ) -set "jvm_args=-Dorg.graalvm.launcher.shell=true "-Dorg.graalvm.launcher.executablename=%executablename%"" +set "jvm_args=--enable-native-access=org.graalvm.truffle -Dorg.graalvm.launcher.shell=true "-Dorg.graalvm.launcher.executablename=%executablename%"" set "launcher_args=" :: Check option-holding variables. diff --git a/sdk/mx.sdk/vm/launcher_template.sh b/sdk/mx.sdk/vm/launcher_template.sh index cc5044a342b4..ba3238b4f1cf 100644 --- a/sdk/mx.sdk/vm/launcher_template.sh +++ b/sdk/mx.sdk/vm/launcher_template.sh @@ -42,7 +42,7 @@ for e in "${relative_cp[@]}"; do absolute_cp+=("${location}/${e}") done -jvm_args=("-Dorg.graalvm.launcher.shell=true" "-Dorg.graalvm.launcher.executablename=$0") +jvm_args=("--enable-native-access=org.graalvm.truffle" "-Dorg.graalvm.launcher.shell=true" "-Dorg.graalvm.launcher.executablename=$0") launcher_args=() # Unfortunately, parsing of `--vm.*` arguments has to be done blind: From e9cf7a7de1cc71eaad923b321aa1489075baad8a Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Thu, 10 Oct 2024 12:29:09 +0200 Subject: [PATCH 013/105] Merge multiple subsequent PublishWritesNodes into a single one --- .../nodes/extended/PublishWritesNode.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/PublishWritesNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/PublishWritesNode.java index 82a87d636b79..c3b13c098cb4 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/PublishWritesNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/PublishWritesNode.java @@ -27,6 +27,7 @@ import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_0; import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_0; +import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.nodeinfo.InputType; import jdk.graal.compiler.nodeinfo.NodeInfo; @@ -36,6 +37,8 @@ import jdk.graal.compiler.nodes.memory.MemoryAccess; import jdk.graal.compiler.nodes.memory.MemoryKill; import jdk.graal.compiler.nodes.memory.address.AddressNode; +import jdk.graal.compiler.nodes.spi.Canonicalizable; +import jdk.graal.compiler.nodes.spi.CanonicalizerTool; import jdk.graal.compiler.nodes.spi.LIRLowerable; import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.graal.compiler.nodes.spi.ValueProxy; @@ -66,7 +69,7 @@ * {@link PublishWritesNode}. */ @NodeInfo(cycles = CYCLES_0, size = SIZE_0, allowedUsageTypes = {InputType.Anchor, InputType.Value}) -public class PublishWritesNode extends FixedWithNextNode implements LIRLowerable, ValueProxy, GuardingNode, AnchoringNode { +public class PublishWritesNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, ValueProxy, GuardingNode, AnchoringNode { public static final NodeClass TYPE = NodeClass.create(PublishWritesNode.class); @Input ValueNode allocation; @@ -111,6 +114,22 @@ public ValueNode getOriginalNode() { return allocation; } + @Override + public Node canonical(CanonicalizerTool tool) { + if (!tool.allUsagesAvailable()) { + return this; + } + /* + * Sometimes an AbstractNewObjectNode that was already wrapped by a PublishWritesNode is + * virtualized, and a second PublishWritesNode is created when the virtual object is + * lowered. If the two are adjacent, merge them into a single node. + */ + if (allocation instanceof PublishWritesNode && predecessor() == allocation) { + return allocation; + } + return this; + } + @Override public GuardingNode getGuard() { return this; From ceac2456962bb5b10e8613be63767529cfa09e48 Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Thu, 10 Oct 2024 12:30:25 +0200 Subject: [PATCH 014/105] Publish packed argument arrays created in ForeignGraphKit with a PublishWritesNode --- .../oracle/svm/hosted/foreign/ForeignGraphKit.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignGraphKit.java b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignGraphKit.java index 1862524f374c..2933076fba47 100644 --- a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignGraphKit.java +++ b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignGraphKit.java @@ -31,17 +31,19 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import org.graalvm.collections.Pair; + +import com.oracle.graal.pointsto.infrastructure.GraphProvider; +import com.oracle.graal.pointsto.meta.HostedProviders; +import com.oracle.svm.hosted.phases.HostedGraphKit; + import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.nodes.ConstantNode; import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.extended.PublishWritesNode; import jdk.graal.compiler.nodes.java.NewArrayNode; import jdk.graal.compiler.replacements.nodes.ReadRegisterNode; import jdk.graal.compiler.replacements.nodes.WriteRegisterNode; -import org.graalvm.collections.Pair; -import com.oracle.graal.pointsto.infrastructure.GraphProvider; -import com.oracle.graal.pointsto.meta.HostedProviders; -import com.oracle.svm.hosted.phases.HostedGraphKit; - import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; @@ -67,7 +69,7 @@ public ValueNode packArguments(List arguments) { assert argument.getStackKind().equals(JavaKind.Object); createStoreIndexed(argumentArray, i, JavaKind.Object, argument); } - return argumentArray; + return append(new PublishWritesNode(argumentArray)); } List unboxArguments(List args, MethodType methodType) { From 641293b81c38f43c1999e8cc24e6baf76af013b7 Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Wed, 9 Oct 2024 12:28:57 +0200 Subject: [PATCH 015/105] Adapt JDK-8341708: Optimize safepoint poll encoding with smaller poll data offset --- .../jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java index 4f63e1596064..9e0140a5ec04 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java @@ -431,10 +431,10 @@ public long defaultPrototypeMarkWord() { public final boolean useObjectMonitorTable = getFlag("UseObjectMonitorTable", Boolean.class, false, JDK >= 24); // JDK-8253180 & JDK-8265932 - public final int threadPollingPageOffset = getFieldOffset("JavaThread::_poll_data", Integer.class, "SafepointMechanism::ThreadData") + - getFieldOffset("SafepointMechanism::ThreadData::_polling_page", Integer.class, "volatile uintptr_t"); - public final int threadPollingWordOffset = getFieldOffset("JavaThread::_poll_data", Integer.class, "SafepointMechanism::ThreadData") + - getFieldOffset("SafepointMechanism::ThreadData::_polling_word", Integer.class, "volatile uintptr_t"); + public final int threadPollDataOffset = JDK >= 24 ? getFieldOffset("Thread::_poll_data", Integer.class, "SafepointMechanism::ThreadData") + : getFieldOffset("JavaThread::_poll_data", Integer.class, "SafepointMechanism::ThreadData"); + public final int threadPollingPageOffset = threadPollDataOffset + getFieldOffset("SafepointMechanism::ThreadData::_polling_page", Integer.class, "volatile uintptr_t"); + public final int threadPollingWordOffset = threadPollDataOffset + getFieldOffset("SafepointMechanism::ThreadData::_polling_word", Integer.class, "volatile uintptr_t"); public final int savedExceptionPCOffset = getFieldOffset("JavaThread::_saved_exception_pc", Integer.class, "address"); private final int threadLocalAllocBufferEndOffset = getFieldOffset("ThreadLocalAllocBuffer::_end", Integer.class, "HeapWord*"); From a098070e6ae900fdb0c640bc1baf073fe3fe9acf Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Wed, 9 Oct 2024 12:29:32 +0200 Subject: [PATCH 016/105] Update galahad JDK. --- common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.json b/common.json index 026f2d2be635..e3a13f62564a 100644 --- a/common.json +++ b/common.json @@ -8,7 +8,7 @@ "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+19-2105", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+20-2281", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk17": {"name": "jpg-jdk", "version": "17.0.7", "build_id": "jdk-17.0.7+8", "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.1-b02", "platformspecific": true }, From 6af3d09e6ea5ae9164cd526da63d448b1773d653 Mon Sep 17 00:00:00 2001 From: Christian Humer Date: Mon, 14 Oct 2024 12:09:47 +0200 Subject: [PATCH 017/105] Fix Truffle host inlining may peek into native calls and fail. --- .../compiler/truffle/test/HostInliningTest.java | 17 +++++++++++++++++ .../truffle/host/HostInliningPhase.java | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/HostInliningTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/HostInliningTest.java index d746e53f320a..03c439690f36 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/HostInliningTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/HostInliningTest.java @@ -147,6 +147,7 @@ public void test() { runTest("testThrow"); runTest("testRangeCheck"); runTest("testImplicitCast"); + runTest("testNativeCall"); } @SuppressWarnings("try") @@ -963,6 +964,22 @@ static int testImplicitCast(int value) { return (int) MyTypesGen.asImplicitDouble(0, value); } + @BytecodeInterpreterSwitch + @ExpectNotInlined(name = {"nativeCall"}, count = {1}) + static int testNativeCall(int value) { + if (value == 42) { + // we do not call nativeCall directly to trigger the peek deopt logic in host inlining + peekNativeCall(); + } + return 42; + } + + static void peekNativeCall() { + nativeCall(); + } + + static native void nativeCall(); + static int testIndirectIntrinsicsImpl(A a) { return a.intrinsic(); // inlined and intrinsic } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/HostInliningPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/HostInliningPhase.java index c0a6e7d20130..2aa4e65da59e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/HostInliningPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/HostInliningPhase.java @@ -603,6 +603,10 @@ private BackPropagation peekPropagatesDeoptOrUnwind(InliningPhaseContext context return BackPropagation.NOTHING; } + if (!method.hasBytecodes() || method.isNative()) { + return BackPropagation.NOTHING; + } + StructuredGraph graph = lookupGraph(context, callerInvoke, method); FixedNode current = graph.start(); while (current instanceof FixedWithNextNode) { From 00df696bf57ab6dd61f8b186a41dfa5279d0d4fc Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Tue, 15 Oct 2024 06:38:50 +0200 Subject: [PATCH 018/105] support invoke non-virtual jdwp invoke option --- .../oracle/truffle/espresso/jdwp/api/MethodRef.java | 12 +++++++++++- .../com/oracle/truffle/espresso/jdwp/impl/JDWP.java | 12 +++++++++--- .../src/com/oracle/truffle/espresso/impl/Method.java | 8 +++++++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/MethodRef.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/MethodRef.java index b3b99fb1795e..a7ddc903237d 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/MethodRef.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/MethodRef.java @@ -154,7 +154,17 @@ public interface MethodRef { * @param args guest-language arguments used when calling the method * @return the guest-language return value */ - Object invokeInterfaceMethod(Object... args); + Object invokeMethodInterface(Object... args); + + /** + * Invokes an instance method in a non-virtual fashion with input arguments. Overridden methods + * that would normally be called when invoking from Java source code using the self object is + * not invoked. The first argument must be the self object. + * + * @param args guest-language arguments used when calling the method + * @return the guest-language return value + */ + Object invokeMethodNonVirtual(Object... args); /** * Determines if the declaring class has a source file attribute. diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java index b87563a4100d..420c67d0f5b0 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java @@ -53,6 +53,8 @@ public final class JDWP { private static final int ACC_SYNTHETIC = 0x00001000; private static final int JDWP_SYNTHETIC = 0xF0000000; + public static final int INVOKE_SINGLE_THREADED = 0x01; + public static final int INVOKE_NON_VIRTUAL = 0x02; private JDWP() { } @@ -1799,15 +1801,19 @@ static CommandResult createReply(Packet packet, DebuggerController controller, D controller.fine(() -> "trying to invoke method: " + method.getNameAsString()); int invocationOptions = input.readInt(); - byte suspensionStrategy = invocationOptions == 1 ? SuspendStrategy.EVENT_THREAD : SuspendStrategy.ALL; + boolean invokeSingleThreaded = (invocationOptions & INVOKE_SINGLE_THREADED) != 0; + boolean invokeNonvirtual = (invocationOptions & INVOKE_NON_VIRTUAL) != 0; + byte suspensionStrategy = invokeSingleThreaded ? SuspendStrategy.EVENT_THREAD : SuspendStrategy.ALL; try { // we have to call the method in the correct thread, so post a // Callable to the controller and wait for the result to appear ThreadJob job = new ThreadJob<>(thread, () -> { - if (Modifier.isPrivate(method.getModifiers())) { + if (invokeNonvirtual) { + return method.invokeMethodNonVirtual(args); + } else if (Modifier.isPrivate(method.getModifiers())) { return method.invokeMethodSpecial(args); } else if (method.getDeclaringKlassRef().isInterface()) { - return method.invokeInterfaceMethod(args); + return method.invokeMethodInterface(args); } else { return method.invokeMethodVirtual(args); } 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 19edc3c97d48..d4174d92b3ce 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 @@ -1708,11 +1708,17 @@ public Object invokeMethodSpecial(Object... args) { } @Override - public Object invokeInterfaceMethod(Object... args) { + public Object invokeMethodInterface(Object... args) { checkRemovedByRedefinition(); return invokeDirectInterface(args); } + @Override + public Object invokeMethodNonVirtual(Object... args) { + checkRemovedByRedefinition(); + return invokeDirect(args); + } + private void checkRemovedByRedefinition() { if (getMethod().isRemovedByRedefinition()) { Meta meta = getMeta(); From dba58aa1dd085ec2bd4a986c99677bd4ea2a6228 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Mon, 14 Oct 2024 16:42:20 +0200 Subject: [PATCH 019/105] Create parent constant before loading relinked constant --- .../graal/pointsto/heap/ImageLayerLoader.java | 25 +++++++++++++-- .../pointsto/heap/ImageLayerSnapshotUtil.java | 10 +++++- .../graal/pointsto/heap/ImageLayerWriter.java | 32 +++++++++++++------ .../heap/SVMImageLayerSnapshotUtil.java | 4 +++ .../svm/hosted/heap/SVMImageLayerWriter.java | 4 +-- 5 files changed, 59 insertions(+), 16 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java index 9d841571cdab..c46b3cef536f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java @@ -84,6 +84,8 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NULL_POINTER_CONSTANT; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.OBJECT_OFFSET_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.OBJECT_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PARENT_CONSTANT_ID_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PARENT_CONSTANT_INDEX_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PERSISTED; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.POSITION_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PRIMITIVE_ARRAY_TAG; @@ -295,8 +297,10 @@ *

* Relinking a base layer {@link ImageHeapConstant} is finding the corresponding hosted object in * the extension image build process and storing it in the constant. This is only done for object - * that can be created or found using a specific recipe. Some fields from those constant can then be - * relinked using the value of the hosted object. + * that can be created or found using a specific recipe. Those constants are then called parent + * constants. Some fields of their field values can then be relinked using the value of the hosted + * object. The produced constants are called child constants, and they have to be consistent across + * image builds. *

* The "offset object" is the offset of the constant in the heap from the base layer. */ @@ -1014,7 +1018,7 @@ public void executeHeapScannerTasks() { * underlying host VM, found by querying the parent object that made this constant reachable * (see {@link ImageLayerLoader#getReachableHostedValue(ImageHeapConstant, int)}). */ - protected ImageHeapConstant getOrCreateConstant(EconomicMap constantsMap, int id, JavaConstant parentReachableHostedObject) { + protected ImageHeapConstant getOrCreateConstant(EconomicMap constantsMap, int id, JavaConstant parentReachableHostedObjectCandidate) { if (constants.containsKey(id)) { return constants.get(id); } @@ -1028,6 +1032,21 @@ protected ImageHeapConstant getOrCreateConstant(EconomicMap cons String objectOffset = get(baseLayerConstant, OBJECT_OFFSET_TAG); int identityHashCode = get(baseLayerConstant, IDENTITY_HASH_CODE_TAG); + + JavaConstant parentReachableHostedObject; + if (parentReachableHostedObjectCandidate == null) { + Integer parentConstantId = get(baseLayerConstant, PARENT_CONSTANT_ID_TAG); + if (parentConstantId != null) { + ImageHeapConstant parentConstant = getOrCreateConstant(parentConstantId); + int index = get(baseLayerConstant, PARENT_CONSTANT_INDEX_TAG); + parentReachableHostedObject = getReachableHostedValue(parentConstant, index); + } else { + parentReachableHostedObject = null; + } + } else { + parentReachableHostedObject = parentReachableHostedObjectCandidate; + } + if (parentReachableHostedObject != null && !type.getJavaClass().equals(Class.class)) { /* * The hash codes of DynamicHubs need to be injected before they are used in a map, diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java index 3d30d926ac03..4d742f22d580 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java @@ -65,6 +65,8 @@ public class ImageLayerSnapshotUtil { public static final String PERSISTED = "persisted"; + public static final int UNDEFINED_CONSTANT_ID = -1; + public static final int UNDEFINED_FIELD_INDEX = -1; public static final int NULL_POINTER_CONSTANT = -1; public static final int NOT_MATERIALIZED_CONSTANT = -2; public static final String OBJECT_TAG = "A"; @@ -123,6 +125,8 @@ public class ImageLayerSnapshotUtil { public static final String TARGET_CONSTRUCTOR_TAG = "target constructor"; public static final String THROW_ALLOCATED_OBJECT_TAG = "throw allocated object"; public static final String IDENTITY_HASH_CODE_TAG = "identityHashCode"; + public static final String PARENT_CONSTANT_ID_TAG = "parent constant id"; + public static final String PARENT_CONSTANT_INDEX_TAG = "parent constant index"; public static final String HUB_IDENTITY_HASH_CODE_TAG = "hub identityHashCode"; public static final String IS_INITIALIZED_AT_BUILD_TIME_TAG = "is initialized at build time"; public static final String IS_NO_INITIALIZER_NO_TRACKING_TAG = "in no initializer no tracking"; @@ -224,6 +228,10 @@ protected static String getQualifiedName(AnalysisMethod method) { return method.getSignature().getReturnType().toJavaName(true) + " " + method.getQualifiedName(); } + /** + * Get all the field indexes that should be relinked using the hosted value of a constant from + * the given type. + */ @SuppressWarnings("unused") public Set getRelinkedFields(AnalysisType type, AnalysisMetaAccess metaAccess) { return Set.of(); @@ -304,7 +312,7 @@ protected ImageHeapConstantBuiltIn(ImageLayerWriter imageLayerWriter, ImageLayer @Override public String encode(ObjectCopier.Encoder encoder, Object obj) { ImageHeapConstant imageHeapConstant = (ImageHeapConstant) obj; - imageLayerWriter.elementsToPersist.add(new AnalysisFuture<>(() -> imageLayerWriter.persistConstant(imageHeapConstant))); + imageLayerWriter.elementsToPersist.add(new AnalysisFuture<>(() -> imageLayerWriter.persistConstant(UNDEFINED_CONSTANT_ID, UNDEFINED_FIELD_INDEX, imageHeapConstant))); return String.valueOf(imageHeapConstant.getConstantData().id); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java index 7921b8ed1f6c..1c53296f9211 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java @@ -80,6 +80,8 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NOT_MATERIALIZED_CONSTANT; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NULL_POINTER_CONSTANT; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.OBJECT_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PARENT_CONSTANT_ID_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PARENT_CONSTANT_INDEX_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.POSITION_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PRIMITIVE_ARRAY_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.RETURN_TYPE_TAG; @@ -89,6 +91,8 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.SUPER_CLASS_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.TID_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.TYPES_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.UNDEFINED_CONSTANT_ID; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.UNDEFINED_FIELD_INDEX; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.VALUE_TAG; import static jdk.graal.compiler.java.LambdaUtils.LAMBDA_CLASS_NAME_SUBSTRING; @@ -296,7 +300,7 @@ public void persistAnalysisInfo() { for (Map.Entry> entry : imageHeap.getReachableObjects().entrySet()) { for (ImageHeapConstant imageHeapConstant : entry.getValue()) { - persistConstant(imageHeapConstant); + persistConstant(UNDEFINED_CONSTANT_ID, UNDEFINED_FIELD_INDEX, imageHeapConstant); } } for (AnalysisFuture task : elementsToPersist) { @@ -516,15 +520,16 @@ protected void persistField(AnalysisField field, EconomicMap fie fieldMap.put(FIELD_FOLDED_TAG, field.getFoldedReason() != null); } - protected void persistConstant(ImageHeapConstant imageHeapConstant) { + protected void persistConstant(int parentId, int index, ImageHeapConstant imageHeapConstant) { if (!constantsMap.containsKey(Integer.toString(getConstantId(imageHeapConstant)))) { EconomicMap constantMap = EconomicMap.create(); - persistConstant(imageHeapConstant, constantMap); + persistConstant(parentId, index, imageHeapConstant, constantMap); } } - protected void persistConstant(ImageHeapConstant imageHeapConstant, EconomicMap constantMap) { - constantsMap.put(Integer.toString(getConstantId(imageHeapConstant)), constantMap); + protected void persistConstant(int parentId, int index, ImageHeapConstant imageHeapConstant, EconomicMap constantMap) { + int id = getConstantId(imageHeapConstant); + constantsMap.put(Integer.toString(id), constantMap); constantMap.put(TID_TAG, imageHeapConstant.getType().getId()); IdentityHashCodeProvider identityHashCodeProvider = (IdentityHashCodeProvider) aUniverse.getBigbang().getConstantReflectionProvider(); @@ -534,17 +539,23 @@ protected void persistConstant(ImageHeapConstant imageHeapConstant, EconomicMap< switch (imageHeapConstant) { case ImageHeapInstance imageHeapInstance -> { Object[] fieldValues = imageHeapInstance.isReaderInstalled() ? imageHeapInstance.getFieldValues() : null; - persistConstant(constantMap, INSTANCE_TAG, fieldValues); + persistConstant(id, imageHeapConstant.getType(), constantMap, INSTANCE_TAG, fieldValues); persistConstantRelinkingInfo(constantMap, imageHeapConstant, aUniverse.getBigbang()); } case ImageHeapObjectArray imageHeapObjectArray -> - persistConstant(constantMap, ARRAY_TAG, imageHeapObjectArray.getElementValues()); + persistConstant(id, imageHeapConstant.getType(), constantMap, ARRAY_TAG, imageHeapObjectArray.getElementValues()); case ImageHeapPrimitiveArray imageHeapPrimitiveArray -> { constantMap.put(CONSTANT_TYPE_TAG, PRIMITIVE_ARRAY_TAG); constantMap.put(DATA_TAG, getString(imageHeapPrimitiveArray.getType().getComponentType().getJavaKind(), imageHeapPrimitiveArray.getArray())); } default -> throw AnalysisError.shouldNotReachHere("Unexpected constant type " + imageHeapConstant); } + + if (!constantsToRelink.contains(id) && parentId != UNDEFINED_CONSTANT_ID) { + constantMap.put(PARENT_CONSTANT_ID_TAG, parentId); + assert index != UNDEFINED_FIELD_INDEX : "Tried to persist child constant %s from parent constant %d, but got index %d".formatted(imageHeapConstant, parentId, index); + constantMap.put(PARENT_CONSTANT_INDEX_TAG, index); + } } protected int getConstantId(ImageHeapConstant imageHeapConstant) { @@ -595,11 +606,12 @@ private static List getString(JavaKind kind, Object arrayObject) { }; } - protected void persistConstant(EconomicMap constantMap, String constantType, Object[] values) { + protected void persistConstant(int id, AnalysisType type, EconomicMap constantMap, String constantType, Object[] values) { constantMap.put(CONSTANT_TYPE_TAG, constantType); if (values != null) { List> data = new ArrayList<>(); - for (Object object : values) { + for (int i = 0; i < values.length; ++i) { + Object object = values[i]; if (delegateProcessing(data, object)) { /* The object was already persisted */ } else if (object instanceof ImageHeapConstant imageHeapConstant) { @@ -609,7 +621,7 @@ protected void persistConstant(EconomicMap constantMap, String c * in reachable constants. They can be created in the extension image, but * should not be used. */ - persistConstant(imageHeapConstant); + persistConstant(imageLayerSnapshotUtil.getRelinkedFields(type, aUniverse.getBigbang().getMetaAccess()).contains(i) ? id : UNDEFINED_CONSTANT_ID, i, imageHeapConstant); } else if (object == JavaConstant.NULL_POINTER) { data.add(List.of(OBJECT_TAG, NULL_POINTER_CONSTANT)); } else if (object instanceof PrimitiveConstant primitiveConstant) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java index a829d10a6a27..ccc99cb0fa86 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java @@ -103,6 +103,10 @@ public class SVMImageLayerSnapshotUtil extends ImageLayerSnapshotUtil { protected static final Set dynamicHubRelinkedFields = Set.of(companion, classInitializationInfo, name, superHub, componentType, arrayHub); + /** + * This map stores the field indexes that should be relinked using the hosted value of a + * constant from the key type. + */ protected final Map> fieldsToRelink = new HashMap<>(); @SuppressWarnings("this-escape") diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java index d9ebd7c99d98..f91d256759aa 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java @@ -234,12 +234,12 @@ protected void persistField(AnalysisField field, EconomicMap fie } @Override - protected void persistConstant(ImageHeapConstant imageHeapConstant, EconomicMap constantMap) { + protected void persistConstant(int parentId, int index, ImageHeapConstant imageHeapConstant, EconomicMap constantMap) { ObjectInfo objectInfo = nativeImageHeap.getConstantInfo(imageHeapConstant); if (objectInfo != null) { constantMap.put(OBJECT_OFFSET_TAG, String.valueOf(objectInfo.getOffset())); } - super.persistConstant(imageHeapConstant, constantMap); + super.persistConstant(parentId, index, imageHeapConstant, constantMap); } @Override From a72dc1cdefd8cb34ec4dc57ce2a40a6e51ddd158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C3=B6=20Barany?= Date: Mon, 7 Oct 2024 15:20:55 +0200 Subject: [PATCH 020/105] Avoid recursion in GraphOrder and SchedulePhase --- .../phases/schedule/SchedulePhase.java | 40 +++++- .../compiler/phases/util/GraphOrder.java | 121 +++++++++++++----- 2 files changed, 127 insertions(+), 34 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/schedule/SchedulePhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/schedule/SchedulePhase.java index 2489ad6dbe6f..4932e5752425 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/schedule/SchedulePhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/schedule/SchedulePhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -603,9 +603,24 @@ private static void sortIntoList(Node n, HIRBlock b, ArrayList result, Nod unprocessed.clear(n); - for (Node input : n.inputs()) { - if (nodeMap.get(input) == b && unprocessed.isMarked(input) && input != excludeNode) { - sortIntoList(input, b, result, nodeMap, unprocessed, excludeNode); + /* + * Schedule all unprocessed transitive inputs. This uses an explicit stack instead of + * recursion to avoid overflowing the call stack. + */ + NodeStack stack = new NodeStack(); + ArrayList tempList = new ArrayList<>(); + stack.push(n); + while (!stack.isEmpty()) { + Node top = stack.peek(); + pushUnprocessedInputs(top, b, nodeMap, unprocessed, excludeNode, stack, tempList); + if (stack.peek() == top) { + if (top != n) { + if (unprocessed.isMarked(top) && !(top instanceof ProxyNode)) { + result.add(top); + } + unprocessed.clear(top); + } + stack.pop(); } } @@ -614,7 +629,24 @@ private static void sortIntoList(Node n, HIRBlock b, ArrayList result, Nod } else { result.add(n); } + } + private static void pushUnprocessedInputs(Node n, HIRBlock b, NodeMap nodeMap, NodeBitMap unprocessed, Node excludeNode, NodeStack stack, ArrayList tempList) { + tempList.clear(); + n.inputs().snapshotTo(tempList); + /* + * Nodes on top of the stack are scheduled first. Pushing inputs left to right would + * therefore mean scheduling them right to left. We observe the best performance when + * scheduling inputs left to right, therefore we push them in reverse order. We could + * explore more elaborate scheduling policies, like scheduling for reduced register + * pressure using Sethi-Ullman numbering (GR-34624). + */ + for (int i = tempList.size() - 1; i >= 0; i--) { + Node input = tempList.get(i); + if (nodeMap.get(input) == b && unprocessed.isMarked(input) && input != excludeNode && !(input instanceof PhiNode)) { + stack.push(input); + } + } } protected void calcLatestBlock(HIRBlock earliestBlock, SchedulingStrategy strategy, Node currentNode, NodeMap currentNodeMap, LocationIdentity constrainingLocation, diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/GraphOrder.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/GraphOrder.java index 6b8dd378d840..bcf99d0df675 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/GraphOrder.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/GraphOrder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeBitMap; import jdk.graal.compiler.graph.NodeFlood; +import jdk.graal.compiler.graph.NodeStack; import jdk.graal.compiler.graph.Position; import jdk.graal.compiler.nodes.AbstractBeginNode; import jdk.graal.compiler.nodes.AbstractEndNode; @@ -49,6 +50,7 @@ import jdk.graal.compiler.nodes.GraphState.GuardsStage; import jdk.graal.compiler.nodes.GraphState.StageFlag; import jdk.graal.compiler.nodes.GuardNode; +import jdk.graal.compiler.nodes.GuardPhiNode; import jdk.graal.compiler.nodes.LoopBeginNode; import jdk.graal.compiler.nodes.LoopExitNode; import jdk.graal.compiler.nodes.PhiNode; @@ -108,52 +110,111 @@ public static boolean assertNonCyclicGraph(StructuredGraph graph) { private static List createOrder(StructuredGraph graph) { final ArrayList nodes = new ArrayList<>(); final NodeBitMap visited = graph.createNodeBitMap(); + final NodeStack stack = new NodeStack(); new StatelessPostOrderNodeIterator(graph.start()) { @Override protected void node(FixedNode node) { - visitForward(nodes, visited, node, false); + orderNodeAndNeighbors(nodes, visited, stack, node); } }.apply(); return nodes; } - private static void visitForward(ArrayList nodes, NodeBitMap visited, Node node, boolean floatingOnly) { + /** + * Visit the given fixed {@code node} and its inputs, state after (if any), and phis anchored at + * the node (if any). Add these nodes in order to the {@code nodes} list. The intended order is: + * + *

    + *
  1. any floating non-stateAfter inputs, transitively
  2. + *
  3. for an EndNode, phi values for this end at the corresponding merge
  4. + *
  5. the fixed node itself
  6. + *
  7. for any kind of merge, its phis
  8. + *
  9. the stateAfter, if any
  10. + *
+ * + * Any previously {@code visited} nodes are skipped. An unvisited fixed node found as part of + * the traversal indicates an illegal cycle in the graph. + */ + private static void orderNodeAndNeighbors(ArrayList nodes, NodeBitMap visited, NodeStack stack, FixedNode fixedNode) { try { - assert node == null || node.isAlive() : node + " not alive"; - if (node != null && !visited.isMarked(node)) { - if (floatingOnly && node instanceof FixedNode) { - throw new GraalError("unexpected reference to fixed node: %s (this indicates an unexpected cycle)", node); + GraalError.guarantee(fixedNode == null || fixedNode.isAlive(), "%s not alive", fixedNode); + if (fixedNode == null || visited.isMarked(fixedNode)) { + return; + } + visited.mark(fixedNode); + FrameState stateAfter = null; + if (fixedNode instanceof StateSplit) { + stateAfter = ((StateSplit) fixedNode).stateAfter(); + } + /* 1. any floating non-stateAfter inputs. */ + visitTransitiveInputs(nodes, visited, fixedNode, stateAfter, stack); + /* 2. for an EndNode, phi values for this end at the corresponding merge */ + if (fixedNode instanceof EndNode end) { + for (PhiNode phi : end.merge().phis()) { + ValueNode phiValue = phi.valueAt(end); + if (phiValue == null) { + GraalError.guarantee(phi instanceof GuardPhiNode, "only guard phis may have null values: %s", phi); + } else if (!visited.isMarked(phiValue)) { + visited.mark(phiValue); + visitTransitiveInputs(nodes, visited, phiValue, stateAfter, stack); + nodes.add(phiValue); + } } - visited.mark(node); - FrameState stateAfter = null; - if (node instanceof StateSplit) { - stateAfter = ((StateSplit) node).stateAfter(); + } + /* 3. the fixed node itself */ + nodes.add(fixedNode); + /* 4. for any kind of merge, its phis */ + if (fixedNode instanceof AbstractMergeNode merge) { + for (PhiNode phi : merge.phis()) { + visited.mark(phi); + nodes.add(phi); } - for (Node input : node.inputs()) { - if (input != stateAfter) { - visitForward(nodes, visited, input, true); - } + } + /* 5. the stateAfter, if any */ + if (stateAfter != null && !visited.isMarked(stateAfter)) { + visited.mark(stateAfter); + visitTransitiveInputs(nodes, visited, stateAfter, null, stack); + nodes.add(stateAfter); + } + } catch (GraalError e) { + throw GraalGraphError.transformAndAddContext(e, fixedNode); + } + } + + /** + * Add floating inputs of {@code visitRoot}, including transitive inputs, to the {@code nodes}, + * such that inputs precede their usages in the list. Skip any nodes that are already + * {@code visited} or equal {@code excludeNode}. The {@code stack} is used as an intermediate + * data structure to keep track of transitive inputs. It must be empty when this method is + * called, and it will be empty when this method returns. + *

+ * + * This method does not add the {@code visitRoot} itself to the {@code nodes}. + */ + private static void visitTransitiveInputs(ArrayList nodes, NodeBitMap visited, Node visitRoot, FrameState excludeNode, NodeStack stack) { + GraalError.guarantee(stack.isEmpty(), "stack must be empty, it's only shared to avoid allocations"); + stack.push(visitRoot); + while (!stack.isEmpty()) { + Node top = stack.peek(); + for (Node input : top.inputs()) { + if (input != excludeNode && !visited.isMarked(input)) { + stack.push(input); } - if (node instanceof EndNode) { - EndNode end = (EndNode) node; - for (PhiNode phi : end.merge().phis()) { - visitForward(nodes, visited, phi.valueAt(end), true); + } + if (stack.peek() == top) { + if (top != visitRoot) { + if (top instanceof FixedNode) { + throw new GraalError("unexpected reference to fixed node: %s (this indicates an unexpected cycle)", top); } - } - nodes.add(node); - if (node instanceof AbstractMergeNode) { - for (PhiNode phi : ((AbstractMergeNode) node).phis()) { - visited.mark(phi); - nodes.add(phi); + /* No new transitive inputs were pushed, this input is ready to be scheduled. */ + if (!visited.isMarked(top)) { + nodes.add(top); } + visited.mark(top); } - if (stateAfter != null) { - visitForward(nodes, visited, stateAfter, true); - } + stack.pop(); } - } catch (GraalError e) { - throw GraalGraphError.transformAndAddContext(e, node); } } From 35d63a5ba574719eeb7a1e2a7cb7b00eb35c670d Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Wed, 16 Oct 2024 15:48:03 +0200 Subject: [PATCH 021/105] [GR-57335] Add getters to KnownOffsets and helper to determine itable start offsets in OpenTypeWorld --- .../src/com/oracle/svm/core/graal/meta/KnownOffsets.java | 8 ++++++++ .../snippets/OpenTypeWorldDispatchTableSnippets.java | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/KnownOffsets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/KnownOffsets.java index cc4d3a2ffc49..77a2ddd5e4f6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/KnownOffsets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/KnownOffsets.java @@ -110,6 +110,14 @@ private boolean isFullyInitialized() { return vtableEntrySize > 0; } + public int getVTableBaseOffset() { + return vtableBaseOffset; + } + + public int getVTableEntrySize() { + return vtableEntrySize; + } + /** * Returns of the offset of the index either relative to the start of the vtable * ({@code fromDynamicHubStart} == false) or start of the dynamic hub diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/OpenTypeWorldDispatchTableSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/OpenTypeWorldDispatchTableSnippets.java index 2309dffa2cd4..c9334501682d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/OpenTypeWorldDispatchTableSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/OpenTypeWorldDispatchTableSnippets.java @@ -72,7 +72,7 @@ private static long loadDispatchTableStartingOffset( } } - private static long determineITableStartingOffset( + public static long determineITableStartingOffset( DynamicHub checkedHub, int interfaceID) { @@ -120,7 +120,7 @@ class DispatchTableStartingOffsetLowering implements NodeLoweringProvider Date: Wed, 2 Oct 2024 15:11:01 +0200 Subject: [PATCH 022/105] Collect all external values for Layered Image --- .../compiler/util/test/ObjectCopierTest.java | 8 +- .../hotspot/libgraal/CompilerConfig.java | 95 +--------- .../graal/compiler/nodes/EncodedGraph.java | 5 +- .../jdk/graal/compiler/util/ObjectCopier.java | 108 +++++++++++- .../graal/pointsto/heap/ImageLayerLoader.java | 32 ++-- .../pointsto/heap/ImageLayerSnapshotUtil.java | 98 +++-------- .../graal/pointsto/heap/ImageLayerWriter.java | 41 ++--- .../imagelayer/ImageLayerBuildingSupport.java | 18 +- .../svm/hosted/HostedConfiguration.java | 5 + .../svm/hosted/NativeImageGenerator.java | 28 ++- .../svm/hosted/heap/SVMImageLayerLoader.java | 29 ++- .../heap/SVMImageLayerSnapshotUtil.java | 166 ++++++++++-------- .../svm/hosted/heap/SVMImageLayerWriter.java | 2 +- .../HostedImageLayerBuildingSupport.java | 23 ++- .../oracle/svm/hosted/meta/HostedMethod.java | 9 - .../thread/LayeredVMThreadLocalCollector.java | 21 +-- .../hosted/thread/VMThreadLocalCollector.java | 30 +++- 17 files changed, 345 insertions(+), 373 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/util/test/ObjectCopierTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/util/test/ObjectCopierTest.java index 80566ffe769e..98b6513eafbb 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/util/test/ObjectCopierTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/util/test/ObjectCopierTest.java @@ -35,11 +35,11 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import jdk.graal.compiler.core.test.SubprocessTest; import org.graalvm.collections.EconomicMap; import org.junit.Assert; import org.junit.Test; +import jdk.graal.compiler.core.test.SubprocessTest; import jdk.graal.compiler.util.ObjectCopier; /** @@ -172,10 +172,10 @@ public void testIt() { root.put("singleton2", TestObject.TEST_OBJECT_SINGLETON); root.put("singleton2_2", TestObject.TEST_OBJECT_SINGLETON); - List externalValues = List.of(ObjectCopier.getField(BaseClass.class, "BASE_SINGLETON"), + List externalValueFields = List.of(ObjectCopier.getField(BaseClass.class, "BASE_SINGLETON"), ObjectCopier.getField(TestObject.class, "TEST_OBJECT_SINGLETON")); - String encoded = ObjectCopier.encode(new ObjectCopier.Encoder(externalValues), root); + String encoded = ObjectCopier.encode(new ObjectCopier.Encoder(externalValueFields), root); if (DEBUG) { System.out.printf("encoded:%n%s%n", encoded); } @@ -184,7 +184,7 @@ public void testIt() { System.out.printf("root:%n%s%n", root); System.out.printf("decoded:%n%s%n", decoded); } - String reencoded = ObjectCopier.encode(new ObjectCopier.Encoder(externalValues), decoded); + String reencoded = ObjectCopier.encode(new ObjectCopier.Encoder(externalValueFields), decoded); if (DEBUG) { System.out.printf("reencoded:%n%s%n", reencoded); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/CompilerConfig.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/CompilerConfig.java index 3f5178cc4f5a..28e61f20f7ea 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/CompilerConfig.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/CompilerConfig.java @@ -24,37 +24,29 @@ */ package jdk.graal.compiler.hotspot.libgraal; -import java.io.IOException; import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.net.URI; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.stream.Stream; -import jdk.graal.compiler.core.common.spi.ForeignCallSignature; -import jdk.graal.compiler.core.target.Backend; -import jdk.graal.compiler.hotspot.HotSpotForeignCallLinkage; -import jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; -import jdk.graal.compiler.truffle.hotspot.HotSpotTruffleCompilerImpl; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.MapCursor; -import org.graalvm.word.LocationIdentity; +import jdk.graal.compiler.core.common.spi.ForeignCallSignature; +import jdk.graal.compiler.core.target.Backend; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.hotspot.EncodedSnippets; +import jdk.graal.compiler.hotspot.HotSpotForeignCallLinkage; import jdk.graal.compiler.hotspot.HotSpotGraalCompiler; import jdk.graal.compiler.hotspot.HotSpotGraalRuntimeProvider; import jdk.graal.compiler.hotspot.HotSpotReplacementsImpl; import jdk.graal.compiler.hotspot.SymbolicSnippetEncoder; +import jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; import jdk.graal.compiler.hotspot.meta.HotSpotProviders; import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.truffle.hotspot.HotSpotTruffleCompilerImpl; import jdk.graal.compiler.util.ObjectCopier; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; @@ -84,13 +76,13 @@ public static void main(String[] args) throws Exception { List foreignCallSignatures = getForeignCallSignatures(replacements, options, graalRuntime); EncodedSnippets encodedSnippets = getEncodedSnippets(replacements, options); - List externalValues = getExternalValues(); + List externalValueFields = ObjectCopier.getExternalValueFields(); EconomicMap encodedObjects = EconomicMap.create(); encodedObjects.put("encodedSnippets", encodedSnippets); encodedObjects.put("foreignCallSignatures", foreignCallSignatures); - ObjectCopier.Encoder encoder = new ObjectCopier.Encoder(externalValues) { + ObjectCopier.Encoder encoder = new ObjectCopier.Encoder(externalValueFields) { @Override protected ClassInfo makeClassInfo(Class declaringClass) { ClassInfo ci = ClassInfo.of(declaringClass); @@ -152,77 +144,4 @@ private static void collectForeignCalls(HotSpotHostForeignCallsProvider foreignC } }); } - - private static List getExternalValues() throws IOException { - List externalValues = new ArrayList<>(); - addImmutableCollectionsFields(externalValues); - addStaticFinalObjectFields(LocationIdentity.class, externalValues); - - try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Collections.emptyMap())) { - for (String module : List.of("jdk.internal.vm.ci", "jdk.graal.compiler", "com.oracle.graal.graal_enterprise")) { - Path top = fs.getPath("/modules/" + module); - try (Stream files = Files.find(top, Integer.MAX_VALUE, (path, attrs) -> attrs.isRegularFile())) { - files.forEach(p -> { - String fileName = p.getFileName().toString(); - if (fileName.endsWith(".class") && !fileName.equals("module-info.class")) { - // Strip module prefix and convert to dotted form - int nameCount = p.getNameCount(); - String className = p.subpath(2, nameCount).toString().replace('/', '.'); - // Strip ".class" suffix - className = className.replace('/', '.').substring(0, className.length() - ".class".length()); - try { - Class graalClass = Class.forName(className); - addStaticFinalObjectFields(graalClass, externalValues); - } catch (ClassNotFoundException e) { - throw new GraalError(e); - } - } - }); - } - } - } - return externalValues; - } - - /** - * Adds the static, final, non-primitive fields of non-enum {@code declaringClass} to - * {@code fields}. In the process, the fields are made {@linkplain Field#setAccessible - * accessible}. - */ - private static void addStaticFinalObjectFields(Class declaringClass, List fields) { - if (Enum.class.isAssignableFrom(declaringClass)) { - return; - } - for (Field field : declaringClass.getDeclaredFields()) { - int fieldModifiers = field.getModifiers(); - int fieldMask = Modifier.STATIC | Modifier.FINAL; - if ((fieldModifiers & fieldMask) != fieldMask) { - continue; - } - if (field.getType().isPrimitive()) { - continue; - } - field.setAccessible(true); - fields.add(field); - } - } - - /** - * Adds the EMPTY* fields from {@code java.util.ImmutableCollections} to {@code fields}, making - * them {@linkplain Field#setAccessible accessible} in the process. - */ - private static void addImmutableCollectionsFields(List fields) { - Class c = List.of().getClass().getDeclaringClass(); - GraalError.guarantee(c.getName().equals("java.util.ImmutableCollections"), "Incompatible ImmutableCollections class"); - for (Field f : c.getDeclaredFields()) { - if (f.getName().startsWith("EMPTY")) { - int modifiers = f.getModifiers(); - GraalError.guarantee(Modifier.isStatic(modifiers), "Expect %s to be static", f); - GraalError.guarantee(Modifier.isFinal(modifiers), "Expect %s to be final", f); - GraalError.guarantee(!f.getType().isPrimitive(), "Expect %s to be non-primitive", f); - f.setAccessible(true); - fields.add(f); - } - } - } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/EncodedGraph.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/EncodedGraph.java index aedcafb6f507..37e4bf6baa70 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/EncodedGraph.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/EncodedGraph.java @@ -30,7 +30,6 @@ import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.NodeClass; - import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -139,6 +138,10 @@ public Object getObject(int i) { return objects[i]; } + public void setObject(int i, Object object) { + objects[i] = object; + } + public NodeClass[] getNodeClasses() { return types; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java index 9af28e1cde78..4be038275550 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/util/ObjectCopier.java @@ -25,11 +25,18 @@ package jdk.graal.compiler.util; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; @@ -785,16 +792,30 @@ public static class Encoder extends ObjectCopier { /** * Map from values to static final fields. In a serialized object graph, references to such - * values are encoded with a reference to the field. + * values are encoded using the static final field they come from. This field is then looked + * up via reflection when the value needs to be decoded. */ - final Map externalValues = new IdentityHashMap<>(); + final Map externalValues; - public Encoder(List externalValues) { + public Encoder(List externalValueFields) { + this(gatherExternalValues(externalValueFields)); + } + + /** + * Use precomputed {@code externalValues} to avoid recomputing them. + */ + public Encoder(Map externalValues) { objects.add(null); objectToId.put(null, new ObjectID(0, null)); - for (Field f : externalValues) { - addExternalValue(f); + this.externalValues = externalValues; + } + + public static Map gatherExternalValues(List externalValueFields) { + Map result = new IdentityHashMap<>(); + for (Field f : externalValueFields) { + addExternalValue(result, f); } + return result; } /** @@ -808,7 +829,7 @@ protected ClassInfo makeClassInfo(Class declaringClass) { return ClassInfo.of(declaringClass); } - private void addExternalValue(Field field) { + private static void addExternalValue(Map externalValues, Field field) { GraalError.guarantee(Modifier.isStatic(field.getModifiers()), "Field '%s' is not static. Only a static field can be used as known location for an instance.", field); Object value = readField(field, null); if (value == null) { @@ -825,7 +846,7 @@ private void addExternalValue(Field field) { } public Map getExternalValues() { - return externalValues; + return Collections.unmodifiableMap(externalValues); } private String encodeMap(UnmodifiableEconomicMap map) { @@ -1000,6 +1021,79 @@ public static Field getField(Class declaredClass, String fieldName) { } } + public static List getExternalValueFields() throws IOException { + List externalValues = new ArrayList<>(); + addImmutableCollectionsFields(externalValues); + addStaticFinalObjectFields(LocationIdentity.class, externalValues); + + try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Collections.emptyMap())) { + for (String module : List.of("jdk.internal.vm.ci", "jdk.graal.compiler", "com.oracle.graal.graal_enterprise")) { + Path top = fs.getPath("/modules/" + module); + try (Stream files = Files.find(top, Integer.MAX_VALUE, (path, attrs) -> attrs.isRegularFile())) { + files.forEach(p -> { + String fileName = p.getFileName().toString(); + if (fileName.endsWith(".class") && !fileName.equals("module-info.class")) { + // Strip module prefix and convert to dotted form + int nameCount = p.getNameCount(); + String className = p.subpath(2, nameCount).toString().replace('/', '.'); + // Strip ".class" suffix + className = className.replace('/', '.').substring(0, className.length() - ".class".length()); + try { + Class graalClass = Class.forName(className); + addStaticFinalObjectFields(graalClass, externalValues); + } catch (ClassNotFoundException e) { + throw new GraalError(e); + } + } + }); + } + } + } + return externalValues; + } + + /** + * Adds the static, final, non-primitive fields of non-enum {@code declaringClass} to + * {@code fields}. In the process, the fields are made {@linkplain Field#setAccessible + * accessible}. + */ + public static void addStaticFinalObjectFields(Class declaringClass, List fields) { + if (Enum.class.isAssignableFrom(declaringClass)) { + return; + } + for (Field field : declaringClass.getDeclaredFields()) { + int fieldModifiers = field.getModifiers(); + int fieldMask = Modifier.STATIC | Modifier.FINAL; + if ((fieldModifiers & fieldMask) != fieldMask) { + continue; + } + if (field.getType().isPrimitive()) { + continue; + } + field.setAccessible(true); + fields.add(field); + } + } + + /** + * Adds the EMPTY* fields from {@code java.util.ImmutableCollections} to {@code fields}, making + * them {@linkplain Field#setAccessible accessible} in the process. + */ + private static void addImmutableCollectionsFields(List fields) { + Class c = List.of().getClass().getDeclaringClass(); + GraalError.guarantee(c.getName().equals("java.util.ImmutableCollections"), "Incompatible ImmutableCollections class"); + for (Field f : c.getDeclaredFields()) { + if (f.getName().startsWith("EMPTY")) { + int modifiers = f.getModifiers(); + GraalError.guarantee(Modifier.isStatic(modifiers), "Expect %s to be static", f); + GraalError.guarantee(Modifier.isFinal(modifiers), "Expect %s to be final", f); + GraalError.guarantee(!f.getType().isPrimitive(), "Expect %s to be non-primitive", f); + f.setAccessible(true); + fields.add(f); + } + } + } + /** * Describes the path from a root object to a target object. That is, the sequence of field and * array reads performed on the root object to access the target object. diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java index 9d841571cdab..ddf7b0bcb561 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java @@ -323,7 +323,7 @@ record FieldIdentifier(String tid, String name) { } protected final Set> heapScannerTasks = ConcurrentHashMap.newKeySet(); - private final ImageLayerSnapshotUtil imageLayerSnapshotUtil; + private ImageLayerSnapshotUtil imageLayerSnapshotUtil; private ImageLayerLoaderHelper imageLayerLoaderHelper; protected final Map typeToConstant = new ConcurrentHashMap<>(); protected final Map stringToConstant = new ConcurrentHashMap<>(); @@ -343,14 +343,17 @@ public record FilePaths(Path snapshot, Path snapshotGraphs) { } public ImageLayerLoader() { - this(new ImageLayerSnapshotUtil(), List.of()); + this(List.of()); } - public ImageLayerLoader(ImageLayerSnapshotUtil imageLayerSnapshotUtil, List loadPaths) { - this.imageLayerSnapshotUtil = imageLayerSnapshotUtil; + public ImageLayerLoader(List loadPaths) { this.loadPaths = loadPaths; } + public void setImageLayerSnapshotUtil(ImageLayerSnapshotUtil imageLayerSnapshotUtil) { + this.imageLayerSnapshotUtil = imageLayerSnapshotUtil; + } + public AnalysisUniverse getUniverse() { return universe; } @@ -809,19 +812,12 @@ public AnalysisParsedGraph getAnalysisParsedGraph(AnalysisMethod analysisMethod) EconomicMap methodData = getMethodData(analysisMethod); String encodedAnalyzedGraph = readEncodedGraph(methodData, ANALYSIS_PARSED_GRAPH_TAG); Boolean intrinsic = get(methodData, INTRINSIC_TAG); - /* - * Methods without a persisted graph are folded and static methods. - * - * GR-55278: graphs that contain a reference to a $$Lambda cannot be persisted as well. - */ - if (encodedAnalyzedGraph != null) { - EncodedGraph analyzedGraph = (EncodedGraph) ObjectCopier.decode(imageLayerSnapshotUtil.getGraphDecoder(this, analysisMethod, universe.getSnippetReflection()), encodedAnalyzedGraph); - if (hasStrengthenedGraph(analysisMethod)) { - loadAllAnalysisElements(readEncodedGraph(methodData, STRENGTHENED_GRAPH_TAG)); - } - return new AnalysisParsedGraph(analyzedGraph, intrinsic); + EncodedGraph analyzedGraph = (EncodedGraph) ObjectCopier.decode(imageLayerSnapshotUtil.getGraphDecoder(this, analysisMethod, universe.getSnippetReflection()), encodedAnalyzedGraph); + if (hasStrengthenedGraph(analysisMethod)) { + loadAllAnalysisElements(readEncodedGraph(methodData, STRENGTHENED_GRAPH_TAG)); } - throw AnalysisError.shouldNotReachHere("The method " + analysisMethod + " does not have a graph from the base layer"); + afterGraphDecodeHook(analyzedGraph); + return new AnalysisParsedGraph(analyzedGraph, intrinsic); } private String readEncodedGraph(EconomicMap methodData, String elementIdentifier) { @@ -856,12 +852,12 @@ public void setStrengthenedGraph(AnalysisMethod analysisMethod) { EconomicMap methodData = getMethodData(analysisMethod); String encodedAnalyzedGraph = readEncodedGraph(methodData, STRENGTHENED_GRAPH_TAG); EncodedGraph analyzedGraph = (EncodedGraph) ObjectCopier.decode(imageLayerSnapshotUtil.getGraphDecoder(this, analysisMethod, universe.getSnippetReflection()), encodedAnalyzedGraph); - processGraph(analyzedGraph); + afterGraphDecodeHook(analyzedGraph); analysisMethod.setAnalyzedGraph(analyzedGraph); } @SuppressWarnings("unused") - protected void processGraph(EncodedGraph encodedGraph) { + protected void afterGraphDecodeHook(EncodedGraph encodedGraph) { } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java index 3d30d926ac03..91eb1ca10add 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java @@ -24,17 +24,13 @@ */ package com.oracle.graal.pointsto.heap; +import java.io.IOException; import java.lang.reflect.Executable; import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import java.util.Locale; +import java.util.Map; import java.util.Set; -import org.graalvm.word.LocationIdentity; - import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -45,16 +41,11 @@ import com.oracle.graal.pointsto.meta.PointsToAnalysisType; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.graal.pointsto.util.AnalysisFuture; -import com.oracle.svm.util.ModuleSupport; -import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; -import jdk.graal.compiler.graph.NodeClass; import jdk.graal.compiler.nodes.EncodedGraph; import jdk.graal.compiler.nodes.FieldLocationIdentity; -import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.util.ObjectCopier; -import jdk.vm.ci.meta.JavaKind; public class ImageLayerSnapshotUtil { public static final String FILE_NAME_PREFIX = "layer-snapshot-"; @@ -164,33 +155,28 @@ public class ImageLayerSnapshotUtil { public static final String IMAGE_SINGLETON_KEYS = "image singleton keys"; public static final String IMAGE_SINGLETON_OBJECTS = "image singleton objects"; - protected final List externalValues; + protected final List externalValueFields; + /** This needs to be initialized after analysis, as some fields are not available before. */ + protected Map externalValues; - @SuppressWarnings("this-escape") public ImageLayerSnapshotUtil() { - externalValues = new ArrayList<>(); - - addExternalValues(LocationIdentity.class); - addExternalValues(NamedLocationIdentity.class); - } - - protected void addExternalValues(Class clazz) { - Arrays.stream(clazz.getDeclaredFields()).filter(this::shouldAddExternalValue).forEach(this::addExternalValue); - } - - private void addExternalValue(Field f) { - ModuleSupport.accessModuleByClass(ModuleSupport.Access.OPEN, ImageLayerSnapshotUtil.class, f.getDeclaringClass()); - f.setAccessible(true); - externalValues.add(f); - } - - private boolean shouldAddExternalValue(Field f) { - Class type = f.getType(); - return Modifier.isStatic(f.getModifiers()) && shouldAddExternalValue(type); + try { + this.externalValueFields = ObjectCopier.getExternalValueFields(); + } catch (IOException e) { + throw AnalysisError.shouldNotReachHere("Unexpected exception when creating external value fields list", e); + } } - protected boolean shouldAddExternalValue(Class type) { - return LocationIdentity.class.isAssignableFrom(type); + /** + * Compute and cache the final {@code externalValues} map in + * {@link ImageLayerSnapshotUtil#externalValues} to avoid computing it for each graph. + *

+ * A single {@code ObjectCopier.Encoder} instance could alternatively be used for all graphs, + * but it would then be impossible to process multiple graphs concurrently. + */ + public void initializeExternalValues() { + assert externalValues == null : "The external values should be computed only once."; + externalValues = ObjectCopier.Encoder.gatherExternalValues(externalValueFields); } public static String snapshotFileName(String imageName) { @@ -240,15 +226,13 @@ public GraphDecoder getGraphDecoder(ImageLayerLoader imageLayerLoader, AnalysisM public static class GraphEncoder extends ObjectCopier.Encoder { @SuppressWarnings("this-escape") - public GraphEncoder(List externalValues, ImageLayerWriter imageLayerWriter) { + public GraphEncoder(Map externalValues, ImageLayerWriter imageLayerWriter) { super(externalValues); - addBuiltin(new NodeClassBuiltIn()); addBuiltin(new ImageHeapConstantBuiltIn(imageLayerWriter, null)); addBuiltin(new AnalysisTypeBuiltIn(imageLayerWriter, null)); addBuiltin(new AnalysisMethodBuiltIn(imageLayerWriter, null, null)); addBuiltin(new AnalysisFieldBuiltIn(imageLayerWriter, null)); addBuiltin(new FieldLocationIdentityBuiltIn(imageLayerWriter, null)); - addBuiltin(new NamedLocationIdentityArrayBuiltIn()); } } @@ -259,13 +243,11 @@ public static class GraphDecoder extends ObjectCopier.Decoder { public GraphDecoder(ClassLoader classLoader, ImageLayerLoader imageLayerLoader, AnalysisMethod analysisMethod) { super(classLoader); this.imageLayerLoader = imageLayerLoader; - addBuiltin(new NodeClassBuiltIn()); addBuiltin(new ImageHeapConstantBuiltIn(null, imageLayerLoader)); addBuiltin(new AnalysisTypeBuiltIn(null, imageLayerLoader)); addBuiltin(new AnalysisMethodBuiltIn(null, imageLayerLoader, analysisMethod)); addBuiltin(new AnalysisFieldBuiltIn(null, imageLayerLoader)); addBuiltin(new FieldLocationIdentityBuiltIn(null, imageLayerLoader)); - addBuiltin(new NamedLocationIdentityArrayBuiltIn()); } @Override @@ -274,23 +256,6 @@ public Class loadClass(String className) { } } - public static class NodeClassBuiltIn extends ObjectCopier.Builtin { - protected NodeClassBuiltIn() { - super(NodeClass.class); - } - - @Override - public String encode(ObjectCopier.Encoder encoder, Object obj) { - return ((NodeClass) obj).getClazz().getName(); - } - - @Override - protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, String encoding, String encoded) { - Class holder = ReflectionUtil.lookupClass(false, encoded); - return ReflectionUtil.readField(holder, "TYPE", null); - } - } - public static class ImageHeapConstantBuiltIn extends ObjectCopier.Builtin { private final ImageLayerWriter imageLayerWriter; private final ImageLayerLoader imageLayerLoader; @@ -430,25 +395,4 @@ private static String encodeField(AnalysisField field, ImageLayerWriter imageLay private static AnalysisField decodeField(ImageLayerLoader imageLayerLoader, String encoded) { return imageLayerLoader.getAnalysisField(Integer.parseInt(encoded)); } - - public static class NamedLocationIdentityArrayBuiltIn extends ObjectCopier.Builtin { - protected NamedLocationIdentityArrayBuiltIn() { - super(NamedLocationIdentity.class); - } - - @Override - public String encode(ObjectCopier.Encoder encoder, Object obj) { - NamedLocationIdentity namedLocationIdentity = (NamedLocationIdentity) obj; - AnalysisError.guarantee(NamedLocationIdentity.isArrayLocation(namedLocationIdentity), - "The named location identity %s should be encoded using an external value.", namedLocationIdentity); - String name = namedLocationIdentity.toString().split("Array: ")[1]; - /* Capitalizing the first letter gets the name of the Enum value */ - return name.substring(0, 1).toUpperCase(Locale.ROOT) + name.substring(1); - } - - @Override - protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, String encoding, String encoded) { - return NamedLocationIdentity.getArrayLocation(JavaKind.valueOf(encoded)); - } - } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java index a7915e360a78..483756d78f6c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java @@ -90,7 +90,6 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.TID_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.TYPES_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.VALUE_TAG; -import static jdk.graal.compiler.java.LambdaUtils.LAMBDA_CLASS_NAME_SUBSTRING; import java.io.IOException; import java.io.PrintWriter; @@ -127,6 +126,7 @@ import com.oracle.svm.util.FileDumpingUtil; import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.java.LambdaUtils; import jdk.graal.compiler.nodes.EncodedGraph; import jdk.graal.compiler.nodes.spi.IdentityHashCodeProvider; import jdk.graal.compiler.util.ObjectCopier; @@ -140,7 +140,7 @@ public class ImageLayerWriter { static final Charset GRAPHS_CHARSET = Charset.defaultCharset(); - protected final ImageLayerSnapshotUtil imageLayerSnapshotUtil; + protected ImageLayerSnapshotUtil imageLayerSnapshotUtil; private ImageLayerWriterHelper imageLayerWriterHelper; private ImageHeap imageHeap; protected AnalysisUniverse aUniverse; @@ -203,13 +203,12 @@ void finish() { } public ImageLayerWriter() { - this(true, new ImageLayerSnapshotUtil()); + this(true); } @SuppressWarnings({"this-escape", "unused"}) - public ImageLayerWriter(boolean useSharedLayerGraphs, ImageLayerSnapshotUtil imageLayerSnapshotUtil) { + public ImageLayerWriter(boolean useSharedLayerGraphs) { this.useSharedLayerGraphs = useSharedLayerGraphs; - this.imageLayerSnapshotUtil = imageLayerSnapshotUtil; this.jsonMap = EconomicMap.create(); this.constantsToRelink = new ArrayList<>(); this.persistedTypeIds = ConcurrentHashMap.newKeySet(); @@ -220,6 +219,10 @@ public ImageLayerWriter(boolean useSharedLayerGraphs, ImageLayerSnapshotUtil ima this.constantsMap = new ConcurrentHashMap<>(); } + public void setImageLayerSnapshotUtil(ImageLayerSnapshotUtil imageLayerSnapshotUtil) { + this.imageLayerSnapshotUtil = imageLayerSnapshotUtil; + } + public void setInternedStringsIdentityMap(IdentityHashMap map) { this.internedStringsIdentityMap = map; } @@ -257,6 +260,10 @@ public void dumpFiles() { }); } + public void initializeExternalValues() { + imageLayerSnapshotUtil.initializeExternalValues(); + } + public void persistImageHeapSize(long imageHeapSize) { jsonMap.put(IMAGE_HEAP_SIZE_TAG, String.valueOf(imageHeapSize)); } @@ -449,7 +456,7 @@ public void persistAnalysisParsedGraph(AnalysisMethod method) { Object analyzedGraph = method.getGraph(); if (analyzedGraph instanceof AnalysisParsedGraph analysisParsedGraph) { if (!methodMap.containsKey(INTRINSIC_TAG)) { - if (!persistGraph(analysisParsedGraph.getEncodedGraph(), methodMap, ANALYSIS_PARSED_GRAPH_TAG)) { + if (!persistGraph(method, analysisParsedGraph.getEncodedGraph(), methodMap, ANALYSIS_PARSED_GRAPH_TAG)) { return; } methodMap.put(INTRINSIC_TAG, analysisParsedGraph.isIntrinsic()); @@ -462,22 +469,17 @@ public void persistMethodStrengthenedGraph(AnalysisMethod method) { if (!methodMap.containsKey(STRENGTHENED_GRAPH_TAG)) { EncodedGraph analyzedGraph = method.getAnalyzedGraph(); - persistGraph(analyzedGraph, methodMap, STRENGTHENED_GRAPH_TAG); + persistGraph(method, analyzedGraph, methodMap, STRENGTHENED_GRAPH_TAG); } } - private boolean persistGraph(EncodedGraph analyzedGraph, EconomicMap methodMap, String graphTag) { + private boolean persistGraph(AnalysisMethod method, EncodedGraph analyzedGraph, EconomicMap methodMap, String graphTag) { if (!useSharedLayerGraphs) { return false; } String encodedGraph = ObjectCopier.encode(imageLayerSnapshotUtil.getGraphEncoder(this), analyzedGraph); - /* - * The ObjectCopier cannot look up Lambda types by reflection, so it cannot decode a graph - * that contains a reference to a Lambda. Since the original Class is needed, the analysis - * id cannot be used either. - */ - if (encodedGraph.contains(LAMBDA_CLASS_NAME_SUBSTRING)) { - return false; + if (encodedGraph.contains(LambdaUtils.LAMBDA_CLASS_NAME_SUBSTRING)) { + throw AnalysisError.shouldNotReachHere("The graph for the method %s contains a reference to a lambda type, which cannot be decoded: %s".formatted(method, encodedGraph)); } String location = graphsOutput.add(encodedGraph); methodMap.put(graphTag, location); @@ -648,13 +650,4 @@ private static Object getPrimitiveConstantValue(PrimitiveConstant primitiveConst protected boolean delegateProcessing(List> data, Object constant) { return false; } - - public boolean persistedMethodGraph(AnalysisMethod method) { - String name = imageLayerSnapshotUtil.getMethodIdentifier(method); - if (methodsMap.containsKey(name)) { - EconomicMap methodMap = methodsMap.get(name); - return methodMap.get(ANALYSIS_PARSED_GRAPH_TAG) != null || methodMap.get(STRENGTHENED_GRAPH_TAG) != null; - } - return false; - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/ImageLayerBuildingSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/ImageLayerBuildingSupport.java index d0b1001dddf6..d9de1f1dbbaa 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/ImageLayerBuildingSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/ImageLayerBuildingSupport.java @@ -62,7 +62,7 @@ * Note this is intentionally not a LayeredImageSingleton itself to prevent circular dependencies. */ public abstract class ImageLayerBuildingSupport { - protected final boolean buildingImageLayer; + public final boolean buildingImageLayer; private final boolean buildingInitialLayer; private final boolean buildingApplicationLayer; @@ -70,30 +70,16 @@ protected ImageLayerBuildingSupport(boolean buildingImageLayer, boolean building this.buildingImageLayer = buildingImageLayer; this.buildingInitialLayer = buildingInitialLayer; this.buildingApplicationLayer = buildingApplicationLayer; - - if (buildingImageLayer) { - openModules(); - } - } /** * To allow the {@link ObjectCopier} to access private fields by reflection, some modules needs * to be opened when a layer is built. */ - private static void openModules() { + public static void openModules() { ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, "java.base", "java.lang"); ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, "java.base", "java.util"); ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, "java.base", "java.util.concurrent"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, "org.graalvm.nativeimage.builder", "com.oracle.svm.core.c"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, "org.graalvm.nativeimage.builder", "com.oracle.svm.core.c.function"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, "org.graalvm.nativeimage.builder", "com.oracle.svm.core.c.struct"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, "org.graalvm.nativeimage.builder", "com.oracle.svm.core.graal.code"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, "org.graalvm.nativeimage.builder", "com.oracle.svm.core.graal.stackvalue"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, "org.graalvm.nativeimage.builder", "com.oracle.svm.core.snippets"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, "org.graalvm.nativeimage.builder", "com.oracle.svm.core.threadlocal"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, "org.graalvm.nativeimage.builder", "com.oracle.svm.hosted.imagelayer"); - ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, "org.graalvm.nativeimage.builder", "com.oracle.svm.hosted.meta"); } private static ImageLayerBuildingSupport singleton() { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java index a7a60d0bd807..7528d8f1e8e5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java @@ -65,6 +65,7 @@ import com.oracle.svm.hosted.config.HybridLayout; import com.oracle.svm.hosted.config.HybridLayoutSupport; import com.oracle.svm.hosted.heap.SVMImageLayerLoaderHelper; +import com.oracle.svm.hosted.heap.SVMImageLayerSnapshotUtil; import com.oracle.svm.hosted.heap.SVMImageLayerWriterHelper; import com.oracle.svm.hosted.image.LIRNativeImageCodeCache; import com.oracle.svm.hosted.image.NativeImageCodeCache; @@ -241,6 +242,10 @@ public SVMImageLayerLoaderHelper createSVMImageLayerLoaderHelper() { return new SVMImageLayerLoaderHelper(HostedImageLayerBuildingSupport.singleton().getLoader()); } + public SVMImageLayerSnapshotUtil createSVMImageLayerSnapshotUtil(ImageClassLoader imageClassLoader) { + return new SVMImageLayerSnapshotUtil(imageClassLoader); + } + public CompileQueue createCompileQueue(DebugContext debug, FeatureHandler featureHandler, HostedUniverse hostedUniverse, RuntimeConfiguration runtimeConfiguration, boolean deoptimizeAll) { return new CompileQueue(debug, featureHandler, hostedUniverse, runtimeConfiguration, deoptimizeAll, Collections.emptyList()); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 2e0d358f289d..2b6428215d6c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -98,6 +98,7 @@ import com.oracle.graal.pointsto.heap.HostedValuesProvider; import com.oracle.graal.pointsto.heap.ImageHeap; import com.oracle.graal.pointsto.heap.ImageHeapScanner; +import com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil; import com.oracle.graal.pointsto.heap.ImageLayerWriter; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod; @@ -233,6 +234,7 @@ import com.oracle.svm.hosted.heap.SVMImageHeapScanner; import com.oracle.svm.hosted.heap.SVMImageHeapVerifier; import com.oracle.svm.hosted.heap.SVMImageLayerLoader; +import com.oracle.svm.hosted.heap.SVMImageLayerWriter; import com.oracle.svm.hosted.image.AbstractImage; import com.oracle.svm.hosted.image.AbstractImage.NativeImageKind; import com.oracle.svm.hosted.image.NativeImageCodeCache; @@ -530,12 +532,8 @@ public void run(Map entryPoints, setSystemPropertiesForImageLate(k); var hostedOptionValues = new HostedOptionValues(optionProvider.getHostedValues()); - HostedImageLayerBuildingSupport imageLayerSupport = HostedImageLayerBuildingSupport.initialize(hostedOptionValues); - SVMImageLayerLoader imageLayerLoader = imageLayerSupport.getLoader(); - if (imageLayerLoader != null) { - imageLayerLoader.setImageClassLoader(loader); - } - ImageSingletonsSupportImpl.HostedManagement.install(new ImageSingletonsSupportImpl.HostedManagement(imageLayerLoader != null || imageLayerSupport.getWriter() != null), imageLayerSupport); + HostedImageLayerBuildingSupport imageLayerSupport = HostedImageLayerBuildingSupport.initialize(hostedOptionValues, loader); + ImageSingletonsSupportImpl.HostedManagement.install(new ImageSingletonsSupportImpl.HostedManagement(imageLayerSupport.buildingImageLayer), imageLayerSupport); ImageSingletons.add(LayeredImageSingletonSupport.class, (LayeredImageSingletonSupport) ImageSingletonsSupportImpl.get()); ImageSingletons.add(ProgressReporter.class, reporter); @@ -613,6 +611,10 @@ protected void doRun(Map entryPoints, JavaMainSupport j BeforeUniverseBuildingAccessImpl beforeUniverseBuildingConfig = new BeforeUniverseBuildingAccessImpl(featureHandler, loader, debug, hMetaAccess); featureHandler.forEachFeature(feature -> feature.beforeUniverseBuilding(beforeUniverseBuildingConfig)); + if (ImageLayerBuildingSupport.buildingSharedLayer()) { + HostedImageLayerBuildingSupport.singleton().getWriter().initializeExternalValues(); + } + new UniverseBuilder(aUniverse, bb.getMetaAccess(), hUniverse, hMetaAccess, HostedConfiguration.instance().createStrengthenGraphs(bb, hUniverse), bb.getUnsupportedFeatures()).build(debug); @@ -963,13 +965,21 @@ protected void setupNativeImage(OptionValues options, Map loadPaths) { - super(new SVMImageLayerSnapshotUtil(), loadPaths); + public SVMImageLayerLoader(List loadPaths, ImageClassLoader imageClassLoader) { + super(loadPaths); dynamicHubArrayHubField = ReflectionUtil.lookupField(DynamicHub.class, "arrayHub"); + this.imageClassLoader = imageClassLoader; } public void setHostedUniverse(HostedUniverse hostedUniverse) { this.hostedUniverse = hostedUniverse; } - public void setImageClassLoader(ImageClassLoader imageClassLoader) { - this.imageClassLoader = imageClassLoader; - } - public HostedUniverse getHostedUniverse() { return hostedUniverse; } @@ -197,13 +192,11 @@ protected void initializeBaseLayerMethod(AnalysisMethod analysisMethod, Economic } @Override - protected void processGraph(EncodedGraph encodedGraph) { - super.processGraph(encodedGraph); - Object[] objects = encodedGraph.getObjects(); - for (Object object : objects) { - if (object instanceof VMThreadLocalInfo vmThreadLocalInfo) { - LayeredVMThreadLocalCollector layeredVMThreadLocalCollector = (LayeredVMThreadLocalCollector) ImageSingletons.lookup(VMThreadLocalCollector.class); - layeredVMThreadLocalCollector.registerPriorThreadLocalInfo(vmThreadLocalInfo); + protected void afterGraphDecodeHook(EncodedGraph encodedGraph) { + super.afterGraphDecodeHook(encodedGraph); + for (int i = 0; i < encodedGraph.getNumObjects(); ++i) { + if (encodedGraph.getObject(i) instanceof CGlobalDataInfo cGlobalDataInfo) { + encodedGraph.setObject(i, CGlobalDataFeature.singleton().registerAsAccessedOrGet(cGlobalDataInfo.getData())); } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java index a829d10a6a27..48d646d25d74 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerSnapshotUtil.java @@ -31,13 +31,15 @@ import java.lang.reflect.Executable; import java.lang.reflect.Field; +import java.net.URI; +import java.net.URISyntaxException; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import org.graalvm.nativeimage.ImageSingletons; + import com.oracle.graal.pointsto.heap.ImageLayerLoader; import com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil; import com.oracle.graal.pointsto.heap.ImageLayerWriter; @@ -45,35 +47,16 @@ import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.svm.core.SubstrateDiagnostics; +import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.core.c.struct.CInterfaceLocationIdentity; -import com.oracle.svm.core.deopt.DeoptimizationCounters; -import com.oracle.svm.core.graal.snippets.DeoptTester; -import com.oracle.svm.core.graal.snippets.StackOverflowCheckImpl; -import com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets; -import com.oracle.svm.core.heap.NoAllocationVerifier; import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.identityhashcode.IdentityHashCodeSupport; -import com.oracle.svm.core.jfr.JfrThreadLocal; -import com.oracle.svm.core.jfr.events.JfrAllocationEvents; -import com.oracle.svm.core.jfr.events.ThreadCPULoadEvent; -import com.oracle.svm.core.jfr.sampler.AbstractJfrExecutionSampler; -import com.oracle.svm.core.jni.JNIObjectHandles; -import com.oracle.svm.core.jni.JNIThreadLocalEnvironment; -import com.oracle.svm.core.jni.JNIThreadLocalPendingException; -import com.oracle.svm.core.jni.JNIThreadLocalPrimitiveArrayViews; -import com.oracle.svm.core.jni.JNIThreadOwnedMonitors; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.reflect.serialize.SerializationSupport; -import com.oracle.svm.core.snippets.ExceptionUnwind; -import com.oracle.svm.core.snippets.ImplicitExceptions; -import com.oracle.svm.core.stack.JavaFrameAnchors; -import com.oracle.svm.core.thread.JavaThreads; -import com.oracle.svm.core.thread.PlatformThreads; -import com.oracle.svm.core.thread.Safepoint; -import com.oracle.svm.core.thread.ThreadingSupportImpl; -import com.oracle.svm.core.thread.VMThreads; import com.oracle.svm.core.threadlocal.FastThreadLocal; +import com.oracle.svm.core.threadlocal.VMThreadLocalInfo; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.ImageClassLoader; +import com.oracle.svm.hosted.VMFeature; import com.oracle.svm.hosted.code.FactoryMethod; import com.oracle.svm.hosted.code.IncompatibleClassChangeFallbackMethod; import com.oracle.svm.hosted.meta.HostedArrayClass; @@ -81,6 +64,8 @@ import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedSnippetReflectionProvider; import com.oracle.svm.hosted.meta.HostedType; +import com.oracle.svm.hosted.thread.VMThreadLocalCollector; +import com.oracle.svm.util.ModuleSupport; import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; @@ -104,46 +89,59 @@ public class SVMImageLayerSnapshotUtil extends ImageLayerSnapshotUtil { protected static final Set dynamicHubRelinkedFields = Set.of(companion, classInitializationInfo, name, superHub, componentType, arrayHub); protected final Map> fieldsToRelink = new HashMap<>(); + private final ImageClassLoader imageClassLoader; @SuppressWarnings("this-escape") - public SVMImageLayerSnapshotUtil() { + public SVMImageLayerSnapshotUtil(ImageClassLoader imageClassLoader) { super(); - addExternalValues(DeoptTester.class); - addExternalValues(JfrThreadLocal.class); - addExternalValues(JfrAllocationEvents.class); - addExternalValues(AbstractJfrExecutionSampler.class); - addExternalValues(ThreadCPULoadEvent.class); - addExternalValues(JNIObjectHandles.class); - addExternalValues(JNIThreadLocalPendingException.class); - addExternalValues(JNIThreadLocalPrimitiveArrayViews.class); - addExternalValues(JNIThreadOwnedMonitors.class); - addExternalValues(JNIThreadLocalEnvironment.class); - addExternalValues(ExceptionUnwind.class); - addExternalValues(JavaThreads.class); - addExternalValues(ImplicitExceptions.class); - addExternalValues(IdentityHashCodeSupport.class); - addExternalValues(StackOverflowCheckImpl.class); - addExternalValues(CInterfaceLocationIdentity.class); - addExternalValues(JavaFrameAnchors.class); - addExternalValues(PlatformThreads.class); - addExternalValues(VMThreads.class); - addExternalValues(VMThreads.StatusSupport.class); - addExternalValues(VMThreads.SafepointBehavior.class); - addExternalValues(VMThreads.ActionOnTransitionToJavaSupport.class); - addExternalValues(Safepoint.class); - addExternalValues(NoAllocationVerifier.class); - addExternalValues(ThreadingSupportImpl.class); - addExternalValues(ThreadingSupportImpl.RecurringCallbackTimer.class); - addExternalValues(DeoptimizationCounters.class); - addExternalValues(Objects.requireNonNull(ReflectionUtil.lookupClass(false, "com.oracle.svm.core.genscavenge.ThreadLocalAllocation"))); - addExternalValues(Objects.requireNonNull(ReflectionUtil.lookupClass(false, "com.oracle.svm.core.genscavenge.graal.BarrierSnippets"))); - addExternalValues(SubstrateDiagnostics.class); - addExternalValues(SubstrateAllocationSnippets.class); + this.imageClassLoader = imageClassLoader; + addSVMExternalValueFields(); } - @Override - protected boolean shouldAddExternalValue(Class type) { - return FastThreadLocal.class.isAssignableFrom(type) || super.shouldAddExternalValue(type); + /** + * Gets the externalValues (like {@link ObjectCopier#getExternalValueFields()}) of classes from + * the SVM core classes. + */ + private void addSVMExternalValueFields() { + for (URI svmURI : getBuilderLocations()) { + for (String className : imageClassLoader.classLoaderSupport.classes(svmURI)) { + try { + Class clazz = imageClassLoader.forName(className); + + String packageName = clazz.getPackageName(); + if (!shouldScanPackage(packageName)) { + continue; + } + + /* The ObjectCopier needs to access the static fields by reflection */ + Module module = clazz.getModule(); + ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, ObjectCopier.class, false, module.getName(), packageName); + + ObjectCopier.addStaticFinalObjectFields(clazz, externalValueFields); + } catch (ClassNotFoundException e) { + throw AnalysisError.shouldNotReachHere("The class %s from the modulePath %s was not found".formatted(className, svmURI.getPath()), e); + } + } + } + } + + protected Set getBuilderLocations() { + try { + Class vmFeatureClass = ImageSingletons.lookup(VMFeature.class).getClass(); + URI svmURI = VMFeature.class.getProtectionDomain().getCodeSource().getLocation().toURI(); + if (vmFeatureClass == VMFeature.class) { + return Set.of(svmURI); + } else { + return Set.of(svmURI, vmFeatureClass.getProtectionDomain().getCodeSource().getLocation().toURI()); + } + } catch (URISyntaxException e) { + throw VMError.shouldNotReachHere("Error when trying to get SVM URI", e); + } + } + + @SuppressWarnings("unused") + protected boolean shouldScanPackage(String packageName) { + return true; } @Override @@ -232,7 +230,7 @@ public GraphDecoder getGraphDecoder(ImageLayerLoader imageLayerLoader, AnalysisM public static class SVMGraphEncoder extends GraphEncoder { @SuppressWarnings("this-escape") - public SVMGraphEncoder(List externalValues, ImageLayerWriter imageLayerWriter) { + public SVMGraphEncoder(Map externalValues, ImageLayerWriter imageLayerWriter) { super(externalValues, imageLayerWriter); addBuiltin(new HostedTypeBuiltIn(null)); addBuiltin(new HostedMethodBuiltIn(null)); @@ -240,6 +238,7 @@ public SVMGraphEncoder(List externalValues, ImageLayerWriter imageLayerWr addBuiltin(new HostedSnippetReflectionProviderBuiltIn(null)); addBuiltin(new CInterfaceLocationIdentityBuiltIn()); addBuiltin(new FastThreadLocalLocationIdentityBuiltIn()); + addBuiltin(new VMThreadLocalInfoBuiltIn()); } } @@ -253,6 +252,7 @@ public SVMGraphDecoder(ClassLoader classLoader, SVMImageLayerLoader svmImageLaye addBuiltin(new HostedSnippetReflectionProviderBuiltIn(snippetReflectionProvider)); addBuiltin(new CInterfaceLocationIdentityBuiltIn()); addBuiltin(new FastThreadLocalLocationIdentityBuiltIn()); + addBuiltin(new VMThreadLocalInfoBuiltIn()); } } @@ -357,18 +357,46 @@ protected FastThreadLocalLocationIdentityBuiltIn() { protected String encode(ObjectCopier.Encoder encoder, Object obj) { FastThreadLocal.FastThreadLocalLocationIdentity fastThreadLocalLocationIdentity = (FastThreadLocal.FastThreadLocalLocationIdentity) obj; FastThreadLocal fastThreadLocal = ReflectionUtil.readField(FastThreadLocal.FastThreadLocalLocationIdentity.class, "this$0", fastThreadLocalLocationIdentity); - Field staticField = encoder.getExternalValues().get(fastThreadLocal); - return staticField.getDeclaringClass().getName() + ":" + staticField.getName(); + return encodeStaticField(encoder, fastThreadLocal); } @Override protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, String encoding, String encoded) { - String[] fieldParts = encoded.split(":"); - String className = fieldParts[0]; - String fieldName = fieldParts[1]; - Class declaringClass = ReflectionUtil.lookupClass(false, className); - FastThreadLocal fastThreadLocal = ReflectionUtil.readStaticField(declaringClass, fieldName); + FastThreadLocal fastThreadLocal = getObjectFromStaticField(encoded); return fastThreadLocal.getLocationIdentity(); } } + + public static class VMThreadLocalInfoBuiltIn extends ObjectCopier.Builtin { + protected VMThreadLocalInfoBuiltIn() { + super(VMThreadLocalInfo.class); + } + + @Override + protected String encode(ObjectCopier.Encoder encoder, Object obj) { + VMThreadLocalInfo vmThreadLocalInfo = (VMThreadLocalInfo) obj; + VMThreadLocalCollector vmThreadLocalCollector = ImageSingletons.lookup(VMThreadLocalCollector.class); + FastThreadLocal fastThreadLocal = vmThreadLocalCollector.getThreadLocal(vmThreadLocalInfo); + return encodeStaticField(encoder, fastThreadLocal); + } + + @Override + protected Object decode(ObjectCopier.Decoder decoder, Class concreteType, String encoding, String encoded) { + FastThreadLocal fastThreadLocal = getObjectFromStaticField(encoded); + return ImageSingletons.lookup(VMThreadLocalCollector.class).forFastThreadLocal(fastThreadLocal); + } + } + + private static String encodeStaticField(ObjectCopier.Encoder encoder, Object object) { + Field staticField = encoder.getExternalValues().get(object); + return staticField.getDeclaringClass().getName() + ":" + staticField.getName(); + } + + private static T getObjectFromStaticField(String staticField) { + String[] fieldParts = staticField.split(":"); + String className = fieldParts[0]; + String fieldName = fieldParts[1]; + Class declaringClass = ReflectionUtil.lookupClass(false, className); + return ReflectionUtil.readStaticField(declaringClass, fieldName); + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java index a2094f61ec04..e49d2a6bbeed 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java @@ -101,7 +101,7 @@ public class SVMImageLayerWriter extends ImageLayerWriter { private HostedUniverse hUniverse; public SVMImageLayerWriter(boolean useSharedLayerGraphs) { - super(useSharedLayerGraphs, new SVMImageLayerSnapshotUtil()); + super(useSharedLayerGraphs); } public void setNativeImageHeap(NativeImageHeap nativeImageHeap) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java index b773606d3811..5b3a405c4a5c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java @@ -53,6 +53,7 @@ import com.oracle.svm.core.util.ArchiveSupport; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.ImageClassLoader; import com.oracle.svm.hosted.NativeImageGenerator; import com.oracle.svm.hosted.c.NativeLibraries; import com.oracle.svm.hosted.heap.SVMImageLayerLoader; @@ -164,27 +165,35 @@ private static boolean isLayerOptionEnabled(HostedOptionKey threadLocalAssignmentMap; - - /** - * With the inlining of prior layer methods, it is possible for VMThreadLocalsInfos from prior - * layers to exist in graphs. We must record these instances so that they can have offsets - * assigned. In addition, now it is possible for MultipleThreadLocals to exist which are - * assigned to the same offset; however, this does not affect correctness, as all offsets are - * assigned in the initial layer and during lowering this discrepancy disappears. - */ - final Set priorLayerThreadLocals; private final boolean initialLayer; private int nextOffset; @@ -83,14 +71,9 @@ private LayeredVMThreadLocalCollector(Map threadLocalAssignm this.threadLocalAssignmentMap = threadLocalAssignmentMap; initialLayer = ImageLayerBuildingSupport.buildingInitialLayer(); - this.priorLayerThreadLocals = initialLayer ? null : ConcurrentHashMap.newKeySet(); this.nextOffset = nextOffset; } - public void registerPriorThreadLocalInfo(VMThreadLocalInfo info) { - priorLayerThreadLocals.add(info); - } - @Override public Object apply(Object source) { /* @@ -114,12 +97,12 @@ public int sortAndAssignOffsets() { } else { assert nextOffset != -1; - Stream.concat(priorLayerThreadLocals.stream(), threadLocals.values().stream()).forEach(info -> { + for (VMThreadLocalInfo info : threadLocals.values()) { var assignment = threadLocalAssignmentMap.get(info.name); info.offset = assignment.offset(); assert assignment.size() == calculateSize(info) : Assertions.errorMessage("Mismatch in computed size: ", assignment.size(), calculateSize(info), info.name); info.sizeInBytes = assignment.size(); - }); + } } return nextOffset; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadLocalCollector.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadLocalCollector.java index 28d26cc2229d..ea19d54a6206 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadLocalCollector.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/thread/VMThreadLocalCollector.java @@ -62,6 +62,7 @@ public static class Options { } Map threadLocals; + Map infoToThreadLocals; private boolean sealed; final boolean validateUniqueNames; final Set seenNames; @@ -78,16 +79,21 @@ protected VMThreadLocalCollector(boolean validateUniqueNames) { public void installThreadLocalMap() { assert threadLocals == null : threadLocals; threadLocals = ObservableImageHeapMapProvider.create(); + infoToThreadLocals = new ConcurrentHashMap<>(); } - @Override - public Object apply(Object source) { - if (source instanceof FastThreadLocal threadLocal) { + public VMThreadLocalInfo forFastThreadLocal(FastThreadLocal threadLocal) { + VMThreadLocalInfo localInfo = threadLocals.get(threadLocal); + if (localInfo == null) { if (sealed) { - assert threadLocals.containsKey(threadLocal) : "VMThreadLocal must have been discovered during static analysis"; + throw VMError.shouldNotReachHere("VMThreadLocal must have been discovered during static analysis"); } else { - var previous = threadLocals.putIfAbsent(threadLocal, new VMThreadLocalInfo(threadLocal)); - if (previous == null && validateUniqueNames) { + VMThreadLocalInfo newInfo = new VMThreadLocalInfo(threadLocal); + localInfo = threadLocals.computeIfAbsent(threadLocal, tl -> { + infoToThreadLocals.putIfAbsent(newInfo, threadLocal); + return newInfo; + }); + if (localInfo == newInfo && validateUniqueNames) { /* * Ensure this name is unique. */ @@ -95,6 +101,14 @@ public Object apply(Object source) { } } } + return localInfo; + } + + @Override + public Object apply(Object source) { + if (source instanceof FastThreadLocal fastThreadLocal) { + forFastThreadLocal(fastThreadLocal); + } /* * We want to collect all instances without actually replacing them, so we always return the * source object. @@ -118,6 +132,10 @@ public VMThreadLocalInfo findInfo(GraphBuilderContext b, ValueNode threadLocalNo return result; } + public FastThreadLocal getThreadLocal(VMThreadLocalInfo vmThreadLocalInfo) { + return infoToThreadLocals.get(vmThreadLocalInfo); + } + protected static int calculateSize(VMThreadLocalInfo info) { if (info.sizeSupplier != null) { int unalignedSize = info.sizeSupplier.getAsInt(); From 30e72ee23b66dc0f4fabfc94a5e100a41e4fae02 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Wed, 16 Oct 2024 13:21:01 -0700 Subject: [PATCH 023/105] Add supportsBulkClearArray --- .../meta/DefaultHotSpotLoweringProvider.java | 10 ++++++++++ .../graal/compiler/nodes/spi/LoweringProvider.java | 14 ++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java index c51b9d5131ab..762a03ef4a81 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java @@ -27,6 +27,7 @@ import static jdk.graal.compiler.core.common.GraalOptions.AlwaysInlineVTableStubs; import static jdk.graal.compiler.core.common.GraalOptions.InlineVTableStubs; import static jdk.graal.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace; +import static jdk.graal.compiler.hotspot.HotSpotGraalRuntime.HotSpotGC; import static jdk.graal.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END; import static jdk.graal.compiler.hotspot.meta.HotSpotHostForeignCallsProvider.GENERIC_ARRAYCOPY; import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; @@ -354,6 +355,15 @@ public final void initializeExtensions(OptionValues options, Iterable Date: Mon, 14 Oct 2024 11:33:08 -0700 Subject: [PATCH 024/105] Limit the number of threads used for CTW --- .../hotspot/test/LibGraalCompilationDriver.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LibGraalCompilationDriver.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LibGraalCompilationDriver.java index cb8ff8267965..69cbc6bb773d 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LibGraalCompilationDriver.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LibGraalCompilationDriver.java @@ -117,8 +117,8 @@ public class LibGraalCompilationDriver { private final boolean multiThreaded; /** - * Number of threads to use for multithreaded compilation. If 0, the value of - * {@code Runtime.getRuntime().availableProcessors()} is used instead. + * Number of threads to use for multithreaded compilation. If 0, a good default value is picked + * by {@link #getThreadCount()}. */ private final int numThreads; @@ -694,7 +694,12 @@ private int getThreadCount() { if (multiThreaded) { threadCount = numThreads; if (threadCount == 0) { - threadCount = Runtime.getRuntime().availableProcessors(); + /* + * On very large machine there might be hundreds of processors and the compiler + * doesn't really scale well enough for that so limit the max number of threads. 32 + * was picked as that seemed to scale well enough in testing. + */ + threadCount = Math.min(32, Runtime.getRuntime().availableProcessors()); } } return threadCount; From 6e37d0e0341ea01e5b64b395f920eb92ce135172 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Wed, 16 Oct 2024 12:48:49 +0200 Subject: [PATCH 025/105] Espresso: when continuations are enabled, ensure lambdas are always serializable. Note that this does not enable the use of ObjectOutputStream with lambdas - in that case the user must still opt-in via the standard Java interface intersection syntax to make javac generate the synthetic `$deserializeLambda$` method. However, in cooperation with an alternative serialization engine that doesn't depend on that synthetic method, this feature does allow transparent serialization of lambdas. --- espresso/docs/continuations.md | 3 +- espresso/docs/how-espresso-works.md | 32 ++++- .../truffle/espresso/descriptors/Symbol.java | 20 +++ .../oracle/truffle/espresso/meta/Meta.java | 7 ++ ...et_java_lang_invoke_LambdaMetafactory.java | 114 ++++++++++++++++++ 5 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_invoke_LambdaMetafactory.java diff --git a/espresso/docs/continuations.md b/espresso/docs/continuations.md index dbc9b960d979..0a27daf695a2 100644 --- a/espresso/docs/continuations.md +++ b/espresso/docs/continuations.md @@ -37,7 +37,8 @@ normally, or if an exception escaped). `Continuation` implements `Serializable` and can serialize to a backwards compatible format. Because frames can point to anything in their parameters and local variables, the class `ContinuationSerializable` provides static methods `readObjectExternal` and `writeObjectExternal` which may be used to coordinate serialization of -continuation-related objects with a non-jdk serialization engine. +continuation-related objects with a non-jdk serialization engine. Note that when the `--java.Continuum` flag is specified, +all lambdas are serializable but deserialization will require special support from your serializer engine. ## Security diff --git a/espresso/docs/how-espresso-works.md b/espresso/docs/how-espresso-works.md index 37481e0fd299..823b7bf6dd21 100644 --- a/espresso/docs/how-espresso-works.md +++ b/espresso/docs/how-espresso-works.md @@ -168,9 +168,8 @@ conflicts, and they are hidden from guest-world reflection. ### The stack Guest threads are run on host threads 1:1. That means guest stacks use host stacks, and for virtual threads to work the -hosting JVM must support the combination of virtual threads and Truffle, which as of December 2023 HotSpot does not. -Likewise guest exceptions are wrapped in `EspressoException` and then thrown, so the JVM running Espresso provides -stack unwinding services and similar. +hosting JVM must support the combination of virtual threads and Truffle. Guest exceptions are wrapped in +`EspressoException` and then thrown, so the JVM running Espresso provides stack unwinding services and similar. Truffle provides stack frame management. A `nodes.BytecodeNode` receives a Truffle `VirtualFrame` object, which manages a series of slots stored on the host stack, or when _materialized_, the frame is stored on the heap. In dynamic Truffle @@ -186,7 +185,32 @@ change) they are never being used inconsistently. Behind the scenes then we only separately from everything else so the GC can find them, and thus other types of stack slot are just stored in uninterpreted longs. -## Substitutions and extension modules +## Substitutions + +Espresso can replace or wrap any method in the JDK with code that runs in host space. Defining them is easy. Make a +class in the `com.oracle.truffle.espresso.substitutions` package annotated with `@EspressoSubstitutions`. The name is a +simple transform of the class containing the method to replace/wrap: for a class `a.b.Foo` the name of the substitution +class should be `Target_a_b_Foo`. + +You can then define static methods annotated with `@Substitution`. The arguments should be of type `StaticObject` to +refer to an object in the guest heap, annotated with `@Inject` if you want access to `Meta`, `EspressoLanguage` or other +internal classes. You must annotate `StaticObject` usages with `@JavaType(Foo.class)` to ensure the prototype matches +correctly. + +A substitution is a Truffle node and you can also define substitutions as `Node` subclasses directly instead of having +them generated for you by the annotation processor. Therefore, you should carefully consider whether to apply +`@TruffleBoundary` to your substitutions using the usual heuristics (should it be inlined into the caller?) + +If you need to wrap a method define two extra arguments: + +``` +@Bind("getMeta()") Meta meta, +@Cached("create(meta.a_b_Foo.getCallTargetNoSubstitution())") DirectCallNode original +``` + +and then use `original.call(self);`. Obviously, add the relevant boilerplate to the `Meta` class for this to work. + +## Extension modules Espresso specific features may need guest-exposed APIs to control them. For example Espresso exposes a HotSwap control API that lets apps register for callbacks that run when the program code is mutated. diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java index 937da2206f77..6e90f74a7e47 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java @@ -389,6 +389,10 @@ public static void ensureInitialized() { public static final Symbol ptypes = StaticSymbols.putName("ptypes"); public static final Symbol rtype = StaticSymbols.putName("rtype"); + // java.lang.invoke.LambdaMetafactory + public static final Symbol metafactory = StaticSymbols.putName("metafactory"); + public static final Symbol altMetafactory = StaticSymbols.putName("altMetafactory"); + // j.l.ref.Finalizer public static final Symbol finalize = StaticSymbols.putName("finalize"); public static final Symbol register = StaticSymbols.putName("register"); @@ -896,6 +900,7 @@ public static void ensureInitialized() { public static final Symbol java_lang_invoke_MethodHandles$Lookup = StaticSymbols.putType("Ljava/lang/invoke/MethodHandles$Lookup;"); public static final Symbol java_lang_invoke_CallSite = StaticSymbols.putType("Ljava/lang/invoke/CallSite;"); public static final Symbol java_lang_invoke_DirectMethodHandle = StaticSymbols.putType("Ljava/lang/invoke/DirectMethodHandle;"); + public static final Symbol java_lang_invoke_LambdaMetafactory = StaticSymbols.putType("Ljava/lang/invoke/LambdaMetafactory;"); // MethodHandleNatives is not public. public static final Symbol java_lang_invoke_MethodHandleNatives = StaticSymbols.putType("Ljava/lang/invoke/MethodHandleNatives;"); @@ -1265,6 +1270,21 @@ public static void ensureInitialized() { Type.java_lang_Object); public static final Symbol MethodHandles$Lookup = StaticSymbols.putSignature(Type.java_lang_invoke_MethodHandles$Lookup); + public static final Symbol CallSite_Lookup_String_MethodType_MethodType_MethodHandle_MethodType = StaticSymbols.putSignature( + Type.java_lang_invoke_CallSite, + Type.java_lang_invoke_MethodHandles$Lookup, + Type.java_lang_String, + Type.java_lang_invoke_MethodType, + Type.java_lang_invoke_MethodType, + Type.java_lang_invoke_MethodHandle, + Type.java_lang_invoke_MethodType); + public static final Symbol CallSite_Lookup_String_MethodType_Object_array = StaticSymbols.putSignature( + Type.java_lang_invoke_CallSite, + Type.java_lang_invoke_MethodHandles$Lookup, + Type.java_lang_String, + Type.java_lang_invoke_MethodType, + Type.java_lang_Object_array); + public static final Symbol Field_Object_long_Class = StaticSymbols.putSignature(Type.java_lang_reflect_Field, Type.java_lang_Object, Type._long, Type.java_lang_Class); public static final Symbol Thread$State_int = StaticSymbols.putSignature(Type.java_lang_Thread$State, Type._int); 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 165220e22014..458bcdbdd328 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 @@ -842,6 +842,10 @@ public Meta(EspressoContext context) { java_lang_invoke_MethodHandleNatives_linkDynamicConstant = null; } + ObjectKlass lambdaMetafactory = knownKlass(Type.java_lang_invoke_LambdaMetafactory); + java_lang_invoke_LambdaMetafactory_metafactory = lambdaMetafactory.requireDeclaredMethod(Name.metafactory, Signature.CallSite_Lookup_String_MethodType_MethodType_MethodHandle_MethodType); + java_lang_invoke_LambdaMetafactory_altMetafactory = lambdaMetafactory.requireDeclaredMethod(Name.altMetafactory, Signature.CallSite_Lookup_String_MethodType_Object_array); + // Interop java_time_Duration = knownKlass(Type.java_time_Duration); java_time_Duration_seconds = java_time_Duration.requireDeclaredField(Name.seconds, Type._long); @@ -1708,6 +1712,9 @@ private DiffVersionLoadHelper diff() { public final Method java_lang_invoke_MethodHandleNatives_linkCallSite; public final Method java_lang_invoke_MethodHandleNatives_linkDynamicConstant; + public final Method java_lang_invoke_LambdaMetafactory_metafactory; + public final Method java_lang_invoke_LambdaMetafactory_altMetafactory; + public final Method java_lang_Object_wait; public final Method java_lang_Object_toString; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_invoke_LambdaMetafactory.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_invoke_LambdaMetafactory.java new file mode 100644 index 000000000000..89ab1b97ad81 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_invoke_LambdaMetafactory.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.espresso.substitutions; + +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.espresso.meta.Meta; +import com.oracle.truffle.espresso.runtime.EspressoContext; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; + +import java.lang.invoke.CallSite; +import java.lang.invoke.LambdaMetafactory; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; + +/** + * This class exists for serializable continuations. It forcibly overrides the lambda generation + * mode to request that serializability is always included. This is insufficient to enable + * serialization with ObjectOutputStream because the standard Java protocol requires code generation + * by javac, but it is sufficient to make lambdas transparently serializable when using a + * custom serializer. + */ +@EspressoSubstitutions +public final class Target_java_lang_invoke_LambdaMetafactory { + @Substitution + abstract static class Metafactory extends SubstitutionNode { + abstract @JavaType(CallSite.class) StaticObject execute( + @JavaType(internalName = "Ljava/lang/invoke/MethodHandles$Lookup;") StaticObject caller, + @JavaType(String.class) StaticObject interfaceMethodName, + @JavaType(MethodType.class) StaticObject factoryType, + @JavaType(MethodType.class) StaticObject interfaceMethodType, + @JavaType(MethodHandle.class) StaticObject implementation, + @JavaType(MethodType.class) StaticObject dynamicMethodType); + + @Specialization + @JavaType(CallSite.class) + StaticObject doCached( + @JavaType(internalName = "Ljava/lang/invoke/MethodHandles$Lookup;") StaticObject caller, + @JavaType(String.class) StaticObject interfaceMethodName, + @JavaType(MethodType.class) StaticObject factoryType, + @JavaType(MethodType.class) StaticObject interfaceMethodType, + @JavaType(MethodHandle.class) StaticObject implementation, + @JavaType(MethodType.class) StaticObject dynamicMethodType, + @Bind("getMeta()") Meta meta, + @Cached("create(meta.java_lang_invoke_LambdaMetafactory_altMetafactory.getCallTargetNoSubstitution())") DirectCallNode altMetafactory, + @Cached("create(meta.java_lang_invoke_LambdaMetafactory_metafactory.getCallTargetNoSubstitution())") DirectCallNode original, + @Bind("getContext()") EspressoContext context) { + if (context.getEspressoEnv().Continuum) { + // altMetafactory has a curious calling convention, apparently designed for + // extensibility. + StaticObject extraArgsRef = context.getAllocator().createNewReferenceArray(meta.java_lang_Object, 4); + StaticObject[] extraArgs = extraArgsRef.unwrap(context.getLanguage()); + extraArgs[0] = interfaceMethodType; + extraArgs[1] = implementation; + extraArgs[2] = dynamicMethodType; + extraArgs[3] = (StaticObject) meta.java_lang_Integer_valueOf.getCallTarget().call(LambdaMetafactory.FLAG_SERIALIZABLE); + return (StaticObject) altMetafactory.call(caller, interfaceMethodName, factoryType, extraArgsRef); + } else { + return (StaticObject) original.call(caller, interfaceMethodName, factoryType, interfaceMethodType, implementation, dynamicMethodType); + } + } + } + + @Substitution + abstract static class AltMetafactory extends SubstitutionNode { + abstract @JavaType(CallSite.class) StaticObject execute( + @JavaType(internalName = "Ljava/lang/invoke/MethodHandles$Lookup;") StaticObject caller, + @JavaType(String.class) StaticObject interfaceMethodName, + @JavaType(MethodType.class) StaticObject factoryType, + @JavaType(Object[].class) StaticObject args); + + @Specialization + @JavaType(CallSite.class) + StaticObject doCached( + @JavaType(internalName = "Ljava/lang/invoke/MethodHandles$Lookup;") StaticObject caller, + @JavaType(String.class) StaticObject interfaceMethodName, + @JavaType(MethodType.class) StaticObject factoryType, + @JavaType(Object[].class) StaticObject args, + @Bind("getMeta()") Meta meta, + @Cached("create(meta.java_lang_invoke_LambdaMetafactory_altMetafactory.getCallTargetNoSubstitution())") DirectCallNode original, + @Bind("getContext()") EspressoContext context) { + if (context.getEspressoEnv().Continuum) { + StaticObject[] extraArgs = args.unwrap(context.getLanguage()); + extraArgs[3] = meta.boxInteger(meta.unboxInteger(extraArgs[3]) | LambdaMetafactory.FLAG_SERIALIZABLE); + return (StaticObject) original.call(caller, interfaceMethodName, factoryType, StaticObject.wrap(extraArgs, meta)); + } else { + return (StaticObject) original.call(caller, interfaceMethodName, factoryType, args); + } + } + } +} From 937a98b549eedb2a9b14587088ccdf6c9fa61582 Mon Sep 17 00:00:00 2001 From: akolic Date: Tue, 24 Sep 2024 17:19:53 +0200 Subject: [PATCH 026/105] Add new benchmark suite 'BaristaNativeImageBenchmarkSuite' --- common.json | 2 +- sdk/mx.sdk/mx_sdk_benchmark.py | 79 ++++--- .../mx_substratevm_benchmark.py | 194 ++++++++++++++++++ vm/mx.vm/mx_vm_benchmark.py | 11 +- 4 files changed, 250 insertions(+), 36 deletions(-) diff --git a/common.json b/common.json index 026f2d2be635..07cde52ac3d6 100644 --- a/common.json +++ b/common.json @@ -4,7 +4,7 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.33.0", + "mx_version": "7.33.1", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { diff --git a/sdk/mx.sdk/mx_sdk_benchmark.py b/sdk/mx.sdk/mx_sdk_benchmark.py index aaf48de97b3d..26e9cc15a1fa 100644 --- a/sdk/mx.sdk/mx_sdk_benchmark.py +++ b/sdk/mx.sdk/mx_sdk_benchmark.py @@ -84,6 +84,10 @@ lambda args: mx_benchmark.benchmark(["specjbb2015"] + args), '[-- [VM options] [-- [SPECjbb2015 options]]]' ], + 'barista': [ + lambda args: createBenchmarkShortcut("barista", args), + '[|*] [-- [VM options] [-- [Barista harness options]]]' + ], 'renaissance': [ lambda args: createBenchmarkShortcut("renaissance", args), '[|*] [-- [VM options] [-- [Renaissance options]]]' @@ -1189,9 +1193,15 @@ def rules(self, out, benchmarks, bmSuiteArgs): class BaristaBenchmarkSuite(mx_benchmark.CustomHarnessBenchmarkSuite): """Barista benchmark suite implementation. A collection of microservice workloads running on the Barista harness. + + The run arguments are passed to the Barista harness. + If you want to run something like `hwloc-bind` or `taskset` prefixed before the app, you should use the '--cmd-app-prefix' Barista harness option. + If you want to pass options to the app, you should use the '--app-args' Barista harness option. """ - def __init__(self, *args, **kwargs): - super(BaristaBenchmarkSuite, self).__init__(BaristaBenchmarkSuite.BaristaCommand(), *args, **kwargs) + def __init__(self, custom_harness_command: mx_benchmark.CustomHarnessCommand = None): + if custom_harness_command is None: + custom_harness_command = BaristaBenchmarkSuite.BaristaCommand() + super().__init__(custom_harness_command) self._version = None self._context = None @@ -1199,6 +1209,10 @@ def __init__(self, *args, **kwargs): def context(self): return self._context + @context.setter + def context(self, value): + self._context = value + def version(self): if self._version is None: # tomllib was included in python standard library with version 3.11 @@ -1244,6 +1258,9 @@ def baristaFilePath(self, file_name): def baristaProjectConfigurationPath(self): return self.baristaFilePath("pyproject.toml") + def baristaBuilderPath(self): + return self.baristaFilePath("build") + def baristaHarnessPath(self): return self.baristaFilePath("barista") @@ -1255,12 +1272,15 @@ def register_tracker(self, name, tracker_type): if tracker_type in _baristaConfig["disable_trackers"]: mx.log(f"Ignoring the registration of '{name}' tracker as it was disabled for {self.__class__.__name__}.") return - super(BaristaBenchmarkSuite, self).register_tracker(name, tracker_type) + super().register_tracker(name, tracker_type) def createCommandLineArgs(self, benchmarks, bmSuiteArgs): # Pass the VM options, BaristaCommand will form the final command. return self.vmArgs(bmSuiteArgs) + def all_command_line_args_are_vm_args(self): + return True + def rules(self, out, benchmarks, bmSuiteArgs): json_file_group_name = "barista_json_results_file_path" json_file_pattern = fr"Saving all collected metrics to JSON file: (?P<{json_file_group_name}>\S+?)$" @@ -1348,27 +1368,8 @@ def rules(self, out, benchmarks, bmSuiteArgs): return all_rules - def runAndReturnStdOut(self, benchmarks, bmSuiteArgs): - if benchmarks is None: - benchmarks = self.benchmarkList(bmSuiteArgs) - - out_acc = "" - last_dims = None - # Run the benchmarks one by one - for benchmark in benchmarks: - self._currently_running_benchmark = benchmark - retcode, out, dims = super(BaristaBenchmarkSuite, self).runAndReturnStdOut([benchmark], bmSuiteArgs) - if not self.validateReturnCode(retcode): - self.on_fail(f"Benchmark failed, exit code: {retcode}. Benchmark: {benchmark}") - out_acc += out - if last_dims is not None and last_dims != dims: - self.on_fail(f"Expected equal dims\nlast: {last_dims}\ncurr: {dims}") - last_dims = dims - self._currently_running_benchmark = "".join(benchmarks) - return retcode, out_acc, dims - def validateStdoutWithDimensions(self, out, benchmarks, bmSuiteArgs, retcode=None, dims=None, extraRules=None) -> DataPoints: - datapoints = super(BaristaBenchmarkSuite, self).validateStdoutWithDimensions(out, benchmarks, bmSuiteArgs, retcode=retcode, dims=dims, extraRules=extraRules) + datapoints = super().validateStdoutWithDimensions(out, benchmarks, bmSuiteArgs, retcode=retcode, dims=dims, extraRules=extraRules) for datapoint in datapoints: # Expand the 'load-tester' field group if "load-tester.command" in datapoint: @@ -1389,9 +1390,16 @@ def validateStdoutWithDimensions(self, out, benchmarks, bmSuiteArgs, retcode=Non del datapoint["load-tester.command"] return datapoints - def run(self, benchmarks, bmSuiteArgs) -> DataPoints: - self._context = BaristaBenchmarkSuite.RuntimeContext(self, benchmarks, bmSuiteArgs) - return super(BaristaBenchmarkSuite, self).run(benchmarks, bmSuiteArgs) + def _vmRun(self, vm, workdir, command, benchmarks, bmSuiteArgs): + self.enforce_single_benchmark(benchmarks) + self.context = BaristaBenchmarkSuite.RuntimeContext(self, vm, benchmarks[0], bmSuiteArgs) + return super()._vmRun(vm, workdir, command, benchmarks, bmSuiteArgs) + + def enforce_single_benchmark(self, benchmarks): + if not isinstance(benchmarks, list): + raise TypeError(f"{self.__class__.__name__} expects to receive a list of benchmarks to run, instead got an instance of {benchmarks.__class__.__name__}! Please specify a single benchmark!") + if len(benchmarks) != 1: + raise ValueError(f"You have requested {benchmarks} to be run but {self.__class__.__name__} can only run a single benchmark at a time! Please specify a single benchmark!") class BaristaCommand(mx_benchmark.CustomHarnessCommand): """Maps a JVM command into a command tailored for the Barista harness. @@ -1466,17 +1474,18 @@ def produceHarnessCommand(self, cmd, suite): if jvm_cmd_prefix: self._updateCommandOption(barista_cmd, "--cmd-app-prefix", "-p", " ".join(jvm_cmd_prefix)) barista_cmd += ["--mode", "jvm"] - barista_cmd.append(suite._currently_running_benchmark) + barista_cmd.append(suite.context.benchmark) return barista_cmd class RuntimeContext(): """Container class for the runtime context of BaristaBenchmarkSuite. """ - def __init__(self, suite, benchmarks, bmSuiteArgs): + def __init__(self, suite, vm, benchmark, bmSuiteArgs): if not isinstance(suite, BaristaBenchmarkSuite): raise TypeError(f"Expected an instance of {BaristaBenchmarkSuite.__name__}, instead got an instance of {suite.__class__.__name__}") self._suite = suite - self._benchmarks = benchmarks + self._vm = vm + self._benchmark = benchmark self._bmSuiteArgs = bmSuiteArgs @property @@ -1484,8 +1493,16 @@ def suite(self): return self._suite @property - def benchmarks(self): - return self._benchmarks + def vm(self): + return self._vm + + @property + def benchmark(self): + """The currently running benchmark. + + Corresponds to `benchmarks[0]` in a suite method that has a `benchmarks` argument. + """ + return self._benchmark @property def bmSuiteArgs(self): diff --git a/substratevm/mx.substratevm/mx_substratevm_benchmark.py b/substratevm/mx.substratevm/mx_substratevm_benchmark.py index 3e446dec0de2..ea56b9677092 100644 --- a/substratevm/mx.substratevm/mx_substratevm_benchmark.py +++ b/substratevm/mx.substratevm/mx_substratevm_benchmark.py @@ -28,7 +28,9 @@ import os import tempfile import zipfile +import re from glob import glob +from pathlib import Path import mx import mx_benchmark @@ -259,6 +261,198 @@ def successPatterns(self): mx_benchmark.add_bm_suite(RenaissanceNativeImageBenchmarkSuite()) +class BaristaNativeImageBenchmarkSuite(mx_sdk_benchmark.BaristaBenchmarkSuite, mx_sdk_benchmark.NativeImageBenchmarkMixin, mx_sdk_benchmark.NativeImageBundleBasedBenchmarkMixin): + """Native Image variant of the Barista benchmark suite implementation. A collection of microservice workloads running in native execution mode on the Barista harness. + + The run arguments are passed to the Barista harness. + If you want to run something like `hwloc-bind` or `taskset` prefixed before the app image, you should use the '--cmd-app-prefix' Barista harness option. + If you want to pass options to the app image, you should use the '--app-args' Barista harness option. + """ + def __init__(self, custom_harness_command: mx_benchmark.CustomHarnessCommand = None): + if custom_harness_command is None: + custom_harness_command = BaristaNativeImageBenchmarkSuite.BaristaNativeImageCommand() + super().__init__(custom_harness_command) + self._application_nibs = {} + # because of an issue in handling image build args in the intended order [GR-58214] + # we need the image name that is set inside the nib + self._application_fixed_image_names = {} + + def name(self): + return "barista-native-image" + + def benchSuiteName(self, bmSuiteArgs=None): + return "barista" + + def benchmarkName(self): + return self.context.benchmark + + def application_nib(self): + if self.benchmarkName() not in self._application_nibs: + # Run subprocess retrieving the application nib from the Barista 'build' script + out = mx.OutputCapture() + mx.run([self.baristaBuilderPath(), "--get-nib", self.benchmarkName()], out=out) + # Capture the application nib from the Barista 'build' script output + nib_pattern = r"application nib file path is: ([^\n]+)\n" + nib_match = re.search(nib_pattern, out.data) + if not nib_match: + raise ValueError(f"Could not extract the nib file path from the command output! Expected to match pattern {repr(nib_pattern)}.") + # Cache for future access + self._application_nibs[self.benchmarkName()] = nib_match.group(1) + # Try to capture the fixed image name from the Barista 'build' script output + fixed_image_name_pattern = r"fixed image name is: ([^\n]+)\n" + fixed_image_name_match = re.search(fixed_image_name_pattern, out.data) + # Cache fixed image name, if present + if fixed_image_name_match: + self._application_fixed_image_names[self.benchmarkName()] = fixed_image_name_match.group(1) + return self._application_nibs[self.benchmarkName()] + + def application_fixed_image_name(self): + self.application_nib() + return self._application_fixed_image_names.get(self.benchmarkName(), None) + + def applicationDist(self): + return Path(self.application_nib()).parent + + def uses_bundles(self): + return True + + def createCommandLineArgs(self, benchmarks, bmSuiteArgs): + # Pass the VM options, BaristaNativeImageCommand will form the final command. + return self.vmArgs(bmSuiteArgs) + + def extra_jvm_arg(self, benchmark, args): + # Added by BaristaNativeImageCommand + return [] + + def extra_agent_run_arg(self, benchmark, args, image_run_args): + # Added by BaristaNativeImageCommand + return [] + + def extra_profile_run_arg(self, benchmark, args, image_run_args, should_strip_run_args): + # Added by BaristaNativeImageCommand + return [] + + def extra_run_arg(self, benchmark, args, image_run_args): + # Added by BaristaNativeImageCommand + return [] + + def run(self, benchmarks, bmSuiteArgs) -> mx_benchmark.DataPoints: + return self.intercept_run(super(), benchmarks, bmSuiteArgs) + + def ensure_image_is_at_desired_location(self, bmSuiteArgs): + if self.stages_info.requested_stage.is_image() and self.application_fixed_image_name() is not None: + # Because of an issue in handling image build args in the intended order [GR-58214] + # we need to move the image from the path that is set inside the nib to the path expected by our vm. + # This code has no effect if the image is already at the desired location. + vm = self.get_vm_registry().get_vm_from_suite_args(bmSuiteArgs) + if vm.stages_info.should_produce_datapoints(mx_sdk_benchmark.Stage.INSTRUMENT_IMAGE): + desired_image_path = vm.config.instrumented_image_path + elif vm.stages_info.should_produce_datapoints(mx_sdk_benchmark.Stage.IMAGE): + desired_image_path = vm.config.image_path + else: + return + actual_image_path = desired_image_path.parent / self.application_fixed_image_name() + if actual_image_path.is_file() and not desired_image_path.is_file(): + mx.move(actual_image_path, desired_image_path) + + def runAndReturnStdOut(self, benchmarks, bmSuiteArgs): + retcode, out, dims = super().runAndReturnStdOut(benchmarks, bmSuiteArgs) + self.ensure_image_is_at_desired_location(bmSuiteArgs) + return retcode, out, dims + + class BaristaNativeImageCommand(mx_sdk_benchmark.BaristaBenchmarkSuite.BaristaCommand): + """Maps the command produced by NativeImageVM into a command tailored for the Barista harness. + """ + def _short_load_testing_phases(self): + """Configures the main barista load-testing phases to be quite short. + + Useful for the `agent` and `instrument-run` stages. + """ + return [ + "--warmup-iteration-count", "1", + "--warmup-duration", "5", + "--throughput-iteration-count", "0", + "--latency-iteration-count", "0", + ] + + def _get_built_app_image(self, suite, stage): + """Retrieves the path to the app image built in the previous stage. + + In the case of `instrument-run`, retrieves the image built during `instrument-image`. + In the case of `run`, retrieves the image built during `image`. + """ + vm = suite.context.vm + if stage == mx_sdk_benchmark.Stage.INSTRUMENT_RUN: + return vm.config.instrumented_image_path + else: + return vm.config.image_path + + def produce_JVM_harness_command(self, cmd, suite): + """Maps a JVM command into a command tailored for the Barista harness. + + Utilizes the implementation of the ``mx_sdk_benchmark.BaristaBenchmarkSuite.BaristaCommand`` base class + """ + return super().produceHarnessCommand(cmd, suite) + + def produceHarnessCommand(self, cmd, suite): + """Maps a NativeImageVM command into a command tailored for the Barista harness. + + This method is invoked only in the `agent`, `instrument-run` and `run` stages, because hooks are + only applied in these stages (defined in ``NativeImageBenchmarkMixin.run_stage``). + In the case of the `agent` stage, relies on the parent ``BaristaCommand`` class for the mapping. + + :param list[str] cmd: NativeImageVM command to be mapped. + :param BaristaNativeImageBenchmarkSuite suite: Barista benchmark suite running the benchmark on the Barista harness. + :return: Command tailored for the Barista harness. + :rtype: list[str] + """ + if not isinstance(suite, BaristaNativeImageBenchmarkSuite): + raise TypeError(f"Expected an instance of {BaristaNativeImageBenchmarkSuite.__name__}, instead got an instance of {suite.__class__.__name__}") + + stage = suite.stages_info.requested_stage + if stage == mx_sdk_benchmark.Stage.AGENT: + # BaristaCommand works for agent stage, since it's a JVM stage + cmd = self.produce_JVM_harness_command(cmd, suite) + # Make agent run short + cmd += self._short_load_testing_phases() + # Add explicit agent stage args + cmd += mx_sdk_benchmark.parse_prefixed_args("-Dnative-image.benchmark.extra-jvm-arg=", suite.context.bmSuiteArgs) + cmd += mx_sdk_benchmark.parse_prefixed_args("-Dnative-image.benchmark.extra-agent-run-arg=", suite.context.bmSuiteArgs) + return cmd + + # Extract app image options and command prefix from the NativeImageVM command + app_image = str(self._get_built_app_image(suite, stage)) + try: + index_of_app_image = cmd.index(app_image) + except: + mx.log_error(f"Could not find app image '{app_image}' in {cmd}") + raise + nivm_cmd_prefix = cmd[:index_of_app_image] + nivm_app_options = cmd[index_of_app_image + 1:] + + # Provide image built in the previous stage to the Barista harnesss using the `--app-executable` option + ni_barista_cmd = [suite.baristaHarnessPath(), "--mode", "native", "--app-executable", app_image] + ni_barista_cmd += suite.runArgs(suite.context.bmSuiteArgs) + ni_barista_cmd += mx_sdk_benchmark.parse_prefixed_args("-Dnative-image.benchmark.extra-jvm-arg=", suite.context.bmSuiteArgs) + if stage == mx_sdk_benchmark.Stage.INSTRUMENT_RUN: + # Make instrument run short + ni_barista_cmd += self._short_load_testing_phases() + # Add explicit instrument stage args + ni_barista_cmd += mx_sdk_benchmark.parse_prefixed_args("-Dnative-image.benchmark.extra-profile-run-arg=", suite.context.bmSuiteArgs) or mx_sdk_benchmark.parse_prefixed_args("-Dnative-image.benchmark.extra-run-arg=", suite.context.bmSuiteArgs) + else: + # Add explicit run stage args + ni_barista_cmd += mx_sdk_benchmark.parse_prefixed_args("-Dnative-image.benchmark.extra-run-arg=", suite.context.bmSuiteArgs) + if nivm_cmd_prefix: + self._updateCommandOption(ni_barista_cmd, "--cmd-app-prefix", "-p", " ".join(nivm_cmd_prefix)) + if nivm_app_options: + self._updateCommandOption(ni_barista_cmd, "--app-args", "-a", " ".join(nivm_app_options)) + ni_barista_cmd += [suite.benchmarkName()] + return ni_barista_cmd + + +mx_benchmark.add_bm_suite(BaristaNativeImageBenchmarkSuite()) + + class BaseDaCapoNativeImageBenchmarkSuite(): '''`SetBuildInfo` method in DaCapo source reads from the file nested in daCapo jar. diff --git a/vm/mx.vm/mx_vm_benchmark.py b/vm/mx.vm/mx_vm_benchmark.py index f0aac7391239..d436b429fbab 100644 --- a/vm/mx.vm/mx_vm_benchmark.py +++ b/vm/mx.vm/mx_vm_benchmark.py @@ -134,7 +134,7 @@ def __init__(self, vm: NativeImageVM, bm_suite: BenchmarkSuite | NativeImageBenc self.bm_suite = bm_suite self.benchmark_suite_name = bm_suite.benchSuiteName(args) self.benchmark_name = bm_suite.benchmarkName() - self.executable, self.classpath_arguments, self.modulepath_arguments, self.system_properties, self.image_vm_args, image_run_args, self.split_run = NativeImageVM.extract_benchmark_arguments(args) + self.executable, self.classpath_arguments, self.modulepath_arguments, self.system_properties, self.image_vm_args, image_run_args, self.split_run = NativeImageVM.extract_benchmark_arguments(args, bm_suite.all_command_line_args_are_vm_args()) self.extra_image_build_arguments: List[str] = bm_suite.extra_image_build_argument(self.benchmark_name, args) # use list() to create fresh copies to safeguard against accidental modification self.image_run_args = bm_suite.extra_run_arg(self.benchmark_name, args, list(image_run_args)) @@ -746,7 +746,10 @@ def supported_vm_arg_prefixes(): '--patch-module', '--boot-class-path', '--source-path', '-cp', '-classpath', '-p'] @staticmethod - def _split_vm_arguments(args): + def _split_vm_arguments(args, all_args_are_vm_args): + if all_args_are_vm_args: + return args, [], [] + i = 0 while i < len(args): arg = args[i] @@ -762,7 +765,7 @@ def _split_vm_arguments(args): mx.abort('No executable found in args: ' + str(args)) @staticmethod - def extract_benchmark_arguments(args): + def extract_benchmark_arguments(args, all_args_are_vm_args): i = 0 clean_args = args[:] split_run = None @@ -776,7 +779,7 @@ def extract_benchmark_arguments(args): else: i += 1 clean_args = [x for x in clean_args if "-Dnative-image" not in x] - vm_args, executable, image_run_args = NativeImageVM._split_vm_arguments(clean_args) + vm_args, executable, image_run_args = NativeImageVM._split_vm_arguments(clean_args, all_args_are_vm_args) classpath_arguments = [] modulepath_arguments = [] From 22033be6fee8b713d919999c609936d282a06589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C3=B6=20Barany?= Date: Thu, 17 Oct 2024 14:27:41 +0200 Subject: [PATCH 027/105] Don't assert divisor != 1 when optimizing divs --- .../graal/compiler/phases/common/OptimizeDivPhase.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/OptimizeDivPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/OptimizeDivPhase.java index 7d2819cb17bd..1c98d96ada98 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/OptimizeDivPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/OptimizeDivPhase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,7 +184,13 @@ protected ValueNode createDiv(ValueNode val) { protected static void optimizeSignedDiv(Canonicalizable.Binary div) { ValueNode forX = div.getX(); long c = div.getY().asJavaConstant().asLong(); - assert c != 1 && c != -1 && c != 0 : Assertions.errorMessageContext("div", div, "c", c); + if (c == 1 || c == -1 || c == 0) { + /* + * Leave to canonicalization. The constant may have been produced by optimizing another + * div, without a chance to canonicalize this div yet. + */ + return; + } IntegerStamp dividendStamp = (IntegerStamp) forX.stamp(NodeView.DEFAULT); int bitSize = dividendStamp.getBits(); From 4388af739cd5ccb6c5920d833e1b187b55b6aed4 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Thu, 17 Oct 2024 14:37:10 +0000 Subject: [PATCH 028/105] [GR-42711] Fix array element types in the Ruby TCK PullRequest: truffleruby/4377 --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 15d7dea5b5bb..3551800f4808 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -49,7 +49,7 @@ }, { "name": "truffleruby", - "version": "72fd3638619156f62219207b723ae348d9fc3038", + "version": "0e05bfe4380fb7c2107eb29940762b296f1fd454", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/truffleruby.git", "kind": "git"}, From 8dd003d3c5eb09affc6e2877ecd0cb76ceed077c Mon Sep 17 00:00:00 2001 From: Jakub Chaloupka Date: Tue, 8 Oct 2024 11:23:34 +0200 Subject: [PATCH 029/105] Clear polyglot source cache more aggressively. --- .../api/test/source/SourceCacheTest.java | 83 ++++++++++++++++++- .../truffle/polyglot/PolyglotEngineImpl.java | 9 +- .../polyglot/PolyglotSharingLayer.java | 3 +- .../truffle/polyglot/PolyglotSourceCache.java | 47 +++++++---- 4 files changed, 124 insertions(+), 18 deletions(-) diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceCacheTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceCacheTest.java index 12c3344d3125..7202c8ce392c 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceCacheTest.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceCacheTest.java @@ -54,7 +54,13 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.graalvm.options.OptionCategory; +import org.graalvm.options.OptionDescriptors; +import org.graalvm.options.OptionKey; +import org.graalvm.options.OptionStability; +import org.graalvm.options.OptionValues; import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Engine; import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.Source; import org.junit.Assert; @@ -62,6 +68,7 @@ import org.junit.function.ThrowingRunnable; import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.Option; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.frame.VirtualFrame; @@ -89,7 +96,7 @@ public void testTraceSourceCacheFailure() throws Throwable { @Test public void testTraceSourceCacheEviction() throws IOException { - TruffleTestAssumptions.assumeWeakEncapsulation(); + TruffleTestAssumptions.assumeWeakEncapsulation(); // Can't control GC in the isolate. try (ByteArrayOutputStream out = new ByteArrayOutputStream(); Context context = Context.newBuilder().option("engine.TraceSourceCache", "true").out(out).err(out).build()) { Source auxiliarySource = Source.newBuilder(SourceCacheTestLanguage.ID, "x", "AuxiliarySource").build(); String sourceName = "TestSource"; @@ -162,10 +169,13 @@ private static void testCommon(String languageId, Map options, S } } - @TruffleLanguage.Registration + @TruffleLanguage.Registration(contextPolicy = TruffleLanguage.ContextPolicy.SHARED) static class SourceCacheTestLanguage extends TruffleLanguage { static final String ID = TestUtils.getDefaultLanguageId(SourceCacheTestLanguage.class); + @Option(category = OptionCategory.USER, help = "Sharing Group.", stability = OptionStability.STABLE) // + static OptionKey SharingGroup = new OptionKey<>(""); + @Override protected Env createContext(Env env) { return env; @@ -181,6 +191,20 @@ public Object execute(VirtualFrame frame) { } }.getCallTarget(); } + + @Override + protected boolean areOptionsCompatible(OptionValues firstOptions, OptionValues newOptions) { + /* + * Forces creation of a new sharing layer for each context where the option SharingGroup + * has a different value. + */ + return firstOptions.get(SharingGroup).equals(newOptions.get(SharingGroup)); + } + + @Override + protected OptionDescriptors getOptionDescriptors() { + return new SourceCacheTestLanguageOptionDescriptors(); + } } @SuppressWarnings("serial") @@ -205,4 +229,59 @@ protected CallTarget parse(ParsingRequest request) throws Exception { throw new ParseException(); } } + + @Test + public void testSourceCachesCleared() throws IOException { + TruffleTestAssumptions.assumeWeakEncapsulation(); // Can't control GC in the isolate. + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); Engine engine = Engine.newBuilder().option("engine.TraceSourceCache", "true").out(out).err(out).build()) { + String sourceName1; + String sourceName2; + Source source1 = Source.newBuilder(SourceCacheTestLanguage.ID, "1", sourceName1 = "TestSource1").build(); + Source source2 = Source.newBuilder(SourceCacheTestLanguage.ID, "2", sourceName2 = "TestSource2").build(); + try (Context context1 = Context.newBuilder().engine(engine).option(SourceCacheTestLanguage.ID + ".SharingGroup", "one").build()) { + String sourceHash1 = String.format("0x%08x", context1.eval(source1).asInt()); + String sourceHash2 = String.format("0x%08x", context1.eval(source2).asInt()); + /* + * context2 creates a separate sharing layer because of the option SharingGroup and + * the implementation of the method SourceCacheTestLanguage#areOptionCompatible. + */ + try (Context context2 = Context.newBuilder().engine(engine).option(SourceCacheTestLanguage.ID + ".SharingGroup", "two").build()) { + WeakReference souceRef2 = new WeakReference<>(source2); + source2 = null; + GCUtils.assertGc("Source 2 was not collected", souceRef2); + /* + * The following context2 eval is supposed to clear source2 from context1 + * layer's source cache. + */ + context2.eval(source1); + WeakReference souceRef1 = new WeakReference<>(source1); + source1 = null; + GCUtils.assertGc("Source 1 was not collected", souceRef1); + /* + * The following context2 close is supposed to clear source1 both from context1 + * layer's source cache and from context2 layer's source cache. + */ + } + List logs = new ArrayList<>(); + forEachLog(out.toByteArray(), (matcher) -> { + String logType = matcher.group(1); + String suffix; + String loggedHash = matcher.group(2); + String loggedName = matcher.group(3); + if (sourceName1.equals(loggedName)) { + Assert.assertEquals(sourceHash1, loggedHash); + suffix = "1"; + } else if (sourceName2.equals(loggedName)) { + Assert.assertEquals(sourceHash2, loggedHash); + suffix = "2"; + } else { + suffix = "Unknown"; + } + logs.add(logType + suffix); + }); + String[] expectedSequence = new String[]{"miss1", "miss2", "evict2", "miss1", "evict1", "evict1"}; + Assert.assertArrayEquals(expectedSequence, logs.toArray()); + } + } + } } diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotEngineImpl.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotEngineImpl.java index d6e27be24e0c..3d772c92b839 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotEngineImpl.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotEngineImpl.java @@ -76,6 +76,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; @@ -124,6 +125,7 @@ import com.oracle.truffle.api.nodes.LanguageInfo; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.polyglot.PolyglotContextConfig.FileSystemConfig; import com.oracle.truffle.polyglot.PolyglotContextConfig.PreinitConfig; @@ -135,7 +137,6 @@ import com.oracle.truffle.polyglot.PolyglotLoggers.EngineLoggerProvider; import com.oracle.truffle.polyglot.PolyglotLoggers.LoggerCache; import com.oracle.truffle.polyglot.SystemThread.InstrumentSystemThread; -import java.util.function.Consumer; /** The implementation of {@link org.graalvm.polyglot.Engine}, stored in the receiver field. */ final class PolyglotEngineImpl implements com.oracle.truffle.polyglot.PolyglotImpl.VMObject { @@ -239,6 +240,8 @@ final class PolyglotEngineImpl implements com.oracle.truffle.polyglot.PolyglotIm final List sharedLayers = new ArrayList<>(); + private final ReferenceQueue deadSourcesQueue = new ReferenceQueue<>(); + private boolean runtimeInitialized; AbstractPolyglotHostService polyglotHostService; // effectively final after engine patching @@ -456,6 +459,10 @@ void freeSharingLayer(PolyglotSharingLayer layer, PolyglotContextImpl context) { } } + ReferenceQueue getDeadSourcesQueue() { + return deadSourcesQueue; + } + void ensureRuntimeInitialized(PolyglotContextImpl context) { assert Thread.holdsLock(lock); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotSharingLayer.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotSharingLayer.java index 2036ce68cd98..bbc24404ade6 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotSharingLayer.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotSharingLayer.java @@ -113,7 +113,7 @@ static final class Shared { int claimedCount; private Shared(PolyglotEngineImpl engine, ContextPolicy contextPolicy, Map previousLanguageOptions) { - this.sourceCache = new PolyglotSourceCache(TracingSourceCacheListener.createOrNull(engine)); + this.sourceCache = new PolyglotSourceCache(engine.getDeadSourcesQueue(), TracingSourceCacheListener.createOrNull(engine)); this.contextPolicy = contextPolicy; this.instances = new PolyglotLanguageInstance[engine.languageCount]; this.previousLanguageOptions = previousLanguageOptions; @@ -340,6 +340,7 @@ public void freeSharingLayer(PolyglotContextImpl context) { assert isClaimed(); shared.claimedCount--; + shared.sourceCache.cleanupStaleEntries(); if (engine.getEngineOptionValues().get(PolyglotEngineOptions.TraceCodeSharing)) { traceFreeLayer(context); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotSourceCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotSourceCache.java index 8b502ddb4ed1..33f50b010f60 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotSourceCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotSourceCache.java @@ -56,13 +56,13 @@ final class PolyglotSourceCache { - private final Cache strongCache; - private final Cache weakCache; + private final StrongCache strongCache; + private final WeakCache weakCache; private SourceCacheListener sourceCacheListener; - PolyglotSourceCache(SourceCacheListener sourceCacheListener) { + PolyglotSourceCache(ReferenceQueue deadSourcesQueue, TracingSourceCacheListener sourceCacheListener) { this.sourceCacheListener = sourceCacheListener; - this.weakCache = new WeakCache(); + this.weakCache = new WeakCache(deadSourcesQueue); this.strongCache = new StrongCache(); } @@ -103,6 +103,10 @@ void listCachedSources(PolyglotImpl polyglot, Collection source) { weakCache.listSources(polyglot, source); } + void cleanupStaleEntries() { + WeakCache.cleanupStaleEntries(weakCache.deadSources, sourceCacheListener); + } + private static CallTarget parseImpl(PolyglotLanguageContext context, String[] argumentNames, Source source) { validateSource(context, source); CallTarget parsedTarget = LANGUAGE.parse(context.requireEnv(), source, null, argumentNames); @@ -256,14 +260,20 @@ void listSources(PolyglotImpl polyglot, Collection sources) { private final class WeakCache extends Cache { private final ConcurrentHashMap sourceCache = new ConcurrentHashMap<>(); - private final ReferenceQueue deadSources = new ReferenceQueue<>(); + private final ReferenceQueue deadSources; + private final WeakReference cacheRef; + + WeakCache(ReferenceQueue deadSources) { + this.deadSources = deadSources; + this.cacheRef = new WeakReference<>(this); + } @Override CallTarget lookup(PolyglotLanguageContext context, Source source, String[] argumentNames, boolean parse) { - cleanupStaleEntries(); + cleanupStaleEntries(deadSources, sourceCacheListener); Object sourceId = EngineAccessor.SOURCE.getSourceIdentifier(source); Source sourceValue = EngineAccessor.SOURCE.copySource(source); - WeakSourceKey ref = new WeakSourceKey(new SourceKey(sourceId, argumentNames), source, deadSources); + WeakSourceKey ref = new WeakSourceKey(new SourceKey(sourceId, argumentNames), source, cacheRef, deadSources); WeakCacheValue value = sourceCache.get(ref); if (value == null) { if (parse) { @@ -308,18 +318,25 @@ boolean isEmpty() { @Override void listSources(PolyglotImpl polyglot, Collection sources) { - cleanupStaleEntries(); + cleanupStaleEntries(deadSources, sourceCacheListener); for (WeakCacheValue value : sourceCache.values()) { sources.add(PolyglotImpl.getOrCreatePolyglotSource(polyglot, value.source)); } } - private void cleanupStaleEntries() { + /** + * This is deliberately a static method, because the dead sources queue is + * {@link PolyglotEngineImpl#getDeadSourcesQueue() shared} among all weak caches on a + * particular polyglot engine, and so the elements of {@link WeakCache#deadSources the + * queue} may {@link WeakSourceKey#cacheRef refer} to different weak caches. + */ + private static void cleanupStaleEntries(ReferenceQueue deadSourcesQueue, SourceCacheListener cacheListener) { WeakSourceKey sourceRef; - while ((sourceRef = (WeakSourceKey) deadSources.poll()) != null) { - WeakCacheValue value = sourceCache.remove(sourceRef); - if (value != null && sourceCacheListener != null) { - sourceCacheListener.onCacheEvict(value.source, value.target, SourceCacheListener.CacheType.WEAK, value.hits.get()); + while ((sourceRef = (WeakSourceKey) deadSourcesQueue.poll()) != null) { + WeakCache cache = sourceRef.cacheRef.get(); + WeakCacheValue value = cache != null ? cache.sourceCache.remove(sourceRef) : null; + if (value != null && cacheListener != null) { + cacheListener.onCacheEvict(value.source, value.target, SourceCacheListener.CacheType.WEAK, value.hits.get()); } } } @@ -373,9 +390,11 @@ public boolean equals(Object obj) { private static final class WeakSourceKey extends WeakReference { final SourceKey key; + final WeakReference cacheRef; - WeakSourceKey(SourceKey key, Source value, ReferenceQueue q) { + WeakSourceKey(SourceKey key, Source value, WeakReference cacheRef, ReferenceQueue q) { super(value, q); + this.cacheRef = cacheRef; this.key = key; } From 734d5bbcb5f26fe2228df2f81d8cbe9df633059e Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Wed, 16 Oct 2024 18:04:35 +0200 Subject: [PATCH 030/105] Improve TCK error messages * So it shows the TypeDescriptor's of the parameters. * Example 1: java.lang.AssertionError: Running snippet '<' retrieved from 'python' provider (java class com.oracle.graal.python.tck.PythonProvider) with parameters: '[1, 2]' from 'ruby' provider, value: [1, 2] (Meta Object: Array) '[true, false]' from 'ruby' provider, value: [true, false] (Meta Object: Array) failed: Expected PolyglotException, but executed successfully. Result: null Exception: null Snippet: lambda x, y: x < y Parameter 0 Snippet: -> { [1, 2] } Parameter 0 Declared Return Type: [object & Array & Iterable] Parameter 0 Returned Value Type: [object & Iterable & Array] Parameter 1 Snippet: -> { [true, false] } Parameter 1 Declared Return Type: [object & Array<> & Iterable<>] Parameter 1 Returned Value Type: [object & Array & Iterable] vs before: java.lang.AssertionError: Running snippet '<' retrieved from 'python' provider (java class com.oracle.graal.python.tck.PythonProvider) with parameters: '[1, 2]' from 'ruby' provider, value: [1, 2] (Meta Object: Array) '[true, false]' from 'ruby' provider, value: [true, false] (Meta Object: Array) failed: Expected PolyglotException, but executed successfully. Result: null Exception: null Snippet: lambda x, y: x < y Parameter 0 Snippet: -> { [1, 2] } Parameter 1 Snippet: -> { [true, false] } * Example 2: java.lang.AssertionError: Running snippet '<' retrieved from 'python' provider (java class com.oracle.graal.python.tck.PythonProvider) with parameters: '[1, 2]' from 'ruby' provider, value: [1, 2] (Meta Object: Array) '[]' from 'ruby' provider, value: [] (Meta Object: Array) failed: Expected PolyglotException, but executed successfully. Result: null Exception: null Snippet: lambda x, y: x < y Parameter 0 Snippet: -> { [1, 2] } Parameter 0 Declared Return Type: [object & Array & Iterable] Parameter 0 Returned Value Type: [object & Array & Iterable] Parameter 1 Snippet: -> { [] } Parameter 1 Declared Return Type: [object & Array<> & Iterable<>] Parameter 1 Returned Value Type: [object & Iterable<> & Array<>] vs before: java.lang.AssertionError: Running snippet '<' retrieved from 'python' provider (java class com.oracle.graal.python.tck.PythonProvider) with parameters: '[1, 2]' from 'ruby' provider, value: [1, 2] (Meta Object: Array) '[]' from 'ruby' provider, value: [] (Meta Object: Array) failed: Expected PolyglotException, but executed successfully. Result: null Exception: null Snippet: lambda x, y: x < y Parameter 0 Snippet: -> { [1, 2] } Parameter 1 Snippet: -> { [] } --- .../org.graalvm.polyglot.tck/snapshot.sigtest | 1 + .../graalvm/polyglot/tck/TypeDescriptor.java | 35 +++++++++++++------ .../oracle/truffle/tck/tests/TestUtil.java | 9 ++--- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/sdk/src/org.graalvm.polyglot.tck/snapshot.sigtest b/sdk/src/org.graalvm.polyglot.tck/snapshot.sigtest index 8110139f3e40..a77bb6754b80 100644 --- a/sdk/src/org.graalvm.polyglot.tck/snapshot.sigtest +++ b/sdk/src/org.graalvm.polyglot.tck/snapshot.sigtest @@ -122,6 +122,7 @@ supr java.lang.Object hfds executableReturnType,executableValue,id,parameterTypes,verifier CLSS public final org.graalvm.polyglot.tck.TypeDescriptor +fld public final static org.graalvm.polyglot.tck.TypeDescriptor ALL fld public final static org.graalvm.polyglot.tck.TypeDescriptor ANY fld public final static org.graalvm.polyglot.tck.TypeDescriptor ARRAY fld public final static org.graalvm.polyglot.tck.TypeDescriptor BOOLEAN diff --git a/sdk/src/org.graalvm.polyglot.tck/src/org/graalvm/polyglot/tck/TypeDescriptor.java b/sdk/src/org.graalvm.polyglot.tck/src/org/graalvm/polyglot/tck/TypeDescriptor.java index a1480f1769ac..1f6d99d81acb 100644 --- a/sdk/src/org.graalvm.polyglot.tck/src/org/graalvm/polyglot/tck/TypeDescriptor.java +++ b/sdk/src/org.graalvm.polyglot.tck/src/org/graalvm/polyglot/tck/TypeDescriptor.java @@ -317,18 +317,29 @@ public final class TypeDescriptor { public static final TypeDescriptor INSTANTIABLE_ANY = new TypeDescriptor(new InstantiableImpl(ExecutableImpl.Kind.TOP, null, true, Collections.emptyList())); /** - * Represents all types. It's an intersection of no type. + * Represents any type. It's a union of all types. * * @since 0.30 */ public static final TypeDescriptor ANY = new TypeDescriptor(new UnionImpl(new HashSet<>(Arrays.asList( - NOTYPE.impl, NULL.impl, BOOLEAN.impl, NUMBER.impl, STRING.impl, HOST_OBJECT.impl, NATIVE_POINTER.impl, OBJECT.impl, ARRAY.impl, EXECUTABLE_ANY.impl, INSTANTIABLE_ANY.impl, - DATE.impl, TIME.impl, TIME_ZONE.impl, DURATION.impl, META_OBJECT.impl, ITERABLE.impl, ITERATOR.impl, EXCEPTION.impl, HASH.impl)))); + NOTYPE.impl, NULL.impl, BOOLEAN.impl, NUMBER.impl, STRING.impl, HOST_OBJECT.impl, NATIVE_POINTER.impl, OBJECT.impl, ARRAY.impl, + DATE.impl, TIME.impl, TIME_ZONE.impl, DURATION.impl, META_OBJECT.impl, ITERABLE.impl, ITERATOR.impl, EXCEPTION.impl, HASH.impl, + EXECUTABLE_ANY.impl, INSTANTIABLE_ANY.impl)))); + + /** + * Represents all types. It's an intersection of all types. + * + * @since 24.2 + */ + public static final TypeDescriptor ALL = new TypeDescriptor(intersectionImpl(Arrays.asList( + NOTYPE.impl, NULL.impl, BOOLEAN.impl, NUMBER.impl, STRING.impl, HOST_OBJECT.impl, NATIVE_POINTER.impl, OBJECT.impl, ARRAY.impl, + DATE.impl, TIME.impl, TIME_ZONE.impl, DURATION.impl, META_OBJECT.impl, ITERABLE.impl, ITERATOR.impl, EXCEPTION.impl, HASH.impl, + EXECUTABLE.impl, INSTANTIABLE.impl))); private static final TypeDescriptor[] PREDEFINED_TYPES = new TypeDescriptor[]{ - NOTYPE, NULL, BOOLEAN, NUMBER, STRING, HOST_OBJECT, DATE, TIME, TIME_ZONE, DURATION, META_OBJECT, EXCEPTION, NATIVE_POINTER, OBJECT, ARRAY, EXECUTABLE, EXECUTABLE_ANY, - INSTANTIABLE, ITERABLE, ITERATOR, HASH, - INSTANTIABLE_ANY, ANY + NOTYPE, NULL, BOOLEAN, NUMBER, STRING, HOST_OBJECT, NATIVE_POINTER, OBJECT, ARRAY, + DATE, TIME, TIME_ZONE, DURATION, META_OBJECT, ITERABLE, ITERATOR, EXCEPTION, HASH, + EXECUTABLE_ANY, EXECUTABLE, INSTANTIABLE_ANY, INSTANTIABLE, ANY, ALL }; private final TypeDescriptorImpl impl; @@ -987,9 +998,7 @@ private static TypeDescriptor detectContentType(Iterator content) { } switch (contentTypes.size()) { case 0: - return intersection(NOTYPE, NULL, BOOLEAN, NUMBER, STRING, HOST_OBJECT, NATIVE_POINTER, OBJECT, - ARRAY, EXECUTABLE, INSTANTIABLE, ITERABLE, ITERATOR, DATE, TIME, TIME_ZONE, DURATION, - META_OBJECT, EXCEPTION, HASH); + return ALL; case 1: return contentTypes.iterator().next(); default: @@ -1370,7 +1379,7 @@ public final String toString() { if (typeParameter == null) { sb.append(""); } else { - sb.append(typeParameter.toString()); + sb.append(typeParameter); } } sb.append(">"); @@ -1608,6 +1617,9 @@ public boolean equals(Object obj) { @Override public String toString() { + if (this == ALL.impl) { + return ""; + } return types.isEmpty() ? "" : types.stream().map(Object::toString).collect(Collectors.joining(" & ", "[", "]")); } } @@ -1709,6 +1721,9 @@ public boolean equals(Object obj) { @Override public String toString() { + if (this == ANY.impl) { + return ""; + } return types.stream().map(Object::toString).collect(Collectors.joining(" | ", "[", "]")); } } diff --git a/truffle/src/com.oracle.truffle.tck.tests/src/com/oracle/truffle/tck/tests/TestUtil.java b/truffle/src/com.oracle.truffle.tck.tests/src/com/oracle/truffle/tck/tests/TestUtil.java index dcde05e601d0..2b8d56c8582a 100644 --- a/truffle/src/com.oracle.truffle.tck.tests/src/com/oracle/truffle/tck/tests/TestUtil.java +++ b/truffle/src/com.oracle.truffle.tck.tests/src/com/oracle/truffle/tck/tests/TestUtil.java @@ -231,10 +231,11 @@ static String formatErrorMessage( message.append("Result: ").append(resultValue).append('\n'); message.append("Exception: ").append(exception).append('\n'); message.append("Snippet: ").append(getSource(snippet.getExecutableValue())).append('\n'); - int i = 0; - for (Map.Entry langAndparamSnippet : testRun.getActualParameterSnippets()) { - final Snippet paramSnippet = langAndparamSnippet.getValue(); - message.append(String.format("Parameter %d Snippet: ", i++)).append(getSource(paramSnippet.getExecutableValue())).append('\n'); + for (int i = 0; i < actualParameterSnippets.size(); i++) { + final Snippet paramSnippet = actualParameterSnippets.get(i).getValue(); + message.append(String.format("Parameter %d Snippet: ", i)).append(getSource(paramSnippet.getExecutableValue())).append('\n'); + message.append(String.format("Parameter %d Declared Return Type: %s%n", i, paramSnippet.getReturnType())); + message.append(String.format("Parameter %d Returned Value Type: %s%n", i, TypeDescriptor.forValue(actualParameters.get(i)))); } return message.toString(); From 07badd6d2caa311b254589eb9632969b99b50e29 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Thu, 17 Oct 2024 20:00:40 +0000 Subject: [PATCH 031/105] update JVMCI to 24+20-jvmci-b01 --- common.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common.json b/common.json index 026f2d2be635..335a1a882dc7 100644 --- a/common.json +++ b/common.json @@ -45,13 +45,13 @@ "oraclejdk23": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+37", "platformspecific": true, "extrabundles": ["static-libs"]}, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+19", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+19-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+19-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+19-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+19-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+19-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+19-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+20", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+20-jvmci-b01-20241017180532-3e48bf9cdf", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+20-jvmci-b01-20241017180532-3e48bf9cdf-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+20-jvmci-b01-20241017180532-3e48bf9cdf-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+20-jvmci-b01-20241017180532-3e48bf9cdf+a202bc2826", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+20-jvmci-b01-20241017180532-3e48bf9cdf+a202bc2826-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+20-jvmci-b01-20241017180532-3e48bf9cdf+a202bc2826-sulong", "platformspecific": true } }, "eclipse": { From 768eee25cd3431461a8d46d8e54cb1ffa33f347f Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Wed, 16 Oct 2024 18:08:36 +0000 Subject: [PATCH 032/105] Update language imports --- vm/mx.vm/suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 3551800f4808..b2f35acf1182 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -33,7 +33,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "8c73897da75360e4c34c64f27e769c5774fc70d3", + "version": "fad9af323bbf014168bda8f1aae3c96b08c7d33e", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] @@ -42,7 +42,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "8c73897da75360e4c34c64f27e769c5774fc70d3", + "version": "fad9af323bbf014168bda8f1aae3c96b08c7d33e", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] From b2c7e0670c05a82d3ad29198ab87cf9f5d066df3 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Thu, 17 Oct 2024 21:36:53 -0700 Subject: [PATCH 033/105] Handle multiple ValueProxyNodes in removeIntermediateMaterialization --- .../src/jdk/graal/compiler/nodes/IfNode.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/IfNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/IfNode.java index b1e7a7c9a8b1..5e4130821823 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/IfNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/IfNode.java @@ -2256,19 +2256,20 @@ private static void propagateInjectedProfile(BranchProbabilityData profile, EndN private void connectEnds(List ends, ValuePhiNode phi, EconomicMap phiValues, AbstractBeginNode successor, AbstractMergeNode oldMerge, SimplifierTool tool) { if (!ends.isEmpty()) { // If there was a value proxy usage, then the proxy needs a new value. - ValueProxyNode valueProxy = null; + List valueProxies; if (successor instanceof LoopExitNode) { - for (Node usage : phi.usages()) { - if (usage instanceof ValueProxyNode && ((ValueProxyNode) usage).proxyPoint() == successor) { - valueProxy = (ValueProxyNode) usage; - } - } + /* + * In rare cases the ValueProxyNodes might not have GVN'ed so handle as many + * matching ValueProxyNodes as exist. + */ + valueProxies = phi.usages().filter(u -> u instanceof ValueProxyNode && ((ValueProxyNode) u).proxyPoint() == successor).snapshot(); + } else { + valueProxies = null; } - final ValueProxyNode proxy = valueProxy; if (ends.size() == 1) { AbstractEndNode end = ends.get(0); - if (proxy != null) { - phi.replaceAtUsages(phiValues.get(end), n -> n == proxy); + if (valueProxies != null) { + phi.replaceAtUsages(phiValues.get(end), valueProxies::contains); } ((FixedWithNextNode) end.predecessor()).setNext(successor); oldMerge.removeEnd(end); @@ -2281,8 +2282,8 @@ private void connectEnds(List ends, ValuePhiNode phi, EconomicMap n == proxy); + if (valueProxies != null) { + phi.replaceAtUsages(newPhi, valueProxies::contains); } for (EndNode end : ends) { From e00e41234fa0439007591c5750fed2328a62c0cf Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 18 Oct 2024 08:01:33 +0200 Subject: [PATCH 034/105] compiler: update JVMCIVersionCheck --- .../src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index c04c3ae8facb..cf6deb77efbb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -55,8 +55,8 @@ public final class JVMCIVersionCheck { private static final Map> JVMCI_MIN_VERSIONS = Map.of( "21", Map.of(DEFAULT_VENDOR_ENTRY, createLegacyVersion(23, 1, 33)), "24", Map.of( - "Oracle Corporation", createLabsJDKVersion("24+19", 1), - DEFAULT_VENDOR_ENTRY, createLabsJDKVersion("24+19", 1))); + "Oracle Corporation", createLabsJDKVersion("24+20", 1), + DEFAULT_VENDOR_ENTRY, createLabsJDKVersion("24+20", 1))); private static final int NA = 0; /** * Minimum Java release supported by Graal. From 70a944b56d994886a7f7feacfed73e148646d5b2 Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 18 Oct 2024 08:17:30 +0200 Subject: [PATCH 035/105] svm: review libcontainer changes from JDK 24+20 --- .../oracle/svm/core/container/ContainerLibrary.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java index f35cc572ffc7..4366b898ec63 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java @@ -60,25 +60,25 @@ @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+19/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/osContainer_linux.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/osContainer_linux.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+19/src/hotspot/os/linux/os_linux.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+20/src/hotspot/os/linux/os_linux.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/os_linux.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/os_linux.inline.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/posix/include/jvm_md.h") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/posix/os_posix.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/posix/os_posix.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+20/src/hotspot/os/posix/os_posix.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+20/src/hotspot/os/posix/os_posix.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/posix/os_posix.inline.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/memory/allocation.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/memory/allocation.inline.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/memory/allStatic.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/nmt/memTag.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+17/src/hotspot/share/runtime/os.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/runtime/os.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+20/src/hotspot/share/runtime/os.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/runtime/os.inline.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/utilities/checkedCast.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/utilities/compilerWarnings_gcc.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/utilities/compilerWarnings.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/utilities/globalDefinitions_gcc.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/utilities/globalDefinitions.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+20/src/hotspot/share/utilities/globalDefinitions.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+18/src/hotspot/share/utilities/macros.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/utilities/ostream.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/utilities/ostream.hpp") From 11cda4912648786bec25340c298708a8e3a7e9db Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 18 Oct 2024 08:39:23 +0200 Subject: [PATCH 036/105] [GR-46615] ProcessBuilderTest did not finish in time. --- .../oracle/truffle/api/test/polyglot/ProcessBuilderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ProcessBuilderTest.java b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ProcessBuilderTest.java index 7eef70653c33..c9ed2bf1fa0a 100644 --- a/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ProcessBuilderTest.java +++ b/truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/ProcessBuilderTest.java @@ -181,7 +181,7 @@ protected Object execute(RootNode node, Env env, Object[] contextArguments, Obje ByteArrayOutputStream stderr = new ByteArrayOutputStream(); TruffleProcessBuilder builder = env.newProcessBuilder(toStringArray(frameArguments)); Process p = builder.redirectOutput(builder.createRedirectToStream(stdout)).redirectError(builder.createRedirectToStream(stderr)).start(); - if (!p.waitFor(30, TimeUnit.SECONDS)) { + if (!p.waitFor(60, TimeUnit.SECONDS)) { p.destroy(); Assert.fail("Process did not finish in expected time."); } From 8a4f370f2877a38e5cff29a61ccde16288bd002c Mon Sep 17 00:00:00 2001 From: Felix Berlakovich Date: Fri, 24 May 2024 12:49:03 +0200 Subject: [PATCH 037/105] Open CompilationTask for extension --- .../jdk/graal/compiler/hotspot/CompilationTask.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java index 9d154fc22888..5249c6c98604 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java @@ -93,7 +93,7 @@ public void onStuckCompilation(CompilationWatchDog watchDog, Thread watched, Com private final HotSpotJVMCIRuntime jvmciRuntime; protected final HotSpotGraalCompiler compiler; - private final HotSpotCompilationIdentifier compilationId; + protected final HotSpotCompilationIdentifier compilationId; private HotSpotInstalledCode installedCode; @@ -117,8 +117,8 @@ public void onStuckCompilation(CompilationWatchDog watchDog, Thread watched, Com private TypeFilter profileSaveFilter; protected class HotSpotCompilationWrapper extends CompilationWrapper { - CompilationResult result; - StructuredGraph graph; + protected CompilationResult result; + protected StructuredGraph graph; protected HotSpotCompilationWrapper() { super(compiler.getGraalRuntime().getOutputDirectory(), compiler.getGraalRuntime().getCompilationProblemsPerAction()); @@ -278,6 +278,10 @@ protected HotSpotCompilationRequestResult performCompilation(DebugContext debug) stats.finish(method, installedCode); + return buildCompilationRequestResult(method); + } + + protected HotSpotCompilationRequestResult buildCompilationRequestResult(HotSpotResolvedJavaMethod method) { // For compilation of substitutions the method in the compilation request might be // different than the actual method parsed. The root of the compilation will always // be the first method in the methods list, so use that instead. @@ -488,7 +492,7 @@ protected HotSpotCompilationRequestResult runCompilation(DebugContext debug, Hot } @SuppressWarnings("try") - private void installMethod(DebugContext debug, StructuredGraph graph, final CompilationResult compResult) { + protected void installMethod(DebugContext debug, StructuredGraph graph, final CompilationResult compResult) { final CodeCacheProvider codeCache = jvmciRuntime.getHostJVMCIBackend().getCodeCache(); HotSpotBackend backend = compiler.getGraalRuntime().getHostBackend(); installedCode = null; From f1a82ac6a3f66d81d200f694ffc13870701736f8 Mon Sep 17 00:00:00 2001 From: Felix Berlakovich Date: Mon, 8 Jul 2024 08:45:27 +0200 Subject: [PATCH 038/105] Add wall-clock timer --- .../{TimerKeyImpl.java => BaseTimerKey.java} | 61 +++++---------- .../jdk/graal/compiler/debug/CPUTimerKey.java | 75 +++++++++++++++++++ .../graal/compiler/debug/DebugContext.java | 21 +++++- .../compiler/debug/WallClockTimerKey.java | 73 ++++++++++++++++++ 4 files changed, 182 insertions(+), 48 deletions(-) rename compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/{TimerKeyImpl.java => BaseTimerKey.java} (72%) create mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/CPUTimerKey.java create mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/WallClockTimerKey.java diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/TimerKeyImpl.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/BaseTimerKey.java similarity index 72% rename from compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/TimerKeyImpl.java rename to compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/BaseTimerKey.java index fb434fc55455..15602b4da5b1 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/TimerKeyImpl.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/BaseTimerKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,9 +30,9 @@ import org.graalvm.collections.Pair; -final class TimerKeyImpl extends AccumulatedKey implements TimerKey { - static class FlatTimer extends AbstractKey implements TimerKey { - private TimerKeyImpl accm; +abstract class BaseTimerKey extends AccumulatedKey implements TimerKey { + static final class FlatTimer extends AbstractKey implements TimerKey { + private BaseTimerKey accm; FlatTimer(String nameFormat, Object nameArg1, Object nameArg2) { super(nameFormat, nameArg1, nameArg2); @@ -43,11 +43,6 @@ protected String createName(String format, Object arg1, Object arg2) { return super.createName(format, arg1, arg2) + FLAT_KEY_SUFFIX; } - @Override - public String toHumanReadableFormat(long value) { - return valueToString(value); - } - @Override public TimeUnit getTimeUnit() { return accm.getTimeUnit(); @@ -59,13 +54,18 @@ public DebugCloseable start(DebugContext debug) { } @Override - public Pair toCSVFormat(long value) { - return TimerKeyImpl.toCSVFormatHelper(value); + public TimerKey doc(String doc) { + throw new IllegalArgumentException("Cannot set documentation for derived key " + getName()); } @Override - public TimerKey doc(String doc) { - throw new IllegalArgumentException("Cannot set documentation for derived key " + getName()); + public String toHumanReadableFormat(long value) { + return accm.toHumanReadableFormat(value); + } + + @Override + public Pair toCSVFormat(long value) { + return accm.toCSVFormat(value); } @Override @@ -74,7 +74,7 @@ public String getDocName() { } } - TimerKeyImpl(String nameFormat, Object nameArg1, Object nameArg2) { + BaseTimerKey(String nameFormat, Object nameArg1, Object nameArg2) { super(new FlatTimer(nameFormat, nameArg1, nameArg2), nameFormat, nameArg1, nameArg2); ((FlatTimer) flat).accm = this; } @@ -82,7 +82,7 @@ public String getDocName() { @Override public DebugCloseable start(DebugContext debug) { if (debug.isTimerEnabled(this)) { - Timer result = new Timer(this, debug); + Timer result = createTimerInstance(debug); debug.currentTimer = result; return result; } else { @@ -90,26 +90,12 @@ public DebugCloseable start(DebugContext debug) { } } - public static String valueToString(long value) { - return String.format("%d.%d ms", value / 1000000, (value / 100000) % 10); - } - @Override public TimerKey getFlat() { return (FlatTimer) flat; } - @Override - public String toHumanReadableFormat(long value) { - return valueToString(value); - } - - @Override - public TimeUnit getTimeUnit() { - return TimeUnit.NANOSECONDS; - } - - static final class Timer extends CloseableCounter implements DebugCloseable { + abstract static class Timer extends CloseableCounter implements DebugCloseable { final DebugContext debug; Timer(AccumulatedKey counter, DebugContext debug) { @@ -122,22 +108,9 @@ public void close() { super.close(); debug.currentTimer = parent; } - - @Override - protected long getCounterValue() { - return TimeSource.getTimeNS(); - } - } - @Override - public Pair toCSVFormat(long value) { - return toCSVFormatHelper(value); - } - - static Pair toCSVFormatHelper(long value) { - return Pair.create(Long.toString(value / 1000), "us"); - } + protected abstract Timer createTimerInstance(DebugContext debug); @Override public TimerKey doc(String doc) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/CPUTimerKey.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/CPUTimerKey.java new file mode 100644 index 000000000000..7b3960cde96d --- /dev/null +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/CPUTimerKey.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.graal.compiler.debug; + +import java.util.concurrent.TimeUnit; + +import org.graalvm.collections.Pair; + +/** + * Represents a timer key that measures elapsed CPU time by relying on the available + * {@link TimeSource}. Note that CPU time is different from the elapsed wall clock time. + * Specifically, the CPU time does not include process waiting time, but only actual time spent on + * the CPU. For example, time spent waiting for a subprocess to finish is not included in this + * timer. + */ +final class CPUTimerKey extends BaseTimerKey { + CPUTimerKey(String nameFormat, Object nameArg1, Object nameArg2) { + super(nameFormat, nameArg1, nameArg2); + } + + static class CPUTimer extends Timer { + + CPUTimer(AccumulatedKey counter, DebugContext debug) { + super(counter, debug); + } + + @Override + protected long getCounterValue() { + return TimeSource.getTimeNS(); + } + } + + @Override + public String toHumanReadableFormat(long value) { + return String.format("%d.%d ms", value / 1000000, (value / 100000) % 10); + } + + @Override + public Pair toCSVFormat(long value) { + return Pair.create(Long.toString(value / 1000), "us"); + } + + @Override + protected Timer createTimerInstance(DebugContext debug) { + return new CPUTimer(this, debug); + } + + @Override + public TimeUnit getTimeUnit() { + return TimeUnit.NANOSECONDS; + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugContext.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugContext.java index b3b0cdb80c98..46c46d8c7789 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugContext.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/DebugContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2011,7 +2011,7 @@ public DebugConfig getConfig() { } /** - * Creates a {@linkplain TimerKey timer}. + * Creates a {@linkplain CPUTimerKey} timer. *

* A disabled timer has virtually no overhead. */ @@ -2019,6 +2019,15 @@ public static TimerKey timer(CharSequence name) { return createTimer("%s", name, null); } + /** + * Creates a {@link WallClockTimerKey} timer. + *

+ * A disabled timer has virtually no overhead. + */ + public static TimerKey wallClockTimer(CharSequence name) { + return createWallClockTimer("%s", name, null); + } + /** * Creates a debug timer. Invoking this method is equivalent to: * @@ -2115,7 +2124,11 @@ static String formatDebugName(String format, Object arg1, Object arg2) { } private static TimerKey createTimer(String format, Object arg1, Object arg2) { - return new TimerKeyImpl(format, arg1, arg2); + return new CPUTimerKey(format, arg1, arg2); + } + + private static TimerKey createWallClockTimer(String format, Object arg1, Object arg2) { + return new WallClockTimerKey(format, arg1, arg2); } /** @@ -2135,7 +2148,7 @@ public interface Scope extends AutoCloseable { void close(); } - boolean isTimerEnabled(TimerKeyImpl key) { + boolean isTimerEnabled(BaseTimerKey key) { if (!metricsEnabled) { // Pulling this common case out of `isTimerEnabledSlow` // gives C1 a better chance to inline this method. diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/WallClockTimerKey.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/WallClockTimerKey.java new file mode 100644 index 000000000000..4c25bf1cb69e --- /dev/null +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/debug/WallClockTimerKey.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.graal.compiler.debug; + +import java.util.concurrent.TimeUnit; + +import org.graalvm.collections.Pair; + +/** + * Represents a timer that measures elapsed wall-clock time. In contrast to {@link CPUTimerKey}, + * this timer also includes time spent waiting for resources. Use this timer if to measure the total + * duration of an event, including, e.g., time spent waiting for a subprocess. + */ +final class WallClockTimerKey extends BaseTimerKey { + + WallClockTimerKey(String nameFormat, Object nameArg1, Object nameArg2) { + super(nameFormat, nameArg1, nameArg2); + } + + static final class WallClockTimer extends BaseTimerKey.Timer { + WallClockTimer(AccumulatedKey counter, DebugContext debug) { + super(counter, debug); + } + + @Override + long getCounterValue() { + return System.currentTimeMillis(); + } + } + + @Override + protected Timer createTimerInstance(DebugContext debug) { + return new WallClockTimer(this, debug); + } + + @Override + public TimeUnit getTimeUnit() { + return TimeUnit.MILLISECONDS; + } + + @Override + public String toHumanReadableFormat(long value) { + return String.format("%d ms", value); + } + + @Override + public Pair toCSVFormat(long value) { + return Pair.create(Long.toString(value), "ms"); + } +} From 480c1b27f8d72fc974d13520aba3037c476c59f0 Mon Sep 17 00:00:00 2001 From: Felix Berlakovich Date: Sun, 6 Oct 2024 17:29:42 +0200 Subject: [PATCH 039/105] Add integrationtest for harness OSR compilation --- .../compiler/replacements/StandardGraphBuilderPlugins.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java index 3ce195a80beb..af969b5866ab 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/StandardGraphBuilderPlugins.java @@ -1784,7 +1784,11 @@ private static void registerGraalDirectivesPlugins(InvocationPlugins plugins, Sn r.register(new RequiredInlineOnlyInvocationPlugin("inCompiledCode") { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { - b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(true)); + if (b.bci() >= b.getGraph().getEntryBCI()) { + b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(true)); + } else { + b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(false)); + } return true; } }); From 7af881b9db39b6052767cd08c25e895c81d552da Mon Sep 17 00:00:00 2001 From: Thomas Schrott Date: Wed, 28 Aug 2024 12:52:47 +0200 Subject: [PATCH 040/105] Use the refactored isolate arguments and cleanup. --- .../src/com/oracle/svm/core/IsolateArgumentParser.java | 9 --------- .../src/com/oracle/svm/core/IsolateArguments.java | 10 ---------- .../svm/core/graal/snippets/CEntryPointSnippets.java | 3 --- .../oracle/svm/core/os/CommittedMemoryProvider.java | 9 +-------- .../oracle/svm/core/os/OSCommittedMemoryProvider.java | 4 ++-- 5 files changed, 3 insertions(+), 32 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java index 0d4d572e7c05..531ff8b47b95 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArgumentParser.java @@ -217,9 +217,6 @@ public void parse(CEntryPointCreateIsolateParameters parameters, IsolateArgument } copyStringArguments(arguments); - - // Temporarily needed. - overrideParameters(parameters, arguments); } @Uninterruptible(reason = "Tear-down in progress.") @@ -269,12 +266,6 @@ private static void copyStringArguments(IsolateArguments arguments) { } } - // Temporary method. - @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) - protected void overrideParameters(CEntryPointCreateIsolateParameters parameters, IsolateArguments arguments) { - parameters.setReservedSpaceSize(WordFactory.unsigned(readLong(arguments, getOptionIndex(SubstrateGCOptions.ReservedAddressSpaceSize)))); - } - /** * Note that this logic must be in sync with * {@link com.oracle.svm.core.option.RuntimeOptionParser#parseAndConsumeAllOptions}. diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArguments.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArguments.java index 0e16ef1730a2..90d4b640fafa 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArguments.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/IsolateArguments.java @@ -30,8 +30,6 @@ import org.graalvm.nativeimage.c.type.CLongPointer; import org.graalvm.word.PointerBase; -import com.oracle.svm.core.c.function.CEntryPointCreateIsolateParameters; - @RawStructure public interface IsolateArguments extends PointerBase { @@ -60,7 +58,6 @@ public interface IsolateArguments extends PointerBase { @RawField void setProtectionKey(int pkey); - // Temporary unused. @RawField int getProtectionKey(); @@ -70,11 +67,4 @@ public interface IsolateArguments extends PointerBase { @RawField boolean getIsCompilationIsolate(); - // Temporary field. - @RawField - void setParameters(CEntryPointCreateIsolateParameters parameters); - - @RawField - CEntryPointCreateIsolateParameters getParameters(); - } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index 89db07381e90..1b41bc3d5bb8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -242,9 +242,6 @@ private static int createIsolate(CEntryPointCreateIsolateParameters providedPara CLongPointer parsedArgs = StackValue.get(IsolateArgumentParser.singleton().getParsedArgsSize()); arguments.setParsedArgs(parsedArgs); - // Temporarily needed. - arguments.setParameters(parameters); - IsolateArgumentParser.singleton().parse(parameters, arguments); Container.initialize(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/CommittedMemoryProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/CommittedMemoryProvider.java index a36381519cc3..a7b01f526f33 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/CommittedMemoryProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/CommittedMemoryProvider.java @@ -32,7 +32,6 @@ import com.oracle.svm.core.IsolateArguments; import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.c.function.CEntryPointCreateIsolateParameters; import jdk.graal.compiler.api.replacements.Fold; @@ -53,13 +52,7 @@ static CommittedMemoryProvider get() { * @return zero in case of success, non-zero in case of an error. */ @Uninterruptible(reason = "Still being initialized.") - int initialize(WordPointer heapBasePointer, CEntryPointCreateIsolateParameters parameters); - - @Uninterruptible(reason = "Still being initialized.") - default int initialize(WordPointer heapBasePointer, IsolateArguments arguments) { - // The default implementation of this method is temporary. - return initialize(heapBasePointer, arguments.getParameters()); - } + int initialize(WordPointer heapBasePointer, IsolateArguments arguments); /** * Tear down for the current isolate. This must be the last method of this interface diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/OSCommittedMemoryProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/OSCommittedMemoryProvider.java index f7115ef811ce..60d06ade6fb4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/OSCommittedMemoryProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/os/OSCommittedMemoryProvider.java @@ -32,10 +32,10 @@ import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.type.WordPointer; +import com.oracle.svm.core.IsolateArguments; import com.oracle.svm.core.Isolates; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.c.function.CEntryPointCreateIsolateParameters; import com.oracle.svm.core.c.function.CEntryPointErrors; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; @@ -48,7 +48,7 @@ public OSCommittedMemoryProvider() { @Override @Uninterruptible(reason = "Still being initialized.") - public int initialize(WordPointer heapBasePointer, CEntryPointCreateIsolateParameters parameters) { + public int initialize(WordPointer heapBasePointer, IsolateArguments arguments) { if (!SubstrateOptions.SpawnIsolates.getValue()) { int result = protectSingleIsolateImageHeap(); if (result == CEntryPointErrors.NO_ERROR) { From d557cf606f52ae0197050d6066c88f5c9cbc1f4b Mon Sep 17 00:00:00 2001 From: d-kozak Date: Tue, 8 Oct 2024 13:36:55 +0200 Subject: [PATCH 041/105] Typeflow.getState() cleanup --- .../graal/pointsto/PointsToAnalysis.java | 12 +++-- .../flow/AbstractSpecialInvokeTypeFlow.java | 6 ++- .../flow/AbstractStaticInvokeTypeFlow.java | 2 +- .../flow/AbstractVirtualInvokeTypeFlow.java | 6 ++- .../flow/ActualParameterTypeFlow.java | 6 +-- .../pointsto/flow/ActualReturnTypeFlow.java | 4 +- .../pointsto/flow/ArrayCopyTypeFlow.java | 2 +- .../pointsto/flow/ArrayElementsTypeFlow.java | 2 +- .../flow/BooleanPrimitiveCheckTypeFlow.java | 10 ++-- .../graal/pointsto/flow/BoxTypeFlow.java | 2 +- .../flow/CallSiteSensitiveMethodTypeFlow.java | 2 +- .../graal/pointsto/flow/CloneTypeFlow.java | 12 ++++- .../graal/pointsto/flow/ConditionalFlow.java | 16 +++--- .../flow/ConstantPrimitiveSourceTypeFlow.java | 2 +- .../graal/pointsto/flow/ConstantTypeFlow.java | 2 +- .../flow/ContextInsensitiveFieldTypeFlow.java | 2 +- .../flow/DynamicNewInstanceTypeFlow.java | 14 ++++- .../graal/pointsto/flow/FieldTypeFlow.java | 2 +- .../pointsto/flow/FormalParamTypeFlow.java | 2 +- .../pointsto/flow/FormalReceiverTypeFlow.java | 2 +- .../pointsto/flow/FormalReturnTypeFlow.java | 2 +- .../pointsto/flow/LoadFieldTypeFlow.java | 4 +- .../graal/pointsto/flow/MergeTypeFlow.java | 2 +- .../graal/pointsto/flow/MethodTypeFlow.java | 6 ++- .../pointsto/flow/MethodTypeFlowBuilder.java | 5 +- .../pointsto/flow/NewInstanceTypeFlow.java | 2 +- .../pointsto/flow/NullCheckTypeFlow.java | 2 +- .../pointsto/flow/OffsetLoadTypeFlow.java | 4 +- .../pointsto/flow/OffsetStoreTypeFlow.java | 4 +- .../flow/PrimitiveFilterTypeFlow.java | 10 ++-- .../graal/pointsto/flow/ProxyTypeFlow.java | 8 ++- .../graal/pointsto/flow/SourceTypeFlow.java | 9 ++-- .../pointsto/flow/StoreFieldTypeFlow.java | 4 +- .../oracle/graal/pointsto/flow/TypeFlow.java | 52 +++++++++++++++++-- .../graal/pointsto/reports/ReportUtils.java | 8 +-- .../pointsto/results/StrengthenGraphs.java | 7 ++- .../pointsto/typestate/PointsToStats.java | 4 +- .../hosted/dashboard/PointsToBreakdown.java | 4 +- 38 files changed, 167 insertions(+), 78 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index 938a2d448413..029170707d77 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -210,7 +210,9 @@ public void forceUnsafeUpdate(AnalysisField field) { * update; an update of the receiver object flow will trigger an updated of the * observers, i.e., of the unsafe load. */ - this.postFlow(unsafeLoad.receiver()); + if (unsafeLoad.receiver().isFlowEnabled()) { + this.postFlow(unsafeLoad.receiver()); + } } // force update of the unsafe stores @@ -223,7 +225,9 @@ public void forceUnsafeUpdate(AnalysisField field) { * update; an update of the receiver object flow will trigger an updated of the * observers, i.e., of the unsafe store. */ - this.postFlow(unsafeStore.receiver()); + if (unsafeStore.receiver().isFlowEnabled()) { + this.postFlow(unsafeStore.receiver()); + } } } @@ -563,6 +567,7 @@ public interface TypeFlowRunnable extends DebugContextRunnable { } public void postFlow(final TypeFlow operation) { + assert operation.isFlowEnabled() : "Only enabled flows should be updated: " + operation; if (operation.inQueue) { return; } @@ -766,7 +771,8 @@ public void addCompleted(DebugContextRunnable r, long nanos) { TypeFlow tf = ((TypeFlowRunnable) r).getTypeFlow(); String source = String.valueOf(tf.getSource()); System.out.format("LONG RUNNING %.2f %s %x %s state %s %x uses %d observers %d%n", (double) nanos / 1_000_000_000, ClassUtil.getUnqualifiedName(tf.getClass()), - System.identityHashCode(tf), source, PointsToStats.asString(tf.getState()), System.identityHashCode(tf.getState()), tf.getUses().size(), tf.getObservers().size()); + System.identityHashCode(tf), source, PointsToStats.asString(tf.getRawState()), System.identityHashCode(tf.getRawState()), tf.getUses().size(), + tf.getObservers().size()); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AbstractSpecialInvokeTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AbstractSpecialInvokeTypeFlow.java index a482cd97dc34..cf0bc52ddf44 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AbstractSpecialInvokeTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AbstractSpecialInvokeTypeFlow.java @@ -47,7 +47,9 @@ protected AbstractSpecialInvokeTypeFlow(PointsToAnalysis bb, MethodFlowsGraph me @Override protected void onFlowEnabled(PointsToAnalysis bb) { - bb.postTask(() -> onObservedUpdate(bb)); + if (getReceiver().isFlowEnabled()) { + bb.postTask(() -> onObservedUpdate(bb)); + } } @Override @@ -71,7 +73,7 @@ public void onObservedSaturated(PointsToAnalysis bb, TypeFlow observed) { @Override public String toString() { - return "SpecialInvoke<" + targetMethod.format("%h.%n") + ">" + ":" + getState(); + return "SpecialInvoke<" + targetMethod.format("%h.%n") + ">" + ":" + getStateDescription(); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AbstractStaticInvokeTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AbstractStaticInvokeTypeFlow.java index 0198e99e379e..ef79ececde67 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AbstractStaticInvokeTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AbstractStaticInvokeTypeFlow.java @@ -43,6 +43,6 @@ protected AbstractStaticInvokeTypeFlow(PointsToAnalysis bb, MethodFlowsGraph met @Override public String toString() { - return "StaticInvoke<" + targetMethod.format("%h.%n") + ">" + ":" + getState(); + return "StaticInvoke<" + targetMethod.format("%h.%n") + ">" + ":" + getStateDescription(); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AbstractVirtualInvokeTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AbstractVirtualInvokeTypeFlow.java index fc2cb080e39f..e91f529efe24 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AbstractVirtualInvokeTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AbstractVirtualInvokeTypeFlow.java @@ -89,7 +89,9 @@ public final boolean isDirectInvoke() { @Override protected void onFlowEnabled(PointsToAnalysis bb) { - bb.postTask(() -> onObservedUpdate(bb)); + if (getReceiver().isFlowEnabled()) { + bb.postTask(() -> onObservedUpdate(bb)); + } } @Override @@ -129,6 +131,6 @@ public Collection getCalleesForReturnLinking() { @Override public String toString() { - return "VirtualInvoke<" + targetMethod.format("%h.%n") + ">" + ":" + getState(); + return "VirtualInvoke<" + targetMethod.format("%h.%n") + ">" + ":" + getStateDescription(); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ActualParameterTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ActualParameterTypeFlow.java index 9d82a31907c3..a1588f806e8b 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ActualParameterTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ActualParameterTypeFlow.java @@ -24,10 +24,10 @@ */ package com.oracle.graal.pointsto.flow; -import jdk.graal.compiler.nodes.ValueNode; - import com.oracle.graal.pointsto.meta.AnalysisType; +import jdk.graal.compiler.nodes.ValueNode; + /** * A sink type flow for the context insensitive invoke used to link in parameters in each caller * context. @@ -39,6 +39,6 @@ public ActualParameterTypeFlow(AnalysisType declaredType) { @Override public String toString() { - return "ActualParameter<" + getState() + '>'; + return "ActualParameter<" + getStateDescription() + '>'; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ActualReturnTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ActualReturnTypeFlow.java index fac14f47f0fc..0598f22fbfb9 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ActualReturnTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ActualReturnTypeFlow.java @@ -53,7 +53,7 @@ public TypeFlow copy(PointsToAnalysis bb, MethodFlowsGraph met @Override public String toString() { - return "ActualReturn<" + getState() + '>'; + return "ActualReturn<" + getStateDescription() + '>'; } public void setInvokeFlow(InvokeTypeFlow invokeFlow) { @@ -68,7 +68,7 @@ public InvokeTypeFlow invokeFlow() { public String format(boolean withState, boolean withSource) { return "Actual return of call to " + invokeFlow.targetMethod.format("%H.%n(%p)") + (withSource ? " at " + formatSource() : "") + - (withState ? " with state <" + getState() + ">" : ""); + (withState ? " with state <" + getStateDescription() + ">" : ""); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayCopyTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayCopyTypeFlow.java index 59eec8415a9b..082a49c6e9c2 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayCopyTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayCopyTypeFlow.java @@ -141,6 +141,6 @@ public TypeFlow destination() { @Override public String toString() { - return "ArrayCopyTypeFlow<" + getState() + ">"; + return "ArrayCopyTypeFlow<" + getStateDescription() + ">"; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayElementsTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayElementsTypeFlow.java index 1ab883d65253..3cdfaeb06a21 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayElementsTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayElementsTypeFlow.java @@ -85,7 +85,7 @@ public AnalysisObject object() { @Override public String toString() { - return "MixedElementsFlow<" + source.getName() + "\n" + getState() + ">"; + return "MixedElementsFlow<" + source.getName() + "\n" + getStateDescription() + ">"; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/BooleanPrimitiveCheckTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/BooleanPrimitiveCheckTypeFlow.java index 92327796d25d..ea2f4bad2a80 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/BooleanPrimitiveCheckTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/BooleanPrimitiveCheckTypeFlow.java @@ -61,7 +61,7 @@ public TypeFlow copy(PointsToAnalysis bb, MethodFlowsGraph met @Override public boolean addState(PointsToAnalysis bb, TypeState add) { - return super.addState(bb, eval()); + return super.addState(bb, eval(bb)); } @Override @@ -70,7 +70,7 @@ protected void onInputSaturated(PointsToAnalysis bb, TypeFlow input) { * If an input saturated, it does not mean that the condition has to always saturate as * well, e.g. Any == {5} will return {5}. */ - super.addState(bb, eval()); + super.addState(bb, eval(bb)); } /** @@ -78,9 +78,9 @@ protected void onInputSaturated(PointsToAnalysis bb, TypeFlow input) { * * @return can be either empty, true, false, or any. */ - public TypeState eval() { - var leftState = left.isSaturated() ? TypeState.anyPrimitiveState() : left.getState(); - var rightState = right.isSaturated() ? TypeState.anyPrimitiveState() : right.getState(); + public TypeState eval(PointsToAnalysis bb) { + var leftState = left.getOutputState(bb); + var rightState = right.getOutputState(bb); if (leftState.isEmpty() || rightState.isEmpty()) { return TypeState.forEmpty(); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/BoxTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/BoxTypeFlow.java index 872c7ab3f474..6e9d3b0edec9 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/BoxTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/BoxTypeFlow.java @@ -46,7 +46,7 @@ public TypeFlow copy(PointsToAnalysis bb, MethodFlowsGraph met @Override public String toString() { - return "BoxFlow<" + getState() + ">"; + return "BoxFlow<" + getStateDescription() + ">"; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CallSiteSensitiveMethodTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CallSiteSensitiveMethodTypeFlow.java index c016db0c0574..c048ed22751e 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CallSiteSensitiveMethodTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CallSiteSensitiveMethodTypeFlow.java @@ -117,7 +117,7 @@ public TypeState foldTypeFlow(PointsToAnalysis bb, TypeFlow originalTypeFlow) } if (originalTypeFlow instanceof FieldTypeFlow || originalTypeFlow instanceof ArrayElementsTypeFlow) { // field and array flows are not call site sensitive and thus not cloneable - return originalTypeFlow.state; + return originalTypeFlow.getState(); } TypeState result = TypeState.forEmpty(); for (MethodFlowsGraph methodFlows : clonedMethodFlows.values()) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CloneTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CloneTypeFlow.java index 2384a11c7c6c..c653d73e52e4 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CloneTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CloneTypeFlow.java @@ -61,8 +61,18 @@ public TypeFlow copy(PointsToAnalysis bb, MethodFlowsGraph met return new CloneTypeFlow(bb, this, methodFlows, allocContext); } + @Override + protected void onFlowEnabled(PointsToAnalysis bb) { + if (input.isFlowEnabled()) { + bb.postTask(() -> onObservedUpdate(bb)); + } + } + @Override public void onObservedUpdate(PointsToAnalysis bb) { + if (!isFlowEnabled()) { + return; + } /* The input state has changed, clone its objects. */ TypeState inputState = input.getState(); @@ -73,7 +83,7 @@ public void onObservedUpdate(PointsToAnalysis bb) { * encapsulate the location of the cloning. From the point of view of the analysis a clone * flow is a source. */ - TypeState resultState = bb.analysisPolicy().cloneState(bb, state, inputState, source, allocationContext); + TypeState resultState = bb.analysisPolicy().cloneState(bb, getState(), inputState, source, allocationContext); /* Update the clone flow state. */ addState(bb, resultState); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ConditionalFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ConditionalFlow.java index 2c541020ccff..0f6f8814396f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ConditionalFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ConditionalFlow.java @@ -70,22 +70,24 @@ public TypeFlow copy(PointsToAnalysis bb, MethodFlowsGraph met @Override public void onObservedUpdate(PointsToAnalysis bb) { - addState(bb, condition.getState()); + addState(bb, condition.getOutputState(bb)); } @Override public void onObservedSaturated(PointsToAnalysis bb, TypeFlow observed) { /* If the condition is already saturated, merge both inputs. */ - super.addState(bb, TypeState.forUnion(bb, trueValue.getState(), falseValue.getState())); + super.addState(bb, TypeState.forUnion(bb, trueValue.getOutputState(bb), falseValue.getOutputState(bb))); } @Override public boolean addState(PointsToAnalysis bb, TypeState add) { + TypeState trueState = trueValue.getOutputState(bb); + TypeState falseState = falseValue.getOutputState(bb); if (condition.isSaturated()) { /* If the condition is already saturated, merge both inputs. */ - return super.addState(bb, TypeState.forUnion(bb, trueValue.getState(), falseValue.getState())); + return super.addState(bb, TypeState.forUnion(bb, trueState, falseState)); } - var conditionValue = condition.getState(); + var conditionValue = condition.getOutputState(bb); if (conditionValue.isEmpty()) { /* If the condition is empty, do not produce any output yet. */ return false; @@ -94,11 +96,11 @@ public boolean addState(PointsToAnalysis bb, TypeState add) { var canBeTrue = prim.canBeTrue(); var canBeFalse = prim.canBeFalse(); if (canBeTrue && !canBeFalse) { - return super.addState(bb, trueValue.getState()); + return super.addState(bb, trueState); } else if (!canBeTrue && canBeFalse) { - return super.addState(bb, falseValue.getState()); + return super.addState(bb, falseState); } - return super.addState(bb, TypeState.forUnion(bb, trueValue.getState(), falseValue.getState())); + return super.addState(bb, TypeState.forUnion(bb, trueState, falseState)); } throw AnalysisError.shouldNotReachHere("Unexpected non-primitive type state of the condition: " + conditionValue + ", at flow " + this); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ConstantPrimitiveSourceTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ConstantPrimitiveSourceTypeFlow.java index ddf4024a9f0d..3b547a4e89fc 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ConstantPrimitiveSourceTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ConstantPrimitiveSourceTypeFlow.java @@ -37,7 +37,7 @@ public ConstantPrimitiveSourceTypeFlow(BytecodePosition source, AnalysisType typ } public ConstantPrimitiveSourceTypeFlow(ConstantPrimitiveSourceTypeFlow original, MethodFlowsGraph methodFlows) { - super(original, methodFlows, original.getState()); + super(original, methodFlows, original.getRawState()); } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ConstantTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ConstantTypeFlow.java index ebdb65a2f16e..b9bcf93d8c40 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ConstantTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ConstantTypeFlow.java @@ -73,6 +73,6 @@ public boolean needsInitialization() { @Override public String toString() { - return "ConstantFlow<" + getState() + ">"; + return "ConstantFlow<" + getStateDescription() + ">"; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ContextInsensitiveFieldTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ContextInsensitiveFieldTypeFlow.java index 645b51d08edc..c1fae54bf7c1 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ContextInsensitiveFieldTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ContextInsensitiveFieldTypeFlow.java @@ -56,7 +56,7 @@ public boolean addState(PointsToAnalysis bb, TypeState add) { @Override public String toString() { - return "ContextInsensitiveFieldTypeFlow<" + source.format("%h.%n") + System.lineSeparator() + getState() + ">"; + return "ContextInsensitiveFieldTypeFlow<" + source.format("%h.%n") + System.lineSeparator() + getStateDescription() + ">"; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DynamicNewInstanceTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DynamicNewInstanceTypeFlow.java index 63df237c007b..34bc03f8e1de 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DynamicNewInstanceTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DynamicNewInstanceTypeFlow.java @@ -77,11 +77,21 @@ public boolean needsInitialization() { return true; } + @Override + protected void onFlowEnabled(PointsToAnalysis bb) { + if (newTypeFlow.isFlowEnabled()) { + bb.postTask(() -> onObservedUpdate(bb)); + } + } + @Override public void onObservedUpdate(PointsToAnalysis bb) { + if (!isFlowEnabled()) { + return; + } /* The state of the new type provider has changed. */ TypeState newTypeState = newTypeFlow.getState(); - TypeState updateState = bb.analysisPolicy().dynamicNewInstanceState(bb, state, newTypeState, source, allocationContext); + TypeState updateState = bb.analysisPolicy().dynamicNewInstanceState(bb, getState(), newTypeState, source, allocationContext); addState(bb, updateState); } @@ -108,6 +118,6 @@ public boolean canSaturate() { @Override public String toString() { - return "DynamicNewInstanceFlow<" + getState() + ">"; + return "DynamicNewInstanceFlow<" + getStateDescription() + ">"; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldTypeFlow.java index f56aaa40790a..3724d70c579e 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldTypeFlow.java @@ -98,7 +98,7 @@ public FieldFilterTypeFlow filterFlow(PointsToAnalysis bb) { @Override public String toString() { - return "FieldFlow<" + source.format("%h.%n") + System.lineSeparator() + getState() + ">"; + return "FieldFlow<" + source.format("%h.%n") + System.lineSeparator() + getStateDescription() + ">"; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalParamTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalParamTypeFlow.java index 3b9b11d07a04..3a972ccf92a1 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalParamTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalParamTypeFlow.java @@ -69,7 +69,7 @@ public int position() { public String format(boolean withState, boolean withSource) { return "Parameter " + position + " of " + method().format("%H.%n(%p)") + (withSource ? " at " + formatSource() : "") + - (withState ? " with state <" + getState() + ">" : ""); + (withState ? " with state <" + getStateDescription() + ">" : ""); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReceiverTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReceiverTypeFlow.java index 252a841f8f62..fb7eaad20fbc 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReceiverTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReceiverTypeFlow.java @@ -90,7 +90,7 @@ public boolean addReceiverState(PointsToAnalysis bb, TypeState add) { public String format(boolean withState, boolean withSource) { return "Formal receiver of " + method().format("%H.%n(%p)") + (withSource ? " at " + formatSource() : "") + - (withState ? " with state <" + getState() + ">" : ""); + (withState ? " with state <" + getStateDescription() + ">" : ""); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReturnTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReturnTypeFlow.java index 88ec0eb06e24..26ce11f7cba7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReturnTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReturnTypeFlow.java @@ -68,6 +68,6 @@ public TypeFlow copy(PointsToAnalysis bb, MethodFlowsGraph met public String format(boolean withState, boolean withSource) { return "Formal return from " + method().format("%H.%n(%p)") + (withSource ? " at " + formatSource() : "") + - (withState ? " with state <" + getState() + ">" : ""); + (withState ? " with state <" + getStateDescription() + ">" : ""); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/LoadFieldTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/LoadFieldTypeFlow.java index c5dd681f3236..7b45b6bc6afd 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/LoadFieldTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/LoadFieldTypeFlow.java @@ -81,7 +81,7 @@ public boolean needsInitialization() { @Override public String toString() { - return "LoadStaticFieldTypeFlow<" + getState() + ">"; + return "LoadStaticFieldTypeFlow<" + getStateDescription() + ">"; } } @@ -163,7 +163,7 @@ protected void onSaturated() { @Override public String toString() { - return "LoadInstanceFieldTypeFlow<" + getState() + ">"; + return "LoadInstanceFieldTypeFlow<" + getStateDescription() + ">"; } } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MergeTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MergeTypeFlow.java index a735c2818890..5e8e7dd01d3e 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MergeTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MergeTypeFlow.java @@ -46,6 +46,6 @@ public TypeFlow copy(PointsToAnalysis bb, MethodFlowsGraph met @Override public String toString() { - return "MergeTypeFlow<" + getState() + ">"; + return "MergeTypeFlow<" + getStateDescription() + ">"; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java index 255cf7887e0d..8048d4785852 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java @@ -248,7 +248,11 @@ public boolean isSaturated(@SuppressWarnings("unused") PointsToAnalysis bb, Type * Return the type state of the original flow. */ public TypeState foldTypeFlow(@SuppressWarnings("unused") PointsToAnalysis bb, TypeFlow originalTypeFlow) { - return originalTypeFlow == null ? null : originalTypeFlow.getState(); + if (originalTypeFlow == null) { + return null; + } + assert !originalTypeFlow.isSaturated() : "Saturated flows should not be accessed here: " + originalTypeFlow; + return originalTypeFlow.getState(); } /** diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java index 4b4089a54d53..2dd06112e704 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java @@ -550,6 +550,7 @@ private void insertPlaceholderParamAndReturnFlows() { } else { parameter = new FormalParamTypeFlow(position, paramType, index); } + parameter.enableFlow(bb); flowsGraph.setParameter(index, parameter); } } @@ -562,7 +563,9 @@ private void insertPlaceholderParamAndReturnFlows() { * We want to determine whether void methods can return, so we need to create * FormalReturnTypeFlow for them. */ - flowsGraph.setReturnFlow(new FormalReturnTypeFlow(position, returnType)); + FormalReturnTypeFlow returnFlow = new FormalReturnTypeFlow(position, returnType); + returnFlow.enableFlow(bb); + flowsGraph.setReturnFlow(returnFlow); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/NewInstanceTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/NewInstanceTypeFlow.java index a62d7eec9336..9d9002e712ab 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/NewInstanceTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/NewInstanceTypeFlow.java @@ -149,6 +149,6 @@ private AnalysisObject createHeapObject(PointsToAnalysis bb, AnalysisContext obj @Override public String toString() { - return "NewInstanceFlow<" + getState() + ">"; + return "NewInstanceFlow<" + getStateDescription() + ">"; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/NullCheckTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/NullCheckTypeFlow.java index 4651c87d150f..2665c6aaee7b 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/NullCheckTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/NullCheckTypeFlow.java @@ -72,7 +72,7 @@ public TypeState filter(PointsToAnalysis bb, TypeState newState) { @Override public String toString() { - return "NullCheckTypeFlow<" + (getDeclaredType() != null ? getDeclaredType().toJavaName(false) : "null") + " : " + getState() + ">"; + return "NullCheckTypeFlow<" + (getDeclaredType() != null ? getDeclaredType().toJavaName(false) : "null") + " : " + getStateDescription() + ">"; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetLoadTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetLoadTypeFlow.java index ca3c6d4713c6..928e9fd2e257 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetLoadTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetLoadTypeFlow.java @@ -144,7 +144,7 @@ public TypeState filter(PointsToAnalysis bb, TypeState newState) { @Override public String toString() { - return "LoadIndexedTypeFlow<" + getState() + ">"; + return "LoadIndexedTypeFlow<" + getStateDescription() + ">"; } } @@ -246,7 +246,7 @@ public void onObservedUpdate(PointsToAnalysis bb) { @Override public String toString() { - return "UnsafeLoadTypeFlow<" + getState() + ">"; + return "UnsafeLoadTypeFlow<" + getStateDescription() + ">"; } } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetStoreTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetStoreTypeFlow.java index b01f8da156ec..c83377909d05 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetStoreTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetStoreTypeFlow.java @@ -169,7 +169,7 @@ public void onObservedSaturated(PointsToAnalysis bb, TypeFlow observed) { @Override public String toString() { - return "StoreIndexedTypeFlow<" + getState() + ">"; + return "StoreIndexedTypeFlow<" + getStateDescription() + ">"; } } @@ -294,7 +294,7 @@ public void onObservedSaturated(PointsToAnalysis bb, TypeFlow observed) { @Override public String toString() { - return "UnsafeStoreTypeFlow<" + getState() + ">"; + return "UnsafeStoreTypeFlow<" + getStateDescription() + ">"; } } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/PrimitiveFilterTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/PrimitiveFilterTypeFlow.java index 0045fb47e211..956559fc370c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/PrimitiveFilterTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/PrimitiveFilterTypeFlow.java @@ -65,7 +65,7 @@ public TypeFlow copy(PointsToAnalysis bb, MethodFlowsGraph met @Override public boolean addState(PointsToAnalysis bb, TypeState add) { - return super.addState(bb, eval()); + return super.addState(bb, eval(bb)); } @Override @@ -74,15 +74,15 @@ protected void onInputSaturated(PointsToAnalysis bb, TypeFlow input) { * If an input saturated, it does not mean that the condition has to always saturate as * well, e.g. Any == 5 still returns 5. */ - super.addState(bb, eval()); + super.addState(bb, eval(bb)); } /** * Filters the type state of left using condition and right. */ - private TypeState eval() { - var leftState = left.isSaturated() ? TypeState.anyPrimitiveState() : left.getState(); - var rightState = right.isSaturated() ? TypeState.anyPrimitiveState() : right.getState(); + private TypeState eval(PointsToAnalysis bb) { + var leftState = left.getOutputState(bb); + var rightState = right.getOutputState(bb); assert leftState.isPrimitive() || leftState.isEmpty() : left; assert rightState.isPrimitive() || rightState.isEmpty() : right; return TypeState.filter(leftState, comparison, rightState); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ProxyTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ProxyTypeFlow.java index 2b558c4b404c..cd9c1ab15ee4 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ProxyTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ProxyTypeFlow.java @@ -24,6 +24,7 @@ */ package com.oracle.graal.pointsto.flow; +import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.typestate.TypeState; import com.oracle.graal.pointsto.util.AnalysisError; @@ -69,7 +70,12 @@ public void update(PointsToAnalysis bb) { } @Override - public TypeState getState() { + public TypeState getOutputState(BigBang bb) { + throw AnalysisError.shouldNotReachHere("should not be reached during analysis"); + } + + @Override + public TypeState getRawState() { throw AnalysisError.shouldNotReachHere("should not be reached during analysis"); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/SourceTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/SourceTypeFlow.java index 8a20c867cd8b..28222a4d8846 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/SourceTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/SourceTypeFlow.java @@ -24,14 +24,13 @@ */ package com.oracle.graal.pointsto.flow; -import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode; -import jdk.graal.compiler.nodes.extended.JavaReadNode; - import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.typestate.TypeState; import com.oracle.graal.pointsto.util.AnalysisError; +import jdk.graal.compiler.nodes.extended.BytecodeExceptionNode; +import jdk.graal.compiler.nodes.extended.JavaReadNode; import jdk.vm.ci.code.BytecodePosition; /** @@ -59,7 +58,7 @@ public SourceTypeFlow(BytecodePosition position, AnalysisType type, boolean canB } public SourceTypeFlow(SourceTypeFlow original, MethodFlowsGraph methodFlows) { - super(original, methodFlows, original.getState().canBeNull() ? TypeState.forNull() : TypeState.forEmpty()); + super(original, methodFlows, original.getRawState().canBeNull() ? TypeState.forNull() : TypeState.forEmpty()); } @Override @@ -100,6 +99,6 @@ public boolean canSaturate() { @Override public String toString() { - return "SourceFlow<" + getState() + ">"; + return "SourceFlow<" + getStateDescription() + ">"; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/StoreFieldTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/StoreFieldTypeFlow.java index ed4a895517e6..a309cbe6740f 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/StoreFieldTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/StoreFieldTypeFlow.java @@ -92,7 +92,7 @@ public boolean needsInitialization() { @Override public String toString() { - return "StoreStaticFieldTypeFlow<" + getState() + ">"; + return "StoreStaticFieldTypeFlow<" + getStateDescription() + ">"; } } @@ -199,7 +199,7 @@ public void onObservedSaturated(PointsToAnalysis bb, TypeFlow observed) { @Override public String toString() { - return "StoreInstanceFieldTypeFlow<" + getState() + ">"; + return "StoreInstanceFieldTypeFlow<" + getStateDescription() + ">"; } } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java index 41981c8bcee8..5ad6ae5d1052 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java @@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.meta.AnalysisMethod; @@ -107,7 +108,7 @@ public abstract class TypeFlow { */ protected final AnalysisType declaredType; - protected volatile TypeState state; + private volatile TypeState state; /** Nonzero iff this flow was enabled by its predicate. */ @SuppressWarnings("unused") private volatile int isEnabled; @@ -412,15 +413,43 @@ public boolean isContextInsensitive() { return false; } - public AnalysisType getDeclaredType() { - return declaredType; + /** + * Returns the type state that is currently propagated along the use edges out of this flow. For + * disabled flows, this value is always empty. For saturated flows, this value will be + * AllInstantiated/AnyPrimitive. This is a helper method that should be used when the user is + * not sure what is the state of this flow. If it is known from the context that this flow is + * already enabled, use {@link TypeFlow#getState} + */ + public TypeState getOutputState(BigBang bb) { + if (!isFlowEnabled()) { + return TypeState.forEmpty(); + } else if (isSaturated() && declaredType != null) { + return declaredType.getTypeFlow(bb, true).state; + } + return state; } + /** + * Returns the type state of the flow. Should be used most of the time, but only for flows that + * are already enabled. + */ public TypeState getState() { - /* GR-58690 - We should not query the type state of disabled flows. */ + assert isFlowEnabled() : "This method should be used only for enabled flows: " + this; + return state; + } + + /** + * Returns the raw type state of this flow regardless of its disabled/enabled/saturation status. + * Use this only when you know what you are doing, e.g. for logging. + */ + public TypeState getRawState() { return state; } + public AnalysisType getDeclaredType() { + return declaredType; + } + public boolean isAllInstantiated() { return this instanceof AllInstantiatedTypeFlow; } @@ -1035,7 +1064,20 @@ public String formatSource() { } public String format(boolean withState, boolean withSource) { - return ClassUtil.getUnqualifiedName(getClass()) + (withSource ? " at " + formatSource() : "") + (withState ? " with state <" + getState() + '>' : ""); + return ClassUtil.getUnqualifiedName(getClass()) + (withSource ? " at " + formatSource() : "") + (withState ? " with state <" + getStateDescription() + '>' : ""); + } + + /** + * Returns the string representation of the state of this flow, including + * disabled/enabled/saturation status. Meant mainly for logging and debugging. + */ + protected final String getStateDescription() { + if (!isFlowEnabled()) { + return "DISABLED: " + state; + } else if (isSaturated()) { + return "SATURATED: " + state; + } + return state.toString(); } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java index 280e10433dad..21e38e9e6751 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java @@ -298,22 +298,22 @@ public static String typePropagationTrace(PointsToAnalysis bb, TypeFlow flow, public static String typePropagationTrace(PointsToAnalysis bb, TypeFlow flow, AnalysisType type, String indent) { if (bb.trackTypeFlowInputs()) { StringBuilder msg = new StringBuilder(String.format("Propagation trace through type flows for type %s: %n", type.toJavaName())); - followInput(flow, type, indent, new HashSet<>(), msg); + followInput(bb, flow, type, indent, new HashSet<>(), msg); return msg.toString(); } else { return String.format("To print the propagation trace through type flows for type %s set the -H:+TrackInputFlows option. %n", type.toJavaName()); } } - private static void followInput(TypeFlow flow, AnalysisType type, String indent, HashSet> seen, StringBuilder msg) { + private static void followInput(PointsToAnalysis bb, TypeFlow flow, AnalysisType type, String indent, HashSet> seen, StringBuilder msg) { seen.add(flow); if (flow instanceof AllInstantiatedTypeFlow) { msg.append(String.format("AllInstantiated(%s)%n", flow.getDeclaredType().toJavaName(true))); } else { msg.append(String.format("%sat %s: %s%n", indent, flow.formatSource(), flow.format(false, false))); for (TypeFlow input : flow.getInputs()) { - if (!seen.contains(input) && input.getState().containsType(type)) { - followInput(input, type, indent, seen, msg); + if (!seen.contains(input) && input.getOutputState(bb).containsType(type)) { + followInput(bb, input, type, indent, seen, msg); break; } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java index 8fa695ec560a..7418ba9c607c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java @@ -803,6 +803,9 @@ private void devirtualizeInvoke(AnalysisMethod singleCallee, Invoke invoke) { private boolean isUnreachable(Node branch) { TypeFlow branchFlow = getNodeFlow(branch); if (branchFlow != null && !methodFlow.isSaturated(((PointsToAnalysis) bb), branchFlow)) { + if (!branchFlow.isFlowEnabled()) { + return true; + } TypeState typeState = methodFlow.foldTypeFlow((PointsToAnalysis) bb, branchFlow); if (branchFlow.isPrimitiveFlow()) { /* @@ -811,7 +814,7 @@ private boolean isUnreachable(Node branch) { */ assert branchFlow instanceof PrimitiveFilterTypeFlow : "Unexpected type of primitive flow encountered as branch predicate: " + branchFlow; } - return !branchFlow.isFlowEnabled() || typeState.isEmpty(); + return typeState.isEmpty(); } return false; } @@ -893,7 +896,7 @@ private Object strengthenStampFromTypeFlow(ValueNode node, TypeFlow nodeFlow, */ boolean hasUsages = node.usages().filter(n -> !(n instanceof FrameState)).isNotEmpty(); - TypeState nodeTypeState = methodFlow.foldTypeFlow((PointsToAnalysis) bb, nodeFlow); + TypeState nodeTypeState = nodeFlow.isFlowEnabled() ? methodFlow.foldTypeFlow((PointsToAnalysis) bb, nodeFlow) : TypeState.forEmpty(); if (hasUsages && allowConstantFolding && !nodeTypeState.canBeNull()) { JavaConstant constantValue = nodeTypeState.asConstant(); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java index 13fc569cdea7..cb4c1427581c 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/PointsToStats.java @@ -296,8 +296,8 @@ private static void reportTypeFlowStats(BufferedWriter out) { TypeFlowStats stats = e.getValue(); doWrite(out, String.format("%-35s\t%-10d\t%-10d\t%-10b\t%-10b\t%-10d\t%-10d\t%-10d\t%-10s\t%-10d\t%10d\t%10d\t%10s%n", - asString(flow), stateToId.get(flow.getState()), objectsCount(flow.getState()), - flow.getState().canBeNull(), flow.isClone(), + asString(flow), stateToId.get(flow.getRawState()), objectsCount(flow.getRawState()), + flow.getRawState().canBeNull(), flow.isClone(), flow.getUses().size(), flow.getObservers().size(), flow.getUses().size() + flow.getObservers().size(), retainReson.getOrDefault(flow, ""), stats.queuedUpdatesCount(), stats.successfulUpdatesCount(), stats.allUpdatesCount(), diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/PointsToBreakdown.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/PointsToBreakdown.java index f70fae0fcaaf..66770332b009 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/PointsToBreakdown.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dashboard/PointsToBreakdown.java @@ -587,12 +587,12 @@ private void serializeTypeFlow(BigBang bb, TypeFlow flow) { flowWrapper.calleeNames.add(callee.getQualifiedName()); } } else if (flow instanceof NewInstanceTypeFlow || flow instanceof DynamicNewInstanceTypeFlow) { - flowWrapper.types = serializeTypeState(bb, flow.getState()); + flowWrapper.types = serializeTypeState(bb, flow.getRawState()); } else if (flow instanceof LoadFieldTypeFlow.LoadInstanceFieldTypeFlow || flow instanceof LoadFieldTypeFlow.LoadStaticFieldTypeFlow) { LoadFieldTypeFlow loadFlow = (LoadFieldTypeFlow) flow; flowWrapper.qualifiedName = fieldName(loadFlow.field()); } else if (flow instanceof StoreFieldTypeFlow.StoreInstanceFieldTypeFlow || flow instanceof StoreFieldTypeFlow.StoreStaticFieldTypeFlow) { - TypeState typeState = flow.getState(); + TypeState typeState = flow.getRawState(); flowWrapper.types = serializeTypeState(bb, typeState); StoreFieldTypeFlow storeFlow = (StoreFieldTypeFlow) flow; flowWrapper.qualifiedName = fieldName(storeFlow.field()); From 269e0f8949fda2780cf1a40d62b2d5e6d84161af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksandar=20Pejovi=C4=87?= Date: Fri, 18 Oct 2024 12:05:30 +0200 Subject: [PATCH 042/105] Avoid NullPointerException when provider name is null --- .../src/com/oracle/svm/core/jdk/SecuritySubstitutions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java index 755e805795ec..d48c3330709e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SecuritySubstitutions.java @@ -259,7 +259,7 @@ static void initialize(Target_java_security_Provider_Windows provider) { return; } - if (provider.name.equals("SunMSCAPI")) { + if ("SunMSCAPI".equals(provider.name)) { try { System.loadLibrary("sunmscapi"); } catch (Throwable ignored) { From c2b0cfee3dcb81303a20657702cc58e9a3876bcb Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Tue, 15 Oct 2024 15:20:26 +0200 Subject: [PATCH 043/105] Intrinsify Reference.clear (JDK-8329597) --- .../core/common/memory/BarrierType.java | 7 ++++ .../hotspot/GraalHotSpotVMConfig.java | 6 +++ .../ZWriteBarrierSetLIRGeneratorTool.java | 3 ++ .../meta/HotSpotGraphBuilderPlugins.java | 38 ++++++++++++++++++- .../meta/HotSpotHostForeignCallsProvider.java | 5 +++ .../nodes/gc/CardTableBarrierSet.java | 3 +- .../graal/compiler/nodes/gc/G1BarrierSet.java | 4 +- .../compiler/nodes/memory/WriteNode.java | 2 +- ...Target_java_lang_ref_PhantomReference.java | 9 +++++ .../heap/Target_java_lang_ref_Reference.java | 14 ++++--- 10 files changed, 81 insertions(+), 10 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/memory/BarrierType.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/memory/BarrierType.java index a4bda771e17d..85d24549a69b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/memory/BarrierType.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/memory/BarrierType.java @@ -60,6 +60,13 @@ public enum BarrierType { */ POST_INIT_WRITE, + /** + * Clear {@link java.lang.ref.Reference}.referent. In the HotSpot world this corresponds to a + * write decorated with {@code AS_NO_KEEPALIVE}. Depending on the particular garbage collector + * this might do something different than {@link #FIELD}. + */ + AS_NO_KEEPALIVE_WRITE, + /** * Read of {@link java.lang.ref.Reference}.referent. In the HotSpot world this corresponds to an * access decorated with {@code ON_WEAK_OOP_REF}. Depending on the particular garbage collector diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java index 9e0140a5ec04..54db0081a22f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java @@ -83,6 +83,10 @@ public boolean useG1GC() { return gc == HotSpotGraalRuntime.HotSpotGC.G1; } + public boolean useXGC() { + return gc == HotSpotGraalRuntime.HotSpotGC.X; + } + public final HotSpotGraalRuntime.HotSpotGC gc = getSelectedGC(); private HotSpotGraalRuntime.HotSpotGC getSelectedGC() throws GraalError { @@ -585,6 +589,8 @@ private long getZGCAddressField(String name) { "ZBarrierSetRuntime::no_keepalive_load_barrier_on_weak_oop_field_preloaded"); public final long zBarrierSetRuntimeNoKeepaliveLoadBarrierOnPhantomOopFieldPreloaded = getZGCAddressField( "ZBarrierSetRuntime::no_keepalive_load_barrier_on_phantom_oop_field_preloaded"); + public final long zBarrierSetRuntimeNoKeepaliveStoreBarrierOnOopFieldWithoutHealing = getZGCAddressField( + "ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing"); public final long zBarrierSetRuntimeStoreBarrierOnNativeOopFieldWithoutHealing = getZGCAddressField("ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing"); public final long zBarrierSetRuntimeStoreBarrierOnOopFieldWithHealing = getZGCAddressField("ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing"); public final long zBarrierSetRuntimeStoreBarrierOnOopFieldWithoutHealing = getZGCAddressField("ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing"); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/ZWriteBarrierSetLIRGeneratorTool.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/ZWriteBarrierSetLIRGeneratorTool.java index c32581eeb31e..065c9701e743 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/ZWriteBarrierSetLIRGeneratorTool.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/ZWriteBarrierSetLIRGeneratorTool.java @@ -111,6 +111,9 @@ default ForeignCallLinkage getWriteBarrierStub(BarrierType barrierType, StoreKin callTarget = getForeignCalls().lookupForeignCall(HotSpotHostForeignCallsProvider.Z_STORE_BARRIER_WITHOUT_HEALING); } break; + case AS_NO_KEEPALIVE_WRITE: + callTarget = getForeignCalls().lookupForeignCall(HotSpotHostForeignCallsProvider.Z_REFERENCE_CLEAR_BARRIER); + break; default: throw GraalError.shouldNotReachHere("Unexpected barrier type: " + barrierType); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index 46a753a05829..a1b546c95982 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -265,7 +265,7 @@ public void run() { registerArrayPlugins(invocationPlugins, replacements, config); registerStringPlugins(invocationPlugins, replacements, wordTypes, foreignCalls, config); registerArraysSupportPlugins(invocationPlugins, replacements, target.arch); - registerReferencePlugins(invocationPlugins, replacements); + registerReferencePlugins(invocationPlugins, config, replacements); registerTrufflePlugins(invocationPlugins, wordTypes, config); registerInstrumentationImplPlugins(invocationPlugins, config, replacements); for (HotSpotInvocationPluginProvider p : GraalServices.load(HotSpotInvocationPluginProvider.class)) { @@ -1366,7 +1366,7 @@ public boolean isGraalOnly() { }); } - private static void registerReferencePlugins(InvocationPlugins plugins, Replacements replacements) { + private static void registerReferencePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { Registration r = new Registration(plugins, Reference.class, replacements); r.register(new ReachabilityFencePlugin() { @Override @@ -1386,6 +1386,23 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec return true; } }); + if (JavaVersionUtil.JAVA_SPEC >= 24 && !config.useXGC()) { + r.register(new InlineOnlyInvocationPlugin("clear0", Receiver.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + ValueNode offset = b.add(ConstantNode.forLong(HotSpotReplacementsUtil.referentOffset(b.getMetaAccess()))); + AddressNode address = b.add(new OffsetAddressNode(receiver.get(true), offset)); + FieldLocationIdentity locationIdentity = new FieldLocationIdentity(HotSpotReplacementsUtil.referentField(b.getMetaAccess())); + JavaReadNode referent = b.add(new JavaReadNode(StampFactory.object(), JavaKind.Object, address, locationIdentity, BarrierType.WEAK_REFERS_TO, MemoryOrderMode.PLAIN, true)); + helper.emitReturnIf(IsNullNode.create(referent), null, GraalDirectives.LIKELY_PROBABILITY); + b.add(new JavaWriteNode(JavaKind.Object, address, locationIdentity, ConstantNode.defaultForKind(JavaKind.Object), BarrierType.AS_NO_KEEPALIVE_WRITE, true)); + helper.emitFinalReturn(JavaKind.Void, null); + return true; + } + } + }); + } r = new Registration(plugins, PhantomReference.class, replacements); r.register(new InlineOnlyInvocationPlugin("refersTo0", Receiver.class, Object.class) { @Override @@ -1399,6 +1416,23 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec return true; } }); + if (JavaVersionUtil.JAVA_SPEC >= 24 && !config.useXGC()) { + r.register(new InlineOnlyInvocationPlugin("clear0", Receiver.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + ValueNode offset = b.add(ConstantNode.forLong(HotSpotReplacementsUtil.referentOffset(b.getMetaAccess()))); + AddressNode address = b.add(new OffsetAddressNode(receiver.get(true), offset)); + FieldLocationIdentity locationIdentity = new FieldLocationIdentity(HotSpotReplacementsUtil.referentField(b.getMetaAccess())); + JavaReadNode referent = b.add(new JavaReadNode(StampFactory.object(), JavaKind.Object, address, locationIdentity, BarrierType.PHANTOM_REFERS_TO, MemoryOrderMode.PLAIN, true)); + helper.emitReturnIf(IsNullNode.create(referent), null, GraalDirectives.LIKELY_PROBABILITY); + b.add(new JavaWriteNode(JavaKind.Object, address, locationIdentity, ConstantNode.defaultForKind(JavaKind.Object), BarrierType.AS_NO_KEEPALIVE_WRITE, true)); + helper.emitFinalReturn(JavaKind.Void, null); + return true; + } + } + }); + } } private static void registerInstrumentationImplPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java index 72374c8473c8..0cc01b9fa957 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java @@ -226,6 +226,10 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall public static final HotSpotForeignCallDescriptor Z_REFERENCE_GET_BARRIER = new HotSpotForeignCallDescriptor(LEAF_NO_VZERO, HAS_SIDE_EFFECT, NO_LOCATIONS, "ZBarrierSetRuntime::load_barrier_on_weak_oop_field_preloaded", long.class, long.class, long.class); + // void no_keepalive_store_barrier_on_oop_field_without_healing(oop* p); + public static final HotSpotForeignCallDescriptor Z_REFERENCE_CLEAR_BARRIER = new HotSpotForeignCallDescriptor(LEAF_NO_VZERO, HAS_SIDE_EFFECT, NO_LOCATIONS, + "ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing", void.class, long.class); + // oopDesc* no_keepalive_load_barrier_on_weak_oop_field_preloaded(oopDesc* o, oop* p); public static final HotSpotForeignCallDescriptor Z_WEAK_REFERS_TO_BARRIER = new HotSpotForeignCallDescriptor(LEAF_NO_VZERO, HAS_SIDE_EFFECT, NO_LOCATIONS, "ZBarrierSetRuntime::no_keepalive_load_barrier_on_weak_oop_field_preloaded", long.class, long.class, long.class); @@ -579,6 +583,7 @@ public void initialize(HotSpotProviders providers, OptionValues options) { linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_STORE_BARRIER_WITH_HEALING, c.zBarrierSetRuntimeStoreBarrierOnOopFieldWithHealing, DONT_PREPEND_THREAD); linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_STORE_BARRIER_NATIVE, c.zBarrierSetRuntimeStoreBarrierOnNativeOopFieldWithoutHealing, DONT_PREPEND_THREAD); linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_REFERENCE_GET_BARRIER, c.zBarrierSetRuntimeLoadBarrierOnWeakOopFieldPreloaded, DONT_PREPEND_THREAD); + linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_REFERENCE_CLEAR_BARRIER, c.zBarrierSetRuntimeNoKeepaliveStoreBarrierOnOopFieldWithoutHealing, DONT_PREPEND_THREAD); linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_WEAK_REFERS_TO_BARRIER, c.zBarrierSetRuntimeNoKeepaliveLoadBarrierOnWeakOopFieldPreloaded, DONT_PREPEND_THREAD); linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_PHANTOM_REFERS_TO_BARRIER, c.zBarrierSetRuntimeNoKeepaliveLoadBarrierOnPhantomOopFieldPreloaded, DONT_PREPEND_THREAD); linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_ARRAY_BARRIER, c.zBarrierSetRuntimeLoadBarrierOnOopArray, DONT_PREPEND_THREAD); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/CardTableBarrierSet.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/CardTableBarrierSet.java index 0cbaddf1b1b4..da4ee8b0728c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/CardTableBarrierSet.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/CardTableBarrierSet.java @@ -204,6 +204,7 @@ public boolean needsWriteBarrier(FixedAccessNode node, ValueNode writtenValue) { case NONE: return false; case FIELD: + case AS_NO_KEEPALIVE_WRITE: case ARRAY: case UNKNOWN: return writeRequiresBarrier(node, writtenValue); @@ -234,7 +235,7 @@ private static boolean hasWriteBarrier(ArrayRangeWrite write) { private static void addSerialPostWriteBarrier(FixedAccessNode node, AddressNode address, StructuredGraph graph) { // Use a precise barrier for everything that might be an array write. Being too precise with // the barriers does not cause any correctness issues. - boolean precise = node.getBarrierType() != BarrierType.FIELD; + boolean precise = node.getBarrierType() != BarrierType.FIELD && node.getBarrierType() != BarrierType.AS_NO_KEEPALIVE_WRITE; graph.addAfterFixed(node, graph.add(new SerialWriteBarrierNode(address, precise))); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/G1BarrierSet.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/G1BarrierSet.java index dc6f7b1faf32..4baf43064443 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/G1BarrierSet.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/G1BarrierSet.java @@ -168,12 +168,14 @@ private void addWriteBarriers(FixedAccessNode node, ValueNode writtenValue, Valu case FIELD: case ARRAY: case UNKNOWN: + case AS_NO_KEEPALIVE_WRITE: if (isObjectValue(writtenValue)) { StructuredGraph graph = node.graph(); boolean init = node.getLocationIdentity().isInit(); - if (!init) { + if (!init && barrierType != BarrierType.AS_NO_KEEPALIVE_WRITE) { // The pre barrier does nothing if the value being read is null, so it can // be explicitly skipped when this is an initializing store. + // No keep-alive means no need for the pre-barrier. addG1PreWriteBarrier(node, node.getAddress(), expectedValue, doLoad, graph); } if (writeRequiresPostBarrier(node, writtenValue)) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/WriteNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/WriteNode.java index 4c2a884d1146..a6ac8b4638a2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/WriteNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/WriteNode.java @@ -72,7 +72,7 @@ protected WriteNode(NodeClass c, AddressNode address, Locat MemoryOrderMode memoryOrder) { super(c, address, location, value, barrierType); assert barrierType == BarrierType.NONE || barrierType == BarrierType.ARRAY || barrierType == BarrierType.FIELD || barrierType == BarrierType.UNKNOWN || - barrierType == BarrierType.POST_INIT_WRITE : barrierType; + barrierType == BarrierType.POST_INIT_WRITE || barrierType == BarrierType.AS_NO_KEEPALIVE_WRITE : barrierType; this.killedLocationIdentity = killedLocationIdentity; this.memoryOrder = memoryOrder; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_PhantomReference.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_PhantomReference.java index 51200247d4b3..6f046af09657 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_PhantomReference.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_PhantomReference.java @@ -29,6 +29,8 @@ import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.jdk.JDKLatest; @TargetClass(PhantomReference.class) public final class Target_java_lang_ref_PhantomReference { @@ -36,4 +38,11 @@ public final class Target_java_lang_ref_PhantomReference { boolean refersTo0(Object obj) { return ReferenceInternals.refersTo(SubstrateUtil.cast(this, PhantomReference.class), obj); } + + @Substitute + @TargetElement(onlyWith = JDKLatest.class) + private void clear0() { + ReferenceInternals.clear(SubstrateUtil.cast(this, PhantomReference.class)); + } + } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_Reference.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_Reference.java index 0c9d1d35d338..29e434368fc1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_Reference.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_Reference.java @@ -43,6 +43,8 @@ import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.jdk.JDKLatest; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; @@ -123,16 +125,18 @@ public final class Target_java_lang_ref_Reference { @KeepOriginal native T get(); - @Substitute - public void clear() { - ReferenceInternals.clear(SubstrateUtil.cast(this, Reference.class)); - } + @KeepOriginal + native void clear(); @Substitute private void clear0() { - clear(); + ReferenceInternals.clear(SubstrateUtil.cast(this, Reference.class)); } + @TargetElement(onlyWith = JDKLatest.class) + @KeepOriginal + native void clearImpl(); + @KeepOriginal native boolean refersToImpl(T obj); From 1cadbba013c76d1fe62ab44ae37165627f4ad2b3 Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Tue, 15 Oct 2024 15:36:11 +0200 Subject: [PATCH 044/105] Update galahad JDK. --- common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.json b/common.json index ba235300354c..67c0b18153a4 100644 --- a/common.json +++ b/common.json @@ -8,7 +8,7 @@ "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+20-2281", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+20-2342", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk17": {"name": "jpg-jdk", "version": "17.0.7", "build_id": "jdk-17.0.7+8", "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.1-b02", "platformspecific": true }, From 4df44f6cc90a6bc36ad424781486d3ef7c3ffe57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C3=B6=20Barany?= Date: Fri, 18 Oct 2024 10:25:21 +0200 Subject: [PATCH 045/105] compiler: adapt UnimplementedGraalIntrinsics for JDK-8338023 --- .../compiler/hotspot/meta/UnimplementedGraalIntrinsics.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java index ab107792c328..3648c655b324 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java @@ -153,8 +153,10 @@ public UnimplementedGraalIntrinsics(Architecture arch) { if (jdk >= 24) { add(toBeInvestigated, // @formatter:off - "jdk/internal/vm/vector/VectorSupport.selectFromOp(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$VectorSelectFromOp;)Ljdk/internal/vm/vector/VectorSupport$Vector;"); + "jdk/internal/vm/vector/VectorSupport.selectFromOp(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$VectorSelectFromOp;)Ljdk/internal/vm/vector/VectorSupport$Vector;", + "jdk/internal/vm/vector/VectorSupport.selectFromTwoVectorOp(Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$SelectFromTwoVector;)Ljdk/internal/vm/vector/VectorSupport$Vector;" // @formatter:on + ); } // These are known to be implemented down stream From 08947b2fc020dbf158870023ebce8a2dbda55b4f Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Fri, 18 Oct 2024 11:18:27 +0000 Subject: [PATCH 046/105] deploy snapshots --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index 9efe1d95b7af..2f405568eff0 100644 --- a/common.json +++ b/common.json @@ -46,12 +46,12 @@ "oraclejdk23": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+37", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+20", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+20-jvmci-b01-20241017180532-3e48bf9cdf", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+20-jvmci-b01-20241017180532-3e48bf9cdf-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+20-jvmci-b01-20241017180532-3e48bf9cdf-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+20-jvmci-b01-20241017180532-3e48bf9cdf+a202bc2826", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+20-jvmci-b01-20241017180532-3e48bf9cdf+a202bc2826-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+20-jvmci-b01-20241017180532-3e48bf9cdf+a202bc2826-sulong", "platformspecific": true } + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+20-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+20-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+20-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+20-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+20-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+20-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 0ee9078d1fb04dda04210399aff56ee59116421c Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Tue, 15 Oct 2024 15:20:26 +0200 Subject: [PATCH 047/105] Intrinsify Reference.clear (JDK-8329597) --- .../core/common/memory/BarrierType.java | 7 ++++ .../hotspot/GraalHotSpotVMConfig.java | 6 +++ .../ZWriteBarrierSetLIRGeneratorTool.java | 3 ++ .../meta/HotSpotGraphBuilderPlugins.java | 38 ++++++++++++++++++- .../meta/HotSpotHostForeignCallsProvider.java | 5 +++ .../nodes/gc/CardTableBarrierSet.java | 3 +- .../graal/compiler/nodes/gc/G1BarrierSet.java | 4 +- .../compiler/nodes/memory/WriteNode.java | 2 +- ...Target_java_lang_ref_PhantomReference.java | 9 +++++ .../heap/Target_java_lang_ref_Reference.java | 14 ++++--- 10 files changed, 81 insertions(+), 10 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/memory/BarrierType.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/memory/BarrierType.java index a4bda771e17d..85d24549a69b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/memory/BarrierType.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/common/memory/BarrierType.java @@ -60,6 +60,13 @@ public enum BarrierType { */ POST_INIT_WRITE, + /** + * Clear {@link java.lang.ref.Reference}.referent. In the HotSpot world this corresponds to a + * write decorated with {@code AS_NO_KEEPALIVE}. Depending on the particular garbage collector + * this might do something different than {@link #FIELD}. + */ + AS_NO_KEEPALIVE_WRITE, + /** * Read of {@link java.lang.ref.Reference}.referent. In the HotSpot world this corresponds to an * access decorated with {@code ON_WEAK_OOP_REF}. Depending on the particular garbage collector diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java index 9e0140a5ec04..54db0081a22f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java @@ -83,6 +83,10 @@ public boolean useG1GC() { return gc == HotSpotGraalRuntime.HotSpotGC.G1; } + public boolean useXGC() { + return gc == HotSpotGraalRuntime.HotSpotGC.X; + } + public final HotSpotGraalRuntime.HotSpotGC gc = getSelectedGC(); private HotSpotGraalRuntime.HotSpotGC getSelectedGC() throws GraalError { @@ -585,6 +589,8 @@ private long getZGCAddressField(String name) { "ZBarrierSetRuntime::no_keepalive_load_barrier_on_weak_oop_field_preloaded"); public final long zBarrierSetRuntimeNoKeepaliveLoadBarrierOnPhantomOopFieldPreloaded = getZGCAddressField( "ZBarrierSetRuntime::no_keepalive_load_barrier_on_phantom_oop_field_preloaded"); + public final long zBarrierSetRuntimeNoKeepaliveStoreBarrierOnOopFieldWithoutHealing = getZGCAddressField( + "ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing"); public final long zBarrierSetRuntimeStoreBarrierOnNativeOopFieldWithoutHealing = getZGCAddressField("ZBarrierSetRuntime::store_barrier_on_native_oop_field_without_healing"); public final long zBarrierSetRuntimeStoreBarrierOnOopFieldWithHealing = getZGCAddressField("ZBarrierSetRuntime::store_barrier_on_oop_field_with_healing"); public final long zBarrierSetRuntimeStoreBarrierOnOopFieldWithoutHealing = getZGCAddressField("ZBarrierSetRuntime::store_barrier_on_oop_field_without_healing"); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/ZWriteBarrierSetLIRGeneratorTool.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/ZWriteBarrierSetLIRGeneratorTool.java index c32581eeb31e..065c9701e743 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/ZWriteBarrierSetLIRGeneratorTool.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/ZWriteBarrierSetLIRGeneratorTool.java @@ -111,6 +111,9 @@ default ForeignCallLinkage getWriteBarrierStub(BarrierType barrierType, StoreKin callTarget = getForeignCalls().lookupForeignCall(HotSpotHostForeignCallsProvider.Z_STORE_BARRIER_WITHOUT_HEALING); } break; + case AS_NO_KEEPALIVE_WRITE: + callTarget = getForeignCalls().lookupForeignCall(HotSpotHostForeignCallsProvider.Z_REFERENCE_CLEAR_BARRIER); + break; default: throw GraalError.shouldNotReachHere("Unexpected barrier type: " + barrierType); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index 46a753a05829..a1b546c95982 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -265,7 +265,7 @@ public void run() { registerArrayPlugins(invocationPlugins, replacements, config); registerStringPlugins(invocationPlugins, replacements, wordTypes, foreignCalls, config); registerArraysSupportPlugins(invocationPlugins, replacements, target.arch); - registerReferencePlugins(invocationPlugins, replacements); + registerReferencePlugins(invocationPlugins, config, replacements); registerTrufflePlugins(invocationPlugins, wordTypes, config); registerInstrumentationImplPlugins(invocationPlugins, config, replacements); for (HotSpotInvocationPluginProvider p : GraalServices.load(HotSpotInvocationPluginProvider.class)) { @@ -1366,7 +1366,7 @@ public boolean isGraalOnly() { }); } - private static void registerReferencePlugins(InvocationPlugins plugins, Replacements replacements) { + private static void registerReferencePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { Registration r = new Registration(plugins, Reference.class, replacements); r.register(new ReachabilityFencePlugin() { @Override @@ -1386,6 +1386,23 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec return true; } }); + if (JavaVersionUtil.JAVA_SPEC >= 24 && !config.useXGC()) { + r.register(new InlineOnlyInvocationPlugin("clear0", Receiver.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + ValueNode offset = b.add(ConstantNode.forLong(HotSpotReplacementsUtil.referentOffset(b.getMetaAccess()))); + AddressNode address = b.add(new OffsetAddressNode(receiver.get(true), offset)); + FieldLocationIdentity locationIdentity = new FieldLocationIdentity(HotSpotReplacementsUtil.referentField(b.getMetaAccess())); + JavaReadNode referent = b.add(new JavaReadNode(StampFactory.object(), JavaKind.Object, address, locationIdentity, BarrierType.WEAK_REFERS_TO, MemoryOrderMode.PLAIN, true)); + helper.emitReturnIf(IsNullNode.create(referent), null, GraalDirectives.LIKELY_PROBABILITY); + b.add(new JavaWriteNode(JavaKind.Object, address, locationIdentity, ConstantNode.defaultForKind(JavaKind.Object), BarrierType.AS_NO_KEEPALIVE_WRITE, true)); + helper.emitFinalReturn(JavaKind.Void, null); + return true; + } + } + }); + } r = new Registration(plugins, PhantomReference.class, replacements); r.register(new InlineOnlyInvocationPlugin("refersTo0", Receiver.class, Object.class) { @Override @@ -1399,6 +1416,23 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec return true; } }); + if (JavaVersionUtil.JAVA_SPEC >= 24 && !config.useXGC()) { + r.register(new InlineOnlyInvocationPlugin("clear0", Receiver.class) { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + try (InvocationPluginHelper helper = new InvocationPluginHelper(b, targetMethod)) { + ValueNode offset = b.add(ConstantNode.forLong(HotSpotReplacementsUtil.referentOffset(b.getMetaAccess()))); + AddressNode address = b.add(new OffsetAddressNode(receiver.get(true), offset)); + FieldLocationIdentity locationIdentity = new FieldLocationIdentity(HotSpotReplacementsUtil.referentField(b.getMetaAccess())); + JavaReadNode referent = b.add(new JavaReadNode(StampFactory.object(), JavaKind.Object, address, locationIdentity, BarrierType.PHANTOM_REFERS_TO, MemoryOrderMode.PLAIN, true)); + helper.emitReturnIf(IsNullNode.create(referent), null, GraalDirectives.LIKELY_PROBABILITY); + b.add(new JavaWriteNode(JavaKind.Object, address, locationIdentity, ConstantNode.defaultForKind(JavaKind.Object), BarrierType.AS_NO_KEEPALIVE_WRITE, true)); + helper.emitFinalReturn(JavaKind.Void, null); + return true; + } + } + }); + } } private static void registerInstrumentationImplPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java index 72374c8473c8..0cc01b9fa957 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java @@ -226,6 +226,10 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall public static final HotSpotForeignCallDescriptor Z_REFERENCE_GET_BARRIER = new HotSpotForeignCallDescriptor(LEAF_NO_VZERO, HAS_SIDE_EFFECT, NO_LOCATIONS, "ZBarrierSetRuntime::load_barrier_on_weak_oop_field_preloaded", long.class, long.class, long.class); + // void no_keepalive_store_barrier_on_oop_field_without_healing(oop* p); + public static final HotSpotForeignCallDescriptor Z_REFERENCE_CLEAR_BARRIER = new HotSpotForeignCallDescriptor(LEAF_NO_VZERO, HAS_SIDE_EFFECT, NO_LOCATIONS, + "ZBarrierSetRuntime::no_keepalive_store_barrier_on_oop_field_without_healing", void.class, long.class); + // oopDesc* no_keepalive_load_barrier_on_weak_oop_field_preloaded(oopDesc* o, oop* p); public static final HotSpotForeignCallDescriptor Z_WEAK_REFERS_TO_BARRIER = new HotSpotForeignCallDescriptor(LEAF_NO_VZERO, HAS_SIDE_EFFECT, NO_LOCATIONS, "ZBarrierSetRuntime::no_keepalive_load_barrier_on_weak_oop_field_preloaded", long.class, long.class, long.class); @@ -579,6 +583,7 @@ public void initialize(HotSpotProviders providers, OptionValues options) { linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_STORE_BARRIER_WITH_HEALING, c.zBarrierSetRuntimeStoreBarrierOnOopFieldWithHealing, DONT_PREPEND_THREAD); linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_STORE_BARRIER_NATIVE, c.zBarrierSetRuntimeStoreBarrierOnNativeOopFieldWithoutHealing, DONT_PREPEND_THREAD); linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_REFERENCE_GET_BARRIER, c.zBarrierSetRuntimeLoadBarrierOnWeakOopFieldPreloaded, DONT_PREPEND_THREAD); + linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_REFERENCE_CLEAR_BARRIER, c.zBarrierSetRuntimeNoKeepaliveStoreBarrierOnOopFieldWithoutHealing, DONT_PREPEND_THREAD); linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_WEAK_REFERS_TO_BARRIER, c.zBarrierSetRuntimeNoKeepaliveLoadBarrierOnWeakOopFieldPreloaded, DONT_PREPEND_THREAD); linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_PHANTOM_REFERS_TO_BARRIER, c.zBarrierSetRuntimeNoKeepaliveLoadBarrierOnPhantomOopFieldPreloaded, DONT_PREPEND_THREAD); linkStackOnlyForeignCall(c.gc == Z, options, providers, Z_ARRAY_BARRIER, c.zBarrierSetRuntimeLoadBarrierOnOopArray, DONT_PREPEND_THREAD); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/CardTableBarrierSet.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/CardTableBarrierSet.java index 0cbaddf1b1b4..da4ee8b0728c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/CardTableBarrierSet.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/CardTableBarrierSet.java @@ -204,6 +204,7 @@ public boolean needsWriteBarrier(FixedAccessNode node, ValueNode writtenValue) { case NONE: return false; case FIELD: + case AS_NO_KEEPALIVE_WRITE: case ARRAY: case UNKNOWN: return writeRequiresBarrier(node, writtenValue); @@ -234,7 +235,7 @@ private static boolean hasWriteBarrier(ArrayRangeWrite write) { private static void addSerialPostWriteBarrier(FixedAccessNode node, AddressNode address, StructuredGraph graph) { // Use a precise barrier for everything that might be an array write. Being too precise with // the barriers does not cause any correctness issues. - boolean precise = node.getBarrierType() != BarrierType.FIELD; + boolean precise = node.getBarrierType() != BarrierType.FIELD && node.getBarrierType() != BarrierType.AS_NO_KEEPALIVE_WRITE; graph.addAfterFixed(node, graph.add(new SerialWriteBarrierNode(address, precise))); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/G1BarrierSet.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/G1BarrierSet.java index dc6f7b1faf32..4baf43064443 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/G1BarrierSet.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/gc/G1BarrierSet.java @@ -168,12 +168,14 @@ private void addWriteBarriers(FixedAccessNode node, ValueNode writtenValue, Valu case FIELD: case ARRAY: case UNKNOWN: + case AS_NO_KEEPALIVE_WRITE: if (isObjectValue(writtenValue)) { StructuredGraph graph = node.graph(); boolean init = node.getLocationIdentity().isInit(); - if (!init) { + if (!init && barrierType != BarrierType.AS_NO_KEEPALIVE_WRITE) { // The pre barrier does nothing if the value being read is null, so it can // be explicitly skipped when this is an initializing store. + // No keep-alive means no need for the pre-barrier. addG1PreWriteBarrier(node, node.getAddress(), expectedValue, doLoad, graph); } if (writeRequiresPostBarrier(node, writtenValue)) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/WriteNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/WriteNode.java index 4c2a884d1146..a6ac8b4638a2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/WriteNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/memory/WriteNode.java @@ -72,7 +72,7 @@ protected WriteNode(NodeClass c, AddressNode address, Locat MemoryOrderMode memoryOrder) { super(c, address, location, value, barrierType); assert barrierType == BarrierType.NONE || barrierType == BarrierType.ARRAY || barrierType == BarrierType.FIELD || barrierType == BarrierType.UNKNOWN || - barrierType == BarrierType.POST_INIT_WRITE : barrierType; + barrierType == BarrierType.POST_INIT_WRITE || barrierType == BarrierType.AS_NO_KEEPALIVE_WRITE : barrierType; this.killedLocationIdentity = killedLocationIdentity; this.memoryOrder = memoryOrder; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_PhantomReference.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_PhantomReference.java index 51200247d4b3..6f046af09657 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_PhantomReference.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_PhantomReference.java @@ -29,6 +29,8 @@ import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.jdk.JDKLatest; @TargetClass(PhantomReference.class) public final class Target_java_lang_ref_PhantomReference { @@ -36,4 +38,11 @@ public final class Target_java_lang_ref_PhantomReference { boolean refersTo0(Object obj) { return ReferenceInternals.refersTo(SubstrateUtil.cast(this, PhantomReference.class), obj); } + + @Substitute + @TargetElement(onlyWith = JDKLatest.class) + private void clear0() { + ReferenceInternals.clear(SubstrateUtil.cast(this, PhantomReference.class)); + } + } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_Reference.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_Reference.java index 0c9d1d35d338..29e434368fc1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_Reference.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/heap/Target_java_lang_ref_Reference.java @@ -43,6 +43,8 @@ import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.annotate.TargetElement; +import com.oracle.svm.core.jdk.JDKLatest; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; @@ -123,16 +125,18 @@ public final class Target_java_lang_ref_Reference { @KeepOriginal native T get(); - @Substitute - public void clear() { - ReferenceInternals.clear(SubstrateUtil.cast(this, Reference.class)); - } + @KeepOriginal + native void clear(); @Substitute private void clear0() { - clear(); + ReferenceInternals.clear(SubstrateUtil.cast(this, Reference.class)); } + @TargetElement(onlyWith = JDKLatest.class) + @KeepOriginal + native void clearImpl(); + @KeepOriginal native boolean refersToImpl(T obj); From 1a5c83857f5f9fd163c561e2cb6479c3a8eff105 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Fri, 18 Oct 2024 12:03:43 -0700 Subject: [PATCH 048/105] Add sanity check that killCFG doesn't produce orphaned control flow --- .../src/jdk/graal/compiler/nodes/util/GraphUtil.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/util/GraphUtil.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/util/GraphUtil.java index 4b2f28463fc9..781bc8b2efdb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/util/GraphUtil.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/util/GraphUtil.java @@ -149,6 +149,11 @@ private static void killCFGInner(FixedNode node) { marked.markDeleted(); } } + for (Node m : markedNodes) { + if (m instanceof FixedWithNextNode fixed) { + GraalError.guarantee(fixed.next() == null || fixed.next().isDeleted(), "dead node %s has live next %s", m, fixed.next()); + } + } } private static void markFixedNodes(FixedNode node, EconomicSet markedNodes, EconomicMap> unmarkedMerges) { From d03c791c6eead75d991f7a0171776ed5389b0aa0 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 18 Oct 2024 21:05:42 +0000 Subject: [PATCH 049/105] Update truffleruby import. --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index b2f35acf1182..c312f8a65bec 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -49,7 +49,7 @@ }, { "name": "truffleruby", - "version": "0e05bfe4380fb7c2107eb29940762b296f1fd454", + "version": "495a0e5cc6911e01b021fc9aace1137c1492b496", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/truffleruby.git", "kind": "git"}, From 013e7eba12e6b9f4e04e836b9022f11256e29d8b Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Fri, 18 Oct 2024 21:51:20 +0000 Subject: [PATCH 050/105] [GR-42711] Make foreign numbers inherit from ForeignNumberType, foreign strings from str and fix TCK PullRequest: graalpython/3513 --- vm/mx.vm/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index b2f35acf1182..d7b97f67f9ac 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -65,7 +65,7 @@ }, { "name": "graalpython", - "version": "8656dcf48d16f2d9f4ce90ef52ace9456abcae02", + "version": "d591da47a62a6a4bbee22d8cb824390f222bfa53", "dynamic": True, "urls": [ {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"}, From d24b00626b8f31b25faf054db56528e441f47ccc Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 18 Oct 2024 09:58:54 +0200 Subject: [PATCH 051/105] Added documentation to ErrorTypeTest. --- .../truffle/tck/tests/ErrorTypeTest.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/truffle/src/com.oracle.truffle.tck.tests/src/com/oracle/truffle/tck/tests/ErrorTypeTest.java b/truffle/src/com.oracle.truffle.tck.tests/src/com/oracle/truffle/tck/tests/ErrorTypeTest.java index 82853d259628..b858d1405c37 100644 --- a/truffle/src/com.oracle.truffle.tck.tests/src/com/oracle/truffle/tck/tests/ErrorTypeTest.java +++ b/truffle/src/com.oracle.truffle.tck.tests/src/com/oracle/truffle/tck/tests/ErrorTypeTest.java @@ -63,6 +63,33 @@ import org.junit.AfterClass; import org.junit.Assume; +/** + * This test class is designed to validate how language expressions and statements handle invalid + * values. Unlike other TCK tests, this test explicitly examines scenarios where values passed to + * language operators or statements are not assignable to their expected parameter types. The goal + * is to ensure that the language correctly throws exceptions when processing these invalid values. + *

+ * The expected behavior is that the execution of the code snippets under test will throw a + * {@link PolyglotException} when invalid values are encountered. All types not explicitly listed as + * valid in expression or statement snippet are considered invalid, and the test expects the + * execution to fail with a {@link PolyglotException} in such cases. + *

+ * The following features may help {@link org.graalvm.polyglot.tck.LanguageProvider} implementers in + * specifying all valid snippet types, ensuring this test passes successfully. + *

    + *
  • Overloaded Snippets: Expression and statement snippets may support multiple overloads, + * where more snippets with the same name and different parameter types are provided. The test + * framework considers all valid parameter types across these overloads and removes them from an + * invalid values set. An example can be found in the + * JavaScript '+' expression.
  • + *
  • Custom Result Verification: Snippets may register a custom implementation of + * {@link org.graalvm.polyglot.tck.ResultVerifier} to allow dynamic exception filtering or + * additional validation during test execution. An example can be found in the + * JavaScript '>>>' expression.
  • + *
+ */ @RunWith(Parameterized.class) public class ErrorTypeTest { From c7c9bbe0d0800a8d8db2514972cb0b6301ff6311 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Sun, 20 Oct 2024 12:33:45 -0700 Subject: [PATCH 052/105] Fix malformed test graph --- .../test/LoopSafepointStateVerificationTest.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/LoopSafepointStateVerificationTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/LoopSafepointStateVerificationTest.java index e91f279d74f4..36010e377487 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/LoopSafepointStateVerificationTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/LoopSafepointStateVerificationTest.java @@ -26,12 +26,12 @@ import java.util.Optional; -import jdk.graal.compiler.debug.DebugOptions; import org.junit.Assert; import org.junit.Test; import jdk.graal.compiler.api.directives.GraalDirectives; import jdk.graal.compiler.core.common.GraalOptions; +import jdk.graal.compiler.debug.DebugOptions; import jdk.graal.compiler.debug.TTY; import jdk.graal.compiler.graph.Graph; import jdk.graal.compiler.nodes.EndNode; @@ -40,6 +40,7 @@ import jdk.graal.compiler.nodes.GraphState; import jdk.graal.compiler.nodes.LoopBeginNode; import jdk.graal.compiler.nodes.LoopEndNode; +import jdk.graal.compiler.nodes.LoopExitNode; import jdk.graal.compiler.nodes.PhiNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions; @@ -78,7 +79,7 @@ public void test01() { test(opt, "snippet01"); Assert.fail("Should have detected that the phase in this class does not retain the mustNotSafepoint flag of a loop begin"); } catch (Throwable t) { - assert t.getMessage().contains("previously the loop had canHaveSafepoints=false but now it has canHaveSafepoints=true"); + assert t.toString().contains("previously the loop had canHaveSafepoints=false but now it has canHaveSafepoints=true") : t; } } @@ -144,6 +145,9 @@ protected void run(StructuredGraph graph, HighTierContext context) { LoopBeginNode oldLoopBegin = lex.loopBegin(); EndNode fwd = oldLoopBegin.forwardEnd(); + for (LoopExitNode exit : oldLoopBegin.loopExits().snapshot()) { + exit.setLoopBegin(lb); + } FixedNode next = oldLoopBegin.next(); oldLoopBegin.setNext(null); @@ -153,10 +157,8 @@ protected void run(StructuredGraph graph, HighTierContext context) { lb.addForwardEnd(fwdEnd); FixedWithNextNode fwn = (FixedWithNextNode) fwd.predecessor(); - fwn.setNext(null); - GraphUtil.killCFG(fwd); fwn.setNext(fwdEnd); - + GraphUtil.killCFG(fwd); } }); From b99a496cd71b276f363266dd421e3d8a1fb11bee Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Tue, 15 Oct 2024 15:26:16 +0700 Subject: [PATCH 053/105] [GR-49661] Refactor DataBuilder::createMultiDataItem --- .../compiler/asm/amd64/AMD64Assembler.java | 5 +++++ .../jdk/graal/compiler/lir/asm/DataBuilder.java | 17 +++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java index fd6c6d3df948..d63c4250cb47 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java @@ -2013,6 +2013,11 @@ public static class VexRVROp extends VexOp { public static final VexRVROp KXORB = new VexRVROp("KXORB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x47, VEXOpAssertion.AVX512DQ_MASK); public static final VexRVROp KXORQ = new VexRVROp("KXORQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x47, VEXOpAssertion.AVX512BW_MASK); public static final VexRVROp KXORD = new VexRVROp("KXORD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x47, VEXOpAssertion.AVX512BW_MASK); + + public static final VexRVROp KXNORW = new VexRVROp("KXNORW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x46, VEXOpAssertion.AVX512F_MASK); + public static final VexRVROp KXNORB = new VexRVROp("KXNORB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x46, VEXOpAssertion.AVX512DQ_MASK); + public static final VexRVROp KXNORQ = new VexRVROp("KXNORQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x46, VEXOpAssertion.AVX512BW_MASK); + public static final VexRVROp KXNORD = new VexRVROp("KXNORD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x46, VEXOpAssertion.AVX512BW_MASK); // @formatter:on protected VexRVROp(String opcode, int pp, int mmmmm, int w, int op, VEXOpAssertion assertion) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/DataBuilder.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/DataBuilder.java index db3266a40c1d..3b2021cf2833 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/DataBuilder.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/asm/DataBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package jdk.graal.compiler.lir.asm; import java.nio.ByteBuffer; +import java.util.List; import jdk.graal.compiler.code.DataSection; import jdk.graal.compiler.code.DataSection.Data; @@ -121,14 +122,14 @@ public Data createPackedDataItem(Data[] nested) { return createPackedDataItem(alignment, size, nested); } - public Data createMultiDataItem(Constant... constants) { - assert constants.length > 0; - if (constants.length == 1) { - return createDataItem(constants[0]); + public Data createMultiDataItem(List constants) { + assert !constants.isEmpty() : "must not be empty"; + if (constants.size() == 1) { + return createDataItem(constants.get(0)); } else { - Data[] data = new Data[constants.length]; - for (int i = 0; i < constants.length; i++) { - data[i] = createDataItem(constants[i]); + Data[] data = new Data[constants.size()]; + for (int i = 0; i < constants.size(); i++) { + data[i] = createDataItem(constants.get(i)); } return createPackedDataItem(data); } From dcc8fc5cfb7c7e537095b7866438e57552d78680 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Mon, 21 Oct 2024 14:16:38 +0200 Subject: [PATCH 054/105] compilation alarm time test: just verify we waited a positive amount --- .../debug/test/CompilationAlarmPhaseTimesTest.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/debug/test/CompilationAlarmPhaseTimesTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/debug/test/CompilationAlarmPhaseTimesTest.java index a91aefc89fee..b56c2ec8c599 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/debug/test/CompilationAlarmPhaseTimesTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/debug/test/CompilationAlarmPhaseTimesTest.java @@ -73,13 +73,6 @@ protected void run(StructuredGraph graph, LowTierContext context) { */ public static final int SLEEP_SECONDS = 10; - /** - * Thread.sleep is using nanoTime and compilation alarm uses System.currenTimeMillis which is a - * different timer so there can be small imprecision. We allow this amount milliseconds total - * imprecision. - */ - public static final int IMPRECISION_DELTA = 100; - @Test public void testTimeOutRetryToString() { final double secondsToWait = 1D; @@ -103,9 +96,7 @@ public void testTimeOutRetryToString() { duration += c; index++; } - final double scaledSecondsToWait = CompilationAlarm.scaleExpirationPeriod(secondsToWait, opt); - assert Integer.parseInt(duration) >= (scaledSecondsToWait * 1000) - - IMPRECISION_DELTA : String.format("Must at least wait for 2000ms but waited %s error was %s", duration, message); + assert Integer.parseInt(duration) > 0 : String.format("Must at least wait some positive amount of time but waited %s error was %s", duration, message); } } From 9de60a7b7476753d2ff1bf61111d421428abc4ff Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Thu, 17 Oct 2024 13:48:12 +0200 Subject: [PATCH 055/105] Espresso processors: support inner classes in `getInternalName` --- espresso/mx.espresso/suite.py | 2 +- .../processor/SubstitutionProcessor.java | 118 +++++++++--------- ...et_java_lang_invoke_LambdaMetafactory.java | 19 +-- 3 files changed, 67 insertions(+), 72 deletions(-) diff --git a/espresso/mx.espresso/suite.py b/espresso/mx.espresso/suite.py index f3f6f825ed51..d873664eb3b7 100644 --- a/espresso/mx.espresso/suite.py +++ b/espresso/mx.espresso/suite.py @@ -156,7 +156,7 @@ "requires": [ "java.compiler" ], - "javaCompliance" : "17+", + "javaCompliance" : "21+", "checkstyle": "com.oracle.truffle.espresso", }, diff --git a/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionProcessor.java b/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionProcessor.java index cf2eafa5fd0d..f2ebd15bfbf7 100644 --- a/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionProcessor.java +++ b/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionProcessor.java @@ -39,6 +39,7 @@ import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ArrayType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; @@ -391,7 +392,7 @@ String getReturnTypeFromHost(ExecutableElement method) { // passing the method as anchor for reporting errors instead. return getClassFromJavaType(a, method); } - return getInternalName(returnType.toString()); + return getInternalName(returnType); } private List getGuestTypes(ExecutableElement inner, boolean hasReceiver) { @@ -408,7 +409,7 @@ private List getGuestTypes(ExecutableElement inner, boolean hasReceiver) if (!isReceiver && processingEnv.getTypeUtils().isSameType(parameter.asType(), staticObject.asType())) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "non-receiver StaticObject parameters require the @JavaType annotation", parameter); } - String arg = getInternalName(parameter.asType().toString()); + String arg = getInternalName(parameter.asType()); parameterTypeNames.add(arg); } isReceiver = false; @@ -454,7 +455,7 @@ private String getClassFromJavaType(AnnotationMirror annotation, Element element // .internalName overrides .value . if (internalName == null || internalName.isEmpty()) { TypeMirror value = getAnnotationValue(annotation, "value", TypeMirror.class); - internalName = getInternalName(value.toString()); + internalName = getInternalName(value); // JavaType.value = JavaType.class is used as the "no type" type, forbid accidental // usages. if (processingEnv.getTypeUtils().isSameType(value, javaType.asType())) { @@ -472,69 +473,62 @@ private String getClassFromJavaType(AnnotationMirror annotation, Element element return internalName; } - private static String getArraySubstring(int nbDim) { - char[] chars = new char[nbDim]; - Arrays.fill(chars, '['); - return new String(chars); - } - /** - * Given a qualified class name, returns the fully qualified internal name of the class. + * Given a type, returns its fully qualified internal name. * * In particular, - *
  • This transforms primitives (boolean, int) to their JVM signature (Z, I). - *
  • Replaces "." by "/" and, if not present, prepends a "L" an appends a ";" to reference - * types (/ex: java.lang.Object -> Ljava/lang/Object;) - *
  • If an array is passed, it is of the form "java.lang.Object[]" or "byte[][]". This - * prepends the correct number of "[" before applying this function to the name without the - * "[]". (/ex: byte[][] -> [[B) + *
  • Primitives (boolean, int) use their JVM signature (Z, I). + *
  • Use "/" rather than "." to separate packages (/ex: java.lang.Object -> + * Ljava/lang/Object;) + *
  • Array types use "[" followed by the internal name of the component type. */ - private String getInternalName(String className) { - int arrayStart = className.indexOf("[]"); - if (arrayStart != -1) { - int nbDim = 0; - boolean isOpen = false; - for (int i = arrayStart; i < className.length(); i++) { - if (isOpen) { - if (className.charAt(i) != ']') { - throw new IllegalArgumentException("Malformed class name: " + className); - } - nbDim++; - } else { - if (className.charAt(i) != '[') { - throw new IllegalArgumentException("Malformed class name: " + className); - } - } - isOpen = !isOpen; - } - return getArraySubstring(nbDim) + getInternalName(className.substring(0, arrayStart)); - } - - if (className.startsWith("[") || className.endsWith(";")) { - return className.replace('.', '/'); - } - switch (className) { - case "boolean": - return "Z"; - case "byte": - return "B"; - case "char": - return "C"; - case "short": - return "S"; - case "int": - return "I"; - case "float": - return "F"; - case "double": - return "D"; - case "long": - return "J"; - case "void": - return "V"; - } - // Reference type. - return "L" + className.replace('.', '/') + ";"; + private String getInternalName(TypeMirror type) { + int arrayDims = 0; + TypeMirror elementalType = type; + while (elementalType.getKind() == TypeKind.ARRAY) { + elementalType = ((ArrayType) elementalType).getComponentType(); + arrayDims += 1; + } + + if (arrayDims == 0) { + return getNonArrayInternalName(type); + } + StringBuilder sb = new StringBuilder(); + sb.repeat('[', arrayDims); + sb.append(getNonArrayInternalName(elementalType)); + return sb.toString(); + } + + private String getNonArrayInternalName(TypeMirror type) { + TypeKind typeKind = type.getKind(); + assert typeKind != TypeKind.ARRAY; + if (typeKind.isPrimitive() || typeKind == TypeKind.VOID) { + return switch (typeKind) { + case BOOLEAN -> "Z"; + case BYTE -> "B"; + case CHAR -> "C"; + case SHORT -> "S"; + case INT -> "I"; + case FLOAT -> "F"; + case DOUBLE -> "D"; + case LONG -> "J"; + case VOID -> "V"; + default -> throw new IllegalStateException("Unexpected primitive type kind: " + typeKind); + }; + } + if (typeKind != TypeKind.DECLARED) { + throw new IllegalStateException("Unexpected type kind: " + typeKind); + } + Element element = processingEnv.getTypeUtils().asElement(type); + Name binaryName = processingEnv.getElementUtils().getBinaryName((TypeElement) element); + StringBuilder sb = new StringBuilder(); + sb.append("L").append(binaryName).append(';'); + int idx = sb.indexOf(".", 1); + while (idx >= 0) { + sb.setCharAt(idx, '/'); + idx = sb.indexOf(".", idx + 1); + } + return sb.toString(); } private List getEspressoTypes(ExecutableElement inner) { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_invoke_LambdaMetafactory.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_invoke_LambdaMetafactory.java index 89ab1b97ad81..ca962ec23878 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_invoke_LambdaMetafactory.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_invoke_LambdaMetafactory.java @@ -23,6 +23,12 @@ package com.oracle.truffle.espresso.substitutions; +import java.lang.invoke.CallSite; +import java.lang.invoke.LambdaMetafactory; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; @@ -31,11 +37,6 @@ import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; -import java.lang.invoke.CallSite; -import java.lang.invoke.LambdaMetafactory; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodType; - /** * This class exists for serializable continuations. It forcibly overrides the lambda generation * mode to request that serializability is always included. This is insufficient to enable @@ -48,7 +49,7 @@ public final class Target_java_lang_invoke_LambdaMetafactory { @Substitution abstract static class Metafactory extends SubstitutionNode { abstract @JavaType(CallSite.class) StaticObject execute( - @JavaType(internalName = "Ljava/lang/invoke/MethodHandles$Lookup;") StaticObject caller, + @JavaType(MethodHandles.Lookup.class) StaticObject caller, @JavaType(String.class) StaticObject interfaceMethodName, @JavaType(MethodType.class) StaticObject factoryType, @JavaType(MethodType.class) StaticObject interfaceMethodType, @@ -58,7 +59,7 @@ abstract static class Metafactory extends SubstitutionNode { @Specialization @JavaType(CallSite.class) StaticObject doCached( - @JavaType(internalName = "Ljava/lang/invoke/MethodHandles$Lookup;") StaticObject caller, + @JavaType(MethodHandles.Lookup.class) StaticObject caller, @JavaType(String.class) StaticObject interfaceMethodName, @JavaType(MethodType.class) StaticObject factoryType, @JavaType(MethodType.class) StaticObject interfaceMethodType, @@ -87,7 +88,7 @@ StaticObject doCached( @Substitution abstract static class AltMetafactory extends SubstitutionNode { abstract @JavaType(CallSite.class) StaticObject execute( - @JavaType(internalName = "Ljava/lang/invoke/MethodHandles$Lookup;") StaticObject caller, + @JavaType(MethodHandles.Lookup.class) StaticObject caller, @JavaType(String.class) StaticObject interfaceMethodName, @JavaType(MethodType.class) StaticObject factoryType, @JavaType(Object[].class) StaticObject args); @@ -95,7 +96,7 @@ abstract static class AltMetafactory extends SubstitutionNode { @Specialization @JavaType(CallSite.class) StaticObject doCached( - @JavaType(internalName = "Ljava/lang/invoke/MethodHandles$Lookup;") StaticObject caller, + @JavaType(MethodHandles.Lookup.class) StaticObject caller, @JavaType(String.class) StaticObject interfaceMethodName, @JavaType(MethodType.class) StaticObject factoryType, @JavaType(Object[].class) StaticObject args, From 8cc6f0ec12469788bcbdc1c2e1a4edca446b7d33 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Mon, 21 Oct 2024 14:07:59 +0200 Subject: [PATCH 056/105] Fix incremental build issue in espresso ESPRESSO_SUPPORT would sometimes get wrongly rebuilt with a message mentioning `.` as being newer. This was due to a wrong usage of `TimeStampFile.newest` called with a path instead of a sequence of paths. --- espresso/mx.espresso/mx_espresso.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/espresso/mx.espresso/mx_espresso.py b/espresso/mx.espresso/mx_espresso.py index 9cde1836f6e4..7f5453c5aee3 100644 --- a/espresso/mx.espresso/mx_espresso.py +++ b/espresso/mx.espresso/mx_espresso.py @@ -223,7 +223,7 @@ def __str__(self): return f'Create {self.subject}' def newestOutput(self): - return mx.TimeStampFile.newest(self.subject.output_file()) + return mx.TimeStampFile(self.subject.output_file()) def needsBuild(self, newestInput): r = super().needsBuild(newestInput) From c2e6674beec393abc86e29f93993e48bdc8a4efa Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Mon, 21 Oct 2024 14:18:31 +0200 Subject: [PATCH 057/105] Fix incremental build issue with graalvm-jimage It would sometimes not get rebuilt although the included modules are changed. For example that would happen if a component changes its included jars. --- sdk/mx.sdk/mx_sdk_vm_impl.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index ecbde93749c1..af9e52f98b10 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -1772,11 +1772,12 @@ def needsBuild(self, newestInput): return True, '{} does not exist'.format(out_file.path) if newestInput and out_file.isOlderThan(newestInput): return True, '{} is older than {}'.format(out_file, newestInput) - if exists(self._config_file()): - with open(self._config_file(), 'r') as f: - old_config = [l.strip() for l in f.readlines()] - if set(old_config) != set(self._config()): - return True, 'the configuration changed' + if not exists(self._config_file()): + return True, '{} does not exits'.format(self._config_file()) + with open(self._config_file(), 'r') as f: + old_config = [l.strip() for l in f.readlines()] + if set(old_config) != set(self._config()): + return True, 'the configuration changed' return False, None def newestOutput(self): @@ -1800,14 +1801,16 @@ def _config(self): # always updated when the JDK is rebuilt. src_jimage = mx.TimeStampFile(join(_src_jdk.home, 'lib', 'modules')) return [ - f'components: {", ".join(sorted(_components_set()))}', f'include sources: {_include_sources_str()}', f'strip jars: {mx.get_opts().strip_jars}', f'vendor-version: {graalvm_vendor_version()}', + f'use jlink{_jlink_libraries()}', + f'build exploded: {mx.get_env("MX_BUILD_EXPLODED") == "true"}', f'source jimage: {src_jimage}', - f'use_upgrade_module_path: {mx.get_env("GRAALVM_JIMAGE_USE_UPGRADE_MODULE_PATH", None)}', f'default_to_jvmci: {self.subject.default_to_jvmci}', f'missing_export_target_action: {self.subject.missing_export_target_action}', + f'jars: {sorted("{}:{}".format(d.suite, d.name) for d in self.subject.deps)}', + f'ignore jars: {sorted(self.subject.jimage_ignore_jars)}', ] def _config_file(self): From efc1716c9582452da8dc1c5dd3c99e7307ecd208 Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Tue, 15 Oct 2024 13:58:05 +0300 Subject: [PATCH 058/105] Add a new guide: Troubleshoot Native Image Run-Time Errors --- .../guides/troubleshoot-run-time-errors.md | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 docs/reference-manual/native-image/guides/troubleshoot-run-time-errors.md diff --git a/docs/reference-manual/native-image/guides/troubleshoot-run-time-errors.md b/docs/reference-manual/native-image/guides/troubleshoot-run-time-errors.md new file mode 100644 index 000000000000..2f54f16a58ff --- /dev/null +++ b/docs/reference-manual/native-image/guides/troubleshoot-run-time-errors.md @@ -0,0 +1,75 @@ +--- +layout: ni-docs +toc_group: how-to-guides +link_title: Troubleshoot Native Image Run-Time Errors +permalink: /reference-manual/native-image/guides/troubleshoot-run-time-errors/ +--- + +# Troubleshoot Native Image Run-Time Errors + +A successful ahead-of-time compilation can still generate images that crash at run time or do not behave the same way as the application would behave on a Java VM. +In this guide, some reasons for that are shown, along with the strategies to diagnose and resolve the issues. + +Note that sometimes upgrading to the latest version of GraalVM can already resolve an issue. + +## 1. Diagnose Missing Metadata Registration + +Start by diagnosing if there is any metadata configuration missing. +Native Image requires all utilized classes to be known during the build. +The static analysis tries to make predictions about the run-time behavior of your application. +In some cases, you need to provide the analysis with configuration to make all dynamic feature calls visible to it. +Failing to do so will result in an image that terminates at run-time with hard-to-diagnose errors once the dynamic feature is used in the application. +This can be avoided by eagerly checking for missing metadata. + +1. Pass the `--exact-reachablity-metadata` option to the `native-image` tool and rebuild the application. If you want to do this only for a specific package, specify a package prefix `--exact-reachablity-metadata=[package prefix]`. + + > This option was introduced in GraalVM for JDK 23 and will become the default in the next feature release. It is equivalent to the `-H:ThrowMissingRegistrationErrors=` host option. + +2. Next run that native executable passing the `-XX:MissingRegistrationReportingMode=Warn` option to find all places in your code where missing registrations occur. + +3. If there is some missing metadata reported, make sure to add it to the _reachability-metadata.json_ file. See how to do it in the [Reachability Metadata documentation](https://www.graalvm.org/latest/reference-manual/native-image/metadata/#specifying-metadata-with-json). + +4. Then restart the native executable with `-XX:MissingRegistrationReportingMode=Exit` to detect places where the application accidentally ignores a missing registration error (with `catch (Throwable t)` blocks). The application will then unconditionally print the error message with the stack trace and exit immediately. This behavior is ideal for running application tests to guarantee all metadata is included. + +### Shared Libraries + +For diagnosing shared libraries built with Native Image, you can either: +* specify `-R:MissingRegistrationReportingMode=Exit` when building a native shared library; +* or specify `-XX:MissingRegistrationReportingMode=Exit` when the isolate is created. `graal_create_isolate_params_t` has `argc (_reserved_1)` and `argv (_reserved_2)` fields that can be used to pass C-style command-line options at run time. However, note that both fields are currently not public APIs. + +## 2. Set java.home Explicitly + +If your application code uses the `java.home` property, set it explicitly with `-Djava.home=` when running a native executable. +Otherwise, the `System.getProperty("java.home")` call will return a `null` value. + +## 3. Enable URL Protocols + +Try enabling all URL protocols on-demand at build time: `--enable-url-protocols=`. +To enable the HTTPS support only, pass `--enable-https`. + +## 4. Enable Signal Handling + +If your application is using signal handling or the `java.lang.Terminator` exit handlers, provide the option `--install-exit-handlers` option at build time. + +## 5. Include All Charsets and Locales + +Other handy options are `-H:+AddAllCharsets` to add charsets support, and `-H:+IncludeAllLocales` to pre-initialize support for locale-sensitive behavior in the `java.util` and `java.text` packages. +Pass those options at build time. +This might increase the size of the resulting binary. + +## 6. Add Missing Security Providers + +If your application is using Security Providers, try to pre-initialize security providers by passing the option `-H:AdditionalSecurityProviders=` at build time. +Here is a list of all JDK security providers to choose from: +`sun.security.provider.Sun,sun.security.rsa.SunRsaSign,sun.security.ec.SunEC,sun.security.ssl.SunJSSE,com.sun.crypto.provider.SunJCE,sun.security.jgss.SunProvider,com.sun.security.sasl.Provider,org.jcp.xml.dsig.internal.dom.XMLDSigRI,sun.security.smartcardio.SunPCSC,sun.security.provider.certpath.ldap.JdkLDAP,com.sun.security.sasl.gsskerb.JdkSASL`. + +## 7. File a Native Image Run-Time Issue + +Only if you tried all the above suggestions, file a [Native Image Run-Time Issue Report](https://github.com/oracle/graal/issues/new?assignees=&labels=native-image%2Cbug%2Crun-time&projects=&template=1_1_native_image_run_time_bug_report.yml&title=%5BNative+Image%5D+) at GitHub, filling out the necessary information. + +To gather the required information for filing a proper and actionable ticket, it is recommended to run a `native-image` build with the diagnostics mode enabled. +Pass the `--diagnostics-mode` option enabling diagnostics output for class initialization, substitutions, and so on. + +### Related Documentation + +* [Specifying Metadata with JSON](../ReachabilityMetadata.md#specifying-metadata-with-json) \ No newline at end of file From 42883a254db3868ea3d7010e52433134c6711e52 Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Wed, 9 Oct 2024 14:30:05 +0200 Subject: [PATCH 059/105] Adapt JDK-8341052: SHA-512 implementation using SHA-NI --- .../src/com/oracle/svm/core/amd64/AMD64LibCHelper.java | 4 ++++ .../include/amd64cpufeatures.h | 1 + .../include/amd64hotspotcpuinfo.h | 3 ++- substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/amd64/AMD64LibCHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/amd64/AMD64LibCHelper.java index 41f6a8c3e139..49cf71929a7d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/amd64/AMD64LibCHelper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/amd64/AMD64LibCHelper.java @@ -306,6 +306,10 @@ public interface CPUFeatures extends PointerBase { @AllowNarrowingCast @CField boolean fAPX_F(); + + @AllowNarrowingCast + @CField + boolean fSHA512(); } // Checkstyle: resume } diff --git a/substratevm/src/com.oracle.svm.native.libchelper/include/amd64cpufeatures.h b/substratevm/src/com.oracle.svm.native.libchelper/include/amd64cpufeatures.h index 10e98fe1e423..3572afa7f244 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/include/amd64cpufeatures.h +++ b/substratevm/src/com.oracle.svm.native.libchelper/include/amd64cpufeatures.h @@ -87,4 +87,5 @@ typedef struct { uint8_t fAVX512_IFMA; uint8_t fAVX_IFMA; uint8_t fAPX_F; + uint8_t fSHA512; } CPUFeatures; diff --git a/substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h b/substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h index 86d957d74df9..5c0cda212dd3 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h +++ b/substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h @@ -274,7 +274,8 @@ typedef union { typedef union { uint32_t value; struct { - uint32_t : 23, + uint32_t sha512 : 1, + : 22, avx_ifma : 1, : 8; } bits; diff --git a/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c b/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c index 44eb2d5e2838..a6c71ad4d218 100644 --- a/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c +++ b/substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c @@ -438,6 +438,8 @@ NO_INLINE static void set_cpufeatures(CPUFeatures *features, CpuidInfo *_cpuid_i { features->fAVX = 1; features->fVZEROUPPER = 1; + if (_cpuid_info->sefsl1_cpuid7_eax.bits.sha512 != 0) + features->fSHA512 = 1; if (_cpuid_info->std_cpuid1_ecx.bits.f16c != 0) features->fF16C = 1; if (_cpuid_info->sef_cpuid7_ebx.bits.avx2 != 0) From 6cf57637c65bdead032dce5aeacdd0960c8ff6bb Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Wed, 9 Oct 2024 12:29:32 +0200 Subject: [PATCH 060/105] Update galahad JDK. --- common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.json b/common.json index 67c0b18153a4..b2b51b5d13b8 100644 --- a/common.json +++ b/common.json @@ -8,7 +8,7 @@ "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+20-2342", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+21-2436", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk17": {"name": "jpg-jdk", "version": "17.0.7", "build_id": "jdk-17.0.7+8", "platformspecific": true, "extrabundles": ["static-libs"]}, "labsjdk-ce-17": {"name": "labsjdk", "version": "ce-17.0.7+4-jvmci-23.1-b02", "platformspecific": true }, From 759e817b578d930cb33a8daa301d5643c45fa400 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Mon, 21 Oct 2024 20:03:36 +0200 Subject: [PATCH 061/105] Fix for akka-uct regression with GR-55538. --- .../src/com/oracle/svm/core/genscavenge/HeapImpl.java | 3 +++ .../layeredimagesingleton/NonLayeredImageSingletonFeature.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java index 0802124adcab..9e753d12c70b 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HeapImpl.java @@ -35,6 +35,7 @@ import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; +import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.MemoryWalker; import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.SubstrateDiagnostics; @@ -161,6 +162,7 @@ public boolean isInImageHeap(Object obj) { } @Override + @AlwaysInline("GC performance") @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isInImageHeap(Pointer objPointer) { return isInPrimaryImageHeap(objPointer) || (AuxiliaryImageHeap.isPresent() && AuxiliaryImageHeap.singleton().containsObject(objPointer)); @@ -176,6 +178,7 @@ public boolean isInPrimaryImageHeap(Object obj) { } @Override + @AlwaysInline("GC performance") @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public boolean isInPrimaryImageHeap(Pointer objPointer) { for (ImageHeapInfo info : getImageHeapInfos()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/NonLayeredImageSingletonFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/NonLayeredImageSingletonFeature.java index 7f9ec4431fd6..930f526d9a89 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/NonLayeredImageSingletonFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/NonLayeredImageSingletonFeature.java @@ -79,7 +79,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec return result; }); - b.addPush(JavaKind.Object, ConstantNode.forConstant(b.getSnippetReflection().forObject(multiLayeredArray), b.getMetaAccess())); + b.addPush(JavaKind.Object, ConstantNode.forConstant(b.getSnippetReflection().forObject(multiLayeredArray), 1, true, b.getMetaAccess())); return true; } }); From cd784f8e25ddee25f32740fdfbb7f2b50eaf66d8 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Sun, 20 Oct 2024 19:59:44 -0700 Subject: [PATCH 062/105] Review comments --- .../aarch64/AArch64LoweringProviderMixin.java | 2 +- .../amd64/AMD64LoweringProviderMixin.java | 3 +- .../riscv64/RISCV64LoweringProviderMixin.java | 2 +- .../meta/DefaultHotSpotLoweringProvider.java | 11 +++--- .../HotSpotAllocationSnippets.java | 8 ++--- .../compiler/nodes/spi/LoweringProvider.java | 12 +++---- .../graal/GenScavengeAllocationSnippets.java | 36 +++++++++---------- .../SubstrateLLVMLoweringProvider.java | 2 +- .../snippets/SubstrateAllocationSnippets.java | 16 ++++----- 9 files changed, 47 insertions(+), 45 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64LoweringProviderMixin.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64LoweringProviderMixin.java index 109d1c32797e..f03a2784234c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64LoweringProviderMixin.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/aarch64/AArch64LoweringProviderMixin.java @@ -43,7 +43,7 @@ default Integer smallestCompareWidth() { } @Override - default boolean supportsBulkZeroing() { + default boolean supportsBulkZeroingOfEden() { return true; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64LoweringProviderMixin.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64LoweringProviderMixin.java index dd0f2a86d9ce..6cd994feeb39 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64LoweringProviderMixin.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64LoweringProviderMixin.java @@ -41,7 +41,6 @@ import jdk.graal.compiler.replacements.nodes.BitScanReverseNode; import jdk.graal.compiler.replacements.nodes.CountLeadingZerosNode; import jdk.graal.compiler.replacements.nodes.CountTrailingZerosNode; - import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.meta.JavaKind; @@ -59,7 +58,7 @@ default Integer smallestCompareWidth() { } @Override - default boolean supportsBulkZeroing() { + default boolean supportsBulkZeroingOfEden() { return true; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/riscv64/RISCV64LoweringProviderMixin.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/riscv64/RISCV64LoweringProviderMixin.java index 199d2b87e682..5a8a80c577f5 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/riscv64/RISCV64LoweringProviderMixin.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/riscv64/RISCV64LoweringProviderMixin.java @@ -42,7 +42,7 @@ default Integer smallestCompareWidth() { } @Override - default boolean supportsBulkZeroing() { + default boolean supportsBulkZeroingOfEden() { return false; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java index 762a03ef4a81..0ed2dc5c1edf 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java @@ -356,12 +356,15 @@ public final void initializeExtensions(OptionValues options, Iterable Date: Tue, 22 Oct 2024 12:39:44 +0200 Subject: [PATCH 063/105] =?UTF-8?q?[GR-57115]=20Introduce=20-H:=C2=B1=20Su?= =?UTF-8?q?pportRuntimeClassLoading?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also known as "Crema". Not working yet. Co-authored-by: Gilles Duboscq --- .../core/hub/RuntimeClassLoadingSupport.java | 54 +++++++++++++++++++ .../jdk/Target_java_lang_ClassLoader.java | 45 ++++++++++------ 2 files changed, 82 insertions(+), 17 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeClassLoadingSupport.java diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeClassLoadingSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeClassLoadingSupport.java new file mode 100644 index 000000000000..2596e2d4fef0 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeClassLoadingSupport.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.hub; + +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.option.HostedOptionKey; +import com.oracle.svm.core.option.SubstrateOptionsParser; +import com.oracle.svm.core.util.UserError; + +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.options.Option; + +public class RuntimeClassLoadingSupport { + public static final class Options { + @Option(help = "Enable support for runtime class loading.") // + public static final HostedOptionKey SupportRuntimeClassLoading = new HostedOptionKey<>(false, Options::validate); + + private static void validate(HostedOptionKey optionKey) { + if (optionKey.hasBeenSet() && optionKey.getValue() && SubstrateOptions.ClosedTypeWorld.getValue()) { + throw UserError.invalidOptionValue(SupportRuntimeClassLoading, SupportRuntimeClassLoading.getValue(), + "Requires an open type world, Please use " + SubstrateOptionsParser.commandArgument(SubstrateOptions.ClosedTypeWorld, "-")); + } + } + } + + public static final String ENABLE_CLASS_LOADING_OPTION = SubstrateOptionsParser.commandArgument(Options.SupportRuntimeClassLoading, "+"); + + @Fold + public static boolean supportsRuntimeClassLoading() { + return Options.SupportRuntimeClassLoading.getValue(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java index ce0006e988ba..eaf2438211c5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java @@ -45,6 +45,7 @@ import com.oracle.svm.core.annotate.TargetElement; import com.oracle.svm.core.hub.ClassForNameSupport; import com.oracle.svm.core.hub.PredefinedClassesSupport; +import com.oracle.svm.core.hub.RuntimeClassLoadingSupport; import com.oracle.svm.core.util.VMError; import jdk.graal.compiler.java.LambdaUtils; @@ -254,39 +255,40 @@ private static long findNative(@SuppressWarnings("unused") ClassLoader loader, S @Substitute @SuppressWarnings({"unused", "static-method"}) Class defineClass(byte[] b, int off, int len) throws ClassFormatError { - return PredefinedClassesSupport.loadClass(SubstrateUtil.cast(this, ClassLoader.class), null, b, off, len, null); + return defineClass(null, b, off, len); } @Substitute @SuppressWarnings({"unused", "static-method"}) Class defineClass(String name, byte[] b, int off, int len) throws ClassFormatError { - return PredefinedClassesSupport.loadClass(SubstrateUtil.cast(this, ClassLoader.class), name, b, off, len, null); + return defineClass(name, b, off, len, null); } @Substitute @SuppressWarnings({"unused", "static-method"}) private Class defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) { - return PredefinedClassesSupport.loadClass(SubstrateUtil.cast(this, ClassLoader.class), name, b, off, len, protectionDomain); + return ClassLoaderHelper.defineClass(SubstrateUtil.cast(this, ClassLoader.class), name, b, off, len, protectionDomain); } @Substitute @SuppressWarnings({"unused", "static-method"}) private Class defineClass(String name, java.nio.ByteBuffer b, ProtectionDomain protectionDomain) { - if (!PredefinedClassesSupport.hasBytecodeClasses()) { - throw PredefinedClassesSupport.throwNoBytecodeClasses(name); - } - byte[] array; - int off; - int len = b.remaining(); - if (b.hasArray()) { - array = b.array(); - off = b.position() + b.arrayOffset(); - } else { - array = new byte[len]; - b.get(array); - off = 0; + // only bother extracting the bytes if it has a chance to work + if (PredefinedClassesSupport.hasBytecodeClasses() || RuntimeClassLoadingSupport.supportsRuntimeClassLoading()) { + byte[] array; + int off; + int len = b.remaining(); + if (b.hasArray()) { + array = b.array(); + off = b.position() + b.arrayOffset(); + } else { + array = new byte[len]; + b.get(array); + off = 0; + } + return ClassLoaderHelper.defineClass(SubstrateUtil.cast(this, ClassLoader.class), name, array, off, len, null); } - return PredefinedClassesSupport.loadClass(SubstrateUtil.cast(this, ClassLoader.class), name, array, off, len, null); + throw PredefinedClassesSupport.throwNoBytecodeClasses(name); } @Substitute @@ -319,6 +321,15 @@ private static Class defineClass0(ClassLoader loader, Class lookup, String private static native Target_java_lang_AssertionStatusDirectives retrieveDirectives(); } +final class ClassLoaderHelper { + public static Class defineClass(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) { + if (PredefinedClassesSupport.hasBytecodeClasses()) { + return PredefinedClassesSupport.loadClass(loader, name, b, off, len, protectionDomain); + } + throw VMError.unimplemented("Crema"); + } +} + @TargetClass(className = "java.lang.AssertionStatusDirectives") // final class Target_java_lang_AssertionStatusDirectives { } From 6b8d0ae5ff89433db2c0da2c7f81100fd72e8a22 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Tue, 22 Oct 2024 18:13:37 +0700 Subject: [PATCH 064/105] x86 - Refactor VEXOpAssertion --- .../compiler/asm/amd64/AMD64Assembler.java | 847 ++++++++---------- .../asm/amd64/AMD64BaseAssembler.java | 8 +- .../asm/amd64/AMD64MacroAssembler.java | 4 +- .../lir/amd64/AMD64ArrayIndexOfOp.java | 6 +- .../lir/amd64/vector/AMD64VectorBinary.java | 6 +- .../lir/amd64/vector/AMD64VectorClearOp.java | 2 +- .../lir/amd64/vector/AMD64VectorShuffle.java | 4 +- 7 files changed, 396 insertions(+), 481 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java index d63c4250cb47..43de34067a1d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java @@ -84,8 +84,6 @@ import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -import org.graalvm.collections.EconomicSet; - import jdk.graal.compiler.asm.BranchTargetOutOfBoundsException; import jdk.graal.compiler.asm.Label; import jdk.graal.compiler.asm.amd64.AVXKind.AVXSize; @@ -100,10 +98,10 @@ import jdk.graal.compiler.options.OptionValues; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64.CPUFeature; -import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.Register.RegisterCategory; import jdk.vm.ci.code.TargetDescription; +import org.graalvm.collections.EconomicSet; /** * This class implements an assembler that can encode most X86 instructions. @@ -990,26 +988,73 @@ private AMD64Shift(String opcode, int code) { } } + /** + * This is used to verify the availability of a vex-encoded instruction during code emission. + */ + private enum VEXFeatureAssertion { + AVX1(EnumSet.of(CPUFeature.AVX), EnumSet.of(CPUFeature.AVX)), + AVX2(EnumSet.of(CPUFeature.AVX2), EnumSet.of(CPUFeature.AVX2)), + AVX1_AVX2(EnumSet.of(CPUFeature.AVX), EnumSet.of(CPUFeature.AVX2)), + AVX1_128(EnumSet.of(CPUFeature.AVX), null), + AVX2_128(EnumSet.of(CPUFeature.AVX2), null), + AVX1_256(null, EnumSet.of(CPUFeature.AVX)), + AVX2_256(null, EnumSet.of(CPUFeature.AVX2)), + BMI1(EnumSet.of(CPUFeature.BMI1), null), + BMI2(EnumSet.of(CPUFeature.BMI2), null), + FMA(EnumSet.of(CPUFeature.FMA), EnumSet.of(CPUFeature.FMA)), + FMA_128(EnumSet.of(CPUFeature.FMA), null), + AVX1_AES_128(EnumSet.of(CPUFeature.AVX, CPUFeature.AES), null), + F16C(EnumSet.of(CPUFeature.F16C), EnumSet.of(CPUFeature.F16C)), + CLMUL_AVX1(EnumSet.of(CPUFeature.AVX, CPUFeature.CLMUL), EnumSet.of(CPUFeature.AVX, CPUFeature.CLMUL)), + GFNI_AVX1(EnumSet.of(CPUFeature.AVX, CPUFeature.GFNI), EnumSet.of(CPUFeature.AVX, CPUFeature.GFNI)), + AVX512F_L0(EnumSet.of(CPUFeature.AVX512F), null), + AVX512BW_L0(EnumSet.of(CPUFeature.AVX512BW), null), + AVX512DQ_L0(EnumSet.of(CPUFeature.AVX512DQ), null), + AVX512F_L1(null, EnumSet.of(CPUFeature.AVX512F)), + AVX512BW_L1(null, EnumSet.of(CPUFeature.AVX512BW)), + AVX512DQ_L1(null, EnumSet.of(CPUFeature.AVX512DQ)); + + private final EnumSet l128Features; + private final EnumSet l256Features; + + VEXFeatureAssertion(EnumSet l128Features, EnumSet l256Features) { + this.l128Features = l128Features; + this.l256Features = l256Features; + } + + public boolean isValid(EnumSet features, AVXSize size) { + return switch (size) { + case XMM -> l128Features != null && features.containsAll(l128Features); + case YMM -> l256Features != null && features.containsAll(l256Features); + case ZMM -> false; + default -> throw GraalError.shouldNotReachHereUnexpectedValue(size); + }; + } + } + + /** + * This is used to verify the availability of an evex-encoded instruction during code emission. + */ private enum EVEXFeatureAssertion { /* * With very few exceptions (namely, KMOV{B,D,Q}), all AVX512 instructions require AVX512F. * For simplicity, include AVX512F in all AVX512 assertions, and mention it in the name of * the assertion even though it is implied. */ - AVX512F_ALL(EnumSet.of(AVX512F), EnumSet.of(AVX512F), EnumSet.of(AVX512F)), - AVX512F_128ONLY(EnumSet.of(AVX512F), null, null), - AVX512BW_128ONLY(EnumSet.of(AVX512BW), null, null), - AVX512DQ_128ONLY(EnumSet.of(AVX512DQ), null, null), + AVX512F_128(EnumSet.of(AVX512F), null, null), + AVX512BW_128(EnumSet.of(AVX512BW), null, null), + AVX512DQ_128(EnumSet.of(AVX512DQ), null, null), AVX512F_VL(EnumSet.of(AVX512F, AVX512VL), EnumSet.of(AVX512F, AVX512VL), EnumSet.of(AVX512F)), AVX512F_CD_VL(EnumSet.of(AVX512F, AVX512CD, AVX512VL), EnumSet.of(AVX512F, AVX512CD, AVX512VL), EnumSet.of(AVX512F, AVX512CD)), - AVX512F_DQ_ALL(EnumSet.of(AVX512F, AVX512DQ), EnumSet.of(AVX512F, AVX512DQ), EnumSet.of(AVX512F, AVX512DQ)), AVX512F_DQ_VL(EnumSet.of(AVX512F, AVX512DQ, AVX512VL), EnumSet.of(AVX512F, AVX512DQ, AVX512VL), EnumSet.of(AVX512F, AVX512DQ)), - AVX512F_BW_ALL(EnumSet.of(AVX512F, AVX512BW), EnumSet.of(AVX512F, AVX512BW), EnumSet.of(AVX512F, AVX512BW)), AVX512F_BW_VL(EnumSet.of(AVX512F, AVX512BW, AVX512VL), EnumSet.of(AVX512F, AVX512BW, AVX512VL), EnumSet.of(AVX512F, AVX512BW)), AVX512F_VL_256_512(null, EnumSet.of(AVX512F, AVX512VL), EnumSet.of(AVX512F)), AVX512F_DQ_VL_256_512(null, EnumSet.of(AVX512F, AVX512DQ, AVX512VL), EnumSet.of(AVX512F, AVX512DQ)), - AVX512F_DQ_512ONLY(null, null, EnumSet.of(AVX512F, AVX512DQ)), - AVX512F_512ONLY(null, null, EnumSet.of(AVX512F)); + AVX512F_DQ_512(null, null, EnumSet.of(AVX512F, AVX512DQ)), + AVX512F_512(null, null, EnumSet.of(AVX512F)), + AVX512_VBMI_VL(EnumSet.of(CPUFeature.AVX512_VBMI, CPUFeature.AVX512VL), EnumSet.of(CPUFeature.AVX512_VBMI, CPUFeature.AVX512VL), EnumSet.of(CPUFeature.AVX512_VBMI)), + CLMUL_AVX512F_VL(EnumSet.of(CPUFeature.AVX512VL, CPUFeature.CLMUL), EnumSet.of(CPUFeature.AVX512VL, CPUFeature.CLMUL), EnumSet.of(CPUFeature.AVX512F, CPUFeature.CLMUL)), + GFNI_AVX512F_VL(EnumSet.of(CPUFeature.AVX512VL, CPUFeature.GFNI), EnumSet.of(CPUFeature.AVX512VL, CPUFeature.GFNI), EnumSet.of(CPUFeature.AVX512F, CPUFeature.GFNI)); private final EnumSet l128features; private final EnumSet l256features; @@ -1021,32 +1066,13 @@ private enum EVEXFeatureAssertion { this.l512features = l512features; } - public boolean check(EnumSet features, int l) { - switch (l) { - case VEXPrefixConfig.L128: - GraalError.guarantee(l128features != null && features.containsAll(l128features), "emitting illegal 128 bit instruction, required features: %s", l128features); - break; - case VEXPrefixConfig.L256: - GraalError.guarantee(l256features != null && features.containsAll(l256features), "emitting illegal 256 bit instruction, required features: %s", l256features); - break; - case VEXPrefixConfig.L512: - GraalError.guarantee(l512features != null && features.containsAll(l512features), "emitting illegal 512 bit instruction, required features: %s", l512features); - break; - } - return true; - } - - public boolean supports(EnumSet features, AVXKind.AVXSize avxSize) { - switch (avxSize) { - case XMM: - return l128features != null && features.containsAll(l128features); - case YMM: - return l256features != null && features.containsAll(l256features); - case ZMM: - return l512features != null && features.containsAll(l512features); - default: - throw GraalError.shouldNotReachHereUnexpectedValue(avxSize); // ExcludeFromJacocoGeneratedReport - } + public boolean isValid(EnumSet features, AVXSize size) { + return switch (size) { + case XMM -> l128features != null && features.containsAll(l128features); + case YMM -> l256features != null && features.containsAll(l256features); + case ZMM -> l512features != null && features.containsAll(l512features); + default -> throw GraalError.shouldNotReachHereUnexpectedValue(size); + }; } } @@ -1073,146 +1099,129 @@ public boolean contains(Register r) { } private static final UnionRegisterCategory CPU_OR_MASK = new UnionRegisterCategory("CPU_OR_MASK", CPU, MASK); + private static final UnionRegisterCategory CPU_OR_XMM = new UnionRegisterCategory("CPU_OR_XMM", CPU, XMM); private static boolean categoryContains(RegisterCategory category, Register register) { return register.getRegisterCategory().equals(category) || (category instanceof UnionRegisterCategory && ((UnionRegisterCategory) category).contains(register)); } - public enum VEXOpAssertion { - AVX1(CPUFeature.AVX, CPUFeature.AVX, null), - AVX1_2(CPUFeature.AVX, CPUFeature.AVX2, null), - AVX2(CPUFeature.AVX2, CPUFeature.AVX2, null), - AVX1_128ONLY(CPUFeature.AVX, null, null), - AVX1_256ONLY(null, CPUFeature.AVX, null), - AVX2_256ONLY(null, CPUFeature.AVX2, null), - XMM_CPU(CPUFeature.AVX, null, null, null, XMM, null, CPU, null), - XMM_XMM_CPU(CPUFeature.AVX, null, null, null, XMM, XMM, CPU, null), - CPU_XMM(CPUFeature.AVX, null, null, null, CPU, null, XMM, null), - AVX1_CPU_XMM(CPUFeature.AVX, CPUFeature.AVX, null, null, CPU, null, XMM, null), - AVX1_2_CPU_XMM(CPUFeature.AVX, CPUFeature.AVX2, null, null, CPU, null, XMM, null), - BMI1(CPUFeature.BMI1, null, null, null, CPU, CPU, CPU, null), - BMI2(CPUFeature.BMI2, null, null, null, CPU, CPU, CPU, null), - FMA(CPUFeature.FMA, CPUFeature.FMA, EVEXFeatureAssertion.AVX512F_VL), - FMA_AVX512F_128ONLY(CPUFeature.FMA, null, null, EVEXFeatureAssertion.AVX512F_128ONLY, XMM, XMM, XMM, null), - - XMM_CPU_AVX512F_128ONLY(CPUFeature.AVX, null, null, EVEXFeatureAssertion.AVX512F_128ONLY, XMM, null, CPU, null), - XMM_CPU_AVX512BW_128ONLY(CPUFeature.AVX, null, null, EVEXFeatureAssertion.AVX512BW_128ONLY, XMM, null, CPU, null), - XMM_CPU_AVX512DQ_128ONLY(CPUFeature.AVX, null, null, EVEXFeatureAssertion.AVX512DQ_128ONLY, XMM, null, CPU, null), - CPU_XMM_AVX512F_128ONLY(CPUFeature.AVX, null, null, EVEXFeatureAssertion.AVX512F_128ONLY, CPU, null, XMM, null), - XMM_XMM_XMM_AVX512F_128ONLY(CPUFeature.AVX, null, null, EVEXFeatureAssertion.AVX512F_128ONLY, XMM, XMM, XMM, null), - XMM_XMM_CPU_AVX512F_128ONLY(CPUFeature.AVX, null, null, EVEXFeatureAssertion.AVX512F_128ONLY, XMM, XMM, CPU, null), - XMM_XMM_CPU_AVX512BW_128ONLY(CPUFeature.AVX, null, null, EVEXFeatureAssertion.AVX512BW_128ONLY, XMM, XMM, CPU, null), - XMM_XMM_CPU_AVX512DQ_128ONLY(CPUFeature.AVX, null, null, EVEXFeatureAssertion.AVX512DQ_128ONLY, XMM, XMM, CPU, null), - XMM_CPU_AVX512BW_VL(CPUFeature.AVX512VL, CPUFeature.AVX512VL, CPUFeature.AVX512BW, EVEXFeatureAssertion.AVX512F_BW_VL, XMM, null, CPU, null), - XMM_CPU_AVX512F_VL(CPUFeature.AVX512VL, CPUFeature.AVX512VL, CPUFeature.AVX512F, EVEXFeatureAssertion.AVX512F_VL, XMM, null, CPU, null), - AVX1_AVX512F_128_ONLY(CPUFeature.AVX, CPUFeature.AVX, EVEXFeatureAssertion.AVX512F_128ONLY), - AVX1_AVX512F_ALL(CPUFeature.AVX, CPUFeature.AVX, EVEXFeatureAssertion.AVX512F_ALL), - AVX1_AVX512F_VL(CPUFeature.AVX, CPUFeature.AVX, EVEXFeatureAssertion.AVX512F_VL), - AVX1_256ONLY_AVX512F_VL(null, CPUFeature.AVX, EVEXFeatureAssertion.AVX512F_VL_256_512), - AVX1_128ONLY_AVX512F_128ONLY(CPUFeature.AVX, null, EVEXFeatureAssertion.AVX512F_128ONLY), - AVX1_AVX2_AVX512F_BW(CPUFeature.AVX, CPUFeature.AVX2, EVEXFeatureAssertion.AVX512F_BW_ALL), - AVX1_AVX2_AVX512BW_VL(CPUFeature.AVX, CPUFeature.AVX2, EVEXFeatureAssertion.AVX512F_BW_VL), - AVX1_AVX2_AVX512DQ_VL(CPUFeature.AVX, CPUFeature.AVX2, EVEXFeatureAssertion.AVX512F_DQ_VL), - AVX1_AVX2_AVX512F_VL(CPUFeature.AVX, CPUFeature.AVX2, EVEXFeatureAssertion.AVX512F_VL), - AVX2_AVX512BW_VL(CPUFeature.AVX2, CPUFeature.AVX2, EVEXFeatureAssertion.AVX512F_BW_VL), - AVX2_AVX512F_VL(CPUFeature.AVX2, CPUFeature.AVX2, EVEXFeatureAssertion.AVX512F_VL), - AVX2_AVX512F_VL_256_512(null, CPUFeature.AVX2, EVEXFeatureAssertion.AVX512F_VL), - AVX512BW_VL(CPUFeature.AVX512VL, CPUFeature.AVX512VL, EVEXFeatureAssertion.AVX512F_BW_VL), - AVX512F_VL(CPUFeature.AVX512VL, CPUFeature.AVX512VL, EVEXFeatureAssertion.AVX512F_VL), - AVX512F_VL_256_512(null, CPUFeature.AVX512VL, EVEXFeatureAssertion.AVX512F_VL_256_512), - AVX512DQ_VL(CPUFeature.AVX512VL, CPUFeature.AVX512VL, EVEXFeatureAssertion.AVX512F_DQ_VL), - AVX512DQ_VL_256_512(null, CPUFeature.AVX512VL, EVEXFeatureAssertion.AVX512F_DQ_VL_256_512), - AVX512DQ_512ONLY(null, null, EVEXFeatureAssertion.AVX512F_DQ_512ONLY), - AVX512F_512ONLY(null, null, EVEXFeatureAssertion.AVX512F_512ONLY), - AVX_AVX512F_VL_256_512(null, CPUFeature.AVX, EVEXFeatureAssertion.AVX512F_VL), - AVX1_AVX512DQ_VL(CPUFeature.AVX, CPUFeature.AVX, EVEXFeatureAssertion.AVX512F_DQ_VL), - - AVX512F_CPU_OR_MASK(CPUFeature.AVX512F, null, null, EVEXFeatureAssertion.AVX512F_ALL, CPU_OR_MASK, null, CPU_OR_MASK, null), - AVX512DQ_CPU_OR_MASK(CPUFeature.AVX512DQ, null, null, EVEXFeatureAssertion.AVX512F_DQ_ALL, CPU_OR_MASK, null, CPU_OR_MASK, null), - AVX512BW_CPU_OR_MASK(CPUFeature.AVX512BW, null, null, EVEXFeatureAssertion.AVX512F_BW_ALL, CPU_OR_MASK, null, CPU_OR_MASK, null), - AVX512F_MASK(CPUFeature.AVX512F, null, null, null, MASK, MASK, MASK, null), - AVX512DQ_MASK(CPUFeature.AVX512DQ, null, null, null, MASK, MASK, MASK, null), - AVX512BW_MASK(CPUFeature.AVX512BW, null, null, null, MASK, MASK, MASK, null), - MASK_XMM_XMM_AVX512BW_VL(CPUFeature.AVX512VL, CPUFeature.AVX512VL, null, EVEXFeatureAssertion.AVX512F_BW_VL, MASK, XMM, XMM, null), - MASK_NULL_XMM_AVX512BW_VL(CPUFeature.AVX512VL, CPUFeature.AVX512VL, null, EVEXFeatureAssertion.AVX512F_BW_VL, MASK, null, XMM, null), - MASK_NULL_XMM_AVX512DQ_VL(CPUFeature.AVX512VL, CPUFeature.AVX512VL, null, EVEXFeatureAssertion.AVX512F_DQ_VL, MASK, null, XMM, null), - MASK_NULL_XMM_AVX512DQ(CPUFeature.AVX512DQ, CPUFeature.AVX512DQ, null, EVEXFeatureAssertion.AVX512F_DQ_ALL, MASK, null, XMM, null), - MASK_XMM_XMM_AVX512F_VL(CPUFeature.AVX512VL, CPUFeature.AVX512VL, null, EVEXFeatureAssertion.AVX512F_VL, MASK, XMM, XMM, null), - AVX1_128ONLY_CLMUL(CPUFeature.AVX, null, CPUFeature.CLMUL, null, XMM, XMM, XMM, XMM), - AVX1_128ONLY_AES(CPUFeature.AVX, null, CPUFeature.AES, null, XMM, XMM, XMM, XMM), - AVX1_GFNI_AVX512F_VL(GFNI, GFNI, CPUFeature.AVX, EVEXFeatureAssertion.AVX512F_VL, XMM, XMM, XMM, null), - F16C_AVX512F_VL(F16C, F16C, null, EVEXFeatureAssertion.AVX512F_VL, XMM, XMM, XMM, null); - - private final CPUFeature l128feature; - private final CPUFeature l256feature; - private final CPUFeature extendedFeature; - private final EVEXFeatureAssertion l512features; + /** + * This is used to verify the availability of an instruction during code emission. + */ + private enum VEXOpAssertion { + AVX1(VEXFeatureAssertion.AVX1, null, XMM, XMM, XMM), + AVX1_2(VEXFeatureAssertion.AVX1_AVX2, null, XMM, XMM, XMM), + AVX2(VEXFeatureAssertion.AVX2, null, XMM, XMM, XMM), + AVX1_128ONLY(VEXFeatureAssertion.AVX1_128, null, XMM, XMM, XMM), + AVX1_256ONLY(VEXFeatureAssertion.AVX1_256, null, XMM, XMM, XMM), + AVX2_256ONLY(VEXFeatureAssertion.AVX2_256, null, XMM, XMM, XMM), + XMM_CPU(VEXFeatureAssertion.AVX1_128, null, XMM, null, CPU), + XMM_XMM_CPU(VEXFeatureAssertion.AVX1_128, null, XMM, XMM, CPU), + CPU_XMM(VEXFeatureAssertion.AVX1_128, null, CPU, null, XMM), + AVX1_CPU_XMM(VEXFeatureAssertion.AVX1, null, CPU, null, XMM), + AVX1_2_CPU_XMM(VEXFeatureAssertion.AVX1_AVX2, null, CPU, null, XMM), + BMI1(VEXFeatureAssertion.BMI1, null, CPU, CPU, CPU), + BMI2(VEXFeatureAssertion.BMI2, null, CPU, CPU, CPU), + FMA(VEXFeatureAssertion.FMA, EVEXFeatureAssertion.AVX512F_VL, XMM, XMM, XMM), + FMA_AVX512F_128ONLY(VEXFeatureAssertion.FMA_128, EVEXFeatureAssertion.AVX512F_128, XMM, XMM, XMM), + + AVX1_AVX512F_CPU_OR_XMM(VEXFeatureAssertion.AVX1_128, EVEXFeatureAssertion.AVX512F_128, CPU_OR_XMM, null, CPU_OR_XMM), + XMM_CPU_AVX1_AVX512BW_128ONLY(VEXFeatureAssertion.AVX1_128, EVEXFeatureAssertion.AVX512BW_128, XMM, null, CPU), + XMM_CPU_AVX1_AVX512DQ_128ONLY(VEXFeatureAssertion.AVX1_128, EVEXFeatureAssertion.AVX512DQ_128, XMM, null, CPU), + CPU_XMM_AVX1_AVX512F_128ONLY(VEXFeatureAssertion.AVX1_128, EVEXFeatureAssertion.AVX512F_128, CPU, null, XMM), + XMM_XMM_CPU_AVX1_AVX512F_128ONLY(VEXFeatureAssertion.AVX1_128, EVEXFeatureAssertion.AVX512F_128, XMM, XMM, CPU), + XMM_XMM_CPU_AVX1_AVX512BW_128ONLY(VEXFeatureAssertion.AVX1_128, EVEXFeatureAssertion.AVX512BW_128, XMM, XMM, CPU), + XMM_XMM_CPU_AVX1_AVX512DQ_128ONLY(VEXFeatureAssertion.AVX1_128, EVEXFeatureAssertion.AVX512DQ_128, XMM, XMM, CPU), + XMM_CPU_AVX512BW_VL(null, EVEXFeatureAssertion.AVX512F_BW_VL, XMM, null, CPU), + XMM_CPU_AVX512F_VL(null, EVEXFeatureAssertion.AVX512F_VL, XMM, null, CPU), + AVX1_AVX512F_VL(VEXFeatureAssertion.AVX1, EVEXFeatureAssertion.AVX512F_VL, XMM, XMM, XMM), + AVX1_AVX512DQ_VL(VEXFeatureAssertion.AVX1, EVEXFeatureAssertion.AVX512F_DQ_VL, XMM, XMM, XMM), + AVX1_AVX512F_128(VEXFeatureAssertion.AVX1_128, EVEXFeatureAssertion.AVX512F_128, XMM, XMM, XMM), + AVX1_AVX512F_VL_256_512(VEXFeatureAssertion.AVX1_256, EVEXFeatureAssertion.AVX512F_VL_256_512, XMM, XMM, XMM), + AVX1_AVX2_AVX512F_VL(VEXFeatureAssertion.AVX1_AVX2, EVEXFeatureAssertion.AVX512F_VL, XMM, XMM, XMM), + AVX1_AVX2_AVX512BW_VL(VEXFeatureAssertion.AVX1_AVX2, EVEXFeatureAssertion.AVX512F_BW_VL, XMM, XMM, XMM), + AVX1_AVX2_AVX512DQ_VL(VEXFeatureAssertion.AVX1_AVX2, EVEXFeatureAssertion.AVX512F_DQ_VL, XMM, XMM, XMM), + AVX2_AVX512F_VL(VEXFeatureAssertion.AVX2, EVEXFeatureAssertion.AVX512F_VL, XMM, XMM, XMM), + AVX2_AVX512BW_VL(VEXFeatureAssertion.AVX2, EVEXFeatureAssertion.AVX512F_BW_VL, XMM, XMM, XMM), + AVX2_AVX512F_VL_256_512(VEXFeatureAssertion.AVX2_256, EVEXFeatureAssertion.AVX512F_VL_256_512, XMM, XMM, XMM), + AVX512F_VL(null, EVEXFeatureAssertion.AVX512F_VL, XMM, XMM, XMM), + AVX512BW_VL(null, EVEXFeatureAssertion.AVX512F_BW_VL, XMM, XMM, XMM), + AVX512DQ_VL(null, EVEXFeatureAssertion.AVX512F_DQ_VL, XMM, XMM, XMM), + AVX512F_VL_256_512(null, EVEXFeatureAssertion.AVX512F_VL_256_512, XMM, XMM, XMM), + AVX512DQ_VL_256_512(null, EVEXFeatureAssertion.AVX512F_DQ_VL_256_512, XMM, XMM, XMM), + AVX512F_512ONLY(null, EVEXFeatureAssertion.AVX512F_512, XMM, XMM, XMM), + AVX512DQ_512ONLY(null, EVEXFeatureAssertion.AVX512F_DQ_512, XMM, XMM, XMM), + AVX512_VBMI_VL(null, EVEXFeatureAssertion.AVX512_VBMI_VL, XMM, XMM, XMM), + + AVX512F_CPU_OR_MASK(VEXFeatureAssertion.AVX512F_L0, null, CPU_OR_MASK, null, CPU_OR_MASK), + AVX512BW_CPU_OR_MASK(VEXFeatureAssertion.AVX512BW_L0, null, CPU_OR_MASK, null, CPU_OR_MASK), + AVX512DQ_CPU_OR_MASK(VEXFeatureAssertion.AVX512DQ_L0, null, CPU_OR_MASK, null, CPU_OR_MASK), + AVX512F_MASK_L0(VEXFeatureAssertion.AVX512F_L0, null, MASK, MASK, MASK), + AVX512DQ_MASK_L0(VEXFeatureAssertion.AVX512DQ_L0, null, MASK, MASK, MASK), + AVX512BW_MASK_L0(VEXFeatureAssertion.AVX512BW_L0, null, MASK, MASK, MASK), + AVX512F_MASK_L1(VEXFeatureAssertion.AVX512F_L1, null, MASK, MASK, MASK), + AVX512DQ_MASK_L1(VEXFeatureAssertion.AVX512DQ_L1, null, MASK, MASK, MASK), + AVX512BW_MASK_L1(VEXFeatureAssertion.AVX512BW_L1, null, MASK, MASK, MASK), + MASK_XMM_XMM_AVX512F_VL(null, EVEXFeatureAssertion.AVX512F_VL, MASK, XMM, XMM), + MASK_XMM_XMM_AVX512BW_VL(null, EVEXFeatureAssertion.AVX512F_BW_VL, MASK, XMM, XMM), + MASK_XMM_XMM_AVX512F_128(null, EVEXFeatureAssertion.AVX512F_128, MASK, XMM, XMM), + MASK_XMM_AVX512BW_VL(null, EVEXFeatureAssertion.AVX512F_BW_VL, MASK, null, XMM), + MASK_XMM_AVX512DQ_VL(null, EVEXFeatureAssertion.AVX512F_DQ_VL, MASK, null, XMM), + MASK_XMM_AVX512DQ_128(null, EVEXFeatureAssertion.AVX512DQ_128, MASK, null, XMM), + + CLMUL_AVX1_AVX512F_VL(VEXFeatureAssertion.CLMUL_AVX1, EVEXFeatureAssertion.CLMUL_AVX512F_VL, XMM, XMM, XMM), + AES_AVX1_128ONLY(VEXFeatureAssertion.AVX1_AES_128, null, XMM, XMM, XMM), + GFNI_AVX1_AVX512F_VL(VEXFeatureAssertion.GFNI_AVX1, EVEXFeatureAssertion.GFNI_AVX512F_VL, XMM, XMM, XMM), + F16C_AVX512F_VL(VEXFeatureAssertion.F16C, EVEXFeatureAssertion.AVX512F_VL, XMM, XMM, XMM); + + private final VEXFeatureAssertion vexFeatures; + private final EVEXFeatureAssertion evexFeatures; private final RegisterCategory rCategory; private final RegisterCategory vCategory; private final RegisterCategory mCategory; - private final RegisterCategory imm8Category; - - VEXOpAssertion(CPUFeature l128feature, CPUFeature l256feature, EVEXFeatureAssertion l512features) { - this(l128feature, l256feature, null, l512features, XMM, XMM, XMM, XMM); - } - VEXOpAssertion(CPUFeature l128feature, CPUFeature l256feature, CPUFeature extendedFeature, EVEXFeatureAssertion l512features, RegisterCategory rCategory, RegisterCategory vCategory, - RegisterCategory mCategory, RegisterCategory imm8Category) { - this.l128feature = l128feature; - this.l256feature = l256feature; - this.extendedFeature = extendedFeature; - this.l512features = l512features; + VEXOpAssertion(VEXFeatureAssertion vexFeatures, EVEXFeatureAssertion evexFeatures, RegisterCategory rCategory, RegisterCategory vCategory, RegisterCategory mCategory) { + this.vexFeatures = vexFeatures; + this.evexFeatures = evexFeatures; this.rCategory = rCategory; this.vCategory = vCategory; this.mCategory = mCategory; - this.imm8Category = imm8Category; } - public boolean check(EnumSet features, AVXKind.AVXSize size, Register r, Register v, Register m) { - return check(features, getLFlag(size), r, v, m, null); + private boolean isValid(EnumSet features, AVXSize size) { + return vexFeatures != null && vexFeatures.isValid(features, size) || evexFeatures != null && evexFeatures.isValid(features, size); } + } - public boolean check(EnumSet features, AVXKind.AVXSize size, Register r, Register v, Register m, Register imm8) { - return check(features, getLFlag(size), r, v, m, imm8); - } + /** + * This is used to query the availability of operations, in contrast to {@link VEXOpAssertion} + * where the {@link AVXSize} parameter is used purely as an encoding property, this class used + * {@code AVXSize} to denote the size of the operations. As a result, it is generally expected + * that if an operation is available with a large {@code AVXSize}, it is also available with + * smaller ones. + */ + public enum VectorFeatureAssertion { + AVX1_AVX512F_VL(VEXOpAssertion.AVX1_AVX512F_VL), + AVX1_AVX512DQ_VL(VEXOpAssertion.AVX1_AVX512DQ_VL), + AVX1_AVX2_AVX512F_VL(VEXOpAssertion.AVX1_AVX2_AVX512F_VL), + AVX1_AVX2_AVX512BW_VL(VEXOpAssertion.AVX1_AVX2_AVX512BW_VL), + AVX1_AVX2_AVX512DQ_VL(VEXOpAssertion.AVX1_AVX2_AVX512DQ_VL), + AVX2_AVX512F_VL(VEXOpAssertion.AVX2_AVX512F_VL), + AVX2_AVX512BW_VL(VEXOpAssertion.AVX2_AVX512BW_VL), + AVX512F_VL(VEXOpAssertion.AVX512F_VL), + AVX512BW_VL(VEXOpAssertion.AVX512BW_VL), + AVX512DQ_VL(VEXOpAssertion.AVX512DQ_VL), + FMA(VEXOpAssertion.FMA); - public boolean check(EnumSet features, int l, Register r, Register v, Register m, Register imm8) { - if (isAVX512Register(r) || isAVX512Register(v) || isAVX512Register(m) || l == VEXPrefixConfig.L512) { - GraalError.guarantee(l512features != null && l512features.check(features, l), "emitting illegal 512 bit instruction, required features: %s", l512features); - } else if (l == VEXPrefixConfig.L128) { - GraalError.guarantee(l128feature != null && features.contains(l128feature), "emitting illegal 128 bit instruction, required feature: %s", l128feature); - } else if (l == VEXPrefixConfig.L256) { - GraalError.guarantee(l256feature != null && features.contains(l256feature), "emitting illegal 256 bit instruction, required feature: %s", l256feature); - } - if (r != null) { - GraalError.guarantee(categoryContains(rCategory, r), "expected r in category %s, got %s", rCategory, r); - } - if (v != null) { - GraalError.guarantee(categoryContains(vCategory, v), "expected v in category %s, got %s", vCategory, v); - } - if (m != null) { - GraalError.guarantee(categoryContains(mCategory, m), "expected m in category %s, got %s", mCategory, m); - } - if (imm8 != null) { - GraalError.guarantee(imm8.getRegisterCategory().equals(imm8Category), "expected imm8 in category %s, got %s", imm8Category, imm8); - } - if (extendedFeature != null) { - GraalError.guarantee(features.contains(extendedFeature), "emitting illegal instruction, required extended feature: %s", extendedFeature); - } - return true; + private final VEXOpAssertion opAssertion; + + VectorFeatureAssertion(VEXOpAssertion opAssertion) { + this.opAssertion = opAssertion; } - public boolean supports(EnumSet features, AVXKind.AVXSize avxSize, boolean useZMMRegisters) { - boolean extendedFeatureCheck = extendedFeature != null ? features.contains(extendedFeature) : true; - if (useZMMRegisters || avxSize == AVXKind.AVXSize.ZMM) { - return l512features != null && l512features.supports(features, avxSize) && extendedFeatureCheck; - } else if (avxSize == AVXKind.AVXSize.XMM) { - return l128feature != null && features.contains(l128feature) && extendedFeatureCheck; - } else if (avxSize == AVXKind.AVXSize.YMM) { - return l256feature != null && features.contains(l256feature) && extendedFeatureCheck; - } - throw GraalError.shouldNotReachHereUnexpectedValue(avxSize); // ExcludeFromJacocoGeneratedReport + public boolean supports(EnumSet features, AVXSize size) { + return opAssertion.isValid(features, size); } } @@ -1269,16 +1278,8 @@ protected VexOp(String opcode, int pp, int mmmmm, int w, int op, VEXOpAssertion this(opcode, pp, mmmmm, w, op, assertion, EVEXTuple.INVALID, VEXPrefixConfig.WIG); } - public final boolean isSupported(AMD64Assembler vasm, AVXKind.AVXSize size) { - return isSupported(vasm, size, false); - } - - public final boolean isSupported(AMD64Assembler vasm, AVXKind.AVXSize size, boolean useZMMRegisters) { - return assertion.supports(vasm.getFeatures(), size, useZMMRegisters); - } - - public final boolean isSupported(AMD64 arch, AMD64Kind kind) { - return assertion.supports(arch.getFeatures(), AVXKind.getRegisterSize(kind), false); + public boolean isSupported(AMD64Assembler asm, AVXSize size) { + return assertion.isValid(asm.getFeatures(), size); } /** @@ -1308,48 +1309,61 @@ public String toString() { return opcode; } - protected final int getDisp8Scale(boolean useEvex, AVXKind.AVXSize size) { + protected final int getDisp8Scale(boolean useEvex, AVXSize size) { return useEvex ? evexTuple.getDisp8ScalingFactor(size) : DEFAULT_DISP8_SCALE; } - protected final void emitVexOrEvex(AMD64Assembler asm, Register dst, Register nds, Register src, AVXKind.AVXSize size, int actualPP, int actualMMMMM, int actualW, int actualWEvex, - boolean checkAVX) { - emitVexOrEvex(asm, dst, nds, src, Register.None, size, actualPP, actualMMMMM, actualW, actualWEvex, checkAVX, Z0, B0); + protected final void emitVexOrEvex(AMD64Assembler asm, Register dst, Register nds, Register src, AVXSize size, int actualPP, int actualMMMMM, int actualW, int actualWEvex) { + emitVexOrEvex(asm, dst, nds, src, Register.None, size, actualPP, actualMMMMM, actualW, actualWEvex, Z0, B0); } - protected final void emitVexOrEvex(AMD64Assembler asm, Register dst, Register nds, Register src, Register opmask, AVXKind.AVXSize size, int actualPP, int actualMMMMM, int actualW, - int actualWEvex, boolean checkAVX, int z, int b) { + protected final void emitVexOrEvex(AMD64Assembler asm, Register dst, Register nds, Register src, Register opmask, AVXSize size, int actualPP, int actualMMMMM, int actualW, + int actualWEvex, int z, int b) { + AVXSize avxSize = size; + if (avxSize == AVXSize.DWORD || avxSize == AVXSize.QWORD) { + avxSize = AVXSize.XMM; + } if (isEvex) { - asm.evexPrefix(dst, opmask, nds, src, size, actualPP, actualMMMMM, actualWEvex, z, b); + checkEvex(asm, avxSize, dst, opmask, z, nds, src, b); + asm.evexPrefix(dst, opmask, nds, src, avxSize, actualPP, actualMMMMM, actualWEvex, z, b); } else { - GraalError.guarantee(Register.None.equals(opmask), "trying to emit VEX prefix for instruction %s with opmask %s", opcode, opmask); - GraalError.guarantee(size != AVXSize.ZMM, "trying to emit VEX prefix for ZMM sized %s", opcode); - // instructions using registers XMM16 - XMM31 need to be encoded with an EVEX prefix - GraalError.guarantee(!isAVX512Register(dst) && !isAVX512Register(nds) && !isAVX512Register(src), "trying to emit VEX prefix for instruction %s using dst: %s, nds: %s, src: %s", opcode, - dst, nds, src); - - asm.emitVEX(getLFlag(size), actualPP, actualMMMMM, actualW, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0, checkAVX); + checkVex(asm, avxSize, dst, opmask, z, nds, src, b); + asm.emitVEX(getLFlag(avxSize), actualPP, actualMMMMM, actualW, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0); } } - protected final void emitVexOrEvex(AMD64Assembler asm, Register dst, Register nds, AMD64Address src, AVXKind.AVXSize size, int actualPP, int actualMMMMM, int actualW, int actualWEvex, - boolean checkAVX) { - emitVexOrEvex(asm, dst, nds, src, Register.None, size, actualPP, actualMMMMM, actualW, actualWEvex, checkAVX, Z0, B0); + protected final void emitVexOrEvex(AMD64Assembler asm, Register dst, Register nds, AMD64Address src, AVXSize size, int actualPP, int actualMMMMM, int actualW, int actualWEvex) { + emitVexOrEvex(asm, dst, nds, src, Register.None, size, actualPP, actualMMMMM, actualW, actualWEvex, Z0, B0); } - protected final void emitVexOrEvex(AMD64Assembler asm, Register dst, Register nds, AMD64Address src, Register opmask, AVXKind.AVXSize size, int actualPP, int actualMMMMM, int actualW, - int actualWEvex, boolean checkAVX, int z, int b) { + protected final void emitVexOrEvex(AMD64Assembler asm, Register dst, Register nds, AMD64Address src, Register opmask, AVXSize size, int actualPP, int actualMMMMM, int actualW, + int actualWEvex, int z, int b) { if (isEvex) { + checkEvex(asm, size, dst, opmask, z, nds, null, b); asm.evexPrefix(dst, opmask, nds, src, size, actualPP, actualMMMMM, actualWEvex, z, b); } else { - GraalError.guarantee(Register.None.equals(opmask), "trying to emit VEX prefix for instruction %s with opmask %s", opcode, opmask); - GraalError.guarantee(size != AVXSize.ZMM, "trying to emit VEX prefix for ZMM sized %s", opcode); - // instructions using registers XMM16 - XMM31 need to be encoded with an EVEX prefix - GraalError.guarantee(!isAVX512Register(dst) && !isAVX512Register(nds), "trying to emit VEX prefix for instruction %s using dst: %s, nds: %s", opcode, dst, nds); - - asm.emitVEX(getLFlag(size), actualPP, actualMMMMM, actualW, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0, checkAVX); + checkVex(asm, size, dst, opmask, z, nds, null, b); + asm.emitVEX(getLFlag(size), actualPP, actualMMMMM, actualW, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0); } } + + private void checkVex(AMD64Assembler asm, AVXSize size, Register dst, Register mask, int z, Register nds, Register src, int b) { + GraalError.guarantee(mask.equals(Register.None) && z == Z0, "{%s}%s", mask.equals(Register.None) ? mask.name : "K0", z == Z0 ? "" : " {z}"); + GraalError.guarantee(b == B0, "illegal EVEX.b"); + GraalError.guarantee(dst == null || (!isAVX512Register(dst) && categoryContains(assertion.rCategory, dst)), "instruction %s illegal operand %s", opcode, dst); + GraalError.guarantee(!nds.isValid() || (!isAVX512Register(nds) && categoryContains(assertion.vCategory, nds)), "instruction %s illegal operand %s", opcode, nds); + GraalError.guarantee(src == null || (!isAVX512Register(src) && categoryContains(assertion.mCategory, src)), "instruction %s illegal operand %s", opcode, src); + GraalError.guarantee(assertion.vexFeatures.isValid(asm.getFeatures(), size), "instruction %s not supported for size %s", opcode, size); + } + + private void checkEvex(AMD64Assembler asm, AVXSize size, Register dst, Register mask, int z, Register nds, Register src, int b) { + GraalError.guarantee(mask.isValid() || z == Z0, "illegal EVEX.z for no mask"); + GraalError.guarantee(src == null || b == B0, "illegal EVEX.b for register operand %s", src); + GraalError.guarantee(dst == null || categoryContains(assertion.rCategory, dst), "instruction %s illegal operand %s", opcode, dst); + GraalError.guarantee(!nds.isValid() || categoryContains(assertion.vCategory, nds), "instruction %s illegal operand %s", opcode, nds); + GraalError.guarantee(src == null || categoryContains(assertion.mCategory, src), "instruction %s illegal operand %s", opcode, src); + GraalError.guarantee(assertion.evexFeatures.isValid(asm.getFeatures(), size), "instruction %s not supported for size %s", opcode, size); + } } /** @@ -1364,20 +1378,20 @@ public static class VexRROp extends VexOp { public static final VexRROp EVPBROADCASTD_GPR = new VexRROp("EVPBROADCASTD_GPR", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x7C, VEXOpAssertion.XMM_CPU_AVX512F_VL, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0, true); public static final VexRROp EVPBROADCASTQ_GPR = new VexRROp("EVPBROADCASTQ_GPR", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W1, 0x7C, VEXOpAssertion.XMM_CPU_AVX512F_VL, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1, true); - public static final VexRROp KTESTB = new VexRROp("KTESTB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x99, VEXOpAssertion.AVX512DQ_MASK); - public static final VexRROp KTESTW = new VexRROp("KTESTW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x99, VEXOpAssertion.AVX512DQ_MASK); - public static final VexRROp KTESTD = new VexRROp("KTESTD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x99, VEXOpAssertion.AVX512BW_MASK); - public static final VexRROp KTESTQ = new VexRROp("KTESTQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x99, VEXOpAssertion.AVX512BW_MASK); + public static final VexRROp KTESTB = new VexRROp("KTESTB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x99, VEXOpAssertion.AVX512DQ_MASK_L0); + public static final VexRROp KTESTW = new VexRROp("KTESTW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x99, VEXOpAssertion.AVX512DQ_MASK_L0); + public static final VexRROp KTESTD = new VexRROp("KTESTD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x99, VEXOpAssertion.AVX512BW_MASK_L0); + public static final VexRROp KTESTQ = new VexRROp("KTESTQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x99, VEXOpAssertion.AVX512BW_MASK_L0); - public static final VexRROp KORTESTB = new VexRROp("KORTESTB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x98, VEXOpAssertion.AVX512DQ_MASK); - public static final VexRROp KORTESTW = new VexRROp("KORTESTW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x98, VEXOpAssertion.AVX512F_MASK); - public static final VexRROp KORTESTD = new VexRROp("KORTESTD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x98, VEXOpAssertion.AVX512BW_MASK); - public static final VexRROp KORTESTQ = new VexRROp("KORTESTQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x98, VEXOpAssertion.AVX512BW_MASK); + public static final VexRROp KORTESTB = new VexRROp("KORTESTB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x98, VEXOpAssertion.AVX512DQ_MASK_L0); + public static final VexRROp KORTESTW = new VexRROp("KORTESTW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x98, VEXOpAssertion.AVX512F_MASK_L0); + public static final VexRROp KORTESTD = new VexRROp("KORTESTD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x98, VEXOpAssertion.AVX512BW_MASK_L0); + public static final VexRROp KORTESTQ = new VexRROp("KORTESTQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x98, VEXOpAssertion.AVX512BW_MASK_L0); - public static final VexRROp KNOTB = new VexRROp("KNOTB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x44, VEXOpAssertion.AVX512DQ_MASK); - public static final VexRROp KNOTW = new VexRROp("KNOTW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x44, VEXOpAssertion.AVX512F_MASK); - public static final VexRROp KNOTD = new VexRROp("KNOTD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x44, VEXOpAssertion.AVX512BW_MASK); - public static final VexRROp KNOTQ = new VexRROp("KNOTQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x44, VEXOpAssertion.AVX512BW_MASK); + public static final VexRROp KNOTB = new VexRROp("KNOTB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x44, VEXOpAssertion.AVX512DQ_MASK_L0); + public static final VexRROp KNOTW = new VexRROp("KNOTW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x44, VEXOpAssertion.AVX512F_MASK_L0); + public static final VexRROp KNOTD = new VexRROp("KNOTD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x44, VEXOpAssertion.AVX512BW_MASK_L0); + public static final VexRROp KNOTQ = new VexRROp("KNOTQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x44, VEXOpAssertion.AVX512BW_MASK_L0); // @formatter:on protected VexRROp(String opcode, int pp, int mmmmm, int w, int op, VEXOpAssertion assertion, EVEXTuple evexTuple, int wEvex, boolean isEvex) { @@ -1398,17 +1412,11 @@ public VexRROp encoding(AMD64SIMDInstructionEncoding encoding) { } public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, src), "emitting invalid instruction"); - assert op != 0x1A || op != 0x5A : op; - emitVexOrEvex(asm, dst, Register.None, src, size, pp, mmmmm, w, wEvex, false); - asm.emitByte(op); - asm.emitModRM(dst, src); + emit(asm, size, dst, src, Register.None, Z0, B0); } public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, src), "emitting invalid instruction"); - assert op != 0x1A || op != 0x5A : op; - emitVexOrEvex(asm, dst, Register.None, src, mask, size, pp, mmmmm, w, wEvex, false, z, b); + emitVexOrEvex(asm, dst, Register.None, src, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); asm.emitModRM(dst, src); } @@ -1419,11 +1427,11 @@ public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src, R */ public static class VexRMOp extends VexRROp { // @formatter:off - public static final VexRMOp VAESIMC = new VexRMOp("VAESIMC", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0xDB, VEXOpAssertion.AVX1_128ONLY_AES); - public static final VexRMOp VCVTTSS2SI = new VexRMOp("VCVTTSS2SI", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x2C, VEXOpAssertion.CPU_XMM_AVX512F_128ONLY, EVEXTuple.T1F_32BIT, VEXPrefixConfig.W0); - public static final VexRMOp VCVTTSS2SQ = new VexRMOp("VCVTTSS2SQ", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x2C, VEXOpAssertion.CPU_XMM_AVX512F_128ONLY, EVEXTuple.T1F_32BIT, VEXPrefixConfig.W1); - public static final VexRMOp VCVTTSD2SI = new VexRMOp("VCVTTSD2SI", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x2C, VEXOpAssertion.CPU_XMM_AVX512F_128ONLY, EVEXTuple.T1F_64BIT, VEXPrefixConfig.W0); - public static final VexRMOp VCVTTSD2SQ = new VexRMOp("VCVTTSD2SQ", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x2C, VEXOpAssertion.CPU_XMM_AVX512F_128ONLY, EVEXTuple.T1F_64BIT, VEXPrefixConfig.W1); + public static final VexRMOp VAESIMC = new VexRMOp("VAESIMC", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0xDB, VEXOpAssertion.AES_AVX1_128ONLY); + public static final VexRMOp VCVTTSS2SI = new VexRMOp("VCVTTSS2SI", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x2C, VEXOpAssertion.CPU_XMM_AVX1_AVX512F_128ONLY, EVEXTuple.T1F_32BIT, VEXPrefixConfig.W0); + public static final VexRMOp VCVTTSS2SQ = new VexRMOp("VCVTTSS2SQ", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x2C, VEXOpAssertion.CPU_XMM_AVX1_AVX512F_128ONLY, EVEXTuple.T1F_32BIT, VEXPrefixConfig.W1); + public static final VexRMOp VCVTTSD2SI = new VexRMOp("VCVTTSD2SI", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x2C, VEXOpAssertion.CPU_XMM_AVX1_AVX512F_128ONLY, EVEXTuple.T1F_64BIT, VEXPrefixConfig.W0); + public static final VexRMOp VCVTTSD2SQ = new VexRMOp("VCVTTSD2SQ", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x2C, VEXOpAssertion.CPU_XMM_AVX1_AVX512F_128ONLY, EVEXTuple.T1F_64BIT, VEXPrefixConfig.W1); public static final VexRMOp VCVTPS2PD = new VexRMOp("VCVTPS2PD", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5A, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.HVM, VEXPrefixConfig.W0); public static final VexRMOp VCVTPD2PS = new VexRMOp("VCVTPD2PS", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5A, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); public static final VexRMOp VCVTDQ2PS = new VexRMOp("VCVTDQ2PS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5B, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); @@ -1432,9 +1440,9 @@ public static class VexRMOp extends VexRROp { public static final VexRMOp VCVTDQ2PD = new VexRMOp("VCVTDQ2PD", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xE6, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.HVM, VEXPrefixConfig.W0); public static final VexRMOp VMOVDDUP = new VexRMOp("VMOVDDUP", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x12, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.DUP, VEXPrefixConfig.W1); public static final VexRMOp VBROADCASTSS = new VexRMOp("VBROADCASTSS", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x18, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRMOp VBROADCASTSD = new VexRMOp("VBROADCASTSD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x19, VEXOpAssertion.AVX1_256ONLY_AVX512F_VL, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); - public static final VexRMOp VBROADCASTF128 = new VexRMOp("VBROADCASTF128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x1A, VEXOpAssertion.AVX1_256ONLY); - public static final VexRMOp VPBROADCASTI128 = new VexRMOp("VPBROADCASTI128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x5A, VEXOpAssertion.AVX2_256ONLY); + public static final VexRMOp VBROADCASTSD = new VexRMOp("VBROADCASTSD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x19, VEXOpAssertion.AVX1_AVX512F_VL_256_512, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRMOp VBROADCASTF128 = new VexRMOp("VBROADCASTF128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x1A, VEXOpAssertion.AVX1_AVX512F_VL_256_512, EVEXTuple.T4_32BIT, VEXPrefixConfig.W0); + public static final VexRMOp VPBROADCASTI128 = new VexRMOp("VPBROADCASTI128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x5A, VEXOpAssertion.AVX2_AVX512F_VL_256_512, EVEXTuple.T4_32BIT, VEXPrefixConfig.W0); public static final VexRMOp VPBROADCASTB = new VexRMOp("VPBROADCASTB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x78, VEXOpAssertion.AVX2_AVX512BW_VL, EVEXTuple.T1S_8BIT, VEXPrefixConfig.W0); public static final VexRMOp VPBROADCASTW = new VexRMOp("VPBROADCASTW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x79, VEXOpAssertion.AVX2_AVX512BW_VL, EVEXTuple.T1S_16BIT, VEXPrefixConfig.W0); public static final VexRMOp VPBROADCASTD = new VexRMOp("VPBROADCASTD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x58, VEXOpAssertion.AVX2_AVX512F_VL, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); @@ -1455,11 +1463,11 @@ public static class VexRMOp extends VexRROp { public static final VexRMOp VPMOVZXWD = new VexRMOp("VPMOVZXWD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x33, VEXOpAssertion.AVX1_AVX2_AVX512F_VL, EVEXTuple.HVM, VEXPrefixConfig.WIG); public static final VexRMOp VPMOVZXWQ = new VexRMOp("VPMOVZXWQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x34, VEXOpAssertion.AVX1_AVX2_AVX512F_VL, EVEXTuple.QVM, VEXPrefixConfig.WIG); public static final VexRMOp VPMOVZXDQ = new VexRMOp("VPMOVZXDQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x35, VEXOpAssertion.AVX1_AVX2_AVX512F_VL, EVEXTuple.HVM, VEXPrefixConfig.WIG); - public static final VexRMOp VPTEST = new VexRMOp("VPTEST", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x17); + public static final VexRMOp VPTEST = new VexRMOp("VPTEST", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x17, VEXOpAssertion.AVX1); public static final VexRMOp VSQRTPD = new VexRMOp("VSQRTPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x51, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); public static final VexRMOp VSQRTPS = new VexRMOp("VSQRTPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x51, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); - public static final VexRMOp VUCOMISS = new VexRMOp("VUCOMISS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x2E, VEXOpAssertion.AVX1_AVX512F_128_ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRMOp VUCOMISD = new VexRMOp("VUCOMISD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x2E, VEXOpAssertion.AVX1_AVX512F_128_ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRMOp VUCOMISS = new VexRMOp("VUCOMISS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x2E, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRMOp VUCOMISD = new VexRMOp("VUCOMISD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x2E, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); public static final VexRMOp VPABSB = new VexRMOp("VPABSB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x1C, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); public static final VexRMOp VPABSW = new VexRMOp("VPABSW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x1D, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); public static final VexRMOp VPABSD = new VexRMOp("VPABSD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x1E, VEXOpAssertion.AVX1_AVX2_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); @@ -1487,10 +1495,10 @@ public static class VexRMOp extends VexRROp { public static final VexRMOp EVPBROADCASTW = new VexRMOp("EVPBROADCASTW", VPBROADCASTW); public static final VexRMOp EVPBROADCASTD = new VexRMOp("EVPBROADCASTD", VPBROADCASTD); public static final VexRMOp EVPBROADCASTQ = new VexRMOp("EVPBROADCASTQ", VPBROADCASTQ); - public static final VexRMOp EVPMOVB2M = new VexRMOp("EVPMOVB2M", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x29, VEXOpAssertion.MASK_NULL_XMM_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.W0, true); - public static final VexRMOp EVPMOVW2M = new VexRMOp("EVPMOVW2M", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W1, 0x29, VEXOpAssertion.MASK_NULL_XMM_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.W1, true); - public static final VexRMOp EVPMOVD2M = new VexRMOp("EVPMOVD2M", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x39, VEXOpAssertion.MASK_NULL_XMM_AVX512DQ_VL, EVEXTuple.FVM, VEXPrefixConfig.W0, true); - public static final VexRMOp EVPMOVQ2M = new VexRMOp("EVPMOVQ2M", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W1, 0x39, VEXOpAssertion.MASK_NULL_XMM_AVX512DQ_VL, EVEXTuple.FVM, VEXPrefixConfig.W1, true); + public static final VexRMOp EVPMOVB2M = new VexRMOp("EVPMOVB2M", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x29, VEXOpAssertion.MASK_XMM_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.W0, true); + public static final VexRMOp EVPMOVW2M = new VexRMOp("EVPMOVW2M", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W1, 0x29, VEXOpAssertion.MASK_XMM_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.W1, true); + public static final VexRMOp EVPMOVD2M = new VexRMOp("EVPMOVD2M", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x39, VEXOpAssertion.MASK_XMM_AVX512DQ_VL, EVEXTuple.FVM, VEXPrefixConfig.W0, true); + public static final VexRMOp EVPMOVQ2M = new VexRMOp("EVPMOVQ2M", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W1, 0x39, VEXOpAssertion.MASK_XMM_AVX512DQ_VL, EVEXTuple.FVM, VEXPrefixConfig.W1, true); public static final VexRMOp EVPMOVSXBW = new VexRMOp("EVPMOVSXBW", VPMOVSXBW); public static final VexRMOp EVPMOVSXBD = new VexRMOp("EVPMOVSXBD", VPMOVSXBD); public static final VexRMOp EVPMOVSXBQ = new VexRMOp("EVPMOVSXBQ", VPMOVSXBQ); @@ -1515,10 +1523,6 @@ public static class VexRMOp extends VexRROp { // @formatter:on - protected VexRMOp(String opcode, int pp, int mmmmm, int w, int op) { - this(opcode, pp, mmmmm, w, op, VEXOpAssertion.AVX1, EVEXTuple.INVALID, VEXPrefixConfig.WIG); - } - protected VexRMOp(String opcode, int pp, int mmmmm, int w, int op, VEXOpAssertion assertion) { this(opcode, pp, mmmmm, w, op, assertion, EVEXTuple.INVALID, VEXPrefixConfig.WIG); } @@ -1556,15 +1560,13 @@ public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Ad @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, src), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, Register.None, src, mask, size, pp, mmmmm, w, wEvex, false, z, b); + emitVexOrEvex(asm, dst, Register.None, src, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); asm.emitModRM(dst, src); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Address src, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, null), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, Register.None, src, mask, size, pp, mmmmm, w, wEvex, false, z, b); + emitVexOrEvex(asm, dst, Register.None, src, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); asm.emitOperandHelper(dst, src, 0, getDisp8Scale(isEvex, size)); } @@ -1605,10 +1607,10 @@ public static final class VexMoveOp extends VexGeneralMoveOp { // VMOVSS and VMOVSD are RVM instructions when both src and dest are registers. // VexRVMOp.VMOVSS/VMOVSD utilize the merge semantics, while these simply move the whole // XMM register from src to dst - public static final VexMoveOp VMOVSS = new VexMoveOp("VMOVSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x10, 0x11, VEXOpAssertion.AVX1_128ONLY_AVX512F_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexMoveOp VMOVSD = new VexMoveOp("VMOVSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x10, 0x11, VEXOpAssertion.AVX1_128ONLY_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); - public static final VexMoveOp VMOVD = new VexMoveOp("VMOVD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x6E, 0x7E, VEXOpAssertion.XMM_CPU_AVX512F_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexMoveOp VMOVQ = new VexMoveOp("VMOVQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x6E, 0x7E, VEXOpAssertion.XMM_CPU_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexMoveOp VMOVSS = new VexMoveOp("VMOVSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x10, 0x11, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexMoveOp VMOVSD = new VexMoveOp("VMOVSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x10, 0x11, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexMoveOp VMOVD = new VexMoveOp("VMOVD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x6E, 0x7E, VEXOpAssertion.AVX1_AVX512F_CPU_OR_XMM, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexMoveOp VMOVQ = new VexMoveOp("VMOVQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x6E, 0x7E, VEXOpAssertion.AVX1_AVX512F_CPU_OR_XMM, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); // EVEX encoded instructions public static final VexMoveOp EVMOVDQA32 = new VexMoveOp("EVMOVDQA32", VMOVDQA32); @@ -1655,35 +1657,27 @@ public VexMoveOp encoding(AMD64SIMDInstructionEncoding encoding) { @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, AMD64Address dst, Register src) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, src, null, null), "emitting invalid instruction"); - emitVexOrEvex(asm, src, Register.None, dst, size, pp, mmmmm, w, wEvex, false); + emitVexOrEvex(asm, src, Register.None, dst, size, pp, mmmmm, w, wEvex); asm.emitByte(opReverse); asm.emitOperandHelper(src, dst, 0, getDisp8Scale(isEvex, size)); } public void emitReverse(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, src, null, dst), "emitting invalid instruction"); - emitVexOrEvex(asm, src, Register.None, dst, size, pp, mmmmm, w, wEvex, false); + emitVexOrEvex(asm, src, Register.None, dst, size, pp, mmmmm, w, wEvex); asm.emitByte(opReverse); asm.emitModRM(src, dst); } @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, src), "emitting invalid instruction"); - // MOVSS/SD are RVM instruction when both operands are registers - Register nds = (this == VMOVSS || this == VMOVSD || this == EVMOVSS || this == EVMOVSD) ? src : Register.None; - emitVexOrEvex(asm, dst, nds, src, size, pp, mmmmm, w, wEvex, false); - asm.emitByte(op); - asm.emitModRM(dst, src); + emit(asm, size, dst, src, Register.None, Z0, B0); } @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, src), "emitting invalid instruction"); // MOVSS/SD are RVM instruction when both operands are registers Register nds = (this == VMOVSS || this == VMOVSD || this == EVMOVSS || this == EVMOVSD) ? src : Register.None; - emitVexOrEvex(asm, dst, nds, src, mask, size, pp, mmmmm, w, wEvex, false, z, b); + emitVexOrEvex(asm, dst, nds, src, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); asm.emitModRM(dst, src); } @@ -1699,7 +1693,7 @@ public interface VexRRIOp { */ public static class VexRMIOp extends VexOp implements VexRRIOp { // @formatter:off - public static final VexRMIOp VAESKEYGENASSIST = new VexRMIOp("VAESKEYGENASSIST", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.WIG, 0xDF, VEXOpAssertion.AVX1_128ONLY_AES); + public static final VexRMIOp VAESKEYGENASSIST = new VexRMIOp("VAESKEYGENASSIST", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.WIG, 0xDF, VEXOpAssertion.AES_AVX1_128ONLY); public static final VexRMIOp VPERMQ = new VexRMIOp("VPERMQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W1, 0x00, VEXOpAssertion.AVX2_AVX512F_VL_256_512, EVEXTuple.FVM, VEXPrefixConfig.W1); public static final VexRMIOp VPSHUFLW = new VexRMIOp("VPSHUFLW", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x70, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); public static final VexRMIOp VPSHUFHW = new VexRMIOp("VPSHUFHW", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x70, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); @@ -1749,34 +1743,24 @@ public VexRMIOp encoding(AMD64SIMDInstructionEncoding encoding) { @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src, int imm8) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, src), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, Register.None, src, size, pp, mmmmm, w, wEvex, false); - asm.emitByte(op); - asm.emitModRM(dst, src); - asm.emitByte(imm8); + emit(asm, size, dst, src, imm8, Register.None, Z0, B0); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Address src, int imm8) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, null), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, Register.None, src, size, pp, mmmmm, w, wEvex, false); - asm.emitByte(op); - asm.emitOperandHelper(dst, src, 1, getDisp8Scale(isEvex, size)); - asm.emitByte(imm8); + emit(asm, size, dst, src, imm8, Register.None, Z0, B0); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src, int imm8, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, src), "emitting invalid instruction"); - asm.evexPrefix(dst, mask, Register.None, src, size, pp, mmmmm, wEvex, z, b); + emitVexOrEvex(asm, dst, Register.None, src, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); asm.emitModRM(dst, src); asm.emitByte(imm8); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Address src, int imm8, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, null), "emitting invalid instruction"); - asm.evexPrefix(dst, mask, Register.None, src, size, pp, mmmmm, wEvex, z, b); + emitVexOrEvex(asm, dst, Register.None, src, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); - asm.emitOperandHelper(dst, src, 1, getDisp8Scale(true, size)); + asm.emitOperandHelper(dst, src, 1, getDisp8Scale(isEvex, size)); asm.emitByte(imm8); } } @@ -1786,8 +1770,8 @@ public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Ad */ public static final class EvexRMIOp extends VexRMIOp { // @formatter:off - public static final EvexRMIOp EVFPCLASSSS = new EvexRMIOp("EVFPCLASS", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x67, VEXOpAssertion.MASK_NULL_XMM_AVX512DQ, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final EvexRMIOp EVFPCLASSSD = new EvexRMIOp("EVFPCLASD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W1, 0x67, VEXOpAssertion.MASK_NULL_XMM_AVX512DQ, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final EvexRMIOp EVFPCLASSSS = new EvexRMIOp("EVFPCLASS", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x67, VEXOpAssertion.MASK_XMM_AVX512DQ_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final EvexRMIOp EVFPCLASSSD = new EvexRMIOp("EVFPCLASD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W1, 0x67, VEXOpAssertion.MASK_XMM_AVX512DQ_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); // @formatter:on private EvexRMIOp(String opcode, int pp, int mmmmm, int w, int op, VEXOpAssertion assertion, EVEXTuple evexTuple, int wEvex) { @@ -1801,13 +1785,11 @@ public EvexRMIOp encoding(AMD64SIMDInstructionEncoding encoding) { @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src, int imm8) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, src), "emitting invalid instruction"); emit(asm, size, dst, src, imm8, Register.None, EVEXPrefixConfig.Z0, EVEXPrefixConfig.B0); } @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Address src, int imm8) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, null), "emitting invalid instruction"); emit(asm, size, dst, src, imm8, Register.None, EVEXPrefixConfig.Z0, EVEXPrefixConfig.B0); } } @@ -1843,8 +1825,7 @@ public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Registe @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, src, null, dst), "emitting invalid instruction"); - emitVexOrEvex(asm, src, Register.None, dst, mask, size, pp, mmmmm, w, wEvex, false, z, b); + emitVexOrEvex(asm, src, Register.None, dst, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); asm.emitModRM(src, dst); } @@ -1854,8 +1835,7 @@ public void emit(AMD64Assembler asm, AVXKind.AVXSize size, AMD64Address dst, Reg } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, AMD64Address dst, Register src, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, src, null, null), "emitting invalid instruction"); - emitVexOrEvex(asm, src, Register.None, dst, mask, size, pp, mmmmm, w, wEvex, false, z, b); + emitVexOrEvex(asm, src, Register.None, dst, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); asm.emitOperandHelper(src, dst, 1, getDisp8Scale(isEvex, size)); } @@ -1866,14 +1846,14 @@ public void emit(AMD64Assembler asm, AVXKind.AVXSize size, AMD64Address dst, Reg */ public static final class VexMRIOp extends VexOp implements VexRRIOp { // @formatter:off - public static final VexMRIOp VPEXTRB = new VexMRIOp("VPEXTRB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x14, VEXOpAssertion.XMM_CPU_AVX512BW_128ONLY, EVEXTuple.T1S_8BIT, VEXPrefixConfig.W0); - public static final VexMRIOp VPEXTRW = new VexMRIOp("VPEXTRW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x15, VEXOpAssertion.XMM_CPU_AVX512BW_128ONLY, EVEXTuple.T1S_16BIT, VEXPrefixConfig.W0); - public static final VexMRIOp VPEXTRD = new VexMRIOp("VPEXTRD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x16, VEXOpAssertion.XMM_CPU_AVX512DQ_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexMRIOp VPEXTRQ = new VexMRIOp("VPEXTRQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W1, 0x16, VEXOpAssertion.XMM_CPU_AVX512DQ_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexMRIOp VPEXTRB = new VexMRIOp("VPEXTRB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x14, VEXOpAssertion.XMM_CPU_AVX1_AVX512BW_128ONLY, EVEXTuple.T1S_8BIT, VEXPrefixConfig.W0); + public static final VexMRIOp VPEXTRW = new VexMRIOp("VPEXTRW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x15, VEXOpAssertion.XMM_CPU_AVX1_AVX512BW_128ONLY, EVEXTuple.T1S_16BIT, VEXPrefixConfig.W0); + public static final VexMRIOp VPEXTRD = new VexMRIOp("VPEXTRD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x16, VEXOpAssertion.XMM_CPU_AVX1_AVX512DQ_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexMRIOp VPEXTRQ = new VexMRIOp("VPEXTRQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W1, 0x16, VEXOpAssertion.XMM_CPU_AVX1_AVX512DQ_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); // AVX/AVX2 128-bit extract - public static final VexMRIOp VEXTRACTF128 = new VexMRIOp("VEXTRACTF128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x19, VEXOpAssertion.AVX1_256ONLY_AVX512F_VL, EVEXTuple.T4_32BIT, VEXPrefixConfig.W0); - public static final VexMRIOp VEXTRACTI128 = new VexMRIOp("VEXTRACTI128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x39, VEXOpAssertion.AVX2_AVX512F_VL_256_512, EVEXTuple.T4_32BIT, VEXPrefixConfig.W0); + public static final VexMRIOp VEXTRACTF128 = new VexMRIOp("VEXTRACTF128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x19, VEXOpAssertion.AVX1_AVX512F_VL_256_512, EVEXTuple.T4_32BIT, VEXPrefixConfig.W0); + public static final VexMRIOp VEXTRACTI128 = new VexMRIOp("VEXTRACTI128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x39, VEXOpAssertion.AVX2_AVX512F_VL_256_512, EVEXTuple.T4_32BIT, VEXPrefixConfig.W0); // AVX-512 extract public static final VexMRIOp EVPEXTRB = new VexMRIOp("EVPEXTRB", VPEXTRB); @@ -1924,32 +1904,22 @@ public VexMRIOp encoding(AMD64SIMDInstructionEncoding encoding) { @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src, int imm8) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, src, null, dst), "emitting invalid instruction"); - emitVexOrEvex(asm, src, Register.None, dst, size, pp, mmmmm, w, wEvex, false); - asm.emitByte(op); - asm.emitModRM(src, dst); - asm.emitByte(imm8); + emit(asm, size, dst, src, imm8, Register.None, Z0, B0); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, AMD64Address dst, Register src, int imm8) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, src, null, null), "emitting invalid instruction"); - emitVexOrEvex(asm, src, Register.None, dst, size, pp, mmmmm, w, wEvex, false); - asm.emitByte(op); - asm.emitOperandHelper(src, dst, 1, getDisp8Scale(isEvex, size)); - asm.emitByte(imm8); + emit(asm, size, dst, src, imm8, Register.None, Z0, B0); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src, int imm8, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, src, null, dst), "emitting invalid instruction"); - emitVexOrEvex(asm, src, Register.None, dst, mask, size, pp, mmmmm, w, wEvex, false, z, b); + emitVexOrEvex(asm, src, Register.None, dst, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); asm.emitModRM(src, dst); asm.emitByte(imm8); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, AMD64Address dst, Register src, int imm8, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, src, null, null), "emitting invalid instruction"); - emitVexOrEvex(asm, src, Register.None, dst, mask, size, pp, mmmmm, w, wEvex, false, z, b); + emitVexOrEvex(asm, src, Register.None, dst, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); asm.emitOperandHelper(src, dst, 1, getDisp8Scale(isEvex, size)); asm.emitByte(imm8); @@ -1976,16 +1946,16 @@ public VexRVMROp encoding(AMD64SIMDInstructionEncoding encoding) { } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register mask, Register src1, Register src2) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, mask, src1, src2), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex, false); + GraalError.guarantee(mask.getRegisterCategory().equals(XMM), "%s", mask); + emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex); asm.emitByte(op); asm.emitModRM(dst, src2); asm.emitByte(mask.encoding() << 4); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register mask, Register src1, AMD64Address src2) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, mask, src1, null), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex, false); + GraalError.guarantee(mask.getRegisterCategory().equals(XMM), "%s", mask); + emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex); asm.emitByte(op); asm.emitOperandHelper(dst, src2, 0, getDisp8Scale(isEvex, size)); asm.emitByte(mask.encoding() << 4); @@ -1994,30 +1964,30 @@ public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Registe public static class VexRVROp extends VexOp { // @formatter:off - public static final VexRVROp KANDW = new VexRVROp("KANDW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x41, VEXOpAssertion.AVX512F_MASK); - public static final VexRVROp KANDB = new VexRVROp("KANDB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x41, VEXOpAssertion.AVX512DQ_MASK); - public static final VexRVROp KANDQ = new VexRVROp("KANDQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x41, VEXOpAssertion.AVX512BW_MASK); - public static final VexRVROp KANDD = new VexRVROp("KANDD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x41, VEXOpAssertion.AVX512BW_MASK); - - public static final VexRVROp KANDNW = new VexRVROp("KANDNW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x42, VEXOpAssertion.AVX512F_MASK); - public static final VexRVROp KANDNB = new VexRVROp("KANDNB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x42, VEXOpAssertion.AVX512DQ_MASK); - public static final VexRVROp KANDNQ = new VexRVROp("KANDNQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x42, VEXOpAssertion.AVX512BW_MASK); - public static final VexRVROp KANDND = new VexRVROp("KANDND", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x42, VEXOpAssertion.AVX512BW_MASK); - - public static final VexRVROp KORW = new VexRVROp("KORW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x45, VEXOpAssertion.AVX512F_MASK); - public static final VexRVROp KORB = new VexRVROp("KORB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x45, VEXOpAssertion.AVX512DQ_MASK); - public static final VexRVROp KORQ = new VexRVROp("KORQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x45, VEXOpAssertion.AVX512BW_MASK); - public static final VexRVROp KORD = new VexRVROp("KORD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x45, VEXOpAssertion.AVX512BW_MASK); - - public static final VexRVROp KXORW = new VexRVROp("KXORW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x47, VEXOpAssertion.AVX512F_MASK); - public static final VexRVROp KXORB = new VexRVROp("KXORB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x47, VEXOpAssertion.AVX512DQ_MASK); - public static final VexRVROp KXORQ = new VexRVROp("KXORQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x47, VEXOpAssertion.AVX512BW_MASK); - public static final VexRVROp KXORD = new VexRVROp("KXORD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x47, VEXOpAssertion.AVX512BW_MASK); - - public static final VexRVROp KXNORW = new VexRVROp("KXNORW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x46, VEXOpAssertion.AVX512F_MASK); - public static final VexRVROp KXNORB = new VexRVROp("KXNORB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x46, VEXOpAssertion.AVX512DQ_MASK); - public static final VexRVROp KXNORQ = new VexRVROp("KXNORQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x46, VEXOpAssertion.AVX512BW_MASK); - public static final VexRVROp KXNORD = new VexRVROp("KXNORD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x46, VEXOpAssertion.AVX512BW_MASK); + public static final VexRVROp KANDW = new VexRVROp("KANDW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x41, VEXOpAssertion.AVX512F_MASK_L1); + public static final VexRVROp KANDB = new VexRVROp("KANDB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x41, VEXOpAssertion.AVX512DQ_MASK_L1); + public static final VexRVROp KANDQ = new VexRVROp("KANDQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x41, VEXOpAssertion.AVX512BW_MASK_L1); + public static final VexRVROp KANDD = new VexRVROp("KANDD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x41, VEXOpAssertion.AVX512BW_MASK_L1); + + public static final VexRVROp KANDNW = new VexRVROp("KANDNW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x42, VEXOpAssertion.AVX512F_MASK_L1); + public static final VexRVROp KANDNB = new VexRVROp("KANDNB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x42, VEXOpAssertion.AVX512DQ_MASK_L1); + public static final VexRVROp KANDNQ = new VexRVROp("KANDNQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x42, VEXOpAssertion.AVX512BW_MASK_L1); + public static final VexRVROp KANDND = new VexRVROp("KANDND", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x42, VEXOpAssertion.AVX512BW_MASK_L1); + + public static final VexRVROp KORW = new VexRVROp("KORW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x45, VEXOpAssertion.AVX512F_MASK_L1); + public static final VexRVROp KORB = new VexRVROp("KORB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x45, VEXOpAssertion.AVX512DQ_MASK_L1); + public static final VexRVROp KORQ = new VexRVROp("KORQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x45, VEXOpAssertion.AVX512BW_MASK_L1); + public static final VexRVROp KORD = new VexRVROp("KORD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x45, VEXOpAssertion.AVX512BW_MASK_L1); + + public static final VexRVROp KXORW = new VexRVROp("KXORW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x47, VEXOpAssertion.AVX512F_MASK_L1); + public static final VexRVROp KXORB = new VexRVROp("KXORB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x47, VEXOpAssertion.AVX512DQ_MASK_L1); + public static final VexRVROp KXORQ = new VexRVROp("KXORQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x47, VEXOpAssertion.AVX512BW_MASK_L1); + public static final VexRVROp KXORD = new VexRVROp("KXORD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x47, VEXOpAssertion.AVX512BW_MASK_L1); + + public static final VexRVROp KXNORW = new VexRVROp("KXNORW", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x46, VEXOpAssertion.AVX512F_MASK_L1); + public static final VexRVROp KXNORB = new VexRVROp("KXNORB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x46, VEXOpAssertion.AVX512DQ_MASK_L1); + public static final VexRVROp KXNORQ = new VexRVROp("KXNORQ", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x46, VEXOpAssertion.AVX512BW_MASK_L1); + public static final VexRVROp KXNORD = new VexRVROp("KXNORD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x46, VEXOpAssertion.AVX512BW_MASK_L1); // @formatter:on protected VexRVROp(String opcode, int pp, int mmmmm, int w, int op, VEXOpAssertion assertion) { @@ -2029,10 +1999,9 @@ public VexRVROp encoding(AMD64SIMDInstructionEncoding encoding) { return (VexRVROp) encodingLogic(encoding); } - public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, Register src2) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, src1, src2), "emitting invalid instruction"); + public void emit(AMD64Assembler asm, Register dst, Register src1, Register src2) { // format VEX.L1 ... kdest, ksrc1, ksrc2 - asm.emitVEX(1, pp, mmmmm, w, 0, src1.encoding(), false); + emitVexOrEvex(asm, dst, src1, src2, AVXSize.YMM, pp, mmmmm, w, wEvex); asm.emitByte(op); asm.emitModRM(dst, src2); } @@ -2053,28 +2022,28 @@ public static class VexRVMOp extends VexOp { public static final VexRVMOp VXORPD = new VexRVMOp("VXORPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x57, VEXOpAssertion.AVX1_AVX512DQ_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); public static final VexRVMOp VADDPS = new VexRVMOp("VADDPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x58, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VADDPD = new VexRVMOp("VADDPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x58, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); - public static final VexRVMOp VADDSS = new VexRVMOp("VADDSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x58, VEXOpAssertion.AVX1_AVX512F_128_ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRVMOp VADDSD = new VexRVMOp("VADDSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x58,VEXOpAssertion.AVX1_AVX512F_128_ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMOp VADDSS = new VexRVMOp("VADDSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x58, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMOp VADDSD = new VexRVMOp("VADDSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x58, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); public static final VexRVMOp VMULPS = new VexRVMOp("VMULPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x59, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VMULPD = new VexRVMOp("VMULPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x59, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); - public static final VexRVMOp VMULSS = new VexRVMOp("VMULSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x59, VEXOpAssertion.AVX1_AVX512F_128_ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRVMOp VMULSD = new VexRVMOp("VMULSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x59, VEXOpAssertion.AVX1_AVX512F_128_ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMOp VMULSS = new VexRVMOp("VMULSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x59, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMOp VMULSD = new VexRVMOp("VMULSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x59, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); public static final VexRVMOp VSUBPS = new VexRVMOp("VSUBPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5C, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VSUBPD = new VexRVMOp("VSUBPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5C, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); - public static final VexRVMOp VSUBSS = new VexRVMOp("VSUBSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5C, VEXOpAssertion.AVX1_AVX512F_128_ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRVMOp VSUBSD = new VexRVMOp("VSUBSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5C, VEXOpAssertion.AVX1_AVX512F_128_ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMOp VSUBSS = new VexRVMOp("VSUBSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5C, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMOp VSUBSD = new VexRVMOp("VSUBSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5C, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); public static final VexRVMOp VMINPS = new VexRVMOp("VMINPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5D, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VMINPD = new VexRVMOp("VMINPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5D, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); - public static final VexRVMOp VMINSS = new VexRVMOp("VMINSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5D, VEXOpAssertion.AVX1_128ONLY_AVX512F_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRVMOp VMINSD = new VexRVMOp("VMINSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5D, VEXOpAssertion.AVX1_128ONLY_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMOp VMINSS = new VexRVMOp("VMINSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5D, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMOp VMINSD = new VexRVMOp("VMINSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5D, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); public static final VexRVMOp VDIVPS = new VexRVMOp("VDIVPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5E, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VDIVPD = new VexRVMOp("VDIVPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5E, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); - public static final VexRVMOp VDIVSS = new VexRVMOp("VDIVSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5E, VEXOpAssertion.AVX1_AVX512F_128_ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRVMOp VDIVSD = new VexRVMOp("VDIVSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5E, VEXOpAssertion.AVX1_AVX512F_128_ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMOp VDIVSS = new VexRVMOp("VDIVSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5E, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMOp VDIVSD = new VexRVMOp("VDIVSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5E, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); public static final VexRVMOp VMAXPS = new VexRVMOp("VMAXPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5F, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VMAXPD = new VexRVMOp("VMAXPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5F, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); - public static final VexRVMOp VMAXSS = new VexRVMOp("VMAXSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5F, VEXOpAssertion.AVX1_128ONLY_AVX512F_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRVMOp VMAXSD = new VexRVMOp("VMAXSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5F, VEXOpAssertion.AVX1_128ONLY_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMOp VMAXSS = new VexRVMOp("VMAXSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5F, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMOp VMAXSD = new VexRVMOp("VMAXSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5F, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); public static final VexRVMOp VPACKUSDW = new VexRVMOp("VPACKUSDW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x2B, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VPACKUSWB = new VexRVMOp("VPACKUSWB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x67, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); public static final VexRVMOp VPACKSSWB = new VexRVMOp("VPACKSSWB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x63, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); @@ -2089,16 +2058,16 @@ public static class VexRVMOp extends VexOp { public static final VexRVMOp VPADDD = new VexRVMOp("VPADDD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xFE, VEXOpAssertion.AVX1_AVX2_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VPADDQ = new VexRVMOp("VPADDQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xD4, VEXOpAssertion.AVX1_AVX2_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); public static final VexRVMOp VPMAXSB = new VexRVMOp("VPMAXSB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x3C, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); - public static final VexRVMOp VPMAXSW = new VexRVMOp("VPMAXSW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xEE, VEXOpAssertion.AVX1_AVX2_AVX512F_BW, EVEXTuple.FVM, VEXPrefixConfig.WIG); + public static final VexRVMOp VPMAXSW = new VexRVMOp("VPMAXSW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xEE, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); public static final VexRVMOp VPMAXSD = new VexRVMOp("VPMAXSD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x3D, VEXOpAssertion.AVX1_AVX2_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VPMAXUB = new VexRVMOp("VPMAXUB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0xDE, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); - public static final VexRVMOp VPMAXUW = new VexRVMOp("VPMAXUW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x3E, VEXOpAssertion.AVX1_AVX2_AVX512F_BW, EVEXTuple.FVM, VEXPrefixConfig.WIG); + public static final VexRVMOp VPMAXUW = new VexRVMOp("VPMAXUW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x3E, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); public static final VexRVMOp VPMAXUD = new VexRVMOp("VPMAXUD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x3F, VEXOpAssertion.AVX1_AVX2_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VPMINSB = new VexRVMOp("VPMINSB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x38, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); - public static final VexRVMOp VPMINSW = new VexRVMOp("VPMINSW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xEA, VEXOpAssertion.AVX1_AVX2_AVX512F_BW, EVEXTuple.FVM, VEXPrefixConfig.WIG); + public static final VexRVMOp VPMINSW = new VexRVMOp("VPMINSW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xEA, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); public static final VexRVMOp VPMINSD = new VexRVMOp("VPMINSD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x39, VEXOpAssertion.AVX1_AVX2_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VPMINUB = new VexRVMOp("VPMINUB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0xDA, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); - public static final VexRVMOp VPMINUW = new VexRVMOp("VPMINUW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x3A, VEXOpAssertion.AVX1_AVX2_AVX512F_BW, EVEXTuple.FVM, VEXPrefixConfig.W0); + public static final VexRVMOp VPMINUW = new VexRVMOp("VPMINUW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x3A, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VPMINUD = new VexRVMOp("VPMINUD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x3B, VEXOpAssertion.AVX1_AVX2_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VPMULHUW = new VexRVMOp("VPMULHUW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xE4, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); public static final VexRVMOp VPMULHW = new VexRVMOp("VPMULHW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xE5, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); @@ -2128,16 +2097,15 @@ public static class VexRVMOp extends VexOp { public static final VexRVMOp VFMADD231SD = new VexRVMOp("VFMADD231SD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W1, 0xB9, VEXOpAssertion.FMA_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); public static final VexRVMOp VFMADD231PS = new VexRVMOp("VFMADD231PS", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0xB8, VEXOpAssertion.FMA, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VFMADD231PD = new VexRVMOp("VFMADD231PD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W1, 0xB8, VEXOpAssertion.FMA, EVEXTuple.FVM, VEXPrefixConfig.W1); - public static final VexRVMOp VSQRTSD = new VexRVMOp("VSQRTSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x51, VEXOpAssertion.AVX1_AVX512F_ALL, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); - public static final VexRVMOp VSQRTSS = new VexRVMOp("VSQRTSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x51, VEXOpAssertion.AVX1_AVX512F_ALL, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMOp VSQRTSD = new VexRVMOp("VSQRTSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x51, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMOp VSQRTSS = new VexRVMOp("VSQRTSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x51, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); public static final VexRVMOp VPERMD = new VexRVMOp("VPERMD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x36, VEXOpAssertion.AVX2_AVX512F_VL_256_512, EVEXTuple.FVM, VEXPrefixConfig.W0); - - public static final VexRVMOp VMOVSS = new VexRVMOp("VMOVSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x10, VEXOpAssertion.AVX1_128ONLY_AVX512F_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRVMOp VMOVSD = new VexRVMOp("VMOVSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x10, VEXOpAssertion.AVX1_128ONLY_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); - public static final VexRVMOp VMOVHPD = new VexRVMOp("VMOVHPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x16, VEXOpAssertion.AVX1_128ONLY_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); - public static final VexRVMOp VMOVLPD = new VexRVMOp("VMOVLPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x12, VEXOpAssertion.AVX1_128ONLY_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); - public static final VexRVMOp VMOVLHPS = new VexRVMOp("MOVLHPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x16, VEXOpAssertion.XMM_XMM_XMM_AVX512F_128ONLY, EVEXTuple.FVM, VEXPrefixConfig.W0); + public static final VexRVMOp VMOVSS = new VexRVMOp("VMOVSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x10, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMOp VMOVSD = new VexRVMOp("VMOVSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x10, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMOp VMOVHPD = new VexRVMOp("VMOVHPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x16, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMOp VMOVLPD = new VexRVMOp("VMOVLPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x12, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMOp VMOVLHPS = new VexRVMOp("VMOVLHPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x16, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMOp VPHADDW = new VexRVMOp("VPHADDW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x01, VEXOpAssertion.AVX1_2); public static final VexRVMOp VPHADDD = new VexRVMOp("VPHADDD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.WIG, 0x02, VEXOpAssertion.AVX1_2); @@ -2245,7 +2213,7 @@ public static class VexRVMOp extends VexOp { public static final VexRVMOp EVPBLENDMQ = new VexRVMOp("EVPBLENDMQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W1, 0x64, VEXOpAssertion.AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1, true); public static final VexRVMOp EVBLENDMPS = new VexRVMOp("EVBLENDMPS", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x65, VEXOpAssertion.AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0, true); public static final VexRVMOp EVBLENDMPD = new VexRVMOp("EVBLENDMPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W1, 0x65, VEXOpAssertion.AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1, true); - public static final VexRVMOp EVPERMT2B = new VexRVMOp("EVPERMT2B", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x7D, VEXOpAssertion.AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0, true); + public static final VexRVMOp EVPERMT2B = new VexRVMOp("EVPERMT2B", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x7D, VEXOpAssertion.AVX512_VBMI_VL, EVEXTuple.FVM, VEXPrefixConfig.W0, true); public static final VexRVMOp EVMOVSS = new VexRVMOp("EVMOVSS", VMOVSS); public static final VexRVMOp EVMOVSD = new VexRVMOp("EVMOVSD", VMOVSD); @@ -2282,43 +2250,29 @@ public VexRVMOp encoding(AMD64SIMDInstructionEncoding encoding) { } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, Register src2) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, src1, src2), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex, false); - asm.emitByte(op); - asm.emitModRM(dst, src2); + emit(asm, size, dst, src1, src2, Register.None, Z0, B0); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, AMD64Address src2) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, src1, null), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex, false); - asm.emitByte(op); - asm.emitOperandHelper(dst, src2, 0, getDisp8Scale(isEvex, size)); + emit(asm, size, dst, src1, src2, Register.None, Z0, B0); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, Register src2, Register mask) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, src1, src2), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, src1, src2, mask, size, pp, mmmmm, w, wEvex, false, EVEXPrefixConfig.Z0, EVEXPrefixConfig.B0); - asm.emitByte(op); - asm.emitModRM(dst, src2); + emit(asm, size, dst, src1, src2, mask, Z0, B0); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, AMD64Address src2, Register mask) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, src1, null), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, src1, src2, mask, size, pp, mmmmm, w, wEvex, false, EVEXPrefixConfig.Z0, EVEXPrefixConfig.B0); - asm.emitByte(op); - asm.emitOperandHelper(dst, src2, 0, getDisp8Scale(isEvex, size)); + emit(asm, size, dst, src1, src2, mask, Z0, B0); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, Register src2, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, src1, src2), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, src1, src2, mask, size, pp, mmmmm, w, wEvex, false, z, b); + emitVexOrEvex(asm, dst, src1, src2, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); asm.emitModRM(dst, src2); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, AMD64Address src2, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, src1, null), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, src1, src2, mask, size, pp, mmmmm, w, wEvex, false, z, b); + emitVexOrEvex(asm, dst, src1, src2, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); asm.emitOperandHelper(dst, src2, 0, getDisp8Scale(isEvex, size)); } @@ -2330,12 +2284,12 @@ public boolean isPacked() { public static final class VexRVMConvertOp extends VexRVMOp { // @formatter:off - public static final VexRVMConvertOp VCVTSD2SS = new VexRVMConvertOp("VCVTSD2SS", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5A, VEXOpAssertion.XMM_XMM_XMM_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); - public static final VexRVMConvertOp VCVTSS2SD = new VexRVMConvertOp("VCVTSS2SD", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5A, VEXOpAssertion.XMM_XMM_XMM_AVX512F_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRVMConvertOp VCVTSI2SD = new VexRVMConvertOp("VCVTSI2SD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x2A, VEXOpAssertion.XMM_XMM_CPU_AVX512F_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRVMConvertOp VCVTSQ2SD = new VexRVMConvertOp("VCVTSQ2SD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x2A, VEXOpAssertion.XMM_XMM_CPU_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); - public static final VexRVMConvertOp VCVTSI2SS = new VexRVMConvertOp("VCVTSI2SS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x2A, VEXOpAssertion.XMM_XMM_CPU_AVX512F_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRVMConvertOp VCVTSQ2SS = new VexRVMConvertOp("VCVTSQ2SS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x2A, VEXOpAssertion.XMM_XMM_CPU_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMConvertOp VCVTSD2SS = new VexRVMConvertOp("VCVTSD2SS", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5A, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMConvertOp VCVTSS2SD = new VexRVMConvertOp("VCVTSS2SD", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0x5A, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMConvertOp VCVTSI2SD = new VexRVMConvertOp("VCVTSI2SD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x2A, VEXOpAssertion.XMM_XMM_CPU_AVX1_AVX512F_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMConvertOp VCVTSQ2SD = new VexRVMConvertOp("VCVTSQ2SD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x2A, VEXOpAssertion.XMM_XMM_CPU_AVX1_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMConvertOp VCVTSI2SS = new VexRVMConvertOp("VCVTSI2SS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0x2A, VEXOpAssertion.XMM_XMM_CPU_AVX1_AVX512F_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMConvertOp VCVTSQ2SS = new VexRVMConvertOp("VCVTSQ2SS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0x2A, VEXOpAssertion.XMM_XMM_CPU_AVX1_AVX512F_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); // EVEX encoded instruction public static final VexRVMConvertOp EVCVTSD2SS = new VexRVMConvertOp("EVCVTSD2SS", VCVTSD2SS); @@ -2385,36 +2339,26 @@ public VexGeneralPurposeRVMOp encoding(AMD64SIMDInstructionEncoding encoding) { @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, Register src2) { - GraalError.guarantee(assertion.check(asm.getFeatures(), VEXPrefixConfig.LZ, dst, src1, src2, null), "emitting invalid instruction"); - assert size == AVXKind.AVXSize.DWORD || size == AVXKind.AVXSize.QWORD : size; - emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, false); - asm.emitByte(op); - asm.emitModRM(dst, src2); + emit(asm, size, dst, src1, src2, Register.None, Z0, B0); } @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, Register src2, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), VEXPrefixConfig.LZ, dst, src1, src2, null), "emitting invalid instruction"); assert size == AVXKind.AVXSize.DWORD || size == AVXKind.AVXSize.QWORD : size; - emitVexOrEvex(asm, dst, src1, src2, mask, size, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, false, z, b); + emitVexOrEvex(asm, dst, src1, src2, mask, AVXSize.XMM, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, z, b); asm.emitByte(op); asm.emitModRM(dst, src2); } @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, AMD64Address src2) { - GraalError.guarantee(assertion.check(asm.getFeatures(), VEXPrefixConfig.LZ, dst, src1, null, null), "emitting invalid instruction"); - assert size == AVXKind.AVXSize.DWORD || size == AVXKind.AVXSize.QWORD : size; - emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, false); - asm.emitByte(op); - asm.emitOperandHelper(dst, src2, 0); + emit(asm, size, dst, src1, src2, Register.None, Z0, B0); } @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, AMD64Address src2, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), VEXPrefixConfig.LZ, dst, src1, null, null), "emitting invalid instruction"); assert size == AVXKind.AVXSize.DWORD || size == AVXKind.AVXSize.QWORD : size; - emitVexOrEvex(asm, dst, src1, src2, mask, size, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, false, z, b); + emitVexOrEvex(asm, dst, src1, src2, mask, AVXSize.XMM, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, z, b); asm.emitByte(op); asm.emitOperandHelper(dst, src2, 0); } @@ -2439,17 +2383,15 @@ public VexGeneralPurposeRMVOp encoding(AMD64SIMDInstructionEncoding encoding) { } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, Register src2) { - GraalError.guarantee(assertion.check(asm.getFeatures(), VEXPrefixConfig.LZ, dst, src2, src1, null), "emitting invalid instruction"); assert size == AVXKind.AVXSize.DWORD || size == AVXKind.AVXSize.QWORD : size; - emitVexOrEvex(asm, dst, src2, src1, size, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, false); + emitVexOrEvex(asm, dst, src2, src1, AVXSize.XMM, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex); asm.emitByte(op); asm.emitModRM(dst, src1); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Address src1, Register src2) { - GraalError.guarantee(assertion.check(asm.getFeatures(), VEXPrefixConfig.LZ, dst, src2, null, null), "emitting invalid instruction"); assert size == AVXKind.AVXSize.DWORD || size == AVXKind.AVXSize.QWORD : size; - emitVexOrEvex(asm, dst, src2, src1, size, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, false); + emitVexOrEvex(asm, dst, src2, src1, AVXSize.XMM, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex); asm.emitByte(op); asm.emitOperandHelper(dst, src1, 0); } @@ -2457,10 +2399,10 @@ public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Ad public static final class VexAESOp extends VexRVMOp { // @formatter:off - public static final VexAESOp VAESENC = new VexAESOp("VAESENC", 0xDC, VEXOpAssertion.AVX1_128ONLY_AES); - public static final VexAESOp VAESENCLAST = new VexAESOp("VAESENCLAST", 0xDD, VEXOpAssertion.AVX1_128ONLY_AES); - public static final VexAESOp VAESDEC = new VexAESOp("VAESDEC", 0xDE, VEXOpAssertion.AVX1_128ONLY_AES); - public static final VexAESOp VAESDECLAST = new VexAESOp("VAESDECLAST", 0xDF, VEXOpAssertion.AVX1_128ONLY_AES); + public static final VexAESOp VAESENC = new VexAESOp("VAESENC", 0xDC, VEXOpAssertion.AES_AVX1_128ONLY); + public static final VexAESOp VAESENCLAST = new VexAESOp("VAESENCLAST", 0xDD, VEXOpAssertion.AES_AVX1_128ONLY); + public static final VexAESOp VAESDEC = new VexAESOp("VAESDEC", 0xDE, VEXOpAssertion.AES_AVX1_128ONLY); + public static final VexAESOp VAESDECLAST = new VexAESOp("VAESDECLAST", 0xDF, VEXOpAssertion.AES_AVX1_128ONLY); // @formatter:on private VexAESOp(String opcode, int op, VEXOpAssertion assertion) { @@ -2507,9 +2449,7 @@ public VexGatherOp encoding(AMD64SIMDInstructionEncoding encoding) { } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Address address, Register mask) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, mask, null, null), "emitting invalid instruction"); - assert size == AVXKind.AVXSize.XMM || size == AVXKind.AVXSize.YMM : size; - emitVexOrEvex(asm, dst, mask, address, size, pp, mmmmm, w, wEvex, true); + emitVexOrEvex(asm, dst, mask, address, size, pp, mmmmm, w, wEvex); asm.emitByte(op); asm.emitOperandHelper(dst, address, 0); } @@ -2544,9 +2484,7 @@ public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Ad } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Address address, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, null, null), "emitting invalid instruction"); - assert size == AVXSize.XMM || size == AVXSize.YMM || size == AVXSize.ZMM : size; - emitVexOrEvex(asm, dst, Register.None, address, mask, size, pp, mmmmm, w, wEvex, true, z, b); + emitVexOrEvex(asm, dst, Register.None, address, mask, size, pp, mmmmm, w, wEvex, z, b); asm.emitByte(op); asm.emitOperandHelper(dst, address, 0); } @@ -2572,32 +2510,24 @@ public VexGeneralPurposeRMOp encoding(AMD64SIMDInstructionEncoding encoding) { @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, null), "emitting invalid instruction"); - emitVexOrEvex(asm, AMD64.cpuRegisters[ext], dst, src, size, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, false); - asm.emitByte(op); - asm.emitModRM(ext, src); + emit(asm, size, dst, src, Register.None, Z0, B0); } @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, null), "emitting invalid instruction"); - emitVexOrEvex(asm, AMD64.cpuRegisters[ext], dst, src, mask, size, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, false, z, b); + emitVexOrEvex(asm, null, dst, src, mask, AVXSize.XMM, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, z, b); asm.emitByte(op); asm.emitModRM(ext, src); } @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Address src) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, null), "emitting invalid instruction"); - emitVexOrEvex(asm, AMD64.cpuRegisters[ext], dst, src, size, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, false); - asm.emitByte(op); - asm.emitOperandHelper(ext, src, 0); + emit(asm, size, dst, src, Register.None, Z0, B0); } @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Address src, Register mask, int z, int b) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, null), "emitting invalid instruction"); - emitVexOrEvex(asm, AMD64.cpuRegisters[ext], dst, src, mask, size, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, false, z, b); + emitVexOrEvex(asm, null, dst, src, mask, AVXSize.XMM, pp, mmmmm, size == AVXKind.AVXSize.DWORD ? VEXPrefixConfig.W0 : VEXPrefixConfig.W1, wEvex, z, b); asm.emitByte(op); asm.emitOperandHelper(ext, src, 0); } @@ -2663,8 +2593,7 @@ public VexShiftOp encoding(AMD64SIMDInstructionEncoding encoding) { @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src, int imm8) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, null, dst, src), "emitting invalid instruction"); - emitVexOrEvex(asm, null, dst, src, size, pp, mmmmm, w, wEvex, false); + emitVexOrEvex(asm, null, dst, src, size, pp, mmmmm, w, wEvex); asm.emitByte(immOp); asm.emitModRM(r, src); asm.emitByte(imm8); @@ -2706,8 +2635,7 @@ public VexShiftImmOp encoding(AMD64SIMDInstructionEncoding encoding) { @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src, int imm8) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, null, dst, src), "emitting invalid instruction"); - emitVexOrEvex(asm, null, dst, src, size, pp, mmmmm, w, wEvex, false); + emitVexOrEvex(asm, null, dst, src, size, pp, mmmmm, w, wEvex); asm.emitByte(op); asm.emitModRM(r, src); asm.emitByte(imm8); @@ -2719,18 +2647,14 @@ public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Registe */ public static final class VexMaskedMoveOp extends VexOp { // @formatter:off - public static final VexMaskedMoveOp VMASKMOVPS = new VexMaskedMoveOp("VMASKMOVPS", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x2C, 0x2E); - public static final VexMaskedMoveOp VMASKMOVPD = new VexMaskedMoveOp("VMASKMOVPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x2D, 0x2F); + public static final VexMaskedMoveOp VMASKMOVPS = new VexMaskedMoveOp("VMASKMOVPS", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x2C, 0x2E, VEXOpAssertion.AVX1); + public static final VexMaskedMoveOp VMASKMOVPD = new VexMaskedMoveOp("VMASKMOVPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x2D, 0x2F, VEXOpAssertion.AVX1); public static final VexMaskedMoveOp VPMASKMOVD = new VexMaskedMoveOp("VPMASKMOVD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W0, 0x8C, 0x8E, VEXOpAssertion.AVX2); public static final VexMaskedMoveOp VPMASKMOVQ = new VexMaskedMoveOp("VPMASKMOVQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F38, VEXPrefixConfig.W1, 0x8C, 0x8E, VEXOpAssertion.AVX2); // @formatter:on private final int opReverse; - private VexMaskedMoveOp(String opcode, int pp, int mmmmm, int w, int op, int opReverse) { - this(opcode, pp, mmmmm, w, op, opReverse, VEXOpAssertion.AVX1); - } - private VexMaskedMoveOp(String opcode, int pp, int mmmmm, int w, int op, int opReverse, VEXOpAssertion assertion) { super(opcode, pp, mmmmm, w, op, assertion); this.opReverse = opReverse; @@ -2742,15 +2666,13 @@ public VexMaskedMoveOp encoding(AMD64SIMDInstructionEncoding encoding) { } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register mask, AMD64Address src) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, mask, null), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, mask, src, size, pp, mmmmm, w, wEvex, false); + emitVexOrEvex(asm, dst, mask, src, size, pp, mmmmm, w, wEvex); asm.emitByte(op); asm.emitOperandHelper(dst, src, 0); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, AMD64Address dst, Register mask, Register src) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, src, mask, null), "emitting invalid instruction"); - emitVexOrEvex(asm, src, mask, dst, size, pp, mmmmm, w, wEvex, false); + emitVexOrEvex(asm, src, mask, dst, size, pp, mmmmm, w, wEvex); asm.emitByte(opReverse); asm.emitOperandHelper(src, dst, 0, getDisp8Scale(isEvex, size)); } @@ -2797,30 +2719,27 @@ public VexMoveMaskOp encoding(AMD64SIMDInstructionEncoding encoding) { @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, src), "emitting invalid instruction"); GraalError.guarantee(!(inRC(CPU, dst) && inRC(CPU, src)), "source and destination can't both be CPU registers"); int actualOp = op(dst, src); int actualPP = pp(dst, src); int actualW = w(dst, src); - emitVexOrEvex(asm, dst, Register.None, src, size, actualPP, mmmmm, actualW, wEvex, false); + emitVexOrEvex(asm, dst, Register.None, src, size, actualPP, mmmmm, actualW, wEvex); asm.emitByte(actualOp); asm.emitModRM(dst, src); } @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, AMD64Address dst, Register src) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, src, null, null), "emitting invalid instruction"); GraalError.guarantee(inRC(MASK, src), "source must be a mask register"); - emitVexOrEvex(asm, src, Register.None, dst, size, pp, mmmmm, w, wEvex, false); + emitVexOrEvex(asm, src, Register.None, dst, size, pp, mmmmm, w, wEvex); asm.emitByte(OP_MEM_FROM_K); asm.emitOperandHelper(src, dst, 0); } @Override public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, AMD64Address src) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, null, null), "emitting invalid instruction"); GraalError.guarantee(inRC(MASK, dst), "destination must be a mask register"); - emitVexOrEvex(asm, dst, Register.None, src, size, pp, mmmmm, w, wEvex, false); + emitVexOrEvex(asm, dst, Register.None, src, size, pp, mmmmm, w, wEvex); asm.emitByte(OP_K_FROM_K_MEM); asm.emitOperandHelper(dst, src, 0); } @@ -2861,31 +2780,31 @@ private int w(Register dst, Register src) { */ public static final class VexRVMIOp extends VexOp { // @formatter:off - public static final VexRVMIOp VPINSRB = new VexRVMIOp("VPINSRB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x20, VEXOpAssertion.XMM_XMM_CPU_AVX512BW_128ONLY, EVEXTuple.T1S_8BIT, VEXPrefixConfig.WIG); - public static final VexRVMIOp VPINSRW = new VexRVMIOp("VPINSRW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0xC4, VEXOpAssertion.XMM_XMM_CPU_AVX512BW_128ONLY, EVEXTuple.T1S_16BIT, VEXPrefixConfig.WIG); - public static final VexRVMIOp VPINSRD = new VexRVMIOp("VPINSRD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x22, VEXOpAssertion.XMM_XMM_CPU_AVX512DQ_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); - public static final VexRVMIOp VPINSRQ = new VexRVMIOp("VPINSRQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W1, 0x22, VEXOpAssertion.XMM_XMM_CPU_AVX512DQ_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); - public static final VexRVMIOp VINSERTPS = new VexRVMIOp("VINSERTPS", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.WIG, 0x21, VEXOpAssertion.AVX1_128ONLY_AVX512F_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMIOp VPINSRB = new VexRVMIOp("VPINSRB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x20, VEXOpAssertion.XMM_XMM_CPU_AVX1_AVX512BW_128ONLY, EVEXTuple.T1S_8BIT, VEXPrefixConfig.WIG); + public static final VexRVMIOp VPINSRW = new VexRVMIOp("VPINSRW", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0xC4, VEXOpAssertion.XMM_XMM_CPU_AVX1_AVX512BW_128ONLY, EVEXTuple.T1S_16BIT, VEXPrefixConfig.WIG); + public static final VexRVMIOp VPINSRD = new VexRVMIOp("VPINSRD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x22, VEXOpAssertion.XMM_XMM_CPU_AVX1_AVX512DQ_128ONLY, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); + public static final VexRVMIOp VPINSRQ = new VexRVMIOp("VPINSRQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W1, 0x22, VEXOpAssertion.XMM_XMM_CPU_AVX1_AVX512DQ_128ONLY, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1); + public static final VexRVMIOp VINSERTPS = new VexRVMIOp("VINSERTPS", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.WIG, 0x21, VEXOpAssertion.AVX1_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0); public static final VexRVMIOp VSHUFPS = new VexRVMIOp("VSHUFPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xC6, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0); public static final VexRVMIOp VSHUFPD = new VexRVMIOp("VSHUFPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xC6, VEXOpAssertion.AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); // AVX/AVX2 insert - public static final VexRVMIOp VINSERTF128 = new VexRVMIOp("VINSERTF128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x18, VEXOpAssertion.AVX1_256ONLY_AVX512F_VL, EVEXTuple.T4_32BIT, VEXPrefixConfig.W0); + public static final VexRVMIOp VINSERTF128 = new VexRVMIOp("VINSERTF128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x18, VEXOpAssertion.AVX1_AVX512F_VL_256_512, EVEXTuple.T4_32BIT, VEXPrefixConfig.W0); public static final VexRVMIOp VINSERTI128 = new VexRVMIOp("VINSERTI128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x38, VEXOpAssertion.AVX2_AVX512F_VL_256_512, EVEXTuple.T4_32BIT, VEXPrefixConfig.W0); // AVX2 128-bit permutation public static final VexRVMIOp VPERM2I128 = new VexRVMIOp("VPERM2I128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x46, VEXOpAssertion.AVX2_256ONLY); public static final VexRVMIOp VPERM2F128 = new VexRVMIOp("VPERM2F128", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x06, VEXOpAssertion.AVX1_256ONLY); // Carry-Less Multiplication Quadword - public static final VexRVMIOp VPCLMULQDQ = new VexRVMIOp("VPCLMULQDQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.WIG, 0x44, VEXOpAssertion.AVX1_128ONLY_CLMUL); + public static final VexRVMIOp VPCLMULQDQ = new VexRVMIOp("VPCLMULQDQ", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.WIG, 0x44, VEXOpAssertion.CLMUL_AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); // Packed Align Right public static final VexRVMIOp VPALIGNR = new VexRVMIOp("VPALIGNR", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.WIG, 0x0F, VEXOpAssertion.AVX1_AVX2_AVX512BW_VL, EVEXTuple.FVM, VEXPrefixConfig.WIG); // Blend Packed Dwords public static final VexRVMIOp VPBLENDD = new VexRVMIOp("VPBLENDD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W0, 0x02, VEXOpAssertion.AVX2); // Galois Field New Instructions - public static final VexRVMIOp VGF2P8AFFINEQB = new VexRVMIOp("VGF2P8AFFINEQB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W1, 0xCE, VEXOpAssertion.AVX1_GFNI_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); + public static final VexRVMIOp VGF2P8AFFINEQB = new VexRVMIOp("VGF2P8AFFINEQB", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F3A, VEXPrefixConfig.W1, 0xCE, VEXOpAssertion.GFNI_AVX1_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1); // EVEX encoded instructions public static final VexRVMIOp EVPINSRB = new VexRVMIOp("EVPINSRB", VPINSRB); @@ -2955,18 +2874,16 @@ public VexRVMIOp encoding(AMD64SIMDInstructionEncoding encoding) { } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, Register src2, int imm8) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, src1, src2), "emitting invalid instruction"); assert (imm8 & 0xFF) == imm8 : imm8; - emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex, false); + emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex); asm.emitByte(op); asm.emitModRM(dst, src2); asm.emitByte(imm8); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, AMD64Address src2, int imm8) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, src1, null), "emitting invalid instruction"); assert (imm8 & 0xFF) == imm8 : imm8; - emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex, false); + emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex); asm.emitByte(op); asm.emitOperandHelper(dst, src2, 1, getDisp8Scale(isEvex, size)); asm.emitByte(imm8); @@ -2979,16 +2896,16 @@ public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Registe */ public static final class VexFloatCompareOp extends VexOp { // @formatter:off - public static final VexFloatCompareOp VCMPPS = new VexFloatCompareOp("VCMPPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xC2); - public static final VexFloatCompareOp VCMPPD = new VexFloatCompareOp("VCMPPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xC2); - public static final VexFloatCompareOp VCMPSS = new VexFloatCompareOp("VCMPSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xC2); - public static final VexFloatCompareOp VCMPSD = new VexFloatCompareOp("VCMPSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xC2); + public static final VexFloatCompareOp VCMPPS = new VexFloatCompareOp("VCMPPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xC2, VEXOpAssertion.AVX1); + public static final VexFloatCompareOp VCMPPD = new VexFloatCompareOp("VCMPPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xC2, VEXOpAssertion.AVX1); + public static final VexFloatCompareOp VCMPSS = new VexFloatCompareOp("VCMPSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xC2, VEXOpAssertion.AVX1_128ONLY); + public static final VexFloatCompareOp VCMPSD = new VexFloatCompareOp("VCMPSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.WIG, 0xC2, VEXOpAssertion.AVX1_128ONLY); // EVEX encoded instructions - public static final VexFloatCompareOp EVCMPPS = new VexFloatCompareOp("EVCMPPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0xC2, VEXOpAssertion.MASK_XMM_XMM_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0, VCMPPS); - public static final VexFloatCompareOp EVCMPPD = new VexFloatCompareOp("EVCMPPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0xC2, VEXOpAssertion.MASK_XMM_XMM_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1, VCMPPD); - public static final VexFloatCompareOp EVCMPSS = new VexFloatCompareOp("EVCMPSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0xC2, VEXOpAssertion.MASK_XMM_XMM_AVX512F_VL, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0, VCMPSS); - public static final VexFloatCompareOp EVCMPSD = new VexFloatCompareOp("EVCMPSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0xC2, VEXOpAssertion.MASK_XMM_XMM_AVX512F_VL, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1, VCMPSD); + public static final VexFloatCompareOp EVCMPPS = new VexFloatCompareOp("EVCMPPS", VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0xC2, VEXOpAssertion.MASK_XMM_XMM_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W0, VCMPPS); + public static final VexFloatCompareOp EVCMPPD = new VexFloatCompareOp("EVCMPPD", VEXPrefixConfig.P_66, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0xC2, VEXOpAssertion.MASK_XMM_XMM_AVX512F_VL, EVEXTuple.FVM, VEXPrefixConfig.W1, VCMPPD); + public static final VexFloatCompareOp EVCMPSS = new VexFloatCompareOp("EVCMPSS", VEXPrefixConfig.P_F3, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0xC2, VEXOpAssertion.MASK_XMM_XMM_AVX512F_128, EVEXTuple.T1S_32BIT, VEXPrefixConfig.W0, VCMPSS); + public static final VexFloatCompareOp EVCMPSD = new VexFloatCompareOp("EVCMPSD", VEXPrefixConfig.P_F2, VEXPrefixConfig.M_0F, VEXPrefixConfig.W1, 0xC2, VEXOpAssertion.MASK_XMM_XMM_AVX512F_128, EVEXTuple.T1S_64BIT, VEXPrefixConfig.W1, VCMPSD); // @formatter:on public enum Predicate { @@ -3070,8 +2987,8 @@ public static Predicate getPredicate(Condition condition, boolean unorderedIsTru } } - private VexFloatCompareOp(String opcode, int pp, int mmmmm, int w, int op) { - super(opcode, pp, mmmmm, w, op, VEXOpAssertion.AVX1); + private VexFloatCompareOp(String opcode, int pp, int mmmmm, int w, int op, VEXOpAssertion assertion) { + super(opcode, pp, mmmmm, w, op, assertion); } /** @@ -3090,16 +3007,14 @@ public VexFloatCompareOp encoding(AMD64SIMDInstructionEncoding encoding) { } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, Register src2, Predicate p) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, src1, src2), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex, false); + emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex); asm.emitByte(op); asm.emitModRM(dst, src2); asm.emitByte(p.imm8); } public void emit(AMD64Assembler asm, AVXKind.AVXSize size, Register dst, Register src1, AMD64Address src2, Predicate p) { - GraalError.guarantee(assertion.check(asm.getFeatures(), size, dst, src1, null), "emitting invalid instruction"); - emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex, false); + emitVexOrEvex(asm, dst, src1, src2, size, pp, mmmmm, w, wEvex); asm.emitByte(op); asm.emitOperandHelper(dst, src2, 1, getDisp8Scale(isEvex, size)); asm.emitByte(p.imm8); @@ -5086,11 +5001,11 @@ public final void rorq(Register dst, int imm8) { } public final void rorxl(Register dst, Register src, int imm8) { - RORXL.emit(this, AVXKind.AVXSize.QWORD, dst, src, (byte) imm8); + RORXL.emit(this, AVXSize.XMM, dst, src, (byte) imm8); } public final void rorxq(Register dst, Register src, int imm8) { - RORXQ.emit(this, AVXKind.AVXSize.QWORD, dst, src, (byte) imm8); + RORXQ.emit(this, AVXSize.XMM, dst, src, (byte) imm8); } public final void rclq(Register dst, int imm8) { @@ -6016,7 +5931,7 @@ public final void vperm2i128(Register dst, Register nds, Register src, int imm8) } public final void vzeroupper() { - emitVEX(VEXPrefixConfig.L128, VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0, 0, true); + emitVEX(VEXPrefixConfig.L128, VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0, 0); emitByte(0x77); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64BaseAssembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64BaseAssembler.java index 6b627ef09231..0592ca6b3569 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64BaseAssembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64BaseAssembler.java @@ -918,7 +918,7 @@ private int opcodeEscapePrefixToMMMMM(int opcodeEscapePrefix) { public void simdPrefix(Register reg, Register nds, AMD64Address rm, int sizePrefix, int opcodeEscapePrefix, boolean isRexW) { assert reg.encoding < 16 : "encoding out of range: " + reg.encoding; assert nds.encoding < 16 : "encoding out of range: " + nds.encoding; - emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(reg, rm), nds.isValid() ? nds.encoding : 0, true); + emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(reg, rm), nds.isValid() ? nds.encoding : 0); } @Override @@ -926,7 +926,7 @@ public void simdPrefix(Register dst, Register nds, Register src, int sizePrefix, assert dst.encoding < 16 : "encoding out of range: " + dst.encoding; assert src.encoding < 16 : "encoding out of range: " + src.encoding; assert nds.encoding < 16 : "encoding out of range: " + nds.encoding; - emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(dst, src), nds.isValid() ? nds.encoding : 0, true); + emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(dst, src), nds.isValid() ? nds.encoding : 0); } } @@ -1010,9 +1010,7 @@ protected final void simdPrefix(Register dst, Register nds, Register src, Operan * This function automatically chooses the 2 or 3 byte encoding, based on the XBW flags and the * m-mmmm field. */ - protected final void emitVEX(int l, int pp, int mmmmm, int w, int rxb, int vvvv, boolean checkAVX) { - assert !checkAVX || getFeatures().contains(CPUFeature.AVX) : "emitting VEX prefix on a CPU without AVX support"; - + protected final void emitVEX(int l, int pp, int mmmmm, int w, int rxb, int vvvv) { assert l == L128 || l == L256 : "invalid value for VEX.L"; assert pp == P_ || pp == P_66 || pp == P_F3 || pp == P_F2 : "invalid value for VEX.pp"; assert mmmmm == M_0F || mmmmm == M_0F38 || mmmmm == M_0F3A : "invalid value for VEX.m-mmmm"; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64MacroAssembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64MacroAssembler.java index d9931c91f682..d327f9c64aca 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64MacroAssembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64MacroAssembler.java @@ -832,7 +832,7 @@ public final void pmovSZxQWORD(ExtendMode extendMode, Register dst, Stride strid if (strideSrc.value < strideDst.value) { GraalError.guarantee(strideDst.log2 - strideSrc.log2 == 1, "unsupported stride pair %s %s", strideSrc, strideDst); if (isAVX()) { - VexMoveOp.VMOVD.emit(this, AVXKind.AVXSize.DWORD, dst, address); + VexMoveOp.VMOVD.emit(this, AVXKind.AVXSize.XMM, dst, address); loadAndExtendAVX(AVXKind.AVXSize.QWORD, extendMode, dst, strideDst, dst, strideSrc); } else { movdl(dst, address); @@ -841,7 +841,7 @@ public final void pmovSZxQWORD(ExtendMode extendMode, Register dst, Stride strid } else { GraalError.guarantee(strideSrc.value == strideDst.value, "source stride must be smaller or equal to target stride"); if (isAVX()) { - VexMoveOp.VMOVQ.emit(this, AVXKind.AVXSize.QWORD, dst, address); + VexMoveOp.VMOVQ.emit(this, AVXKind.AVXSize.XMM, dst, address); } else { movdq(dst, address); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64ArrayIndexOfOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64ArrayIndexOfOp.java index ccdd83a58273..a32c7a72990a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64ArrayIndexOfOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64ArrayIndexOfOp.java @@ -804,10 +804,12 @@ private void emitArrayLoad(AMD64MacroAssembler asm, AVXSize targetVectorSize, Re if (asm.supports(CPUFeature.AVX)) { switch (targetVectorSize) { case DWORD: - VexMoveOp.VMOVD.emit(asm, AVXSize.DWORD, vecDst, src); + // Move a dword into an XMM register + VexMoveOp.VMOVD.emit(asm, AVXSize.XMM, vecDst, src); break; case QWORD: - VexMoveOp.VMOVQ.emit(asm, AVXSize.QWORD, vecDst, src); + // Move a qword into an XMM register + VexMoveOp.VMOVQ.emit(asm, AVXSize.XMM, vecDst, src); break; case XMM: case YMM: diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/vector/AMD64VectorBinary.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/vector/AMD64VectorBinary.java index 0b36b97f404b..b1b75c8e077c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/vector/AMD64VectorBinary.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/vector/AMD64VectorBinary.java @@ -191,8 +191,8 @@ public static final class AVXOpMaskBinaryOp extends AMD64VectorInstruction { @Use({OperandFlag.REG}) protected AllocatableValue x; @Use({OperandFlag.REG}) protected AllocatableValue y; - public AVXOpMaskBinaryOp(AMD64Assembler.VexRVROp opcode, AVXKind.AVXSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { - super(TYPE, size); + public AVXOpMaskBinaryOp(AMD64Assembler.VexRVROp opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) { + super(TYPE, AVXKind.AVXSize.XMM); this.opcode = opcode; this.result = result; this.x = x; @@ -201,7 +201,7 @@ public AVXOpMaskBinaryOp(AMD64Assembler.VexRVROp opcode, AVXKind.AVXSize size, A @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - opcode.emit(masm, size, asRegister(result), asRegister(x), asRegister(y)); + opcode.emit(masm, asRegister(result), asRegister(x), asRegister(y)); } } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/vector/AMD64VectorClearOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/vector/AMD64VectorClearOp.java index ad83a0cc890b..fe6b5a1820aa 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/vector/AMD64VectorClearOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/vector/AMD64VectorClearOp.java @@ -77,7 +77,7 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { Register register = asRegister(result); if (kind.isMask()) { - KXOR_OPS[CodeUtil.log2(kind.getSizeInBytes())].emit(masm, XMM, register, register, register); + KXOR_OPS[CodeUtil.log2(kind.getSizeInBytes())].emit(masm, register, register, register); return; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/vector/AMD64VectorShuffle.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/vector/AMD64VectorShuffle.java index c2bb40191ee5..e5c98aad8132 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/vector/AMD64VectorShuffle.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/vector/AMD64VectorShuffle.java @@ -197,11 +197,11 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { EVPXOR.emit(masm, AVXKind.getRegisterSize(kind), asRegister(result), asRegister(result), asRegister(result)); if (isRegister(source)) { EVPERMT2B.emit(masm, AVXKind.getRegisterSize(kind), asRegister(result), asRegister(selector), asRegister(source), mask != null ? asRegister(mask) : Register.None, - AMD64BaseAssembler.EVEXPrefixConfig.Z1, + mask != null ? AMD64BaseAssembler.EVEXPrefixConfig.Z1 : AMD64BaseAssembler.EVEXPrefixConfig.Z0, AMD64BaseAssembler.EVEXPrefixConfig.B0); } else { EVPERMT2B.emit(masm, AVXKind.getRegisterSize(kind), asRegister(result), asRegister(selector), (AMD64Address) crb.asAddress(source), mask != null ? asRegister(mask) : Register.None, - AMD64BaseAssembler.EVEXPrefixConfig.Z1, + mask != null ? AMD64BaseAssembler.EVEXPrefixConfig.Z1 : AMD64BaseAssembler.EVEXPrefixConfig.Z0, AMD64BaseAssembler.EVEXPrefixConfig.B0); } } From 6d4f221d8d2d5e5ae565cc48cf38a9edea2f7fb4 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Wed, 16 Oct 2024 12:18:57 +0000 Subject: [PATCH 065/105] [GR-57817] Fixed review comments. --- sdk/CHANGELOG.md | 3 +- truffle/CHANGELOG.md | 2 +- truffle/mx.truffle/mx_truffle.py | 26 ++++++++++---- truffle/mx.truffle/suite.py | 2 +- .../com/oracle/truffle/api/impl/Accessor.java | 4 +-- .../src/truffle_attach.c | 2 +- .../truffle/polyglot/InstrumentCache.java | 3 ++ .../oracle/truffle/polyglot/JDKSupport.java | 35 +++++++++++-------- .../truffle/polyglot/LanguageCache.java | 3 ++ .../truffle/runtime/ModulesSupport.java | 6 ++-- .../hotspot/HotSpotThreadLocalHandshake.java | 10 +++--- .../hotspot/HotSpotTruffleRuntime.java | 8 ++--- .../hotspot/HotSpotTruffleRuntimeAccess.java | 19 +++++----- 13 files changed, 75 insertions(+), 48 deletions(-) diff --git a/sdk/CHANGELOG.md b/sdk/CHANGELOG.md index c38d994154ac..abf92ad06850 100644 --- a/sdk/CHANGELOG.md +++ b/sdk/CHANGELOG.md @@ -5,7 +5,8 @@ This changelog summarizes major changes between GraalVM SDK versions. The main f ## Version 24.2.0 * GR-54905 When using Truffle NFI with the Panama backend, native access must now be granted to the Truffle module instead of the NFI Panama module. Use the `--enable-native-access=org.graalvm.truffle` Java command line option to enable the native access for the NFI Panama backend. * GR-57681 Added the ability to use `Value#as(byte[].class)` to copy the contents of a guest language byte buffer (`Value#hasBufferElements()`) to a new byte array. The new functionality has precedence over accessing the guest object as array (`Value#hasArrayElements()`) if both ways are available. -* GR-57817 Starting with JDK 24 users now need to pass `--enable-native-access=org.graalvm.truffle` or `--enable-native-access=ALL-UNNAMED` to grant Truffle the ability to compile to optimized native code. If native access is denied by the JDK using `--illegal-native-access=deny` then loading the optimizing runtime will fail and the fallback runtime will be used. +* GR-57817 Starting with JDK 24 users now need to configure native access privileges to the java executable in order to avoid warnings from being printed by the JDK. +For usages of the module-path pass the `--enable-native-access=org.graalvm.truffle` option and for class-path usages pass the `--enable-native-access=ALL-UNNAMED` option to resolve the new warning. Note that Truffle automatically forwards the native access capability to all loaded languages and tools, therefore no further configuration is required. If the native access is denied by the user with `--illegal-native-access=deny` then loading the optimizing runtime will fail and the fallback runtime will be used. More information can be found in the integrity-by-default [JEP-472](https://openjdk.org/jeps/472). ## Version 24.1.0 * GR-51177 Enable random offsets of runtime compiled function entry points for the UNTRUSTED polyglot sandbox policy. diff --git a/truffle/CHANGELOG.md b/truffle/CHANGELOG.md index 50ef6cfb3c58..d9c28eae4d64 100644 --- a/truffle/CHANGELOG.md +++ b/truffle/CHANGELOG.md @@ -7,7 +7,7 @@ This changelog summarizes major changes between Truffle versions relevant to lan * GR-57164 Added support for reading unaligned ints, shorts and long to `ByteArraySupport`. * GR-57164 `RootNode.translateStackTraceElement()` is now always consulted for polyglot and debugger stack traces. Stack traces now use the source section, the executable name, the name of the declared meta-object to build `StackTraceElement` instances. * GR-57322 Added `TruffleLanguage.Env.getHostLanguage()` returning the host language info. This allows languages to lookup the top scope of the host language using `Env.getScopeInternal(LanguageInfo)`. -* GR-57817 Native access for all languages and tools is now provided by Truffle. +* GR-57817 Java Native access for [JEP-472](https://openjdk.org/jeps/472) is now automatically provided for all languages and tools by Truffle. For more information, refer to the [GraalVM SDK Changelog](https://github.com/oracle/graal/blob/master/sdk/CHANGELOG.md). ## Version 24.1.0 diff --git a/truffle/mx.truffle/mx_truffle.py b/truffle/mx.truffle/mx_truffle.py index 963c73b73515..0fc5ebb1e7b7 100644 --- a/truffle/mx.truffle/mx_truffle.py +++ b/truffle/mx.truffle/mx_truffle.py @@ -195,6 +195,24 @@ def _open_module_exports_args(): args.append('--add-exports=' + truffle_api_module_name + '/' + package + '=' + targets) return args +def enable_truffle_native_access(vmArgs): + """ + Enables native access to Truffle to allow usage of the Optimized Runtime + and delegation of native access to all languages and tools. + + This function checks the provided VM arguments to determine if a module path + is used. If so, it enables the native access to `org.graalvm.truffle` module. + Otherwise, it enables native access to `ALL-UNNAMED`. + + The function appends the appropriate `--enable-native-access` option to the list of + VM arguments and also returns the updated list. + """ + if '-p' in vmArgs or '--module-path' in vmArgs: + native_access_target_module = 'org.graalvm.truffle' + else: + native_access_target_module = 'ALL-UNNAMED' + vmArgs.extend([f'--enable-native-access={native_access_target_module}']) + return vmArgs class TruffleUnittestConfig(mx_unittest.MxUnittestConfig): @@ -227,12 +245,7 @@ def apply(self, config): # Disable VirtualThread warning vmArgs = vmArgs + ['-Dpolyglot.engine.WarnVirtualThreadSupport=false'] - # Enable native access to Truffle, truffle delegates native access to languages - if '-p' in vmArgs or '--module-path' in vmArgs: - native_access_target_module = 'org.graalvm.truffle' - else: - native_access_target_module = 'ALL-UNNAMED' - vmArgs = vmArgs + [f'--enable-native-access={native_access_target_module}'] + enable_truffle_native_access(vmArgs) return (vmArgs, mainClass, mainClassArgs) @@ -411,6 +424,7 @@ def _native_image_sl(jdk, vm_args, target_dir, use_optimized_runtime=True, use_e # Even when Truffle is on the classpath, it is loaded as a named module due to # the ForceOnModulePath option in its native-image.properties + # GR-58290: Fixed when ForceOnModulePath is removed native_image_args += ["--enable-native-access=org.graalvm.truffle"] native_image_args += mx.get_runtime_jvm_args(names=dist_names, force_cp=force_cp) diff --git a/truffle/mx.truffle/suite.py b/truffle/mx.truffle/suite.py index 0987dc9cc7f1..a595a0293f0c 100644 --- a/truffle/mx.truffle/suite.py +++ b/truffle/mx.truffle/suite.py @@ -1789,7 +1789,7 @@ "layout" : { "META-INF/resources/engine/libtruffleattach///bin/" : "dependency:com.oracle.truffle.attach", }, - "description" : "Contains a library to provide access for the Truffle to JDK internal classes.", + "description" : "Contains a library to provide access for Truffle to JDK internal classes.", "maven": False, "graalCompilerSourceEdition": "ignore", }, diff --git a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java index 5ae2c23d58ea..ab6265d08258 100644 --- a/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java +++ b/truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java @@ -1370,11 +1370,11 @@ public abstract static class ModulesAccessor { public abstract Module getTargetModule(); - public abstract JavaLangAccessor getJavaLangAccessor(); + public abstract JavaLangSupport getJavaLangSupport(); } - public abstract static class JavaLangAccessor { + public abstract static class JavaLangSupport { private static volatile Consumer onMountCallBack; private static volatile Consumer onUnmountCallBack; diff --git a/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c b/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c index ce99d7913c78..c45af028e91e 100644 --- a/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c +++ b/truffle/src/com.oracle.truffle.attach/src/truffle_attach.c @@ -102,7 +102,7 @@ static void JNICALL unmount_callback(jvmtiEnv *jvmti, ...) { } } -JNIEXPORT void JNICALL Java_com_oracle_truffle_api_impl_Accessor_00024JavaLangAccessor_registerJVMTIHook(JNIEnv *env, jclass clz) { +JNIEXPORT void JNICALL Java_com_oracle_truffle_api_impl_Accessor_00024JavaLangSupport_registerJVMTIHook(JNIEnv *env, jclass clz) { virtualThreadHooksClass = (*env)->NewGlobalRef(env, clz); EXCEPTION_CHECK(env); CHECK_NONZERO(virtualThreadHooksClass); diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java index 0891ebfec48f..80b42bb85d79 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/InstrumentCache.java @@ -210,6 +210,9 @@ private static void loadInstrumentImpl(ProviderAdapter providerAdapter, List providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); JDKSupport.exportTransitivelyTo(providerModule); + /* + * Forward the native access capability to all loaded tools. + */ JDKSupport.enableNativeAccess(providerModule); Registration reg = providerClass.getAnnotation(Registration.class); if (reg == null) { diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java index 8528ca0e8264..449d49a39630 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/JDKSupport.java @@ -71,7 +71,7 @@ import com.oracle.truffle.api.InternalResource; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.impl.Accessor; -import com.oracle.truffle.api.impl.Accessor.JavaLangAccessor; +import com.oracle.truffle.api.impl.Accessor.JavaLangSupport; import com.oracle.truffle.api.impl.Accessor.ModulesAccessor; import com.oracle.truffle.api.impl.asm.ClassWriter; import com.oracle.truffle.api.impl.asm.FieldVisitor; @@ -116,15 +116,20 @@ private static ModulesAccessor initializeModuleAccessor() { Path libAttach = truffleAttachRoot.resolve("bin").resolve(System.mapLibraryName("truffleattach")); attachLibPath = libAttach.toString(); } catch (IOException ioe) { - warnTruffleAttachLoadFailure("The Truffle API JAR is missing the 'truffleattach' resource, likely due to issues when repackaged into a fat JAR.", ioe); + performTruffleAttachLoadFailureAction("The Truffle API JAR is missing the 'truffleattach' resource, likely due to issues when Truffle was repackaged into a fat JAR.", ioe); return null; } } try { try { System.load(attachLibPath); - } catch (UnsatisfiedLinkError | IllegalCallerException failedToLoad) { - warnTruffleAttachLoadFailure("Unable to load the TruffleAttach library.", failedToLoad); + } catch (UnsatisfiedLinkError failedToLoad) { + performTruffleAttachLoadFailureAction("Unable to load the TruffleAttach library.", failedToLoad); + return null; + } catch (IllegalCallerException illegalCaller) { + String vmOption = "--enable-native-access=" + (JDKSupport.class.getModule().isNamed() ? "org.graalvm.truffle" : "ALL-UNNAMED"); + performTruffleAttachLoadFailureAction(String.format("Failed to load the TruffleAttach library. The Truffle module does not have native access enabled. " + + "To resolve this, pass the following VM option: %s.", vmOption), illegalCaller); return null; } ModulesAccessor accessor; @@ -144,7 +149,7 @@ private static ModulesAccessor initializeModuleAccessor() { private static native void addExports0(Module m1, String pn, Module m2); - private static void warnTruffleAttachLoadFailure(String reason, Throwable t) { + private static void performTruffleAttachLoadFailureAction(String reason, Throwable t) { String action = System.getProperty("polyglotimpl.AttachLibraryFailureAction", "warn"); switch (action) { case "ignore" -> { @@ -393,16 +398,16 @@ public Module getTargetModule() { } @Override - public JavaLangAccessor getJavaLangAccessor() { - return JavaLangAccessorImpl.INSTANCE; + public JavaLangSupport getJavaLangSupport() { + return JavaLangSupportImpl.INSTANCE; } - private static final class JavaLangAccessorImpl extends JavaLangAccessor { + private static final class JavaLangSupportImpl extends JavaLangSupport { private static final JavaLangAccess JAVA_LANG_ACCESS = SharedSecrets.getJavaLangAccess(); - static final JavaLangAccessor INSTANCE = new JavaLangAccessorImpl(); + static final JavaLangSupport INSTANCE = new JavaLangSupportImpl(); - private JavaLangAccessorImpl() { + private JavaLangSupportImpl() { } @Override @@ -668,11 +673,11 @@ public void addEnableNativeAccessToAllUnnamed() { } @Override - public JavaLangAccessor getJavaLangAccessor() { - return JavaLangAccessorImpl.INSTANCE; + public JavaLangSupport getJavaLangSupport() { + return JavaLangSupportImpl.INSTANCE; } - private static final class JavaLangAccessorImpl extends JavaLangAccessor { + private static final class JavaLangSupportImpl extends JavaLangSupport { /* * For performance reasons, it is necessary for CURRENT_CARRIER_THREAD to be declared as @@ -689,9 +694,9 @@ private static final class JavaLangAccessorImpl extends JavaLangAccessor { } } - private static final JavaLangAccessor INSTANCE = new JavaLangAccessorImpl(); + private static final JavaLangSupport INSTANCE = new JavaLangSupportImpl(); - private JavaLangAccessorImpl() { + private JavaLangSupportImpl() { /* * Ensure the CURRENT_CARRIER_THREAD method handle is initialized by invoking it. * This prevents the interpreter from triggering class initialization during the diff --git a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java index d3ed9792739b..f60c81d57e61 100644 --- a/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java +++ b/truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/LanguageCache.java @@ -323,6 +323,9 @@ private static void loadLanguageImpl(ProviderAdapter providerAdapter, List providerClass = providerAdapter.getProviderClass(); Module providerModule = providerClass.getModule(); JDKSupport.exportTransitivelyTo(providerModule); + /* + * Forward the native access capability to all loaded languages. + */ JDKSupport.enableNativeAccess(providerModule); Registration reg = providerClass.getAnnotation(Registration.class); if (reg == null) { diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java index ad4c98c84261..0e443d5df05c 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/ModulesSupport.java @@ -49,7 +49,7 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleRuntime; import com.oracle.truffle.api.impl.Accessor; -import com.oracle.truffle.api.impl.Accessor.JavaLangAccessor; +import com.oracle.truffle.api.impl.Accessor.JavaLangSupport; import com.oracle.truffle.api.impl.Accessor.ModulesAccessor; public final class ModulesSupport { @@ -156,8 +156,8 @@ public static void exportTruffleRuntimeTo(Class client) { } } - public static JavaLangAccessor getJavaLangAccessor() { - return ACCESSOR.getJavaLangAccessor(); + public static JavaLangSupport getJavaLangSupport() { + return ACCESSOR.getJavaLangSupport(); } /** diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java index e28415f775b6..6aa5f191eac8 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java @@ -42,7 +42,7 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.impl.Accessor.JavaLangAccessor; +import com.oracle.truffle.api.impl.Accessor.JavaLangSupport; import com.oracle.truffle.api.impl.ThreadLocalHandshake; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.runtime.ModulesSupport; @@ -53,7 +53,7 @@ final class HotSpotThreadLocalHandshake extends ThreadLocalHandshake { private static final sun.misc.Unsafe UNSAFE = HotSpotTruffleRuntime.UNSAFE; - private static final JavaLangAccessor JAVA_LANG_ACCESS = ModulesSupport.getJavaLangAccessor(); + private static final JavaLangSupport JAVA_LANG_SUPPORT = ModulesSupport.getJavaLangSupport(); static final HotSpotThreadLocalHandshake SINGLETON = new HotSpotThreadLocalHandshake(); private static final ThreadLocal STATE = new ThreadLocal<>(); @@ -84,7 +84,7 @@ public void ensureThreadInitialized() { // This is only used in interpreter, PE uses HotSpotTruffleSafepointLoweringSnippet.pollSnippet @Override public void poll(Node enclosingNode) { - Thread carrierThread = JAVA_LANG_ACCESS.currentCarrierThread(); + Thread carrierThread = JAVA_LANG_SUPPORT.currentCarrierThread(); long eetop = UNSAFE.getLong(carrierThread, THREAD_EETOP_OFFSET); if (UNSAFE.getInt(null, eetop + PENDING_OFFSET) != 0) { processHandshake(enclosingNode); @@ -108,7 +108,7 @@ public TruffleSafepointImpl getCurrent() { @Override protected void clearFastPending() { - Thread carrierThread = JAVA_LANG_ACCESS.currentCarrierThread(); + Thread carrierThread = JAVA_LANG_SUPPORT.currentCarrierThread(); long eetop = UNSAFE.getLongVolatile(carrierThread, THREAD_EETOP_OFFSET); UNSAFE.putIntVolatile(null, eetop + PENDING_OFFSET, 0); } @@ -151,7 +151,7 @@ protected void setFastPending(Thread thread) { static void setPendingFlagForVirtualThread() { TruffleSafepointImpl safepoint = STATE.get(); if (safepoint != null) { - Thread carrierThread = JAVA_LANG_ACCESS.currentCarrierThread(); + Thread carrierThread = JAVA_LANG_SUPPORT.currentCarrierThread(); long eetop = UNSAFE.getLongVolatile(carrierThread, THREAD_EETOP_OFFSET); /* diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java index a7005e6a6308..c49fab962417 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntime.java @@ -54,7 +54,7 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameInstance; import com.oracle.truffle.api.impl.AbstractFastThreadLocal; -import com.oracle.truffle.api.impl.Accessor.JavaLangAccessor; +import com.oracle.truffle.api.impl.Accessor.JavaLangSupport; import com.oracle.truffle.api.impl.ThreadLocalHandshake; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.compiler.TruffleCompilable; @@ -103,7 +103,7 @@ public final class HotSpotTruffleRuntime extends OptimizedTruffleRuntime { static final int JAVA_SPEC = Runtime.version().feature(); static final sun.misc.Unsafe UNSAFE = getUnsafe(); - private static final JavaLangAccessor JAVA_LANG_ACCESS = ModulesSupport.getJavaLangAccessor(); + private static final JavaLangSupport JAVA_LANG_SUPPORT = ModulesSupport.getJavaLangSupport(); private static final long THREAD_EETOP_OFFSET; static { try { @@ -557,7 +557,7 @@ private void traceTransferToInterpreter() { // compiler not yet initialized it is not possible we see a deopt yet return; } - long threadStruct = UNSAFE.getLong(JAVA_LANG_ACCESS.currentCarrierThread(), THREAD_EETOP_OFFSET); + long threadStruct = UNSAFE.getLong(JAVA_LANG_SUPPORT.currentCarrierThread(), THREAD_EETOP_OFFSET); long pendingTransferToInterpreterAddress = threadStruct + offset; boolean deoptimized = UNSAFE.getByte(pendingTransferToInterpreterAddress) != 0; if (deoptimized) { @@ -661,7 +661,7 @@ protected int getArrayBaseOffset(Class componentType) { public long getStackOverflowLimit() { int stackOverflowLimitOffset = vmConfigAccess.getFieldOffset(JAVA_SPEC >= 16 ? "JavaThread::_stack_overflow_state._stack_overflow_limit" : "JavaThread::_stack_overflow_limit", Integer.class, "address"); - long eetop = UNSAFE.getLong(JAVA_LANG_ACCESS.currentCarrierThread(), THREAD_EETOP_OFFSET); + long eetop = UNSAFE.getLong(JAVA_LANG_SUPPORT.currentCarrierThread(), THREAD_EETOP_OFFSET); return UNSAFE.getLong(eetop + stackOverflowLimitOffset); } diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java index 0b628ec7b064..a1c4d407c984 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotTruffleRuntimeAccess.java @@ -201,26 +201,27 @@ protected static TruffleRuntime createRuntime() { throw new InternalError(e); } } - HotSpotTruffleRuntime rt = new HotSpotTruffleRuntime(compilationSupport); - registerVirtualThreadSupport(); - compilationSupport.registerRuntime(rt); - return rt; - } - - private static void registerVirtualThreadSupport() { /* * Ensure that HotSpotThreadLocalHandshake and HotSpotFastThreadLocal are loaded before the * hooks are called. This prevents class initialization during the virtual thread hooks - * which must not trigger class loading or suspend the VirtualThread. + * These hooks must not trigger class loading or suspend the VirtualThread (per their + * specification). */ HotSpotThreadLocalHandshake.initializePendingOffset(); HotSpotFastThreadLocal.ensureLoaded(); + HotSpotTruffleRuntime rt = new HotSpotTruffleRuntime(compilationSupport); + registerVirtualThreadMountHooks(); + compilationSupport.registerRuntime(rt); + return rt; + } + + private static void registerVirtualThreadMountHooks() { Consumer onMount = (t) -> { HotSpotFastThreadLocal.mount(); HotSpotThreadLocalHandshake.setPendingFlagForVirtualThread(); }; Consumer onUmount = (t) -> HotSpotFastThreadLocal.unmount(); - ModulesSupport.getJavaLangAccessor().registerVirtualThreadMountHooks(onMount, onUmount); + ModulesSupport.getJavaLangSupport().registerVirtualThreadMountHooks(onMount, onUmount); } private static RuntimeException throwVersionError(String errorFormat, Object... args) { From 1c4e16d3baf2dc5dc05be2d922ae503d4a7454e3 Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Wed, 25 Sep 2024 14:59:39 +0200 Subject: [PATCH 066/105] base layer use closed world method implementations for function calls --- .../pointsto/results/StrengthenGraphs.java | 118 +++++++++++------- 1 file changed, 76 insertions(+), 42 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java index 7418ba9c607c..23de463c81bc 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java @@ -131,11 +131,11 @@ /** * This class applies static analysis results directly to the {@link StructuredGraph Graal IR} used * to build the type flow graph. - * + * * It uses a {@link CustomSimplification} for the {@link CanonicalizerPhase}, because that provides * all the framework for iterative stamp propagation and adding/removing control flow nodes while * processing the graph. - * + * * From the single-method view that the compiler has when later compiling the graph, static analysis * results appear "out of thin air": At some random point in the graph, we suddenly have a more * precise type (= stamp) for a value. Since many nodes are floating, and even currently fixed nodes @@ -275,17 +275,17 @@ public final void applyResults(AnalysisMethod method) { * Returns a type that can replace the original type in stamps as an exact type. When the * returned type is the original type itself, the original type has no subtype and can be used * as an exact type. - * + * * Returns null if there is no single implementor type. */ protected abstract AnalysisType getSingleImplementorType(AnalysisType originalType); /* * Returns a type that can replace the original type in stamps. - * + * * Returns null if the original type has no assignable type that is instantiated, i.e., the code * using the type is unreachable. - * + * * Returns the original type itself if there is no optimization potential, i.e., if the original * type itself is instantiated or has more than one instantiated direct subtype. */ @@ -388,7 +388,7 @@ class StrengthenSimplifier implements CustomSimplification { this.toTargetFunction = bb.getHostVM().getStrengthenGraphsToTargetFunction(method.getMultiMethodKey()); } - private TypeFlow getNodeFlow(Node node) { + protected TypeFlow getNodeFlow(Node node) { return nodeFlows == null || nodeFlows.isNew(node) ? null : nodeFlows.get(node); } @@ -563,6 +563,7 @@ private AnalysisType asConstantNonReachableType(ValueNode value, CoreProviders p } private void handleInvoke(Invoke invoke, SimplifierTool tool) { + FixedNode node = invoke.asFixedNode(); MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); @@ -668,32 +669,25 @@ private void handleInvoke(Invoke invoke, SimplifierTool tool) { if (invokeFlow.getTargetMethod().hasReceiver() && !methodFlow.isSaturated((PointsToAnalysis) bb, invokeFlow.getReceiver())) { receiverTypeState = methodFlow.foldTypeFlow((PointsToAnalysis) bb, invokeFlow.getReceiver()); } - - /* - * In an open type world we cannot trust the type state of the receiver for - * virtual calls as new subtypes could be added later. - * - * Note: MethodFlowsGraph.saturateAllParameters() does saturate the receiver in - * many cases, so the check above would also lead to a null typeProfile, but we - * cannot guarantee that we cover all cases. - */ - JavaTypeProfile typeProfile = makeTypeProfile(receiverTypeState); - /* - * In a closed type world analysis the method profile of an invoke is complete - * and contains all the callees reachable at that invocation location. Even if - * that invoke is saturated it is still correct as it contains all the reachable - * implementations of the target method. However, in an open type world the - * method profile of an invoke, saturated or not, is incomplete, as there can be - * implementations that we haven't yet seen. - */ - JavaMethodProfile methodProfile = makeMethodProfile(callees); - - assert typeProfile == null || typeProfile.getTypes().length > 1 : "Should devirtualize with typeProfile=" + typeProfile + " and methodProfile=" + methodProfile + " and callees" + - callees + " invoke " + invokeFlow + " " + invokeFlow.getReceiver() + " in method " + getQualifiedName(graph); - assert methodProfile == null || methodProfile.getMethods().length > 1 : "Should devirtualize with typeProfile=" + typeProfile + " and methodProfile=" + methodProfile + - " and callees" + callees + " invoke " + invokeFlow + " " + invokeFlow.getReceiver() + " in method " + getQualifiedName(graph); - - setInvokeProfiles(invoke, typeProfile, methodProfile); + assignInvokeProfiles(invoke, invokeFlow, callees, receiverTypeState, false); + } + } else { + /* Last resort, try to inject profiles optimistically. */ + TypeState receiverTypeState = null; + if (invokeFlow.getTargetMethod().hasReceiver()) { + if (invokeFlow.isSaturated()) { + /* + * For saturated invokes use all seen instantiated subtypes of target method + * declaring class. In an open world this is incomplete as new types may be + * seen later, but it is an optimistic approximation. + */ + receiverTypeState = targetMethod.getDeclaringClass().getTypeFlow(bb, false).getState(); + } else { + receiverTypeState = methodFlow.foldTypeFlow((PointsToAnalysis) bb, invokeFlow.getReceiver()); + } + } + if (receiverTypeState != null && receiverTypeState.typesCount() <= MAX_TYPES_OPTIMISTIC_PROFILES) { + assignInvokeProfiles(invoke, invokeFlow, callees, receiverTypeState, true); } } @@ -718,6 +712,45 @@ private void handleInvoke(Invoke invoke, SimplifierTool tool) { updateStampUsingPiNode(node, newStampOrConstant, anchorPointAfterInvoke, tool); } + /** + * Maximum number of types seen in a {@link TypeState} for a virtual {@link Invoke} to + * consider optimistic profile injection. See {@link #handleInvoke(Invoke, SimplifierTool)} + * for more details. Note that this is a footprint consideration - we do not want to carry + * around gargantuan {@link JavaTypeProfile} in {@link MethodCallTargetNode} that cannot be + * used anyway. + */ + private static final int MAX_TYPES_OPTIMISTIC_PROFILES = 100; + + private void assignInvokeProfiles(Invoke invoke, InvokeTypeFlow invokeFlow, Collection callees, TypeState receiverTypeState, boolean assumeNotRecorded) { + /* + * In an open type world we cannot trust the type state of the receiver for virtual + * calls as new subtypes could be added later. + * + * Note: assumeNotRecorded specifies if profiles are injected for a closed or open + * world. For a closed world with precise analysis results we never have a + * notRecordedProbabiltiy in any profile. For the open world we always assume that there + * is a not recorded probability in the profile. Such a not recorded probability will be + * injected if assumeNotRecorded==true. + */ + JavaTypeProfile typeProfile = makeTypeProfile(receiverTypeState, assumeNotRecorded); + /* + * In a closed type world analysis the method profile of an invoke is complete and + * contains all the callees reachable at that invocation location. Even if that invoke + * is saturated it is still correct as it contains all the reachable implementations of + * the target method. However, in an open type world the method profile of an invoke, + * saturated or not, is incomplete, as there can be implementations that we haven't yet + * seen. + */ + JavaMethodProfile methodProfile = makeMethodProfile(callees, assumeNotRecorded); + + assert typeProfile == null || typeProfile.getTypes().length > 1 || assumeNotRecorded : "Should devirtualize with typeProfile=" + typeProfile + " and methodProfile=" + methodProfile + + " and callees" + callees + " invoke " + invokeFlow + " " + invokeFlow.getReceiver() + " in method " + getQualifiedName(graph); + assert methodProfile == null || methodProfile.getMethods().length > 1 || assumeNotRecorded : "Should devirtualize with typeProfile=" + typeProfile + " and methodProfile=" + methodProfile + + " and callees" + callees + " invoke " + invokeFlow + " " + invokeFlow.getReceiver() + " in method " + getQualifiedName(graph); + + setInvokeProfiles(invoke, typeProfile, methodProfile); + } + /** * If all possible callees return the same parameter, then we can replace the invoke with * that parameter at all usages. This is the same that would happen when the callees are @@ -1101,17 +1134,17 @@ private static String getQualifiedName(StructuredGraph graph) { return ((AnalysisMethod) graph.method()).getQualifiedName(); } - protected JavaTypeProfile makeTypeProfile(TypeState typeState) { + protected JavaTypeProfile makeTypeProfile(TypeState typeState, boolean injectNotRecordedProbability) { if (typeState == null || analysisSizeCutoff != -1 && typeState.typesCount() > analysisSizeCutoff) { return null; } - var created = createTypeProfile(typeState); + var created = createTypeProfile(typeState, injectNotRecordedProbability); var existing = cachedTypeProfiles.putIfAbsent(created, created); return existing != null ? existing : created; } - private JavaTypeProfile createTypeProfile(TypeState typeState) { - double probability = 1d / typeState.typesCount(); + private JavaTypeProfile createTypeProfile(TypeState typeState, boolean injectNotRecordedProbability) { + double probability = 1d / (typeState.typesCount() + (injectNotRecordedProbability ? 1 : 0)); Stream stream = typeState.typesStream(bb); if (converter != null) { @@ -1121,22 +1154,22 @@ private JavaTypeProfile createTypeProfile(TypeState typeState) { .map(type -> new JavaTypeProfile.ProfiledType(type, probability)) .toArray(JavaTypeProfile.ProfiledType[]::new); - return new JavaTypeProfile(TriState.get(typeState.canBeNull()), 0, pitems); + return new JavaTypeProfile(TriState.get(typeState.canBeNull()), injectNotRecordedProbability ? probability : 0, pitems); } - protected JavaMethodProfile makeMethodProfile(Collection callees) { + protected JavaMethodProfile makeMethodProfile(Collection callees, boolean injectNotRecordedProbability) { if (analysisSizeCutoff != -1 && callees.size() > analysisSizeCutoff) { return null; } - var created = createMethodProfile(callees); + var created = createMethodProfile(callees, injectNotRecordedProbability); var existing = cachedMethodProfiles.putIfAbsent(created, created); return existing != null ? existing.profile : created.profile; } - private CachedJavaMethodProfile createMethodProfile(Collection callees) { + private CachedJavaMethodProfile createMethodProfile(Collection callees, boolean injectNotRecordedProbability) { JavaMethodProfile.ProfiledMethod[] pitems = new JavaMethodProfile.ProfiledMethod[callees.size()]; int hashCode = 0; - double probability = 1d / pitems.length; + double probability = 1d / (pitems.length + (injectNotRecordedProbability ? 1 : 0)); int idx = 0; for (AnalysisMethod aMethod : callees) { @@ -1144,8 +1177,9 @@ private CachedJavaMethodProfile createMethodProfile(Collection c pitems[idx++] = new JavaMethodProfile.ProfiledMethod(convertedMethod, probability); hashCode = hashCode * 31 + convertedMethod.hashCode(); } - return new CachedJavaMethodProfile(new JavaMethodProfile(0, pitems), hashCode); + return new CachedJavaMethodProfile(new JavaMethodProfile(injectNotRecordedProbability ? probability : 0, pitems), hashCode); } + } /** From 46a13ca84b0ad2218bbb204e9c140b83831a07c2 Mon Sep 17 00:00:00 2001 From: "dominik.mascherbauer@oracle.com" Date: Tue, 22 Oct 2024 17:44:18 +0200 Subject: [PATCH 067/105] Fix gdbdebughelpers compressed oop computation --- substratevm/debug/gdbpy/gdb-debughelpers.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/substratevm/debug/gdbpy/gdb-debughelpers.py b/substratevm/debug/gdbpy/gdb-debughelpers.py index 047a229b982c..f17cd4c2e6ea 100644 --- a/substratevm/debug/gdbpy/gdb-debughelpers.py +++ b/substratevm/debug/gdbpy/gdb-debughelpers.py @@ -212,10 +212,12 @@ def get_compressed_oop(cls, obj: gdb.Value) -> int: assert compression_shift >= 0 compressed_oop = compressed_oop >> compression_shift if is_hub: + assert compression_shift >= 0 + compressed_oop = compressed_oop << compression_shift assert num_alignment_bits >= 0 - compressed_oop = compressed_oop << num_alignment_bits + compressed_oop = compressed_oop >> num_alignment_bits assert num_reserved_bits >= 0 - compressed_oop = compressed_oop >> num_reserved_bits + compressed_oop = compressed_oop << num_reserved_bits return compressed_oop From 7c16bcb0e235bc8de14a8952f958a9b305bf2271 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Tue, 17 Sep 2024 20:00:10 +0200 Subject: [PATCH 068/105] Correctly load class initializer and handle field reflection lookup errors --- .../oracle/graal/pointsto/heap/ImageLayerLoader.java | 11 ++++++++++- .../graal/pointsto/heap/ImageLayerSnapshotUtil.java | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java index c4d70dc9e08f..068bc04685f7 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java @@ -29,6 +29,7 @@ import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.ARGUMENT_IDS_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.ARRAY_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CAN_BE_STATICALLY_BOUND_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CLASS_INIT_NAME; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CLASS_JAVA_NAME_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CLASS_NAME_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CODE_SIZE_TAG; @@ -700,6 +701,8 @@ private void loadMethod(EconomicMap methodData) { if (name.equals(CONSTRUCTOR_NAME)) { type.findConstructor(signature); + } else if (name.equals(CLASS_INIT_NAME)) { + type.getClassInitializer(); } else { type.findMethod(name, signature); } @@ -905,7 +908,13 @@ private void loadField(FieldIdentifier fieldIdentifier, EconomicMap Date: Mon, 14 Oct 2024 16:26:23 +0200 Subject: [PATCH 069/105] Do not emit prefetch allocates with SerialGC --- .../jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java | 6 +++++- .../hotspot/replacements/HotSpotAllocationSnippets.java | 3 +++ .../hotspot/replacements/HotSpotReplacementsUtil.java | 5 +++++ .../core/graal/snippets/SubstrateAllocationSnippets.java | 3 +++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java index 54db0081a22f..04e6a10c41b5 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java @@ -79,6 +79,10 @@ public CompressEncoding getKlassEncoding() { return klassEncoding; } + public boolean useSerialGC() { + return gc == HotSpotGraalRuntime.HotSpotGC.Serial; + } + public boolean useG1GC() { return gc == HotSpotGraalRuntime.HotSpotGC.G1; } @@ -244,7 +248,7 @@ public final int logMinObjAlignment() { /** * The offset of the array length word in an array object's header. - * + *

    * See {@code arrayOopDesc::length_offset_in_bytes()}. */ public final int arrayOopDescLengthOffset() { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotAllocationSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotAllocationSnippets.java index 7091b81a87d2..d4826ba198de 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotAllocationSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotAllocationSnippets.java @@ -320,6 +320,9 @@ private void threadBeingInitializedCheck(KlassPointer klass) { @Override protected final int getPrefetchStyle() { + if (HotSpotReplacementsUtil.useSerialGC(INJECTED_VMCONFIG)) { + return 0; + } return HotSpotReplacementsUtil.allocatePrefetchStyle(INJECTED_VMCONFIG); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java index 9a2ac7629edd..a01adc439d46 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotReplacementsUtil.java @@ -194,6 +194,11 @@ public static boolean useG1GC(@InjectedParameter GraalHotSpotVMConfig config) { return config.useG1GC(); } + @Fold + public static boolean useSerialGC(@InjectedParameter GraalHotSpotVMConfig config) { + return config.useSerialGC(); + } + /** * @see GraalHotSpotVMConfig#doingUnsafeAccessOffset */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java index e43067f34dd7..066f352bb27e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java @@ -406,6 +406,9 @@ static LocationIdentity byteArrayIdentity() { @Override protected final int getPrefetchStyle() { + if (SubstrateOptions.useSerialGC()) { + return 0; + } return SubstrateOptions.AllocatePrefetchStyle.getValue(); } From c2ab86096921e8431021f2ba695787edb7f7873f Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Wed, 16 Oct 2024 17:43:42 +0200 Subject: [PATCH 070/105] Outline SVM cold allocations --- .../HotSpotAllocationSnippets.java | 4 +- .../replacements/AllocationSnippets.java | 3 +- .../genscavenge/ThreadLocalAllocation.java | 21 +++++-- .../snippets/SubstrateAllocationSnippets.java | 55 +++++++++++++++---- 4 files changed, 64 insertions(+), 19 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotAllocationSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotAllocationSnippets.java index d4826ba198de..2a1d38cdb90f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotAllocationSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotAllocationSnippets.java @@ -165,7 +165,7 @@ public Object allocateArray(KlassPointer hub, @ConstantParameter boolean supportsOptimizedFilling, @ConstantParameter HotSpotAllocationProfilingData profilingData, @ConstantParameter boolean withException) { - Object result = allocateArrayImpl(hub.asWord(), length, arrayBaseOffset, log2ElementSize, fillContents, fillStartOffset, emitMemoryBarrier, maybeUnroll, supportsBulkZeroing, + Object result = allocateArrayImpl(hub.asWord(), length, false, arrayBaseOffset, log2ElementSize, fillContents, fillStartOffset, emitMemoryBarrier, maybeUnroll, supportsBulkZeroing, supportsOptimizedFilling, profilingData, withException); return piArrayCastToSnippetReplaceeStamp(result, length); } @@ -272,7 +272,7 @@ public Object allocateArrayDynamic(Class elementType, int arrayBaseOffset = (layoutHelper >> layoutHelperHeaderSizeShift(INJECTED_VMCONFIG)) & layoutHelperHeaderSizeMask(INJECTED_VMCONFIG); int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG); Object result; - result = allocateArrayImpl(nonNullKlass.asWord(), length, arrayBaseOffset, log2ElementSize, fillContents, arrayBaseOffset, emitMemoryBarrier, false, + result = allocateArrayImpl(nonNullKlass.asWord(), length, false, arrayBaseOffset, log2ElementSize, fillContents, arrayBaseOffset, emitMemoryBarrier, false, supportsBulkZeroing, supportsOptimizedFilling, profilingData, withException); return piArrayCastToSnippetReplaceeStamp(result, length); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/AllocationSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/AllocationSnippets.java index 029f3a9d9604..6431e7f2b034 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/AllocationSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/AllocationSnippets.java @@ -74,6 +74,7 @@ protected Object allocateInstanceImpl(Word hub, public Object allocateArrayImpl(Word hub, int length, + boolean forceSlowPath, int arrayBaseOffset, int log2ElementSize, FillContent fillContents, @@ -95,7 +96,7 @@ public Object allocateArrayImpl(Word hub, Word newTop = top.add(allocationSize); Object result; - if (useTLAB() && probability(FAST_PATH_PROBABILITY, shouldAllocateInTLAB(allocationSize, true)) && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { + if (!forceSlowPath && useTLAB() && probability(FAST_PATH_PROBABILITY, shouldAllocateInTLAB(allocationSize, true)) && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { writeTlabTop(thread, newTop); emitPrefetchAllocate(newTop, true); boolean useOptimizedFilling = !withException && supportsOptimizedFilling; diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java index 6ba691a3de37..2dc00e124ef0 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java @@ -223,11 +223,12 @@ private static Object slowPathNewInstance(Word objectHeader) { DynamicHub hub = ObjectHeaderImpl.getObjectHeaderImpl().dynamicHubFromObjectHeader(objectHeader); UnsignedWord size = LayoutEncoding.getPureInstanceAllocationSize(hub.getLayoutEncoding()); - Object result = slowPathNewInstanceWithoutAllocating(hub, size); - - runSlowPathHooks(); - sampleSlowPathAllocation(result, size, Integer.MIN_VALUE); - + Object result = allocateInstanceInCurrentTlab(hub, size); + if (result == null) { + result = slowPathNewInstanceWithoutAllocating(hub, size); + runSlowPathHooks(); + sampleSlowPathAllocation(result, size, Integer.MIN_VALUE); + } return result; } finally { StackOverflowCheck.singleton().protectYellowZone(); @@ -334,6 +335,16 @@ private static Object slowPathNewArrayLikeObject0(DynamicHub hub, int length, Un } } + @Uninterruptible(reason = "Holds uninitialized memory.") + private static Object allocateInstanceInCurrentTlab(DynamicHub hub, UnsignedWord size) { + if (size.aboveThan(availableTlabMemory(getTlab()))) { + return null; + } + assert size.equal(LayoutEncoding.getPureInstanceAllocationSize(hub.getLayoutEncoding())); + Pointer memory = allocateRawMemoryInTlab(size, getTlab()); + return FormatObjectNode.formatObject(memory, DynamicHub.toClass(hub), false, FillContent.WITH_ZEROES, true); + } + @Uninterruptible(reason = "Holds uninitialized memory.") private static Object allocateInstanceInNewTlab(DynamicHub hub, UnsignedWord size, AlignedHeader newTlabChunk) { assert size.equal(LayoutEncoding.getPureInstanceAllocationSize(hub.getLayoutEncoding())); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java index 066f352bb27e..d38832185e90 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java @@ -82,10 +82,13 @@ import jdk.graal.compiler.nodes.GraphState; import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.nodes.PiNode; +import jdk.graal.compiler.nodes.ProfileData; import jdk.graal.compiler.nodes.SnippetAnchorNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.UnreachableNode; import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.cfg.ControlFlowGraph; +import jdk.graal.compiler.nodes.cfg.HIRBlock; import jdk.graal.compiler.nodes.extended.ForeignCallNode; import jdk.graal.compiler.nodes.extended.ForeignCallWithExceptionNode; import jdk.graal.compiler.nodes.java.DynamicNewArrayNode; @@ -133,18 +136,20 @@ public void registerForeignCalls(SubstrateForeignCallsProvider foreignCalls) { @Snippet protected Object allocateInstance(@NonNullParameter DynamicHub hub, - @ConstantParameter long size, + @ConstantParameter long size, + @ConstantParameter boolean forceSlowPath, @ConstantParameter FillContent fillContents, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter AllocationProfilingData profilingData, @ConstantParameter boolean withException) { - Object result = allocateInstanceImpl(encodeAsTLABObjectHeader(hub), WordFactory.unsigned(size), false, fillContents, emitMemoryBarrier, true, profilingData, withException); + Object result = allocateInstanceImpl(encodeAsTLABObjectHeader(hub), WordFactory.unsigned(size), forceSlowPath, fillContents, emitMemoryBarrier, true, profilingData, withException); return piCastToSnippetReplaceeStamp(result); } @Snippet public Object allocateArray(@NonNullParameter DynamicHub hub, int length, + @ConstantParameter boolean forceSlowPath, @ConstantParameter int arrayBaseOffset, @ConstantParameter int log2ElementSize, @ConstantParameter FillContent fillContents, @@ -154,7 +159,7 @@ public Object allocateArray(@NonNullParameter DynamicHub hub, @ConstantParameter boolean supportsOptimizedFilling, @ConstantParameter AllocationProfilingData profilingData, @ConstantParameter boolean withException) { - Object result = allocateArrayImpl(encodeAsTLABObjectHeader(hub), length, arrayBaseOffset, log2ElementSize, fillContents, + Object result = allocateArrayImpl(encodeAsTLABObjectHeader(hub), length, forceSlowPath, arrayBaseOffset, log2ElementSize, fillContents, afterArrayLengthOffset(), emitMemoryBarrier, maybeUnroll, supportsBulkZeroing, supportsOptimizedFilling, profilingData, withException); return piArrayCastToSnippetReplaceeStamp(result, length); } @@ -162,7 +167,8 @@ public Object allocateArray(@NonNullParameter DynamicHub hub, @Snippet public Object allocateStoredContinuation(@NonNullParameter DynamicHub hub, int length, - @ConstantParameter int arrayBaseOffset, + @ConstantParameter boolean forceSlowPath, + @ConstantParameter int arrayBaseOffset, @ConstantParameter int log2ElementSize, @ConstantParameter long ipOffset, @ConstantParameter boolean emitMemoryBarrier, @@ -178,7 +184,7 @@ public Object allocateStoredContinuation(@NonNullParameter DynamicHub hub, Word newTop = top.add(allocationSize); Object result; - if (useTLAB() && probability(FAST_PATH_PROBABILITY, shouldAllocateInTLAB(allocationSize, true)) && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { + if (!forceSlowPath && useTLAB() && probability(FAST_PATH_PROBABILITY, shouldAllocateInTLAB(allocationSize, true)) && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { writeTlabTop(thread, newTop); emitPrefetchAllocate(newTop, true); result = formatStoredContinuation(encodeAsTLABObjectHeader(hub), allocationSize, length, top, emitMemoryBarrier, ipOffset, profilingData.snippetCounters); @@ -193,7 +199,8 @@ public Object allocateStoredContinuation(@NonNullParameter DynamicHub hub, @Snippet public Object allocatePod(@NonNullParameter DynamicHub hub, int arrayLength, - byte[] referenceMap, + @ConstantParameter boolean forceSlowPath, + byte[] referenceMap, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter boolean maybeUnroll, @ConstantParameter boolean supportsBulkZeroing, @@ -211,7 +218,7 @@ public Object allocatePod(@NonNullParameter DynamicHub hub, Word newTop = top.add(allocationSize); Object result; - if (useTLAB() && probability(FAST_PATH_PROBABILITY, shouldAllocateInTLAB(allocationSize, true)) && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { + if (!forceSlowPath && useTLAB() && probability(FAST_PATH_PROBABILITY, shouldAllocateInTLAB(allocationSize, true)) && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { writeTlabTop(thread, newTop); emitPrefetchAllocate(newTop, true); result = formatPod(encodeAsTLABObjectHeader(hub), hub, allocationSize, arrayLength, referenceMap, top, AllocationSnippets.FillContent.WITH_ZEROES, @@ -226,26 +233,28 @@ public Object allocatePod(@NonNullParameter DynamicHub hub, @Snippet public Object allocateInstanceDynamic(@NonNullParameter DynamicHub hub, + @ConstantParameter boolean forceSlowPath, @ConstantParameter FillContent fillContents, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter boolean supportsBulkZeroing, @ConstantParameter boolean supportsOptimizedFilling, @ConstantParameter AllocationProfilingData profilingData, @ConstantParameter boolean withException) { - return allocateInstanceDynamicImpl(hub, fillContents, emitMemoryBarrier, supportsBulkZeroing, supportsOptimizedFilling, profilingData, withException); + return allocateInstanceDynamicImpl(hub, forceSlowPath, fillContents, emitMemoryBarrier, supportsBulkZeroing, supportsOptimizedFilling, profilingData, withException); } - protected Object allocateInstanceDynamicImpl(DynamicHub hub, FillContent fillContents, boolean emitMemoryBarrier, @SuppressWarnings("unused") boolean supportsBulkZeroing, + protected Object allocateInstanceDynamicImpl(DynamicHub hub, boolean forceSlowPath, FillContent fillContents, boolean emitMemoryBarrier, @SuppressWarnings("unused") boolean supportsBulkZeroing, @SuppressWarnings("unused") boolean supportsOptimizedFilling, AllocationProfilingData profilingData, boolean withException) { // The hub was already verified by a ValidateNewInstanceClassNode. UnsignedWord size = LayoutEncoding.getPureInstanceAllocationSize(hub.getLayoutEncoding()); - Object result = allocateInstanceImpl(encodeAsTLABObjectHeader(hub), size, false, fillContents, emitMemoryBarrier, false, profilingData, withException); + Object result = allocateInstanceImpl(encodeAsTLABObjectHeader(hub), size, forceSlowPath, fillContents, emitMemoryBarrier, false, profilingData, withException); return piCastToSnippetReplaceeStamp(result); } @Snippet public Object allocateArrayDynamic(DynamicHub elementType, int length, + @ConstantParameter boolean forceSlowPath, @ConstantParameter FillContent fillContents, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter boolean supportsBulkZeroing, @@ -258,7 +267,7 @@ public Object allocateArrayDynamic(DynamicHub elementType, int arrayBaseOffset = getArrayBaseOffset(layoutEncoding); int log2ElementSize = LayoutEncoding.getArrayIndexShift(layoutEncoding); - Object result = allocateArrayImpl(encodeAsTLABObjectHeader(checkedArrayHub), length, arrayBaseOffset, log2ElementSize, fillContents, + Object result = allocateArrayImpl(encodeAsTLABObjectHeader(checkedArrayHub), length, forceSlowPath, arrayBaseOffset, log2ElementSize, fillContents, arrayBaseOffset, emitMemoryBarrier, false, supportsBulkZeroing, supportsOptimizedFilling, profilingData, withException); return piArrayCastToSnippetReplaceeStamp(result, length); @@ -719,6 +728,18 @@ private static AllocationCounter createAllocationSiteCounter(ValueNode node, Res return allocationSite.createCounter(counterName); } + public static final double HOT_ALLOCATION_THRESHOLD = FAST_PATH_PROBABILITY; + + private static boolean shouldOutlineAllocation(Node node, StructuredGraph graph) { + if (GraalOptions.ReduceCodeSize.getValue(graph.getOptions())) { + return true; + } + ControlFlowGraph cfg = graph.getLastCFG(); + HIRBlock block = cfg.blockFor(node); + return ProfileData.ProfileSource.isTrusted(block.getFrequencySource()) + && block.getRelativeFrequency() < HOT_ALLOCATION_THRESHOLD; + } + private class NewInstanceLowering implements NodeLoweringProvider { @Override public void lower(NewInstanceNode node, LoweringTool tool) { @@ -736,6 +757,7 @@ public void lower(NewInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstance, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.addConst("size", size); + args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("profilingData", getProfilingData(node, type)); @@ -761,6 +783,7 @@ public void lower(NewInstanceWithExceptionNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstance, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.addConst("size", size); + args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); args.addConst("fillContents", FillContent.fromBoolean(true)); args.addConst("emitMemoryBarrier", true); args.addConst("profilingData", getProfilingData(node, type)); @@ -792,6 +815,7 @@ public void lower(SubstrateNewHybridInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); + args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); args.addConst("fillContents", FillContent.fromBoolean(fillContents)); @@ -826,6 +850,7 @@ public void lower(NewStoredContinuationNode node, LoweringTool tool) { Arguments args = new Arguments(allocateStoredContinuation, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); + args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); args.addConst("ipOffset", ContinuationSupport.singleton().getIPOffset()); @@ -855,6 +880,7 @@ public void lower(NewArrayNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); + args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); @@ -889,6 +915,7 @@ public void lower(NewArrayWithExceptionNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); + args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); @@ -967,6 +994,7 @@ public void lower(DynamicNewInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstanceDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", node.getInstanceType()); + args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); @@ -988,6 +1016,7 @@ public void lower(DynamicNewInstanceWithExceptionNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstanceDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", node.getInstanceType()); + args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); args.addConst("fillContents", FillContent.fromBoolean(true)); args.addConst("emitMemoryBarrier", true/* barriers */); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); @@ -1010,6 +1039,7 @@ public void lower(DynamicNewArrayNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArrayDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("elementType", node.getElementType()); args.add("length", node.length()); + args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); @@ -1032,6 +1062,7 @@ public void lower(DynamicNewArrayWithExceptionNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArrayDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("elementType", node.getElementType()); args.add("length", node.length()); + args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); args.addConst("fillContents", FillContent.fromBoolean(true)); args.addConst("emitMemoryBarrier", true/* barriers */); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); @@ -1043,6 +1074,7 @@ public void lower(DynamicNewArrayWithExceptionNode node, LoweringTool tool) { } } + private class ValidateNewInstanceClassLowering implements NodeLoweringProvider { @Override public void lower(ValidateNewInstanceClassNode node, LoweringTool tool) { @@ -1070,6 +1102,7 @@ public void lower(NewPodInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocatePod, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", node.getHub()); args.add("arrayLength", node.getArrayLength()); + args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); args.add("referenceMap", node.getReferenceMap()); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("maybeUnroll", node.getArrayLength().isConstant()); From d69c4074909900246fe6b25ef5d2f8044e83c166 Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Fri, 18 Oct 2024 14:21:39 +0200 Subject: [PATCH 071/105] Make GraalOptions.ReduceCodeSize fully determine alloc outlining strategy --- .../graal/snippets/SubstrateAllocationSnippets.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java index d38832185e90..f006e05d38c7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java @@ -82,13 +82,10 @@ import jdk.graal.compiler.nodes.GraphState; import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.nodes.PiNode; -import jdk.graal.compiler.nodes.ProfileData; import jdk.graal.compiler.nodes.SnippetAnchorNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.UnreachableNode; import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.cfg.ControlFlowGraph; -import jdk.graal.compiler.nodes.cfg.HIRBlock; import jdk.graal.compiler.nodes.extended.ForeignCallNode; import jdk.graal.compiler.nodes.extended.ForeignCallWithExceptionNode; import jdk.graal.compiler.nodes.java.DynamicNewArrayNode; @@ -728,16 +725,8 @@ private static AllocationCounter createAllocationSiteCounter(ValueNode node, Res return allocationSite.createCounter(counterName); } - public static final double HOT_ALLOCATION_THRESHOLD = FAST_PATH_PROBABILITY; - private static boolean shouldOutlineAllocation(Node node, StructuredGraph graph) { - if (GraalOptions.ReduceCodeSize.getValue(graph.getOptions())) { - return true; - } - ControlFlowGraph cfg = graph.getLastCFG(); - HIRBlock block = cfg.blockFor(node); - return ProfileData.ProfileSource.isTrusted(block.getFrequencySource()) - && block.getRelativeFrequency() < HOT_ALLOCATION_THRESHOLD; + return GraalOptions.ReduceCodeSize.getValue(graph.getOptions()); } private class NewInstanceLowering implements NodeLoweringProvider { From 6075922693d99e46bb8f915ce13701dbca35bd7a Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Mon, 21 Oct 2024 17:21:59 +0200 Subject: [PATCH 072/105] Format fixes --- .../snippets/SubstrateAllocationSnippets.java | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java index f006e05d38c7..bd46de731a80 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java @@ -133,8 +133,8 @@ public void registerForeignCalls(SubstrateForeignCallsProvider foreignCalls) { @Snippet protected Object allocateInstance(@NonNullParameter DynamicHub hub, - @ConstantParameter long size, - @ConstantParameter boolean forceSlowPath, + @ConstantParameter long size, + @ConstantParameter boolean forceSlowPath, @ConstantParameter FillContent fillContents, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter AllocationProfilingData profilingData, @@ -146,7 +146,7 @@ protected Object allocateInstance(@NonNullParameter DynamicHub hub, @Snippet public Object allocateArray(@NonNullParameter DynamicHub hub, int length, - @ConstantParameter boolean forceSlowPath, + @ConstantParameter boolean forceSlowPath, @ConstantParameter int arrayBaseOffset, @ConstantParameter int log2ElementSize, @ConstantParameter FillContent fillContents, @@ -164,8 +164,8 @@ public Object allocateArray(@NonNullParameter DynamicHub hub, @Snippet public Object allocateStoredContinuation(@NonNullParameter DynamicHub hub, int length, - @ConstantParameter boolean forceSlowPath, - @ConstantParameter int arrayBaseOffset, + @ConstantParameter boolean forceSlowPath, + @ConstantParameter int arrayBaseOffset, @ConstantParameter int log2ElementSize, @ConstantParameter long ipOffset, @ConstantParameter boolean emitMemoryBarrier, @@ -196,8 +196,8 @@ public Object allocateStoredContinuation(@NonNullParameter DynamicHub hub, @Snippet public Object allocatePod(@NonNullParameter DynamicHub hub, int arrayLength, - @ConstantParameter boolean forceSlowPath, - byte[] referenceMap, + @ConstantParameter boolean forceSlowPath, + byte[] referenceMap, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter boolean maybeUnroll, @ConstantParameter boolean supportsBulkZeroing, @@ -230,7 +230,7 @@ public Object allocatePod(@NonNullParameter DynamicHub hub, @Snippet public Object allocateInstanceDynamic(@NonNullParameter DynamicHub hub, - @ConstantParameter boolean forceSlowPath, + @ConstantParameter boolean forceSlowPath, @ConstantParameter FillContent fillContents, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter boolean supportsBulkZeroing, @@ -251,7 +251,7 @@ protected Object allocateInstanceDynamicImpl(DynamicHub hub, boolean forceSlowPa @Snippet public Object allocateArrayDynamic(DynamicHub elementType, int length, - @ConstantParameter boolean forceSlowPath, + @ConstantParameter boolean forceSlowPath, @ConstantParameter FillContent fillContents, @ConstantParameter boolean emitMemoryBarrier, @ConstantParameter boolean supportsBulkZeroing, @@ -725,7 +725,7 @@ private static AllocationCounter createAllocationSiteCounter(ValueNode node, Res return allocationSite.createCounter(counterName); } - private static boolean shouldOutlineAllocation(Node node, StructuredGraph graph) { + private static boolean shouldOutlineAllocation(StructuredGraph graph) { return GraalOptions.ReduceCodeSize.getValue(graph.getOptions()); } @@ -746,7 +746,7 @@ public void lower(NewInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstance, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.addConst("size", size); - args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); + args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("profilingData", getProfilingData(node, type)); @@ -772,7 +772,7 @@ public void lower(NewInstanceWithExceptionNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstance, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.addConst("size", size); - args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); + args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); args.addConst("fillContents", FillContent.fromBoolean(true)); args.addConst("emitMemoryBarrier", true); args.addConst("profilingData", getProfilingData(node, type)); @@ -804,7 +804,7 @@ public void lower(SubstrateNewHybridInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); - args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); + args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); args.addConst("fillContents", FillContent.fromBoolean(fillContents)); @@ -839,7 +839,7 @@ public void lower(NewStoredContinuationNode node, LoweringTool tool) { Arguments args = new Arguments(allocateStoredContinuation, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); - args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); + args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); args.addConst("ipOffset", ContinuationSupport.singleton().getIPOffset()); @@ -869,7 +869,7 @@ public void lower(NewArrayNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); - args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); + args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); @@ -904,7 +904,7 @@ public void lower(NewArrayWithExceptionNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); - args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); + args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); @@ -983,7 +983,7 @@ public void lower(DynamicNewInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstanceDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", node.getInstanceType()); - args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); + args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); @@ -1005,7 +1005,7 @@ public void lower(DynamicNewInstanceWithExceptionNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstanceDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", node.getInstanceType()); - args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); + args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); args.addConst("fillContents", FillContent.fromBoolean(true)); args.addConst("emitMemoryBarrier", true/* barriers */); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); @@ -1028,7 +1028,7 @@ public void lower(DynamicNewArrayNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArrayDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("elementType", node.getElementType()); args.add("length", node.length()); - args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); + args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); @@ -1051,7 +1051,7 @@ public void lower(DynamicNewArrayWithExceptionNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArrayDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("elementType", node.getElementType()); args.add("length", node.length()); - args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); + args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); args.addConst("fillContents", FillContent.fromBoolean(true)); args.addConst("emitMemoryBarrier", true/* barriers */); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); @@ -1063,7 +1063,6 @@ public void lower(DynamicNewArrayWithExceptionNode node, LoweringTool tool) { } } - private class ValidateNewInstanceClassLowering implements NodeLoweringProvider { @Override public void lower(ValidateNewInstanceClassNode node, LoweringTool tool) { @@ -1091,7 +1090,7 @@ public void lower(NewPodInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocatePod, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", node.getHub()); args.add("arrayLength", node.getArrayLength()); - args.addConst("forceSlowPath", shouldOutlineAllocation(node, graph)); + args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); args.add("referenceMap", node.getReferenceMap()); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("maybeUnroll", node.getArrayLength().isConstant()); From 7dc3a67df3d8a06be634c17b153c78068eb98ed9 Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Wed, 23 Oct 2024 11:36:50 +0200 Subject: [PATCH 073/105] Make PublishWritesNode verification only check for init reads --- .../graal/compiler/nodes/extended/PublishWritesNode.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/PublishWritesNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/PublishWritesNode.java index c3b13c098cb4..51cf93e6a7e5 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/PublishWritesNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/extended/PublishWritesNode.java @@ -90,11 +90,11 @@ public boolean inferStamp() { @Override public boolean verifyNode() { - // Check that the published allocation node is not used by reads directly. + // Check that the published allocation node is not used by init reads directly. for (AddressNode address : allocation.usages().filter(AddressNode.class)) { var readUsages = address.usages().filter(n -> { - // n is a non-writing access (a.k.a. a read) - return n instanceof MemoryAccess && !MemoryKill.isMemoryKill(n); + // n is a non-writing access (a.k.a. a read) to INIT_LOCATION + return n instanceof MemoryAccess access && access.getLocationIdentity().isInit() && !MemoryKill.isMemoryKill(n); }); assertTrue(readUsages.isEmpty(), "%s has unpublished reads", allocation); } From f4650dd603fe0c3e935135fcc2da554544a1b6b7 Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Wed, 23 Oct 2024 11:37:09 +0200 Subject: [PATCH 074/105] Enable -H:DumpOnError for libgraal builds --- substratevm/mx.substratevm/mx_substratevm.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index 0f1bf1bb5d77..6aca29791e7d 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -1545,6 +1545,9 @@ def prevent_build_path_in_libgraal(): '--enable-monitoring=heapdump', '-H:HeapDumpDefaultFilenamePrefix=libgraal_pid', + # Generate a .bgv dump upon compilation failure + '-H:+DumpOnError', + # No VM-internal threads may be spawned for libgraal and the reference handling is executed manually. '-H:-AllowVMInternalThreads', '-R:-AutomaticReferenceHandling', From 7b41095a940c4c0f1f4c80a84b23eb065c5abab3 Mon Sep 17 00:00:00 2001 From: Tom Shull Date: Mon, 14 Oct 2024 15:09:08 +0200 Subject: [PATCH 075/105] Workarounds for layered image reloading quirks. --- .../heap/StandaloneHeapSnapshotVerifier.java | 4 ++-- .../pointsto/heap/HeapSnapshotVerifier.java | 20 +++++++++++++------ .../DefaultVirtualInvokeTypeFlow.java | 3 ++- .../svm/hosted/heap/SVMImageHeapVerifier.java | 4 +++- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneHeapSnapshotVerifier.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneHeapSnapshotVerifier.java index 98926736963a..eb20034344a6 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneHeapSnapshotVerifier.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/heap/StandaloneHeapSnapshotVerifier.java @@ -41,9 +41,9 @@ public StandaloneHeapSnapshotVerifier(BigBang bb, ImageHeap imageHeap, ImageHeap } @Override - protected ObjectScanner installObjectScanner(UniverseMetaAccess metaAccess, CompletionExecutor executor) { + protected ObjectScanner installObjectScanner(UniverseMetaAccess metaAccess, CompletionExecutor executor, boolean skipReachableCheck) { StandaloneImageHeapScanner standaloneImageHeapScanner = (StandaloneImageHeapScanner) this.scanner; - return new StandaloneObjectScanner(bb, executor, scannedObjects, new ScanningObserver(), standaloneImageHeapScanner.getShouldScanConstant(), + return new StandaloneObjectScanner(bb, executor, scannedObjects, new ScanningObserver(skipReachableCheck), standaloneImageHeapScanner.getShouldScanConstant(), standaloneImageHeapScanner.getShouldScanField()); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java index 8b2fe293b534..c02730ed3e55 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java @@ -84,20 +84,25 @@ public boolean checkHeapSnapshot(DebugContext debug, UniverseMetaAccess metaAcce return checkHeapSnapshot(metaAccess, executor, stage, false, embeddedConstants); } + public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecutor executor, String phase, boolean forAnalysis, Map embeddedConstants) { + return checkHeapSnapshot(metaAccess, executor, phase, forAnalysis, embeddedConstants, false); + } + /** * Heap verification does a complete scan from roots (static fields and embedded constant) and * compares the object graph against the shadow heap. If any new reachable objects or primitive * values are found then the verifier automatically patches the shadow heap. If this is during * analysis then the heap scanner will also notify the analysis of the new objects. */ - public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecutor executor, String phase, boolean forAnalysis, Map embeddedConstants) { + protected boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecutor executor, String phase, boolean forAnalysis, Map embeddedConstants, + boolean skipReachableCheck) { info("Verifying the heap snapshot %s%s ...", phase, (forAnalysis ? ", iteration " + iterations : "")); analysisModified = false; heapPatched = false; int reachableTypesBefore = bb.getUniverse().getReachableTypes(); iterations++; scannedObjects.reset(); - ObjectScanner objectScanner = installObjectScanner(metaAccess, executor); + ObjectScanner objectScanner = installObjectScanner(metaAccess, executor, skipReachableCheck); executor.start(); scanTypes(objectScanner); objectScanner.scanBootImageHeapRoots(embeddedConstants); @@ -132,8 +137,8 @@ public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecut return analysisModified || verificationReachableTypes > 0; } - protected ObjectScanner installObjectScanner(@SuppressWarnings("unused") UniverseMetaAccess metaAccess, CompletionExecutor executor) { - return new ObjectScanner(bb, executor, scannedObjects, new ScanningObserver()); + protected ObjectScanner installObjectScanner(@SuppressWarnings("unused") UniverseMetaAccess metaAccess, CompletionExecutor executor, boolean skipReachableCheck) { + return new ObjectScanner(bb, executor, scannedObjects, new ScanningObserver(skipReachableCheck)); } protected void scanTypes(@SuppressWarnings("unused") ObjectScanner objectScanner) { @@ -144,7 +149,10 @@ public void cleanupAfterAnalysis() { protected final class ScanningObserver implements ObjectScanningObserver { - public ScanningObserver() { + private final boolean skipReachableCheck; + + public ScanningObserver(boolean skipReachableCheck) { + this.skipReachableCheck = skipReachableCheck; } @Override @@ -418,7 +426,7 @@ private void ensureTypeScanned(JavaConstant typeConstant, AnalysisType type, Sca @SuppressWarnings({"unchecked", "rawtypes"}) private void ensureTypeScanned(JavaConstant value, JavaConstant typeConstant, AnalysisType type, ScanReason reason) { - if (!type.isReachable()) { + if (!skipReachableCheck && !type.isReachable()) { error(reason, "The heap snapshot verifier discovered a type not marked as reachable: %s", type); } Object task = imageHeap.getSnapshot(typeConstant); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/DefaultVirtualInvokeTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/DefaultVirtualInvokeTypeFlow.java index 4c093c434751..d3de0688bacd 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/DefaultVirtualInvokeTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/typestate/DefaultVirtualInvokeTypeFlow.java @@ -37,6 +37,7 @@ import com.oracle.graal.pointsto.flow.TypeFlow; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.meta.BaseLayerType; import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import com.oracle.svm.common.meta.MultiMethod.MultiMethodKey; @@ -73,7 +74,7 @@ public void onObservedUpdate(PointsToAnalysis bb) { } for (AnalysisType type : receiverState.types(bb)) { - assert receiverType.isAssignableFrom(type) : type + " should be a subtype of " + receiverType; + assert receiverType.isAssignableFrom(type) || type.getWrapped() instanceof BaseLayerType : type + " should be a subtype of " + receiverType; if (isSaturated()) { /*- * The receiver can become saturated during the callees linking, which saturates diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java index 797c0431fbe3..61ddc21ea4ae 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java @@ -36,6 +36,7 @@ import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.util.CompletionExecutor; +import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; import com.oracle.svm.hosted.SVMHost; import jdk.vm.ci.meta.Constant; @@ -48,7 +49,8 @@ public SVMImageHeapVerifier(BigBang bb, ImageHeap imageHeap, ImageHeapScanner sc @Override public boolean checkHeapSnapshot(UniverseMetaAccess metaAccess, CompletionExecutor executor, String phase, boolean forAnalysis, Map embeddedConstants) { - return super.checkHeapSnapshot(metaAccess, executor, phase, forAnalysis, embeddedConstants) || imageStateModified(); + boolean skipReachableCheck = forAnalysis && ImageLayerBuildingSupport.buildingExtensionLayer(); + return super.checkHeapSnapshot(metaAccess, executor, phase, forAnalysis, embeddedConstants, skipReachableCheck) || imageStateModified(); } /** From 602c5de13b48ea2d130eb514c7f020667046ec9b Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Mon, 30 Sep 2024 14:29:35 +0200 Subject: [PATCH 076/105] [GR-58225] JVMCI native library compiler has disabled Java calls by default. --- .../libgraal/truffle/GraalEntryPoints.java | 2 +- .../truffle/HSTruffleCompilerRuntime.java | 10 +-- .../LibGraalTruffleHostEnvironment.java | 84 ++++++++++++++++++- .../LibGraalTruffleHostEnvironmentLookup.java | 10 ++- .../truffle/TruffleCompilerConfiguration.java | 13 ++- .../compiler/truffle/TruffleCompilerImpl.java | 67 ++++++++------- .../truffle/host/HostInliningPhase.java | 1 + .../truffle/host/TruffleHostEnvironment.java | 25 ++++++ .../truffle/host/TruffleKnownHostTypes.java | 4 + .../HotSpotTruffleCompilationSupport.java | 2 +- .../hotspot/HotSpotTruffleCompilerImpl.java | 6 +- ...TruffleCommunityCompilerConfiguration.java | 4 +- .../hotspot/libgraal/LibGraalFeature.java | 2 +- .../TruffleFromLibGraalStartPoints.java | 15 ---- .../oracle/svm/truffle/TruffleSupport.java | 2 +- .../hotspot/libgraal/TruffleFromLibGraal.java | 2 - .../runtime/OptimizedTruffleRuntime.java | 4 + .../TruffleFromLibGraalEntryPoints.java | 33 +++++++- 18 files changed, 213 insertions(+), 73 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/truffle/GraalEntryPoints.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/truffle/GraalEntryPoints.java index 502a9ec8eb43..a98a5dac143f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/truffle/GraalEntryPoints.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/truffle/GraalEntryPoints.java @@ -69,7 +69,7 @@ public static Object newCompiler(Object truffleCompilerRuntime) { * `TruffleCompilerImpl`. The `doCompile` method enters a local compilation context through * its own call to `HotSpotGraalServices.openLocalCompilationContext`. */ - return HotSpotTruffleCompilerImpl.create((HSTruffleCompilerRuntime) truffleCompilerRuntime); + return HotSpotTruffleCompilerImpl.create((HSTruffleCompilerRuntime) truffleCompilerRuntime, null); } public static void initializeCompiler(Object compiler, Object compilableHsHandle, boolean firstInitialization) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/truffle/HSTruffleCompilerRuntime.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/truffle/HSTruffleCompilerRuntime.java index 28c031f45818..e645e0fb4cff 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/truffle/HSTruffleCompilerRuntime.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/truffle/HSTruffleCompilerRuntime.java @@ -100,14 +100,7 @@ public PartialEvaluationMethodInfo getPartialEvaluationMethodInfo(ResolvedJavaMe @Override public HostMethodInfo getHostMethodInfo(ResolvedJavaMethod method) { - long methodHandle = HotSpotJVMCIRuntime.runtime().translate(method); - boolean[] res; - try { - res = (boolean[]) HANDLES.getHostMethodInfo.invoke(hsHandle, methodHandle); - } catch (Throwable t) { - throw handleException(t); - } - return new HostMethodInfo(res[0], res[1], res[2], res[3]); + throw new UnsupportedOperationException("Use TruffleHostEnvironment#getHostMethodInfo()"); } @Override @@ -250,7 +243,6 @@ public boolean isSuppressedFailure(TruffleCompilable compilable, Supplier { HostMethodInfoCache() { @@ -77,9 +98,68 @@ protected Object createKey(ResolvedJavaMethod method) { @Override protected HostMethodInfo computeValue(ResolvedJavaMethod method) { - return runtime().getHostMethodInfo(method); + TruffleKnownHostTypes hostTypes = types(); + List annotationDataList = method.getAnnotationData(hostTypes.TruffleBoundary, hostTypes.BytecodeInterpreterSwitch, + hostTypes.BytecodeInterpreterSwitchBoundary, hostTypes.InliningCutoff); + boolean isTruffleBoundary = false; + boolean isBytecodeInterpreterSwitch = false; + boolean isBytecodeInterpreterSwitchBoundary = false; + boolean isInliningCutoff = false; + for (AnnotationData annotationData : annotationDataList) { + String annotationTypeFqn = annotationData.getAnnotationType().getName(); + if (hostTypes.TruffleBoundary.getName().equals(annotationTypeFqn)) { + isTruffleBoundary = true; + } else if (hostTypes.BytecodeInterpreterSwitch.getName().equals(annotationTypeFqn)) { + isBytecodeInterpreterSwitch = true; + } else if (hostTypes.BytecodeInterpreterSwitchBoundary.getName().equals(annotationTypeFqn)) { + isBytecodeInterpreterSwitchBoundary = true; + } else if (hostTypes.InliningCutoff.getName().equals(annotationTypeFqn)) { + isInliningCutoff = true; + } + } + return new HostMethodInfo(isTruffleBoundary, isBytecodeInterpreterSwitch, isBytecodeInterpreterSwitchBoundary, isInliningCutoff); } } + private static final class TruffleRuntimeScopeImpl implements TruffleRuntimeScope { + + private static final MethodHandle CAN_CALL_JAVA_SCOPE = findCompilerThreadCanCallJavaScopeConstructor(); + + @SuppressWarnings("unchecked") + private static MethodHandle findCompilerThreadCanCallJavaScopeConstructor() { + try { + return MethodHandles.lookup().findConstructor(Class.forName("jdk.vm.ci.hotspot.CompilerThreadCanCallJavaScope"), MethodType.methodType(void.class, boolean.class)); + } catch (ReflectiveOperationException e) { +// GR-58987: Uncomment when OpenJDK pull request is merged +// if (Runtime.version().feature() >= 24) { +// throw new InternalError(e); +// } + } + return null; + } + + private final AutoCloseable impl; + + TruffleRuntimeScopeImpl() { + try { + impl = (AutoCloseable) CAN_CALL_JAVA_SCOPE.invoke(true); + } catch (Error | RuntimeException e) { + throw e; + } catch (Throwable throwable) { + throw new InternalError(throwable); + } + } + + @Override + public void close() { + try { + impl.close(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new AssertionError(e); + } + } + } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/truffle/LibGraalTruffleHostEnvironmentLookup.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/truffle/LibGraalTruffleHostEnvironmentLookup.java index 0f9b55de9792..be7781e34e08 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/truffle/LibGraalTruffleHostEnvironmentLookup.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/libgraal/truffle/LibGraalTruffleHostEnvironmentLookup.java @@ -26,6 +26,7 @@ import jdk.graal.compiler.serviceprovider.GlobalAtomicLong; import jdk.graal.compiler.truffle.host.TruffleHostEnvironment; +import jdk.graal.compiler.truffle.host.TruffleHostEnvironment.TruffleRuntimeScope; import jdk.vm.ci.common.NativeImageReinitialize; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.meta.ResolvedJavaType; @@ -51,6 +52,7 @@ public final class LibGraalTruffleHostEnvironmentLookup implements TruffleHostEn @NativeImageReinitialize private TruffleHostEnvironment previousRuntime; @Override + @SuppressWarnings("try") public TruffleHostEnvironment lookup(ResolvedJavaType forType) { long globalReference = WEAK_TRUFFLE_RUNTIME_INSTANCE.get(); if (globalReference == NO_TRUFFLE_REGISTERED) { @@ -74,9 +76,11 @@ public TruffleHostEnvironment lookup(ResolvedJavaType forType) { * We do not currently validate the forType. But in the future we want to lookup the runtime * per type. So in theory multiple truffle runtimes can be loaded. */ - HSTruffleCompilerRuntime runtime = new HSTruffleCompilerRuntime(NativeImageHostCalls.createGlobalHandle(runtimeLocalHandle, true), NativeImageHostCalls.getObjectClass(runtimeLocalHandle)); - this.previousRuntime = environment = new LibGraalTruffleHostEnvironment(runtime, HotSpotJVMCIRuntime.runtime().getHostJVMCIBackend().getMetaAccess()); - return environment; + try (TruffleRuntimeScope scope = LibGraalTruffleHostEnvironment.openTruffleRuntimeScopeImpl()) { + HSTruffleCompilerRuntime runtime = new HSTruffleCompilerRuntime(NativeImageHostCalls.createGlobalHandle(runtimeLocalHandle, true), NativeImageHostCalls.getObjectClass(runtimeLocalHandle)); + this.previousRuntime = environment = new LibGraalTruffleHostEnvironment(runtime, HotSpotJVMCIRuntime.runtime().getHostJVMCIBackend().getMetaAccess()); + return environment; + } } private static HSTruffleCompilerRuntime hsRuntime(TruffleHostEnvironment environment) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerConfiguration.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerConfiguration.java index 4ca4aba8fe44..81d6cf24e5f8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerConfiguration.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerConfiguration.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.List; +import java.util.function.Supplier; import jdk.graal.compiler.api.replacements.SnippetReflectionProvider; import jdk.graal.compiler.core.target.Backend; @@ -34,6 +35,7 @@ import com.oracle.truffle.compiler.TruffleCompilerRuntime; +import jdk.graal.compiler.truffle.host.TruffleHostEnvironment.TruffleRuntimeScope; import jdk.vm.ci.code.Architecture; public final class TruffleCompilerConfiguration { @@ -44,6 +46,7 @@ public final class TruffleCompilerConfiguration { private final TruffleTierConfiguration lastTier; private final KnownTruffleTypes types; private final Suites hostSuite; + private final Supplier openCanCallTruffleRuntimeScope; public TruffleCompilerConfiguration( TruffleCompilerRuntime runtime, @@ -52,7 +55,8 @@ public TruffleCompilerConfiguration( TruffleTierConfiguration firstTier, TruffleTierConfiguration lastTier, KnownTruffleTypes knownTruffleTypes, - Suites hostSuite) { + Suites hostSuite, + Supplier openCanCallTruffleRuntimeScope) { this.runtime = runtime; this.plugins = plugins; this.provider = provider; @@ -60,6 +64,7 @@ public TruffleCompilerConfiguration( this.lastTier = lastTier; this.types = knownTruffleTypes; this.hostSuite = hostSuite; + this.openCanCallTruffleRuntimeScope = openCanCallTruffleRuntimeScope; } public TruffleCompilerRuntime runtime() { @@ -91,7 +96,7 @@ public Suites hostSuite() { } public TruffleCompilerConfiguration withFirstTier(TruffleTierConfiguration tier) { - return new TruffleCompilerConfiguration(runtime, plugins, provider, tier, lastTier, types, hostSuite); + return new TruffleCompilerConfiguration(runtime, plugins, provider, tier, lastTier, types, hostSuite, openCanCallTruffleRuntimeScope); } public List backends() { @@ -107,4 +112,8 @@ public Architecture architecture() { assert arch.equals(firstTier().backend().getTarget().arch) : "target architecture must be the same for first and last tier."; return arch; } + + TruffleRuntimeScope openCanCallTruffleRuntimeScope() { + return openCanCallTruffleRuntimeScope != null ? openCanCallTruffleRuntimeScope.get() : null; + } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerImpl.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerImpl.java index 33693fce4487..46fbbe35a2b0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerImpl.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/TruffleCompilerImpl.java @@ -41,6 +41,7 @@ import java.util.Map; import java.util.function.Consumer; +import jdk.graal.compiler.truffle.host.TruffleHostEnvironment.TruffleRuntimeScope; import jdk.vm.ci.meta.ProfilingInfo; import org.graalvm.collections.EconomicMap; @@ -810,48 +811,54 @@ private final class TruffleCodeInstallationTask extends Backend.CodeInstallation private final List> optimizedAssumptions = new ArrayList<>(); @Override + @SuppressWarnings("try") public void preProcess(CompilationResult result) { if (result == null || result.getAssumptions() == null) { return; } - TruffleCompilerRuntime runtime = config.runtime(); - ArrayList newAssumptions = new ArrayList<>(); - for (Assumption assumption : result.getAssumptions()) { - if (assumption != null && assumption instanceof TruffleAssumption) { - TruffleAssumption truffleAssumption = (TruffleAssumption) assumption; - Consumer dep = runtime.registerOptimizedAssumptionDependency(truffleAssumption.getAssumption()); - if (dep == null) { - // Before bailing out, notify other assumptions waiting - // for the code that it will never be installed - notifyAssumptions(null); - - throw new RetryableBailoutException("Assumption invalidated while compiling code: %s", truffleAssumption); + try (TruffleRuntimeScope scope = config.openCanCallTruffleRuntimeScope()) { + TruffleCompilerRuntime runtime = config.runtime(); + ArrayList newAssumptions = new ArrayList<>(); + for (Assumption assumption : result.getAssumptions()) { + if (assumption != null && assumption instanceof TruffleAssumption) { + TruffleAssumption truffleAssumption = (TruffleAssumption) assumption; + Consumer dep = runtime.registerOptimizedAssumptionDependency(truffleAssumption.getAssumption()); + if (dep == null) { + // Before bailing out, notify other assumptions waiting + // for the code that it will never be installed + notifyAssumptions(null); + + throw new RetryableBailoutException("Assumption invalidated while compiling code: %s", truffleAssumption); + } + optimizedAssumptions.add(dep); + } else { + newAssumptions.add(assumption); } - optimizedAssumptions.add(dep); - } else { - newAssumptions.add(assumption); } + result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()])); } - result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()])); } @Override + @SuppressWarnings("try") public void postProcess(CompilationResult compilationResult, InstalledCode installedCode) { - afterCodeInstallation(compilationResult, installedCode); - - if (!optimizedAssumptions.isEmpty()) { - OptimizedAssumptionDependency dependency; - if (installedCode instanceof OptimizedAssumptionDependency) { - /* - * On SVM the installed code can be an assumption dependency. On HotSpot we - * cannot subclass HotSpotNmethod therefore that is not an option. - */ - dependency = (OptimizedAssumptionDependency) installedCode; - } else { - TruffleCompilable compilable = getCompilable(compilationResult); - dependency = new TruffleCompilerAssumptionDependency(compilable, installedCode); + try (TruffleRuntimeScope scope = config.openCanCallTruffleRuntimeScope()) { + afterCodeInstallation(compilationResult, installedCode); + + if (!optimizedAssumptions.isEmpty()) { + OptimizedAssumptionDependency dependency; + if (installedCode instanceof OptimizedAssumptionDependency) { + /* + * On SVM the installed code can be an assumption dependency. On HotSpot we + * cannot subclass HotSpotNmethod therefore that is not an option. + */ + dependency = (OptimizedAssumptionDependency) installedCode; + } else { + TruffleCompilable compilable = getCompilable(compilationResult); + dependency = new TruffleCompilerAssumptionDependency(compilable, installedCode); + } + notifyAssumptions(dependency); } - notifyAssumptions(dependency); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/HostInliningPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/HostInliningPhase.java index c0a6e7d20130..edb09a677584 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/HostInliningPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/HostInliningPhase.java @@ -179,6 +179,7 @@ private boolean isTransferToInterpreterMethod(InliningPhaseContext context, Reso } @Override + @SuppressWarnings("try") protected final void runInlining(StructuredGraph graph, HighTierContext highTierContext) { ResolvedJavaMethod method = graph.method(); TruffleHostEnvironment env = TruffleHostEnvironment.get(method); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleHostEnvironment.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleHostEnvironment.java index a206b0d089c8..8ae55c4da3ec 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleHostEnvironment.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleHostEnvironment.java @@ -152,6 +152,16 @@ public static TruffleHostEnvironment get(ResolvedJavaType relativeTo) { return lookup.lookup(relativeTo); } + /** + * Opens a scope that permits the Truffle compiler to make calls to the Truffle runtime, even + * from threads that are otherwise restricted. + * + * @see TruffleRuntimeScope + */ + public TruffleRuntimeScope openTruffleRuntimeScope() { + return null; + } + @LibGraalService public interface Lookup { @@ -159,4 +169,19 @@ public interface Lookup { } + /** + * A scope enabling calls to the Truffle runtime. This is essential for environments where + * certain threads are not permitted to make calls to the Truffle runtime. An example of such an + * environment is the libgraal compiler, which prevents CompileBroker threads from making Java + * calls. + *

    + * This class should be used in conjunction with a try-with-resources statement to ensure the + * scope is closed appropriately. + *

    + */ + public interface TruffleRuntimeScope extends AutoCloseable { + + @Override + void close(); + } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleKnownHostTypes.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleKnownHostTypes.java index f8afe2457c28..ecd7dad0df73 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleKnownHostTypes.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/host/TruffleKnownHostTypes.java @@ -53,6 +53,10 @@ public final class TruffleKnownHostTypes extends AbstractKnownTruffleTypes { public final ResolvedJavaMethod CompilerDirectives_transferToInterpreter = findMethod(CompilerDirectives, "transferToInterpreter"); public final ResolvedJavaMethod CompilerDirectives_transferToInterpreterAndInvalidate = findMethod(CompilerDirectives, "transferToInterpreterAndInvalidate"); public final ResolvedJavaMethod CompilerDirectives_inInterpreter = findMethod(CompilerDirectives, "inInterpreter"); + public final ResolvedJavaType TruffleBoundary = lookupType("com.oracle.truffle.api.CompilerDirectives$TruffleBoundary"); + public final ResolvedJavaType BytecodeInterpreterSwitch = lookupType("com.oracle.truffle.api.HostCompilerDirectives$BytecodeInterpreterSwitch"); + public final ResolvedJavaType BytecodeInterpreterSwitchBoundary = lookupType("com.oracle.truffle.api.HostCompilerDirectives$BytecodeInterpreterSwitchBoundary"); + public final ResolvedJavaType InliningCutoff = lookupType("com.oracle.truffle.api.HostCompilerDirectives$InliningCutoff"); public final ResolvedJavaType HostCompilerDirectives = lookupTypeCached("com.oracle.truffle.api.HostCompilerDirectives"); public final ResolvedJavaMethod HostCompilerDirectives_inInterpreterFastPath = findMethod(HostCompilerDirectives, "inInterpreterFastPath"); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilationSupport.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilationSupport.java index 50d0c252c23e..1d06d87e5ac8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilationSupport.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilationSupport.java @@ -68,7 +68,7 @@ public static String getLazyCompilerConfigurationName() { @Override public TruffleCompiler createCompiler(TruffleCompilerRuntime runtime) { - HotSpotTruffleCompilerImpl compiler = HotSpotTruffleCompilerImpl.create(runtime); + HotSpotTruffleCompilerImpl compiler = HotSpotTruffleCompilerImpl.create(runtime, null); compilerConfigurationName = compiler.getHotspotGraalRuntime().getCompilerConfigurationName(); return compiler; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilerImpl.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilerImpl.java index 462fbecb1354..6edf08da1e48 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilerImpl.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/HotSpotTruffleCompilerImpl.java @@ -33,8 +33,10 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.function.Supplier; import jdk.graal.compiler.core.GraalCompiler; +import jdk.graal.compiler.truffle.host.TruffleHostEnvironment.TruffleRuntimeScope; import org.graalvm.collections.EconomicMap; import com.oracle.truffle.compiler.TruffleCompilable; @@ -139,7 +141,7 @@ protected void parseGraalOptions(String[] options, EconomicMap, Obj OptionsParser.parseOptions(options, values, OptionsParser.getOptionsLoader()); } - public static HotSpotTruffleCompilerImpl create(final TruffleCompilerRuntime runtime) { + public static HotSpotTruffleCompilerImpl create(final TruffleCompilerRuntime runtime, Supplier openCanCallTruffleRuntimeScope) { OptionValues options = HotSpotGraalOptionValues.defaultOptions(); /* * Host inlining is not necessary for Truffle guest compilation so disable it. @@ -163,7 +165,7 @@ public static HotSpotTruffleCompilerImpl create(final TruffleCompilerRuntime run Plugins plugins = phase.getGraphBuilderConfig().getPlugins(); final TruffleCompilerConfiguration compilerConfig = new TruffleCompilerConfiguration(runtime, plugins, snippetReflection, - firstTier, lastTier, knownTruffleTypes, hostSuites); + firstTier, lastTier, knownTruffleTypes, hostSuites, openCanCallTruffleRuntimeScope); HotSpotTruffleCompilerImpl compiler = new HotSpotTruffleCompilerImpl(graalRuntime, compilerConfig); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/TruffleCommunityCompilerConfiguration.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/TruffleCommunityCompilerConfiguration.java index 4cd4f6821e59..4a56cf4d972e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/TruffleCommunityCompilerConfiguration.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/hotspot/TruffleCommunityCompilerConfiguration.java @@ -37,6 +37,8 @@ import jdk.vm.ci.code.Architecture; +import java.util.function.Supplier; + /** * Central place to register Truffle related compiler phases and plugins for host Java compilation * on HotSpot. @@ -44,7 +46,7 @@ * Note that this configuration is also used as basis for Truffle guest compilation on HotSpot. * Therefore make sure that phases which are only relevant for host compilations are explicitly * disabled for Truffle guest compilation in - * {@link HotSpotTruffleCompilerImpl#create(TruffleCompilerRuntime)}. + * {@link HotSpotTruffleCompilerImpl#create(TruffleCompilerRuntime, Supplier)}. *

    * Note that on SubstrateVM TruffleBaseFeature and TruffleFeature must be used for this purpose, * this configuration is NOT loaded. So make sure SVM configuration is in sync if you make changes diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java index 8b66364b8b12..96c9dec079dd 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java @@ -178,7 +178,7 @@ public void afterRegistration(AfterRegistrationAccess access) { buildTimeClass = loader.loadClassOrFail("jdk.graal.compiler.hotspot.libgraal.BuildTime"); // Guest JVMCI and Graal need access to some JDK internal packages - String[] basePackages = {"jdk.internal.misc", "jdk.internal.util"}; + String[] basePackages = {"jdk.internal.misc", "jdk.internal.util", "jdk.internal.vm"}; ModuleSupport.accessPackagesToClass(ModuleSupport.Access.EXPORT, null, false, "java.base", basePackages); try { diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/TruffleFromLibGraalStartPoints.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/TruffleFromLibGraalStartPoints.java index c7c656a6d550..9d6cf19898dc 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/TruffleFromLibGraalStartPoints.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/TruffleFromLibGraalStartPoints.java @@ -58,7 +58,6 @@ import static com.oracle.svm.graal.hotspot.libgraal.TruffleFromLibGraalStartPointsGen.callGetDebugProperties; import static com.oracle.svm.graal.hotspot.libgraal.TruffleFromLibGraalStartPointsGen.callGetDescription; import static com.oracle.svm.graal.hotspot.libgraal.TruffleFromLibGraalStartPointsGen.callGetFailedSpeculationsAddress; -import static com.oracle.svm.graal.hotspot.libgraal.TruffleFromLibGraalStartPointsGen.callGetHostMethodInfo; import static com.oracle.svm.graal.hotspot.libgraal.TruffleFromLibGraalStartPointsGen.callGetKnownCallSiteCount; import static com.oracle.svm.graal.hotspot.libgraal.TruffleFromLibGraalStartPointsGen.callGetLanguage; import static com.oracle.svm.graal.hotspot.libgraal.TruffleFromLibGraalStartPointsGen.callGetLineNumber; @@ -135,20 +134,6 @@ public static byte[] getPartialEvaluationMethodInfo(Object hsHandle, long method }; } - @TruffleFromLibGraal(Id.GetHostMethodInfo) - public static boolean[] getHostMethodInfo(Object hsHandle, long methodHandle) { - JNIEnv env = JNIMethodScope.env(); - JByteArray hsByteArray = callGetHostMethodInfo(calls, env, ((HSObject) hsHandle).getHandle(), methodHandle); - CCharPointer buffer = StackValue.get(4); - JNIUtil.GetByteArrayRegion(env(), hsByteArray, 0, 4, buffer); - BinaryInput in = BinaryInput.create(buffer, 4); - boolean[] result = new boolean[4]; - for (int i = 0; i < result.length; i++) { - result[i] = in.readBoolean(); - } - return result; - } - @TruffleFromLibGraal(Id.OnCodeInstallation) public static void onCodeInstallation(Object hsHandle, Object compilableHsHandle, long installedCodeHandle) { JNIEnv env = JNIMethodScope.env(); diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleSupport.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleSupport.java index 7aeaf85488b4..5c2a11085844 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleSupport.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleSupport.java @@ -118,7 +118,7 @@ protected static TruffleCompilerConfiguration createSubstrateTruffleCompilerConf TruffleRuntimeCompilationSupport.getRuntimeConfig().getProviders(), TruffleRuntimeCompilationSupport.getFullOptSuites(), TruffleRuntimeCompilationSupport.getLIRSuites(), types); return new TruffleCompilerConfiguration(runtime, graphBuilderPlugins, runtimeCompilationFeature.getHostedProviders().getSnippetReflection(), firstTier, lastTier, types, - TruffleRuntimeCompilationSupport.getFullOptSuites()); + TruffleRuntimeCompilationSupport.getFullOptSuites(), null); } public static boolean isIsolatedCompilation() { diff --git a/truffle/src/com.oracle.truffle.compiler/src/com/oracle/truffle/compiler/hotspot/libgraal/TruffleFromLibGraal.java b/truffle/src/com.oracle.truffle.compiler/src/com/oracle/truffle/compiler/hotspot/libgraal/TruffleFromLibGraal.java index 1783ab5bfbb5..5d1de91e1859 100644 --- a/truffle/src/com.oracle.truffle.compiler/src/com/oracle/truffle/compiler/hotspot/libgraal/TruffleFromLibGraal.java +++ b/truffle/src/com.oracle.truffle.compiler/src/com/oracle/truffle/compiler/hotspot/libgraal/TruffleFromLibGraal.java @@ -172,8 +172,6 @@ enum Id implements FromLibGraalId { OnTruffleTierFinished, @Signature({Object.class, Object.class, long.class}) GetPartialEvaluationMethodInfo, - @Signature({Object.class, Object.class, long.class}) - GetHostMethodInfo, @Signature({Consumer.class, Object.class, long.class}) RegisterOptimizedAssumptionDependency, @Signature({void.class, Object.class, int.class, int.class}) diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java index 7b4f3bbef627..85c800d34ad6 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/OptimizedTruffleRuntime.java @@ -405,6 +405,10 @@ private static UnmodifiableEconomicMap> initLookupTypes(Iterabl OptimizedAssumption.class, HostCompilerDirectives.class, CompilerDirectives.class, + CompilerDirectives.TruffleBoundary.class, + HostCompilerDirectives.BytecodeInterpreterSwitch.class, + HostCompilerDirectives.BytecodeInterpreterSwitchBoundary.class, + HostCompilerDirectives.InliningCutoff.class, InlineDecision.class, CompilerAsserts.class, ExactMath.class, diff --git a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/libgraal/TruffleFromLibGraalEntryPoints.java b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/libgraal/TruffleFromLibGraalEntryPoints.java index 30ec4c9e312c..1732d193bea1 100644 --- a/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/libgraal/TruffleFromLibGraalEntryPoints.java +++ b/truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/libgraal/TruffleFromLibGraalEntryPoints.java @@ -100,6 +100,7 @@ import java.util.Set; import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.stream.Collectors; import java.util.stream.Stream; import com.oracle.truffle.compiler.ConstantFieldInfo; @@ -452,7 +453,11 @@ static Object getPartialEvaluationMethodInfo(Object truffleRuntime, long methodH return out.getArray(); } - @TruffleFromLibGraal(Id.GetHostMethodInfo) + /** + * This method is no longer used by the JDK 24 `libgraal` compiler but must be retained for + * backward compatibility with LTS JDK 21. + */ + @Deprecated static Object getHostMethodInfo(Object truffleRuntime, long methodHandle) { ResolvedJavaMethod method = LibGraal.unhand(ResolvedJavaMethod.class, methodHandle); HostMethodInfo info = ((TruffleCompilerRuntime) truffleRuntime).getHostMethodInfo(method); @@ -469,15 +474,37 @@ static Object getHostMethodInfo(Object truffleRuntime, long methodHandle) { /** * Checks that all {@link TruffleFromLibGraal}s are implemented and that their signatures match * the {@linkplain Id#getSignature() ID signatures}. + * + *

    + * Ensures compatibility with Long-Term Support (LTS) releases by supporting two types of + * compatible changes: + *

      + *
    1. **Modification of method parameters**: When method parameters are changed, the original + * method must be retained to ensure backward compatibility with the LTS release. Both the old + * and new methods should be annotated with the {@link TruffleFromLibGraal} annotation. + * Additionally, the old method must be marked with the {@link Deprecated} annotation.
    2. + * + *
    3. **Method removal**: If a method is removed, it must still be retained for compatibility + * with the LTS release. The {@link Id} for the removed method should be eliminated, and the old + * method should not be annotated with the {@link TruffleFromLibGraal} annotation. The method + * must be marked with the {@link Deprecated} annotation.
    4. + *
    + *

    */ private static boolean checkHotSpotCalls() { Set unimplemented = EnumSet.allOf(Id.class); + Map entryPointMethodNames = unimplemented.stream().collect(Collectors.toMap(Id::getMethodName, (id) -> id)); Map> idToMethod = new LinkedHashMap<>(); for (Method method : TruffleFromLibGraalEntryPoints.class.getDeclaredMethods()) { if (Modifier.isStatic(method.getModifiers())) { TruffleFromLibGraal a = method.getAnnotation(TruffleFromLibGraal.class); + Id id; if (a != null) { - Id id = a.value(); + id = a.value(); + List methods = idToMethod.computeIfAbsent(id, (k) -> new ArrayList<>()); + methods.add(method); + } else if (method.getAnnotation(Deprecated.class) != null && (id = entryPointMethodNames.get(method.getName())) != null) { + // LTS compatibility method for a removed Id List methods = idToMethod.computeIfAbsent(id, (k) -> new ArrayList<>()); methods.add(method); } @@ -489,7 +516,7 @@ private static boolean checkHotSpotCalls() { int legacyMethodCount = 0; for (Method method : methods) { check(id, id.getMethodName().equals(method.getName()), "Expected name \"%s\", got \"%s\"", id.getMethodName(), method.getName()); - if (method.getAnnotation(Deprecated.class) != null) { + if (method.getAnnotation(Deprecated.class) != null && method.getAnnotation(TruffleFromLibGraal.class) != null) { legacyMethodCount++; } if (Arrays.equals(id.getParameterTypes(), method.getParameterTypes())) { From 0c63921e103ea7b15ef626e52b01065344c0c3c6 Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Tue, 22 Oct 2024 15:46:15 +0300 Subject: [PATCH 077/105] Remove --strict-image-heap option in docs where necessary (enabled by default) --- .../native-image/BuildOutput.md | 20 ++++++++++--------- .../native-image/ReachabilityMetadata.md | 2 +- .../guides/specify-class-initialization.md | 4 ++-- .../guides/troubleshoot-run-time-errors.md | 16 +++++++-------- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/docs/reference-manual/native-image/BuildOutput.md b/docs/reference-manual/native-image/BuildOutput.md index 9784eeacfff8..74085e9d8f15 100644 --- a/docs/reference-manual/native-image/BuildOutput.md +++ b/docs/reference-manual/native-image/BuildOutput.md @@ -280,15 +280,6 @@ This feature is currently only available for code compiled by Graal for Linux AM The build output may contain one or more of the following recommendations that help you get the best out of Native Image. -#### `INIT`: Use the Strict Image Heap Configuration - -Start using `--strict-image-heap` to reduce the amount of configuration and prepare for future GraalVM releases where this will be the default. -This mode requires only the classes that are stored in the image heap to be marked with `--initialize-at-build-time`. -This effectively reduces the number of configuration entries necessary to achieve build-time initialization. -When adopting the new mode it is best to start introducing build-time initialization from scratch. -During this process, it is best to select individual classes (as opposed to whole packages) for build time initialization. -Also, before migrating to the new flag make sure to update all framework dependencies to the latest versions as they might need to migrate too. - #### `AWT`: Missing Reachability Metadata for Abstract Window Toolkit The Native Image analysis has included classes from the [`java.awt` package](https://docs.oracle.com/en/java/javase/22/docs/api/java.desktop/java/awt/package-summary.html) but could not find any reachability metadata for it. @@ -335,6 +326,17 @@ More precisely, this mode reduces the number of optimizations performed by the G The quick build mode is not only useful for development, it can also cause the generated executable file to be smaller in size. Note, however, that the overall peak throughput of the executable may be lower due to the reduced number of optimizations. +#### `INIT`: Use the Strict Image Heap Configuration + +Start using `--strict-image-heap` to reduce the amount of configuration and prepare for future GraalVM releases where this will be the default. +This mode requires only the classes that are stored in the image heap to be marked with `--initialize-at-build-time`. +This effectively reduces the number of configuration entries necessary to achieve build-time initialization. +When adopting the new mode it is best to start introducing build-time initialization from scratch. +During this process, it is best to select individual classes (as opposed to whole packages) for build time initialization. +Also, before migrating to the new flag make sure to update all framework dependencies to the latest versions as they might need to migrate too. + +> Note that `--strict-image-heap` is enabled by default in Native Image starting from GraalVM for JDK 22. + ## Resource Usage Statistics #### Garbage Collections diff --git a/docs/reference-manual/native-image/ReachabilityMetadata.md b/docs/reference-manual/native-image/ReachabilityMetadata.md index a26efac569a0..3263fef98384 100644 --- a/docs/reference-manual/native-image/ReachabilityMetadata.md +++ b/docs/reference-manual/native-image/ReachabilityMetadata.md @@ -28,7 +28,7 @@ Metadata can be provided to the `native-image` builder in the following ways: > Note: Native Image is migrating to the more user-friendly implementation of reachability metadata that shows problems early on and allows easy debugging. > -> To enable the new user-friendly reachability-metadata mode for your application pass the option `--exact-reachability-metadata` at build time. To enable the user-friendly mode only for concrete packages, pass `--exact-reachability-metadata=`. +> To enable the new user-friendly reachability-metadata mode for your application, pass the option `--exact-reachability-metadata` at build time. To enable the user-friendly mode only for concrete packages, pass `--exact-reachability-metadata=`. > > To get an overview of all places in your code where missing registrations occur, without committing to the exact behavior, you can pass `-XX:MissingRegistrationReportingMode=Warn` when starting the application. > diff --git a/docs/reference-manual/native-image/guides/specify-class-initialization.md b/docs/reference-manual/native-image/guides/specify-class-initialization.md index dcf4ec818eb9..4d8e67f91582 100644 --- a/docs/reference-manual/native-image/guides/specify-class-initialization.md +++ b/docs/reference-manual/native-image/guides/specify-class-initialization.md @@ -22,7 +22,7 @@ If you want only class `C1` in package `p` to be initialized at runtime, use: You can also programmatically specify class initialization using the [`RuntimeClassInitialization`] class (https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java) from the [Native Image Feature interface](https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/Feature.java). -This guide demonstrates how to build a native executable by running the class initializer at runtime (default behavior), and then at build time, and compares the two approaches. +This guide demonstrates how to build a native executable by running the class initializer at runtime (default behavior), and then at build time, and compares the two approaches. ### Prerequisite Make sure you have installed a GraalVM JDK. @@ -103,7 +103,7 @@ The parser creates records and adds them to a `List` collection. native-image --initialize-at-build-time=TalkParser,Talk -o buildtime-parser TalkParser ``` - If your application adds additional types to the executable heap, each type (or the corresponding package) needs to be marked for build-time initialization explicitly to fulfill the requirements of `--strict-image-heap`. + If your application adds additional types to the image heap, each type (or the corresponding package) needs to be marked for build-time initialization explicitly. An appropriate actionable error message will guide you through the process. 6. Run and `time` the second executable for comparison: diff --git a/docs/reference-manual/native-image/guides/troubleshoot-run-time-errors.md b/docs/reference-manual/native-image/guides/troubleshoot-run-time-errors.md index 2f54f16a58ff..7445ecbcfd73 100644 --- a/docs/reference-manual/native-image/guides/troubleshoot-run-time-errors.md +++ b/docs/reference-manual/native-image/guides/troubleshoot-run-time-errors.md @@ -12,7 +12,7 @@ In this guide, some reasons for that are shown, along with the strategies to dia Note that sometimes upgrading to the latest version of GraalVM can already resolve an issue. -## 1. Diagnose Missing Metadata Registration +### 1. Diagnose Missing Metadata Registration Start by diagnosing if there is any metadata configuration missing. Native Image requires all utilized classes to be known during the build. @@ -31,39 +31,39 @@ This can be avoided by eagerly checking for missing metadata. 4. Then restart the native executable with `-XX:MissingRegistrationReportingMode=Exit` to detect places where the application accidentally ignores a missing registration error (with `catch (Throwable t)` blocks). The application will then unconditionally print the error message with the stack trace and exit immediately. This behavior is ideal for running application tests to guarantee all metadata is included. -### Shared Libraries +#### Shared Libraries For diagnosing shared libraries built with Native Image, you can either: * specify `-R:MissingRegistrationReportingMode=Exit` when building a native shared library; * or specify `-XX:MissingRegistrationReportingMode=Exit` when the isolate is created. `graal_create_isolate_params_t` has `argc (_reserved_1)` and `argv (_reserved_2)` fields that can be used to pass C-style command-line options at run time. However, note that both fields are currently not public APIs. -## 2. Set java.home Explicitly +### 2. Set java.home Explicitly If your application code uses the `java.home` property, set it explicitly with `-Djava.home=` when running a native executable. Otherwise, the `System.getProperty("java.home")` call will return a `null` value. -## 3. Enable URL Protocols +### 3. Enable URL Protocols Try enabling all URL protocols on-demand at build time: `--enable-url-protocols=`. To enable the HTTPS support only, pass `--enable-https`. -## 4. Enable Signal Handling +### 4. Enable Signal Handling If your application is using signal handling or the `java.lang.Terminator` exit handlers, provide the option `--install-exit-handlers` option at build time. -## 5. Include All Charsets and Locales +### 5. Include All Charsets and Locales Other handy options are `-H:+AddAllCharsets` to add charsets support, and `-H:+IncludeAllLocales` to pre-initialize support for locale-sensitive behavior in the `java.util` and `java.text` packages. Pass those options at build time. This might increase the size of the resulting binary. -## 6. Add Missing Security Providers +### 6. Add Missing Security Providers If your application is using Security Providers, try to pre-initialize security providers by passing the option `-H:AdditionalSecurityProviders=` at build time. Here is a list of all JDK security providers to choose from: `sun.security.provider.Sun,sun.security.rsa.SunRsaSign,sun.security.ec.SunEC,sun.security.ssl.SunJSSE,com.sun.crypto.provider.SunJCE,sun.security.jgss.SunProvider,com.sun.security.sasl.Provider,org.jcp.xml.dsig.internal.dom.XMLDSigRI,sun.security.smartcardio.SunPCSC,sun.security.provider.certpath.ldap.JdkLDAP,com.sun.security.sasl.gsskerb.JdkSASL`. -## 7. File a Native Image Run-Time Issue +### 7. File a Native Image Run-Time Issue Only if you tried all the above suggestions, file a [Native Image Run-Time Issue Report](https://github.com/oracle/graal/issues/new?assignees=&labels=native-image%2Cbug%2Crun-time&projects=&template=1_1_native_image_run_time_bug_report.yml&title=%5BNative+Image%5D+) at GitHub, filling out the necessary information. From 5ea3027ca9e490b41313abb90d62435d61fb79c5 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Mon, 21 Oct 2024 14:21:18 +0200 Subject: [PATCH 078/105] Make it possible to use EXTRA_IMAGE_BUILDER_ARGUMENTS in env files * compute it in infer_env * show it in graalvm-show --print-env * show such extra options in the list of images of graalvm-show * allow more than one option to be passed by separating options with commas. --- sdk/mx.sdk/mx_sdk_vm_impl.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index af9e52f98b10..40f57e049ae3 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -4080,7 +4080,9 @@ def _infer_env(graalvm_dist): if isinstance(non_rebuildable_images, bool): non_rebuildable_images = [str(non_rebuildable_images)] - return sorted(list(dynamicImports)), sorted(components), sorted(excludeComponents), sorted(nativeImages), sorted(disableInstallables), sorted(non_rebuildable_images), _debuginfo_dists(), _no_licenses() + extra_image_builder_args = _parse_cmd_arg('extra_image_builder_argument', env_var_name='EXTRA_IMAGE_BUILDER_ARGUMENTS', separator=None, parse_bool=False) or [] + + return sorted(list(dynamicImports)), sorted(components), sorted(excludeComponents), sorted(nativeImages), sorted(disableInstallables), sorted(non_rebuildable_images), _debuginfo_dists(), _no_licenses(), sorted(extra_image_builder_args) def graalvm_clean_env(out_env=None): @@ -4103,7 +4105,7 @@ def graalvm_env(out_env=None): """ env = out_env or os.environ.copy() graalvm_dist = get_final_graalvm_distribution() - dynamicImports, components, exclude_components, nativeImages, disableInstallables, non_rebuildable_images, debuginfo_dists, noLicenses = _infer_env(graalvm_dist) + dynamicImports, components, exclude_components, nativeImages, disableInstallables, non_rebuildable_images, debuginfo_dists, noLicenses, extra_image_builder_args = _infer_env(graalvm_dist) env['GRAALVM_HOME'] = graalvm_home() @@ -4113,6 +4115,7 @@ def graalvm_env(out_env=None): env['EXCLUDE_COMPONENTS'] = ','.join(exclude_components) env['DISABLE_INSTALLABLES'] = ','.join(disableInstallables) env['NON_REBUILDABLE_IMAGES'] = ','.join(non_rebuildable_images) + env['EXTRA_IMAGE_BUILDER_ARGUMENTS'] = ' '.join(extra_image_builder_args) if debuginfo_dists: env['DEBUGINFO_DISTS'] = 'true' if noLicenses: @@ -4212,9 +4215,13 @@ def graalvm_show(args, forced_graalvm_dist=None): print("Launchers:") for launcher in sorted(launchers, key=lambda l: l.native_image_name): suffix = '' - profile_cnt = len(_image_profiles(GraalVmNativeProperties.canonical_image_name(launcher.native_image_config))) + name = GraalVmNativeProperties.canonical_image_name(launcher.native_image_config) + profile_cnt = len(_image_profiles(name)) if profile_cnt > 0: suffix += " ({} pgo profile file{})".format(profile_cnt, 's' if profile_cnt > 1 else '') + extra_args = _extra_image_builder_args(name) + if extra_args: + suffix += " (" + mx.list_to_cmd_line(extra_args) + ")" print(" - {name} ({native}, {rebuildable}){suffix}".format( name=launcher.native_image_name, native="native" if launcher.is_native() else "bash", @@ -4237,9 +4244,13 @@ def graalvm_show(args, forced_graalvm_dist=None): suffix += "rebuildable)" else: suffix += "non-rebuildable)" - profile_cnt = len(_image_profiles(GraalVmNativeProperties.canonical_image_name(library.native_image_config))) + name = GraalVmNativeProperties.canonical_image_name(library.native_image_config) + profile_cnt = len(_image_profiles(name)) if profile_cnt > 0: suffix += " ({} pgo profile file{})".format(profile_cnt, 's' if profile_cnt > 1 else '') + extra_args = _extra_image_builder_args(name) + if extra_args: + suffix += " (" + mx.list_to_cmd_line(extra_args) + ")" print(" - {name}{suffix}".format( name=library.native_image_name, suffix=suffix)) @@ -4297,17 +4308,18 @@ def graalvm_show(args, forced_graalvm_dist=None): print(f"Dependencies of the '{dist_name}' distribution:\n -", '\n - '.join(sorted(dep.name for dep in dist.deps))) if args.print_env: - def _print_env(name, val): + def _print_env(name, val, separator=','): if val: - print(name + '=' + ','.join(val)) + print(name + '=' + separator.join(val)) print('Inferred env file:') - dynamic_imports, components, exclude_components, native_images, disable_installables, non_rebuildable_images, debuginfo_dists, no_licenses = _infer_env(graalvm_dist) + dynamic_imports, components, exclude_components, native_images, disable_installables, non_rebuildable_images, debuginfo_dists, no_licenses, extra_image_builder_args = _infer_env(graalvm_dist) _print_env('DYNAMIC_IMPORTS', dynamic_imports) _print_env('COMPONENTS', components) _print_env('EXCLUDE_COMPONENTS', exclude_components) _print_env('NATIVE_IMAGES', native_images) _print_env('DISABLE_INSTALLABLES', disable_installables) _print_env('NON_REBUILDABLE_IMAGES', non_rebuildable_images) + _print_env('EXTRA_IMAGE_BUILDER_ARGUMENTS', extra_image_builder_args, separator=' ') if debuginfo_dists: print('DEBUGINFO_DISTS=true') if no_licenses: @@ -4520,7 +4532,8 @@ def _extra_image_builder_args(image): prefix = image + ':' prefix_len = len(prefix) args = [] - extra_args = _parse_cmd_arg('extra_image_builder_argument', env_var_name='EXTRA_IMAGE_BUILDER_ARGUMENTS', separator=None, parse_bool=False, default_value='') + # separator=None means any whitespace and there will be no empty elements + extra_args = _parse_cmd_arg('extra_image_builder_argument', env_var_name='EXTRA_IMAGE_BUILDER_ARGUMENTS', separator=None, parse_bool=False) or [] for arg in extra_args: if arg.startswith(prefix): args.append(arg[prefix_len:]) From e27de1bacfa8c211e535a151f63427357d870ae3 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Mon, 21 Oct 2024 14:31:57 +0200 Subject: [PATCH 079/105] Avoid adding TRUFFLE_NFI_PANAMA on jdk>21 graalvms --- truffle/mx.truffle/mx_truffle.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/truffle/mx.truffle/mx_truffle.py b/truffle/mx.truffle/mx_truffle.py index d4050dd5a6dc..31d3c3086973 100644 --- a/truffle/mx.truffle/mx_truffle.py +++ b/truffle/mx.truffle/mx_truffle.py @@ -1777,6 +1777,9 @@ def clean(self, forBuild=False): ) mx_sdk_vm.register_graalvm_component(truffle_nfi_component) +_libffi_jars = ['truffle:TRUFFLE_NFI_LIBFFI'] +if mx.get_jdk().javaCompliance >= "22": + _libffi_jars += ['truffle:TRUFFLE_NFI_PANAMA'] mx_sdk_vm.register_graalvm_component(mx_sdk_vm.GraalVmLanguage( suite=_suite, name='Truffle NFI LIBFFI', @@ -1785,7 +1788,7 @@ def clean(self, forBuild=False): license_files=[], third_party_license_files=[], dependencies=['Truffle NFI'], - truffle_jars=['truffle:TRUFFLE_NFI_LIBFFI', 'truffle:TRUFFLE_NFI_PANAMA'], + truffle_jars=_libffi_jars, installable=False, stability="supported", )) From 530ce0a5009c02d34dc3f57c2f931c1bfa4a0d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Wed, 23 Oct 2024 13:39:45 +0200 Subject: [PATCH 080/105] Ensure ForkJoin commonPool parallelism always respects NativeImageOptions.NumberOfThreads --- substratevm/CHANGELOG.md | 1 + .../oracle/svm/hosted/NativeImageOptions.java | 44 +++++++++---------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 7cd24cfb122f..6fcfce6e8539 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -13,6 +13,7 @@ At runtime, premain runtime options are set along with main class' arguments in * (GR-58000) Support for `GetStringUTFLengthAsLong` added in JNI_VERSION_24 ([JDK-8328877](https://bugs.openjdk.org/browse/JDK-8328877)) * (GR-58383) The length of the printed stack trace when using `-XX:MissingRegistrationReportingMode=Warn` can now be set with `-XX:MissingRegistrationWarnContextLines=` and its default length is now 8. * (GR-58914) `ActiveProcessorCount` must be set at isolate or VM creation time. +* (GR-59326) Ensure builder ForkJoin commonPool parallelism always respects NativeImageOptions.NumberOfThreads. ## GraalVM for JDK 23 (Internal Version 24.1.0) * (GR-51520) The old class initialization strategy, which was deprecated in GraalVM for JDK 22, is removed. The option `StrictImageHeap` no longer has any effect. diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageOptions.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageOptions.java index 1d3446610fcd..fe3cb0f92f23 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageOptions.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageOptions.java @@ -38,9 +38,9 @@ import com.oracle.graal.pointsto.reports.ReportUtils; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.option.APIOption; +import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue; import com.oracle.svm.core.option.BundleMember; import com.oracle.svm.core.option.HostedOptionKey; -import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue; import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.UserError; @@ -214,28 +214,26 @@ public static int getActualNumberOfThreads() { } public static void setCommonPoolParallelism(OptionValues optionValues) { - if (NativeImageOptions.NumberOfThreads.hasBeenSet(optionValues)) { - /* - * The main thread always helps to process tasks submitted to the common pool (e.g., see - * ForkJoinPool#awaitTermination()), so subtract one from the number of threads. The - * common pool can be disabled "by setting the parallelism property to zero" (see - * ForkJoinPool's javadoc). - */ - int numberOfCommonPoolThreads = NativeImageOptions.NumberOfThreads.getValue(optionValues) - 1; - String commonPoolParallelismProperty = "java.util.concurrent.ForkJoinPool.common.parallelism"; - assert System.getProperty(commonPoolParallelismProperty) == null : commonPoolParallelismProperty + " already set"; - System.setProperty(commonPoolParallelismProperty, "" + numberOfCommonPoolThreads); - int actualCommonPoolParallelism = ForkJoinPool.commonPool().getParallelism(); - /* - * getParallelism() returns at least 1, even in single-threaded mode where common pool - * is disabled. - */ - boolean isSingleThreadedMode = numberOfCommonPoolThreads == 0 && actualCommonPoolParallelism == 1; - if (!isSingleThreadedMode && actualCommonPoolParallelism != numberOfCommonPoolThreads) { - String warning = "Failed to set parallelism of common pool (actual parallelism is %s).".formatted(actualCommonPoolParallelism); - assert false : warning; - LogUtils.warning(warning); - } + /* + * The main thread always helps to process tasks submitted to the common pool (e.g., see + * ForkJoinPool#awaitTermination()), so subtract one from the number of threads. The common + * pool can be disabled "by setting the parallelism property to zero" (see ForkJoinPool's + * javadoc). + */ + int numberOfCommonPoolThreads = NativeImageOptions.NumberOfThreads.getValueOrDefault(optionValues.getMap()) - 1; + String commonPoolParallelismProperty = "java.util.concurrent.ForkJoinPool.common.parallelism"; + assert System.getProperty(commonPoolParallelismProperty) == null : commonPoolParallelismProperty + " already set"; + System.setProperty(commonPoolParallelismProperty, "" + numberOfCommonPoolThreads); + int actualCommonPoolParallelism = ForkJoinPool.commonPool().getParallelism(); + /* + * getParallelism() returns at least 1, even in single-threaded mode where common pool is + * disabled. + */ + boolean isSingleThreadedMode = numberOfCommonPoolThreads == 0 && actualCommonPoolParallelism == 1; + if (!isSingleThreadedMode && actualCommonPoolParallelism != numberOfCommonPoolThreads) { + String warning = "Failed to set parallelism of common pool (actual parallelism is %s).".formatted(actualCommonPoolParallelism); + assert false : warning; + LogUtils.warning(warning); } } From f6ba52203dacdfa7db3214ffd5354f34baecda57 Mon Sep 17 00:00:00 2001 From: Gilles Duboscq Date: Mon, 14 Oct 2024 17:06:40 +0200 Subject: [PATCH 081/105] Fix interacting with non-llvm JNI libraries when using nfi-llvm When a library without bytecode is loaded through nfi's llvm backend, it will fallback to loading it through nfi's libffi backend. Those symbols cannot be used with signature created "with llvm". With these changes, we make sure that we only use "with llvm" signatures for symbols that are actually from llvm bitcode libraries. Another issue with using libffi" JNI libraries while we are using the nfi-llvm library is that libffi doesn't support variadic closures (libffi/libffi#388). As a result JNI's variadic closures cannot be used accross the native->managed boundary, they can rather be native closures called from native code or llvm closures called from llvm bitcode. As a result, in nfi-llvm mode, we might need to create a "libffi" JniEnv by loading nespresso through the "libffi" nfi backend. Many changes are aimed at making the JNI less central in order to support having 2 JniEnvs. --- .../src/mokapot.c | 2 +- .../include/nespresso.h | 1 - .../src/nespresso.c | 16 +- .../processor/NativeEnvProcessor.java | 2 +- .../espresso/processor/StructsProcessor.java | 26 +- .../truffle/espresso/EspressoLanguage.java | 19 +- .../truffle/espresso/ffi/NativeAccess.java | 69 +++- .../ffi/nfi/NFIIsolatedNativeAccess.java | 8 +- .../espresso/ffi/nfi/NFINativeAccess.java | 99 ++--- .../ffi/nfi/NFISulongNativeAccess.java | 86 ++++- .../ffi/nfi/NFISulongSignatureCallNode.java | 80 ++++ .../oracle/truffle/espresso/impl/Method.java | 42 +- .../truffle/espresso/jni/JNIHandles.java | 14 +- .../oracle/truffle/espresso/jni/JniEnv.java | 365 ++++++++---------- .../truffle/espresso/jni/NativeEnv.java | 52 +-- .../espresso/nodes/EspressoRootNode.java | 5 +- .../espresso/nodes/NativeMethodNode.java | 46 +-- .../espresso/runtime/AgentLibraries.java | 12 +- .../espresso/runtime/EspressoContext.java | 35 +- .../runtime/panama/DowncallStubNode.java | 2 +- .../runtime/panama/DowncallStubs.java | 23 +- .../substitutions/CallableFromNative.java | 3 +- .../substitutions/Target_sun_misc_Unsafe.java | 15 +- .../com/oracle/truffle/espresso/vm/VM.java | 17 +- .../vm/structs/JavaMemberOffsetGetter.java | 10 +- .../espresso/vm/structs/StructStorage.java | 8 +- .../espresso/vm/structs/StructWrapper.java | 9 +- .../espresso/vm/structs/StructsAccess.java | 5 +- 28 files changed, 621 insertions(+), 450 deletions(-) create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFISulongSignatureCallNode.java 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 b09110ac6bd0..f9b9d6668230 100644 --- a/espresso/src/com.oracle.truffle.espresso.mokapot/src/mokapot.c +++ b/espresso/src/com.oracle.truffle.espresso.mokapot/src/mokapot.c @@ -79,7 +79,6 @@ JNIEXPORT void mokapotCaptureState(int32_t* addr, jint mask) { JNIEXPORT MokapotEnv* JNICALL initializeMokapotContext(JNIEnv* env, void* (*fetch_by_name)(const char *, void*)) { - MokapotEnv *moka_env = (MokapotEnv *) malloc(sizeof(*moka_env)); struct MokapotNativeInterface_ *functions = (struct MokapotNativeInterface_*) malloc(sizeof(*functions)); @@ -96,6 +95,7 @@ JNIEXPORT MokapotEnv* JNICALL initializeMokapotContext(JNIEnv* env, void* (*fetc java_vm_functions->reserved2 = NULL; // Store the MokapotEnv* in the JNIEnv*. + // This is read in nespresso's GetJavaVM struct JNINativeInterface_* tmp = (struct JNINativeInterface_*) *env; tmp->reserved1 = (void*) moka_env; diff --git a/espresso/src/com.oracle.truffle.espresso.native/include/nespresso.h b/espresso/src/com.oracle.truffle.espresso.native/include/nespresso.h index 76534a3355ac..5d7f7324732f 100644 --- a/espresso/src/com.oracle.truffle.espresso.native/include/nespresso.h +++ b/espresso/src/com.oracle.truffle.espresso.native/include/nespresso.h @@ -49,7 +49,6 @@ JNIEXPORT void * JNICALL allocateMemory(size_t size); JNIEXPORT void JNICALL freeMemory(void *ptr); JNIEXPORT void * JNICALL reallocateMemory(void *ptr, size_t new_size); JNIEXPORT void JNICALL ctypeInit(void); -JNIEXPORT jlong JNICALL get_SIZE_MAX(); #define JNI_FUNCTION_LIST(V) \ V(GetVersion) \ diff --git a/espresso/src/com.oracle.truffle.espresso.native/src/nespresso.c b/espresso/src/com.oracle.truffle.espresso.native/src/nespresso.c index 74c877fe7fbb..85df2efc9793 100644 --- a/espresso/src/com.oracle.truffle.espresso.native/src/nespresso.c +++ b/espresso/src/com.oracle.truffle.espresso.native/src/nespresso.c @@ -125,7 +125,7 @@ struct VarargsA { static jboolean valist_pop_boolean(struct Varargs* varargs) { struct VarargsV* v = (struct VarargsV*) varargs; - return (jboolean) (va_arg(v->args, jint) == 0 ? JNI_FALSE : JNI_TRUE); + return va_arg(v->args, jint) == 0 ? JNI_FALSE : JNI_TRUE; } static jbyte valist_pop_byte(struct Varargs* varargs) { @@ -145,7 +145,7 @@ static jshort valist_pop_short(struct Varargs* varargs) { static jint valist_pop_int(struct Varargs* varargs) { struct VarargsV* v = (struct VarargsV*) varargs; - return (jint) va_arg(v->args, jint); + return va_arg(v->args, jint); } static jfloat valist_pop_float(struct Varargs* varargs) { @@ -155,22 +155,22 @@ static jfloat valist_pop_float(struct Varargs* varargs) { static jdouble valist_pop_double(struct Varargs* varargs) { struct VarargsV* v = (struct VarargsV*) varargs; - return (jdouble) va_arg(v->args, jdouble); + return va_arg(v->args, jdouble); } static jlong valist_pop_long(struct Varargs* varargs) { struct VarargsV* v = (struct VarargsV*) varargs; - return (jlong) va_arg(v->args, jlong); + return va_arg(v->args, jlong); } static jobject valist_pop_object(struct Varargs* varargs) { struct VarargsV* v = (struct VarargsV*) varargs; - return (jobject) va_arg(v->args, jobject); + return va_arg(v->args, jobject); } static void* valist_pop_word(struct Varargs* varargs) { struct VarargsV* v = (struct VarargsV*) varargs; - return (void*) va_arg(v->args, void*); + return va_arg(v->args, void*); } // jvalue* varargs impl @@ -578,7 +578,3 @@ JNIEXPORT void JNICALL freeMemory(void *ptr) { JNIEXPORT void * JNICALL reallocateMemory(void *ptr, size_t new_size) { return realloc(ptr, new_size); } - -JNIEXPORT jlong JNICALL get_SIZE_MAX() { - return (jlong) SIZE_MAX; -} diff --git a/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/NativeEnvProcessor.java b/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/NativeEnvProcessor.java index 467dce020cf8..127ab3ec53b6 100644 --- a/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/NativeEnvProcessor.java +++ b/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/NativeEnvProcessor.java @@ -458,7 +458,7 @@ ClassBuilder generateInvoke(ClassBuilder classBuilder, String className, String .withOverrideAnnotation() // .withModifiers(new ModifierBuilder().asPublic().asFinal()) // .withReturnType("Object") // - .withParams("Object " + ENV_ARG_NAME, "Object[] " + ARGS_NAME); + .withParams("com.oracle.truffle.espresso.jni.NativeEnv " + ENV_ARG_NAME, "Object[] " + ARGS_NAME); if (!h.skipSafepoint) { invoke.addBodyLine(EspressoProcessor.SAFEPOINT_POLL); } diff --git a/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/StructsProcessor.java b/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/StructsProcessor.java index 2ffe5cff6939..813ca3ae595c 100644 --- a/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/StructsProcessor.java +++ b/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/StructsProcessor.java @@ -79,13 +79,13 @@ public class StructsProcessor extends AbstractProcessor { // Imports private static final String IMPORT_BYTEBUFFER = "java.nio.ByteBuffer"; - private static final String IMPORT_JNI_ENV = "com.oracle.truffle.espresso.jni.JniEnv"; + private static final String IMPORT_JNI_HANDLES = "com.oracle.truffle.espresso.jni.JNIHandles"; private static final String IMPORT_RAW_POINTER = "com.oracle.truffle.espresso.ffi.RawPointer"; // Classes private static final String TRUFFLE_OBJECT = "TruffleObject"; private static final String INTEROP_LIBRARY = "InteropLibrary"; - private static final String JNI_ENV_CLASS = "JniEnv"; + private static final String JNI_HANDLES_CLASS = "JNIHandles"; private static final String MEMBER_OFFSET_GETTER_CLASS = "MemberOffsetGetter"; private static final String NATIVE_MEMBER_OFFSET_GETTER_CLASS = "NativeMemberOffsetGetter"; private static final String JAVA_MEMBER_OFFSET_GETTER_CLASS = "JavaMemberOffsetGetter"; @@ -105,7 +105,7 @@ public class StructsProcessor extends AbstractProcessor { // Arguments private static final String VALUE = "valueToPut"; - private static final String JNI_ENV_ARG = "jni"; + private static final String JNI_HANDLES_ARG = "handles"; private static final String PTR = "pointer"; private static final String MEMBER_OFFSET_GETTER_ARG = "offsetGetter"; private static final String MEMBER_INFO_PTR = "memberInfoPtr"; @@ -256,7 +256,7 @@ private static String generateStruct(String strName, List members, List< .inPackage(STRUCTS_PACKAGE) // .withImportGroup(Collections.singletonList(IMPORT_BYTEBUFFER)) // .withImportGroup(Collections.singletonList(IMPORT_TRUFFLE_OBJECT)) // - .withImportGroup(Arrays.asList(IMPORT_STATIC_OBJECT, IMPORT_JNI_ENV, IMPORT_RAW_POINTER)); + .withImportGroup(Arrays.asList(IMPORT_STATIC_OBJECT, IMPORT_JNI_HANDLES, IMPORT_RAW_POINTER)); String wrapperName = className + WRAPPER; @@ -312,8 +312,8 @@ private static void generateWrapper(ClassBuilder struct, List members, L MethodBuilder wrapperConstructor = new MethodBuilder(wrapperName) // .asConstructor() // - .withParams(argument(JNI_ENV_CLASS, JNI_ENV_ARG), argument(TRUFFLE_OBJECT, PTR)) // - .addBodyLine(call(null, "super", new String[]{JNI_ENV_ARG, PTR, STRUCT_SIZE}), ';'); + .withParams(argument(JNI_HANDLES_CLASS, JNI_HANDLES_ARG), argument(TRUFFLE_OBJECT, PTR)) // + .addBodyLine(call(null, "super", new String[]{JNI_HANDLES_ARG, PTR, STRUCT_SIZE}), ';'); wrapper.withMethod(wrapperConstructor); for (int i = 0; i < length; i++) { @@ -344,8 +344,8 @@ private static void generateWrapMethod(ClassBuilder struct, String wrapperClass) .withOverrideAnnotation() // .withModifiers(new ModifierBuilder().asPublic()) // .withReturnType(wrapperClass) // - .withParams(argument(JNI_ENV_CLASS, JNI_ENV_ARG), argument(TRUFFLE_OBJECT, PTR)) // - .addBodyLine("return new ", call(null, wrapperClass, new String[]{JNI_ENV_ARG, PTR}), ';'); + .withParams(argument(JNI_HANDLES_CLASS, JNI_HANDLES_ARG), argument(TRUFFLE_OBJECT, PTR)) // + .addBodyLine("return new ", call(null, wrapperClass, new String[]{JNI_HANDLES_ARG, PTR}), ';'); struct.withMethod(wrapMethod); } @@ -354,13 +354,13 @@ private static String generateStructCollector(List structs) { .withCopyright() // .inPackage(STRUCTS_PACKAGE) // .withImportGroup(Arrays.asList(IMPORT_INTEROP_LIBRARY, IMPORT_TRUFFLE_OBJECT)) // - .withImportGroup(Collections.singletonList(IMPORT_JNI_ENV)); + .withImportGroup(Collections.singletonList(IMPORT_JNI_HANDLES)); ClassBuilder structCollector = new ClassBuilder(STRUCTS_CLASS) // .withQualifiers(new ModifierBuilder().asPublic().asFinal()); generateCollectorFieldDeclaration(structCollector, structs); - generateColectorConstructor(structCollector, structs); + generateCollectorConstructor(structCollector, structs); structCollectorFile.withClass(structCollector); return structCollectorFile.build(); @@ -372,11 +372,11 @@ private static void generateCollectorFieldDeclaration(ClassBuilder collector, Li } } - private static void generateColectorConstructor(ClassBuilder collector, List structs) { + private static void generateCollectorConstructor(ClassBuilder collector, List structs) { MethodBuilder constructor = new MethodBuilder(STRUCTS_CLASS) // .asConstructor() // .withModifiers(new ModifierBuilder().asPublic()) // - .withParams(argument(JNI_ENV_CLASS, JNI_ENV_ARG), argument(TRUFFLE_OBJECT, MEMBER_INFO_PTR), argument(TRUFFLE_OBJECT, LOOKUP_MEMBER_OFFSET)) // + .withParams(argument(JNI_HANDLES_CLASS, JNI_HANDLES_ARG), argument(TRUFFLE_OBJECT, MEMBER_INFO_PTR), argument(TRUFFLE_OBJECT, LOOKUP_MEMBER_OFFSET)) // .addBodyLine(INTEROP_LIBRARY, ' ', assignment(LIBRARY, call(INTEROP_LIBRARY, GET_UNCACHED, EMPTY_ARGS))) // .addBodyLine(MEMBER_OFFSET_GETTER_CLASS, ' ', assignment(MEMBER_OFFSET_GETTER_ARG, "new " + call(null, NATIVE_MEMBER_OFFSET_GETTER_CLASS, new String[]{LIBRARY, MEMBER_INFO_PTR, LOOKUP_MEMBER_OFFSET}))); @@ -395,7 +395,7 @@ private static void generateOptionalMemberInfo(MethodBuilder constructor, List + * Some implementations might not be able to load native libraries in the mode they expect + * (e.g., the sulong native access might not be able to find bitcode in a library). When that + * happens the libraries will still work but return fallback symbols (e.g., in that case sulong + * would return libffi symbols). Callable signatures for such symbols must be prepared specially + * by passing true to the forFallbackSymbol parameter of + * {@link #getCallableSignature} because signature only work for a specific type of symbol + * (GR-37607). + * + * @param symbol a symbol obtained from {@link #lookupSymbol}. + */ + boolean isFallbackSymbol(TruffleObject symbol); + + /** + * If the current native access has a {@link #isFallbackSymbol fallback mode}, this provides a + * native access that works like the fallback mode. + *

    + * This can be used to load a {@link com.oracle.truffle.espresso.jni.NativeEnv} with the + * fallback access in case it is necessary to provide a fallback environment for libraries with + * fallback symbols. This is necessary when a native env containing variadic function pointers + * is passed to a fallback symbol (see libffi/libffi#388). + * + * @return a native access that corresponds to the way fallback symbols are implemented if the + * current native access {@linkplain #hasFallbackSymbols() has fallback symbols}, + * null otherwise. + */ + NativeAccess getFallbackAccess(); Object callSignature(Object signature, @Pointer TruffleObject symbol, Object... args) throws UnsupportedMessageException, UnsupportedTypeException, ArityException; - SignatureCallNode createSignatureCall(NativeSignature nativeSignature, boolean fromJava); + SignatureCallNode createSignatureCall(NativeSignature nativeSignature); default @Pointer TruffleObject lookupAndBindSymbol(@Pointer TruffleObject library, String symbolName, NativeSignature nativeSignature) { + return lookupAndBindSymbol(library, symbolName, nativeSignature, false, false); + } + + default @Pointer TruffleObject lookupAndBindSymbol(@Pointer TruffleObject library, String symbolName, NativeSignature nativeSignature, boolean allowFallback, boolean allowMissing) { @Pointer TruffleObject symbol = lookupSymbol(library, symbolName); if (symbol == null) { + if (!allowMissing) { + throw EspressoError.shouldNotReachHere("Failed to locate required symbol: " + symbolName); + } // not found return null; } + if (!allowFallback && isFallbackSymbol(symbol)) { + String message = "Unexpected fallback symbol: " + symbolName + "\n" + + "A likely explanation is that a core espresso library was expected to contain bitcode but it doesn't.\n" + + "Core JDK libraries with LLVM bitcode are currently only available on linux-amd64 and darwin-amd64.\n" + + "On linux-aarch64 you could instead try to set `java.NativeBackend` to `nfi-dlmopen`."; + if (EspressoOptions.RUNNING_ON_SVM) { + message += "\nIn a native-image, if a single espresso context is used, it's recommended to use the `nfi-native` backend."; + } else { + message += "\nOn other platforms, you can try to run your embedding of espresso as a native-image if a single espresso context is used."; + } + throw EspressoError.shouldNotReachHere(message); + } return bindSymbol(symbol, nativeSignature); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFIIsolatedNativeAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFIIsolatedNativeAccess.java index c5f9b97d11bb..0fc2560fb303 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFIIsolatedNativeAccess.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFIIsolatedNativeAccess.java @@ -176,7 +176,7 @@ Object toDisplayString(boolean allowSideEffects) { } try { @Pointer - TruffleObject address = (TruffleObject) uncachedInterop.execute(malloc, size); + TruffleObject address = (TruffleObject) UNCACHED_INTEROP.execute(malloc, size); if (InteropLibrary.getUncached().isNull(address)) { // malloc returned NULL return null; @@ -192,7 +192,7 @@ Object toDisplayString(boolean allowSideEffects) { public void freeMemory(@Pointer TruffleObject buffer) { assert InteropLibrary.getUncached().isPointer(buffer); try { - uncachedInterop.execute(free, buffer); + UNCACHED_INTEROP.execute(free, buffer); } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); throw EspressoError.shouldNotReachHere(e); @@ -207,7 +207,7 @@ public void freeMemory(@Pointer TruffleObject buffer) { assert InteropLibrary.getUncached().isPointer(buffer); try { @Pointer - TruffleObject address = (TruffleObject) uncachedInterop.execute(realloc, buffer, newSize); + TruffleObject address = (TruffleObject) UNCACHED_INTEROP.execute(realloc, buffer, newSize); if (InteropLibrary.getUncached().isNull(address)) { // realloc returned NULL return null; @@ -222,7 +222,7 @@ public void freeMemory(@Pointer TruffleObject buffer) { @Override public void prepareThread() { try { - uncachedInterop.execute(ctypeInit); + UNCACHED_INTEROP.execute(ctypeInit); } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); throw EspressoError.shouldNotReachHere(e); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFINativeAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFINativeAccess.java index 5e107de29270..2c2c4ec82f0d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFINativeAccess.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFINativeAccess.java @@ -72,20 +72,14 @@ * its own (nfi-native backend) and also serves as base for other NFI backends. */ public class NFINativeAccess implements NativeAccess { - + protected static final TruffleLogger LOGGER = TruffleLogger.getLogger(EspressoLanguage.ID, NFINativeAccess.class); + protected static final InteropLibrary UNCACHED_INTEROP = InteropLibrary.getUncached(); + protected static final SignatureLibrary UNCACHED_SIGNATURE = SignatureLibrary.getUncached(); private static final Unsafe UNSAFE = UnsafeAccess.get(); - private static final boolean CACHE_SIGNATURES = "true".equals(System.getProperty("espresso.nfi.cache_signatures", "true")); + private static final DebugCounter NFI_SIGNATURES_CREATED = DebugCounter.create("NFI signatures created"); - private final DebugCounter nfiSignaturesCreated = DebugCounter.create("NFI signatures created"); - - private final Map nativeSignatureCache; - private final Map javaSignatureCache; - - protected final InteropLibrary uncachedInterop = InteropLibrary.getUncached(); - protected final SignatureLibrary uncachedSignature = SignatureLibrary.getUncached(); - private final TruffleLogger logger = TruffleLogger.getLogger(EspressoLanguage.ID, NFINativeAccess.class); - + private final Map signatureCache; protected final TruffleLanguage.Env env; protected static String nfiType(NativeType nativeType) { @@ -109,7 +103,7 @@ protected static String nfiType(NativeType nativeType) { // @formatter:on } - protected String nfiStringSignature(NativeSignature nativeSignature, @SuppressWarnings("unused") boolean fromJava) { + protected String nfiStringSignature(NativeSignature nativeSignature, @SuppressWarnings("unused") boolean forFallbackSymbol) { StringBuilder sb = new StringBuilder(64); sb.append('('); boolean isFirst = true; @@ -129,31 +123,32 @@ protected String nfiStringSignature(NativeSignature nativeSignature, @SuppressWa return sb.toString(); } - protected final TruffleLogger getLogger() { - return logger; - } - - protected Object createNFISignature(NativeSignature nativeSignature, boolean fromJava) { - nfiSignaturesCreated.inc(); - Source source = Source.newBuilder("nfi", - nfiStringSignature(nativeSignature, fromJava), "signature").build(); + protected Object createNFISignature(NativeSignature nativeSignature, boolean forFallbackSymbol) { + NFI_SIGNATURES_CREATED.inc(); + Source source = Source.newBuilder("nfi", nfiStringSignature(nativeSignature, forFallbackSymbol), "signature").build(); CallTarget target = env.parseInternal(source); return target.call(); } - protected final Object getOrCreateNFISignature(NativeSignature nativeSignature, boolean fromJava) { - return CACHE_SIGNATURES - ? (fromJava ? javaSignatureCache.computeIfAbsent(nativeSignature, sig -> createNFISignature(nativeSignature, true)) - : nativeSignatureCache.computeIfAbsent(nativeSignature, sig -> createNFISignature(nativeSignature, false))) - : createNFISignature(nativeSignature, fromJava); + private record ClassifiedSignature(NativeSignature signature, boolean forFallbackSymbol) { + } + + protected final Object getOrCreateNFISignature(NativeSignature nativeSignature, boolean forFallbackSymbol) { + if (!CACHE_SIGNATURES) { + return createNFISignature(nativeSignature, forFallbackSymbol); + } + Object key; + if (hasFallbackSymbols()) { + key = new ClassifiedSignature(nativeSignature, forFallbackSymbol); + } else { + key = nativeSignature; + } + return signatureCache.computeIfAbsent(key, k -> createNFISignature(nativeSignature, forFallbackSymbol)); } NFINativeAccess(TruffleLanguage.Env env) { this.env = env; - javaSignatureCache = CACHE_SIGNATURES - ? new ConcurrentHashMap<>() - : null; - nativeSignatureCache = CACHE_SIGNATURES + signatureCache = CACHE_SIGNATURES ? new ConcurrentHashMap<>() : null; } @@ -190,13 +185,13 @@ private static boolean isExpectedException(AbstractTruffleException e) { return (TruffleObject) target.call(); } catch (IllegalArgumentException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); - getLogger().log(Level.SEVERE, "TruffleNFI native library isolation is not supported", e); + LOGGER.log(Level.SEVERE, "TruffleNFI native library isolation is not supported", e); throw EspressoError.shouldNotReachHere(e); } catch (AbstractTruffleException e) { // TODO(peterssen): Remove assert once GR-27045 reaches a definitive consensus. assert isExpectedException(e); // AbstractTruffleException is treated as if it were an UnsatisfiedLinkError. - getLogger().fine("AbstractTruffleException while loading library though NFI (" + nfiSource + ") : " + e.getMessage()); + LOGGER.fine("AbstractTruffleException while loading library though NFI (" + nfiSource + ") : " + e.getMessage()); return null; } } @@ -204,13 +199,13 @@ private static boolean isExpectedException(AbstractTruffleException e) { @Override public void unloadLibrary(@Pointer TruffleObject library) { // TODO(peterssen): NFI does not support unloading libraries eagerly. - getLogger().fine(String.format("JVM_UnloadLibrary: %x was not unloaded!", NativeUtils.interopAsPointer(library))); + LOGGER.fine(String.format("JVM_UnloadLibrary: %x was not unloaded!", NativeUtils.interopAsPointer(library))); } @Override public @Pointer TruffleObject lookupSymbol(@Pointer TruffleObject library, String symbolName) { try { - TruffleObject symbol = (TruffleObject) uncachedInterop.readMember(library, symbolName); + TruffleObject symbol = (TruffleObject) UNCACHED_INTEROP.readMember(library, symbolName); if (InteropLibrary.getUncached().isNull(symbol)) { return null; } @@ -322,18 +317,18 @@ protected static Object doGeneric(NativeToJavaWrapper receiver, Object[] argumen @Override public @Pointer TruffleObject bindSymbol(@Pointer TruffleObject symbol, NativeSignature nativeSignature) { - if (uncachedInterop.isNull(symbol)) { + if (UNCACHED_INTEROP.isNull(symbol)) { return null; // LD_DEBUG=unused makes non-existing symbols to be NULL. } - TruffleObject executable = (TruffleObject) uncachedSignature.bind(getCallableSignature(nativeSignature, true), symbol); - assert uncachedInterop.isExecutable(executable); + TruffleObject executable = (TruffleObject) UNCACHED_SIGNATURE.bind(getCallableSignature(nativeSignature, isFallbackSymbol(symbol)), symbol); + assert UNCACHED_INTEROP.isExecutable(executable); return new NativeToJavaWrapper(executable, nativeSignature); } @Override @TruffleBoundary - public Object getCallableSignature(NativeSignature nativeSignature, boolean fromJava) { - return getOrCreateNFISignature(nativeSignature, fromJava); + public Object getCallableSignature(NativeSignature nativeSignature, boolean forFallbackSymbol) { + return getOrCreateNFISignature(nativeSignature, forFallbackSymbol); } @Override @@ -342,16 +337,34 @@ public Object callSignature(Object signature, @Pointer TruffleObject symbol, Obj } @Override - public SignatureCallNode createSignatureCall(NativeSignature nativeSignature, boolean fromJava) { - return NFISignatureCallNode.create(getCallableSignature(nativeSignature, fromJava)); + public boolean hasFallbackSymbols() { + return false; + } + + @Override + public boolean isFallbackSymbol(TruffleObject symbol) { + return false; + } + + @Override + public NativeAccess getFallbackAccess() { + return null; + } + + @Override + public SignatureCallNode createSignatureCall(NativeSignature nativeSignature) { + assert !hasFallbackSymbols(); + return NFISignatureCallNode.create(getCallableSignature(nativeSignature, false)); } @Override public @Pointer TruffleObject createNativeClosure(TruffleObject executable, NativeSignature nativeSignature) { - assert uncachedInterop.isExecutable(executable); + assert UNCACHED_INTEROP.isExecutable(executable); TruffleObject wrappedExecutable = new JavaToNativeWrapper(executable, nativeSignature); - TruffleObject nativeFn = (TruffleObject) uncachedSignature.createClosure(getCallableSignature(nativeSignature, false), wrappedExecutable); - assert uncachedInterop.isPointer(nativeFn); + // always create a "fallback" signature for native closure so that they can always be + // converted to pointers + TruffleObject nativeFn = (TruffleObject) UNCACHED_SIGNATURE.createClosure(getCallableSignature(nativeSignature, true), wrappedExecutable); + assert UNCACHED_INTEROP.isPointer(nativeFn); return nativeFn; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFISulongNativeAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFISulongNativeAccess.java index 547d1a6c02c6..e00815567009 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFISulongNativeAccess.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFISulongNativeAccess.java @@ -27,18 +27,22 @@ import java.nio.file.Path; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; import org.graalvm.home.HomeFinder; import org.graalvm.options.OptionValues; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.EspressoOptions; import com.oracle.truffle.espresso.ffi.NativeAccess; import com.oracle.truffle.espresso.ffi.NativeSignature; import com.oracle.truffle.espresso.ffi.Pointer; +import com.oracle.truffle.espresso.ffi.SignatureCallNode; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.runtime.EspressoProperties; import com.oracle.truffle.espresso.substitutions.Collect; @@ -46,14 +50,62 @@ public final class NFISulongNativeAccess extends NFINativeAccess { @Override - protected String nfiStringSignature(NativeSignature nativeSignature, boolean fromJava) { - String res = super.nfiStringSignature(nativeSignature, fromJava); - if (fromJava) { + protected String nfiStringSignature(NativeSignature nativeSignature, boolean forFallbackSymbol) { + String res = super.nfiStringSignature(nativeSignature, forFallbackSymbol); + if (!forFallbackSymbol) { return "with llvm " + res; } return res; } + @Override + public boolean hasFallbackSymbols() { + return true; + } + + @TruffleBoundary + private static boolean isSulongSymbolClass(Object symbolClass) { + return "LLVMLanguage".equals(((Class) symbolClass).getSimpleName()); + } + + @Override + public boolean isFallbackSymbol(TruffleObject symbol) { + return isFallbackSymbol(symbol, InteropLibrary.getUncached()); + } + + private NFINativeAccess fallback; + + @Override + public NativeAccess getFallbackAccess() { + if (fallback == null) { + // races are benign + fallback = new NFINativeAccess(env); + } + return fallback; + } + + static boolean isFallbackSymbol(TruffleObject symbol, InteropLibrary interop) { + Object symbolClass = getSymbolClass(symbol, interop); + return symbolClass == null || !isSulongSymbolClass(symbolClass); + } + + private static Object getSymbolClass(TruffleObject symbol, InteropLibrary interop) { + if (!interop.hasLanguage(symbol)) { + return null; + } + try { + return interop.getLanguage(symbol); + } catch (UnsupportedMessageException e) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere(e); + } + } + + @Override + public SignatureCallNode createSignatureCall(NativeSignature nativeSignature) { + return NFISulongSignatureCallNode.create(this, nativeSignature); + } + NFISulongNativeAccess(TruffleLanguage.Env env) { super(env); } @@ -103,14 +155,14 @@ static String getJavaVersion(Path javaHome) { * version. First checks the 'default' folder, as it matches the Java version of the parent * GraalVM. Then checks remaining folders under llvmRoot. */ - private Path legacyGraalvmllvmBootLibraryPath(String javaVersion, Path llvmRoot) { + private static Path legacyGraalvmllvmBootLibraryPath(String javaVersion, Path llvmRoot) { // Try $ESPRESSO_HOME/lib/llvm/default first. Path llvmDefault = llvmRoot.resolve("default"); if (!Files.exists(llvmDefault)) { - getLogger().warning(() -> "espresso-llvm (default) component not found. Install it, if available for your platform."); + LOGGER.warning(() -> "espresso-llvm (default) component not found. Install it, if available for your platform."); } String llvmDefaultVersion = getJavaVersion(llvmDefault); - getLogger().fine(() -> "Check " + llvmDefault + " with Java version: " + llvmDefaultVersion); + LOGGER.fine(() -> "Check " + llvmDefault + " with Java version: " + llvmDefaultVersion); if (javaVersion.equals(llvmDefaultVersion)) { return llvmDefault; } @@ -123,20 +175,20 @@ private Path legacyGraalvmllvmBootLibraryPath(String javaVersion, Path llvmRoot) return null; // no folders with Java libraries + embedded LLVM-bitcode. } - List sortedPaths = null; - try { + List sortedPaths; + try (var stream = Files.list(llvmRoot)) { // Order must be deterministic. - sortedPaths = Files.list(llvmRoot) // + sortedPaths = stream // .filter(f -> !llvmDefault.equals(f) && Files.isDirectory(f)) // .sorted() // - .collect(Collectors.toList()); + .toList(); } catch (IOException e) { throw EspressoError.shouldNotReachHere(e.getMessage(), e); } for (Path llvmImpl : sortedPaths) { String llvmImplVersion = getJavaVersion(llvmImpl); - getLogger().fine(() -> "Checking " + llvmImpl + " with Java version: " + llvmImplVersion); + LOGGER.fine(() -> "Checking " + llvmImpl + " with Java version: " + llvmImplVersion); if (javaVersion.equals(llvmImplVersion)) { return llvmImpl; } @@ -155,18 +207,18 @@ private Path legacyGraalvmllvmBootLibraryPath(String javaVersion, Path llvmRoot) @Override public void updateEspressoProperties(EspressoProperties.Builder builder, OptionValues options) { if (options.hasBeenSet(EspressoOptions.BootLibraryPath)) { - getLogger().info("--java.BootLibraryPath was set by the user, skipping override for " + Provider.ID); + LOGGER.info("--java.BootLibraryPath was set by the user, skipping override for " + Provider.ID); } else { String targetJavaVersion = getJavaVersion(builder.javaHome()); if (targetJavaVersion == null) { - getLogger().warning("Cannot determine the Java version for '" + builder.javaHome() + "'. The default --java.BootLibraryPath will be used."); + LOGGER.warning("Cannot determine the Java version for '" + builder.javaHome() + "'. The default --java.BootLibraryPath will be used."); } else { Path espressoHome = HomeFinder.getInstance().getLanguageHomes().get(EspressoLanguage.ID); if (espressoHome != null && Files.isDirectory(espressoHome)) { Path llvmRoot = espressoHome.resolve("lib").resolve("llvm"); Path llvmBootLibraryPath = legacyGraalvmllvmBootLibraryPath(targetJavaVersion, llvmRoot); if (llvmBootLibraryPath == null) { - getLogger().warning("Couldn't find libraries with LLVM bitcode for Java version '" + targetJavaVersion + "'. The default --java.BootLibraryPath will be used."); + LOGGER.warning("Couldn't find libraries with LLVM bitcode for Java version '" + targetJavaVersion + "'. The default --java.BootLibraryPath will be used."); } else { builder.bootLibraryPath(Collections.singletonList(llvmBootLibraryPath)); } @@ -175,7 +227,7 @@ public void updateEspressoProperties(EspressoProperties.Builder builder, OptionV if (Files.isDirectory(llvmRoot)) { builder.bootLibraryPath(Collections.singletonList(llvmRoot)); } else { - getLogger().warning("Couldn't find libraries with LLVM bitcode. The default --java.BootLibraryPath will be used."); + LOGGER.warning("Couldn't find libraries with LLVM bitcode. The default --java.BootLibraryPath will be used."); } } } @@ -187,7 +239,7 @@ public void updateEspressoProperties(EspressoProperties.Builder builder, OptionV * file system. */ if (options.hasBeenSet(EspressoOptions.JVMLibraryPath)) { - getLogger().info("--java.JVMLibraryPath was set by the user, skipping override for " + Provider.ID); + LOGGER.info("--java.JVMLibraryPath was set by the user, skipping override for " + Provider.ID); } else { builder.jvmLibraryPath(Collections.singletonList(builder.espressoLibs())); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFISulongSignatureCallNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFISulongSignatureCallNode.java new file mode 100644 index 000000000000..e06f5519057d --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFISulongSignatureCallNode.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.ffi.nfi; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.ArityException; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.interop.UnsupportedTypeException; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.espresso.ffi.NativeSignature; +import com.oracle.truffle.espresso.ffi.SignatureCallNode; +import com.oracle.truffle.nfi.api.SignatureLibrary; + +public abstract class NFISulongSignatureCallNode extends SignatureCallNode { + protected static final int LIMIT = 2; + protected final NativeSignature signature; + private final NFISulongNativeAccess access; + + protected NFISulongSignatureCallNode(NFISulongNativeAccess access, NativeSignature signature) { + this.access = access; + this.signature = signature; + } + + public static SignatureCallNode create(NFISulongNativeAccess access, NativeSignature signature) { + return NFISulongSignatureCallNodeGen.create(access, signature); + } + + protected abstract Object execute(Object functionPointer, Object... args) throws ArityException, UnsupportedTypeException, UnsupportedMessageException; + + @Override + public Object call(Object functionPointer, Object... args) throws ArityException, UnsupportedTypeException, UnsupportedMessageException { + return execute(functionPointer, args); + } + + protected static boolean isFallbackSymbol(Object symbol, InteropLibrary interop) { + return NFISulongNativeAccess.isFallbackSymbol((TruffleObject) symbol, interop); + } + + protected Object getCallableSignature(boolean forFallbackSymbol) { + return access.getCallableSignature(signature, forFallbackSymbol); + } + + @Specialization(limit = "LIMIT", guards = "isFallbackSymbol(functionPointer, symbolInterop) == isFallbackSymbol") + static Object doCached(Object functionPointer, Object[] args, + @SuppressWarnings("unused") @CachedLibrary("functionPointer") InteropLibrary symbolInterop, + @SuppressWarnings("unused") @Cached("isFallbackSymbol(functionPointer, symbolInterop)") boolean isFallbackSymbol, + @Cached("getCallableSignature(isFallbackSymbol)") Object callableSignature, + @CachedLibrary("signature") SignatureLibrary signatureLibrary) throws ArityException, UnsupportedTypeException, UnsupportedMessageException { + return signatureLibrary.call(callableSignature, functionPointer, args); + } + + @Specialization + Object doUncached(Object functionPointer, Object[] args) throws ArityException, UnsupportedTypeException, UnsupportedMessageException { + TruffleObject target = (TruffleObject) functionPointer; + return access.callSignature(getCallableSignature(access.isFallbackSymbol(target)), target, args); + } +} 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 6ebc12360b26..3f8e722a5e4e 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 @@ -310,11 +310,6 @@ public static NativeSignature buildJniNativeSignature(Symbol[] signature) return NativeSignature.create(returnType, parameterTypes); } - public TruffleObject lookupAndBind(@Pointer TruffleObject library, String mangledName) { - NativeSignature signature = buildJniNativeSignature(getParsedSignature()); - return getNativeAccess().lookupAndBindSymbol(library, mangledName, signature); - } - private TruffleObject bind(@Pointer TruffleObject symbol) { NativeSignature signature = buildJniNativeSignature(getParsedSignature()); return getNativeAccess().bindSymbol(symbol, signature); @@ -358,9 +353,10 @@ private CallTarget lookupLibJavaCallTarget() { for (boolean withSignature : new boolean[]{false, true}) { String mangledName = Mangle.mangleMethod(this, withSignature); // Look in libjava - TruffleObject nativeMethod = lookupAndBind(getVM().getJavaLibrary(), mangledName); + NativeSignature signature = buildJniNativeSignature(getParsedSignature()); + TruffleObject nativeMethod = getNativeAccess().lookupAndBindSymbol(getVM().getJavaLibrary(), mangledName, signature, false, true); if (nativeMethod != null) { - return EspressoRootNode.createNative(getMethodVersion(), nativeMethod).getCallTarget(); + return EspressoRootNode.createNative(getContext().getJNI(), getMethodVersion(), nativeMethod).getCallTarget(); } } } @@ -368,38 +364,40 @@ private CallTarget lookupLibJavaCallTarget() { } private CallTarget lookupAgents() { + if (!getContext().getEspressoEnv().EnableAgents) { + return null; + } // Look in agents for (boolean withSignature : new boolean[]{false, true}) { String mangledName = Mangle.mangleMethod(this, withSignature); - TruffleObject nativeMethod = getContext().bindToAgent(this, mangledName); - if (nativeMethod != null) { - return EspressoRootNode.createNative(getMethodVersion(), nativeMethod).getCallTarget(); + TruffleObject symbol = getContext().lookupAgentSymbol(mangledName); + if (symbol != null) { + TruffleObject nativeMethod = bind(symbol); + return EspressoRootNode.createNative(getContext().getJNI(symbol), getMethodVersion(), nativeMethod).getCallTarget(); } } return null; } private CallTarget lookupJniCallTarget() { - CallTarget target; - Method findNative = getMeta().java_lang_ClassLoader_findNative; - // Lookup the short name first, otherwise lookup the long name (with - // signature). - target = lookupJniCallTarget(findNative, false); + Meta meta = getMeta(); + // Lookup the short name first, otherwise lookup the long name (with signature). + CallTarget target = lookupJniCallTarget(meta, false); if (target == null) { - target = lookupJniCallTarget(findNative, true); + target = lookupJniCallTarget(meta, true); } return target; } - private CallTarget lookupJniCallTarget(Method findNative, boolean fullSignature) { + private CallTarget lookupJniCallTarget(Meta meta, boolean fullSignature) { String mangledName = Mangle.mangleMethod(this, fullSignature); - long handle = (long) findNative.invokeWithConversions(null, getDeclaringKlass().getDefiningClassLoader(), mangledName); + long handle = (long) meta.java_lang_ClassLoader_findNative.invokeDirectStatic(getDeclaringKlass().getDefiningClassLoader(), meta.toGuestString(mangledName)); if (handle == 0) { // not found return null; } TruffleObject symbol = getVM().getFunction(handle); TruffleObject nativeMethod = bind(symbol); - return EspressoRootNode.createNative(this.getMethodVersion(), nativeMethod).getCallTarget(); + return EspressoRootNode.createNative(getContext().getJNI(symbol), getMethodVersion(), nativeMethod).getCallTarget(); } public boolean isConstructor() { @@ -469,7 +467,7 @@ public Object invokeWithConversions(Object self, Object... args) { // Impossible to call from guest code, so what is above is illegal for continuations. tls.blockContinuationSuspension(); try { - getContext().getJNI().clearPendingException(); + getLanguage().clearPendingException(); assert args.length == Signatures.parameterCount(getParsedSignature()); // assert !isStatic() || ((StaticObject) self).isStatic(); @@ -505,7 +503,7 @@ public Object invokeDirect(Object... args) { // Impossible to call from guest code, so what is above is illegal for continuations. tls.blockContinuationSuspension(); try { - getContext().getJNI().clearPendingException(); + getLanguage().clearPendingException(); assert !isStatic(); assert args.length == Signatures.parameterCount(getParsedSignature()) + 1; assert getDeclaringKlass().isAssignableFrom(((StaticObject) args[0]).getKlass()); @@ -521,7 +519,7 @@ public Object invokeDirectStatic(Object... args) { // Impossible to call from guest code, so what is above is illegal for continuations. tls.blockContinuationSuspension(); try { - getContext().getJNI().clearPendingException(); + getLanguage().clearPendingException(); assert isStatic(); assert args.length == Signatures.parameterCount(getParsedSignature()); getDeclaringKlass().safeInitialize(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JNIHandles.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JNIHandles.java index f56fd57d1df8..c07f0661de46 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JNIHandles.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JNIHandles.java @@ -29,6 +29,8 @@ import java.util.function.Supplier; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.espresso.impl.Field; +import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; /** @@ -49,6 +51,8 @@ public final class JNIHandles { */ static final int NATIVE_CALL_MIN_LOCAL_HANDLE_CAPACITY = 16; + private final WeakHandles fieldIds = new WeakHandles<>(); + private final WeakHandles methodIds = new WeakHandles<>(); private final ThreadLocal locals; private final GlobalHandles globals; @@ -187,6 +191,14 @@ public void popFrame() { public int pushFrame() { return pushFrame(NATIVE_CALL_MIN_LOCAL_HANDLE_CAPACITY); } + + public WeakHandles fieldIds() { + return fieldIds; + } + + public WeakHandles methodIds() { + return methodIds; + } } /** @@ -329,7 +341,7 @@ public void ensureCapacity(int capacity) { targetCapacity = Math.multiplyExact(targetCapacity, 2); } if (targetCapacity > objects.length) { - Object[] oldArray = objects; + StaticObject[] oldArray = objects; assert targetCapacity >= top + capacity; objects = new StaticObject[targetCapacity]; System.arraycopy(oldArray, 0, objects, 0, oldArray.length); 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 aa780e840c86..5fd5b4417ae7 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 @@ -23,6 +23,8 @@ package com.oracle.truffle.espresso.jni; import java.io.PrintWriter; +import java.lang.reflect.Executable; +import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; @@ -40,7 +42,6 @@ import java.util.function.Supplier; 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.TruffleLogger; import com.oracle.truffle.api.interop.ArityException; @@ -56,6 +57,7 @@ import com.oracle.truffle.espresso.descriptors.Symbol.Signature; import com.oracle.truffle.espresso.descriptors.Symbol.Type; import com.oracle.truffle.espresso.descriptors.Validation; +import com.oracle.truffle.espresso.ffi.NativeAccess; import com.oracle.truffle.espresso.ffi.NativeSignature; import com.oracle.truffle.espresso.ffi.NativeType; import com.oracle.truffle.espresso.ffi.Pointer; @@ -117,7 +119,7 @@ @GenerateNativeEnv(target = JniImpl.class) public final class JniEnv extends NativeEnv { - private static final TruffleLogger LOGGER = TruffleLogger.getLogger(EspressoLanguage.ID, JniEnv.class); + public static final TruffleLogger LOGGER = TruffleLogger.getLogger(EspressoLanguage.ID, JniEnv.class); public static final int JNI_OK = 0; /* success */ public static final int JNI_ERR = -1; /* unknown error */ @@ -140,16 +142,14 @@ public final class JniEnv extends NativeEnv { // TODO(peterssen): Add user-configurable option. private static final int MAX_JNI_LOCAL_CAPACITY = 1 << 16; - private final JNIHandles handles; - @CompilationFinal private JniVersion jniVersion; + private static final List JNI_IMPL_FACTORIES = JniImplCollector.getInstances(CallableFromNative.Factory.class); - private @Pointer TruffleObject jniEnvPtr; + private final JniVersion jniVersion; + private final String debugEnvName; // Native library nespresso.dll (Windows) or libnespresso.so (Unixes) at runtime. private final TruffleObject nespressoLibrary; - // Native methods in libenespresso. - private final @Pointer TruffleObject initializeNativeContext; private final @Pointer TruffleObject disposeNativeContext; private final @Pointer TruffleObject popBoolean; private final @Pointer TruffleObject popByte; @@ -161,49 +161,45 @@ public final class JniEnv extends NativeEnv { private final @Pointer TruffleObject popLong; private final @Pointer TruffleObject popObject; - private final @Pointer TruffleObject getSizeMax; - - private static final List JNI_IMPL_FACTORIES = JniImplCollector.getInstances(CallableFromNative.Factory.class); - - @Override - protected List getCollector() { - return JNI_IMPL_FACTORIES; - } - - @Override - protected JniEnv jni() { - return this; - } - - private final WeakHandles fieldIds = new WeakHandles<>(); - private final WeakHandles methodIds = new WeakHandles<>(); - - // The maximum value supported by the native size_t e.g. SIZE_MAX. - private long cachedSizeMax = 0; + private @Pointer TruffleObject jniEnvPtr; // Prevent cleaner threads from collecting in-use native buffers. private final Map nativeBuffers = new ConcurrentHashMap<>(); - public StaticObject getPendingException() { - return getContext().getLanguage().getThreadLocalState().getPendingExceptionObject(); - } - - public EspressoException getPendingEspressoException() { - return getContext().getLanguage().getThreadLocalState().getPendingException(); - } + private JniEnv(EspressoContext context, NativeAccess nativeAccess) { + super(context); + jniVersion = JniVersion.getJniVersion(getJavaVersion()); + debugEnvName = "JniEnv(" + jniVersion + "; " + nativeAccess.getClass().getSimpleName() + ")"; + Path espressoLibraryPath = context.getEspressoLibs(); + nespressoLibrary = nativeAccess.loadLibrary(Collections.singletonList(espressoLibraryPath), "nespresso", true); + // Native methods in libenespresso. + TruffleObject initializeNativeContext = nativeAccess.lookupAndBindSymbol(nespressoLibrary, "initializeNativeContext", NativeSignature.create(NativeType.POINTER, NativeType.POINTER)); + disposeNativeContext = nativeAccess.lookupAndBindSymbol(nespressoLibrary, "disposeNativeContext", NativeSignature.create(NativeType.VOID, NativeType.POINTER, NativeType.POINTER)); - public void clearPendingException() { - getContext().getLanguage().getThreadLocalState().clearPendingException(); + // Varargs native bindings. + popBoolean = nativeAccess.lookupAndBindSymbol(nespressoLibrary, "pop_boolean", NativeSignature.create(NativeType.BOOLEAN, NativeType.POINTER)); + popByte = nativeAccess.lookupAndBindSymbol(nespressoLibrary, "pop_byte", NativeSignature.create(NativeType.BYTE, NativeType.POINTER)); + popChar = nativeAccess.lookupAndBindSymbol(nespressoLibrary, "pop_char", NativeSignature.create(NativeType.CHAR, NativeType.POINTER)); + popShort = nativeAccess.lookupAndBindSymbol(nespressoLibrary, "pop_short", NativeSignature.create(NativeType.SHORT, NativeType.POINTER)); + popInt = nativeAccess.lookupAndBindSymbol(nespressoLibrary, "pop_int", NativeSignature.create(NativeType.INT, NativeType.POINTER)); + popFloat = nativeAccess.lookupAndBindSymbol(nespressoLibrary, "pop_float", NativeSignature.create(NativeType.FLOAT, NativeType.POINTER)); + popDouble = nativeAccess.lookupAndBindSymbol(nespressoLibrary, "pop_double", NativeSignature.create(NativeType.DOUBLE, NativeType.POINTER)); + popLong = nativeAccess.lookupAndBindSymbol(nespressoLibrary, "pop_long", NativeSignature.create(NativeType.LONG, NativeType.POINTER)); + popObject = nativeAccess.lookupAndBindSymbol(nespressoLibrary, "pop_object", NativeSignature.create(NativeType.OBJECT, NativeType.POINTER)); + + jniEnvPtr = initializeAndGetEnv(initializeNativeContext); + assert jniEnvPtr != null && !getUncached().isNull(jniEnvPtr); + assert getUncached().isPointer(jniEnvPtr); } - public void setPendingException(StaticObject ex) { - Meta meta = getMeta(); - assert StaticObject.notNull(ex) && meta.java_lang_Throwable.isAssignableFrom(ex.getKlass()); - setPendingException(EspressoException.wrap(ex, meta)); + @Override + public String toString() { + return debugEnvName; } - public void setPendingException(EspressoException ex) { - getContext().getLanguage().getThreadLocalState().setPendingException(ex); + @Override + protected List getCollector() { + return JNI_IMPL_FACTORIES; } @Override @@ -304,28 +300,16 @@ public Object popObject() { try { Object ret = getUncached().execute(popObject, nativePointer); @Handle(StaticObject.class) - long handle = 0; + long handle; if (getUncached().isPointer(ret)) { /* due to GR-37169 it can be any pointer type, not just a long in nfi-llvm */ handle = getUncached().asPointer(ret); } else { handle = (long) ret; } - TruffleObject result = getHandles().get(Math.toIntExact(handle)); - if (result instanceof StaticObject) { - return result; - } else { - if (getUncached().isNull(result)) { - // TODO(garcia) understand the weird stuff happening here. - // DaCapo batik gives us a NativePointer to 0 here. This is a workaround - // until I - // figure out just what is happening here. - return StaticObject.NULL; - } else { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.unimplemented("non null native pointer in JniEnv"); - } - } + StaticObject result = getHandles().get(Math.toIntExact(handle)); + assert result != null; + return result; } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException | ClassCastException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); throw EspressoError.shouldNotReachHere(e); @@ -372,48 +356,11 @@ public Object[] popVarArgs(@Pointer TruffleObject varargsPtr, final Symbol return args; } - private JniEnv(EspressoContext context) { - super(context); - Path espressoLibraryPath = context.getEspressoLibs(); - nespressoLibrary = getNativeAccess().loadLibrary(Collections.singletonList(espressoLibraryPath), "nespresso", true); - initializeNativeContext = getNativeAccess().lookupAndBindSymbol(nespressoLibrary, "initializeNativeContext", - NativeSignature.create(NativeType.POINTER, NativeType.POINTER)); - disposeNativeContext = getNativeAccess().lookupAndBindSymbol(nespressoLibrary, "disposeNativeContext", - NativeSignature.create(NativeType.VOID, NativeType.POINTER, NativeType.POINTER)); - - getSizeMax = getNativeAccess().lookupAndBindSymbol(nespressoLibrary, "get_SIZE_MAX", NativeSignature.create(NativeType.LONG)); - - assert sizeMax() > Integer.MAX_VALUE : "size_t must be 64-bit wide"; - - // Varargs native bindings. - popBoolean = getNativeAccess().lookupAndBindSymbol(nespressoLibrary, "pop_boolean", NativeSignature.create(NativeType.BOOLEAN, NativeType.POINTER)); - popByte = getNativeAccess().lookupAndBindSymbol(nespressoLibrary, "pop_byte", NativeSignature.create(NativeType.BYTE, NativeType.POINTER)); - popChar = getNativeAccess().lookupAndBindSymbol(nespressoLibrary, "pop_char", NativeSignature.create(NativeType.CHAR, NativeType.POINTER)); - popShort = getNativeAccess().lookupAndBindSymbol(nespressoLibrary, "pop_short", NativeSignature.create(NativeType.SHORT, NativeType.POINTER)); - popInt = getNativeAccess().lookupAndBindSymbol(nespressoLibrary, "pop_int", NativeSignature.create(NativeType.INT, NativeType.POINTER)); - popFloat = getNativeAccess().lookupAndBindSymbol(nespressoLibrary, "pop_float", NativeSignature.create(NativeType.FLOAT, NativeType.POINTER)); - popDouble = getNativeAccess().lookupAndBindSymbol(nespressoLibrary, "pop_double", NativeSignature.create(NativeType.DOUBLE, NativeType.POINTER)); - popLong = getNativeAccess().lookupAndBindSymbol(nespressoLibrary, "pop_long", NativeSignature.create(NativeType.LONG, NativeType.POINTER)); - popObject = getNativeAccess().lookupAndBindSymbol(nespressoLibrary, "pop_object", NativeSignature.create(NativeType.OBJECT, NativeType.POINTER)); - - this.jniEnvPtr = initializeAndGetEnv(initializeNativeContext); - assert getUncached().isPointer(jniEnvPtr); - - this.handles = new JNIHandles(); - - assert jniEnvPtr != null && !getUncached().isNull(jniEnvPtr); - } - @Override protected String getName() { return "JniEnv"; } - @Override - public JNIHandles getHandles() { - return handles; - } - @TruffleBoundary private ByteBuffer allocateDirect(int capacity, JavaKind kind) { return allocateDirect(Math.multiplyExact(capacity, kind.getByteCount())); @@ -428,7 +375,12 @@ private ByteBuffer allocateDirect(int capacity) { } public static JniEnv create(EspressoContext context) { - return new JniEnv(context); + return new JniEnv(context, context.getNativeAccess()); + } + + public static JniEnv createFallback(EspressoContext context) { + assert context.getNativeAccess().hasFallbackSymbols(); + return new JniEnv(context, context.getNativeAccess().getFallbackAccess()); } public @Pointer TruffleObject getNativePointer() { @@ -441,29 +393,20 @@ public void dispose() { } try { getUncached().execute(disposeNativeContext, jniEnvPtr, RawPointer.nullInstance()); - this.jniEnvPtr = null; } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("Cannot dispose Espresso native interface"); + throw EspressoError.shouldNotReachHere("Cannot dispose Espresso native interface", e); + } finally { + this.jniEnvPtr = null; } - assert jniEnvPtr == null || getUncached().isNull(jniEnvPtr); } - public long sizeMax() { - long result = cachedSizeMax; - if (result == 0) { - try { - result = (long) getUncached().execute(getSizeMax); - if (result < 0) { - result = Long.MAX_VALUE; - } - cachedSizeMax = result; - } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere(e); - } - } - return result; + private WeakHandles fieldIds() { + return getHandles().fieldIds(); + } + + private WeakHandles methodIds() { + return getHandles().methodIds(); } // Checkstyle: stop method name check @@ -511,7 +454,7 @@ public long sizeMax() { throw meta.throwExceptionWithMessage(meta.java_lang_NoSuchFieldError, name); } assert !field.isStatic(); - return fieldIds.handlify(field); + return fieldIds().handlify(field); } /** @@ -554,7 +497,7 @@ public long sizeMax() { Meta meta = getMeta(); throw meta.throwExceptionWithMessage(meta.java_lang_NoSuchFieldError, name); } - return fieldIds.handlify(field); + return fieldIds().handlify(field); } /** @@ -598,7 +541,7 @@ public long sizeMax() { Meta meta = getMeta(); throw meta.throwExceptionWithMessage(meta.java_lang_NoSuchMethodError, name); } - return methodIds.handlify(method); + return methodIds().handlify(method); } /** @@ -651,7 +594,7 @@ public long sizeMax() { Meta meta = getMeta(); throw meta.throwExceptionWithMessage(meta.java_lang_NoSuchMethodError, name); } - return methodIds.handlify(method); + return methodIds().handlify(method); } // endregion Get*ID @@ -660,63 +603,63 @@ public long sizeMax() { @JniImpl public @JavaType(Object.class) StaticObject GetStaticObjectField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); return field.getAsObject(getMeta(), field.getDeclaringKlass().tryInitializeAndGetStatics()); } @JniImpl public boolean GetStaticBooleanField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); return field.getAsBoolean(getMeta(), field.getDeclaringKlass().tryInitializeAndGetStatics(), false); } @JniImpl public byte GetStaticByteField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); return field.getAsByte(getMeta(), field.getDeclaringKlass().tryInitializeAndGetStatics(), false); } @JniImpl public char GetStaticCharField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); return field.getAsChar(getMeta(), field.getDeclaringKlass().tryInitializeAndGetStatics(), false); } @JniImpl public short GetStaticShortField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); return field.getAsShort(getMeta(), field.getDeclaringKlass().tryInitializeAndGetStatics(), false); } @JniImpl public int GetStaticIntField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); return field.getAsInt(getMeta(), field.getDeclaringKlass().tryInitializeAndGetStatics(), false); } @JniImpl public long GetStaticLongField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); return field.getAsLong(getMeta(), field.getDeclaringKlass().tryInitializeAndGetStatics(), false); } @JniImpl public float GetStaticFloatField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); return field.getAsFloat(getMeta(), field.getDeclaringKlass().tryInitializeAndGetStatics(), false); } @JniImpl public double GetStaticDoubleField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); return field.getAsDouble(getMeta(), field.getDeclaringKlass().tryInitializeAndGetStatics(), false); } @@ -727,55 +670,55 @@ public double GetStaticDoubleField(@SuppressWarnings("unused") @JavaType(Class.c @JniImpl public @JavaType(Object.class) StaticObject GetObjectField(@JavaType(Object.class) StaticObject object, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); return field.getAsObject(getMeta(), object); } @JniImpl public boolean GetBooleanField(@JavaType(Object.class) StaticObject object, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); return field.getAsBoolean(getMeta(), object, false); } @JniImpl public byte GetByteField(@JavaType(Object.class) StaticObject object, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); return field.getAsByte(getMeta(), object, false); } @JniImpl public char GetCharField(@JavaType(Object.class) StaticObject object, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); return field.getAsChar(getMeta(), object, false); } @JniImpl public short GetShortField(@JavaType(Object.class) StaticObject object, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); return field.getAsShort(getMeta(), object, false); } @JniImpl public int GetIntField(@JavaType(Object.class) StaticObject object, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); return field.getAsInt(getMeta(), object, false); } @JniImpl public long GetLongField(@JavaType(Object.class) StaticObject object, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); return field.getAsLong(getMeta(), object, false); } @JniImpl public float GetFloatField(@JavaType(Object.class) StaticObject object, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); return field.getAsFloat(getMeta(), object, false); } @JniImpl public double GetDoubleField(@JavaType(Object.class) StaticObject object, @Handle(Field.class) long fieldId) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); return field.getAsDouble(getMeta(), object, false); } @@ -785,63 +728,63 @@ public double GetDoubleField(@JavaType(Object.class) StaticObject object, @Handl @JniImpl public void SetStaticObjectField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId, @JavaType(Object.class) StaticObject val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); field.set(field.getDeclaringKlass().tryInitializeAndGetStatics(), val); } @JniImpl public void SetStaticBooleanField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId, boolean val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); field.set(field.getDeclaringKlass().tryInitializeAndGetStatics(), val); } @JniImpl public void SetStaticByteField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId, byte val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); field.set(field.getDeclaringKlass().tryInitializeAndGetStatics(), val); } @JniImpl public void SetStaticCharField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId, char val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); field.set(field.getDeclaringKlass().tryInitializeAndGetStatics(), val); } @JniImpl public void SetStaticShortField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId, short val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); field.set(field.getDeclaringKlass().tryInitializeAndGetStatics(), val); } @JniImpl public void SetStaticIntField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId, int val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); field.set(field.getDeclaringKlass().tryInitializeAndGetStatics(), val); } @JniImpl public void SetStaticLongField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId, long val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); field.set(field.getDeclaringKlass().tryInitializeAndGetStatics(), val); } @JniImpl public void SetStaticFloatField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId, float val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); field.set(field.getDeclaringKlass().tryInitializeAndGetStatics(), val); } @JniImpl public void SetStaticDoubleField(@SuppressWarnings("unused") @JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId, double val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.isStatic(); field.set(field.getDeclaringKlass().tryInitializeAndGetStatics(), val); } @@ -852,55 +795,55 @@ public void SetStaticDoubleField(@SuppressWarnings("unused") @JavaType(Class.cla @JniImpl public void SetObjectField(@JavaType(Object.class) StaticObject obj, @Handle(Field.class) long fieldId, @JavaType(Object.class) StaticObject val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); field.set(obj, val); } @JniImpl public void SetBooleanField(@JavaType(Object.class) StaticObject obj, @Handle(Field.class) long fieldId, boolean val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); field.set(obj, val); } @JniImpl public void SetByteField(@JavaType(Object.class) StaticObject obj, @Handle(Field.class) long fieldId, byte val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); field.set(obj, val); } @JniImpl public void SetCharField(@JavaType(Object.class) StaticObject obj, @Handle(Field.class) long fieldId, char val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); field.set(obj, val); } @JniImpl public void SetShortField(@JavaType(Object.class) StaticObject obj, @Handle(Field.class) long fieldId, short val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); field.set(obj, val); } @JniImpl public void SetIntField(@JavaType(Object.class) StaticObject obj, @Handle(Field.class) long fieldId, int val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); field.set(obj, val); } @JniImpl public void SetLongField(@JavaType(Object.class) StaticObject obj, @Handle(Field.class) long fieldId, long val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); field.set(obj, val); } @JniImpl public void SetFloatField(@JavaType(Object.class) StaticObject obj, @Handle(Field.class) long fieldId, float val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); field.set(obj, val); } @JniImpl public void SetDoubleField(@JavaType(Object.class) StaticObject obj, @Handle(Field.class) long fieldId, double val) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); field.set(obj, val); } @@ -910,7 +853,7 @@ public void SetDoubleField(@JavaType(Object.class) StaticObject obj, @Handle(Fie private Object callVirtualMethodGeneric(StaticObject receiver, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { assert !receiver.getKlass().isInterface(); - Method resolutionSeed = methodIds.getObject(methodId); + Method resolutionSeed = methodIds().getObject(methodId); assert !resolutionSeed.isStatic(); assert resolutionSeed.getDeclaringKlass().isAssignableFrom(receiver.getKlass()); Object[] args = popVarArgs(varargsPtr, resolutionSeed.getParsedSignature(), receiver); @@ -1014,7 +957,7 @@ public void CallVoidMethodVarargs(@JavaType(Object.class) StaticObject receiver, public @JavaType(Object.class) StaticObject CallNonvirtualObjectMethodVarargs(@JavaType(Object.class) StaticObject receiver, @JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert !method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirect(popVarArgs(varargsPtr, method.getParsedSignature(), receiver)); @@ -1024,7 +967,7 @@ public void CallVoidMethodVarargs(@JavaType(Object.class) StaticObject receiver, @JniImpl public boolean CallNonvirtualBooleanMethodVarargs(@JavaType(Object.class) StaticObject receiver, @JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert !method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirect(popVarArgs(varargsPtr, method.getParsedSignature(), receiver)); @@ -1034,7 +977,7 @@ public boolean CallNonvirtualBooleanMethodVarargs(@JavaType(Object.class) Static @JniImpl public char CallNonvirtualCharMethodVarargs(@JavaType(Object.class) StaticObject receiver, @JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert !method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirect(popVarArgs(varargsPtr, method.getParsedSignature(), receiver)); @@ -1044,7 +987,7 @@ public char CallNonvirtualCharMethodVarargs(@JavaType(Object.class) StaticObject @JniImpl public byte CallNonvirtualByteMethodVarargs(@JavaType(Object.class) StaticObject receiver, @JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert !method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirect(popVarArgs(varargsPtr, method.getParsedSignature(), receiver)); @@ -1054,7 +997,7 @@ public byte CallNonvirtualByteMethodVarargs(@JavaType(Object.class) StaticObject @JniImpl public short CallNonvirtualShortMethodVarargs(@JavaType(Object.class) StaticObject receiver, @JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert !method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirect(popVarArgs(varargsPtr, method.getParsedSignature(), receiver)); @@ -1064,7 +1007,7 @@ public short CallNonvirtualShortMethodVarargs(@JavaType(Object.class) StaticObje @JniImpl public int CallNonvirtualIntMethodVarargs(@JavaType(Object.class) StaticObject receiver, @JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert !method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirect(popVarArgs(varargsPtr, method.getParsedSignature(), receiver)); @@ -1074,7 +1017,7 @@ public int CallNonvirtualIntMethodVarargs(@JavaType(Object.class) StaticObject r @JniImpl public float CallNonvirtualFloatMethodVarargs(@JavaType(Object.class) StaticObject receiver, @JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert !method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirect(popVarArgs(varargsPtr, method.getParsedSignature(), receiver)); @@ -1084,7 +1027,7 @@ public float CallNonvirtualFloatMethodVarargs(@JavaType(Object.class) StaticObje @JniImpl public double CallNonvirtualDoubleMethodVarargs(@JavaType(Object.class) StaticObject receiver, @JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert !method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirect(popVarArgs(varargsPtr, method.getParsedSignature(), receiver)); @@ -1094,7 +1037,7 @@ public double CallNonvirtualDoubleMethodVarargs(@JavaType(Object.class) StaticOb @JniImpl public long CallNonvirtualLongMethodVarargs(@JavaType(Object.class) StaticObject receiver, @JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert !method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirect(popVarArgs(varargsPtr, method.getParsedSignature(), receiver)); @@ -1104,7 +1047,7 @@ public long CallNonvirtualLongMethodVarargs(@JavaType(Object.class) StaticObject @JniImpl public void CallNonvirtualVoidMethodVarargs(@JavaType(Object.class) StaticObject receiver, @JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert !method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirect(popVarArgs(varargsPtr, method.getParsedSignature(), receiver)); @@ -1117,7 +1060,7 @@ public void CallNonvirtualVoidMethodVarargs(@JavaType(Object.class) StaticObject @JniImpl public @JavaType(Object.class) StaticObject CallStaticObjectMethodVarargs(@JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirectStatic(popVarArgs(varargsPtr, method.getParsedSignature())); @@ -1126,7 +1069,7 @@ public void CallNonvirtualVoidMethodVarargs(@JavaType(Object.class) StaticObject @JniImpl public boolean CallStaticBooleanMethodVarargs(@JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirectStatic(popVarArgs(varargsPtr, method.getParsedSignature())); @@ -1135,7 +1078,7 @@ public boolean CallStaticBooleanMethodVarargs(@JavaType(Class.class) StaticObjec @JniImpl public char CallStaticCharMethodVarargs(@JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirectStatic(popVarArgs(varargsPtr, method.getParsedSignature())); @@ -1144,7 +1087,7 @@ public char CallStaticCharMethodVarargs(@JavaType(Class.class) StaticObject claz @JniImpl public byte CallStaticByteMethodVarargs(@JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirectStatic(popVarArgs(varargsPtr, method.getParsedSignature())); @@ -1153,7 +1096,7 @@ public byte CallStaticByteMethodVarargs(@JavaType(Class.class) StaticObject claz @JniImpl public short CallStaticShortMethodVarargs(@JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirectStatic(popVarArgs(varargsPtr, method.getParsedSignature())); @@ -1162,7 +1105,7 @@ public short CallStaticShortMethodVarargs(@JavaType(Class.class) StaticObject cl @JniImpl public int CallStaticIntMethodVarargs(@JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirectStatic(popVarArgs(varargsPtr, method.getParsedSignature())); @@ -1171,7 +1114,7 @@ public int CallStaticIntMethodVarargs(@JavaType(Class.class) StaticObject clazz, @JniImpl public float CallStaticFloatMethodVarargs(@JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirectStatic(popVarArgs(varargsPtr, method.getParsedSignature())); @@ -1180,7 +1123,7 @@ public float CallStaticFloatMethodVarargs(@JavaType(Class.class) StaticObject cl @JniImpl public double CallStaticDoubleMethodVarargs(@JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirectStatic(popVarArgs(varargsPtr, method.getParsedSignature())); @@ -1189,7 +1132,7 @@ public double CallStaticDoubleMethodVarargs(@JavaType(Class.class) StaticObject @JniImpl public long CallStaticLongMethodVarargs(@JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirectStatic(popVarArgs(varargsPtr, method.getParsedSignature())); @@ -1198,7 +1141,7 @@ public long CallStaticLongMethodVarargs(@JavaType(Class.class) StaticObject claz @JniImpl public void CallStaticVoidMethodVarargs(@JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert method.isStatic(); assert (clazz.getMirrorKlass(getMeta())) == method.getDeclaringKlass(); Object result = method.invokeDirectStatic(popVarArgs(varargsPtr, method.getParsedSignature())); @@ -1774,8 +1717,8 @@ public void GetStringUTFRegion(@JavaType(String.class) StaticObject str, int sta * @return JNI_TRUE when there is a pending exception; otherwise, returns JNI_FALSE. */ @JniImpl - public boolean ExceptionCheck() { - EspressoException ex = getPendingEspressoException(); + public static boolean ExceptionCheck(@Inject EspressoLanguage language) { + EspressoException ex = language.getPendingEspressoException(); // ex != null => ex != NULL assert ex == null || StaticObject.notNull(ex.getGuestException()); return ex != null; @@ -1788,16 +1731,16 @@ public boolean ExceptionCheck() { * thrown, this routine has no effect. */ @JniImpl - public void ExceptionClear() { - clearPendingException(); + public static void ExceptionClear(@Inject EspressoLanguage language) { + language.clearPendingException(); } /** *

    jint Throw(JNIEnv *env, jthrowable obj);

    *

    - * Causes a {@link java.lang.Throwable} object to be thrown. + * Causes a {@link Throwable} object to be thrown. * - * @param obj a {@link java.lang.Throwable} object. + * @param obj a {@link Throwable} object. * @return 0 on success; a negative value on failure. */ @JniImpl @@ -1815,10 +1758,10 @@ public static int Throw(@JavaType(Throwable.class) StaticObject obj, @Inject Met * and causes that exception to be thrown. * * @param clazz a subclass of java.lang.Throwable. - * @param messagePtr the message used to construct the {@link java.lang.Throwable} object. The - * string is encoded in modified UTF-8. + * @param messagePtr the message used to construct the {@link Throwable} object. The string is + * encoded in modified UTF-8. * @return 0 on success; a negative value on failure. - * @throws EspressoException the newly constructed {@link java.lang.Throwable} object. + * @throws EspressoException the newly constructed {@link Throwable} object. */ @JniImpl public int ThrowNew(@JavaType(Class.class) StaticObject clazz, @Pointer TruffleObject messagePtr, @Inject Meta meta) { @@ -1839,7 +1782,7 @@ public int ThrowNew(@JavaType(Class.class) StaticObject clazz, @Pointer TruffleO */ @JniImpl public @JavaType(Throwable.class) StaticObject ExceptionOccurred() { - StaticObject ex = getPendingException(); + StaticObject ex = getLanguage().getPendingException(); if (ex == null) { ex = StaticObject.NULL; } @@ -1853,15 +1796,15 @@ public int ThrowNew(@JavaType(Class.class) StaticObject clazz, @Pointer TruffleO * stderr. This is a convenience routine provided for debugging. */ @JniImpl - public void ExceptionDescribe() { - EspressoException ex = getPendingEspressoException(); + public void ExceptionDescribe(@Inject EspressoLanguage language) { + EspressoException ex = language.getPendingEspressoException(); if (ex != null) { StaticObject guestException = ex.getGuestException(); Meta meta = getMeta(); assert InterpreterToVM.instanceOf(guestException, meta.java_lang_Throwable); meta.java_lang_Throwable_printStackTrace.invokeDirectVirtual(guestException); // Restore exception cleared by invokeDirect. - setPendingException(ex); + language.setPendingException(ex); } } @@ -1899,7 +1842,7 @@ public int MonitorExit(@JavaType(Object.class) StaticObject object, @Inject Meta InterpreterToVM.monitorExit(object, meta); } catch (EspressoException e) { assert InterpreterToVM.instanceOf(e.getGuestException(), getMeta().java_lang_IllegalMonitorStateException); - setPendingException(e); + meta.getLanguage().setPendingException(e); return JNI_ERR; } return JNI_OK; @@ -2178,8 +2121,8 @@ public void ReleaseDoubleArrayElements(@JavaType(double[].class) StaticObject ob *

    void* GetDirectBufferAddress(JNIEnv* env, jobject buf);

    *

    * Fetches and returns the starting address of the memory region referenced by the given direct - * {@link java.nio.Buffer}. This function allows native code to access the same memory region - * that is accessible to Java code via the buffer object. + * {@link Buffer}. This function allows native code to access the same memory region that is + * accessible to Java code via the buffer object. * * @param buf a direct java.nio.Buffer object (must not be NULL) * @return the starting address of the memory region referenced by the buffer. Returns NULL if @@ -2187,7 +2130,7 @@ public void ReleaseDoubleArrayElements(@JavaType(double[].class) StaticObject ob * or if JNI access to direct buffers is not supported by this virtual machine. */ @JniImpl - public @Pointer TruffleObject GetDirectBufferAddress(@JavaType(java.nio.Buffer.class) StaticObject buf) { + public @Pointer TruffleObject GetDirectBufferAddress(@JavaType(Buffer.class) StaticObject buf) { assert StaticObject.notNull(buf); // TODO(peterssen): Returns NULL if the memory region is undefined. // HotSpot check. @@ -2206,8 +2149,7 @@ public void ReleaseDoubleArrayElements(@JavaType(double[].class) StaticObject ob *

    jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf);

    *

    * Fetches and returns the capacity of the memory region referenced by the given direct - * {@link java.nio.Buffer}. The capacity is the number of elements that the memory region - * contains. + * {@link Buffer}. The capacity is the number of elements that the memory region contains. * * @param buf a direct java.nio.Buffer object (must not be NULL) * @return the capacity of the memory region associated with the buffer. Returns -1 if the given @@ -2216,7 +2158,7 @@ public void ReleaseDoubleArrayElements(@JavaType(double[].class) StaticObject ob * direct buffers is not supported by this virtual machine. */ @JniImpl - public long GetDirectBufferCapacity(@JavaType(java.nio.Buffer.class) StaticObject buf) { + public long GetDirectBufferCapacity(@JavaType(Buffer.class) StaticObject buf) { assert StaticObject.notNull(buf); // TODO(peterssen): Return -1 if the object is an unaligned view buffer and the processor // architecture does not support unaligned access. @@ -2248,7 +2190,8 @@ public int RegisterNative(@JavaType(Class.class) StaticObject clazz, @Pointer Tr Meta meta = getMeta(); if (name == null || signature == null) { - setPendingException(Meta.initException(meta.java_lang_NoSuchMethodError)); + StaticObject ex = Meta.initException(meta.java_lang_NoSuchMethodError); + getLanguage().setPendingException(EspressoException.wrap(ex, meta)); return JNI_ERR; } @@ -2257,18 +2200,17 @@ public int RegisterNative(@JavaType(Class.class) StaticObject clazz, @Pointer Tr targetMethod.unregisterNative(); getSubstitutions().removeRuntimeSubstitution(targetMethod); } else { - setPendingException(Meta.initException(meta.java_lang_NoSuchMethodError)); + StaticObject ex = Meta.initException(meta.java_lang_NoSuchMethodError); + getLanguage().setPendingException(EspressoException.wrap(ex, meta)); return JNI_ERR; } - Substitutions.EspressoRootNodeFactory factory = null; - // Lookup known VM methods to shortcut native boudaries. - factory = lookupKnownVmMethods(closure, targetMethod); - + // Lookup known VM methods to shortcut native boundaries. + Substitutions.EspressoRootNodeFactory factory = lookupKnownVmMethods(closure, targetMethod); if (factory == null) { NativeSignature ns = Method.buildJniNativeSignature(targetMethod.getParsedSignature()); final TruffleObject boundNative = getNativeAccess().bindSymbol(closure, ns); - factory = createJniRootNodeFactory(() -> EspressoRootNode.createNative(targetMethod.getMethodVersion(), boundNative), targetMethod); + factory = createJniRootNodeFactory(() -> EspressoRootNode.createNative(getContext().getJNI(closure), targetMethod.getMethodVersion(), boundNative), targetMethod); } Symbol classType = clazz.getMirrorKlass(getMeta()).getType(); @@ -2362,12 +2304,12 @@ public int UnregisterNatives(@JavaType(Class.class) StaticObject clazz) { * Throws OutOfMemoryError and returns 0 if fails. */ @JniImpl - public @JavaType(java.lang.reflect.Executable.class) StaticObject ToReflectedMethod(@JavaType(Class.class) StaticObject unused, @Handle(Method.class) long methodId, + public @JavaType(Executable.class) StaticObject ToReflectedMethod(@JavaType(Class.class) StaticObject unused, @Handle(Method.class) long methodId, @SuppressWarnings("unused") boolean isStatic, @Inject EspressoLanguage language) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert method.getDeclaringKlass().isAssignableFrom(unused.getMirrorKlass(getMeta())); - StaticObject methods = null; + StaticObject methods; if (method.isConstructor()) { methods = getVM().JVM_GetClassDeclaredConstructors(method.getDeclaringKlass().mirror(), false); } else { @@ -2376,7 +2318,7 @@ public int UnregisterNatives(@JavaType(Class.class) StaticObject clazz) { for (StaticObject declMethod : methods. unwrap(language)) { assert InterpreterToVM.instanceOf(declMethod, getMeta().java_lang_reflect_Executable); - Method m = null; + Method m; if (method.isConstructor()) { assert InterpreterToVM.instanceOf(declMethod, getMeta().java_lang_reflect_Constructor); m = (Method) getMeta().HIDDEN_CONSTRUCTOR_KEY.getHiddenObject(declMethod); @@ -2405,7 +2347,7 @@ public int UnregisterNatives(@JavaType(Class.class) StaticObject clazz) { @JniImpl public @JavaType(java.lang.reflect.Field.class) StaticObject ToReflectedField(@JavaType(Class.class) StaticObject unused, @Handle(Field.class) long fieldId, @SuppressWarnings("unused") boolean isStatic, @Inject EspressoLanguage language) { - Field field = fieldIds.getObject(fieldId); + Field field = fieldIds().getObject(fieldId); assert field.getDeclaringKlass().isAssignableFrom(unused.getMirrorKlass(getMeta())); StaticObject fields = getVM().JVM_GetClassDeclaredFields(field.getDeclaringKlass().mirror(), false); for (StaticObject declField : fields. unwrap(language)) { @@ -2430,7 +2372,7 @@ public int UnregisterNatives(@JavaType(Class.class) StaticObject clazz) { assert InterpreterToVM.instanceOf(field, getMeta().java_lang_reflect_Field); Field guestField = Field.getReflectiveFieldRoot(field, getMeta()); guestField.getDeclaringKlass().initialize(); - return fieldIds.handlify(guestField); + return fieldIds().handlify(guestField); } /** @@ -2439,7 +2381,7 @@ public int UnregisterNatives(@JavaType(Class.class) StaticObject clazz) { * Converts a java.lang.reflect.Method or java.lang.reflect.Constructor object to a method ID. */ @JniImpl - public @Handle(Method.class) long FromReflectedMethod(@JavaType(java.lang.reflect.Executable.class) StaticObject method) { + public @Handle(Method.class) long FromReflectedMethod(@JavaType(Executable.class) StaticObject method) { assert InterpreterToVM.instanceOf(method, getMeta().java_lang_reflect_Method) || InterpreterToVM.instanceOf(method, getMeta().java_lang_reflect_Constructor); Method guestMethod; if (InterpreterToVM.instanceOf(method, getMeta().java_lang_reflect_Method)) { @@ -2451,7 +2393,7 @@ public int UnregisterNatives(@JavaType(Class.class) StaticObject clazz) { throw EspressoError.shouldNotReachHere(); } guestMethod.getDeclaringKlass().initialize(); - return methodIds.handlify(guestMethod); + return methodIds().handlify(guestMethod); } // endregion Reflection @@ -2684,9 +2626,6 @@ public static int EnsureLocalCapacity(int capacity) { @JniImpl @NoSafepoint public int GetVersion() { - if (jniVersion == null) { - jniVersion = JniVersion.getJniVersion(getJavaVersion()); - } return jniVersion.version(); } @@ -2803,7 +2742,7 @@ public void ReleasePrimitiveArrayCritical(@JavaType(Object.class) StaticObject o @JniImpl public @JavaType(Object.class) StaticObject NewObjectVarargs(@JavaType(Class.class) StaticObject clazz, @Handle(Method.class) long methodId, @Pointer TruffleObject varargsPtr) { - Method method = methodIds.getObject(methodId); + Method method = methodIds().getObject(methodId); assert method.isConstructor(); Klass klass = clazz.getMirrorKlass(getMeta()); if (klass.isInterface() || klass.isAbstract()) { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/NativeEnv.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/NativeEnv.java index e9c3740ff53d..b1aa7035030b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/NativeEnv.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/NativeEnv.java @@ -29,7 +29,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.Function; import java.util.logging.Level; import com.oracle.truffle.api.CallTarget; @@ -105,18 +104,14 @@ protected void processCallBackResult(String name, CallableFromNative.Factory fac assert args.length == lookupCallBackArgsCount(); } - public JNIHandles getHandles() { - return jni().getHandles(); + public final JNIHandles getHandles() { + return getContext().getHandles(); } protected final InteropLibrary getUncached() { return uncached; } - protected JniEnv jni() { - return getContext().getJNI(); - } - // endregion Exposed interface // region Initialization helper @@ -213,7 +208,7 @@ private CallableFromNative.Factory lookupFactory(String methodName) { private TruffleObject createNativeClosureForFactory(CallableFromNative.Factory factory, String methodName) { // Dummy placeholder for unimplemented/unknown methods. if (factory == null) { - String envName = NativeEnv.this.getClass().getSimpleName(); + String envName = getClass().getSimpleName(); getLogger().log(Level.FINER, "Fetching unknown/unimplemented {0} method: {1}", new Object[]{envName, methodName}); @Pointer TruffleObject errorClosure = getNativeAccess().createNativeClosure(new Callback(0, new Callback.Function() { @@ -237,48 +232,21 @@ public Object call(Object... args) { } private static class NativeRootNode extends RootNode { - - @FunctionalInterface - private interface NativeEnvComputer extends Function { - NativeEnvComputer getVM = EspressoContext::getVM; - NativeEnvComputer getManagement = context -> context.getVM().getManagement(); - NativeEnvComputer getJNI = EspressoContext::getJNI; - NativeEnvComputer getJvmti = context -> context.getVM().getJvmti(); - } - @SuppressWarnings("FieldMayBeFinal") // @Child private CallableFromNative node; - private final NativeEnvComputer getNativeEnvFromContext; private final String name; + private final NativeEnv env; - NativeRootNode(EspressoLanguage language, CallableFromNative node, String name) { - super(language); + NativeRootNode(NativeEnv env, CallableFromNative node, String name) { + super(env.getLanguage()); this.node = node; this.name = name; - String generatedBy = node.generatedBy(); - switch (generatedBy) { - case "VmImpl": - getNativeEnvFromContext = NativeEnvComputer.getVM; - break; - case "ManagementImpl": - getNativeEnvFromContext = NativeEnvComputer.getManagement; - break; - case "JniImpl": - getNativeEnvFromContext = NativeEnvComputer.getJNI; - break; - case "JvmtiImpl": - getNativeEnvFromContext = NativeEnvComputer.getJvmti; - break; - default: - throw EspressoError.shouldNotReachHere("Unknown NativeEnv subclass found " + generatedBy); - } + this.env = env; } @Override public Object execute(VirtualFrame frame) { - EspressoContext context = EspressoContext.get(this); - Object nativeEnv = getNativeEnvFromContext.apply(context); - return node.invoke(nativeEnv, frame.getArguments()); + return node.invoke(env, frame.getArguments()); } @Override @@ -311,7 +279,7 @@ public Object call(Object... args) { if (actualTarget == null) { CallableFromNative subst = factory.create(); String name = getName() + '.' + factory.methodName(); - NativeRootNode rootNode = new NativeRootNode(getLanguage(), subst, name); + NativeRootNode rootNode = new NativeRootNode(NativeEnv.this, subst, name); target = actualTarget = rootNode.getCallTarget(); } } @@ -326,7 +294,7 @@ public Object call(Object... args) { : (e instanceof StackOverflowError) ? getContext().getStackOverflow() : getContext().getOutOfMemory(); - jni().setPendingException(wrappedError); + EspressoLanguage.get(null).setPendingException(wrappedError); return defaultValue(factory.returnType()); } throw e; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoRootNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoRootNode.java index 6f5fcb5a7552..f05b7d9b4db3 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoRootNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoRootNode.java @@ -41,6 +41,7 @@ import com.oracle.truffle.espresso.analysis.frame.EspressoFrameDescriptor; import com.oracle.truffle.espresso.impl.ContextAccess; import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.jni.JniEnv; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.ForeignStackTraceElementObject; @@ -212,8 +213,8 @@ public static EspressoRootNode createForBytecodes(Method.MethodVersion methodVer /** * Creates a root node that can execute a native Java method. */ - public static EspressoRootNode createNative(Method.MethodVersion methodVersion, TruffleObject nativeMethod) { - return create(null, new NativeMethodNode(nativeMethod, methodVersion)); + public static EspressoRootNode createNative(JniEnv env, Method.MethodVersion methodVersion, TruffleObject nativeMethod) { + return create(null, new NativeMethodNode(env, nativeMethod, methodVersion)); } /** diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/NativeMethodNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/NativeMethodNode.java index 0b0a68fb96d3..c71a9b134b9d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/NativeMethodNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/NativeMethodNode.java @@ -36,12 +36,14 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.descriptors.Signatures; import com.oracle.truffle.espresso.descriptors.Symbol; import com.oracle.truffle.espresso.descriptors.Symbol.Type; import com.oracle.truffle.espresso.descriptors.Types; import com.oracle.truffle.espresso.ffi.nfi.NativeUtils; import com.oracle.truffle.espresso.impl.Method.MethodVersion; +import com.oracle.truffle.espresso.jni.JNIHandles; import com.oracle.truffle.espresso.jni.JniEnv; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.perf.DebugCounter; @@ -54,27 +56,28 @@ */ @ExportLibrary(NodeLibrary.class) final class NativeMethodNode extends EspressoInstrumentableRootNodeImpl { - + private final JniEnv env; private final TruffleObject boundNative; @Child InteropLibrary executeNative; @CompilationFinal boolean throwsException; private static final DebugCounter NATIVE_METHOD_CALLS = DebugCounter.create("Native method calls"); - NativeMethodNode(TruffleObject boundNative, MethodVersion method) { + NativeMethodNode(JniEnv env, TruffleObject boundNative, MethodVersion method) { super(method); + this.env = env; this.boundNative = boundNative; this.executeNative = InteropLibrary.getFactory().create(boundNative); } @TruffleBoundary - private static Object toObjectHandle(JniEnv env, Object arg) { + private static Object toObjectHandle(JNIHandles handles, Object arg) { assert arg instanceof StaticObject; - return (long) env.getHandles().createLocal((StaticObject) arg); + return (long) handles.createLocal((StaticObject) arg); } @ExplodeLoop - private Object[] preprocessArgs(JniEnv env, Object[] args) { + private Object[] preprocessArgs(JNIHandles handles, Object[] args) { Symbol[] parsedSignature = getMethodVersion().getMethod().getParsedSignature(); int paramCount = Signatures.parameterCount(parsedSignature); Object[] nativeArgs = new Object[2 /* JNIEnv* + class or receiver */ + paramCount]; @@ -83,16 +86,16 @@ private Object[] preprocessArgs(JniEnv env, Object[] args) { nativeArgs[0] = env.getNativePointer(); // JNIEnv* if (getMethodVersion().isStatic()) { - nativeArgs[1] = toObjectHandle(env, getMethodVersion().getDeclaringKlass().mirror()); // class + nativeArgs[1] = toObjectHandle(handles, getMethodVersion().getDeclaringKlass().mirror()); // class } else { - nativeArgs[1] = toObjectHandle(env, args[0]); // receiver + nativeArgs[1] = toObjectHandle(handles, args[0]); // receiver } int skipReceiver = getMethodVersion().isStatic() ? 0 : 1; for (int i = 0; i < paramCount; ++i) { Symbol paramType = Signatures.parameterType(parsedSignature, i); if (Types.isReference(paramType)) { - nativeArgs[i + 2] = toObjectHandle(env, args[i + skipReceiver]); + nativeArgs[i + 2] = toObjectHandle(handles, args[i + skipReceiver]); } else { nativeArgs[i + 2] = args[i + skipReceiver]; } @@ -102,21 +105,21 @@ private Object[] preprocessArgs(JniEnv env, Object[] args) { @Override public Object execute(VirtualFrame frame) { - final JniEnv env = getContext().getJNI(); - int nativeFrame = env.getHandles().pushFrame(); + JNIHandles handles = getContext().getHandles(); + int nativeFrame = handles.pushFrame(); NATIVE_METHOD_CALLS.inc(); - var tls = getContext().getLanguage().getThreadLocalState(); + var tls = getLanguage().getThreadLocalState(); tls.blockContinuationSuspension(); // Can't unwind through native frames. try { - Object[] nativeArgs = preprocessArgs(env, frame.getArguments()); + Object[] nativeArgs = preprocessArgs(handles, frame.getArguments()); Object result = executeNative.execute(boundNative, nativeArgs); - return processResult(env, result); + return processResult(handles, result); } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); throw EspressoError.shouldNotReachHere(e); } finally { tls.unblockContinuationSuspension(); - env.getHandles().popFramesIncluding(nativeFrame); + handles.popFramesIncluding(nativeFrame); } } @@ -127,18 +130,18 @@ private void enterThrowsException() { } } - private void maybeThrowAndClearPendingException(JniEnv jniEnv) { - EspressoException ex = jniEnv.getPendingEspressoException(); + private void maybeThrowAndClearPendingException(EspressoLanguage language) { + EspressoException ex = language.getPendingEspressoException(); if (ex != null) { enterThrowsException(); - jniEnv.clearPendingException(); + language.clearPendingException(); throw ex; } } - private Object processResult(JniEnv env, Object result) { + private Object processResult(JNIHandles handles, Object result) { // JNI exception handling. - maybeThrowAndClearPendingException(env); + maybeThrowAndClearPendingException(EspressoLanguage.get(this)); Symbol returnType = Signatures.returnType(getMethodVersion().getMethod().getParsedSignature()); if (Types.isReference(returnType)) { long addr; @@ -148,7 +151,7 @@ private Object processResult(JniEnv env, Object result) { assert result instanceof TruffleObject; addr = NativeUtils.interopAsPointer((TruffleObject) result); } - return env.getHandles().get(Math.toIntExact(addr)); + return handles.get(Math.toIntExact(addr)); } assert !(returnType == Type._void) || result == StaticObject.NULL; return result; @@ -160,13 +163,12 @@ public int getBci(Frame frame) { } @ExportMessage - @SuppressWarnings("static-method") + @SuppressWarnings({"static-method", "MethodMayBeStatic"}) public boolean hasScope(@SuppressWarnings("unused") Frame frame) { return true; } @ExportMessage - @SuppressWarnings("static-method") public Object getScope(Frame frame, @SuppressWarnings("unused") boolean nodeEnter) { return new SubstitutionScope(frame.getArguments(), getMethodVersion()); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/AgentLibraries.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/AgentLibraries.java index 302a2c2e2fdd..4d8843741617 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/AgentLibraries.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/AgentLibraries.java @@ -42,7 +42,6 @@ import com.oracle.truffle.espresso.ffi.NativeType; import com.oracle.truffle.espresso.ffi.RawPointer; import com.oracle.truffle.espresso.impl.ContextAccessImpl; -import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.jni.RawBuffer; import com.oracle.truffle.espresso.jvmti.JvmtiPhase; import com.oracle.truffle.espresso.meta.EspressoError; @@ -59,11 +58,11 @@ final class AgentLibraries extends ContextAccessImpl { super(context); } - TruffleObject bind(Method method, String mangledName) { + TruffleObject lookupSymbol(String mangledName) { for (AgentLibrary agent : agents) { - TruffleObject bound = method.lookupAndBind(agent.lib, mangledName); - if (bound != null) { - return bound; + TruffleObject symbol = getNativeAccess().lookupSymbol(agent.lib, mangledName); + if (symbol != null) { + return symbol; } } return null; @@ -128,8 +127,7 @@ private TruffleObject lookupOnLoad(AgentLibrary agent) { } agent.lib = library; - TruffleObject onLoad = getNativeAccess().lookupAndBindSymbol(library, AGENT_ONLOAD, ONLOAD_SIGNATURE); - return onLoad; + return getNativeAccess().lookupAndBindSymbol(library, AGENT_ONLOAD, ONLOAD_SIGNATURE, true, true); } private static class AgentLibrary { 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 3c5f9ebb93fd..3dc5ff7f1406 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 @@ -86,6 +86,7 @@ import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.jdwp.api.Ids; import com.oracle.truffle.espresso.jdwp.impl.DebuggerController; +import com.oracle.truffle.espresso.jni.JNIHandles; import com.oracle.truffle.espresso.jni.JniEnv; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.meta.Meta; @@ -114,10 +115,8 @@ import sun.misc.SignalHandler; public final class EspressoContext { - // MaxJavaStackTraceDepth is 1024 by default public static final int DEFAULT_STACK_SIZE = 32; - public static final StackTraceElement[] EMPTY_STACK = new StackTraceElement[0]; private static final DebugTimer SPAWN_VM = DebugTimer.create("spawnVM"); private static final DebugTimer SYSTEM_INIT = DebugTimer.create("system init", SPAWN_VM); @@ -185,6 +184,7 @@ public final class EspressoContext { @CompilationFinal private EspressoProperties vmProperties; @CompilationFinal private AgentLibraries agents; @CompilationFinal private NativeAccess nativeAccess; + @CompilationFinal private JNIHandles handles; // endregion VM @CompilationFinal private EspressoException stackOverflow; @@ -401,6 +401,7 @@ private void spawnVM() throws ContextPatchingException { // Spawn JNI first, then the VM. try (DebugCloseable vmInit = VM_INIT.scope(espressoEnv.getTimers())) { + this.handles = new JNIHandles(); this.jniEnv = JniEnv.create(this); // libnespresso this.vm = VM.create(this.jniEnv); // libjvm vm.attachThread(Thread.currentThread()); @@ -772,14 +773,30 @@ public Signatures getSignatures() { return getLanguage().getSignatures(); } + public JNIHandles getHandles() { + return handles; + } + public JniEnv getJNI() { - if (jniEnv == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - jniEnv = JniEnv.create(this); - } return jniEnv; } + private volatile JniEnv fallbackJniEnv; + + public JniEnv getJNI(TruffleObject symbol) { + if (nativeAccess.isFallbackSymbol(symbol)) { + if (fallbackJniEnv == null) { + synchronized (this) { + if (fallbackJniEnv == null) { + fallbackJniEnv = JniEnv.createFallback(this); + } + } + } + return fallbackJniEnv; + } + return getJNI(); + } + public void disposeContext() { synchronized (this) { if (disposeCalled) { @@ -855,9 +872,9 @@ public T lookup(Class pluginType) { // region Agents - public TruffleObject bindToAgent(Method method, String mangledName) { + public TruffleObject lookupAgentSymbol(String mangledName) { if (espressoEnv.EnableAgents) { - return agents.bind(method, mangledName); + return agents.lookupSymbol(mangledName); } return null; } @@ -905,7 +922,7 @@ public void disposeThread(Thread hostThread) { getLogger().warning("unimplemented: disposeThread for non-current thread: " + hostThread + " / " + guestName + ". Called from thread: " + Thread.currentThread()); return; } - if (vm.DetachCurrentThread(this) != JNI_OK) { + if (vm.DetachCurrentThread(this, getLanguage()) != JNI_OK) { throw new RuntimeException("Could not detach thread correctly"); } } finally { 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 bf2bbef1f50e..beeab7ab64ba 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 @@ -48,7 +48,7 @@ protected DowncallStubNode(DowncallStub downcallStub, SignatureCallNode signatur } public static DowncallStubNode create(DowncallStub stub, NativeAccess access) { - return new DowncallStubNode(stub, access.createSignatureCall(stub.signature, false)); + return new DowncallStubNode(stub, access.createSignatureCall(stub.signature)); } public Object call(Object[] args) { 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 358a6376f959..8cc508458c24 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 @@ -227,6 +227,7 @@ public static final class DowncallStub { private final int captureIndex; private final int captureMask; @CompilationFinal private Object callableSignature; + @CompilationFinal private Object fallbackCallableSignature; public DowncallStub(int targetIndex, int[] shuffle, NativeSignature signature, int captureIndex, EnumSet capturedStates) { this.targetIndex = targetIndex; @@ -264,16 +265,34 @@ public TruffleObject getTarget(Object[] args, EspressoContext context) { return resolveTarget(targetHandle, context); } + private Object getCallableSignature(NativeAccess access, boolean forFallbackSymbol) { + if (forFallbackSymbol) { + return getFallbackCallableSignature(access); + } else { + return getCallableSignature(access); + } + } + private Object getCallableSignature(NativeAccess access) { if (callableSignature == null) { if (CompilerDirectives.isPartialEvaluationConstant(this)) { CompilerDirectives.transferToInterpreterAndInvalidate(); } - callableSignature = access.getCallableSignature(signature, true); + callableSignature = access.getCallableSignature(signature, false); } return callableSignature; } + private Object getFallbackCallableSignature(NativeAccess access) { + if (fallbackCallableSignature == null) { + if (CompilerDirectives.isPartialEvaluationConstant(this)) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + } + fallbackCallableSignature = access.getCallableSignature(signature, true); + } + return fallbackCallableSignature; + } + public void captureState(Object[] args, InteropLibrary interop, EspressoContext context) { try { interop.execute(context.getVM().getMokapotCaptureState(), getCaptureAddress(args), captureMask); @@ -291,7 +310,7 @@ public Object uncachedCall(Object[] args, EspressoContext context) { TruffleObject target = getTarget(args, context); NativeAccess access = context.getNativeAccess(); try { - Object result = access.callSignature(getCallableSignature(access), target, processArgs(args)); + Object result = access.callSignature(getCallableSignature(access, access.isFallbackSymbol(target)), target, processArgs(args)); if (hasCapture()) { captureState(args, InteropLibrary.getUncached(), context); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/CallableFromNative.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/CallableFromNative.java index 2bc1f7d7e0c8..a7f544a3a824 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/CallableFromNative.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/CallableFromNative.java @@ -27,6 +27,7 @@ import com.oracle.truffle.espresso.ffi.NativeSignature; import com.oracle.truffle.espresso.ffi.NativeType; import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.jni.NativeEnv; import com.oracle.truffle.espresso.meta.EspressoError; public abstract class CallableFromNative extends SubstitutionProfiler { @@ -90,7 +91,7 @@ public boolean prependEnv() { * formed as follows: {@code env} is passed first, then java objects arguments are * passed as JNI handles. */ - public abstract Object invoke(Object env, Object[] args); + public abstract Object invoke(NativeEnv env, Object[] args); /** * The method to invoke when coming from java code. diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_misc_Unsafe.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_misc_Unsafe.java index 28cb547362eb..7cae2a88def8 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_misc_Unsafe.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_misc_Unsafe.java @@ -55,7 +55,6 @@ import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.jni.JniEnv; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.meta.JavaKind; import com.oracle.truffle.espresso.meta.Meta; @@ -439,9 +438,8 @@ public static void registerNatives() { @TruffleBoundary @Substitution(hasReceiver = true, nameProvider = SharedUnsafeAppend0.class) public static long allocateMemory(@SuppressWarnings("unused") @JavaType(Unsafe.class) StaticObject self, long length, @Inject Meta meta) { - JniEnv jni = meta.getContext().getJNI(); - if (length < 0 || length > jni.sizeMax()) { - throw meta.throwExceptionWithMessage(meta.java_lang_IllegalArgumentException, "requested size doesn't fit in the size_t native type"); + if (length < 0) { + throw meta.throwExceptionWithMessage(meta.java_lang_IllegalArgumentException, "requested size is negative"); } @Buffer TruffleObject buffer = meta.getNativeAccess().allocateMemory(length); @@ -449,7 +447,7 @@ public static long allocateMemory(@SuppressWarnings("unused") @JavaType(Unsafe.c // malloc may return anything for 0-sized allocations. throw meta.throwExceptionWithMessage(meta.java_lang_OutOfMemoryError, "malloc returned NULL"); } - long ptr = 0; + long ptr; try { ptr = InteropLibrary.getUncached().asPointer(buffer); } catch (UnsupportedMessageException e) { @@ -477,16 +475,15 @@ public static long allocateMemory(@SuppressWarnings("unused") @JavaType(Unsafe.c @TruffleBoundary @Substitution(hasReceiver = true, nameProvider = SharedUnsafeAppend0.class) public static long reallocateMemory(@SuppressWarnings("unused") @JavaType(Unsafe.class) StaticObject self, long address, long newSize, @Inject Meta meta) { - JniEnv jni = meta.getContext().getJNI(); - if (newSize < 0 || newSize > jni.sizeMax()) { - throw meta.throwExceptionWithMessage(meta.java_lang_IllegalArgumentException, "requested size doesn't fit in the size_t native type"); + if (newSize < 0) { + throw meta.throwExceptionWithMessage(meta.java_lang_IllegalArgumentException, "requested size is negative"); } @Buffer TruffleObject result = meta.getNativeAccess().reallocateMemory(RawPointer.create(address), newSize); if (result == null) { throw meta.throwExceptionWithMessage(meta.java_lang_OutOfMemoryError, "realloc couldn't reallocate " + newSize + " bytes"); } - long newAddress = 0L; + long newAddress; try { newAddress = InteropLibrary.getUncached().asPointer(result); } catch (UnsupportedMessageException e) { 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 085a3ca3f4be..ea4c12c3e0b0 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 @@ -257,7 +257,8 @@ public void initializeJavaLibrary() { * we have to check for JNI_OnLoad as well. */ EspressoError.guarantee(getVM() != null, "The VM must be initialized before libjava's JNI_OnLoad"); - TruffleObject jniOnLoad = getNativeAccess().lookupAndBindSymbol(this.javaLibrary, "JNI_OnLoad", NativeSignature.create(NativeType.INT, NativeType.POINTER, NativeType.POINTER)); + NativeSignature jniOnLoadSignature = NativeSignature.create(NativeType.INT, NativeType.POINTER, NativeType.POINTER); + TruffleObject jniOnLoad = getNativeAccess().lookupAndBindSymbol(this.javaLibrary, "JNI_OnLoad", jniOnLoadSignature, false, true); if (jniOnLoad != null) { try { getUncached().execute(jniOnLoad, mokapotEnvPtr, RawPointer.nullInstance()); @@ -293,7 +294,7 @@ private VM(JniEnv jniEnv) { disposeMokapotContext = getNativeAccess().lookupAndBindSymbol(mokapotLibrary, "disposeMokapotContext", NativeSignature.create(NativeType.VOID, NativeType.POINTER, NativeType.POINTER)); - if (jniEnv.getContext().getEspressoEnv().EnableManagement) { + if (getContext().getEspressoEnv().EnableManagement) { management = new Management(getContext(), mokapotLibrary); } else { management = null; @@ -374,7 +375,7 @@ public JVMTI getJvmti() { /** * Maps native function pointers to node factories for VM methods. */ - private EconomicMap knownVmMethods = EconomicMap.create(); + private final EconomicMap knownVmMethods = EconomicMap.create(); @Override protected List getCollector() { @@ -405,7 +406,7 @@ protected NativeSignature lookupCallbackSignature() { @Override @TruffleBoundary protected void processCallBackResult(String name, CallableFromNative.Factory factory, Object... args) { - assert args.length == lookupCallBackArgsCount(); + super.processCallBackResult(name, factory, args); try { InteropLibrary uncached = InteropLibrary.getUncached(); Object ptr = args[1]; @@ -1387,7 +1388,7 @@ private int attachCurrentThread(@SuppressWarnings("unused") @Pointer TruffleObje if (InteropLibrary.getUncached().isNull(argsPtr)) { getLogger().fine("AttachCurrentThread with null args"); } else { - JavaVMAttachArgs.JavaVMAttachArgsWrapper attachArgs = getStructs().javaVMAttachArgs.wrap(jni(), argsPtr); + JavaVMAttachArgs.JavaVMAttachArgsWrapper attachArgs = getStructs().javaVMAttachArgs.wrap(getHandles(), argsPtr); if (JVM_IsSupportedJNIVersion(attachArgs.version())) { group = attachArgs.group(); name = NativeUtils.fromUTF8Ptr(attachArgs.name()); @@ -1405,7 +1406,7 @@ private int attachCurrentThread(@SuppressWarnings("unused") @Pointer TruffleObje @VmImpl @TruffleBoundary - public int DetachCurrentThread(@Inject EspressoContext context) { + public int DetachCurrentThread(@Inject EspressoContext context, @Inject EspressoLanguage language) { StaticObject currentThread = context.getCurrentPlatformThread(); if (currentThread == null) { return JNI_OK; @@ -1436,8 +1437,8 @@ public Method visitFrame(FrameInstance frameInstance) { }); return JNI_ERR; } - StaticObject pendingException = jniEnv.getPendingException(); - jniEnv.clearPendingException(); + StaticObject pendingException = language.getPendingException(); + language.clearPendingException(); Meta meta = context.getMeta(); try { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/JavaMemberOffsetGetter.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/JavaMemberOffsetGetter.java index 9ee79eeb4ac6..06ae81045035 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/JavaMemberOffsetGetter.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/JavaMemberOffsetGetter.java @@ -30,7 +30,7 @@ import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.espresso.ffi.nfi.NativeUtils; -import com.oracle.truffle.espresso.jni.JniEnv; +import com.oracle.truffle.espresso.jni.JNIHandles; /** * Uses the obtained offsets regarding the structure that stores offset information to build the @@ -42,17 +42,17 @@ public class JavaMemberOffsetGetter implements MemberOffsetGetter { private final Map memberInfos; - public JavaMemberOffsetGetter(JniEnv jni, TruffleObject memberInfo, Structs structs) { - this.memberInfos = buildInfos(jni, structs, memberInfo); + public JavaMemberOffsetGetter(JNIHandles handles, TruffleObject memberInfo, Structs structs) { + this.memberInfos = buildInfos(handles, structs, memberInfo); } - private static Map buildInfos(JniEnv jni, Structs structs, TruffleObject info) { + private static Map buildInfos(JNIHandles handles, Structs structs, TruffleObject info) { Map map = new HashMap<>(); InteropLibrary library = InteropLibrary.getUncached(); assert !library.isNull(info); TruffleObject current = NativeUtils.dereferencePointerPointer(library, info); while (!library.isNull(current)) { - MemberInfo.MemberInfoWrapper wrapper = structs.memberInfo.wrap(jni, current); + MemberInfo.MemberInfoWrapper wrapper = structs.memberInfo.wrap(handles, current); long offset = wrapper.offset(); String str = NativeUtils.interopPointerToString(wrapper.id()); map.put(str, offset); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructStorage.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructStorage.java index 40eee298b2dd..32dca3821c32 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructStorage.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructStorage.java @@ -25,7 +25,7 @@ import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.espresso.ffi.NativeAccess; -import com.oracle.truffle.espresso.jni.JniEnv; +import com.oracle.truffle.espresso.jni.JNIHandles; /** * Commodity class that stores native structs sizes, along with member offsets. See documentation @@ -38,11 +38,11 @@ public StructStorage(long structSize) { this.structSize = structSize; } - public abstract T wrap(JniEnv jni, TruffleObject structPtr); + public abstract T wrap(JNIHandles handles, TruffleObject structPtr); - public T allocate(NativeAccess nativeAccess, JniEnv jni) { + public T allocate(NativeAccess nativeAccess, JNIHandles handles) { TruffleObject pointer = nativeAccess.allocateMemory(structSize); - return wrap(jni, pointer); + return wrap(handles, pointer); } public long structSize() { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructWrapper.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructWrapper.java index 8eacc45cbd53..3ae5497dee80 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructWrapper.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructWrapper.java @@ -20,7 +20,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package com.oracle.truffle.espresso.vm.structs; import static com.oracle.truffle.espresso.ffi.NativeType.BOOLEAN; @@ -36,7 +35,6 @@ import com.oracle.truffle.espresso.ffi.RawPointer; import com.oracle.truffle.espresso.ffi.nfi.NativeUtils; import com.oracle.truffle.espresso.jni.JNIHandles; -import com.oracle.truffle.espresso.jni.JniEnv; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.vm.structs.GenerateStructs.KnownStruct; @@ -51,7 +49,7 @@ * the processor will generate two classes for each of them: *

      *
    • A {@link StructStorage storage class} to store the size of the struct, and the offsets of - * each struct member. It also provides a {@link StructStorage#wrap(JniEnv, TruffleObject) wrap} + * each struct member. It also provides a {@link StructStorage#wrap(JNIHandles, TruffleObject)} * method, that returns an instance of {@link StructWrapper this class}. These classes are intended * to be per-context singletons.
    • *
    • A {@link StructWrapper wrapper class}, as described above. This generated class will also @@ -736,9 +734,8 @@ public void free(NativeAccess nativeAccess) { nativeAccess.freeMemory(pointer); } - protected StructWrapper(JniEnv jni, TruffleObject pointer, long capacity) { - this.handles = jni.getHandles(); - + protected StructWrapper(JNIHandles handles, TruffleObject pointer, long capacity) { + this.handles = handles; this.pointer = pointer; this.buffer = NativeUtils.directByteBuffer(pointer, capacity); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructsAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructsAccess.java index 03451470eb90..fe7bbc0af1e0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructsAccess.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructsAccess.java @@ -20,7 +20,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package com.oracle.truffle.espresso.vm.structs; import com.oracle.truffle.api.CompilerDirectives; @@ -29,11 +28,11 @@ import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; +import com.oracle.truffle.espresso.ffi.Callback; import com.oracle.truffle.espresso.ffi.NativeSignature; import com.oracle.truffle.espresso.ffi.NativeType; import com.oracle.truffle.espresso.ffi.Pointer; import com.oracle.truffle.espresso.ffi.RawPointer; -import com.oracle.truffle.espresso.ffi.Callback; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.perf.DebugCloseable; import com.oracle.truffle.espresso.perf.DebugTimer; @@ -64,7 +63,7 @@ private static Structs initializeStructs(EspressoContext context, TruffleObject @CompilerDirectives.TruffleBoundary public Object call(Object... args) { TruffleObject memberInfoPtr = (TruffleObject) args[0]; - box[0] = new Structs(context.getJNI(), memberInfoPtr, lookupMemberOffset); + box[0] = new Structs(context.getHandles(), memberInfoPtr, lookupMemberOffset); return RawPointer.nullInstance(); } }); From caec6f0cc82bef56a020411b84fb6a71abbd0fa3 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Wed, 23 Oct 2024 18:19:26 +0200 Subject: [PATCH 082/105] The enable-native-access JDK option is added only to Truffle launchers. --- sdk/mx.sdk/mx_sdk_vm_impl.py | 2 ++ sdk/mx.sdk/vm/launcher_template.cmd | 2 +- sdk/mx.sdk/vm/launcher_template.sh | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sdk/mx.sdk/mx_sdk_vm_impl.py b/sdk/mx.sdk/mx_sdk_vm_impl.py index 9538f5227f9a..f682f1c497c4 100644 --- a/sdk/mx.sdk/mx_sdk_vm_impl.py +++ b/sdk/mx.sdk/mx_sdk_vm_impl.py @@ -2301,6 +2301,8 @@ def _get_main_module(): def _get_extra_jvm_args(): image_config = self.subject.native_image_config extra_jvm_args = mx.list_to_cmd_line(image_config.extra_jvm_args) + if isinstance(self.subject.component, mx_sdk.GraalVmTruffleComponent) or image_config.is_polyglot: + extra_jvm_args = ' '.join([extra_jvm_args, '--enable-native-access=org.graalvm.truffle']) if not _jlink_libraries(): if mx.is_windows(): extra_jvm_args = ' '.join([extra_jvm_args, r'--upgrade-module-path "%location%\..\..\jvmci\graal.jar"']) diff --git a/sdk/mx.sdk/vm/launcher_template.cmd b/sdk/mx.sdk/vm/launcher_template.cmd index a07f2429cbd4..fcf38c325f51 100644 --- a/sdk/mx.sdk/vm/launcher_template.cmd +++ b/sdk/mx.sdk/vm/launcher_template.cmd @@ -51,7 +51,7 @@ for /f "delims=" %%i in ("%relcp:;=!newline!%") do ( ) ) -set "jvm_args=--enable-native-access=org.graalvm.truffle -Dorg.graalvm.launcher.shell=true "-Dorg.graalvm.launcher.executablename=%executablename%"" +set "jvm_args=-Dorg.graalvm.launcher.shell=true "-Dorg.graalvm.launcher.executablename=%executablename%"" set "launcher_args=" :: Check option-holding variables. diff --git a/sdk/mx.sdk/vm/launcher_template.sh b/sdk/mx.sdk/vm/launcher_template.sh index ba3238b4f1cf..cc5044a342b4 100644 --- a/sdk/mx.sdk/vm/launcher_template.sh +++ b/sdk/mx.sdk/vm/launcher_template.sh @@ -42,7 +42,7 @@ for e in "${relative_cp[@]}"; do absolute_cp+=("${location}/${e}") done -jvm_args=("--enable-native-access=org.graalvm.truffle" "-Dorg.graalvm.launcher.shell=true" "-Dorg.graalvm.launcher.executablename=$0") +jvm_args=("-Dorg.graalvm.launcher.shell=true" "-Dorg.graalvm.launcher.executablename=$0") launcher_args=() # Unfortunately, parsing of `--vm.*` arguments has to be done blind: From d7fb40fe7387e4252c248d709907af57b569aa28 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 7 Aug 2024 04:13:36 +0200 Subject: [PATCH 083/105] Optimize Node.clearInputs() for large usage lists. Try to coalesce repeated removal of the node from the usages of the same input to a single removeUsageNTimes() to more efficiently handle the case where the same input occurs more than once. --- .../src/jdk/graal/compiler/graph/Node.java | 46 ++++++++++- .../jdk/graal/compiler/graph/NodeClass.java | 79 +++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java index 97e85d4b9aa9..c1a2425b2d3a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/Node.java @@ -40,7 +40,6 @@ import java.util.function.Predicate; import java.util.function.Supplier; -import jdk.graal.compiler.serviceprovider.GraalServices; import org.graalvm.collections.EconomicSet; import jdk.graal.compiler.core.common.Fields; @@ -61,6 +60,7 @@ import jdk.graal.compiler.nodeinfo.Verbosity; import jdk.graal.compiler.nodes.spi.Simplifiable; import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.serviceprovider.GraalServices; import jdk.internal.misc.Unsafe; /** @@ -644,6 +644,50 @@ public boolean removeUsage(Node node) { return false; } + /** + * Removes (at most) an expected number of occurrences of a given node from this node's + * {@linkplain #usages() usages}. This is significantly faster than repeated execution of + * {@link #removeUsage(Node)} of the same usage from this node, since the usages have to be + * traversed only once. + * + * @param node the node to remove from the usages + * @param limit the number of matching usages to remove (at most) + * @return the number of actually removed usages + */ + public int removeUsageNTimes(Node node, int limit) { + if (limit == 0) { + return 0; + } else if (limit == 1) { + return removeUsage(node) ? 1 : 0; + } + // requires iteration from back to front to check nodes prior to being moved to the front + int removedUsages = 0; + for (int i = extraUsagesCount - 1; i >= 0; i--) { + if (extraUsages[i] == node) { + movUsageFromEndToExtraUsages(i); + incUsageModCount(); + if (++removedUsages == limit) { + return removedUsages; + } + } + } + if (usage1 == node) { + movUsageFromEndToIndexOne(); + incUsageModCount(); + if (++removedUsages == limit) { + return removedUsages; + } + } + if (usage0 == node) { + movUsageFromEndToIndexZero(); + incUsageModCount(); + if (++removedUsages == limit) { + return removedUsages; + } + } + return removedUsages; + } + /** * Removes all nodes in the provided set from {@code this} node's usages. This is significantly * faster than repeated execution of {@link Node#removeUsage}. diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeClass.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeClass.java index fb28e7bdfcd7..797261d13dc0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeClass.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeClass.java @@ -97,6 +97,7 @@ public final class NodeClass extends FieldIntrospection { public static final long OFFSET_MASK = 0xFC; public static final long LIST_MASK = 0x01; public static final long NEXT_EDGE = 0x08; + private static final int SHORT_INPUT_LIST_THRESHOLD = 3; @SuppressWarnings("try") private static T getAnnotationTimed(AnnotatedElement e, Class annotationClass, DebugContext debug) { @@ -1470,6 +1471,11 @@ public void unregisterAtInputsAsUsage(Node node) { private static void unregisterAtInputsAsUsageHelper(Node node, long offset) { NodeList list = Edges.getNodeListUnsafe(node, offset); if (list != null) { + if (list.size() > SHORT_INPUT_LIST_THRESHOLD) { + // Fast path for longer input lists + unregisterAtInputsAsUsageHelperMany(node, list); + return; + } for (int i = 0; i < list.size(); ++i) { Node curNode = list.get(i); if (curNode != null) { @@ -1482,4 +1488,77 @@ private static void unregisterAtInputsAsUsageHelper(Node node, long offset) { list.clearWithoutUpdate(); } } + + /** + * Optimized version of {@link #unregisterAtInputsAsUsageHelper} that is faster for nodes that + * have many input edges leading to the same value node. + *

      + * Removes batches of the same input value at once, in order to reduce repeated traversals of + * potentially long usage lists. This allows faster clearing of nodes with many input edges to + * the same value, i.e., the usage list of one input node may include the same usage many times, + * and removing each occurrence of this usage one by one can be slow if the input value has many + * usages in the graph (as is commonly the case with constant nodes, like null). + *

      + * For example, considering a node with 6 inputs like this: + * + *

      +     *                         |Other|
      +     * C(null) C(null) C(null)    |    C(null) C(null)
      +     *     \      |       |       |       |      /
      +     *   +-----------------------------------------+
      +     *   |   usage node (e.g. VirtualObjectState)  |
      +     *   +-----------------------------------------+
      +     * 
      + * + * We can batch-remove this node from its inputs' usages as follows, depending on + * maxOtherEdgesToLookPast (i.e. the maximum number of other input edges to look past): + *
        + *
      • If maxOtherEdgesToLookPast = 0, we consider only consecutive occurrences of the same + * input node (here: 3 * null + 1 * other + 2 * null). + *
      • If maxOtherEdgesToLookPast = 1, we look past one other input to find more occurrences of + * the same input node to be removed at once (here: 5 * null + 1 * other). Note that we need to + * null out any input slots that would otherwise be processed again. + *
      + */ + private static void unregisterAtInputsAsUsageHelperMany(Node node, NodeList list) { + final int maxOtherEdgesToLookPast = 1; + int size = list.size(); + int i = 0; // Avoid checkstyle warning: Control variable 'i' is modified. + for (; i < size; i++) { + Node curNode = list.get(i); + if (curNode != null) { + // Find more occurrences of the same input node to remove at once. + int sameInputEdges = 1; + int otherInputEdges = 0; + for (int j = i + 1; j < size && otherInputEdges <= maxOtherEdgesToLookPast; j++) { + Node nextNode = list.get(j); + if (nextNode != null) { + if (nextNode == curNode) { + sameInputEdges++; + if (otherInputEdges != 0) { + // Clear NodeList slot without update. + list.initialize(j, null); + } + } else { + otherInputEdges++; + } + } + if (otherInputEdges == 0) { + /* + * As long as we've only seen the same input node or null, there's no need + * to backtrack from here, so we can advance the outer loop accordingly. + * Otherwise, we'll need to continue from first unprocessed "other" edge + * (already processed edges will have been set to null, and be ignored). + */ + i = j; + } + } + curNode.removeUsageNTimes(node, sameInputEdges); + if (curNode.hasNoUsages()) { + node.maybeNotifyZeroUsages(curNode); + } + } + } + list.clearWithoutUpdate(); + } } From 086553f630e9c4d61a3d21eee220d15092dfd4a8 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Wed, 23 Oct 2024 18:07:43 +0000 Subject: [PATCH 084/105] Update language imports --- vm/mx.vm/suite.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index be0e2cff76bb..9d0d776288e8 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -33,7 +33,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "fad9af323bbf014168bda8f1aae3c96b08c7d33e", + "version": "fd636bb71941edceafcd36f007944231dbf9022b", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] @@ -42,14 +42,14 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "fad9af323bbf014168bda8f1aae3c96b08c7d33e", + "version": "fd636bb71941edceafcd36f007944231dbf9022b", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] }, { "name": "truffleruby", - "version": "495a0e5cc6911e01b021fc9aace1137c1492b496", + "version": "b359f4c54c4085ea13390443b62da36d387fba13", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/truffleruby.git", "kind": "git"}, @@ -57,7 +57,7 @@ }, { "name": "fastr", - "version": "1658d1da277317d33d03367146ee56f756496610", + "version": "da31f24212fc71f2635277dee5ecb79d9c037f16", "dynamic": True, "urls": [ {"url": "https://github.com/oracle/fastr.git", "kind": "git"}, @@ -65,7 +65,7 @@ }, { "name": "graalpython", - "version": "d591da47a62a6a4bbee22d8cb824390f222bfa53", + "version": "baec9ea1fc095cc02e243d962089e6b40081fefc", "dynamic": True, "urls": [ {"url": "https://github.com/graalvm/graalpython.git", "kind": "git"}, From ff719b39ca538161384410182abda54d7e9428f1 Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Thu, 24 Oct 2024 08:11:58 +0200 Subject: [PATCH 085/105] [GR-58575] SubstrateVM PLT/GOT Feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces an additional level of indirection for calls where a GOT (Global Offset Table) is an array of method pointers and PLT (Procedure Linkage Table) is a collection of small stubs. With this feature enabled, direct calls are emitted as indirect calls through the GOT. The virtual table is filled with PLT stubs instead. While inspired by ELF, no ELF mechanisms are used in the implementation. Example usecase: Hijack code execution on call boundaries to diverge execution from AOT code to an interpreter. Contributors: - Aleksandar Gradinac: Initial implementation on linux-amd64. - Marko Spasic: Miscellaneous improvements. - Bernhard Urban-Forster: Support for linux-aarch64, darwin-aarch64 and darwin-amd64. - Alfonso² Peterssen: Support for windows-amd64. Co-authored-by: Aleksandar Gradinac Co-authored-by: Marko Spasic Co-authored-by: Alfonso² Peterssen --- substratevm/mx.substratevm/suite.py | 8 +- .../aarch64/SubstrateAArch64Backend.java | 9 + .../graal/amd64/SubstrateAMD64Backend.java | 11 +- .../svm/core/graal/llvm/LLVMGenerator.java | 5 + .../posix/darwin/DarwinGOTHeapSupport.java | 115 ++++++++ .../posix/darwin/DarwinPLTGOTFeature.java | 47 ++++ .../core/posix/linux/LinuxGOTHeapSupport.java | 153 +++++++++++ .../core/posix/linux/LinuxPLTGOTFeature.java | 47 ++++ .../core/windows/WindowsGOTHeapSupport.java | 112 ++++++++ .../core/windows/WindowsPLTGOTFeature.java | 47 ++++ .../graal/code/SubstrateLIRGenerator.java | 2 + .../ExitMethodAddressResolutionNode.java | 61 +++++ .../com/oracle/svm/core/pltgot/GOTAccess.java | 55 ++++ .../svm/core/pltgot/GOTHeapSupport.java | 162 +++++++++++ .../pltgot/IdentityMethodAddressResolver.java | 54 ++++ .../MethodAddressResolutionDispatcher.java | 65 +++++ .../core/pltgot/MethodAddressResolver.java | 40 +++ .../svm/core/pltgot/PLTGOTConfiguration.java | 52 ++++ .../AArch64ExitMethodAddressResolutionOp.java | 52 ++++ ...ch64MethodAddressResolutionDispatcher.java | 60 +++++ .../AMD64ExitMethodAddressResolutionOp.java | 52 ++++ ...MD64MethodAddressResolutionDispatcher.java | 63 +++++ .../com/oracle/svm/graal/pltgot/GOTCall.java | 35 +++ .../pltgot/PLTGOTNonSnippetLowerings.java | 130 +++++++++ .../pltgot/SubstrateGOTCallTargetNode.java | 45 ++++ .../aarch64/PLTGOTAArch64Lowerings.java | 67 +++++ .../pltgot/amd64/PLTGOTAMD64Lowerings.java | 67 +++++ .../com/oracle/svm/hosted/FeatureImpl.java | 10 +- .../svm/hosted/NativeImageGenerator.java | 3 +- ...llectPLTGOTCallSitesResolutionSupport.java | 88 ++++++ .../svm/hosted/pltgot/GOTEntryAllocator.java | 79 ++++++ .../pltgot/HostedPLTGOTConfiguration.java | 98 +++++++ .../IdentityMethodAddressResolverFeature.java | 168 ++++++++++++ .../MethodAddressResolutionSupport.java | 60 +++++ ...MethodAddressResolutionSupportFactory.java | 29 ++ .../svm/hosted/pltgot/PLTGOTFeature.java | 255 ++++++++++++++++++ .../svm/hosted/pltgot/PLTGOTOptions.java | 41 +++ .../PLTGOTPointerRelocationProvider.java | 65 +++++ .../svm/hosted/pltgot/PLTSectionSupport.java | 110 ++++++++ .../svm/hosted/pltgot/PLTStubGenerator.java | 39 +++ .../AArch64HostedPLTGOTConfiguration.java | 67 +++++ .../aarch64/AArch64PLTStubGenerator.java | 182 +++++++++++++ .../amd64/AMD64HostedPLTGOTConfiguration.java | 66 +++++ .../pltgot/amd64/AMD64PLTStubGenerator.java | 167 ++++++++++++ 44 files changed, 3136 insertions(+), 7 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinGOTHeapSupport.java create mode 100644 substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinPLTGOTFeature.java create mode 100644 substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxGOTHeapSupport.java create mode 100644 substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxPLTGOTFeature.java create mode 100644 substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsGOTHeapSupport.java create mode 100644 substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPLTGOTFeature.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/ExitMethodAddressResolutionNode.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/GOTAccess.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/GOTHeapSupport.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/IdentityMethodAddressResolver.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/MethodAddressResolutionDispatcher.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/MethodAddressResolver.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/PLTGOTConfiguration.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/aarch64/AArch64ExitMethodAddressResolutionOp.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/aarch64/AArch64MethodAddressResolutionDispatcher.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/amd64/AMD64ExitMethodAddressResolutionOp.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/amd64/AMD64MethodAddressResolutionDispatcher.java create mode 100644 substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/GOTCall.java create mode 100644 substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/PLTGOTNonSnippetLowerings.java create mode 100644 substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/SubstrateGOTCallTargetNode.java create mode 100644 substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/aarch64/PLTGOTAArch64Lowerings.java create mode 100644 substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/amd64/PLTGOTAMD64Lowerings.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/CollectPLTGOTCallSitesResolutionSupport.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/GOTEntryAllocator.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/HostedPLTGOTConfiguration.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/IdentityMethodAddressResolverFeature.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/MethodAddressResolutionSupport.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/MethodAddressResolutionSupportFactory.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTFeature.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTOptions.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTPointerRelocationProvider.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTSectionSupport.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTStubGenerator.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/aarch64/AArch64HostedPLTGOTConfiguration.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/aarch64/AArch64PLTStubGenerator.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/amd64/AMD64HostedPLTGOTConfiguration.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/amd64/AMD64PLTStubGenerator.java diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 677ef89796ce..415f8587a603 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -480,7 +480,7 @@ "subDir": "src", "sourceDirs": ["src"], "dependencies": [ - "com.oracle.svm.core.graal.amd64", + "com.oracle.svm.hosted", "com.oracle.svm.core.graal.aarch64", "com.oracle.svm.core.graal.riscv64", ], @@ -511,7 +511,7 @@ "subDir": "src", "sourceDirs": ["src"], "dependencies": [ - "com.oracle.svm.core.graal.amd64", + "com.oracle.svm.hosted", ], "requiresConcealed" : { "jdk.internal.vm.ci" : [ @@ -639,8 +639,8 @@ "sourceDirs": ["src"], "dependencies": [ "com.oracle.objectfile", - "com.oracle.svm.core", - "com.oracle.graal.reachability" + "com.oracle.graal.reachability", + "com.oracle.svm.core.graal.amd64", ], "requires" : [ "jdk.jfr", diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java index 12598c0855fb..b87390e83b09 100755 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java @@ -72,6 +72,7 @@ import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.nodes.SafepointCheckNode; +import com.oracle.svm.core.pltgot.PLTGOTConfiguration; import com.oracle.svm.core.thread.VMThreads.StatusSupport; import com.oracle.svm.core.util.VMError; @@ -667,6 +668,14 @@ public Register getHeapBaseRegister() { protected int getVMPageSize() { return SubstrateOptions.getPageSize(); } + + @Override + public void emitExitMethodAddressResolution(Value ip) { + PLTGOTConfiguration configuration = PLTGOTConfiguration.singleton(); + RegisterValue exitThroughRegisterValue = configuration.getExitMethodAddressResolutionRegister(getRegisterConfig()).asValue(ip.getValueKind()); + emitMove(exitThroughRegisterValue, ip); + append(configuration.createExitMethodAddressResolutionOp(exitThroughRegisterValue)); + } } public class SubstrateAArch64NodeLIRBuilder extends AArch64NodeLIRBuilder implements SubstrateNodeLIRBuilder { diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java index 97ab24224391..1f3ffa102aff 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java @@ -93,6 +93,7 @@ import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.nodes.SafepointCheckNode; +import com.oracle.svm.core.pltgot.PLTGOTConfiguration; import com.oracle.svm.core.thread.VMThreads.StatusSupport; import com.oracle.svm.core.util.VMError; @@ -748,6 +749,14 @@ public void emitInstructionSynchronizationBarrier() { throw shouldNotReachHere("AMD64 does not need instruction synchronization"); } + @Override + public void emitExitMethodAddressResolution(Value ip) { + PLTGOTConfiguration configuration = PLTGOTConfiguration.singleton(); + RegisterValue exitThroughRegisterValue = configuration.getExitMethodAddressResolutionRegister(getRegisterConfig()).asValue(ip.getValueKind()); + emitMove(exitThroughRegisterValue, ip); + append(configuration.createExitMethodAddressResolutionOp(exitThroughRegisterValue)); + } + @Override public void emitFarReturn(AllocatableValue result, Value sp, Value ip, boolean fromMethodWithCalleeSavedRegisters) { append(new AMD64FarReturnOp(result, asAllocatable(sp), asAllocatable(ip), fromMethodWithCalleeSavedRegisters)); @@ -1813,7 +1822,7 @@ public void emitCode(CompilationResultBuilder crb, ResolvedJavaMethod installedC } } - private AMD64Assembler createAssemblerNoOptions() { + public AMD64Assembler createAssemblerNoOptions() { OptionValues o = new OptionValues(EconomicMap.create()); return createAssembler(o); } diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java index 4761dbda4642..4e213d0a817a 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java @@ -1147,6 +1147,11 @@ public void emitInstructionSynchronizationBarrier() { throw unimplemented("the LLVM backend doesn't support instruction synchronization"); // ExcludeFromJacocoGeneratedReport } + @Override + public void emitExitMethodAddressResolution(Value ip) { + throw unimplemented("the LLVM backend doesn't support PLT/GOT"); // ExcludeFromJacocoGeneratedReport + } + @Override public I append(I op) { throw unimplemented("the LLVM backend doesn't support LIR instructions"); // ExcludeFromJacocoGeneratedReport diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinGOTHeapSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinGOTHeapSupport.java new file mode 100644 index 000000000000..489fea0db173 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinGOTHeapSupport.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.posix.darwin; + +import static com.oracle.svm.core.posix.headers.Mman.MAP_ANON; +import static com.oracle.svm.core.posix.headers.Mman.MAP_FAILED; +import static com.oracle.svm.core.posix.headers.Mman.MAP_PRIVATE; +import static com.oracle.svm.core.posix.headers.Mman.PROT_READ; +import static com.oracle.svm.core.posix.headers.Mman.PROT_WRITE; +import static com.oracle.svm.core.posix.headers.Mman.NoTransitions.mmap; + +import org.graalvm.nativeimage.StackValue; +import org.graalvm.nativeimage.c.type.CIntPointer; +import org.graalvm.nativeimage.c.type.WordPointer; +import org.graalvm.word.Pointer; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.c.CGlobalData; +import com.oracle.svm.core.c.CGlobalDataFactory; +import com.oracle.svm.core.c.function.CEntryPointErrors; +import com.oracle.svm.core.headers.LibC; +import com.oracle.svm.core.os.VirtualMemoryProvider; +import com.oracle.svm.core.os.VirtualMemoryProvider.Access; +import com.oracle.svm.core.pltgot.GOTHeapSupport; +import com.oracle.svm.core.posix.headers.darwin.DarwinVirtualMemory; + +public class DarwinGOTHeapSupport extends GOTHeapSupport { + + private static final CGlobalData DARWIN_GOT_START_ADDRESS = CGlobalDataFactory.createWord(); + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected int initialize(WordPointer gotStartAddress) { + int flags = MAP_ANON() | MAP_PRIVATE(); + Pointer gotMemory = mmap(WordFactory.nullPointer(), getPageAlignedGotSize(), PROT_READ() | PROT_WRITE(), flags, -1, 0); + if (gotMemory.isNull() || gotMemory.equal(MAP_FAILED())) { + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_FD_CREATE_FAILED; + } + + Pointer gotStartInMemory = gotMemory.add(getGotOffsetFromStartOfMapping()); + LibC.memcpy(gotStartInMemory, IMAGE_GOT_BEGIN.get(), getGotSectionSize()); + + gotStartAddress.write(gotMemory); + DARWIN_GOT_START_ADDRESS.get().write(gotMemory); + + return CEntryPointErrors.NO_ERROR; + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public int mapGot(Pointer start) { + WordPointer taskSelf = DarwinVirtualMemory.mach_task_self(); + + /* Unmap part of the heap address space that is designated for the GOT */ + int ret = DarwinVirtualMemory.vm_deallocate(DarwinVirtualMemory.mach_task_self(), start, getPageAlignedGotSize()); + if (ret != 0) { + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_MMAP_FAILED; + } + + WordPointer gotStart = StackValue.get(WordPointer.class); + gotStart.write(start); + + CIntPointer currentProt = StackValue.get(CIntPointer.class); + CIntPointer maxProt = StackValue.get(CIntPointer.class); + + int intFalse = 0; + + /* + * Map reserved address space for GOT to "global" GOT allocation, so that all isolates are + * backed by the same table. + */ + ret = DarwinVirtualMemory.vm_remap(taskSelf, gotStart, getPageAlignedGotSize(), WordFactory.nullPointer(), intFalse, + taskSelf, DARWIN_GOT_START_ADDRESS.get().read(), intFalse, currentProt, maxProt, DarwinVirtualMemory.VM_INHERIT_SHARE()); + if (ret != 0) { + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_WRONG_MMAP; + } + + /* + * The new mapping "inherits" cur_prot and max_prot from the original mapping, but another + * isolate could race trying to write the original GOT => the new mapping could inherit + * cur_prot=RW. Ensure that the new-mapping remains read-only, regardless of races. + */ + if (currentProt.read() != PROT_READ()) { + ret = VirtualMemoryProvider.get().protect(start, getPageAlignedGotSize(), Access.READ); + if (ret != 0) { + return ret; + } + } + + return CEntryPointErrors.NO_ERROR; + } +} diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinPLTGOTFeature.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinPLTGOTFeature.java new file mode 100644 index 000000000000..d15b4d87b74f --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/darwin/DarwinPLTGOTFeature.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.posix.darwin; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; + +import com.oracle.svm.core.code.DynamicMethodAddressResolutionHeapSupport; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.hosted.pltgot.PLTGOTOptions; + +@AutomaticallyRegisteredFeature +public class DarwinPLTGOTFeature implements InternalFeature { + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return Platform.includedIn(Platform.DARWIN.class) && PLTGOTOptions.EnablePLTGOT.getValue(); + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + ImageSingletons.add(DynamicMethodAddressResolutionHeapSupport.class, new DarwinGOTHeapSupport()); + } +} diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxGOTHeapSupport.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxGOTHeapSupport.java new file mode 100644 index 000000000000..cddb80ab1096 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxGOTHeapSupport.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.posix.linux; + +import static com.oracle.svm.core.posix.headers.Mman.MAP_SHARED; +import static com.oracle.svm.core.posix.headers.Mman.PROT_READ; +import static com.oracle.svm.core.posix.headers.Mman.PROT_WRITE; +import static com.oracle.svm.core.posix.headers.Mman.NoTransitions.mmap; +import static com.oracle.svm.core.posix.headers.Mman.NoTransitions.shm_open; +import static com.oracle.svm.core.posix.headers.Mman.NoTransitions.shm_unlink; + +import org.graalvm.nativeimage.StackValue; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.nativeimage.c.type.CCharPointer; +import org.graalvm.nativeimage.c.type.WordPointer; +import org.graalvm.word.Pointer; +import org.graalvm.word.SignedWord; +import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordBase; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.c.CGlobalData; +import com.oracle.svm.core.c.CGlobalDataFactory; +import com.oracle.svm.core.c.function.CEntryPointErrors; +import com.oracle.svm.core.headers.LibC; +import com.oracle.svm.core.os.VirtualMemoryProvider; +import com.oracle.svm.core.os.VirtualMemoryProvider.Access; +import com.oracle.svm.core.pltgot.GOTHeapSupport; +import com.oracle.svm.core.posix.headers.Errno; +import com.oracle.svm.core.posix.headers.Fcntl; +import com.oracle.svm.core.posix.headers.Unistd; +import com.oracle.svm.core.thread.VMThreads; + +public class LinuxGOTHeapSupport extends GOTHeapSupport { + + private static final String FILE_NAME_PREFIX = "/ni-got-"; + private static final int FILE_NAME_PREFIX_LEN = FILE_NAME_PREFIX.length(); + private static final CGlobalData memoryViewFd = CGlobalDataFactory.createWord((WordBase) WordFactory.signed(-1)); + private static final CGlobalData fileNamePrefix = CGlobalDataFactory.createCString(FILE_NAME_PREFIX); + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected int initialize(WordPointer gotStartAddress) { + int pid = Unistd.NoTransitions.getpid(); + int pidLen = 0; + int temp = pid; + while (temp != 0) { + pidLen++; + temp /= 10; + } + + /* GOT shared memory file name format: fileNamePrefix-pid */ + CCharPointer nameStr = StackValue.get(64 * SizeOf.get(CCharPointer.class)); + LibC.memcpy(nameStr, fileNamePrefix.get(), WordFactory.unsigned(FILE_NAME_PREFIX_LEN)); + + int iter = FILE_NAME_PREFIX_LEN + pidLen; + nameStr.write(iter, (byte) '\0'); + temp = pid; + + while (temp != 0) { + iter--; + nameStr.write(iter, (byte) ('0' + (temp % 10))); + temp /= 10; + } + + int fd = -1; + for (int i = 0; i < 10; ++i) { + fd = shm_open(nameStr, Fcntl.O_CREAT() | Fcntl.O_EXCL() | Fcntl.O_RDWR(), 0); + if (fd == -1) { + int errno = LibC.errno(); + if (errno != Errno.EEXIST()) { + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_FD_CREATE_FAILED; + } + VMThreads.singleton().nativeSleep(5); + } else { + shm_unlink(nameStr); + break; + } + } + + if (fd == -1) { + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_UNIQUE_FILE_CREATE_FAILED; + } + + UnsignedWord gotPageAlignedSize = getPageAlignedGotSize(); + + if (Unistd.NoTransitions.ftruncate(fd, WordFactory.signed(gotPageAlignedSize.rawValue())) != 0) { + Unistd.NoTransitions.close(fd); + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_FD_RESIZE_FAILED; + } + + Pointer gotMemory = mmap(WordFactory.nullPointer(), gotPageAlignedSize, PROT_READ() | PROT_WRITE(), MAP_SHARED(), fd, 0); + if (gotMemory.isNull()) { + Unistd.NoTransitions.close(fd); + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_FD_MAP_FAILED; + } + + Pointer gotStartInMemory = gotMemory.add(getGotOffsetFromStartOfMapping()); + LibC.memcpy(gotStartInMemory, IMAGE_GOT_BEGIN.get(), getGotSectionSize()); + + /* Keep the initial GOT mapping for writing. */ + + memoryViewFd.get().write(WordFactory.signed(fd)); + gotStartAddress.write(gotMemory); + + return CEntryPointErrors.NO_ERROR; + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public int mapGot(Pointer start) { + SignedWord memViewFd = memoryViewFd.get().read(); + if (memViewFd.lessThan(0)) { + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_FD_INVALID; + } + + Pointer mappedAddress = VirtualMemoryProvider.get().mapFile( + start, + getPageAlignedGotSize(), + memViewFd, + WordFactory.zero(), + Access.READ); + + if (mappedAddress.isNull()) { + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_MMAP_FAILED; + } + + return CEntryPointErrors.NO_ERROR; + } +} diff --git a/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxPLTGOTFeature.java b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxPLTGOTFeature.java new file mode 100644 index 000000000000..3accab55cfe2 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/linux/LinuxPLTGOTFeature.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.posix.linux; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; + +import com.oracle.svm.core.code.DynamicMethodAddressResolutionHeapSupport; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.hosted.pltgot.PLTGOTOptions; + +@AutomaticallyRegisteredFeature +public class LinuxPLTGOTFeature implements InternalFeature { + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return Platform.includedIn(Platform.LINUX.class) && PLTGOTOptions.EnablePLTGOT.getValue(); + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + ImageSingletons.add(DynamicMethodAddressResolutionHeapSupport.class, new LinuxGOTHeapSupport()); + } +} diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsGOTHeapSupport.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsGOTHeapSupport.java new file mode 100644 index 000000000000..85081e020f09 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsGOTHeapSupport.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.windows; + +import org.graalvm.nativeimage.c.type.WordPointer; +import org.graalvm.word.Pointer; +import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.c.CGlobalData; +import com.oracle.svm.core.c.CGlobalDataFactory; +import com.oracle.svm.core.c.function.CEntryPointErrors; +import com.oracle.svm.core.headers.LibC; +import com.oracle.svm.core.os.VirtualMemoryProvider; +import com.oracle.svm.core.os.VirtualMemoryProvider.Access; +import com.oracle.svm.core.pltgot.GOTHeapSupport; +import com.oracle.svm.core.util.UnsignedUtils; +import com.oracle.svm.core.windows.headers.MemoryAPI; +import com.oracle.svm.core.windows.headers.WinBase; +import com.oracle.svm.core.windows.headers.WinBase.HANDLE; + +public class WindowsGOTHeapSupport extends GOTHeapSupport { + + private static final CGlobalData GOT_MAPPING_HANDLE = CGlobalDataFactory.createWord(); + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected int initialize(WordPointer gotStartAddress) { + UnsignedWord alignedGotSize = getPageAlignedGotSize(); + + HANDLE gotMappingHandle = MemoryAPI.CreateFileMappingW( + WinBase.INVALID_HANDLE_VALUE(), // in-memory + WordFactory.nullPointer(), + MemoryAPI.PAGE_READWRITE(), + 0, + UnsignedUtils.safeToInt(alignedGotSize), + WordFactory.nullPointer() // anonymous + ); + + if (gotMappingHandle.isNull()) { + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_FD_CREATE_FAILED; + } + + Pointer gotMappedAddress = MemoryAPI.MapViewOfFile( + gotMappingHandle, + MemoryAPI.FILE_MAP_READ() | MemoryAPI.FILE_MAP_WRITE(), + 0, + 0, + WordFactory.zero() // map it whole + ); + + if (gotMappedAddress.isNull()) { + WinBase.CloseHandle(gotMappingHandle); + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_FD_MAP_FAILED; + } + + Pointer gotStartInMemory = gotMappedAddress.add(getGotOffsetFromStartOfMapping()); + LibC.memcpy(gotStartInMemory, IMAGE_GOT_BEGIN.get(), getGotSectionSize()); + + // Keep the initial GOT mapping for writing. + + GOT_MAPPING_HANDLE.get().write(gotMappingHandle); + gotStartAddress.write(gotMappedAddress); + + return CEntryPointErrors.NO_ERROR; + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public int mapGot(Pointer address) { + HANDLE gotMappingHandle = GOT_MAPPING_HANDLE.get().read(); + if (gotMappingHandle.isNull()) { + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_FD_INVALID; + } + + Pointer mappedAddress = VirtualMemoryProvider.get().mapFile( + address, + getPageAlignedGotSize(), + gotMappingHandle, + WordFactory.zero(), + Access.READ); + + if (mappedAddress.isNull()) { + return CEntryPointErrors.DYNAMIC_METHOD_ADDRESS_RESOLUTION_GOT_MMAP_FAILED; + } + + return CEntryPointErrors.NO_ERROR; + } +} diff --git a/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPLTGOTFeature.java b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPLTGOTFeature.java new file mode 100644 index 000000000000..ee5d4522f970 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsPLTGOTFeature.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.windows; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; + +import com.oracle.svm.core.code.DynamicMethodAddressResolutionHeapSupport; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.hosted.pltgot.PLTGOTOptions; + +@AutomaticallyRegisteredFeature +public class WindowsPLTGOTFeature implements InternalFeature { + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return Platform.includedIn(Platform.WINDOWS.class) && PLTGOTOptions.EnablePLTGOT.getValue(); + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + ImageSingletons.add(DynamicMethodAddressResolutionHeapSupport.class, new WindowsGOTHeapSupport()); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateLIRGenerator.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateLIRGenerator.java index 22109f78d166..a9b2ffc401a9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateLIRGenerator.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateLIRGenerator.java @@ -36,4 +36,6 @@ public interface SubstrateLIRGenerator { void emitVerificationMarker(Object marker); void emitInstructionSynchronizationBarrier(); + + void emitExitMethodAddressResolution(Value ip); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/ExitMethodAddressResolutionNode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/ExitMethodAddressResolutionNode.java new file mode 100644 index 000000000000..6d76253e0888 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/ExitMethodAddressResolutionNode.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.pltgot; + +import org.graalvm.nativeimage.c.function.CodePointer; + +import com.oracle.svm.core.graal.code.SubstrateLIRGenerator; + +import jdk.graal.compiler.core.common.type.StampFactory; +import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.lir.gen.LIRGeneratorTool; +import jdk.graal.compiler.nodeinfo.NodeCycles; +import jdk.graal.compiler.nodeinfo.NodeInfo; +import jdk.graal.compiler.nodeinfo.NodeSize; +import jdk.graal.compiler.nodes.ControlSinkNode; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.spi.LIRLowerable; +import jdk.graal.compiler.nodes.spi.NodeLIRBuilderTool; + +@NodeInfo(cycles = NodeCycles.CYCLES_1, size = NodeSize.SIZE_1) +public final class ExitMethodAddressResolutionNode extends ControlSinkNode implements LIRLowerable { + public static final NodeClass TYPE = NodeClass.create(ExitMethodAddressResolutionNode.class); + + @Input protected ValueNode ip; + + public ExitMethodAddressResolutionNode(ValueNode ip) { + super(TYPE, StampFactory.forVoid()); + this.ip = ip; + } + + @Override + public void generate(NodeLIRBuilderTool builder) { + LIRGeneratorTool gen = builder.getLIRGeneratorTool(); + ((SubstrateLIRGenerator) gen).emitExitMethodAddressResolution(builder.operand(ip)); + } + + @NodeIntrinsic + public static native void exitMethodAddressResolution(CodePointer ip); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/GOTAccess.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/GOTAccess.java new file mode 100644 index 000000000000..6c8cffc4f24d --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/GOTAccess.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.pltgot; + +import org.graalvm.word.Pointer; +import org.graalvm.word.UnsignedWord; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.config.ConfigurationValues; + +import jdk.graal.compiler.word.Word; + +public class GOTAccess { + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static int getGotEntryOffsetFromHeapRegister(int gotEntry) { + return -(gotEntry + 1) * ConfigurationValues.getTarget().wordSize; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static void writeToGotEntry(int gotEntry, UnsignedWord address) { + Pointer gotStartAddress = GOTHeapSupport.GOT_START_ADDRESS.get().read(); + Pointer gotEndAddress = gotStartAddress.add(GOTHeapSupport.getPageAlignedGotSize()); + gotEndAddress.writeWord(getGotEntryOffsetFromHeapRegister(gotEntry), address); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static Word readFromGotEntry(int gotEntry) { + Pointer gotStartAddress = GOTHeapSupport.GOT_START_ADDRESS.get().read(); + Pointer gotEndAddress = gotStartAddress.add(GOTHeapSupport.getPageAlignedGotSize()); + return gotEndAddress.readWord(getGotEntryOffsetFromHeapRegister(gotEntry)); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/GOTHeapSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/GOTHeapSupport.java new file mode 100644 index 000000000000..eb26f7b4aff5 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/GOTHeapSupport.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.pltgot; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.c.type.WordPointer; +import org.graalvm.word.LocationIdentity; +import org.graalvm.word.Pointer; +import org.graalvm.word.PointerBase; +import org.graalvm.word.SignedWord; +import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.c.CGlobalData; +import com.oracle.svm.core.c.CGlobalDataFactory; +import com.oracle.svm.core.c.function.CEntryPointErrors; +import com.oracle.svm.core.code.DynamicMethodAddressResolutionHeapSupport; +import com.oracle.svm.core.os.VirtualMemoryProvider; +import com.oracle.svm.core.os.VirtualMemoryProvider.Access; +import com.oracle.svm.core.snippets.KnownIntrinsics; +import com.oracle.svm.core.util.PointerUtils; +import com.oracle.svm.core.util.VMError; + +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.nodes.PauseNode; + +public abstract class GOTHeapSupport extends DynamicMethodAddressResolutionHeapSupport { + + public static final String IMAGE_GOT_END_SYMBOL_NAME = "__svm_got_end"; + public static final CGlobalData IMAGE_GOT_END = CGlobalDataFactory.forSymbol(IMAGE_GOT_END_SYMBOL_NAME); + public static final String IMAGE_GOT_BEGIN_SYMBOL_NAME = "__svm_got_begin"; + public static final CGlobalData IMAGE_GOT_BEGIN = CGlobalDataFactory.forSymbol(IMAGE_GOT_BEGIN_SYMBOL_NAME); + + private static final SignedWord GOT_UNINITIALIZED = WordFactory.signed(-1); + private static final SignedWord GOT_INITIALIZATION_IN_PROGRESS = WordFactory.signed(-2); + private static final CGlobalData GOT_STATUS = CGlobalDataFactory.createWord(GOT_UNINITIALIZED); + static final CGlobalData GOT_START_ADDRESS = CGlobalDataFactory.createWord(); + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected static UnsignedWord getGotSectionSize() { + return IMAGE_GOT_END.get().subtract(IMAGE_GOT_BEGIN.get()); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected static UnsignedWord getPageAlignedGotSize() { + UnsignedWord gotSectionSize = getGotSectionSize(); + UnsignedWord pageSize = VirtualMemoryProvider.get().getGranularity(); + return PointerUtils.roundUp((PointerBase) gotSectionSize, pageSize); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected static UnsignedWord getGotOffsetFromStartOfMapping() { + return getPageAlignedGotSize().subtract(getGotSectionSize()); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public UnsignedWord getRequiredPreHeapMemoryInBytes() { + return getPageAlignedGotSize(); + } + + @Fold + public static GOTHeapSupport get() { + return (GOTHeapSupport) ImageSingletons.lookup(DynamicMethodAddressResolutionHeapSupport.class); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public void makeGOTWritable() { + changeGOTMappingProtection(true); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public void makeGOTReadOnly() { + changeGOTMappingProtection(false); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected abstract int mapGot(Pointer address); + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public int install(Pointer heapBase) { + return mapGot(getPreHeapMappingStartAddress(heapBase)); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected Pointer getPreHeapMappingStartAddress() { + return getPreHeapMappingStartAddress(KnownIntrinsics.heapBase()); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + protected Pointer getPreHeapMappingStartAddress(PointerBase heapBase) { + return ((Pointer) heapBase).subtract(getRequiredPreHeapMemoryInBytes()); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + private static void changeGOTMappingProtection(boolean writable) { + Pointer gotMappingStartAddress = GOT_START_ADDRESS.get().read(); + VMError.guarantee(gotMappingStartAddress.isNonNull()); + int access = Access.READ; + if (writable) { + access |= Access.WRITE; + } + int ret = VirtualMemoryProvider.get().protect(gotMappingStartAddress, getPageAlignedGotSize(), access); + VMError.guarantee(ret == 0, "Failed to change GOT protection."); + } + + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public int initialize() { + boolean isFirstIsolate = GOT_STATUS.get().logicCompareAndSwapWord(0, GOT_UNINITIALIZED, GOT_INITIALIZATION_IN_PROGRESS, LocationIdentity.ANY_LOCATION); + if (!isFirstIsolate) { + while (true) { + SignedWord status = GOT_STATUS.get().readWordVolatile(0, LocationIdentity.ANY_LOCATION); + if (status.notEqual(GOT_INITIALIZATION_IN_PROGRESS)) { + long rawStatus = status.rawValue(); + assert rawStatus == (int) rawStatus; + return (int) rawStatus; + } + /* Being nice to the CPU while busy waiting */ + PauseNode.pause(); + } + } + + // Only the first isolate can reach here. + int ret = initialize(GOT_START_ADDRESS.get()); + if (ret == CEntryPointErrors.NO_ERROR) { + makeGOTReadOnly(); + } + GOT_STATUS.get().writeWordVolatile(0, WordFactory.signed(ret)); + return ret; + } + + /** + * Initialize the GOT and write its address to {@code gotStartAddress}. Return + * {@link CEntryPointErrors#NO_ERROR} on success, an error code otherwise. + */ + protected abstract int initialize(WordPointer gotStartAddress); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/IdentityMethodAddressResolver.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/IdentityMethodAddressResolver.java new file mode 100644 index 000000000000..996d6cf8d4a5 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/IdentityMethodAddressResolver.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.pltgot; + +import org.graalvm.word.Pointer; +import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.c.CGlobalData; +import com.oracle.svm.core.c.CGlobalDataFactory; +import com.oracle.svm.core.config.ConfigurationValues; + +public class IdentityMethodAddressResolver implements MethodAddressResolver { + + private static final CGlobalData methodTable = CGlobalDataFactory.forSymbol("__svm_methodtable_begin"); + + @Override + @Uninterruptible(reason = "Called from the PLT stub where stack walks are not safe.") + public long resolveMethodWithGotEntry(long gotEntry) { + /* Fetch the absolute address of the method that corresponds to the target GOT entry. */ + UnsignedWord methodTableOffset = WordFactory.unsigned(gotEntry).multiply(ConfigurationValues.getTarget().wordSize); + UnsignedWord address = methodTable.get().readWord(methodTableOffset); + /* + * Write the resolved address to the GOT entry so that it can be directly used for future + * calls instead of going through this resolver. + */ + GOTAccess.writeToGotEntry((int) gotEntry, address); + + return address.rawValue(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/MethodAddressResolutionDispatcher.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/MethodAddressResolutionDispatcher.java new file mode 100644 index 000000000000..6d95f0e43975 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/MethodAddressResolutionDispatcher.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.pltgot; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.thread.JavaSpinLockUtils; + +import jdk.internal.misc.Unsafe; + +public class MethodAddressResolutionDispatcher { + private static final MethodAddressResolutionDispatcher dispatcher = new MethodAddressResolutionDispatcher(); + private static final long LOCK_OFFSET = Unsafe.getUnsafe().objectFieldOffset(MethodAddressResolutionDispatcher.class, "lock"); + + @SuppressWarnings("unused")// + private volatile int lock; + private int activeResolverInstances = 0; + + @Uninterruptible(reason = "PLT/GOT method address resolution doesn't support interruptible code paths.") + protected static long resolveMethodAddress(long gotEntry) { + try { + JavaSpinLockUtils.lockNoTransition(dispatcher, LOCK_OFFSET); + if (dispatcher.activeResolverInstances == 0) { + GOTHeapSupport.get().makeGOTWritable(); + } + dispatcher.activeResolverInstances++; + } finally { + JavaSpinLockUtils.unlock(dispatcher, LOCK_OFFSET); + } + + long resolvedMethodAddress = PLTGOTConfiguration.singleton().getMethodAddressResolver().resolveMethodWithGotEntry(gotEntry); + + try { + JavaSpinLockUtils.lockNoTransition(dispatcher, LOCK_OFFSET); + if (dispatcher.activeResolverInstances == 1) { + GOTHeapSupport.get().makeGOTReadOnly(); + } + dispatcher.activeResolverInstances--; + } finally { + JavaSpinLockUtils.unlock(dispatcher, LOCK_OFFSET); + } + return resolvedMethodAddress; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/MethodAddressResolver.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/MethodAddressResolver.java new file mode 100644 index 000000000000..ee45a0204c51 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/MethodAddressResolver.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.pltgot; + +import com.oracle.svm.core.Uninterruptible; + +public interface MethodAddressResolver { + + /** + * Resolves the absolute address of a method represented by the given GOT entry. + * + * Note that it is the responsibility of this method to write the resolved address to the GOT + * entry as otherwise it will be called for subsequent calls of the same method. + */ + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + long resolveMethodWithGotEntry(long gotEntry); + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/PLTGOTConfiguration.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/PLTGOTConfiguration.java new file mode 100644 index 000000000000..f880c0b20f3c --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/PLTGOTConfiguration.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.pltgot; + +import org.graalvm.nativeimage.ImageSingletons; + +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.lir.LIRInstruction; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.RegisterValue; + +public abstract class PLTGOTConfiguration { + protected MethodAddressResolver methodAddressResolver; + + @Fold + public static PLTGOTConfiguration singleton() { + return ImageSingletons.lookup(PLTGOTConfiguration.class); + } + + @Fold + public MethodAddressResolver getMethodAddressResolver() { + return methodAddressResolver; + } + + public abstract Register getExitMethodAddressResolutionRegister(RegisterConfig registerConfig); + + public abstract LIRInstruction createExitMethodAddressResolutionOp(RegisterValue exitThroughRegisterValue); + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/aarch64/AArch64ExitMethodAddressResolutionOp.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/aarch64/AArch64ExitMethodAddressResolutionOp.java new file mode 100644 index 000000000000..4f824a1a146f --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/aarch64/AArch64ExitMethodAddressResolutionOp.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.pltgot.aarch64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler; +import jdk.graal.compiler.lir.LIRInstructionClass; +import jdk.graal.compiler.lir.Opcode; +import jdk.graal.compiler.lir.aarch64.AArch64BlockEndOp; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; +import jdk.vm.ci.meta.Value; + +@Opcode("EXIT_METHOD_ADDRESS_RESOLUTION") +public class AArch64ExitMethodAddressResolutionOp extends AArch64BlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64ExitMethodAddressResolutionOp.class); + private @Use Value ip; + + public AArch64ExitMethodAddressResolutionOp(Value ip) { + super(TYPE); + this.ip = ip; + } + + @Override + protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + crb.frameContext.leave(crb); + masm.jmp(asRegister(ip)); + crb.frameContext.returned(crb); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/aarch64/AArch64MethodAddressResolutionDispatcher.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/aarch64/AArch64MethodAddressResolutionDispatcher.java new file mode 100644 index 000000000000..15dcfb3f23f6 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/aarch64/AArch64MethodAddressResolutionDispatcher.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.pltgot.aarch64; + +import static com.oracle.svm.core.pltgot.ExitMethodAddressResolutionNode.exitMethodAddressResolution; + +import org.graalvm.word.Pointer; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.NeverInline; +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.deopt.DeoptimizationSlotPacking; +import com.oracle.svm.core.graal.code.StubCallingConvention; +import com.oracle.svm.core.pltgot.MethodAddressResolutionDispatcher; +import com.oracle.svm.core.snippets.KnownIntrinsics; + +import jdk.graal.compiler.nodes.UnreachableNode; + +public final class AArch64MethodAddressResolutionDispatcher extends MethodAddressResolutionDispatcher { + /** + * This method is never called directly, instead we jump to it through a scratch register from + * the PLT stub (see {@code AArch64PLTStubGenerator}). The PLT stub writes the GOT entry into + * the stack frame padding space after the return address that is conventionally used for the + * deopt frame data. We do this in order to avoid having to spill the argument passing registers + * to the stack when we call @{code resolveMethodAddress}. Note that we cannot use the full + * word, see {@link DeoptimizationSlotPacking} on the convention that should be used. + */ + @StubCallingConvention + @Uninterruptible(reason = "PLT/GOT method address resolution doesn't support interruptible code paths.") + @NeverInline("This method must never be inlined or called directly because we only jump to it from the PLT stub.") + public static void resolveMethodAddress() { + Pointer paddingSlot = KnownIntrinsics.readCallerStackPointer(); + long gotEntry = DeoptimizationSlotPacking.decodeGOTIndex(paddingSlot.readWord(0).rawValue()); + long resolvedMethodAddress = MethodAddressResolutionDispatcher.resolveMethodAddress(gotEntry); + exitMethodAddressResolution(WordFactory.pointer(resolvedMethodAddress)); + throw UnreachableNode.unreachable(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/amd64/AMD64ExitMethodAddressResolutionOp.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/amd64/AMD64ExitMethodAddressResolutionOp.java new file mode 100644 index 000000000000..8c10e02166d5 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/amd64/AMD64ExitMethodAddressResolutionOp.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.pltgot.amd64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; + +import jdk.graal.compiler.asm.amd64.AMD64MacroAssembler; +import jdk.graal.compiler.lir.LIRInstructionClass; +import jdk.graal.compiler.lir.Opcode; +import jdk.graal.compiler.lir.amd64.AMD64BlockEndOp; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; +import jdk.vm.ci.meta.Value; + +@Opcode("EXIT_METHOD_ADDRESS_RESOLUTION") +public class AMD64ExitMethodAddressResolutionOp extends AMD64BlockEndOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64ExitMethodAddressResolutionOp.class); + private @Use Value ip; + + public AMD64ExitMethodAddressResolutionOp(Value ip) { + super(TYPE); + this.ip = ip; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + crb.frameContext.leave(crb); + masm.jmp(asRegister(ip)); + crb.frameContext.returned(crb); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/amd64/AMD64MethodAddressResolutionDispatcher.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/amd64/AMD64MethodAddressResolutionDispatcher.java new file mode 100644 index 000000000000..8f06638f0394 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/pltgot/amd64/AMD64MethodAddressResolutionDispatcher.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.pltgot.amd64; + +import static com.oracle.svm.core.pltgot.ExitMethodAddressResolutionNode.exitMethodAddressResolution; + +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.NeverInline; +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.graal.code.ExplicitCallingConvention; +import com.oracle.svm.core.graal.code.StubCallingConvention; +import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; +import com.oracle.svm.core.pltgot.MethodAddressResolutionDispatcher; + +import jdk.graal.compiler.nodes.UnreachableNode; + +public final class AMD64MethodAddressResolutionDispatcher extends MethodAddressResolutionDispatcher { + /** + * This method is never called directly, we jump to it from a PLT stub for a method with a given + * gotEntry. Because the {@link SubstrateCallingConventionKind#ForwardReturnValue} calling + * convention takes the value of its one and only parameter {@code gotEntry} from the return + * register, we load the got entry value of a method that we are resolving into the return value + * register in the PLT stub. + * + * In the lir op for {@code exitMethodAddressResolution} we jump through the return register to + * the {@code resolvedMethodAddress} and that's why the method {@code resolveMethodAddress} has + * to have a return kind {@code long} so that the calleeSaved register restore for this method + * doesn't override the return register. See + * {@link jdk.graal.compiler.lir.asm.FrameContext#leave}. + */ + @StubCallingConvention + @Uninterruptible(reason = "PLT/GOT method address resolution doesn't support interruptible code paths.") + @ExplicitCallingConvention(SubstrateCallingConventionKind.ForwardReturnValue) + @NeverInline("This method must never be inlined or called directly because we only jump to it from the PLT stub.") + public static long resolveMethodAddress(long gotEntry) { + long resolvedMethodAddress = MethodAddressResolutionDispatcher.resolveMethodAddress(gotEntry); + exitMethodAddressResolution(WordFactory.pointer(resolvedMethodAddress)); + throw UnreachableNode.unreachable(); + } +} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/GOTCall.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/GOTCall.java new file mode 100644 index 000000000000..e397e8f53d42 --- /dev/null +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/GOTCall.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.graal.pltgot; + +import jdk.vm.ci.code.DebugInfo; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.code.site.InfopointReason; + +public class GOTCall extends Infopoint { + public GOTCall(int pcOffset, DebugInfo debugInfo, InfopointReason reason) { + super(pcOffset, debugInfo, reason); + } +} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/PLTGOTNonSnippetLowerings.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/PLTGOTNonSnippetLowerings.java new file mode 100644 index 000000000000..5216dc48dab4 --- /dev/null +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/PLTGOTNonSnippetLowerings.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.graal.pltgot; + +import java.util.Map; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.word.LocationIdentity; + +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.graal.meta.KnownOffsets; +import com.oracle.svm.core.graal.meta.RuntimeConfiguration; +import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; +import com.oracle.svm.core.graal.snippets.NonSnippetLowerings; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.pltgot.GOTAccess; +import com.oracle.svm.hosted.nodes.ReadReservedRegister; +import com.oracle.svm.hosted.pltgot.GOTEntryAllocator; +import com.oracle.svm.hosted.pltgot.HostedPLTGOTConfiguration; +import com.oracle.svm.hosted.pltgot.MethodAddressResolutionSupport; + +import jdk.graal.compiler.core.common.memory.BarrierType; +import jdk.graal.compiler.core.common.memory.MemoryOrderMode; +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.graph.NodeInputList; +import jdk.graal.compiler.nodes.CallTargetNode; +import jdk.graal.compiler.nodes.ConstantNode; +import jdk.graal.compiler.nodes.FixedNode; +import jdk.graal.compiler.nodes.IndirectCallTargetNode; +import jdk.graal.compiler.nodes.InvokeNode; +import jdk.graal.compiler.nodes.InvokeWithExceptionNode; +import jdk.graal.compiler.nodes.LoweredCallTargetNode; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.graal.compiler.nodes.java.MethodCallTargetNode; +import jdk.graal.compiler.nodes.memory.ReadNode; +import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode; +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.meta.JavaType; + +@Platforms(Platform.HOSTED_ONLY.class) +public final class PLTGOTNonSnippetLowerings { + + public static void registerLowerings(RuntimeConfiguration runtimeConfig, Map, NodeLoweringProvider> lowerings) { + InvokeThroughGOTLowering invokeLowering = new InvokeThroughGOTLowering(runtimeConfig); + lowerings.put(InvokeNode.class, invokeLowering); + lowerings.put(InvokeWithExceptionNode.class, invokeLowering); + } + + @Platforms(Platform.HOSTED_ONLY.class) + private static final class InvokeThroughGOTLowering extends NonSnippetLowerings.InvokeLowering { + + private final MethodAddressResolutionSupport methodAddressResolutionSupport; + private final GOTEntryAllocator gotEntryAllocator; + + InvokeThroughGOTLowering(RuntimeConfiguration runtimeConfig) { + super(runtimeConfig, SubstrateOptions.VerifyTypes.getValue(), KnownOffsets.singleton()); + this.methodAddressResolutionSupport = HostedPLTGOTConfiguration.singleton().getMethodAddressResolutionSupport(); + this.gotEntryAllocator = HostedPLTGOTConfiguration.singleton().getGOTEntryAllocator(); + } + + @Override + protected LoweredCallTargetNode createDirectCall(StructuredGraph graph, MethodCallTargetNode callTarget, NodeInputList parameters, JavaType[] signature, + CallingConvention.Type callType, CallTargetNode.InvokeKind invokeKind, SharedMethod callee, FixedNode node) { + SharedMethod caller = (SharedMethod) graph.method(); + if (methodAddressResolutionSupport.shouldCallViaPLTGOT(caller, callee)) { + ValueNode heapBaseNode = graph.addOrUnique(ReadReservedRegister.createReadHeapBaseNode(graph)); + int targetGotEntry = gotEntryAllocator.getMethodGotEntry(callee); + ValueNode offsetNode = ConstantNode.forIntegerKind(ConfigurationValues.getWordKind(), GOTAccess.getGotEntryOffsetFromHeapRegister(targetGotEntry), graph); + OffsetAddressNode offsetAddressNode = graph.unique(new OffsetAddressNode(heapBaseNode, offsetNode)); + ReadNode methodAddress = graph + .add(new ReadNode(offsetAddressNode, LocationIdentity.ANY_LOCATION, FrameAccess.getWordStamp(), BarrierType.NONE, MemoryOrderMode.PLAIN)); + SubstrateGOTCallTargetNode loweredCallTarget = graph.add( + new SubstrateGOTCallTargetNode(methodAddress, parameters.toArray(ValueNode.EMPTY_ARRAY), callTarget.returnStamp(), signature, callee, callType, invokeKind)); + + graph.addBeforeFixed(node, methodAddress); + return loweredCallTarget; + } + + return super.createDirectCall(graph, callTarget, parameters, signature, callType, invokeKind, callee, node); + } + + @Override + protected IndirectCallTargetNode createIndirectCall(StructuredGraph graph, MethodCallTargetNode callTarget, NodeInputList parameters, SharedMethod callee, JavaType[] signature, + CallingConvention.Type callType, CallTargetNode.InvokeKind invokeKind, ValueNode entry) { + SharedMethod caller = (SharedMethod) graph.method(); + /* + * We don't change how virtual methods are called; instead we make sure that the + * relocation to an appropriate PLT stub will be emitted in a vtable slot for the + * callee. + * + * This will force all the implementations of a callee method to be resolved via PLT/GOT + * mechanism. In the future, when we introduce the concept of hot and cold calls we + * could use a dispatch stub instead to reduce the number of GOT entries. + */ + if (methodAddressResolutionSupport.shouldCallViaPLTGOT(caller, callee)) { + for (SharedMethod implementation : callee.getImplementations()) { + gotEntryAllocator.reserveMethodGotEntry(implementation); + } + } + return super.createIndirectCall(graph, callTarget, parameters, callee, signature, callType, invokeKind, entry); + } + } + +} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/SubstrateGOTCallTargetNode.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/SubstrateGOTCallTargetNode.java new file mode 100644 index 000000000000..c90c6f187114 --- /dev/null +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/SubstrateGOTCallTargetNode.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.graal.pltgot; + +import com.oracle.svm.core.nodes.SubstrateIndirectCallTargetNode; + +import jdk.graal.compiler.core.common.type.StampPair; +import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.nodeinfo.NodeInfo; +import jdk.graal.compiler.nodes.ValueNode; +import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +@NodeInfo +public final class SubstrateGOTCallTargetNode extends SubstrateIndirectCallTargetNode { + public static final NodeClass TYPE = NodeClass.create(SubstrateGOTCallTargetNode.class); + + public SubstrateGOTCallTargetNode(ValueNode computedAddress, ValueNode[] arguments, StampPair returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, + InvokeKind invokeKind) { + super(TYPE, computedAddress, arguments, returnStamp, signature, target, callType, invokeKind, null); + } +} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/aarch64/PLTGOTAArch64Lowerings.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/aarch64/PLTGOTAArch64Lowerings.java new file mode 100644 index 000000000000..41415f28353c --- /dev/null +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/aarch64/PLTGOTAArch64Lowerings.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.graal.pltgot.aarch64; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.hosted.Feature; + +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.graal.meta.RuntimeConfiguration; +import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; +import com.oracle.svm.core.graal.snippets.aarch64.AArch64SnippetsFeature; +import com.oracle.svm.graal.pltgot.PLTGOTNonSnippetLowerings; +import com.oracle.svm.hosted.pltgot.PLTGOTOptions; + +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.util.Providers; + +@AutomaticallyRegisteredFeature +@Platforms(Platform.AARCH64.class) +public class PLTGOTAArch64Lowerings implements InternalFeature { + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return PLTGOTOptions.EnablePLTGOT.getValue(); + } + + @Override + public List> getRequiredFeatures() { + return Collections.singletonList(AArch64SnippetsFeature.class); + } + + @Override + public void registerLowerings(RuntimeConfiguration runtimeConfig, OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings, boolean hosted) { + if (hosted) { + PLTGOTNonSnippetLowerings.registerLowerings(runtimeConfig, lowerings); + } + } +} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/amd64/PLTGOTAMD64Lowerings.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/amd64/PLTGOTAMD64Lowerings.java new file mode 100644 index 000000000000..d6811cdba0c3 --- /dev/null +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/pltgot/amd64/PLTGOTAMD64Lowerings.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.graal.pltgot.amd64; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.hosted.Feature; + +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.graal.meta.RuntimeConfiguration; +import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; +import com.oracle.svm.core.graal.snippets.amd64.AMD64SnippetsFeature; +import com.oracle.svm.graal.pltgot.PLTGOTNonSnippetLowerings; +import com.oracle.svm.hosted.pltgot.PLTGOTOptions; + +import jdk.graal.compiler.graph.Node; +import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.phases.util.Providers; + +@AutomaticallyRegisteredFeature +@Platforms(Platform.AMD64.class) +public class PLTGOTAMD64Lowerings implements InternalFeature { + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return PLTGOTOptions.EnablePLTGOT.getValue(); + } + + @Override + public List> getRequiredFeatures() { + return Collections.singletonList(AMD64SnippetsFeature.class); + } + + @Override + public void registerLowerings(RuntimeConfiguration runtimeConfig, OptionValues options, Providers providers, Map, NodeLoweringProvider> lowerings, boolean hosted) { + if (hosted) { + PLTGOTNonSnippetLowerings.registerLowerings(runtimeConfig, lowerings); + } + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java index 76534d482e6c..e8331c298511 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java @@ -69,6 +69,7 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.annotate.Delete; import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.graal.code.SubstrateBackend; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; import com.oracle.svm.core.hub.ClassForNameSupport; import com.oracle.svm.core.meta.SharedField; @@ -766,15 +767,22 @@ public void registerLinkerInvocationTransformer(Function entryPoints, JavaMainSupport j createAbstractImage(k, hostedEntryPoints, heap, hMetaAccess, codeCache); - FeatureImpl.AfterAbstractImageCreationAccessImpl access = new FeatureImpl.AfterAbstractImageCreationAccessImpl(featureHandler, loader, debug, image); + FeatureImpl.AfterAbstractImageCreationAccessImpl access = new FeatureImpl.AfterAbstractImageCreationAccessImpl(featureHandler, loader, debug, image, + runtimeConfiguration.getBackendForNormalMethod()); featureHandler.forEachGraalFeature(feature -> feature.afterAbstractImageCreation(access)); image.build(imageName, debug); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/CollectPLTGOTCallSitesResolutionSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/CollectPLTGOTCallSitesResolutionSupport.java new file mode 100644 index 000000000000..340c6140f2e0 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/CollectPLTGOTCallSitesResolutionSupport.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.ConcurrentSkipListSet; + +import com.oracle.objectfile.ObjectFile; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.pltgot.MethodAddressResolver; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.meta.HostedUniverse; + +class CollectPLTGOTCallSitesResolutionSupport implements MethodAddressResolutionSupport { + private final MethodAddressResolutionSupport resolver; + private final ConcurrentMap> callerCalleesMap; + private final Set calleesWithUnknownCaller; + + CollectPLTGOTCallSitesResolutionSupport(MethodAddressResolutionSupport resolver) { + this.resolver = resolver; + this.callerCalleesMap = new ConcurrentSkipListMap<>(HostedUniverse.METHOD_COMPARATOR); + this.calleesWithUnknownCaller = new ConcurrentSkipListSet<>(HostedUniverse.METHOD_COMPARATOR); + } + + @Override + public boolean shouldCallViaPLTGOT(SharedMethod caller, SharedMethod callee) { + boolean shouldCall = resolver.shouldCallViaPLTGOT(caller, callee); + if (shouldCall) { + var callees = callerCalleesMap.computeIfAbsent((HostedMethod) caller, k -> ConcurrentHashMap.newKeySet()); + callees.add((HostedMethod) callee); + } + return shouldCall; + } + + @Override + public boolean shouldCallViaPLTGOT(SharedMethod callee) { + boolean shouldCall = resolver.shouldCallViaPLTGOT(callee); + if (shouldCall) { + calleesWithUnknownCaller.add((HostedMethod) callee); + } + return shouldCall; + } + + @Override + public void augmentImageObjectFile(ObjectFile imageObjectFile) { + resolver.augmentImageObjectFile(imageObjectFile); + } + + @Override + public MethodAddressResolver createMethodAddressResolver() { + return resolver.createMethodAddressResolver(); + } + + public Map> getCallerCalleesMap() { + return Collections.unmodifiableMap(callerCalleesMap); + } + + public Set getCalleesWithUnknownCaller() { + return Collections.unmodifiableSet(calleesWithUnknownCaller); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/GOTEntryAllocator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/GOTEntryAllocator.java new file mode 100644 index 000000000000..7c70ca2d51b1 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/GOTEntryAllocator.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.meta.HostedMethod; + +public class GOTEntryAllocator { + public static final int GOT_NO_ENTRY = -2; + + private final ConcurrentHashMap gotMap = new ConcurrentHashMap<>(); + private SharedMethod[] got = null; + + private final AtomicInteger currentFreeEntry = new AtomicInteger(0); + + public int getMethodGotEntry(SharedMethod method) { + return gotMap.computeIfAbsent(method, m -> currentFreeEntry.getAndIncrement()); + } + + public void reserveMethodGotEntry(SharedMethod method) { + getMethodGotEntry(method); + } + + public int queryGotEntry(SharedMethod method) { + assert hasGOTLayout(); + return gotMap.getOrDefault(method, GOT_NO_ENTRY); + } + + public void reserveAndLayout(Set methods, MethodAddressResolutionSupport resolver) { + assert !hasGOTLayout(); + + methods.stream() + .filter(resolver::shouldCallViaPLTGOT) + .forEach(this::reserveMethodGotEntry); + + VMError.guarantee(got == null, "Can layout the GOT only once."); + got = new SharedMethod[gotMap.keySet().size()]; + for (Map.Entry entry : gotMap.entrySet()) { + got[entry.getValue()] = entry.getKey(); + } + } + + public boolean hasGOTLayout() { + return got != null; + } + + public SharedMethod[] getGOT() { + VMError.guarantee(got != null, "Must layout the GOT first before use."); + return got; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/HostedPLTGOTConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/HostedPLTGOTConfiguration.java new file mode 100644 index 000000000000..196c972a6b0e --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/HostedPLTGOTConfiguration.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot; + +import java.lang.reflect.Method; + +import org.graalvm.nativeimage.ImageSingletons; + +import com.oracle.objectfile.SectionName; +import com.oracle.svm.core.pltgot.PLTGOTConfiguration; +import com.oracle.svm.hosted.meta.HostedMetaAccess; +import com.oracle.svm.hosted.meta.HostedMethod; + +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; + +public abstract class HostedPLTGOTConfiguration extends PLTGOTConfiguration { + public static final SectionName SVM_GOT_SECTION = new SectionName.ProgbitsSectionName("svm_got"); + + protected MethodAddressResolutionSupport methodAddressResolutionSupport; + private final GOTEntryAllocator gotEntryAllocator = new GOTEntryAllocator(); + + private PLTSectionSupport pltSectionSupport; + private HostedMetaAccess hostedMetaAccess; + + @SuppressWarnings("this-escape") + public HostedPLTGOTConfiguration() { + this.pltSectionSupport = new PLTSectionSupport(getArchSpecificPLTStubGenerator()); + } + + public static HostedPLTGOTConfiguration singleton() { + return (HostedPLTGOTConfiguration) ImageSingletons.lookup(PLTGOTConfiguration.class); + } + + public abstract Method getArchSpecificResolverAsMethod(); + + public abstract Register getGOTPassingRegister(RegisterConfig registerConfig); + + public abstract PLTStubGenerator getArchSpecificPLTStubGenerator(); + + public void setHostedMetaAccess(HostedMetaAccess metaAccess) { + assert hostedMetaAccess == null : "The field hostedMetaAccess can't be set twice."; + this.hostedMetaAccess = metaAccess; + } + + public void initializeMethodAddressResolutionSupport(MethodAddressResolutionSupportFactory methodAddressResolutionSupportFactory) { + assert methodAddressResolutionSupport == null : "The field methodAddressResolutionSupport can't be initialized twice."; + methodAddressResolutionSupport = methodAddressResolutionSupportFactory.create(); + if (PLTGOTOptions.PrintPLTGOTCallsInfo.getValue()) { + methodAddressResolutionSupport = new CollectPLTGOTCallSitesResolutionSupport(methodAddressResolutionSupport); + } + methodAddressResolver = getMethodAddressResolutionSupport().createMethodAddressResolver(); + } + + public MethodAddressResolutionSupport getMethodAddressResolutionSupport() { + assert methodAddressResolutionSupport != null : "Must call initializeMethodAddressResolutionSupport before calling getMethodAddressResolutionSupport"; + return methodAddressResolutionSupport; + } + + public PLTSectionSupport getPLTSectionSupport() { + return pltSectionSupport; + } + + public void markResolverMethodPatch() { + pltSectionSupport.markResolverMethodPatch(getArchSpecificResolverAsHostedMethod()); + } + + public HostedMethod getArchSpecificResolverAsHostedMethod() { + assert hostedMetaAccess != null : "Must set hostedMetaAccess before calling getArchSpecificResolverAsHostedMethod"; + return hostedMetaAccess.lookupJavaMethod(getArchSpecificResolverAsMethod()); + } + + public GOTEntryAllocator getGOTEntryAllocator() { + return gotEntryAllocator; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/IdentityMethodAddressResolverFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/IdentityMethodAddressResolverFeature.java new file mode 100644 index 000000000000..8ccdc3c026d6 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/IdentityMethodAddressResolverFeature.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot; + +import java.util.Collections; +import java.util.List; + +import org.graalvm.nativeimage.AnnotationAccess; +import org.graalvm.nativeimage.c.function.CEntryPoint; +import org.graalvm.nativeimage.c.function.CFunction; +import org.graalvm.nativeimage.hosted.Feature; + +import com.oracle.objectfile.BasicProgbitsSectionImpl; +import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.SectionName; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.graal.code.ExplicitCallingConvention; +import com.oracle.svm.core.graal.code.StubCallingConvention; +import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; +import com.oracle.svm.core.jdk.InternalVMMethod; +import com.oracle.svm.core.meta.MethodPointer; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.pltgot.IdentityMethodAddressResolver; +import com.oracle.svm.core.pltgot.MethodAddressResolver; +import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; +import com.oracle.svm.hosted.FeatureImpl; +import com.oracle.svm.hosted.image.NativeImage; +import com.oracle.svm.hosted.image.RelocatableBuffer; + +/** + * An example dynamic method address resolver implementation. + * + * The code of all reachable methods is located in the text section of the generated image. This + * resolver introduces another section ('.svm_methodtable') that contains absolute addresses of + * methods whose address is dynamically resolved. The methodtable section is the same size as the + * GOT, and the index of any method is the same in both. This feature registers the + * {@link IdentityMethodAddressResolver} resolver that, when a method is called for the first time, + * lookups the absolute method address in the above section. This address is then written in the + * appropriate GOT entry and is used for subsequent calls of the same method. + * + */ + +public class IdentityMethodAddressResolverFeature implements InternalFeature { + + // Restrict segment names to 16 chars on Mach-O. + public static final SectionName SVM_METHODTABLE = new SectionName.ProgbitsSectionName("svm_methodtbl"); + + private RelocatableBuffer offsetsSectionBuffer; + + private ObjectFile.ProgbitsSectionImpl offsetsSectionBufferImpl; + + protected class IdentityMethodAddressResolverSupport implements MethodAddressResolutionSupport { + private static boolean isAllowed(SharedMethod method) { + if (AnnotationAccess.isAnnotationPresent(method, CEntryPoint.class)) { + return false; + } + if (AnnotationAccess.isAnnotationPresent(method, CFunction.class)) { + return false; + } + if (AnnotationAccess.isAnnotationPresent(method, StubCallingConvention.class)) { + return false; + } + if (AnnotationAccess.isAnnotationPresent(method, Uninterruptible.class)) { + return false; + } + if (AnnotationAccess.isAnnotationPresent(method, SubstrateForeignCallTarget.class)) { + return false; + } + if (AnnotationAccess.isAnnotationPresent(method.getDeclaringClass(), InternalVMMethod.class)) { + return false; + } + if (AnnotationAccess.isAnnotationPresent(method, ExplicitCallingConvention.class) && + AnnotationAccess.getAnnotation(method, ExplicitCallingConvention.class).value().equals(SubstrateCallingConventionKind.ForwardReturnValue)) { + /* + * Methods that use ForwardReturnValue calling convention can't be resolved with + * PLT/GOT on AMD64 because + * AMD64MethodAddressResolutionDispatcher.resolveMethodAddress uses the same calling + * convention, and we can't save the callers value of the `rax` register on AMD64 + * without spilling it. + */ + return false; + } + return true; + } + + @Override + @SuppressWarnings("unused") + public boolean shouldCallViaPLTGOT(SharedMethod caller, SharedMethod callee) { + return isAllowed(callee); + } + + @Override + public boolean shouldCallViaPLTGOT(SharedMethod callee) { + return isAllowed(callee); + } + + @Override + public void augmentImageObjectFile(ObjectFile imageObjectFile) { + GOTEntryAllocator gotEntryAllocator = HostedPLTGOTConfiguration.singleton().getGOTEntryAllocator(); + SharedMethod[] got = gotEntryAllocator.getGOT(); + long methodCount = got.length; + int wordSize = ConfigurationValues.getTarget().wordSize; + long gotSectionSize = methodCount * wordSize; + offsetsSectionBuffer = new RelocatableBuffer(gotSectionSize, imageObjectFile.getByteOrder()); + offsetsSectionBufferImpl = new BasicProgbitsSectionImpl(offsetsSectionBuffer.getBackingArray()); + String name = SVM_METHODTABLE.getFormatDependentName(imageObjectFile.getFormat()); + ObjectFile.Section offsetsSection = imageObjectFile.newProgbitsSection(name, imageObjectFile.getPageSize(), true, false, offsetsSectionBufferImpl); + + ObjectFile.RelocationKind relocationKind = ObjectFile.RelocationKind.getDirect(wordSize); + for (int gotEntryNo = 0; gotEntryNo < got.length; ++gotEntryNo) { + offsetsSectionBuffer.addRelocationWithoutAddend(gotEntryNo * wordSize, relocationKind, new MethodPointer(got[gotEntryNo], true)); + } + + imageObjectFile.createDefinedSymbol(offsetsSection.getName(), offsetsSection, 0, 0, false, false); + imageObjectFile.createDefinedSymbol("__svm_methodtable_begin", offsetsSection, 0, wordSize, false, SubstrateOptions.InternalSymbolsAreGlobal.getValue()); + imageObjectFile.createDefinedSymbol("__svm_methodtable_end", offsetsSection, gotSectionSize, wordSize, false, SubstrateOptions.InternalSymbolsAreGlobal.getValue()); + } + + @Override + public MethodAddressResolver createMethodAddressResolver() { + return new IdentityMethodAddressResolver(); + } + } + + @Override + public List> getRequiredFeatures() { + return Collections.singletonList(PLTGOTFeature.class); + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + HostedPLTGOTConfiguration.singleton().initializeMethodAddressResolutionSupport(IdentityMethodAddressResolverSupport::new); + } + + @Override + public void beforeImageWrite(BeforeImageWriteAccess access) { + prepareOffsetsSection((NativeImage) ((FeatureImpl.BeforeImageWriteAccessImpl) access).getImage()); + } + + private void prepareOffsetsSection(NativeImage image) { + image.markRelocationSitesFromBuffer(offsetsSectionBuffer, offsetsSectionBufferImpl); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/MethodAddressResolutionSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/MethodAddressResolutionSupport.java new file mode 100644 index 000000000000..724206517249 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/MethodAddressResolutionSupport.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot; + +import com.oracle.objectfile.ObjectFile; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.pltgot.MethodAddressResolver; + +/** + * Provides necessary services for dynamic method address resolution through the PLT/GOT. + */ +public interface MethodAddressResolutionSupport { + + /** + * Predicate that determines if an indirect GOT call should be emitted when the callee is called + * from the caller. + * + */ + boolean shouldCallViaPLTGOT(SharedMethod caller, SharedMethod callee); + + /** + * Predicate that determines if an indirect GOT call should be used when the caller of the + * method is not known. + */ + boolean shouldCallViaPLTGOT(SharedMethod callee); + + /** + * Allows the resolver to augment the object file produced by the image builder. This can be + * used, for example, to create a custom section in the resulting object file. + */ + void augmentImageObjectFile(ObjectFile imageObjectFile); + + /** + * Creates a resolver that will be used to resolve the addresses of methods called through the + * PLT/GOT at runtime. + */ + MethodAddressResolver createMethodAddressResolver(); +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/MethodAddressResolutionSupportFactory.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/MethodAddressResolutionSupportFactory.java new file mode 100644 index 000000000000..af7289ca1bc3 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/MethodAddressResolutionSupportFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot; + +public interface MethodAddressResolutionSupportFactory { + MethodAddressResolutionSupport create(); +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTFeature.java new file mode 100644 index 000000000000..3dc472c1856c --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTFeature.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot; + +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.reflect.Method; +import java.util.Iterator; +import java.util.Set; +import java.util.function.Consumer; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; + +import com.oracle.graal.pointsto.reports.ReportUtils; +import com.oracle.objectfile.BasicProgbitsSectionImpl; +import com.oracle.objectfile.ObjectFile; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.graal.RuntimeCompilation; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.pltgot.GOTAccess; +import com.oracle.svm.core.pltgot.GOTHeapSupport; +import com.oracle.svm.core.pltgot.PLTGOTConfiguration; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.FeatureImpl; +import com.oracle.svm.hosted.image.MethodPointerRelocationProvider; +import com.oracle.svm.hosted.image.RelocatableBuffer; +import com.oracle.svm.hosted.pltgot.aarch64.AArch64HostedPLTGOTConfiguration; +import com.oracle.svm.hosted.pltgot.amd64.AMD64HostedPLTGOTConfiguration; + +import jdk.graal.compiler.util.json.JsonWriter; + +/** + * Introduces the PLT and GOT mechanism to native calls that allows resolving the target method's + * address at runtime. + * + * To create a custom method address resolver, a user needs to: + *
        + *
      1. Implement the {@link MethodAddressResolutionSupport} resolver support class.
      2. + *
      3. Create a feature that enables the {@link PLTGOTOptions#EnablePLTGOT} option and registers + * their resolver in the {@link ImageSingletons}.
      4. + *
      + * For an example resolver, see {@link com.oracle.svm.core.pltgot.IdentityMethodAddressResolver}. + * + * From an implementation point of view, this feature and the supporting classes implement + * the PLT (Procedure + * Linkage Table) and GOT (Global Offset Table) mechanism used by the Linux dynamic linker to + * enable lazy binding. + * + * Native Image constructs the GOT during the image build by assigning each eligible method an entry + * into the GOT. At runtime, the GOT is represented as an array of pointers mapped right before the + * image heap. Multiple isolates all see the same GOT. Direct calls of eligible methods are replaced + * with indirect calls that load the method's address from the GOT. + * + * For each eligible method, Native Image constructs a PLT stub. Initially, each GOT entry points to + * the PLT stub of the method assigned to that GOT entry. Vtable entries of eligible methods also + * point to the PLT stub. + * + * There are two kinds of calls on the native level: + *
        + *
      1. Direct calls
      2. + *
      3. Indirect calls
      4. + *
      + * Native image emits direct calls as IP relative calls. If a method is directly called and requires + * the PLT/GOT, these calls are instead emitted as indirect calls where the address of the method to + * call is located at HEAP_BASE_REGISTER - (METHOD_GOT_ENTRY_NO * WORD_SIZE). Indirect calls, used + * for virtual calls, are unchanged. For virtual calls, each vtable entry is rewritten to point to + * the PLT stub associated with the method we are calling, and it will never change during program + * execution. As a consequence, virtual calls for methods that are resolved with the PLT/GOT + * mechanism are doubly indirected. Also, we only rewrite the vtable entries for the methods that + * are called through the PLT/GOT mechanism. + * + * A couple of implementation notes: + *
        + *
      • The GOT is always mapped relative to the image heap of an isolate and is backed by the same + * memory across isolates. This means that modifications made to the GOT by one isolate are visible + * to all other isolates. This mapping is necessary to avoid relocations in the code (we don't want + * to patch the code at runtime).
      • + *
      • Virtual calls now have two levels of indirection instead of one. The vtables contain + * addresses of PLT stubs corresponding to the virtual methods. A PLT stub either resolves the + * address of the actual method and writes it to the GOT, or it reads the previously resolved method + * address from the GOT, before finally jumping into the target method. The vtables themselves are + * never modified so that the relocatable section of the image heap can remain read-only.
      • + * + * If the PLT/GOT mechanism is used for all eligible methods, the additional indirections that are + * now present in calls can result in a slowdown that ranges from just a few percent to up to 20% + * depending on the workload for the default configuration. + *
      + */ +public class PLTGOTFeature implements InternalFeature { + + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return PLTGOTOptions.EnablePLTGOT.getValue(); + } + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + VMError.guarantee(Platform.includedIn(Platform.LINUX.class) || Platform.includedIn(Platform.DARWIN.class) || Platform.includedIn(Platform.WINDOWS.class), + "PLT and GOT is currently only supported on Linux, Darwin and Windows."); + VMError.guarantee(Platform.includedIn(Platform.AARCH64.class) || Platform.includedIn(Platform.AMD64.class), "PLT and GOT is currently only supported on AArch64 and AMD64."); + VMError.guarantee(!RuntimeCompilation.isEnabled(), "PLT and GOT is currently not supported with runtime compilation."); + VMError.guarantee(SubstrateOptions.SpawnIsolates.getValue(), "PLT and GOT cannot work without isolates."); + VMError.guarantee("lir".equals(SubstrateOptions.CompilerBackend.getValue()), "PLT and GOT cannot work with a custom compiler backend."); + + ImageSingletons.add(PLTGOTConfiguration.class, createConfiguration()); + } + + private static PLTGOTConfiguration createConfiguration() { + if (Platform.includedIn(Platform.AMD64.class)) { + return new AMD64HostedPLTGOTConfiguration(); + } else if (Platform.includedIn(Platform.AARCH64.class)) { + return new AArch64HostedPLTGOTConfiguration(); + } else { + throw VMError.shouldNotReachHere("PLT and GOT is currently only supported on AArch64 and AMD64."); + } + } + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + Method resolver = HostedPLTGOTConfiguration.singleton().getArchSpecificResolverAsMethod(); + ((FeatureImpl.BeforeAnalysisAccessImpl) access).registerAsRoot(resolver, false, "PLT GOT support, registered in " + PLTGOTFeature.class); + } + + @Override + public void beforeCompilation(BeforeCompilationAccess access) { + HostedPLTGOTConfiguration.singleton().setHostedMetaAccess(((FeatureImpl.BeforeCompilationAccessImpl) access).getMetaAccess()); + } + + @Override + public void afterCompilation(AfterCompilationAccess access) { + MethodAddressResolutionSupport methodAddressResolutionSupport = HostedPLTGOTConfiguration.singleton().getMethodAddressResolutionSupport(); + GOTEntryAllocator gotEntryAllocator = HostedPLTGOTConfiguration.singleton().getGOTEntryAllocator(); + + gotEntryAllocator.reserveAndLayout(((FeatureImpl.AfterCompilationAccessImpl) access).getCompilations().keySet(), methodAddressResolutionSupport); + + Set gotTable = Set.of(gotEntryAllocator.getGOT()); + ImageSingletons.add(MethodPointerRelocationProvider.class, new PLTGOTPointerRelocationProvider(gotTable::contains)); + } + + @Override + public void beforeImageWrite(BeforeImageWriteAccess access) { + HostedPLTGOTConfiguration.singleton().markResolverMethodPatch(); + if (PLTGOTOptions.PrintPLTGOTCallsInfo.getValue()) { + reportPLTGOTCallSites(); + } + } + + @Override + public void afterAbstractImageCreation(AfterAbstractImageCreationAccess access) { + FeatureImpl.AfterAbstractImageCreationAccessImpl accessImpl = (FeatureImpl.AfterAbstractImageCreationAccessImpl) access; + ObjectFile imageObjectFile = accessImpl.getImage().getObjectFile(); + SharedMethod[] got = HostedPLTGOTConfiguration.singleton().getGOTEntryAllocator().getGOT(); + /* We must create the PLT and the GOT section before we mark any relocations. */ + PLTSectionSupport pltSectionSupport = HostedPLTGOTConfiguration.singleton().getPLTSectionSupport(); + pltSectionSupport.createPLTSection(got, imageObjectFile, accessImpl.getSubstrateBackend()); + createGOTSection(got, imageObjectFile, pltSectionSupport); + HostedPLTGOTConfiguration.singleton().getMethodAddressResolutionSupport().augmentImageObjectFile(imageObjectFile); + } + + public static void createGOTSection(SharedMethod[] got, ObjectFile objectFile, PLTSectionSupport pltSectionSupport) { + int wordSize = ConfigurationValues.getTarget().wordSize; + int gotSectionSize = got.length * wordSize; + RelocatableBuffer gotBuffer = new RelocatableBuffer(gotSectionSize, objectFile.getByteOrder()); + ObjectFile.ProgbitsSectionImpl gotBufferImpl = new BasicProgbitsSectionImpl(gotBuffer.getBackingArray()); + String name = HostedPLTGOTConfiguration.SVM_GOT_SECTION.getFormatDependentName(objectFile.getFormat()); + ObjectFile.Section gotSection = objectFile.newProgbitsSection(name, objectFile.getPageSize(), true, false, gotBufferImpl); + + ObjectFile.RelocationKind relocationKind = ObjectFile.RelocationKind.getDirect(wordSize); + for (int gotEntryNo = 0; gotEntryNo < got.length; ++gotEntryNo) { + int methodGOTEntryOffsetInSection = gotSectionSize + GOTAccess.getGotEntryOffsetFromHeapRegister(gotEntryNo); + pltSectionSupport.markRelocationToPLTResolverJump(gotBufferImpl, methodGOTEntryOffsetInSection, relocationKind, got[gotEntryNo]); + } + + objectFile.createDefinedSymbol(gotSection.getName(), gotSection, 0, 0, false, false); + objectFile.createDefinedSymbol(GOTHeapSupport.IMAGE_GOT_BEGIN_SYMBOL_NAME, gotSection, 0, wordSize, false, + SubstrateOptions.InternalSymbolsAreGlobal.getValue()); + objectFile.createDefinedSymbol(GOTHeapSupport.IMAGE_GOT_END_SYMBOL_NAME, gotSection, gotSectionSize, wordSize, false, + SubstrateOptions.InternalSymbolsAreGlobal.getValue()); + + if (PLTGOTOptions.PrintGOT.getValue()) { + ReportUtils.report("GOT Section contents", SubstrateOptions.reportsPath(), "got", "txt", writer -> { + writer.println("GOT Entry No | GOT Entry Offset From Image Heap Register | Method Name"); + for (int i = 0; i < got.length; ++i) { + writer.printf("%5X %5X %s%n", i, -GOTAccess.getGotEntryOffsetFromHeapRegister(i), got[i].toString()); + } + }); + } + } + + private static void reportPLTGOTCallSites() { + CollectPLTGOTCallSitesResolutionSupport resolver = (CollectPLTGOTCallSitesResolutionSupport) HostedPLTGOTConfiguration.singleton().getMethodAddressResolutionSupport(); + Consumer reportWriter = (pw) -> { + final String methodFormat = "%H.%n(%p)"; + try (JsonWriter writer = new JsonWriter(pw)) { + writer.append('{').newline(); + var calleesWithUnknownCaller = resolver.getCalleesWithUnknownCaller().stream().map(m -> m.format(methodFormat)).toList(); + if (!calleesWithUnknownCaller.isEmpty()) { + writer.quote("UNKNOWN_CALLER").append(":[").indent().newline(); + appendCallees(writer, calleesWithUnknownCaller.iterator()); + writer.newline().unindent().append("]"); + } + for (var entry : resolver.getCallerCalleesMap().entrySet()) { + writer.append(',').newline(); + var caller = entry.getKey(); + var calleesIter = entry.getValue().stream().map(m -> m.format(methodFormat)) + .sorted().iterator(); + writer.quote(caller.format(methodFormat)).append(":[").indent().newline(); + appendCallees(writer, calleesIter); + writer.unindent().newline().append(']'); + } + writer.newline().append('}').newline(); + } catch (IOException e) { + VMError.shouldNotReachHere(e); + } + }; + ReportUtils.report("PLT/GOT call-sites info", + SubstrateOptions.reportsPath(), "plt_got_call-sites_info", "json", reportWriter); + } + + private static void appendCallees(JsonWriter writer, Iterator callees) throws IOException { + while (callees.hasNext()) { + var callee = callees.next(); + writer.quote(callee); + if (callees.hasNext()) { + writer.append(','); + writer.newline(); + } + } + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTOptions.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTOptions.java new file mode 100644 index 000000000000..869874560091 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTOptions.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot; + +import com.oracle.svm.core.option.HostedOptionKey; + +import jdk.graal.compiler.options.Option; +import jdk.graal.compiler.options.OptionType; + +public class PLTGOTOptions { + @Option(help = "Enables support for dynamic method address resolution. Should never be enabled directly.", type = OptionType.Expert)// + public static final HostedOptionKey EnablePLTGOT = new HostedOptionKey<>(false); + + @Option(help = "Prints the contents of the GOT.", type = OptionType.Debug)// + public static final HostedOptionKey PrintGOT = new HostedOptionKey<>(false); + + @Option(help = "Prints Infopoint call sites inside methods called through PLT/GOT.", type = OptionType.Debug)// + public static final HostedOptionKey PrintPLTGOTCallsInfo = new HostedOptionKey<>(false); +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTPointerRelocationProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTPointerRelocationProvider.java new file mode 100644 index 000000000000..df3eb86848f5 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTGOTPointerRelocationProvider.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot; + +import java.util.function.Predicate; + +import com.oracle.objectfile.ObjectFile; +import com.oracle.svm.core.meta.MethodPointer; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.hosted.image.MethodPointerRelocationProvider; +import com.oracle.svm.hosted.meta.HostedMethod; + +/** + * Emits method pointer relocations in the image object file that take PLT/GOT into account. + * + * For methods invoked through PLT/GOT, unless overridden explicitly, emits relocations that point + * to the generated PLT stub. + */ +public class PLTGOTPointerRelocationProvider extends MethodPointerRelocationProvider { + + private final Predicate shouldMarkRelocationToPLTStub; + private final PLTSectionSupport pltSectionSupport; + + public PLTGOTPointerRelocationProvider(Predicate shouldMarkRelocationToPLTStub) { + this.shouldMarkRelocationToPLTStub = shouldMarkRelocationToPLTStub; + this.pltSectionSupport = HostedPLTGOTConfiguration.singleton().getPLTSectionSupport(); + } + + private boolean hasPLTStub(HostedMethod target, boolean isStaticallyResolved) { + return !isStaticallyResolved && shouldMarkRelocationToPLTStub.test(target); + } + + @Override + public void markMethodPointerRelocation(ObjectFile.ProgbitsSectionImpl section, int offset, ObjectFile.RelocationKind relocationKind, HostedMethod target, long addend, + MethodPointer methodPointer, boolean isInjectedNotCompiled) { + boolean isStaticallyResolved = methodPointer.isAbsolute(); + if (hasPLTStub(target, isStaticallyResolved)) { + pltSectionSupport.markRelocationToPLTStub(section, offset, relocationKind, target, addend); + } else { + super.markMethodPointerRelocation(section, offset, relocationKind, target, addend, methodPointer, isInjectedNotCompiled); + } + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTSectionSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTSectionSupport.java new file mode 100644 index 000000000000..1f61742d6e83 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTSectionSupport.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot; + +import java.util.HashMap; +import java.util.Map; + +import com.oracle.objectfile.BasicProgbitsSectionImpl; +import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.ObjectFile.ProgbitsSectionImpl; +import com.oracle.objectfile.ObjectFile.RelocationKind; +import com.oracle.objectfile.SectionName; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.graal.code.SubstrateBackend; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.hosted.image.NativeImage; +import com.oracle.svm.hosted.image.RelocatableBuffer; +import com.oracle.svm.hosted.meta.HostedMethod; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class PLTSectionSupport { + + public static final SectionName SVM_PLT_SECTION_NAME = new SectionName.ProgbitsSectionName("svm_plt"); + + public static String pltSymbolNameForMethod(ResolvedJavaMethod method) { + return "svm_plt_" + NativeImage.localSymbolNameForMethod(method); + } + + private final Map methodPLTStubStart = new HashMap<>(); + private final Map methodPLTStubResolverOffset = new HashMap<>(); + + private ProgbitsSectionImpl pltBufferImpl; + private PLTStubGenerator stubGenerator; + + public PLTSectionSupport(PLTStubGenerator stubGenerator) { + this.stubGenerator = stubGenerator; + } + + void createPLTSection(SharedMethod[] got, ObjectFile objectFile, SubstrateBackend substrateBackend) { + byte[] pltCode = stubGenerator.generatePLT(got, substrateBackend); + int pltSectionSize = pltCode.length; + + RelocatableBuffer pltBuffer = new RelocatableBuffer(pltSectionSize, objectFile.getByteOrder()); + pltBufferImpl = new BasicProgbitsSectionImpl(pltBuffer.getBackingArray()); + String name = SVM_PLT_SECTION_NAME.getFormatDependentName(objectFile.getFormat()); + ObjectFile.Section pltSection = objectFile.newProgbitsSection(name, objectFile.getPageSize(), false, true, pltBufferImpl); + + pltBuffer.getByteBuffer().put(pltCode, 0, pltSectionSize); + + objectFile.createDefinedSymbol(pltSection.getName(), pltSection, 0, 0, true, false); + + for (SharedMethod method : got) { + HostedMethod m = (HostedMethod) method; + int offset = getMethodPLTStubStart(m); + objectFile.createDefinedSymbol(pltSymbolNameForMethod(m), pltSection, offset, ConfigurationValues.getTarget().wordSize, true, + SubstrateOptions.InternalSymbolsAreGlobal.getValue()); + } + + } + + void markRelocationToPLTStub(ProgbitsSectionImpl section, int offset, RelocationKind relocationKind, SharedMethod target, long addend) { + section.markRelocationSite(offset, relocationKind, pltSymbolNameForMethod(target), addend); + } + + void markRelocationToPLTResolverJump(ProgbitsSectionImpl section, int offset, RelocationKind relocationKind, SharedMethod target) { + assert methodPLTStubResolverOffset.get(target) != null : "Trying to mark a relocation to the `resolver-jump` part of the plt stub for a target that doesn't have a plt stub: " + target; + section.markRelocationSite(offset, relocationKind, pltSymbolNameForMethod(target), methodPLTStubResolverOffset.get(target)); + } + + void markResolverMethodPatch(HostedMethod resolverMethod) { + stubGenerator.markResolverMethodPatch(pltBufferImpl, resolverMethod); + } + + public void recordMethodPLTStubStart(SharedMethod method, int offset) { + methodPLTStubStart.put(method, offset); + } + + public void recordMethodPLTStubResolverOffset(SharedMethod method, int resolverOffset) { + methodPLTStubResolverOffset.put(method, resolverOffset); + } + + private int getMethodPLTStubStart(SharedMethod method) { + return methodPLTStubStart.get(method); + } + +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTStubGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTStubGenerator.java new file mode 100644 index 000000000000..694872d0ecce --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/PLTStubGenerator.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot; + +import com.oracle.objectfile.ObjectFile; +import com.oracle.svm.core.graal.code.SubstrateBackend; +import com.oracle.svm.core.meta.SharedMethod; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public interface PLTStubGenerator { + + byte[] generatePLT(SharedMethod[] got, SubstrateBackend substrateBackend); + + void markResolverMethodPatch(ObjectFile.ProgbitsSectionImpl pltBuffer, ResolvedJavaMethod resolverMethod); + +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/aarch64/AArch64HostedPLTGOTConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/aarch64/AArch64HostedPLTGOTConfiguration.java new file mode 100644 index 000000000000..c8765d716650 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/aarch64/AArch64HostedPLTGOTConfiguration.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot.aarch64; + +import java.lang.reflect.Method; + +import com.oracle.svm.core.pltgot.aarch64.AArch64ExitMethodAddressResolutionOp; +import com.oracle.svm.core.pltgot.aarch64.AArch64MethodAddressResolutionDispatcher; +import com.oracle.svm.hosted.pltgot.HostedPLTGOTConfiguration; +import com.oracle.svm.hosted.pltgot.PLTStubGenerator; +import com.oracle.svm.util.ReflectionUtil; + +import jdk.graal.compiler.lir.LIRInstruction; +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.RegisterValue; + +public final class AArch64HostedPLTGOTConfiguration extends HostedPLTGOTConfiguration { + + @Override + public Method getArchSpecificResolverAsMethod() { + return ReflectionUtil.lookupMethod(AArch64MethodAddressResolutionDispatcher.class, "resolveMethodAddress"); + } + + @Override + public PLTStubGenerator getArchSpecificPLTStubGenerator() { + return new AArch64PLTStubGenerator(); + } + + @Override + public Register getExitMethodAddressResolutionRegister(RegisterConfig registerConfig) { + return AArch64.rscratch2; + } + + @Override + public LIRInstruction createExitMethodAddressResolutionOp(RegisterValue exitThroughRegisterValue) { + return new AArch64ExitMethodAddressResolutionOp(exitThroughRegisterValue); + } + + @Override + public Register getGOTPassingRegister(RegisterConfig registerConfig) { + throw new UnsupportedOperationException("AArch64 passes got entries via (unused) deopt frame handle slot."); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/aarch64/AArch64PLTStubGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/aarch64/AArch64PLTStubGenerator.java new file mode 100644 index 000000000000..fff68c2ea1f4 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/aarch64/AArch64PLTStubGenerator.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot.aarch64; + +import static com.oracle.objectfile.ObjectFile.RelocationKind.AARCH64_R_AARCH64_ADD_ABS_LO12_NC; +import static com.oracle.objectfile.ObjectFile.RelocationKind.AARCH64_R_AARCH64_ADR_PREL_PG_HI21; +import static jdk.graal.compiler.asm.aarch64.AArch64Address.createImmediateAddress; +import static jdk.graal.compiler.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_SIGNED_UNSCALED; +import static jdk.vm.ci.aarch64.AArch64.sp; + +import com.oracle.objectfile.ObjectFile; +import com.oracle.svm.core.ReservedRegisters; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.deopt.DeoptimizationSlotPacking; +import com.oracle.svm.core.graal.code.SubstrateBackend; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.pltgot.GOTAccess; +import com.oracle.svm.core.pltgot.aarch64.AArch64MethodAddressResolutionDispatcher; +import com.oracle.svm.hosted.image.NativeImage; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.pltgot.HostedPLTGOTConfiguration; +import com.oracle.svm.hosted.pltgot.PLTSectionSupport; +import com.oracle.svm.hosted.pltgot.PLTStubGenerator; +import com.oracle.svm.hosted.pltgot.amd64.AMD64PLTStubGenerator; + +import jdk.graal.compiler.asm.Assembler; +import jdk.graal.compiler.asm.Label; +import jdk.graal.compiler.asm.aarch64.AArch64Address; +import jdk.graal.compiler.asm.aarch64.AArch64MacroAssembler; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Generates the contents of the PLT section for the PLT/GOT mechanism. + * + * Please first see {@link AMD64PLTStubGenerator} for more details on how PLT/GOT mechanism works in + * general. + * + * AArch64 and AMD64 .svm_plt sections are different because on AArch64 we can't use the + * {@code ForwardReturnValue} calling convention for the + * {@link AArch64MethodAddressResolutionDispatcher#resolveMethodAddress()} without spilling the + * register x0, because x0 is both the first parameter register and the return value register. + * That's why we pass the method's GOT entry index via the (unused) deopt frame handle slot on the + * stack. The .svm_plt stub at the beginning of the section stores the got entry just after the + * return address, which is the deopt frame handle slot, and then we jump to the + * {@link AArch64MethodAddressResolutionDispatcher#resolveMethodAddress()}. As there are other users + * of the deopt slot, an encoding is used (see{@link DeoptimizationSlotPacking}). + * + * The AArch64 variant has a common svm_plt stub to avoid repeating the instruction that stores the + * got entry at the deopt frame handle slot and the instructions that load the address of the + * resolver method and jump to it. + * + * An example of an `.svm_plt` section that contains 2 methods that are called via PLT/GOT on + * darwin-aarch64: + * + *
      + * 0x7f0000 <.svm_plt>:
      + * 0x7f0000:  ldur x8, [sp]
      + * 0x7f0004:  and x8, x8, #0xff00000000000000
      + * 0x7f0008:  orr x9, x9, x8
      + * 0x7f000c:  adrp x8, 0x5df000
      + * 0x7f0010:  add x8, x8, #0xdd0
      + * 0x7f0014:  stur x9, [sp]        @ store gotEntry at the deopt frame handle slot
      + * 0x7f0018:  br x8                @ Jumps to 
      + * 0x7f001c :
      + * 0x7f001c:  ldr x9, [x27,#-8]    @ <--- We jump here from the virtual method call site
      + * 0x7f0020:  br x9                @ Jumps to the resolved method, or to the line below if the method wasn't resolved.
      + * 0x7f0024:  mov w9, wzr          @ <---- We jump here from the direct method call site. This line loads the gotEntry id
      + * 0x7f0028:  b 0x7f0000 <.svm_plt>
      + * 0x7f002c :
      + * 0x7f002c:  ldr x9, [x27,#-16]
      + * 0x7f0030:  br x9
      + * 0x7f0034:  orr w9, wzr, #0x1
      + * 0x7f0038:  b 0x7f0000 <.svm_plt>
      + * 0x7f003c :
      + * 0x7f003c:  ldr x9, [x27,#-24]
      + * 0x7f0040:  br x9
      + * 0x7f0044:  orr w9, wzr, #0x2
      + * 0x7f0048:  b 0x7f0000 <.svm_plt>
      + * 
      + */ +public class AArch64PLTStubGenerator implements PLTStubGenerator { + private int resolverAddressLoadOffset = -1; + + @Override + public byte[] generatePLT(SharedMethod[] got, SubstrateBackend substrateBackend) { + AArch64MacroAssembler masm = new AArch64MacroAssembler(ConfigurationValues.getTarget()); + Label pltStart = new Label(); + masm.bind(pltStart); + try (AArch64MacroAssembler.ScratchRegister scratchRegister1 = masm.getScratchRegister(); AArch64MacroAssembler.ScratchRegister scratchRegister2 = masm.getScratchRegister()) { + Register resolverJmpRegister = scratchRegister1.getRegister(); + Register gotEntryPassingRegister = scratchRegister2.getRegister(); + + generateResolverCallStub(masm, gotEntryPassingRegister, resolverJmpRegister); + + PLTSectionSupport support = HostedPLTGOTConfiguration.singleton().getPLTSectionSupport(); + for (int gotEntryNo = 0; gotEntryNo < got.length; ++gotEntryNo) { + HostedMethod method = (HostedMethod) got[gotEntryNo]; + int pltStubStart = masm.position(); + + /* Start of PLT stub for this GOT entry. */ + support.recordMethodPLTStubStart(method, pltStubStart); + + int gotEntryOffset = GOTAccess.getGotEntryOffsetFromHeapRegister(gotEntryNo); + Register heapReg = ReservedRegisters.singleton().getHeapBaseRegister(); + AArch64Address addr = masm.makeAddress(64, heapReg, gotEntryOffset, gotEntryPassingRegister); + + masm.maybeEmitIndirectTargetMarker(); + masm.ldr(64, gotEntryPassingRegister, addr); + masm.jmp(gotEntryPassingRegister); + + /* + * This is used as initial entry in the GOT, so that on first access this entry is + * going to be resolved. + */ + support.recordMethodPLTStubResolverOffset(method, masm.position() - pltStubStart); + masm.maybeEmitIndirectTargetMarker(); + masm.mov(gotEntryPassingRegister, gotEntryNo); + masm.jmp(pltStart); + } + } + return masm.close(true); + } + + @Override + public void markResolverMethodPatch(ObjectFile.ProgbitsSectionImpl pltBuffer, ResolvedJavaMethod resolverMethod) { + pltBuffer.markRelocationSite(resolverAddressLoadOffset, AARCH64_R_AARCH64_ADR_PREL_PG_HI21, NativeImage.localSymbolNameForMethod(resolverMethod), 0); + pltBuffer.markRelocationSite(resolverAddressLoadOffset + 4, AARCH64_R_AARCH64_ADD_ABS_LO12_NC, NativeImage.localSymbolNameForMethod(resolverMethod), 0); + } + + public void generateResolverCallStub(AArch64MacroAssembler masm, Register gotEntryPassingRegister, Register jmpTarget) { + masm.setCodePatchingAnnotationConsumer(this::recordResolverCallForPatching); + + /* + * GR-54839: Upper byte of deoptSlot may be used by leaveInterpreterStub, therefore an + * encoding is used for this word. + */ + Register scratch = jmpTarget; + masm.ldr(64, scratch, createImmediateAddress(64, IMMEDIATE_SIGNED_UNSCALED, sp, 0)); + masm.and(64, scratch, scratch, DeoptimizationSlotPacking.MASK_VARIABLE_FRAMESIZE); + masm.orr(64, gotEntryPassingRegister, gotEntryPassingRegister, scratch); + + /* + * use indirect jump to avoid problems around branch islands (displacement larger than + * +/-128MB) + */ + masm.adrpAdd(jmpTarget); + masm.str(64, gotEntryPassingRegister, createImmediateAddress(64, IMMEDIATE_SIGNED_UNSCALED, sp, 0)); + masm.jmp(jmpTarget); + } + + private void recordResolverCallForPatching(Assembler.CodeAnnotation a) { + if (resolverAddressLoadOffset != -1) { + return; + } + assert a instanceof AArch64MacroAssembler.AdrpAddMacroInstruction; + AArch64MacroAssembler.AdrpAddMacroInstruction annotation = (AArch64MacroAssembler.AdrpAddMacroInstruction) a; + resolverAddressLoadOffset = annotation.instructionPosition; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/amd64/AMD64HostedPLTGOTConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/amd64/AMD64HostedPLTGOTConfiguration.java new file mode 100644 index 000000000000..766195155610 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/amd64/AMD64HostedPLTGOTConfiguration.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot.amd64; + +import java.lang.reflect.Method; + +import com.oracle.svm.core.pltgot.amd64.AMD64ExitMethodAddressResolutionOp; +import com.oracle.svm.core.pltgot.amd64.AMD64MethodAddressResolutionDispatcher; +import com.oracle.svm.hosted.pltgot.HostedPLTGOTConfiguration; +import com.oracle.svm.hosted.pltgot.PLTStubGenerator; +import com.oracle.svm.util.ReflectionUtil; + +import jdk.graal.compiler.lir.LIRInstruction; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.RegisterValue; + +public final class AMD64HostedPLTGOTConfiguration extends HostedPLTGOTConfiguration { + + @Override + public Method getArchSpecificResolverAsMethod() { + return ReflectionUtil.lookupMethod(AMD64MethodAddressResolutionDispatcher.class, "resolveMethodAddress", long.class); + } + + @Override + public PLTStubGenerator getArchSpecificPLTStubGenerator() { + return new AMD64PLTStubGenerator(); + } + + @Override + public Register getExitMethodAddressResolutionRegister(RegisterConfig registerConfig) { + return getGOTPassingRegister(registerConfig); + } + + @Override + public LIRInstruction createExitMethodAddressResolutionOp(RegisterValue exitThroughRegisterValue) { + return new AMD64ExitMethodAddressResolutionOp(exitThroughRegisterValue); + } + + @Override + public Register getGOTPassingRegister(RegisterConfig registerConfig) { + return registerConfig.getReturnRegister(getArchSpecificResolverAsHostedMethod().getSignature().getReturnKind()); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/amd64/AMD64PLTStubGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/amd64/AMD64PLTStubGenerator.java new file mode 100644 index 000000000000..355f145d631b --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/amd64/AMD64PLTStubGenerator.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.pltgot.amd64; + +import java.util.ArrayList; +import java.util.List; + +import com.oracle.objectfile.ObjectFile; +import com.oracle.svm.core.ReservedRegisters; +import com.oracle.svm.core.graal.amd64.SubstrateAMD64Backend; +import com.oracle.svm.core.graal.code.SubstrateBackend; +import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; +import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.core.pltgot.GOTAccess; +import com.oracle.svm.core.pltgot.amd64.AMD64MethodAddressResolutionDispatcher; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.image.NativeImage; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.pltgot.HostedPLTGOTConfiguration; +import com.oracle.svm.hosted.pltgot.PLTSectionSupport; +import com.oracle.svm.hosted.pltgot.PLTStubGenerator; + +import jdk.graal.compiler.asm.Assembler; +import jdk.graal.compiler.asm.amd64.AMD64Address; +import jdk.graal.compiler.asm.amd64.AMD64BaseAssembler; +import jdk.graal.compiler.asm.amd64.AMD64MacroAssembler; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Generates the contents of the PLT section for the PLT/GOT mechanism. + * + * Every method that can be dynamically resolved through the PLT/GOT mechanism has its unique PLT + * stub. We handle method resolution for virtual calls and direct calls differently. + * + * + * + * When resolving a virtual method the corresponding PLT stub loads the GOT entry associated with + * the called method via r14 - (GOT_ENTRY + 1) * 8 into the return value register (ie. rax). If the + * method is already resolved then the second instruction in the PLT stub will jump directly to the + * resolved method. Otherwise, because the GOT entries are initialized to point to the third + * instruction in the corresponding PLT stub, the second instruction will jump to the instruction + * below that loads the gotEntry id into the return value register and then the fourth instruction + * jumps to the {@link AMD64MethodAddressResolutionDispatcher#resolveMethodAddress(long)} that + * resolves the method with a given got entry. + * + * When resolving direct calls we jump directly to the second part of the PLT stub (third + * instruction) from the callsite because we rewrite the direct calls to the first two instructions + * of the corresponding PLT stub. That way, for direct calls, we only jump to the PLT stub if the + * method wasn't already resolved. + * + * The {@link AMD64MethodAddressResolutionDispatcher#resolveMethodAddress(long)} uses the + * {@link SubstrateCallingConventionKind#ForwardReturnValue} which expects its one and only argument + * to be in the return value register. This calling convention for the method resolver enables us to + * avoid having to spill the callers first argument to the stack. Also, we can reuse the same + * register as scratch for the second instruction in the PLT stub because the return value register + * is caller saved. + * + * An example of the `.svm_plt` section that contains 2 methods that are called via PLT/GOT (on + * Linux AMD64): + * + *
      + * {@code
      + *0000000000355000 :
      + *   355000:  mov      rax,QWORD PTR [r14-0x8] # <- virtual call jumps here.
      + *   355004:  jmp      rax                     # <- if the method is resolved jump to it, else jump to the instruction below.
      + *   355006:  mov      rax,0x0                 # <- direct call jumps here only once if the method hasn't already been resolved
      + *   35500b:  jmp      19e700 
      + *
      + * 0000000000355010 :
      + *   355010:  mov      rax,QWORD PTR [r14-0x10] # load the address from the GOT table. (`35501b` if the method wasn't resolved already, else method's address)
      + *   355014:  jmp      rax
      + *   355016:  mov      rax,0x1
      + *   35501b:  jmp      19e700 
      + * }
      + * 
      + */ +public class AMD64PLTStubGenerator implements PLTStubGenerator { + private List resolverPatchOffsets = new ArrayList<>(); + private int resolverKindAddend; + private ObjectFile.RelocationKind resolverPatchRelocationKind = null; + + @Override + public byte[] generatePLT(SharedMethod[] got, SubstrateBackend substrateBackend) { + HostedPLTGOTConfiguration configuration = HostedPLTGOTConfiguration.singleton(); + VMError.guarantee(configuration.getArchSpecificResolverAsHostedMethod().getCallingConventionKind().equals(SubstrateCallingConventionKind.ForwardReturnValue), + "AMD64PLTStubGenerator assumes that %s is using %s ", + configuration.getArchSpecificResolverAsHostedMethod().format("%H.%n(%p)"), SubstrateCallingConventionKind.ForwardReturnValue.name()); + + SubstrateAMD64Backend amd64Backend = (SubstrateAMD64Backend) substrateBackend; + RegisterConfig registerConfig = amd64Backend.getCodeCache().getRegisterConfig(); + Register register = configuration.getGOTPassingRegister(registerConfig); + + AMD64MacroAssembler asm = (AMD64MacroAssembler) amd64Backend.createAssemblerNoOptions(); + PLTSectionSupport support = HostedPLTGOTConfiguration.singleton().getPLTSectionSupport(); + + asm.setCodePatchingAnnotationConsumer(this::recordResolverCallForPatching); + for (int gotEntryNo = 0; gotEntryNo < got.length; ++gotEntryNo) { + HostedMethod method = (HostedMethod) got[gotEntryNo]; + + /* + * This is the method's call target. The GOT will be read to determine the method's + * actual address. + */ + int pltStubStart = asm.position(); + support.recordMethodPLTStubStart(method, pltStubStart); + + int gotEntryOffset = GOTAccess.getGotEntryOffsetFromHeapRegister(gotEntryNo); + asm.maybeEmitIndirectTargetMarker(); + asm.movq(register, new AMD64Address(ReservedRegisters.singleton().getHeapBaseRegister(), gotEntryOffset)); + asm.jmp(register); + + /* + * This is the initial target of the jmp directly above. Calls the resolver stub with + * the key for this method. + */ + support.recordMethodPLTStubResolverOffset(method, asm.position() - pltStubStart); + asm.maybeEmitIndirectTargetMarker(); + asm.movl(register, gotEntryNo); + /* + * We patch this later to the + * AMD64MethodAddressResolutionDispatcher#resolveMethodAddress(long). + */ + asm.jmp(); + } + + return asm.close(true); + } + + @Override + public void markResolverMethodPatch(ObjectFile.ProgbitsSectionImpl pltBuffer, ResolvedJavaMethod resolverMethod) { + for (int resolverPatchOffset : resolverPatchOffsets) { + pltBuffer.markRelocationSite(resolverPatchOffset, resolverPatchRelocationKind, NativeImage.localSymbolNameForMethod(resolverMethod), resolverKindAddend); + } + } + + private void recordResolverCallForPatching(Assembler.CodeAnnotation a) { + assert a instanceof AMD64BaseAssembler.OperandDataAnnotation; + AMD64BaseAssembler.OperandDataAnnotation annotation = (AMD64BaseAssembler.OperandDataAnnotation) a; + resolverPatchOffsets.add(annotation.operandPosition); + resolverKindAddend = -annotation.operandSize; + resolverPatchRelocationKind = ObjectFile.RelocationKind.getPCRelative(annotation.operandSize); + } +} From 775af5115fb4205f56afee821159ecb8d6e195ec Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Mon, 21 Oct 2024 22:19:31 -0700 Subject: [PATCH 086/105] Adapt to the future removal of the ZGenerational flag --- .../hotspot/GraalHotSpotVMConfig.java | 16 +++++++++++++ .../compiler/hotspot/HotSpotGraalRuntime.java | 24 +++++++++++++------ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java index 54db0081a22f..516385e79d6c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java @@ -35,6 +35,7 @@ import jdk.graal.compiler.debug.Assertions; import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.options.OptionValues; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; import jdk.vm.ci.meta.MetaAccessProvider; @@ -83,6 +84,14 @@ public boolean useG1GC() { return gc == HotSpotGraalRuntime.HotSpotGC.G1; } + /* + * There's no direct way to test for the presence of the boolean flag ZGenerational since there + * aren't any notPresent values which are distinct from the possible values. Instead use true + * and false as the notPresent value and check if it returns different answers. + */ + public final boolean isZGenerationalDefault = JavaVersionUtil.JAVA_SPEC > 21 && + (!access.getFlag("ZGenerational", Boolean.class, false).equals(access.getFlag("ZGenerational", Boolean.class, true))); + public boolean useXGC() { return gc == HotSpotGraalRuntime.HotSpotGC.X; } @@ -598,6 +607,13 @@ private long getZGCAddressField(String name) { public final int zPointerLoadShift = getConstant("ZPointerLoadShift", Integer.class, -1, osArch.equals("aarch64") && zgcSupport); private long getXGCAddressField(String name) { + if (JavaVersionUtil.JAVA_SPEC == 21 || isZGenerationalDefault) { + /* + * Graal does not support single gen ZGC in JDK 21 and it's no longer supported in 24 + * once the ZGenerational global flag has been removed. + */ + return 0; + } String realName = name; long address = 0; if (zgcSupport) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalRuntime.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalRuntime.java index 1c16b4c2a6dd..8319b8838d23 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalRuntime.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/HotSpotGraalRuntime.java @@ -25,6 +25,7 @@ package jdk.graal.compiler.hotspot; import static jdk.graal.compiler.core.common.GraalOptions.HotSpotPrintInlining; +import static jdk.graal.compiler.serviceprovider.JavaVersionUtil.JAVA_SPEC; import static jdk.vm.ci.common.InitTimer.timer; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; @@ -35,7 +36,6 @@ import java.util.Map; import java.util.function.Predicate; -import jdk.vm.ci.services.Services; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.Equivalence; @@ -75,6 +75,7 @@ import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.runtime.JVMCIBackend; +import jdk.vm.ci.services.Services; //JaCoCo Exclude @@ -206,8 +207,8 @@ public enum HotSpotGC { Parallel("UseParallelGC"), G1("UseG1GC"), // non-generational ZGC - X(flagIsSet("UseZGC").and(flagIsNotSet("ZGenerational"))), - Z(flagIsSet("UseZGC").and(flagIsSet("ZGenerational"))), + X(JAVA_SPEC >= 24, true, flagIsSet("UseZGC").and(isZGenerational().negate())), + Z(JAVA_SPEC >= 24, true, flagIsSet("UseZGC").and(isZGenerational())), Epsilon(true, true, flagIsSet("UseEpsilonGC")), // Unsupported GCs @@ -229,11 +230,20 @@ public enum HotSpotGC { private static Predicate flagIsSet(String flag) { final boolean notPresent = false; - return config1 -> config1.getFlag(flag, Boolean.class, notPresent, true); + return config -> config.getFlag(flag, Boolean.class, notPresent, true); } - private static Predicate flagIsNotSet(String flag) { - return flagIsSet(flag).negate(); + private static Predicate isZGenerational() { + return config -> { + if (JAVA_SPEC == 21) { + return false; + } + if (config.isZGenerationalDefault) { + return true; + } else { + return config.getFlag("ZGenerational", Boolean.class); + } + }; } /** @@ -267,7 +277,7 @@ static HotSpotGC forName(int name, GraalHotSpotVMConfig config) { // CollectedHeap::X is not defined in HotSpot. Query CollectedHeap::Z instead // and the ZGenerational flag. if (config.getConstant("CollectedHeap::Z", Integer.class, -1, gc.expectNamePresent) == name) { - if (config.getFlag("ZGenerational", Boolean.class, false, true)) { + if (isZGenerational().test(config)) { return Z; } else { return X; From 3b8fb76b6b6962d13a78907d7efedf20394dc8d5 Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Thu, 24 Oct 2024 13:57:04 +0200 Subject: [PATCH 087/105] Rename "shouldOutlineAllocation" to "shouldForceSlowPath" --- .../snippets/SubstrateAllocationSnippets.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java index bd46de731a80..26e951fe8a37 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java @@ -725,7 +725,7 @@ private static AllocationCounter createAllocationSiteCounter(ValueNode node, Res return allocationSite.createCounter(counterName); } - private static boolean shouldOutlineAllocation(StructuredGraph graph) { + private static boolean shouldForceSlowPath(StructuredGraph graph) { return GraalOptions.ReduceCodeSize.getValue(graph.getOptions()); } @@ -746,7 +746,7 @@ public void lower(NewInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstance, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.addConst("size", size); - args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); + args.addConst("forceSlowPath", shouldForceSlowPath(graph)); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("profilingData", getProfilingData(node, type)); @@ -772,7 +772,7 @@ public void lower(NewInstanceWithExceptionNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstance, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.addConst("size", size); - args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); + args.addConst("forceSlowPath", shouldForceSlowPath(graph)); args.addConst("fillContents", FillContent.fromBoolean(true)); args.addConst("emitMemoryBarrier", true); args.addConst("profilingData", getProfilingData(node, type)); @@ -804,7 +804,7 @@ public void lower(SubstrateNewHybridInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); - args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); + args.addConst("forceSlowPath", shouldForceSlowPath(graph)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); args.addConst("fillContents", FillContent.fromBoolean(fillContents)); @@ -839,7 +839,7 @@ public void lower(NewStoredContinuationNode node, LoweringTool tool) { Arguments args = new Arguments(allocateStoredContinuation, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); - args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); + args.addConst("forceSlowPath", shouldForceSlowPath(graph)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); args.addConst("ipOffset", ContinuationSupport.singleton().getIPOffset()); @@ -869,7 +869,7 @@ public void lower(NewArrayNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); - args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); + args.addConst("forceSlowPath", shouldForceSlowPath(graph)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); @@ -904,7 +904,7 @@ public void lower(NewArrayWithExceptionNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", hubConstant); args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length)); - args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); + args.addConst("forceSlowPath", shouldForceSlowPath(graph)); args.addConst("arrayBaseOffset", arrayBaseOffset); args.addConst("log2ElementSize", log2ElementSize); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); @@ -983,7 +983,7 @@ public void lower(DynamicNewInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstanceDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", node.getInstanceType()); - args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); + args.addConst("forceSlowPath", shouldForceSlowPath(graph)); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); @@ -1005,7 +1005,7 @@ public void lower(DynamicNewInstanceWithExceptionNode node, LoweringTool tool) { Arguments args = new Arguments(allocateInstanceDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", node.getInstanceType()); - args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); + args.addConst("forceSlowPath", shouldForceSlowPath(graph)); args.addConst("fillContents", FillContent.fromBoolean(true)); args.addConst("emitMemoryBarrier", true/* barriers */); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); @@ -1028,7 +1028,7 @@ public void lower(DynamicNewArrayNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArrayDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("elementType", node.getElementType()); args.add("length", node.length()); - args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); + args.addConst("forceSlowPath", shouldForceSlowPath(graph)); args.addConst("fillContents", FillContent.fromBoolean(node.fillContents())); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); @@ -1051,7 +1051,7 @@ public void lower(DynamicNewArrayWithExceptionNode node, LoweringTool tool) { Arguments args = new Arguments(allocateArrayDynamic, graph.getGuardsStage(), tool.getLoweringStage()); args.add("elementType", node.getElementType()); args.add("length", node.length()); - args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); + args.addConst("forceSlowPath", shouldForceSlowPath(graph)); args.addConst("fillContents", FillContent.fromBoolean(true)); args.addConst("emitMemoryBarrier", true/* barriers */); args.addConst("supportsBulkZeroing", tool.getLowerer().supportsBulkZeroing()); @@ -1090,7 +1090,7 @@ public void lower(NewPodInstanceNode node, LoweringTool tool) { Arguments args = new Arguments(allocatePod, graph.getGuardsStage(), tool.getLoweringStage()); args.add("hub", node.getHub()); args.add("arrayLength", node.getArrayLength()); - args.addConst("forceSlowPath", shouldOutlineAllocation(graph)); + args.addConst("forceSlowPath", shouldForceSlowPath(graph)); args.add("referenceMap", node.getReferenceMap()); args.addConst("emitMemoryBarrier", node.emitMemoryBarrier()); args.addConst("maybeUnroll", node.getArrayLength().isConstant()); From 74fea34169cf32bf705771edd6a3f72066a4f209 Mon Sep 17 00:00:00 2001 From: Codrut Stancu Date: Thu, 24 Oct 2024 15:50:41 +0200 Subject: [PATCH 088/105] Adapt saturation to open world. --- .../graal/pointsto/PointsToAnalysis.java | 21 +++++++++ .../flow/AllInstantiatedTypeFlow.java | 2 +- .../flow/AnyPrimitiveSourceTypeFlow.java | 2 +- .../pointsto/flow/ArrayElementsTypeFlow.java | 22 ++++++---- .../graal/pointsto/flow/CloneTypeFlow.java | 17 +++++--- .../flow/DynamicNewInstanceTypeFlow.java | 15 ++++--- .../pointsto/flow/FieldFilterTypeFlow.java | 30 ++++++++++--- .../graal/pointsto/flow/FieldTypeFlow.java | 20 ++++++--- .../graal/pointsto/flow/FilterTypeFlow.java | 43 ++++++++++++++----- .../pointsto/flow/FormalReceiverTypeFlow.java | 17 ++++++-- .../graal/pointsto/flow/InvokeTypeFlow.java | 21 ++++++++- .../pointsto/flow/LoadFieldTypeFlow.java | 4 ++ .../graal/pointsto/flow/MethodFlowsGraph.java | 4 +- .../pointsto/flow/OffsetLoadTypeFlow.java | 4 ++ .../pointsto/flow/OffsetStoreTypeFlow.java | 10 ++++- .../graal/pointsto/flow/SourceTypeFlow.java | 2 +- .../pointsto/flow/StoreFieldTypeFlow.java | 4 ++ .../oracle/graal/pointsto/flow/TypeFlow.java | 12 +++--- .../pointsto/results/StrengthenGraphs.java | 13 +++--- 19 files changed, 198 insertions(+), 65 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index 938a2d448413..2db1fbf5e1ae 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -152,6 +152,27 @@ public PointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM executor.init(timing); } + /** + * Returns true if the type's hierarchy is complete in the observable universe. + *
        + *
      • In open type world this means that all the subtypes of this type are known and + * this type cannot be extended outside the observable universe.
      • + *
      • In closed type world all types are considered closed.
      • + *
      + * + * This method is conservative, it returns false in cases where we are not sure, and further + * refining when a type is closed will improve analysis. For example GR-59311 will also define + * when a sealed type can be treated as a closed type. + */ + public boolean isClosed(AnalysisType type) { + if (hostVM.isClosedTypeWorld()) { + /* In a closed type world all subtypes known. */ + return true; + } + /* Array and leaf types are by definition closed. */ + return type.isArray() || type.isLeaf(); + } + @Override protected CompletionExecutor.Timing getTiming() { return timing; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AllInstantiatedTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AllInstantiatedTypeFlow.java index c46288794c73..07ddb0bdf169 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AllInstantiatedTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AllInstantiatedTypeFlow.java @@ -48,7 +48,7 @@ public TypeFlow copy(PointsToAnalysis bb, MethodFlowsGraph methodF } @Override - public boolean canSaturate() { + public boolean canSaturate(PointsToAnalysis bb) { return false; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AnyPrimitiveSourceTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AnyPrimitiveSourceTypeFlow.java index 61b0af69e134..bfb65cc9a9bb 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AnyPrimitiveSourceTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/AnyPrimitiveSourceTypeFlow.java @@ -57,7 +57,7 @@ private boolean isLocal() { } @Override - public boolean canSaturate() { + public boolean canSaturate(PointsToAnalysis bb) { /* * AnyPrimitiveSourceTypeFlow can be used as a global flow that should always propagate * values. The global version can be identified be having source == null, and it should diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayElementsTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayElementsTypeFlow.java index 1ab883d65253..0b8e3e918fa1 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayElementsTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/ArrayElementsTypeFlow.java @@ -50,17 +50,23 @@ public TypeFlow copy(PointsToAnalysis bb, MethodFlowsGraph methodF } @Override - public boolean canSaturate() { - return false; + public boolean canSaturate(PointsToAnalysis bb) { + /* Arrays flows with a closed component type don't saturate, they track all input types. */ + return !bb.isClosed(declaredType); } @Override protected void onInputSaturated(PointsToAnalysis bb, TypeFlow input) { - /* - * When an array store is saturated conservatively assume that the array can contain any - * subtype of its declared type. - */ - getDeclaredType().getTypeFlow(bb, true).addUse(bb, this); + if (bb.isClosed(declaredType)) { + /* + * When an array store is saturated conservatively assume that the array can contain any + * subtype of its declared type, i.e., of its component type. + */ + declaredType.getTypeFlow(bb, true).addUse(bb, this); + } else { + /* Propagate the saturation stamp through the array flow. */ + super.onInputSaturated(bb, input); + } } @Override @@ -71,7 +77,7 @@ public TypeState filter(PointsToAnalysis bb, TypeState update) { } else { /* * Filter out the objects not compatible with the declared type, i.e., those objects - * whose type cannot be converted to the component type of the this array by assignment + * whose type cannot be converted to the component type of this array by assignment * conversion. At runtime that will throw an ArrayStoreException but during the analysis * we can detect such cases and filter out the incompatible types. */ diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CloneTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CloneTypeFlow.java index 2384a11c7c6c..848ea978d5d5 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CloneTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CloneTypeFlow.java @@ -90,12 +90,17 @@ public void update(PointsToAnalysis bb) { @Override public void onObservedSaturated(PointsToAnalysis bb, TypeFlow observed) { - if (!isSaturated()) { - /* - * When the input flow saturates start observing the flow of the declared type, unless - * the clone is already saturated. - */ - replaceObservedWith(bb, declaredType); + if (bb.isClosed(declaredType)) { + if (!isSaturated()) { + /* + * When the input flow saturates start observing the flow of the declared type, + * unless the clone is already saturated. + */ + replaceObservedWith(bb, declaredType); + } + } else { + /* Propagate the saturation stamp through the clone flow. */ + onSaturated(bb); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DynamicNewInstanceTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DynamicNewInstanceTypeFlow.java index 63df237c007b..319a8c6549fe 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DynamicNewInstanceTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DynamicNewInstanceTypeFlow.java @@ -96,14 +96,19 @@ public void setObserved(TypeFlow declaredTypeFlow) { @Override public void onObservedSaturated(PointsToAnalysis bb, TypeFlow observed) { - /* When the new-type flow saturates start observing the flow of the declared type. */ - replaceObservedWith(bb, declaredType); + if (bb.isClosed(declaredType)) { + /* When the new-type flow saturates start observing the flow of the declared type. */ + replaceObservedWith(bb, declaredType); + } else { + /* Propagate the saturation stamp through the dynamic new instance flow. */ + onSaturated(bb); + } } @Override - public boolean canSaturate() { - /* The dynamic new instance tracks all of its input types. */ - return false; + public boolean canSaturate(PointsToAnalysis bb) { + /* Dynamic new instance of closed types doesn't saturate, it tracks all input types. */ + return !bb.isClosed(declaredType); } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldFilterTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldFilterTypeFlow.java index 1b9b73008098..60c34f601a43 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldFilterTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldFilterTypeFlow.java @@ -75,21 +75,39 @@ public void addPredicated(PointsToAnalysis bb, TypeFlow predicatedFlow) { @Override protected void onInputSaturated(PointsToAnalysis bb, TypeFlow input) { - if (!setSaturated()) { - return; + if (bb.isClosed(declaredType)) { + /* + * We stop saturation propagation to the field flow and instead use the upper limit + * type, i.e., the field declared type, as a safe approximation, but only if the type is + * closed. For open types we simply propagate the saturation. + */ + if (!setSaturated()) { + return; + } + /* Swap out this flow with its declared type flow. */ + swapOut(bb, declaredType.getTypeFlow(bb, true)); + } else { + /* Propagate the saturation stamp through the filter flow. */ + super.onInputSaturated(bb, input); } - /* Swap out this flow with its declared type flow. */ - swapOut(bb, declaredType.getTypeFlow(bb, true)); } @Override protected void notifyUseOfSaturation(PointsToAnalysis bb, TypeFlow use) { - swapAtUse(bb, declaredType.getTypeFlow(bb, true), use); + if (bb.isClosed(declaredType)) { + swapAtUse(bb, declaredType.getTypeFlow(bb, true), use); + } else { + super.notifyUseOfSaturation(bb, use); + } } @Override protected void notifyObserverOfSaturation(PointsToAnalysis bb, TypeFlow observer) { - swapAtObserver(bb, declaredType.getTypeFlow(bb, true), observer); + if (bb.isClosed(declaredType)) { + swapAtObserver(bb, declaredType.getTypeFlow(bb, true), observer); + } else { + super.notifyObserverOfSaturation(bb, observer); + } } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldTypeFlow.java index f56aaa40790a..387ed2754ad6 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FieldTypeFlow.java @@ -65,17 +65,23 @@ public TypeFlow copy(PointsToAnalysis bb, MethodFlowsGraph method } @Override - public boolean canSaturate() { - return false; + public boolean canSaturate(PointsToAnalysis bb) { + /* Fields declared with a closed type don't saturate, they track all input types. */ + return !bb.isClosed(declaredType); } @Override protected void onInputSaturated(PointsToAnalysis bb, TypeFlow input) { - /* - * When a field store is saturated conservatively assume that the field state can contain - * any subtype of its declared type or any primitive value for primitive fields. - */ - getDeclaredType().getTypeFlow(bb, true).addUse(bb, this); + if (bb.isClosed(declaredType)) { + /* + * When a field store is saturated conservatively assume that the field state can + * contain any subtype of its declared type or any primitive value for primitive fields. + */ + declaredType.getTypeFlow(bb, true).addUse(bb, this); + } else { + /* Propagate saturation stamp through the field flow. */ + super.onInputSaturated(bb, input); + } } /** The filter flow is used for unsafe writes and initialized on demand. */ diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FilterTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FilterTypeFlow.java index 76ae822a23dc..0517788e0e90 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FilterTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FilterTypeFlow.java @@ -111,23 +111,42 @@ public void addPredicated(PointsToAnalysis bb, TypeFlow predicatedFlow) { @Override protected void onInputSaturated(PointsToAnalysis bb, TypeFlow input) { - if (isAssignable) { - if (!setSaturated()) { - return; + if (bb.isClosed(filterType)) { + if (isAssignable) { + /* + * If the filter type is closed stop saturation propagation to dependent flows and + * instead use the upper limit type, i.e., the filter type, as a safe approximation. + */ + if (!setSaturated()) { + return; + } + /* Swap this flow out at uses/observers/predicated flows with its filter type. */ + swapOut(bb, filterType.getTypeFlow(bb, includeNull)); + } else { + /* + * For the non-assignable branch simply propagate the saturation stamp through the + * filter flow. + */ + super.onInputSaturated(bb, input); } + } else { /* - * Swap this flow out at its uses/observers/predicated flows with its filter type flow. + * /* For open types simply propagate the saturation stamp through the filter flow, just + * like for the non-assignable branch. GR-59312 will preserve and propagate the upper + * limit type also for open types. */ - swapOut(bb, filterType.getTypeFlow(bb, includeNull)); - } else { super.onInputSaturated(bb, input); } } @Override protected void notifyUseOfSaturation(PointsToAnalysis bb, TypeFlow use) { - if (isAssignable) { - swapAtUse(bb, filterType.getTypeFlow(bb, includeNull), use); + if (bb.isClosed(filterType)) { + if (isAssignable) { + swapAtUse(bb, filterType.getTypeFlow(bb, includeNull), use); + } else { + super.notifyUseOfSaturation(bb, use); + } } else { super.notifyUseOfSaturation(bb, use); } @@ -135,8 +154,12 @@ protected void notifyUseOfSaturation(PointsToAnalysis bb, TypeFlow use) { @Override protected void notifyObserverOfSaturation(PointsToAnalysis bb, TypeFlow observer) { - if (isAssignable) { - swapAtObserver(bb, filterType.getTypeFlow(bb, includeNull), observer); + if (bb.isClosed(filterType)) { + if (isAssignable) { + swapAtObserver(bb, filterType.getTypeFlow(bb, includeNull), observer); + } else { + super.notifyObserverOfSaturation(bb, observer); + } } else { super.notifyObserverOfSaturation(bb, observer); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReceiverTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReceiverTypeFlow.java index 252a841f8f62..aa2e8550a54d 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReceiverTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/FormalReceiverTypeFlow.java @@ -75,10 +75,21 @@ public boolean addState(PointsToAnalysis bb, TypeState add) { @Override protected void onInputSaturated(PointsToAnalysis bb, TypeFlow input) { /* - * The saturation of the actual receiver doesn't result in the saturation of the formal - * receiver; some callees, depending how low in the type hierarchies they are, may only see - * a number of types smaller than the saturation cut-off limit. + * Note that in open world analysis the formal receiver of all callees linked to a context + * insensitive invoke will be notified of saturation. + * + * For a formal receiver with a closed declared type (which corresponds to the declaring + * class of its method) the saturation of the actual receiver doesn't result in the + * saturation of the formal receiver; some callees, depending on how low in the type + * hierarchies they are, may only see a number of types smaller than the saturation cut-off + * limit. + * + * If the declared type is open we cannot make any assumptions and simply propagate the + * saturation stamp. */ + if (!bb.isClosed(declaredType)) { + super.onInputSaturated(bb, input); + } } public boolean addReceiverState(PointsToAnalysis bb, TypeState add) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/InvokeTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/InvokeTypeFlow.java index ece8f7c168fe..eb20ac2eb757 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/InvokeTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/InvokeTypeFlow.java @@ -35,6 +35,7 @@ import com.oracle.graal.pointsto.meta.InvokeInfo; import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; import com.oracle.graal.pointsto.typestate.TypeState; +import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.common.meta.MultiMethod.MultiMethodKey; @@ -259,7 +260,11 @@ protected void linkCallee(PointsToAnalysis bb, boolean isStatic, MethodFlowsGrap // (formalParam, callerContext) -> (actualParam, calleeContext) // Note: the callerContext is an implicit property of the current InvokeTypeFlow // clone - actualParam.addUse(bb, formalParam); + if (actualParam.addUse(bb, formalParam)) { + if (i == 0 && !isStatic) { + maybeSaturateFormalReceiver(bb, actualParam, formalParam); + } + } } } } @@ -275,6 +280,20 @@ protected void linkCallee(PointsToAnalysis bb, boolean isStatic, MethodFlowsGrap } } + /* + * In the open type world we always propagate saturation of the actual receiver to the formal + * receiver, even after the saturated invoke was replaced by the context insensitive variant. + * So, if we are linking the receiver of a context insensitive invoke we immediately notify the + * formal receiver of saturation. + */ + private void maybeSaturateFormalReceiver(PointsToAnalysis bb, TypeFlow actualParam, TypeFlow formalParam) { + if (!bb.getHostVM().isClosedTypeWorld() && this.isContextInsensitive()) { + AnalysisError.guarantee(actualParam instanceof AllInstantiatedTypeFlow && formalParam instanceof FormalReceiverTypeFlow); + /* The actualParam is not technically saturated, but we treat it as such. */ + actualParam.notifyUseOfSaturation(bb, formalParam); + } + } + public void linkReturn(PointsToAnalysis bb, boolean isStatic, MethodFlowsGraphInfo calleeFlows) { /* * If actualReturn is null, then there is no linking necessary. Later, if a typeflow is diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/LoadFieldTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/LoadFieldTypeFlow.java index c5dd681f3236..f08ffa1a42c5 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/LoadFieldTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/LoadFieldTypeFlow.java @@ -146,6 +146,10 @@ public void onObservedUpdate(PointsToAnalysis bb) { @Override public void onObservedSaturated(PointsToAnalysis bb, TypeFlow observed) { + /* + * Nothing needs to change for open world analysis: we want to link all field flows when + * the receiver saturates. + */ if (!isSaturated()) { /* * When the receiver flow saturates start observing the flow of the field declaring diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java index e3e3819e3f2f..9d98ded258ad 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodFlowsGraph.java @@ -449,7 +449,7 @@ void updateInternalState(GraphKind newGraphKind) { public void saturateAllParameters(PointsToAnalysis bb) { AnalysisError.guarantee(bb.isBaseLayerAnalysisEnabled()); for (TypeFlow parameter : getParameters()) { - if (parameter != null && parameter.canSaturate()) { + if (parameter != null && parameter.canSaturate(bb)) { parameter.enableFlow(bb); parameter.onSaturated(bb); } @@ -466,7 +466,7 @@ public void saturateAllParameters(PointsToAnalysis bb) { */ if (miscEntryFlows != null) { for (TypeFlow miscEntryFlow : miscEntryFlows) { - if (miscEntryFlow != null && miscEntryFlow.canSaturate()) { + if (miscEntryFlow != null && miscEntryFlow.canSaturate(bb)) { miscEntryFlow.enableFlow(bb); miscEntryFlow.onSaturated(bb); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetLoadTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetLoadTypeFlow.java index ca3c6d4713c6..59f637426402 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetLoadTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetLoadTypeFlow.java @@ -69,6 +69,10 @@ public void setObserved(TypeFlow newObjectFlow) { @Override public void onObservedSaturated(PointsToAnalysis bb, TypeFlow observed) { + /* + * Nothing needs to change for open world analysis: we want to link all indexed/unsafe flows + * when the receiver saturates. + */ if (!isSaturated()) { /* * When the receiver flow saturates start observing the flow of the object type, unless diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetStoreTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetStoreTypeFlow.java index b01f8da156ec..08d5197ba33b 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetStoreTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/OffsetStoreTypeFlow.java @@ -145,11 +145,15 @@ public void onObservedUpdate(PointsToAnalysis bb) { @Override public void onObservedSaturated(PointsToAnalysis bb, TypeFlow observed) { + /* + * Nothing needs to change for open world analysis: we want to link all indexed store + * flows when the receiver saturates. + */ /* * When receiver flow saturates swap in the saturated indexed store type flow. When the * store itself saturates it propagates the saturation state to the uses/observers and * unlinks them, but it still observes the receiver state to notify no-yet-reachable - * field flows of saturation. + * indexed store flows of saturation. */ /* Deregister the store as an observer of the receiver. */ @@ -270,6 +274,10 @@ public void onObservedUpdate(PointsToAnalysis bb) { @Override public void onObservedSaturated(PointsToAnalysis bb, TypeFlow observed) { + /* + * Nothing needs to change for open world analysis: we want to link all unsafe store + * flows when the receiver saturates. + */ /* * When receiver flow saturates swap in the saturated unsafe store type flow. When the * store itself saturates it propagates the saturation state to the uses/observers and diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/SourceTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/SourceTypeFlow.java index 8a20c867cd8b..f700b1856ad0 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/SourceTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/SourceTypeFlow.java @@ -94,7 +94,7 @@ protected void onSaturated(PointsToAnalysis bb) { } @Override - public boolean canSaturate() { + public boolean canSaturate(PointsToAnalysis bb) { return false; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/StoreFieldTypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/StoreFieldTypeFlow.java index ed4a895517e6..dbd68be19dde 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/StoreFieldTypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/StoreFieldTypeFlow.java @@ -175,6 +175,10 @@ public void onObservedUpdate(PointsToAnalysis bb) { @Override public void onObservedSaturated(PointsToAnalysis bb, TypeFlow observed) { + /* + * Nothing needs to change for open world analysis: we want to link all field flows when + * the receiver saturates. + */ /* * When receiver flow saturates swap in the saturated store type flow. When the store * itself saturates it propagates the saturation state to the uses/observers and unlinks diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java index 41981c8bcee8..28efc11db52b 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/TypeFlow.java @@ -459,7 +459,7 @@ public boolean isSaturated() { * Can this type flow saturate? By default all type flows can saturate, with the exception of a * few ones that need to track all their types, e.g., AllInstantiated, AllSynchronized, etc. */ - public boolean canSaturate() { + public boolean canSaturate(@SuppressWarnings("unused") PointsToAnalysis bb) { return true; } @@ -840,7 +840,7 @@ boolean checkSaturated(PointsToAnalysis bb, TypeState typeState) { /* If the type flow saturation optimization is disabled just return false. */ return false; } - if (!canSaturate()) { + if (!canSaturate(bb)) { /* This type flow needs to track all its individual types. */ return false; } @@ -853,7 +853,7 @@ boolean checkSaturated(PointsToAnalysis bb, TypeState typeState) { /** Called when this type flow becomes saturated. */ protected void onSaturated(PointsToAnalysis bb) { assert bb.analysisPolicy().removeSaturatedTypeFlows() : "The type flow saturation optimization is disabled."; - assert canSaturate() : "This type flow cannot saturate."; + assert canSaturate(bb) : "This type flow cannot saturate."; assert isFlowEnabled() : "A flow cannot saturate before it is enabled."; /* * Array type flow aliasing needs to be enabled for the type flow saturation optimization to @@ -946,14 +946,14 @@ private void markInputSaturated(PointsToAnalysis bb, TypeFlow input) { */ protected void onInputSaturated(PointsToAnalysis bb, @SuppressWarnings("unused") TypeFlow input) { assert bb.analysisPolicy().removeSaturatedTypeFlows() : "The type flow saturation optimization is disabled."; - if (!canSaturate()) { + if (!canSaturate(bb)) { /* This type flow needs to track all its individual types. */ return; } /* - * By default when a type flow is notified that one of its inputs is saturated it will just - * pass this information to its uses and observers and unlink them. Subclases should + * By default, when a type flow is notified that one of its inputs is saturated it will just + * pass this information to its uses and observers and unlink them. Subclasses should * override this method and provide custom behavior. */ onSaturated(bb); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java index 8fa695ec560a..54a42d47a1f2 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java @@ -215,7 +215,8 @@ private static void reportNeverNullInstanceFields(BigBang bb) { int canBeNull = 0; for (var field : bb.getUniverse().getFields()) { if (!field.isStatic() && field.isReachable() && field.getType().getStorageKind() == JavaKind.Object) { - if (field.getSinkFlow().getState().canBeNull()) { + /* If the field flow is saturated we must assume it can be null. */ + if (field.getSinkFlow().isSaturated() || field.getSinkFlow().getState().canBeNull()) { canBeNull++; } else { neverNull++; @@ -416,8 +417,7 @@ public void simplify(Node n, SimplifierTool tool) { if (simplifyDelegate(n, tool)) { // handled elsewhere - } else if (n instanceof ParameterNode && parameterFlows != null) { - ParameterNode node = (ParameterNode) n; + } else if (n instanceof ParameterNode node && parameterFlows != null) { StartNode anchorPoint = graph.start(); Object newStampOrConstant = strengthenStampFromTypeFlow(node, parameterFlows[node.index()], anchorPoint, tool); updateStampUsingPiNode(node, newStampOrConstant, anchorPoint, tool); @@ -883,7 +883,7 @@ private Object strengthenStampFromTypeFlow(ValueNode node, TypeFlow nodeFlow, return null; } if (unreachableValues.contains(node)) { - // This node has already been made unreachable - no further action is needed + /* This node has already been made unreachable - no further action is needed. */ return null; } /* @@ -914,9 +914,8 @@ private Object strengthenStampFromTypeFlow(ValueNode node, TypeFlow nodeFlow, /* * Find all types of the TypeState that are compatible with the current stamp. Since - * stamps are propagated around immediately by the Canonicalizer, and the static - * analysis does not track primitive types at all, it is possible and allowed that the - * stamp is already more precise than the static analysis results. + * stamps are propagated around immediately by the Canonicalizer it is possible and + * allowed that the stamp is already more precise than the static analysis results. */ List typeStateTypes = new ArrayList<>(nodeTypeState.typesCount()); for (AnalysisType typeStateType : nodeTypeState.types(bb)) { From 7c78d22695bc5eab21aeb0246807140a04825eec Mon Sep 17 00:00:00 2001 From: Tom Shull Date: Wed, 23 Oct 2024 17:26:20 +0200 Subject: [PATCH 089/105] Introduce track across layers flag. Used to determine what should be preserved across layers for layered image builds. --- .../com/oracle/graal/pointsto/api/HostVM.java | 4 ++ .../graal/pointsto/heap/ImageLayerWriter.java | 12 ++-- .../graal/pointsto/meta/AnalysisElement.java | 9 ++- .../graal/pointsto/meta/AnalysisField.java | 59 +++++++++++-------- .../graal/pointsto/meta/AnalysisMethod.java | 33 +++++++++-- .../graal/pointsto/meta/AnalysisType.java | 24 +++++++- .../svm/hosted/OpenTypeWorldFeature.java | 14 ++--- .../src/com/oracle/svm/hosted/SVMHost.java | 8 +++ .../svm/hosted/heap/SVMImageLayerWriter.java | 8 ++- .../oracle/svm/hosted/meta/VTableBuilder.java | 12 ++-- 10 files changed, 127 insertions(+), 56 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java index 3f30ff0fefcd..66c9e6479e63 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java @@ -335,6 +335,10 @@ public boolean isClosedTypeWorld() { return true; } + public boolean enableTrackAcrossLayers() { + return false; + } + /** * Helpers to determine what analysis actions should be taken for a given Multi-Method version. */ diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java index 68d939aa2795..cef74b53b90e 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java @@ -272,10 +272,6 @@ public void persistImageHeapSize(long imageHeapSize) { jsonMap.put(IMAGE_HEAP_SIZE_TAG, String.valueOf(imageHeapSize)); } - protected boolean shouldPersistMethod(AnalysisMethod method) { - return method.isReachable(); - } - public void persistAnalysisInfo() { persistHook(); @@ -289,18 +285,18 @@ public void persistAnalysisInfo() { * removed after a mechanism for determining which types have to be persisted is added, or * if a stable name is implemented for them. */ - for (AnalysisType type : aUniverse.getTypes().stream().filter(AnalysisType::isReachable).toList()) { + for (AnalysisType type : aUniverse.getTypes().stream().filter(AnalysisType::isTrackedAcrossLayers).toList()) { checkTypeStability(type); persistType(type); } jsonMap.put(TYPES_TAG, typesMap); - for (AnalysisMethod method : aUniverse.getMethods().stream().filter(this::shouldPersistMethod).toList()) { + for (AnalysisMethod method : aUniverse.getMethods().stream().filter(AnalysisMethod::isTrackedAcrossLayers).toList()) { persistMethod(method); } jsonMap.put(METHODS_TAG, methodsMap); - for (AnalysisField field : aUniverse.getFields().stream().filter(AnalysisField::isReachable).toList()) { + for (AnalysisField field : aUniverse.getFields().stream().filter(AnalysisField::isTrackedAcrossLayers).toList()) { persistField(field); } jsonMap.put(FIELDS_TAG, fieldsMap); @@ -448,7 +444,7 @@ public boolean isMethodPersisted(AnalysisMethod method) { public void persistMethodGraphs() { for (AnalysisMethod method : aUniverse.getMethods()) { - if (method.isReachable()) { + if (method.isTrackedAcrossLayers()) { persistAnalysisParsedGraph(method); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java index eb79dc480a93..f1b0a7fe4cd2 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java @@ -38,7 +38,6 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; -import jdk.graal.compiler.debug.GraalError; import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess; import com.oracle.graal.pointsto.BigBang; @@ -49,6 +48,7 @@ import com.oracle.graal.pointsto.util.AnalysisFuture; import com.oracle.graal.pointsto.util.ConcurrentLightHashSet; +import jdk.graal.compiler.debug.GraalError; import jdk.vm.ci.code.BytecodePosition; import jdk.vm.ci.meta.ModifiersProvider; import jdk.vm.ci.meta.ResolvedJavaField; @@ -112,7 +112,12 @@ protected void notifyReachabilityCallbacks(AnalysisUniverse universe, List isUnsafeAccessedUpdater = AtomicReferenceFieldUpdater .newUpdater(AnalysisField.class, Object.class, "isUnsafeAccessed"); + private static final AtomicReferenceFieldUpdater trackAcrossLayersUpdater = AtomicReferenceFieldUpdater + .newUpdater(AnalysisField.class, Object.class, "trackAcrossLayers"); + private final int id; /** Marks a field loaded from a base layer. */ private final boolean isInBaseLayer; @@ -90,6 +93,12 @@ public abstract class AnalysisField extends AnalysisElement implements WrappedJa @SuppressWarnings("unused") private volatile Object isFolded; @SuppressWarnings("unused") private volatile Object isUnsafeAccessed; + /** + * See {@link AnalysisElement#isTrackedAcrossLayers} for explanation. + */ + @SuppressWarnings("unused") private volatile Object trackAcrossLayers; + private final boolean enableTrackAcrossLayers; + private ConcurrentMap readBy; private ConcurrentMap writtenBy; @@ -150,6 +159,8 @@ public AnalysisField(AnalysisUniverse universe, ResolvedJavaField wrappedField) id = universe.computeNextFieldId(); isInBaseLayer = false; } + + this.enableTrackAcrossLayers = universe.hostVM.enableTrackAcrossLayers(); } @Override @@ -220,13 +231,11 @@ public boolean registerAsAccessed(Object reason) { getDeclaringClass().registerAsReachable(this); assert isValidReason(reason) : "Registering a field as accessed needs to provide a valid reason."; - boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isAccessedUpdater); - if (firstAttempt) { - onReachable(); + return AtomicUtils.atomicSetAndRun(this, reason, isAccessedUpdater, () -> { + onReachable(reason); getUniverse().onFieldAccessed(this); getUniverse().getHeapScanner().onFieldRead(this); - } - return firstAttempt; + }); } /** @@ -236,16 +245,14 @@ public boolean registerAsRead(Object reason) { getDeclaringClass().registerAsReachable(this); assert isValidReason(reason) : "Registering a field as read needs to provide a valid reason."; - boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isReadUpdater); if (readBy != null) { readBy.put(reason, Boolean.TRUE); } - if (firstAttempt) { - onReachable(); + return AtomicUtils.atomicSetAndRun(this, reason, isReadUpdater, () -> { + onReachable(reason); getUniverse().onFieldAccessed(this); getUniverse().getHeapScanner().onFieldRead(this); - } - return firstAttempt; + }); } /** @@ -257,27 +264,25 @@ public boolean registerAsWritten(Object reason) { getDeclaringClass().registerAsReachable(this); assert isValidReason(reason) : "Registering a field as written needs to provide a valid reason."; - boolean firstAttempt = AtomicUtils.atomicSet(this, reason, isWrittenUpdater); - if (writtenBy != null && reason != null) { + if (writtenBy != null) { writtenBy.put(reason, Boolean.TRUE); } - if (firstAttempt) { - onReachable(); + return AtomicUtils.atomicSetAndRun(this, reason, isWrittenUpdater, () -> { + onReachable(reason); if (Modifier.isVolatile(getModifiers()) || getStorageKind() == JavaKind.Object) { getUniverse().onFieldAccessed(this); } - } - return firstAttempt; + }); } public void registerAsFolded(Object reason) { getDeclaringClass().registerAsReachable(this); assert isValidReason(reason) : "Registering a field as folded needs to provide a valid reason."; - if (AtomicUtils.atomicSet(this, reason, isFoldedUpdater)) { + AtomicUtils.atomicSetAndRun(this, reason, isFoldedUpdater, () -> { assert getDeclaringClass().isReachable() : this; - onReachable(); - } + onReachable(reason); + }); } public boolean registerAsUnsafeAccessed(Object reason) { @@ -292,7 +297,7 @@ public boolean registerAsUnsafeAccessed(Object reason) { * only register fields as unsafe accessed with their declaring type once. */ - if (AtomicUtils.atomicSet(this, reason, isUnsafeAccessedUpdater)) { + return AtomicUtils.atomicSetAndRun(this, reason, isUnsafeAccessedUpdater, () -> { /* * The atomic updater ensures that the field is registered as unsafe accessed with its * declaring class only once. However, at the end of this call the registration might @@ -311,9 +316,7 @@ public boolean registerAsUnsafeAccessed(Object reason) { AnalysisType declaringType = getDeclaringClass(); declaringType.registerUnsafeAccessedField(this); } - return true; - } - return false; + }); } public boolean isUnsafeAccessed() { @@ -379,10 +382,18 @@ public boolean isReachable() { } @Override - public void onReachable() { + public void onReachable(Object reason) { + if (enableTrackAcrossLayers) { + AtomicUtils.atomicSet(this, reason, trackAcrossLayersUpdater); + } notifyReachabilityCallbacks(declaringClass.getUniverse(), new ArrayList<>()); } + @Override + public boolean isTrackedAcrossLayers() { + return AtomicUtils.isSet(this, trackAcrossLayersUpdater); + } + public Object getFieldValueInterceptor() { return fieldValueInterceptor; } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java index bc0a65e751f6..dc1b43c5bad2 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java @@ -112,6 +112,9 @@ public abstract class AnalysisMethod extends AnalysisElement implements WrappedJ static final AtomicReferenceFieldUpdater allImplementationsUpdater = AtomicReferenceFieldUpdater .newUpdater(AnalysisMethod.class, Object.class, "allImplementations"); + private static final AtomicReferenceFieldUpdater trackAcrossLayersUpdater = AtomicReferenceFieldUpdater + .newUpdater(AnalysisMethod.class, Object.class, "trackAcrossLayers"); + public record Signature(String name, AnalysisType[] parameterTypes) { } @@ -181,6 +184,12 @@ public record Signature(String name, AnalysisType[] parameterTypes) { */ @SuppressWarnings("unused") private volatile Object allImplementations; + /** + * See {@link AnalysisElement#isTrackedAcrossLayers} for explanation. + */ + @SuppressWarnings("unused") private volatile Object trackAcrossLayers; + private final boolean enableTrackAcrossLayers; + /** * Indicates that this method has opaque return. This is necessary when there are control flows * present which cannot be tracked by analysis, which happens for continuation support. @@ -265,6 +274,8 @@ protected AnalysisMethod(AnalysisUniverse universe, ResolvedJavaMethod wrapped, startTrackInvocations(); } parsingContextMaxDepth = PointstoOptions.ParsingContextMaxDepth.getValue(declaringClass.universe.hostVM.options()); + + this.enableTrackAcrossLayers = universe.hostVM.enableTrackAcrossLayers(); } @SuppressWarnings("this-escape") @@ -292,6 +303,8 @@ protected AnalysisMethod(AnalysisMethod original, MultiMethodKey multiMethodKey) if (PointstoOptions.TrackAccessChain.getValue(declaringClass.universe.hostVM().options())) { startTrackInvocations(); } + + this.enableTrackAcrossLayers = original.enableTrackAcrossLayers; } private static String createName(ResolvedJavaMethod wrapped, MultiMethodKey multiMethodKey) { @@ -464,7 +477,7 @@ public boolean analyzedInPriorLayer() { */ public void registerAsIntrinsicMethod(Object reason) { assert isValidReason(reason) : "Registering a method as intrinsic needs to provide a valid reason, found: " + reason; - AtomicUtils.atomicSetAndRun(this, reason, isIntrinsicMethodUpdater, this::onImplementationInvoked); + AtomicUtils.atomicSetAndRun(this, reason, isIntrinsicMethodUpdater, () -> onImplementationInvoked(reason)); } public void registerAsEntryPoint(Object newEntryPointData) { @@ -495,12 +508,12 @@ public boolean registerAsImplementationInvoked(Object reason) { * return before the class gets marked as reachable. */ getDeclaringClass().registerAsReachable("declared method " + qualifiedName + " is registered as implementation invoked"); - return AtomicUtils.atomicSetAndRun(this, reason, isImplementationInvokedUpdater, this::onImplementationInvoked); + return AtomicUtils.atomicSetAndRun(this, reason, isImplementationInvokedUpdater, () -> onImplementationInvoked(reason)); } public void registerAsInlined(Object reason) { assert reason instanceof NodeSourcePosition || reason instanceof ResolvedJavaMethod : "Registering a method as inlined needs to provide the inline location as reason, found: " + reason; - AtomicUtils.atomicSetAndRun(this, reason, isInlinedUpdater, this::onReachable); + AtomicUtils.atomicSetAndRun(this, reason, isInlinedUpdater, () -> onReachable(reason)); } public void registerImplementationInvokedCallback(Consumer callback) { @@ -636,6 +649,11 @@ public boolean isReachable() { return isImplementationInvoked() || isInlined(); } + @Override + public boolean isTrackedAcrossLayers() { + return AtomicUtils.isSet(this, trackAcrossLayersUpdater); + } + @Override public boolean isTriggered() { if (isReachable()) { @@ -644,13 +662,16 @@ public boolean isTriggered() { return isClassInitializer() && getDeclaringClass().isInitialized(); } - public void onImplementationInvoked() { - onReachable(); + public void onImplementationInvoked(Object reason) { + onReachable(reason); notifyImplementationInvokedCallbacks(); } @Override - public void onReachable() { + public void onReachable(Object reason) { + if (enableTrackAcrossLayers) { + AtomicUtils.atomicSet(this, reason, trackAcrossLayersUpdater); + } notifyReachabilityCallbacks(declaringClass.getUniverse(), new ArrayList<>()); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java index b0b792c0036b..556fb285fd88 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java @@ -108,6 +108,9 @@ public abstract class AnalysisType extends AnalysisElement implements WrappedJav static final AtomicReferenceFieldUpdater overrideableMethodsUpdater = AtomicReferenceFieldUpdater .newUpdater(AnalysisType.class, Object.class, "overrideableMethods"); + private static final AtomicReferenceFieldUpdater trackAcrossLayersUpdater = AtomicReferenceFieldUpdater + .newUpdater(AnalysisType.class, Object.class, "trackAcrossLayers"); + protected final AnalysisUniverse universe; private final ResolvedJavaType wrapped; private final String qualifiedName; @@ -218,6 +221,12 @@ public abstract class AnalysisType extends AnalysisElement implements WrappedJav */ @SuppressWarnings("unused") private volatile Object overrideableMethods; + /** + * See {@link AnalysisElement#isTrackedAcrossLayers} for explanation. + */ + @SuppressWarnings("unused") private volatile Object trackAcrossLayers; + private final boolean enableTrackAcrossLayers; + @SuppressWarnings("this-escape") public AnalysisType(AnalysisUniverse universe, ResolvedJavaType javaType, JavaKind storageKind, AnalysisType objectType, AnalysisType cloneableType) { this.universe = universe; @@ -343,6 +352,8 @@ public AnalysisType(AnalysisUniverse universe, ResolvedJavaType javaType, JavaKi AnalysisError.guarantee(universe.getHeapScanner() != null, "Heap scanner is not available."); return universe.getHeapScanner().computeTypeData(this); }); + + this.enableTrackAcrossLayers = universe.hostVM.enableTrackAcrossLayers(); } private AnalysisType[] convertTypes(ResolvedJavaType[] originalTypes) { @@ -592,14 +603,18 @@ public boolean registerAsReachable(Object reason) { * that the onReachable hook for all supertypes is already finished, because they can * still be running in another thread. */ - AtomicUtils.atomicSetAndRun(this, reason, isReachableUpdater, this::onReachable); + AtomicUtils.atomicSetAndRun(this, reason, isReachableUpdater, () -> onReachable(reason)); return true; } return false; } @Override - protected void onReachable() { + protected void onReachable(Object reason) { + if (enableTrackAcrossLayers) { + AtomicUtils.atomicSet(this, reason, trackAcrossLayersUpdater); + } + List> futures = new ArrayList<>(); notifyReachabilityCallbacks(universe, futures); forAllSuperTypes(type -> ConcurrentLightHashSet.forEach(type, subtypeReachableNotificationsUpdater, @@ -860,6 +875,11 @@ public Object getReachableReason() { return isReachable; } + @Override + public boolean isTrackedAcrossLayers() { + return AtomicUtils.isSet(this, trackAcrossLayersUpdater); + } + /** * The kind of the field in memory (in contrast to {@link #getJavaKind()}, which is the kind of * the field on the Java type system level). For example {@link WordBase word types} have a diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/OpenTypeWorldFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/OpenTypeWorldFeature.java index 3dade2e9dcf8..984c01ba8f05 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/OpenTypeWorldFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/OpenTypeWorldFeature.java @@ -176,15 +176,15 @@ public int loadTypeID(Collection types) { return maxTypeID; } - private static boolean isTypeReachable(HostedType type) { - var result = type.getWrapped().isReachable(); - assert type.getTypeID() != -1 : type; - return result; - } - public void persistTypeInfo(Collection types) { for (HostedType type : types) { - if (isTypeReachable(type)) { + /* + * Currently we are calculating type id information for all types. However, for + * types not tracked across layers, the type ID may not be the same in different + * layers. + */ + assert type.getTypeID() != -1 : type; + if (type.getWrapped().isTrackedAcrossLayers()) { int identifierID = type.getWrapped().getId(); int typeID = type.getTypeID(); int numClassTypes = type.getNumClassTypes(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index 39f61952e6e0..9fd72482d7b9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -200,6 +200,7 @@ public enum UsageKind { private final Boolean optionAllowUnsafeAllocationOfAllInstantiatedTypes = SubstrateOptions.AllowUnsafeAllocationOfAllInstantiatedTypes.getValue(); private final boolean isClosedTypeWorld = SubstrateOptions.useClosedTypeWorld(); + private final boolean enableTrackAcrossLayers; @SuppressWarnings("this-escape") public SVMHost(OptionValues options, ImageClassLoader loader, ClassInitializationSupport classInitializationSupport, AnnotationSubstitutionProcessor annotationSubstitutions, @@ -232,6 +233,8 @@ public SVMHost(OptionValues options, ImageClassLoader loader, ClassInitializatio if (SubstrateOptions.includeAll()) { initializeExcludedFields(); } + + enableTrackAcrossLayers = ImageLayerBuildingSupport.buildingSharedLayer(); } @Override @@ -938,6 +941,11 @@ public boolean isClosedTypeWorld() { return isClosedTypeWorld; } + @Override + public boolean enableTrackAcrossLayers() { + return enableTrackAcrossLayers; + } + private final List> neverInlineTrivialHandlers = new CopyOnWriteArrayList<>(); public void registerNeverInlineTrivialHandler(BiPredicate handler) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java index db8cc6c8bac2..b5da8c77a6d6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java @@ -258,10 +258,12 @@ private static int getRelocatableConstantMethodId(MethodPointer methodPointer) { } private static int getMethodId(AnalysisMethod analysisMethod) { - if (!analysisMethod.isReachable()) { + if (!analysisMethod.isTrackedAcrossLayers()) { /* - * At the moment, only reachable methods are persisted, so the method will not be loaded - * in the extension image. + * Only tracked methods are persisted, so the method will not be loaded in the extension + * image. + * + * GR-59009 will ensure all methods referred to are tracked. */ return -1; } else { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/VTableBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/VTableBuilder.java index 8fa46279ced0..9fbb3ab05491 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/VTableBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/VTableBuilder.java @@ -66,6 +66,10 @@ public static void buildTables(HostedUniverse hUniverse, HostedMetaAccess hMetaA } } + private static boolean shouldIncludeType(HostedType type) { + return type.getWrapped().isReachable() || type.getWrapped().isTrackedAcrossLayers(); + } + private boolean verifyOpenTypeWorldDispatchTables() { HostedMethod invalidVTableEntryHandler = hMetaAccess.lookupJavaMethod(InvalidMethodPointerHandler.INVALID_VTABLE_ENTRY_HANDLER_METHOD); for (HostedType type : hUniverse.getTypes()) { @@ -211,7 +215,7 @@ private void generateOpenTypeWorldDispatchTable(HostedInstanceClass type, Map Date: Thu, 24 Oct 2024 19:00:49 +0000 Subject: [PATCH 090/105] update JVMCI to 24+21-jvmci-b01 --- common.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common.json b/common.json index a8e7ca278c69..7056d6784af3 100644 --- a/common.json +++ b/common.json @@ -45,13 +45,13 @@ "oraclejdk23": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+37", "platformspecific": true, "extrabundles": ["static-libs"]}, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+20", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+20-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+20-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+20-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+20-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+20-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+20-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+21", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+21-jvmci-b01-20241024162317-915c0f22fd", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+21-jvmci-b01-20241024162317-915c0f22fd-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+21-jvmci-b01-20241024162317-915c0f22fd-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+21-jvmci-b01-20241024162317-915c0f22fd+20567b785f", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+21-jvmci-b01-20241024162317-915c0f22fd+20567b785f-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+21-jvmci-b01-20241024162317-915c0f22fd+20567b785f-sulong", "platformspecific": true } }, "eclipse": { From 0056e984f787242d3e71e05628bf6248fd188b44 Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Thu, 24 Oct 2024 11:39:38 +0200 Subject: [PATCH 091/105] Avoid recursive lock method for jdwp suspension and pin objects while in suspended state --- .../oracle/truffle/espresso/jdwp/api/Ids.java | 35 +++++-- .../jdwp/impl/DebuggerController.java | 98 ++++++++----------- .../truffle/espresso/jdwp/impl/JDWP.java | 4 + .../truffle/espresso/jdwp/impl/ThreadJob.java | 26 ++++- 4 files changed, 97 insertions(+), 66 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/Ids.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/Ids.java index 54cc0c352cd4..464b88edf438 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/Ids.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/Ids.java @@ -22,15 +22,17 @@ */ package com.oracle.truffle.espresso.jdwp.api; -import com.oracle.truffle.espresso.jdwp.impl.DebuggerController; - import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.oracle.truffle.espresso.jdwp.impl.DebuggerController; + /** * Class that keeps an ID representation of all entities when communicating with a debugger through * JDWP. Each entity will be assigned a unique ID. Only weak references are kept for entities. @@ -57,6 +59,10 @@ public final class Ids { private DebuggerController controller; + private List pinnedObjects = new ArrayList<>(); + + private volatile boolean pinningState = false; + @SuppressWarnings({"unchecked", "rawtypes"}) public Ids(T nullObject) { this.nullObject = nullObject; @@ -84,8 +90,7 @@ public long getIdAsLong(T object) { } } // check the anonymous inner class map - if (object instanceof KlassRef) { - KlassRef klass = (KlassRef) object; + if (object instanceof KlassRef klass) { Long id = innerClassIDMap.get(klass.getNameAsString()); if (id != null) { // inject new klass under existing ID @@ -155,13 +160,16 @@ private synchronized long generateUniqueId(T object) { expandedArray[objects.length] = new WeakReference<>(object); objects = expandedArray; log(() -> "Generating new ID: " + id + " for object: " + object); - if (object instanceof KlassRef) { - KlassRef klass = (KlassRef) object; + if (object instanceof KlassRef klass) { Matcher matcher = ANON_INNER_CLASS_PATTERN.matcher(klass.getNameAsString()); if (matcher.matches()) { innerClassIDMap.put(klass.getNameAsString(), id); } } + // pin object when VM in suspended state + if (pinningState) { + pinnedObjects.add(object); + } return id; } @@ -203,4 +211,19 @@ private void log(Supplier supplier) { controller.finest(supplier); } } + + public synchronized void pinAll() { + pinningState = true; + for (WeakReference object : objects) { + Object toPin = object.get(); + if (toPin != null) { + pinnedObjects.add(toPin); + } + } + } + + public synchronized void unpinAll() { + pinningState = false; + pinnedObjects.clear(); + } } \ No newline at end of file diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java index b14149b9b1b4..1431ce8a9d05 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java @@ -176,6 +176,10 @@ public JDWPContext getContext() { return context; } + public Ids getIds() { + return ids; + } + public SuspendedInfo getSuspendedInfo(Object thread) { return suspendedInfos.get(thread); } @@ -386,6 +390,7 @@ public Object[] getVisibleGuestThreads() { } void forceResumeAll() { + ids.unpinAll(); for (Object thread : getVisibleGuestThreads()) { boolean resumed = false; SimpleLock suspendLock = getSuspendLock(thread); @@ -398,6 +403,7 @@ void forceResumeAll() { } public void resumeAll() { + ids.unpinAll(); for (Object thread : getVisibleGuestThreads()) { SimpleLock suspendLock = getSuspendLock(thread); synchronized (suspendLock) { @@ -453,6 +459,9 @@ public void immediateSuspend(Object eventThread, byte suspendPolicy, Callable> jobs case SuspendStrategy.ALL: fine(() -> "Suspend ALL"); - Thread suspendThread = new Thread(new Runnable() { - @Override - public void run() { - // suspend other threads - for (Object activeThread : getVisibleGuestThreads()) { - if (activeThread != thread) { - fine(() -> "Request thread suspend for other thread: " + getThreadName(activeThread)); - DebuggerController.this.suspend(activeThread); - } + Thread suspendThread = new Thread(() -> { + // suspend other threads + for (Object activeThread : getVisibleGuestThreads()) { + if (activeThread != thread) { + fine(() -> "Request thread suspend for other thread: " + getThreadName(activeThread)); + DebuggerController.this.suspend(activeThread); } } }); suspendThread.start(); + // pin all objects + ids.pinAll(); suspendEventThread(thread, forceSuspend, jobs); break; } @@ -661,75 +671,54 @@ private static void runJobs(List> jobs) { private void suspendEventThread(Object thread, boolean forceSuspend, List> jobs) { fine(() -> "Suspending event thread: " + getThreadName(thread) + " with new suspension count: " + threadSuspension.getSuspensionCount(thread)); - lockThread(thread, forceSuspend, true, jobs); + lockThread(thread, forceSuspend, jobs); } - private void lockThread(Object thread, boolean forceSuspend, boolean isFirstCall, List> jobs) { + private void lockThread(Object thread, boolean forceSuspend, List> jobs) { SimpleLock lock = getSuspendLock(thread); - // in case a thread job is already posted on this thread - checkThreadJobsAndRun(thread, forceSuspend); synchronized (lock) { if (!forceSuspend && !threadSuspension.isHardSuspended(thread)) { // thread was resumed from other command, so don't suspend now return; } + + if (lock.isLocked()) { + threadSuspension.suspendThread(thread); + runJobs(jobs); + } + } + while (!Thread.currentThread().isInterrupted()) { try { - if (lock.isLocked() && isFirstCall) { - threadSuspension.suspendThread(thread); - runJobs(jobs); - } - while (lock.isLocked()) { - fine(() -> "lock.wait() for thread: " + getThreadName(thread)); + synchronized (lock) { + if (!lock.isLocked()) { + // released from other thread, so break loop + break; + } // no reason to hold a hard suspension status, since now // we have the actual suspension status and suspended information threadSuspension.removeHardSuspendedThread(thread); - lock.wait(); + fine(() -> "lock.wait() for thread: " + getThreadName(thread)); + // Having the thread lock, we can check if a thread job was posted outside of + // locking, and if so, we postpone blocking the thread until next time around. + if (!threadJobs.containsKey(thread)) { + lock.wait(); + } } } catch (InterruptedException e) { // the thread was interrupted, so let it run dry // make sure the interrupted flag is set though Thread.currentThread().interrupt(); } + checkThreadJobsAndRun(thread); } - - checkThreadJobsAndRun(thread, forceSuspend); getGCPrevention().releaseActiveWhileSuspended(thread); fine(() -> "lock wakeup for thread: " + getThreadName(thread)); } - private void checkThreadJobsAndRun(Object thread, boolean forceSuspend) { + private void checkThreadJobsAndRun(Object thread) { if (threadJobs.containsKey(thread)) { - // re-acquire the thread lock after completing - // the job, to avoid the thread resuming. - SimpleLock suspendLock = getSuspendLock(thread); - synchronized (suspendLock) { - suspendLock.acquire(); - } - // a thread job was posted on this thread - // only wake up to perform the job a go back to sleep ThreadJob job = threadJobs.remove(thread); - byte suspensionStrategy = job.getSuspensionStrategy(); - - if (suspensionStrategy == SuspendStrategy.ALL) { - Object[] allThreads = getVisibleGuestThreads(); - // resume all threads during invocation of method to avoid potential deadlocks - for (Object activeThread : allThreads) { - if (activeThread != thread) { - resume(activeThread); - } - } - // perform the job on this thread - job.runJob(); - // suspend all other threads after the invocation - for (Object activeThread : allThreads) { - if (activeThread != thread) { - suspend(activeThread); - } - } - } else { - job.runJob(); - } - lockThread(thread, forceSuspend, false, Collections.emptyList()); + job.runJob(this); } } @@ -737,7 +726,6 @@ public void postJobForThread(ThreadJob job) { SimpleLock lock = getSuspendLock(job.getThread()); synchronized (lock) { threadJobs.put(job.getThread(), job); - lock.release(); lock.notifyAll(); } } diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java index 420c67d0f5b0..de2e3bb761a4 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java @@ -3247,6 +3247,10 @@ private static boolean verifyArrayLength(Object array, int maxIndex, PacketStrea private static Object verifyString(long objectId, PacketStream reply, JDWPContext context) { Object string = context.getIds().fromId((int) objectId); + if (string == null) { + reply.errorCode(ErrorCodes.INVALID_OBJECT); + return null; + } if (!context.isString(string)) { reply.errorCode(ErrorCodes.INVALID_STRING); diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/ThreadJob.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/ThreadJob.java index 7ce260f05ded..9fe7d47f90f8 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/ThreadJob.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/ThreadJob.java @@ -47,17 +47,33 @@ public Object getThread() { return thread; } - public byte getSuspensionStrategy() { - return suspensionStrategy; - } - - public void runJob() { + public void runJob(DebuggerController controller) { + Object[] visibleGuestThreads = controller.getVisibleGuestThreads(); result = new JobResult<>(); try { + if (suspensionStrategy == SuspendStrategy.ALL) { + controller.getIds().unpinAll(); + // resume all other threads during invocation of method to avoid potential deadlocks + for (Object activeThread : visibleGuestThreads) { + if (activeThread != thread) { + controller.resume(activeThread); + } + } + } + // perform the job on this thread result.setResult(callable.call()); } catch (Throwable e) { result.setException(e); } finally { + if (suspensionStrategy == SuspendStrategy.ALL) { + controller.getIds().pinAll(); + // suspend all other threads after the invocation + for (Object activeThread : visibleGuestThreads) { + if (activeThread != thread) { + controller.suspend(activeThread); + } + } + } resultAvailable = true; synchronized (jobLock) { jobLock.notifyAll(); From 46d4aabedd55617e70ec68fffc3c7738c6f647ce Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 25 Oct 2024 08:36:26 +0200 Subject: [PATCH 092/105] compiler: bump JVMCIVersionCheck --- .../src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java index cf6deb77efbb..e6b0e763befd 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/JVMCIVersionCheck.java @@ -55,8 +55,8 @@ public final class JVMCIVersionCheck { private static final Map> JVMCI_MIN_VERSIONS = Map.of( "21", Map.of(DEFAULT_VENDOR_ENTRY, createLegacyVersion(23, 1, 33)), "24", Map.of( - "Oracle Corporation", createLabsJDKVersion("24+20", 1), - DEFAULT_VENDOR_ENTRY, createLabsJDKVersion("24+20", 1))); + "Oracle Corporation", createLabsJDKVersion("24+21", 1), + DEFAULT_VENDOR_ENTRY, createLabsJDKVersion("24+21", 1))); private static final int NA = 0; /** * Minimum Java release supported by Graal. From 3629c998db399699f7ea548c6485ed3da279ee9f Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Fri, 25 Oct 2024 09:04:08 +0200 Subject: [PATCH 093/105] svm: update @BasedOnJDKFile annotations for JDK 24+21 --- .../src/com/oracle/svm/core/amd64/AMD64LibCHelper.java | 2 +- .../src/com/oracle/svm/core/container/ContainerLibrary.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/amd64/AMD64LibCHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/amd64/AMD64LibCHelper.java index 49cf71929a7d..b2bf8a5fd718 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/amd64/AMD64LibCHelper.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/amd64/AMD64LibCHelper.java @@ -43,7 +43,7 @@ * - substratevm/src/com.oracle.svm.native.libchelper/include/amd64hotspotcpuinfo.h * - substratevm/src/com.oracle.svm.native.libchelper/src/cpuid.c */ -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+2/src/hotspot/cpu/x86/vm_version_x86.hpp#L41-L325") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+21/src/hotspot/cpu/x86/vm_version_x86.hpp#L41-L325") @CLibrary(value = "libchelper", requireStatic = true) public class AMD64LibCHelper { @Platforms(Platform.AMD64.class) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java index 4366b898ec63..a02394e67507 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java @@ -60,7 +60,7 @@ @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+19/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/osContainer_linux.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/osContainer_linux.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+20/src/hotspot/os/linux/os_linux.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+21/src/hotspot/os/linux/os_linux.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/os_linux.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/linux/os_linux.inline.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/os/posix/include/jvm_md.h") @@ -71,7 +71,7 @@ @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/memory/allocation.inline.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/memory/allStatic.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/nmt/memTag.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+17/src/hotspot/share/runtime/os.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+21/src/hotspot/share/runtime/os.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+20/src/hotspot/share/runtime/os.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/runtime/os.inline.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+16/src/hotspot/share/utilities/checkedCast.hpp") From c5c5986e865196d383380703255d37c4cb846845 Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Thu, 24 Oct 2024 13:57:27 +0200 Subject: [PATCH 094/105] Do not hardcode prefetch style if SerialGC is enabled --- .../com/oracle/svm/core/SubstrateOptions.java | 20 +++++++++++++++++-- .../snippets/SubstrateAllocationSnippets.java | 5 +---- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 42a553ded691..928168617bc9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -726,8 +726,18 @@ public static boolean hasColorsEnabled(OptionValues values) { @Option(help = "Number of cache lines to load after the object address using prefetch instructions.")// public static final HostedOptionKey AllocateInstancePrefetchLines = new HostedOptionKey<>(1); - @Option(help = "Generated code style for prefetch instructions: for 0 or less no prefetch instructions are generated and for 1 or more prefetch instructions are introduced after each allocation.")// - public static final HostedOptionKey AllocatePrefetchStyle = new HostedOptionKey<>(1); + @Fold + public static int getAllocatePrefetchStyle() { + Integer style = ConcealedOptions.AllocatePrefetchStyle.getValue(); + if (style != null) { + return style; + } + /* + * Prefetches do not lead to measurable performance improvements on SerialGC, so disable + * them by default if SerialGC is selected. + */ + return SubstrateOptions.useSerialGC() ? 0 : 1; + } @Option(help = "Sets the prefetch instruction to prefetch ahead of the allocation pointer. Possible values are from 0 to 3. The actual instructions behind the values depend on the platform.")// public static final HostedOptionKey AllocatePrefetchInstr = new HostedOptionKey<>(0); @@ -1077,6 +1087,12 @@ protected void onValueUpdate(EconomicMap, Object> values, Integer o @Option(help = "Physical memory size (in bytes). By default, the value is queried from the OS/container during VM startup.", type = OptionType.Expert)// public static final RuntimeOptionKey MaxRAM = new RuntimeOptionKey<>(0L, IsolateCreationOnly); + + /** + * Use {@link SubstrateOptions#getAllocatePrefetchStyle()} instead. + */ + @Option(help = "Generated code style for prefetch instructions: for 0 or less no prefetch instructions are generated and for 1 or more prefetch instructions are introduced after each allocation.")// + public static final HostedOptionKey AllocatePrefetchStyle = new HostedOptionKey<>(null); } @Fold diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java index 26e951fe8a37..41b3aa3b2dfc 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java @@ -412,10 +412,7 @@ static LocationIdentity byteArrayIdentity() { @Override protected final int getPrefetchStyle() { - if (SubstrateOptions.useSerialGC()) { - return 0; - } - return SubstrateOptions.AllocatePrefetchStyle.getValue(); + return SubstrateOptions.getAllocatePrefetchStyle(); } @Override From 6199c2976f76b9f23ab60e7f9cc05bee506afd6c Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Tue, 15 Oct 2024 17:53:28 +0200 Subject: [PATCH 095/105] Port Math.tanh intrinsic. --- .../replacements/test/MathTanhTest.java | 49 ++ .../test/StandardMethodSubstitutionsTest.java | 9 + .../compiler/asm/amd64/AMD64Assembler.java | 25 +- .../amd64/AMD64ArithmeticLIRGenerator.java | 6 + .../hotspot/GraalHotSpotVMConfig.java | 1 + .../AMD64HotSpotForeignCallsProvider.java | 2 + .../amd64/AMD64HotSpotLoweringProvider.java | 8 +- .../compiler/hotspot/amd64/AMD64MathStub.java | 7 + .../meta/HotSpotGraphBuilderPlugins.java | 4 +- .../meta/HotSpotHostForeignCallsProvider.java | 4 + .../meta/UnimplementedGraalIntrinsics.java | 58 +- .../replacements/HotSpotHashCodeSnippets.java | 2 +- .../replacements/TypeCheckSnippetUtils.java | 2 +- .../VirtualThreadUpdateJFRSnippets.java | 2 +- .../stubs/LookUpSecondarySupersTableStub.java | 2 +- .../lir/aarch64/AArch64AESDecryptOp.java | 2 +- .../lir/aarch64/AArch64AESEncryptOp.java | 2 +- .../aarch64/AArch64BigIntegerMulAddOp.java | 2 +- .../AArch64BigIntegerMultiplyToLenOp.java | 2 +- .../AArch64BigIntegerSquareToLenOp.java | 2 +- ...Arch64CipherBlockChainingAESDecryptOp.java | 2 +- ...Arch64CipherBlockChainingAESEncryptOp.java | 2 +- .../lir/aarch64/AArch64CountPositivesOp.java | 2 +- .../aarch64/AArch64CounterModeAESCryptOp.java | 2 +- .../aarch64/AArch64GHASHProcessBlocksOp.java | 2 +- .../compiler/lir/aarch64/AArch64MD5Op.java | 4 +- .../compiler/lir/aarch64/AArch64SHA1Op.java | 2 +- .../compiler/lir/aarch64/AArch64SHA256Op.java | 2 +- .../compiler/lir/aarch64/AArch64SHA3Op.java | 2 +- .../compiler/lir/aarch64/AArch64SHA512Op.java | 2 +- .../lir/amd64/AMD64BigIntegerMulAddOp.java | 6 +- .../amd64/AMD64BigIntegerMultiplyToLenOp.java | 4 +- .../amd64/AMD64BigIntegerSquareToLenOp.java | 4 +- .../lir/amd64/AMD64EncodeArrayOp.java | 2 +- .../compiler/lir/amd64/AMD64MathTanhOp.java | 559 ++++++++++++++++++ .../lir/amd64/AMD64RoundFloatToIntegerOp.java | 2 +- .../compiler/lir/amd64/AMD64SHA512Op.java | 4 +- .../lir/amd64/AMD64StringUTF16CompressOp.java | 2 +- .../lir/amd64/AMD64VectorizedMismatchOp.java | 2 +- .../lir/gen/ArithmeticLIRGeneratorTool.java | 5 + .../DefaultJavaLoweringProvider.java | 7 + .../amd64/AMD64GraphBuilderPlugins.java | 5 + .../nodes/UnaryMathIntrinsicNode.java | 7 + .../svm/core/jdk/JavaLangSubstitutions.java | 15 + .../svm/core/snippets/SnippetRuntime.java | 11 +- 45 files changed, 775 insertions(+), 73 deletions(-) create mode 100644 compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/MathTanhTest.java create mode 100644 compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64MathTanhOp.java diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/MathTanhTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/MathTanhTest.java new file mode 100644 index 000000000000..5b46fdfa9609 --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/MathTanhTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.graal.compiler.replacements.test; + +import org.junit.Test; + +import jdk.graal.compiler.jtt.JTTTest; + +public class MathTanhTest extends JTTTest { + + public double tanh(double d) { + return Math.tanh(d); + } + + @Test + public void testTanh() { + for (double d = -3.0d; d <= 3.0D; d += 0.01D) { + test("tanh", d); + } + + double[] inputs = {Math.PI / 2, Math.PI, -1.0D, Double.MAX_VALUE, Double.MIN_VALUE, Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, + Double.longBitsToDouble(0x7fffffffffffffffL), Double.longBitsToDouble(0xffffffffffffffffL)}; + for (double d : inputs) { + test("tanh", d); + } + } +} diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StandardMethodSubstitutionsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StandardMethodSubstitutionsTest.java index d61124e07492..e0df1563fcc0 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StandardMethodSubstitutionsTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/StandardMethodSubstitutionsTest.java @@ -61,12 +61,17 @@ public void testMathSubstitutions() { testGraph("mathTan"); testGraph("mathAll"); + if (getReplacements().hasSubstitution(getResolvedJavaMethod(Math.class, "tanh"), getInitialOptions())) { + testGraph("mathTanh"); + } + test("mathCos", value); test("mathLog", value); test("mathLog10", value); test("mathSin", value); test("mathSqrt", value); test("mathTan", value); + test("mathTanh", value); test("mathAll", value); } @@ -132,6 +137,10 @@ public static double mathTan(double value) { return Math.tan(value); } + public static double mathTanh(double value) { + return Math.tanh(value); + } + public static double mathAll(double value) { return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java index d63c4250cb47..8c0a1f53edd9 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java @@ -784,6 +784,7 @@ public static class SSEOp extends AMD64RMOp { public static final SSEOp MUL = new SSEOp("MUL", P_0F, 0x59, PreferredNDS.DST); public static final SSEOp CVTSS2SD = new SSEOp("CVTSS2SD", P_0F, 0x5A, PreferredNDS.SRC, OpAssertion.SingleAssertion); public static final SSEOp CVTSD2SS = new SSEOp("CVTSD2SS", P_0F, 0x5A, PreferredNDS.SRC, OpAssertion.DoubleAssertion); + public static final SSEOp CVTSD2SI = new SSEOp("CVTSD2SI", 0XF2, P_0F, 0x2D, PreferredNDS.NONE, OpAssertion.FloatToIntAssertion); public static final SSEOp SUB = new SSEOp("SUB", P_0F, 0x5C, PreferredNDS.DST); public static final SSEOp MIN = new SSEOp("MIN", P_0F, 0x5D, PreferredNDS.DST); public static final SSEOp DIV = new SSEOp("DIV", P_0F, 0x5E, PreferredNDS.DST); @@ -3220,6 +3221,10 @@ public final void andpd(Register dst, AMD64Address src) { SSEOp.AND.emit(this, OperandSize.PD, dst, src); } + public final void andnpd(Register dst, Register src) { + SSEOp.ANDN.emit(this, OperandSize.PD, dst, src); + } + public final void bsfq(Register dst, Register src) { prefixq(dst, src); emitByte(0x0F); @@ -3346,6 +3351,10 @@ public final void cvttsd2sil(Register dst, Register src) { SSEOp.CVTTSD2SI.emit(this, OperandSize.DWORD, dst, src); } + public final void cvtsd2siq(Register dst, Register src) { + SSEOp.CVTSD2SI.emit(this, OperandSize.QWORD, dst, src); + } + public final void decl(AMD64Address dst) { DEC.emit(this, OperandSize.DWORD, dst); } @@ -3859,10 +3868,18 @@ public final void movq(Register dst, AMD64Address src, boolean force4BytesDispla } public final void movq(Register dst, Register src) { - assert inRC(CPU, dst) && inRC(CPU, src) : src + " " + dst; - prefixq(dst, src); - emitByte(0x8B); - emitModRM(dst, src); + if (inRC(XMM, dst) && inRC(XMM, src)) { + // Insn: MOVQ xmm1, xmm2 + // Code: F3 0F 7E /r + simdPrefix(dst, Register.None, src, OperandSize.SS, P_0F, false); + emitByte(0x7E); + emitModRM(dst, src); + } else { + assert inRC(CPU, dst) && inRC(CPU, src) : src + " " + dst; + prefixq(dst, src); + emitByte(0x8B); + emitModRM(dst, src); + } } public final void movq(AMD64Address dst, Register src) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java index 5e503283beca..941c4f494aab 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java @@ -141,6 +141,7 @@ import jdk.graal.compiler.lir.amd64.AMD64MathSignumOp; import jdk.graal.compiler.lir.amd64.AMD64MathSinOp; import jdk.graal.compiler.lir.amd64.AMD64MathTanOp; +import jdk.graal.compiler.lir.amd64.AMD64MathTanhOp; import jdk.graal.compiler.lir.amd64.AMD64Move; import jdk.graal.compiler.lir.amd64.AMD64MulDivOp; import jdk.graal.compiler.lir.amd64.AMD64NormalizedUnsignedCompareOp; @@ -1289,6 +1290,11 @@ public Value emitMathTan(Value input) { return new AMD64MathTanOp().emitLIRWrapper(getLIRGen(), input); } + @Override + public Value emitMathTanh(Value input) { + return new AMD64MathTanhOp().emitLIRWrapper(getLIRGen(), input); + } + @Override public Value emitMathExp(Value input) { return new AMD64MathExpOp().emitLIRWrapper(getLIRGen(), input); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java index 54db0081a22f..669bfd77d46d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfig.java @@ -683,6 +683,7 @@ private long getXGCAddressField(String name) { public final long arithmeticSinAddress = getFieldValue("CompilerToVM::Data::dsin", Long.class, "address"); public final long arithmeticCosAddress = getFieldValue("CompilerToVM::Data::dcos", Long.class, "address"); public final long arithmeticTanAddress = getFieldValue("CompilerToVM::Data::dtan", Long.class, "address"); + public final long arithmeticTanhAddress = getFieldValue("CompilerToVM::Data::dtanh", Long.class, "address", 0L, JDK >= 24); public final long arithmeticExpAddress = getFieldValue("CompilerToVM::Data::dexp", Long.class, "address"); public final long arithmeticLogAddress = getFieldValue("CompilerToVM::Data::dlog", Long.class, "address"); public final long arithmeticLog10Address = getFieldValue("CompilerToVM::Data::dlog10", Long.class, "address"); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java index 76899471e6e7..3a1f330e4f42 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java @@ -39,6 +39,7 @@ import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10; import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN; import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN; +import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TANH; import static jdk.vm.ci.amd64.AMD64.rax; import static jdk.vm.ci.amd64.AMD64.rdx; import static jdk.vm.ci.meta.Value.ILLEGAL; @@ -102,6 +103,7 @@ protected void registerMathStubs(GraalHotSpotVMConfig hotSpotVMConfig, HotSpotPr link(new AMD64MathStub(SIN, options, providers, registerStubCall(SIN.foreignCallSignature, LEAF, NO_SIDE_EFFECT, COMPUTES_REGISTERS_KILLED, NO_LOCATIONS))); link(new AMD64MathStub(COS, options, providers, registerStubCall(COS.foreignCallSignature, LEAF, NO_SIDE_EFFECT, COMPUTES_REGISTERS_KILLED, NO_LOCATIONS))); link(new AMD64MathStub(TAN, options, providers, registerStubCall(TAN.foreignCallSignature, LEAF, NO_SIDE_EFFECT, COMPUTES_REGISTERS_KILLED, NO_LOCATIONS))); + link(new AMD64MathStub(TANH, options, providers, registerStubCall(TANH.foreignCallSignature, LEAF, NO_SIDE_EFFECT, COMPUTES_REGISTERS_KILLED, NO_LOCATIONS))); link(new AMD64MathStub(EXP, options, providers, registerStubCall(EXP.foreignCallSignature, LEAF, NO_SIDE_EFFECT, COMPUTES_REGISTERS_KILLED, NO_LOCATIONS))); link(new AMD64MathStub(LOG, options, providers, registerStubCall(LOG.foreignCallSignature, LEAF, NO_SIDE_EFFECT, COMPUTES_REGISTERS_KILLED, NO_LOCATIONS))); link(new AMD64MathStub(LOG10, options, providers, registerStubCall(LOG10.foreignCallSignature, LEAF, NO_SIDE_EFFECT, COMPUTES_REGISTERS_KILLED, NO_LOCATIONS))); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java index eb77c8768f29..71addb932ddb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java @@ -24,13 +24,15 @@ */ package jdk.graal.compiler.hotspot.amd64; +import static jdk.graal.compiler.core.common.GraalOptions.InlineGraalStubs; +import static jdk.graal.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs; + import jdk.graal.compiler.core.amd64.AMD64LoweringProviderMixin; import jdk.graal.compiler.core.common.spi.ForeignCallsProvider; import jdk.graal.compiler.core.common.spi.MetaAccessExtensionProvider; import jdk.graal.compiler.debug.DebugHandlersFactory; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.hotspot.GraalHotSpotVMConfig; -import jdk.graal.compiler.hotspot.HotSpotBackend; import jdk.graal.compiler.hotspot.HotSpotGraalRuntimeProvider; import jdk.graal.compiler.hotspot.meta.DefaultHotSpotLoweringProvider; import jdk.graal.compiler.hotspot.meta.HotSpotProviders; @@ -85,12 +87,12 @@ private void lowerUnaryMath(UnaryMathIntrinsicNode math, LoweringTool tool) { } StructuredGraph graph = math.graph(); ResolvedJavaMethod method = graph.method(); - if (method != null && getReplacements().isSnippet(method)) { + if ((method != null && getReplacements().isSnippet(method)) || InlineGraalStubs.getValue(graph.getOptions())) { // In the context of SnippetStub, i.e., Graal-generated stubs, use the LIR // lowering to emit the stub assembly code instead of the Node lowering. return; } - if (!HotSpotBackend.Options.GraalArithmeticStubs.getValue(graph.getOptions())) { + if (!GraalArithmeticStubs.getValue(graph.getOptions())) { switch (math.getOperation()) { case SIN: case COS: diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64MathStub.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64MathStub.java index d077e98da3eb..b819a30855e5 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64MathStub.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/amd64/AMD64MathStub.java @@ -56,6 +56,8 @@ private static String snippetName(UnaryOperation operation) { return "cos"; case TAN: return "tan"; + case TANH: + return "tanh"; case EXP: return "exp"; case LOG: @@ -99,6 +101,11 @@ private static double tan(double value) { return UnaryMathIntrinsicNode.compute(value, UnaryOperation.TAN); } + @Snippet + private static double tanh(double value) { + return UnaryMathIntrinsicNode.compute(value, UnaryOperation.TANH); + } + @Snippet private static double exp(double value) { return UnaryMathIntrinsicNode.compute(value, UnaryOperation.EXP); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index a1b546c95982..07df1c71f7df 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -722,7 +722,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec } // @formatter:off - @SyncPort(from = "https://github.com/openjdk/jdk/blob/dcac4b0a532f2ca6cb374da7ece331e8266ab351/src/hotspot/share/opto/library_call.cpp#L2918-L2972", + @SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/share/opto/library_call.cpp#L2922-L2976", sha1 = "353e0d45b0f63ac58af86dcab5b19777950da7e2") // @formatter:on private static void inlineNativeNotifyJvmtiFunctions(GraalHotSpotVMConfig config, GraphBuilderContext b, ResolvedJavaMethod targetMethod, ForeignCallDescriptor descriptor, @@ -771,7 +771,7 @@ private static void inlineNativeNotifyJvmtiFunctions(GraalHotSpotVMConfig config } // @formatter:off - @SyncPort(from = "https://github.com/openjdk/jdk/blob/dcac4b0a532f2ca6cb374da7ece331e8266ab351/src/hotspot/share/opto/library_call.cpp#L3752-L3835", + @SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/share/opto/library_call.cpp#L3756-L3839", sha1 = "d65356dbc0235df26aa56b233bcd100462a5dab4") // @formatter:on private static class ContinuationPinningPlugin extends InvocationPlugin { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java index 0cc01b9fa957..068ff4c26e5e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java @@ -96,6 +96,7 @@ import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10; import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN; import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN; +import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TANH; import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall; import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; @@ -700,6 +701,9 @@ protected void registerMathStubs(GraalHotSpotVMConfig hotSpotVMConfig, HotSpotPr registerForeignCall(createDescriptor(LOG.foreignCallSignature, LEAF, NO_SIDE_EFFECT, NO_LOCATIONS), hotSpotVMConfig.arithmeticLogAddress, NativeCall); registerForeignCall(createDescriptor(LOG10.foreignCallSignature, LEAF, NO_SIDE_EFFECT, NO_LOCATIONS), hotSpotVMConfig.arithmeticLog10Address, NativeCall); registerForeignCall(createDescriptor(POW.foreignCallSignature, LEAF, NO_SIDE_EFFECT, NO_LOCATIONS), hotSpotVMConfig.arithmeticPowAddress, NativeCall); + if (hotSpotVMConfig.arithmeticTanhAddress != 0L) { + registerForeignCall(createDescriptor(TANH.foreignCallSignature, LEAF, NO_SIDE_EFFECT, NO_LOCATIONS), hotSpotVMConfig.arithmeticTanhAddress, NativeCall); + } } private void registerSnippetStubs(HotSpotProviders providers, OptionValues options) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java index 3648c655b324..db009653ccb2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java @@ -32,6 +32,7 @@ import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; +import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.code.Architecture; @@ -85,6 +86,32 @@ private static void add(Collection c, String... elements) { public UnimplementedGraalIntrinsics(Architecture arch) { int jdk = Runtime.version().feature(); + + add(toBeInvestigated, // @formatter:off + // JDK-8309130: x86_64 AVX512 intrinsics for Arrays.sort methods (GR-48679) + "java/util/DualPivotQuicksort.partition(Ljava/lang/Class;Ljava/lang/Object;JIIIILjava/util/DualPivotQuicksort$PartitionOperation;)[I", + "java/util/DualPivotQuicksort.sort(Ljava/lang/Class;Ljava/lang/Object;JIILjava/util/DualPivotQuicksort$SortOperation;)V", + // JDK-8223347: Integration of Vector API + "jdk/internal/vm/vector/VectorSupport.compressExpandOp(ILjava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$CompressExpandOperation;)Ljdk/internal/vm/vector/VectorSupport$VectorPayload;", + "jdk/internal/vm/vector/VectorSupport.indexPartiallyInUpperRange(Ljava/lang/Class;Ljava/lang/Class;IJJLjdk/internal/vm/vector/VectorSupport$IndexPartiallyInUpperRangeOperation;)Ljdk/internal/vm/vector/VectorSupport$VectorMask;", + "jdk/internal/vm/vector/VectorSupport.indexVector(Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;ILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$IndexOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;", + jdk == 21 ? "jdk/internal/vm/vector/VectorSupport.loadMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorMask;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorMaskedOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;": + "jdk/internal/vm/vector/VectorSupport.loadMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JZLjdk/internal/vm/vector/VectorSupport$VectorMask;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorMaskedOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;", + "jdk/internal/vm/vector/VectorSupport.loadWithMap(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)Ljdk/internal/vm/vector/VectorSupport$Vector;", + "jdk/internal/vm/vector/VectorSupport.maybeRebox(Ljdk/internal/vm/vector/VectorSupport$VectorPayload;)Ljdk/internal/vm/vector/VectorSupport$VectorPayload;", + jdk == 21 ? "jdk/internal/vm/vector/VectorSupport.storeMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$StoreVectorMaskedOperation;)V": + "jdk/internal/vm/vector/VectorSupport.storeMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JZLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$StoreVectorMaskedOperation;)V", + "jdk/internal/vm/vector/VectorSupport.storeWithMap(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V" + // @formatter:on + ); + + if (jdk >= 24) { + add(toBeInvestigated, // @formatter:off + "jdk/internal/vm/vector/VectorSupport.selectFromOp(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$VectorSelectFromOp;)Ljdk/internal/vm/vector/VectorSupport$Vector;", + "jdk/internal/vm/vector/VectorSupport.selectFromTwoVectorOp(Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$SelectFromTwoVector;)Ljdk/internal/vm/vector/VectorSupport$Vector;" + // @formatter:on + ); + } add(ignore, // These are dead "java/lang/Math.atan2(DD)D", @@ -93,8 +120,6 @@ public UnimplementedGraalIntrinsics(Architecture arch) { // beneficial. "java/lang/Math.max(II)I", "java/lang/Math.min(II)I", - // Newly added by JDK-8338694 - "java/lang/Math.tanh(D)D", // see Math.min/max "java/lang/StrictMath.max(II)I", "java/lang/StrictMath.min(II)I", @@ -132,31 +157,12 @@ public UnimplementedGraalIntrinsics(Architecture arch) { // handled by an intrinsic for StringUTF16.indexOfCharUnsafe add(ignore, "java/lang/StringUTF16.indexOfChar([BIII)I"); } - - add(toBeInvestigated, // @formatter:off - // JDK-8309130: x86_64 AVX512 intrinsics for Arrays.sort methods (GR-48679) - "java/util/DualPivotQuicksort.partition(Ljava/lang/Class;Ljava/lang/Object;JIIIILjava/util/DualPivotQuicksort$PartitionOperation;)[I", - "java/util/DualPivotQuicksort.sort(Ljava/lang/Class;Ljava/lang/Object;JIILjava/util/DualPivotQuicksort$SortOperation;)V", - // JDK-8223347: Integration of Vector API - "jdk/internal/vm/vector/VectorSupport.compressExpandOp(ILjava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$CompressExpandOperation;)Ljdk/internal/vm/vector/VectorSupport$VectorPayload;", - "jdk/internal/vm/vector/VectorSupport.indexPartiallyInUpperRange(Ljava/lang/Class;Ljava/lang/Class;IJJLjdk/internal/vm/vector/VectorSupport$IndexPartiallyInUpperRangeOperation;)Ljdk/internal/vm/vector/VectorSupport$VectorMask;", - "jdk/internal/vm/vector/VectorSupport.indexVector(Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;ILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$IndexOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;", - jdk == 21 ? "jdk/internal/vm/vector/VectorSupport.loadMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorMask;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorMaskedOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;": - "jdk/internal/vm/vector/VectorSupport.loadMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JZLjdk/internal/vm/vector/VectorSupport$VectorMask;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorMaskedOperation;)Ljdk/internal/vm/vector/VectorSupport$Vector;", - "jdk/internal/vm/vector/VectorSupport.loadWithMap(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)Ljdk/internal/vm/vector/VectorSupport$Vector;", - "jdk/internal/vm/vector/VectorSupport.maybeRebox(Ljdk/internal/vm/vector/VectorSupport$VectorPayload;)Ljdk/internal/vm/vector/VectorSupport$VectorPayload;", - jdk == 21 ? "jdk/internal/vm/vector/VectorSupport.storeMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$StoreVectorMaskedOperation;)V": - "jdk/internal/vm/vector/VectorSupport.storeMasked(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Object;JZLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$StoreVectorMaskedOperation;)V", - "jdk/internal/vm/vector/VectorSupport.storeWithMap(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V" - // @formatter:on - ); - if (jdk >= 24) { - add(toBeInvestigated, // @formatter:off - "jdk/internal/vm/vector/VectorSupport.selectFromOp(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljdk/internal/vm/vector/VectorSupport$VectorSelectFromOp;)Ljdk/internal/vm/vector/VectorSupport$Vector;", - "jdk/internal/vm/vector/VectorSupport.selectFromTwoVectorOp(Ljava/lang/Class;Ljava/lang/Class;ILjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$SelectFromTwoVector;)Ljdk/internal/vm/vector/VectorSupport$Vector;" - // @formatter:on - ); + // Newly added by JDK-8338694. HotSpot runtime does not implement + // C2Compiler::is_intrinsic_supported for this intrinsic properly + if (arch instanceof AArch64) { + add(ignore, "java/lang/Math.tanh(D)D"); + } } // These are known to be implemented down stream diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java index 86a15a2136bc..7413f5fbf6ad 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/HotSpotHashCodeSnippets.java @@ -46,7 +46,7 @@ import jdk.graal.compiler.word.Word; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/dcac4b0a532f2ca6cb374da7ece331e8266ab351/src/hotspot/share/opto/library_call.cpp#L4671-L4805", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/share/opto/library_call.cpp#L4675-L4809", sha1 = "c212d1dbff26d02d4d749e085263d4104895f1ba") // @formatter:on public class HotSpotHashCodeSnippets extends IdentityHashCodeSnippets { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/TypeCheckSnippetUtils.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/TypeCheckSnippetUtils.java index eab2d9e8d694..92fbb0970acf 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/TypeCheckSnippetUtils.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/TypeCheckSnippetUtils.java @@ -97,7 +97,7 @@ static boolean checkUnknownSubType(KlassPointer t, KlassPointer sNonNull, Counte } // @formatter:off - @SyncPort(from = "https://github.com/openjdk/jdk/blob/fbe8a81d1900d0de1920ad1df6ad574f3da4bd51/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L4791-L4886", + @SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L4802-L4897", sha1 = "c0e2fdd973dc975757d58080ba94efe628d6a380") // @formatter:on static boolean checkSelfAndSupers(KlassPointer t, KlassPointer s, Counters counters) { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java index 0b3a8222c58c..536e565019bb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replacements/VirtualThreadUpdateJFRSnippets.java @@ -64,7 +64,7 @@ * Snippet for updating JFR thread local data on {@code Thread#setCurrentThread} events. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/dcac4b0a532f2ca6cb374da7ece331e8266ab351/src/hotspot/share/opto/library_call.cpp#L3546-L3672", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/share/opto/library_call.cpp#L3550-L3676", sha1 = "564050736d9601fe43c16d9c393706b4e67f05d2") // @formatter:on public class VirtualThreadUpdateJFRSnippets implements Snippets { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/LookUpSecondarySupersTableStub.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/LookUpSecondarySupersTableStub.java index 58a04ecddf14..8d949f9d2ea0 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/LookUpSecondarySupersTableStub.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/LookUpSecondarySupersTableStub.java @@ -64,7 +64,7 @@ public LookUpSecondarySupersTableStub(OptionValues options, HotSpotProviders pro } // @formatter:off - @SyncPort(from = "https://github.com/openjdk/jdk/blob/03204600c596214895ef86581eba9722f76d39b3/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L4888-L4996", + @SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L4899-L5007", sha1 = "64e666a1061a5188d6e9df14803aaa5e37be0b7b") // @formatter:on @Snippet diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESDecryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESDecryptOp.java index 7408ba41fc90..6202fe2c81da 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESDecryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESDecryptOp.java @@ -56,7 +56,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/8032d640c0d34fe507392a1d4faa4ff2005c771d/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2716-L2747", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2724-L2755", sha1 = "69b7e01dbc601afd660d5dcef88917a43613e00c") @SyncPort(from = "https://github.com/openjdk/jdk/blob/12358e6c94bc96e618efc3ec5299a2cfe1b4669d/src/hotspot/cpu/aarch64/macroAssembler_aarch64_aes.cpp#L34-L110", sha1 = "4916141cba98c26e4d98edb457161f88a8c66ffa") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESEncryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESEncryptOp.java index e964631bf557..789fd1f447c3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESEncryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64AESEncryptOp.java @@ -66,7 +66,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/8032d640c0d34fe507392a1d4faa4ff2005c771d/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2684-L2714", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2692-L2722", sha1 = "e1333c6ab2d693fa9231a7365c568d81db63fae7") @SyncPort(from = "https://github.com/openjdk/jdk/blob/12358e6c94bc96e618efc3ec5299a2cfe1b4669d/src/hotspot/cpu/aarch64/macroAssembler_aarch64_aes.cpp#L112-L283", sha1 = "41ef4f49f68c0e08ff4d698c8cc962e392cc16ec") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMulAddOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMulAddOp.java index 92d16bfc26ad..966c1538c740 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMulAddOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMulAddOp.java @@ -48,7 +48,7 @@ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/43a2f17342af8f5bf1f5823df9fa0bf0bdfdfce2/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4714-L4733", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4722-L4741", sha1 = "57f40186d75104a5e607d6fc047bbd50ef246590") @SyncPort(from = "https://github.com/openjdk/jdk/blob/59ac7039d3ace0ec481742c3a10c81f1675e12da/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp#L4033-L4069", sha1 = "33649be9177daf5f0b4817d807458a5ff8c00365") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMultiplyToLenOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMultiplyToLenOp.java index 8f7a0d15c2e1..8355fee96ada 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMultiplyToLenOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerMultiplyToLenOp.java @@ -57,7 +57,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/43a2f17342af8f5bf1f5823df9fa0bf0bdfdfce2/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4639-L4676", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4647-L4684", sha1 = "b25c503126c37eeb5224202eae09833032d9d8db") @SyncPort(from = "https://github.com/openjdk/jdk/blob/59ac7039d3ace0ec481742c3a10c81f1675e12da/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp#L3524-L3533", sha1 = "376de6fbb2caccaac53c4aa934ce96f8f0dc7f18") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerSquareToLenOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerSquareToLenOp.java index a94a655f320f..9efe4b3771e7 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerSquareToLenOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64BigIntegerSquareToLenOp.java @@ -53,7 +53,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/43a2f17342af8f5bf1f5823df9fa0bf0bdfdfce2/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4678-L4712", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4686-L4720", sha1 = "085aa7785bb62e3e2c880b94963d52a631bb76cf") // @formatter:on public final class AArch64BigIntegerSquareToLenOp extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESDecryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESDecryptOp.java index 5b0f83db8568..61ba34499ffc 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESDecryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESDecryptOp.java @@ -67,7 +67,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/8032d640c0d34fe507392a1d4faa4ff2005c771d/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2853-L2959", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2861-L2967", sha1 = "59698d0ec90b5f69709188321f8b5df625e1a027") // @formatter:on public final class AArch64CipherBlockChainingAESDecryptOp extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESEncryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESEncryptOp.java index 58f2ed4d1db4..8b41c34af415 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESEncryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CipherBlockChainingAESEncryptOp.java @@ -66,7 +66,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/8032d640c0d34fe507392a1d4faa4ff2005c771d/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2749-L2851", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2757-L2859", sha1 = "b64bab8291f14f42af2e45fcb499d20631195072") // @formatter:on public final class AArch64CipherBlockChainingAESEncryptOp extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CountPositivesOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CountPositivesOp.java index 8877e208ef4d..adcd58c4de9a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CountPositivesOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CountPositivesOp.java @@ -71,7 +71,7 @@ // @formatter:off @SyncPort(from = "https://github.com/openjdk/jdk/blob/dcac4b0a532f2ca6cb374da7ece331e8266ab351/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp#L5484-L5553", sha1 = "ce54a7cf2fcfe7ccb8f6604c038887fc1c4ebce1") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/43a2f17342af8f5bf1f5823df9fa0bf0bdfdfce2/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4967-L5133", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L4975-L5141", sha1 = "3b4e6edb4372e8babb009763c2d05961348dd723") // @formatter:on @Opcode("AARCH64_COUNT_POSITIVES") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CounterModeAESCryptOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CounterModeAESCryptOp.java index 036cba8c202a..e9a6e25afc78 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CounterModeAESCryptOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64CounterModeAESCryptOp.java @@ -74,7 +74,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/8032d640c0d34fe507392a1d4faa4ff2005c771d/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2961-L3241", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L2969-L3249", sha1 = "75a3a4dabdc42e5e23bbec0cb448d09fb0d7b129") // @formatter:on public final class AArch64CounterModeAESCryptOp extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64GHASHProcessBlocksOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64GHASHProcessBlocksOp.java index 4fa4d30d8627..3859139328e6 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64GHASHProcessBlocksOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64GHASHProcessBlocksOp.java @@ -65,7 +65,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/43a2f17342af8f5bf1f5823df9fa0bf0bdfdfce2/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L6177-L6311", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L6185-L6319", sha1 = "84b96e679b2ff5dc836da5c28fbbc779b5320a2b") @SyncPort(from = "https://github.com/openjdk/jdk/blob/12358e6c94bc96e618efc3ec5299a2cfe1b4669d/src/hotspot/cpu/aarch64/macroAssembler_aarch64_aes.cpp#L285-L691", sha1 = "1cd41d8f202ebe127aa31053ab3c6851f3900034") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64MD5Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64MD5Op.java index e487317ce9f4..20ae6caa03a3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64MD5Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64MD5Op.java @@ -63,8 +63,8 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/1cf26a5179e619f17909426fdb26a3fb3b748483/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3371-L3605", - sha1 = "c2068cb8bd0d89f8cbfe2dded139137b7e9a9099") +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3377-L3611", + sha1 = "bfad27e36c2940a087613608054bac43345a57e7") // @formatter:on public final class AArch64MD5Op extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA1Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA1Op.java index 0a8290eac325..61857ff4edff 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA1Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA1Op.java @@ -66,7 +66,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/8032d640c0d34fe507392a1d4faa4ff2005c771d/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3605-L3694", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3613-L3702", sha1 = "64b4f4aa44a5201f87d28ee048721dcd3c3231ed") // @formatter:on public final class AArch64SHA1Op extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA256Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA256Op.java index e5340deba718..c6479462861d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA256Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA256Op.java @@ -76,7 +76,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/8032d640c0d34fe507392a1d4faa4ff2005c771d/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3697-L3809", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3705-L3817", sha1 = "f226b109da456148c11f83d1bcd78d14aac862cf") // @formatter:on public final class AArch64SHA256Op extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA3Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA3Op.java index cc6f33a03090..f9a46d414c1e 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA3Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA3Op.java @@ -87,7 +87,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/8032d640c0d34fe507392a1d4faa4ff2005c771d/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3986-L4208", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3994-L4216", sha1 = "c17848fadbacb526e5da3c4e7c2a300c8160e092") // @formatter:on public final class AArch64SHA3Op extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA512Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA512Op.java index 261456a20751..2a14f114ecf8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA512Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64SHA512Op.java @@ -81,7 +81,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/8032d640c0d34fe507392a1d4faa4ff2005c771d/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3811-L3984", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp#L3819-L3992", sha1 = "9a27893e95da304e616ebd2105529e39d9634483") // @formatter:on public final class AArch64SHA512Op extends AArch64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java index e3f7e8d8b959..6af81b18eb95 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMulAddOp.java @@ -57,11 +57,11 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/7fa2f229fbee68112cbdd18b811d95721adfe2ec/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3266-L3318", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3268-L3320", sha1 = "2f3b577fa7f0ced9cc2514af80d2c2833ab7caf2") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/59ac7039d3ace0ec481742c3a10c81f1675e12da/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7437-L7471", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7448-L7482", sha1 = "e68b8c7bdb37d4bd1350c7e1219fdcb419d2618a") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/59ac7039d3ace0ec481742c3a10c81f1675e12da/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7689-L7866", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7700-L7877", sha1 = "d89ad721deb560178359f86e8c6c96ffc6530878") // @formatter:on public final class AMD64BigIntegerMulAddOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java index 07214b7a24ec..9190282fa04f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerMultiplyToLenOp.java @@ -56,9 +56,9 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/7fa2f229fbee68112cbdd18b811d95721adfe2ec/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3035-L3090", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3037-L3092", sha1 = "2bf2eb0a9feca080f99e6932d3750cdf3ce2ef3a") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/59ac7039d3ace0ec481742c3a10c81f1675e12da/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6693-L7150", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6704-L7161", sha1 = "0763af542cf9f40a1c542e4834a67fc4b2c74e1c") // @formatter:on public final class AMD64BigIntegerMultiplyToLenOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java index 747d1f7a2937..6d002dfea444 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64BigIntegerSquareToLenOp.java @@ -55,9 +55,9 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/7fa2f229fbee68112cbdd18b811d95721adfe2ec/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3144-L3188", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L3146-L3190", sha1 = "ab70559cefe0dc177a290d417047955fba3ad1fc") -@SyncPort(from = "https://github.com/openjdk/jdk/blob/59ac7039d3ace0ec481742c3a10c81f1675e12da/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7374-L7687", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7385-L7698", sha1 = "2e4ea1436904cbd5a933eb8c687296d9bbefe4f0") // @formatter:on public final class AMD64BigIntegerSquareToLenOp extends AMD64LIRInstruction { diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java index cd2568a908f7..d4eaaa11c65f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64EncodeArrayOp.java @@ -54,7 +54,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/59ac7039d3ace0ec481742c3a10c81f1675e12da/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6532-L6690", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L6543-L6701", sha1 = "90e15d79705bc87ffbefbcaa4bdfa55123c12aba") // @formatter:on @Opcode("AMD64_ENCODE_ARRAY") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64MathTanhOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64MathTanhOp.java new file mode 100644 index 000000000000..20e008050983 --- /dev/null +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64MathTanhOp.java @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.graal.compiler.lir.amd64; + +import static jdk.graal.compiler.lir.amd64.AMD64LIRHelper.pointerConstant; +import static jdk.graal.compiler.lir.amd64.AMD64LIRHelper.recordExternalAddress; +import static jdk.vm.ci.amd64.AMD64.r8; +import static jdk.vm.ci.amd64.AMD64.rax; +import static jdk.vm.ci.amd64.AMD64.rcx; +import static jdk.vm.ci.amd64.AMD64.rdx; +import static jdk.vm.ci.amd64.AMD64.xmm0; +import static jdk.vm.ci.amd64.AMD64.xmm1; +import static jdk.vm.ci.amd64.AMD64.xmm2; +import static jdk.vm.ci.amd64.AMD64.xmm3; +import static jdk.vm.ci.amd64.AMD64.xmm4; +import static jdk.vm.ci.amd64.AMD64.xmm5; +import static jdk.vm.ci.amd64.AMD64.xmm6; +import static jdk.vm.ci.amd64.AMD64.xmm7; + +import jdk.graal.compiler.asm.Label; +import jdk.graal.compiler.asm.amd64.AMD64Address; +import jdk.graal.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import jdk.graal.compiler.asm.amd64.AMD64MacroAssembler; +import jdk.graal.compiler.core.common.Stride; +import jdk.graal.compiler.lir.LIRInstructionClass; +import jdk.graal.compiler.lir.SyncPort; +import jdk.graal.compiler.lir.asm.ArrayDataPointerConstant; +import jdk.graal.compiler.lir.asm.CompilationResultBuilder; + +// ALGORITHM DESCRIPTION +// --------------------- +// +// tanh(x)=(exp(x)-exp(-x))/(exp(x)+exp(-x))=(1-exp(-2*x))/(1+exp(-2*x)) +// +// Let |x|=xH+xL (upper 26 bits, lower 27 bits) +// log2(e) rounded to 26 bits (high part) plus a double precision low part is +// L2EH+L2EL (upper 26, lower 53 bits) +// +// Let xH*L2EH=k+f+r`, where (k+f)*2^8*2=int(xH*L2EH*2^9), +// f=0.b1 b2 ... b8, k integer +// 2^{-f} is approximated as Tn[f]+Dn[f] +// Tn stores the high 53 bits, Dn stores (2^{-f}-Tn[f]) rounded to double precision +// +// r=r`+xL*L2EH+|x|*L2EL, |r|<2^{-9}+2^{-14}, +// for |x| in [23/64,3*2^7) +// e^{-2*|x|}=2^{-k-f}*2^{-r} ~ 2^{-k}*(Tn+Dn)*(1+p)=(T0+D0)*(1+p) +// +// For |x| in [2^{-4},2^5): +// 2^{-r}-1 ~ p=c1*r+c2*r^2+..+c5*r^5 +// Let R=1/(1+T0+p*T0), truncated to 35 significant bits +// R=1/(1+T0+D0+p*(T0+D0))*(1+eps), |eps|<2^{-33} +// 1+T0+D0+p*(T0+D0)=KH+KL, where +// KH=(1+T0+c1*r*T0)_high (leading 17 bits) +// KL=T0_low+D0+(c1*r*T0)_low+c1*r*D0+(c2*r^2+..c5*r^5)*T0 +// eps ~ (R*KH-1)+R*KL +// 1/(1+T0+D0+p*(T0+D0)) ~ R-R*eps +// The result is approximated as (1-T0-D0-(T0+D0)*p)*(R-R*eps) +// 1-T0-D0-(T0+D0)*p=-((KH-2)+KL) +// The result is formed as +// (KH-2)*R+(-(KH-2)*R*eps+(KL*R-KL*R*eps)), with the correct sign +// set at the end +// +// For |x| in [2^{-64},2^{-4}): +// A Taylor series expansion is used (x+p3*x^3+..+p13*x^{13}) +// +// For |x|<2^{-64}: x is returned +// +// For |x|>=2^32: return +/-1 +// +// Special cases: +// tanh(NaN) = quiet NaN, and raise invalid exception +// tanh(INF) = that INF +// tanh(+/-0) = +/-0 +// +// @formatter:off +@SyncPort(from = "https://github.com/openjdk/jdk/blob/212e32931cafe446d94219d6c3ffd92261984dff/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp#L31-L500", + sha1 = "b2eb58437ef628ce35348a90c3300b4c1e06341a") +// @formatter:on +public final class AMD64MathTanhOp extends AMD64MathIntrinsicUnaryOp { + + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64MathTanhOp.class); + + public AMD64MathTanhOp() { + super(TYPE, /* GPR */ r8, rax, rcx, rdx, + /* XMM */ xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7); + } + + private static ArrayDataPointerConstant halfMask = pointerConstant(16, new int[]{ + // @formatter:off + 0xF8000000, 0x7FFFFFFF + // @formatter:on + }); + + private static ArrayDataPointerConstant oneMask = pointerConstant(16, new int[]{ + // @formatter:off + 0x00000000, 0x3FF00000 + // @formatter:on + }); + + private static ArrayDataPointerConstant twoMask = pointerConstant(16, new int[]{ + // @formatter:off + 0x00000000, 0x40000000 + // @formatter:on + }); + + private static ArrayDataPointerConstant threeMask = pointerConstant(16, new int[]{ + // @formatter:off + 0x00000000, 0xFFFFFFF0, 0x00000000, 0xFFFFFFF0 + // @formatter:on + }); + + private static ArrayDataPointerConstant rMask = pointerConstant(16, new int[]{ + // @formatter:off + 0xFFFC0000, 0xFFFFFFFF, 0xFFFC0000, 0xFFFFFFFF + // @formatter:on + }); + + private static ArrayDataPointerConstant l2e = pointerConstant(16, new int[]{ + // @formatter:off + 0x60000000, 0x40871547 + // @formatter:on + }); + + private static ArrayDataPointerConstant l2eOff8 = pointerConstant(16, new int[]{ + // @formatter:off + 0xF85DDF44, 0x3EE4AE0B + // @formatter:on + }); + + private static ArrayDataPointerConstant shifter = pointerConstant(16, new int[]{ + // @formatter:off + 0x00000000, 0x43380000, 0x00000000, 0xC3380000 + // @formatter:on + }); + + private static ArrayDataPointerConstant cv = pointerConstant(16, new int[]{ + // @formatter:off + 0xe78a6731, 0xbcd5d87f, 0xd704a0bf, 0xbe2c6b08 + // @formatter:on + }); + + private static ArrayDataPointerConstant cvOff16 = pointerConstant(16, new int[]{ + // @formatter:off + 0x6fba4e77, 0x3d83b2ab, 0xff82c58e, 0x3ecebfbd + // @formatter:on + }); + + private static ArrayDataPointerConstant cvOff32 = pointerConstant(16, new int[]{ + // @formatter:off + 0xfefa39ef, 0xbf662e42, 0x00000000, 0x00000000, + // @formatter:on + }); + + private static ArrayDataPointerConstant pv = pointerConstant(16, new int[]{ + // @formatter:off + 0x0e157ddf, 0x3f6d6d3d, 0x1ba1ba1c, 0xbfaba1ba + // @formatter:on + }); + + private static ArrayDataPointerConstant pvOff16 = pointerConstant(16, new int[]{ + // @formatter:off + 0x55e6c23d, 0xbf8226e3, 0x11111111, 0x3fc11111 + // @formatter:on + }); + + private static ArrayDataPointerConstant pvOff32 = pointerConstant(16, new int[]{ + // @formatter:off + 0x882c10fa, 0x3f9664f4, 0x55555555, 0xbfd55555, + // @formatter:on + }); + + private static ArrayDataPointerConstant t2NegF = pointerConstant(16, new int[]{ + // @formatter:off + 0x00000000, 0x3ff00000, 0x00000000, 0x00000000, 0x6b2a23d9, 0x3fefe9d9, + 0x7442fde3, 0x3c64a603, 0x2b8f71f1, 0x3fefd3c2, 0x966579e7, 0x3c52eb74, + 0x3692d514, 0x3fefbdba, 0x15098eb6, 0xbc696773, 0x819e90d8, 0x3fefa7c1, + 0xf3a5931e, 0x3c774853, 0x02243c89, 0x3fef91d8, 0xa779f689, 0xbc512ea8, + 0xad9cbe14, 0x3fef7bfd, 0xd006350a, 0xbc8dbb12, 0x798844f8, 0x3fef6632, + 0x3539343e, 0x3c8fa37b, 0x5b6e4540, 0x3fef5076, 0x2dd8a18b, 0x3c89d3e1, + 0x48dd7274, 0x3fef3ac9, 0x3ed837de, 0xbc695a5a, 0x376bba97, 0x3fef252b, + 0xbf0d8e43, 0x3c83a1a5, 0x1cb6412a, 0x3fef0f9c, 0x65181d45, 0xbc832200, + 0xee615a27, 0x3feefa1b, 0x86a4b6b0, 0x3c8dc7f4, 0xa2188510, 0x3feee4aa, + 0xa487568d, 0x3c81c68d, 0x2d8e67f1, 0x3feecf48, 0xb411ad8c, 0xbc8c93f3, + 0x867cca6e, 0x3feeb9f4, 0x2293e4f2, 0x3c84832f, 0xa2a490da, 0x3feea4af, + 0x179c2893, 0xbc8e9c23, 0x77cdb740, 0x3fee8f79, 0x80b054b1, 0xbc810894, + 0xfbc74c83, 0x3fee7a51, 0xca0c8de2, 0x3c82d522, 0x24676d76, 0x3fee6539, + 0x7522b735, 0xbc763ff8, 0xe78b3ff6, 0x3fee502e, 0x80a9cc8f, 0x3c739e89, + 0x3b16ee12, 0x3fee3b33, 0x31fdc68b, 0xbc89f4a4, 0x14f5a129, 0x3fee2646, + 0x817a1496, 0xbc87b627, 0x6b197d17, 0x3fee1167, 0xbd5c7f44, 0xbc62b529, + 0x337b9b5f, 0x3fedfc97, 0x4f184b5c, 0xbc81a5cd, 0x641c0658, 0x3fede7d5, + 0x8e79ba8f, 0xbc8ca552, 0xf301b460, 0x3fedd321, 0x78f018c3, 0x3c82da57, + 0xd63a8315, 0x3fedbe7c, 0x926b8be4, 0xbc8b76f1, 0x03db3285, 0x3feda9e6, + 0x696db532, 0x3c8c2300, 0x71ff6075, 0x3fed955d, 0xbb9af6be, 0x3c8a052d, + 0x16c98398, 0x3fed80e3, 0x8beddfe8, 0xbc811ec1, 0xe862e6d3, 0x3fed6c76, + 0x4a8165a0, 0x3c4fe87a, 0xdcfba487, 0x3fed5818, 0xd75b3707, 0x3c72ed02, + 0xeacaa1d6, 0x3fed43c8, 0xbf5a1614, 0x3c83db53, 0x080d89f2, 0x3fed2f87, + 0x719d8578, 0xbc8d487b, 0x2b08c968, 0x3fed1b53, 0x219a36ee, 0x3c855636, + 0x4a07897c, 0x3fed072d, 0x43797a9c, 0xbc8cbc37, 0x5b5bab74, 0x3fecf315, + 0xb86dff57, 0xbc8a08e9, 0x555dc3fa, 0x3fecdf0b, 0x53829d72, 0xbc7dd83b, + 0x2e6d1675, 0x3feccb0f, 0x86009093, 0xbc6d220f, 0xdcef9069, 0x3fecb720, + 0xd1e949dc, 0x3c6503cb, 0x5751c4db, 0x3feca340, 0xd10d08f5, 0xbc77f2be, + 0x9406e7b5, 0x3fec8f6d, 0x48805c44, 0x3c61acbc, 0x8988c933, 0x3fec7ba8, + 0xbe255559, 0xbc7e76bb, 0x2e57d14b, 0x3fec67f1, 0xff483cad, 0x3c82884d, + 0x78fafb22, 0x3fec5447, 0x2493b5af, 0x3c812f07, 0x5fffd07a, 0x3fec40ab, + 0xe083c60a, 0x3c8b4537, 0xd9fa652c, 0x3fec2d1c, 0x17c8a5d7, 0xbc86e516, + 0xdd85529c, 0x3fec199b, 0x895048dd, 0x3c711065, 0x6141b33d, 0x3fec0628, + 0xa1fbca34, 0xbc7d8a5a, 0x5bd71e09, 0x3febf2c2, 0x3f6b9c73, 0xbc8efdca, + 0xc3f3a207, 0x3febdf69, 0x60ea5b53, 0xbc2c2623, 0x904bc1d2, 0x3febcc1e, + 0x7a2d9e84, 0x3c723dd0, 0xb79a6f1f, 0x3febb8e0, 0xc9696204, 0xbc2f52d1, + 0x30a1064a, 0x3feba5b0, 0x0e54292e, 0xbc8efcd3, 0xf22749e4, 0x3feb928c, + 0x54cb65c6, 0xbc8b7216, 0xf2fb5e47, 0x3feb7f76, 0x7e54ac3b, 0xbc65584f, + 0x29f1c52a, 0x3feb6c6e, 0x52883f6e, 0x3c82a8f3, 0x8de5593a, 0x3feb5972, + 0xbbba6de3, 0xbc8c71df, 0x15b749b1, 0x3feb4684, 0xe9df7c90, 0xbc6f763d, + 0xb84f15fb, 0x3feb33a2, 0x3084d708, 0xbc52805e, 0x6c9a8952, 0x3feb20ce, + 0x4a0756cc, 0x3c84dd02, 0x298db666, 0x3feb0e07, 0x4c80e425, 0xbc8bdef5, + 0xe622f2ff, 0x3feafb4c, 0x0f315ecd, 0xbc84b2fc, 0x995ad3ad, 0x3feae89f, + 0x345dcc81, 0x3c87a1cd, 0x3a3c2774, 0x3fead5ff, 0xb6b1b8e5, 0x3c87ef3b, + 0xbfd3f37a, 0x3feac36b, 0xcae76cd0, 0xbc7f9234, 0x21356eba, 0x3feab0e5, + 0xdae94545, 0x3c789c31, 0x5579fdbf, 0x3fea9e6b, 0x0ef7fd31, 0x3c80fac9, + 0x53c12e59, 0x3fea8bfe, 0xb2ba15a9, 0xbc84f867, 0x1330b358, 0x3fea799e, + 0xcac563c7, 0x3c8bcb7e, 0x8af46052, 0x3fea674a, 0x30670366, 0x3c550f56, + 0xb23e255d, 0x3fea5503, 0xdb8d41e1, 0xbc8d2f6e, 0x80460ad8, 0x3fea42c9, + 0x589fb120, 0xbc8aa780, 0xec4a2d33, 0x3fea309b, 0x7ddc36ab, 0x3c86305c, + 0xed8eb8bb, 0x3fea1e7a, 0xee8be70e, 0x3c8c6618, 0x7b5de565, 0x3fea0c66, + 0x5d1cd533, 0xbc835949, 0x8d07f29e, 0x3fe9fa5e, 0xaaf1face, 0xbc74a9ce, + 0x19e32323, 0x3fe9e863, 0x78e64c6e, 0x3c6824ca, 0x194bb8d5, 0x3fe9d674, + 0xa3dd8233, 0xbc8516be, 0x82a3f090, 0x3fe9c491, 0xb071f2be, 0x3c6c7c46, + 0x4d53fe0d, 0x3fe9b2bb, 0x4df6d518, 0xbc8dd84e, 0x70ca07ba, 0x3fe9a0f1, + 0x91cee632, 0xbc8173bd, 0xe47a22a2, 0x3fe98f33, 0xa24c78ec, 0x3c6cabda, + 0x9fde4e50, 0x3fe97d82, 0x7c1b85d1, 0xbc8d185b, 0x9a7670b3, 0x3fe96bdd, + 0x7f19c896, 0xbc4ba596, 0xcbc8520f, 0x3fe95a44, 0x96a5f039, 0xbc664b7c, + 0x2b5f98e5, 0x3fe948b8, 0x797d2d99, 0xbc7dc3d6, 0xb0cdc5e5, 0x3fe93737, + 0x81b57ebc, 0xbc575fc7, 0x53aa2fe2, 0x3fe925c3, 0xa639db7f, 0xbc73455f, + 0x0b91ffc6, 0x3fe9145b, 0x2e582524, 0xbc8dd679, 0xd0282c8a, 0x3fe902fe, + 0x85fe3fd2, 0x3c8592ca, 0x99157736, 0x3fe8f1ae, 0xa2e3976c, 0x3c75cc13, + 0x5e0866d9, 0x3fe8e06a, 0x6fc9b2e6, 0xbc87114a, 0x16b5448c, 0x3fe8cf32, + 0x32e9e3aa, 0xbc60d55e, 0xbad61778, 0x3fe8be05, 0xfc43446e, 0x3c8ecb5e, + 0x422aa0db, 0x3fe8ace5, 0x56864b27, 0x3c86e9f1, 0xa478580f, 0x3fe89bd0, + 0x4475202a, 0x3c8d5395, 0xd98a6699, 0x3fe88ac7, 0xf37cb53a, 0x3c8994c2, + 0xd931a436, 0x3fe879ca, 0xd2db47bd, 0x3c75d2d7, 0x9b4492ed, 0x3fe868d9, + 0x9bd4f6ba, 0xbc8fc6f8, 0x179f5b21, 0x3fe857f4, 0xf8b216d0, 0xbc4ba748, + 0x4623c7ad, 0x3fe8471a, 0xa341cdfb, 0xbc78d684, 0x1eb941f7, 0x3fe8364c, + 0x31df2bd5, 0x3c899b9a, 0x994cce13, 0x3fe82589, 0xd41532d8, 0xbc8d4c1d, + 0xadd106d9, 0x3fe814d2, 0x0d151d4d, 0x3c846437, 0x543e1a12, 0x3fe80427, + 0x626d972b, 0xbc827c86, 0x8491c491, 0x3fe7f387, 0xcf9311ae, 0xbc707f11, + 0x36cf4e62, 0x3fe7e2f3, 0xba15797e, 0x3c605d02, 0x62ff86f0, 0x3fe7d26a, + 0xfb72b8b4, 0x3c81bddb, 0x0130c132, 0x3fe7c1ed, 0xd1164dd6, 0x3c8f124c, + 0x0976cfdb, 0x3fe7b17b, 0x8468dc88, 0xbc8bebb5, 0x73eb0187, 0x3fe7a114, + 0xee04992f, 0xbc741577, 0x38ac1cf6, 0x3fe790b9, 0x62aadd3e, 0x3c8349a8, + 0x4fde5d3f, 0x3fe78069, 0x0a02162d, 0x3c8866b8, 0xb1ab6e09, 0x3fe77024, + 0x169147f8, 0x3c8b7877, 0x564267c9, 0x3fe75feb, 0x57316dd3, 0xbc802459, + 0x35d7cbfd, 0x3fe74fbd, 0x618a6e1c, 0x3c8047fd, 0x48a58174, 0x3fe73f9a, + 0x6c65d53c, 0xbc80a8d9, 0x86ead08a, 0x3fe72f82, 0x2cd62c72, 0xbc820aa0, + 0xe8ec5f74, 0x3fe71f75, 0x86887a99, 0xbc716e47, 0x66f42e87, 0x3fe70f74, + 0xd45aa65f, 0x3c49d644, 0xf9519484, 0x3fe6ff7d, 0x25860ef6, 0xbc783c0f, + 0x98593ae5, 0x3fe6ef92, 0x9e1ac8b2, 0xbc80b974, 0x3c651a2f, 0x3fe6dfb2, + 0x683c88ab, 0xbc5bbe3a, 0xddd47645, 0x3fe6cfdc, 0xb6f17309, 0x3c8c7aa9, + 0x750bdabf, 0x3fe6c012, 0x67ff0b0d, 0xbc628956, 0xfa75173e, 0x3fe6b052, + 0x2c9a9d0e, 0x3c6a38f5, 0x667f3bcd, 0x3fe6a09e, 0x13b26456, 0xbc8bdd34, + 0xb19e9538, 0x3fe690f4, 0x9aeb445d, 0x3c7804bd, 0xd44ca973, 0x3fe68155, + 0x44f73e65, 0x3c5038ae, 0xc70833f6, 0x3fe671c1, 0x586c6134, 0xbc7e8732, + 0x82552225, 0x3fe66238, 0x87591c34, 0xbc8bb609, 0xfebc8fb7, 0x3fe652b9, + 0xc9a73e09, 0xbc8ae3d5, 0x34ccc320, 0x3fe64346, 0x759d8933, 0xbc7c483c, + 0x1d1929fd, 0x3fe633dd, 0xbeb964e5, 0x3c884710, 0xb03a5585, 0x3fe6247e, + 0x7e40b497, 0xbc8383c1, 0xe6cdf6f4, 0x3fe6152a, 0x4ab84c27, 0x3c8e4b3e, + 0xb976dc09, 0x3fe605e1, 0x9b56de47, 0xbc83e242, 0x20dceb71, 0x3fe5f6a3, + 0xe3cdcf92, 0xbc79eadd, 0x15ad2148, 0x3fe5e76f, 0x3080e65e, 0x3c8ba6f9, + 0x90998b93, 0x3fe5d845, 0xa8b45643, 0xbc8cd6a7, 0x8a5946b7, 0x3fe5c926, + 0x816986a2, 0x3c2c4b1b, 0xfba87a03, 0x3fe5ba11, 0x4c233e1a, 0xbc8b77a1, + 0xdd485429, 0x3fe5ab07, 0x054647ad, 0x3c86324c, 0x27ff07cc, 0x3fe59c08, + 0xe467e60f, 0xbc87e2ce, 0xd497c7fd, 0x3fe58d12, 0x5b9a1de8, 0x3c7295e1, + 0xdbe2c4cf, 0x3fe57e27, 0x8a57b9c4, 0xbc80b98c, 0x36b527da, 0x3fe56f47, + 0x011d93ad, 0x3c89bb2c, 0xdde910d2, 0x3fe56070, 0x168eebf0, 0xbc80fb6e, + 0xca5d920f, 0x3fe551a4, 0xefede59b, 0xbc7d689c, 0xf4f6ad27, 0x3fe542e2, + 0x192d5f7e, 0x3c77926d, 0x569d4f82, 0x3fe5342b, 0x1db13cad, 0xbc707abe, + 0xe83f4eef, 0x3fe5257d, 0x43efef71, 0xbc6c998d, 0xa2cf6642, 0x3fe516da, + 0x69bd93ef, 0xbc7f7685, 0x7f4531ee, 0x3fe50841, 0x49b7465f, 0x3c6a249b, + 0x769d2ca7, 0x3fe4f9b2, 0xd25957e3, 0xbc84b309, 0x81d8abff, 0x3fe4eb2d, + 0x2e5d7a52, 0xbc85257d, 0x99fddd0d, 0x3fe4dcb2, 0xbc6a7833, 0x3c88ecdb, + 0xb817c114, 0x3fe4ce41, 0x690abd5d, 0x3c805e29, 0xd5362a27, 0x3fe4bfda, + 0xafec42e2, 0x3c6d4397, 0xea6db7d7, 0x3fe4b17d, 0x7f2897f0, 0xbc7125b8, + 0xf0d7d3de, 0x3fe4a32a, 0xf3d1be56, 0x3c89cb62, 0xe192aed2, 0x3fe494e1, + 0x5e499ea0, 0xbc73b289, 0xb5c13cd0, 0x3fe486a2, 0xb69062f0, 0x3c63c1a3, + 0x668b3237, 0x3fe4786d, 0xed445733, 0xbc8c20f0, 0xed1d0057, 0x3fe46a41, + 0xd1648a76, 0x3c8c944b, 0x42a7d232, 0x3fe45c20, 0x82fb1f8e, 0xbc586419, + 0x6061892d, 0x3fe44e08, 0x04ef80d0, 0x3c389b7a, 0x3f84b9d4, 0x3fe43ffa, + 0x9704c003, 0x3c7880be, 0xd950a897, 0x3fe431f5, 0xe35f7999, 0xbc71c7dd, + 0x2709468a, 0x3fe423fb, 0xc0b314dd, 0xbc88462d, 0x21f72e2a, 0x3fe4160a, + 0x1c309278, 0xbc4ef369, 0xc367a024, 0x3fe40822, 0xb6f4d048, 0x3c7bddf8, + 0x04ac801c, 0x3fe3fa45, 0xf956f9f3, 0xbc87d023, 0xdf1c5175, 0x3fe3ec70, + 0x7b8c9bca, 0xbc7af663, 0x4c123422, 0x3fe3dea6, 0x11f09ebc, 0x3c7ada09, + 0x44ede173, 0x3fe3d0e5, 0x8c284c71, 0x3c6fe8d0, 0xc313a8e5, 0x3fe3c32d, + 0x375d29c3, 0xbc8efff8, 0xbfec6cf4, 0x3fe3b57f, 0xe26fff18, 0x3c854c66, + 0x34e59ff7, 0x3fe3a7db, 0xd661f5e3, 0xbc65e436, 0x1b7140ef, 0x3fe39a40, + 0xfc8e2934, 0xbc89a9a5, 0x6d05d866, 0x3fe38cae, 0x3c9904bd, 0xbc8e958d, + 0x231e754a, 0x3fe37f26, 0x9eceb23c, 0xbc89f5ca, 0x373aa9cb, 0x3fe371a7, + 0xbf42eae2, 0xbc863aea, 0xa2de883b, 0x3fe36431, 0xa06cb85e, 0xbc7c3144, + 0x5f929ff1, 0x3fe356c5, 0x5c4e4628, 0xbc7b5cee, 0x66e3fa2d, 0x3fe34962, + 0x930881a4, 0xbc735a75, 0xb26416ff, 0x3fe33c08, 0x843659a6, 0x3c832721, + 0x3ba8ea32, 0x3fe32eb8, 0x3cb4f318, 0xbc8c45e8, 0xfc4cd831, 0x3fe32170, + 0x8e18047c, 0x3c7a9ce7, 0xedeeb2fd, 0x3fe31432, 0xf3f3fcd1, 0x3c7959a3, + 0x0a31b715, 0x3fe306fe, 0xd23182e4, 0x3c76f46a, 0x4abd886b, 0x3fe2f9d2, + 0x532bda93, 0xbc553c55, 0xa93e2f56, 0x3fe2ecaf, 0x45d52383, 0x3c61ca0f, + 0x1f641589, 0x3fe2df96, 0xfbbce198, 0x3c8d16cf, 0xa6e4030b, 0x3fe2d285, + 0x54db41d5, 0x3c800247, 0x39771b2f, 0x3fe2c57e, 0xa6eb5124, 0xbc850145, + 0xd0dad990, 0x3fe2b87f, 0xd6381aa4, 0xbc310adc, 0x66d10f13, 0x3fe2ab8a, + 0x191690a7, 0xbc895743, 0xf51fdee1, 0x3fe29e9d, 0xafad1255, 0x3c7612e8, + 0x7591bb70, 0x3fe291ba, 0x28401cbd, 0xbc72cc72, 0xe1f56381, 0x3fe284df, + 0x8c3f0d7e, 0xbc8a4c3a, 0x341ddf29, 0x3fe2780e, 0x05f9e76c, 0x3c8e067c, + 0x65e27cdd, 0x3fe26b45, 0x9940e9d9, 0x3c72bd33, 0x711ece75, 0x3fe25e85, + 0x4ac31b2c, 0x3c83e1a2, 0x4fb2a63f, 0x3fe251ce, 0xbef4f4a4, 0x3c7ac155, + 0xfb82140a, 0x3fe2451f, 0x911ca996, 0x3c7acfcc, 0x6e756238, 0x3fe2387a, + 0xb6c70573, 0x3c89b07e, 0xa27912d1, 0x3fe22bdd, 0x5577d69f, 0x3c7d34fb, + 0x917ddc96, 0x3fe21f49, 0x9494a5ee, 0x3c72a97e, 0x3578a819, 0x3fe212be, + 0x2cfcaac9, 0x3c83592d, 0x88628cd6, 0x3fe2063b, 0x814a8495, 0x3c7dc775, + 0x8438ce4d, 0x3fe1f9c1, 0xa097af5c, 0xbc8bf524, 0x22fcd91d, 0x3fe1ed50, + 0x027bb78c, 0xbc81df98, 0x5eb44027, 0x3fe1e0e7, 0x088cb6de, 0xbc86fdd8, + 0x3168b9aa, 0x3fe1d487, 0x00a2643c, 0x3c8e016e, 0x95281c6b, 0x3fe1c82f, + 0x8010f8c9, 0x3c800977, 0x84045cd4, 0x3fe1bbe0, 0x352ef607, 0xbc895386, + 0xf8138a1c, 0x3fe1af99, 0xa4b69280, 0x3c87bf85, 0xeb6fcb75, 0x3fe1a35b, + 0x7b4968e4, 0x3c7e5b4c, 0x58375d2f, 0x3fe19726, 0x85f17e08, 0x3c84aadd, + 0x388c8dea, 0x3fe18af9, 0xd1970f6c, 0xbc811023, 0x8695bbc0, 0x3fe17ed4, + 0xe2ac5a64, 0x3c609e3f, 0x3c7d517b, 0x3fe172b8, 0xb9d78a76, 0xbc719041, + 0x5471c3c2, 0x3fe166a4, 0x82ea1a32, 0x3c48f23b, 0xc8a58e51, 0x3fe15a98, + 0xb9eeab0a, 0x3c72406a, 0x934f312e, 0x3fe14e95, 0x39bf44ab, 0xbc7b91e8, + 0xaea92de0, 0x3fe1429a, 0x9af1369e, 0xbc832fbf, 0x14f204ab, 0x3fe136a8, + 0xba48dcf0, 0xbc57108f, 0xc06c31cc, 0x3fe12abd, 0xb36ca5c7, 0xbc41b514, + 0xab5e2ab6, 0x3fe11edb, 0xf703fb72, 0xbc8ca454, 0xd0125b51, 0x3fe11301, + 0x39449b3a, 0xbc86c510, 0x28d7233e, 0x3fe10730, 0x1692fdd5, 0x3c7d46eb, + 0xaffed31b, 0x3fe0fb66, 0xc44ebd7b, 0xbc5b9bed, 0x5fdfa9c5, 0x3fe0efa5, + 0xbc54021b, 0xbc849db9, 0x32d3d1a2, 0x3fe0e3ec, 0x27c57b52, 0x3c303a17, + 0x23395dec, 0x3fe0d83b, 0xe43f316a, 0xbc8bc14d, 0x2b7247f7, 0x3fe0cc92, + 0x16e24f71, 0x3c801edc, 0x45e46c85, 0x3fe0c0f1, 0x06d21cef, 0x3c84f989, + 0x6cf9890f, 0x3fe0b558, 0x4adc610b, 0x3c88a62e, 0x9b1f3919, 0x3fe0a9c7, + 0x873d1d38, 0x3c75d16c, 0xcac6f383, 0x3fe09e3e, 0x18316136, 0x3c814878, + 0xf66607e0, 0x3fe092bd, 0x800a3fd1, 0xbc868063, 0x18759bc8, 0x3fe08745, + 0x4bb284ff, 0x3c5186be, 0x2b72a836, 0x3fe07bd4, 0x54458700, 0x3c732334, + 0x29ddf6de, 0x3fe0706b, 0xe2b13c27, 0xbc7c91df, 0x0e3c1f89, 0x3fe0650a, + 0x5799c397, 0xbc85cb7b, 0xd3158574, 0x3fe059b0, 0xa475b465, 0x3c7d73e2, + 0x72f654b1, 0x3fe04e5f, 0x3aa0d08c, 0x3c74c379, 0xe86e7f85, 0x3fe04315, + 0x1977c96e, 0xbc80a31c, 0x2e11bbcc, 0x3fe037d4, 0xeeade11a, 0x3c556811, + 0x3e778061, 0x3fe02c9a, 0x535b085d, 0xbc619083, 0x143b0281, 0x3fe02168, + 0x0fc54eb6, 0xbc72bf31, 0xa9fb3335, 0x3fe0163d, 0x9ab8cdb7, 0x3c8b6129, + 0xfa5abcbf, 0x3fe00b1a, 0xa7609f71, 0xbc74f6b2, + // @formatter:on + }); + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + Label l2TAGPACKET001 = new Label(); + Label l2TAGPACKET101 = new Label(); + Label l2TAGPACKET201 = new Label(); + Label l2TAGPACKET301 = new Label(); + Label l2TAGPACKET401 = new Label(); + Label l2TAGPACKET501 = new Label(); + Label lB12 = new Label(); + Label lB14 = new Label(); + + masm.bind(lB12); + masm.movsd(xmm3, recordExternalAddress(crb, halfMask)); + masm.xorpd(xmm4, xmm4); + masm.movsd(xmm1, recordExternalAddress(crb, l2e)); + /* + * We do not support offset for the constants in data section because it will be rewritten + * to offset 0 during data patching at CodeInstaller::pd_patch_DataSectionReference in + * HotSpot. Thus we split the original constant into several to ensure every access starts + * at offset 0. This assumes the accesses do not exceed the width of the constants because + * we cannot guarantee that the split constants are placed sequentially. + */ + masm.movsd(xmm2, recordExternalAddress(crb, l2eOff8)); + masm.movl(rax, 32768); + masm.pinsrw(xmm4, rax, 3); + masm.movsd(xmm6, recordExternalAddress(crb, shifter)); + masm.pextrw(rcx, xmm0, 3); + masm.andpd(xmm3, xmm0); + masm.andnpd(xmm4, xmm0); + masm.pshufd(xmm5, xmm4, 68); + masm.movl(rdx, 32768); + masm.andl(rdx, rcx); + masm.andl(rcx, 32767); + masm.subl(rcx, 16304); + masm.cmpl(rcx, 144); + masm.jcc(ConditionFlag.AboveEqual, l2TAGPACKET001); + masm.subsd(xmm4, xmm3); + masm.mulsd(xmm3, xmm1); + masm.mulsd(xmm2, xmm5); + masm.cvtsd2siq(rax, xmm3); + masm.movq(xmm7, xmm3); + masm.addsd(xmm3, xmm6); + masm.mulsd(xmm1, xmm4); + masm.movsd(xmm4, recordExternalAddress(crb, oneMask)); + masm.subsd(xmm3, xmm6); + masm.xorpd(xmm0, xmm0); + masm.addsd(xmm2, xmm1); + masm.subsd(xmm7, xmm3); + masm.movdqu(xmm6, recordExternalAddress(crb, cv)); + masm.addsd(xmm2, xmm7); + masm.movl(rcx, 255); + masm.andl(rcx, rax); + masm.addl(rcx, rcx); + masm.leaq(r8, recordExternalAddress(crb, t2NegF)); + masm.movdqu(xmm5, new AMD64Address(r8, rcx, Stride.S8)); + masm.shrl(rax, 4); + masm.andl(rax, 65520); + masm.subl(rax, 16368); + masm.negl(rax); + masm.pinsrw(xmm0, rax, 3); + masm.movdqu(xmm1, recordExternalAddress(crb, cvOff16)); + masm.pshufd(xmm0, xmm0, 68); + masm.mulpd(xmm0, xmm5); + masm.movsd(xmm7, recordExternalAddress(crb, cvOff32)); + masm.pshufd(xmm2, xmm2, 68); + masm.movq(xmm5, xmm4); + masm.addsd(xmm4, xmm0); + masm.mulpd(xmm6, xmm2); + masm.mulsd(xmm7, xmm2); + masm.mulpd(xmm2, xmm2); + masm.addpd(xmm1, xmm6); + masm.mulsd(xmm2, xmm2); + masm.movsd(xmm3, recordExternalAddress(crb, oneMask)); + masm.mulpd(xmm1, xmm2); + masm.pshufd(xmm6, xmm1, 78); + masm.addsd(xmm1, xmm6); + masm.movq(xmm6, xmm1); + masm.addsd(xmm1, xmm7); + masm.mulsd(xmm1, xmm0); + masm.addsd(xmm1, xmm4); + masm.andpd(xmm4, recordExternalAddress(crb, threeMask)); + masm.divsd(xmm5, xmm1); + masm.subsd(xmm3, xmm4); + masm.pshufd(xmm1, xmm0, 238); + masm.addsd(xmm3, xmm0); + masm.movq(xmm2, xmm4); + masm.addsd(xmm3, xmm1); + masm.mulsd(xmm1, xmm7); + masm.mulsd(xmm7, xmm0); + masm.addsd(xmm3, xmm1); + masm.addsd(xmm4, xmm7); + masm.movsd(xmm1, recordExternalAddress(crb, rMask)); + masm.mulsd(xmm6, xmm0); + masm.andpd(xmm4, recordExternalAddress(crb, threeMask)); + masm.addsd(xmm3, xmm6); + masm.movq(xmm6, xmm4); + masm.subsd(xmm2, xmm4); + masm.addsd(xmm2, xmm7); + masm.movsd(xmm7, recordExternalAddress(crb, oneMask)); + masm.andpd(xmm5, xmm1); + masm.addsd(xmm3, xmm2); + masm.mulsd(xmm4, xmm5); + masm.xorpd(xmm2, xmm2); + masm.mulsd(xmm3, xmm5); + masm.subsd(xmm6, recordExternalAddress(crb, twoMask)); + masm.subsd(xmm4, xmm7); + masm.xorl(rdx, 32768); + masm.pinsrw(xmm2, rdx, 3); + masm.addsd(xmm4, xmm3); + masm.mulsd(xmm6, xmm5); + masm.movq(xmm1, xmm3); + masm.mulsd(xmm3, xmm4); + masm.movq(xmm0, xmm6); + masm.mulsd(xmm6, xmm4); + masm.subsd(xmm1, xmm3); + masm.subsd(xmm1, xmm6); + masm.addsd(xmm0, xmm1); + masm.xorpd(xmm0, xmm2); + masm.jmp(lB14); + + masm.bind(l2TAGPACKET001); + masm.addl(rcx, 960); + masm.cmpl(rcx, 1104); + masm.jcc(ConditionFlag.AboveEqual, l2TAGPACKET101); + masm.movdqu(xmm2, recordExternalAddress(crb, pv)); + masm.pshufd(xmm1, xmm0, 68); + masm.movdqu(xmm3, recordExternalAddress(crb, pvOff16)); + masm.mulpd(xmm1, xmm1); + masm.movdqu(xmm4, recordExternalAddress(crb, pvOff32)); + masm.mulpd(xmm2, xmm1); + masm.pshufd(xmm5, xmm1, 68); + masm.addpd(xmm2, xmm3); + masm.mulsd(xmm5, xmm5); + masm.mulpd(xmm2, xmm1); + masm.mulsd(xmm5, xmm5); + masm.addpd(xmm2, xmm4); + masm.mulpd(xmm2, xmm5); + masm.pshufd(xmm5, xmm2, 238); + masm.addsd(xmm2, xmm5); + masm.mulsd(xmm2, xmm0); + masm.addsd(xmm0, xmm2); + masm.jmp(lB14); + + masm.bind(l2TAGPACKET101); + masm.addl(rcx, 15344); + masm.cmpl(rcx, 16448); + masm.jcc(ConditionFlag.AboveEqual, l2TAGPACKET201); + masm.cmpl(rcx, 16); + masm.jcc(ConditionFlag.Below, l2TAGPACKET301); + masm.xorpd(xmm2, xmm2); + masm.movl(rax, 17392); + masm.pinsrw(xmm2, rax, 3); + masm.mulsd(xmm2, xmm0); + masm.addsd(xmm2, xmm0); + masm.jmp(lB14); + + masm.bind(l2TAGPACKET301); + masm.movq(xmm2, xmm0); + masm.mulsd(xmm2, xmm2); + masm.jmp(lB14); + + masm.bind(l2TAGPACKET201); + masm.cmpl(rcx, 32752); + masm.jcc(ConditionFlag.AboveEqual, l2TAGPACKET401); + masm.xorpd(xmm2, xmm2); + masm.movl(rcx, 15344); + masm.pinsrw(xmm2, rcx, 3); + masm.movq(xmm3, xmm2); + masm.mulsd(xmm2, xmm2); + masm.addsd(xmm2, xmm3); + + masm.bind(l2TAGPACKET501); + masm.xorpd(xmm0, xmm0); + masm.orl(rdx, 16368); + masm.pinsrw(xmm0, rdx, 3); + masm.jmp(lB14); + + masm.bind(l2TAGPACKET401); + masm.movq(xmm2, xmm0); + masm.movdl(rax, xmm0); + masm.psrlq(xmm2, 20); + masm.movdl(rcx, xmm2); + masm.orl(rcx, rax); + masm.cmpl(rcx, 0); + masm.jcc(ConditionFlag.Equal, l2TAGPACKET501); + masm.addsd(xmm0, xmm0); + + masm.bind(lB14); + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java index 95f9b6198c5f..b22256e99195 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64RoundFloatToIntegerOp.java @@ -46,7 +46,7 @@ * {@link Math#round} algorithm for details. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/59ac7039d3ace0ec481742c3a10c81f1675e12da/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L10043-L10139", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L10054-L10150", sha1 = "9e13c7375bbb35809ad79ebd6a9cc19e66f57aa1") @SyncPort(from = "https://github.com/openjdk/jdk/blob/7fa2f229fbee68112cbdd18b811d95721adfe2ec/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L596-L763", sha1 = "312f16a0551887f78cc567638477bbbcbc3765c5") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA512Op.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA512Op.java index 4ac91e50f581..448409106689 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA512Op.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64SHA512Op.java @@ -72,8 +72,8 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/7fa2f229fbee68112cbdd18b811d95721adfe2ec/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L1559-L1592", - sha1 = "0bdbfb85ba18320b87b5dd9ae87e1fd9d55b5882") +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp#L1559-L1594", + sha1 = "aa94accda4424ad1bafadcd9dd85af929f92e7bb") @SyncPort(from = "https://github.com/openjdk/jdk/blob/431d4f7e18369466eedd00926a5162a1461d0b25/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp#L1037-L1520", sha1 = "a13f01c5f15f95cbdb6acb082866aa3f14bc94b4") // @formatter:on diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java index 42db4de10b6f..8afa785a3e9d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64StringUTF16CompressOp.java @@ -59,7 +59,7 @@ import jdk.vm.ci.meta.Value; // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/59ac7039d3ace0ec481742c3a10c81f1675e12da/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L8946-L9154", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L8957-L9165", sha1 = "3e365037f473204b3f742ab364bd9ad514e72161") // @formatter:on @Opcode("AMD64_STRING_COMPRESS") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java index 95ac203fce3e..cd6c87c898e3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64VectorizedMismatchOp.java @@ -61,7 +61,7 @@ * instructions where possible. */ // @formatter:off -@SyncPort(from = "https://github.com/openjdk/jdk/blob/59ac7039d3ace0ec481742c3a10c81f1675e12da/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7152-L7370", +@SyncPort(from = "https://github.com/openjdk/jdk/blob/7131f053b0d26b62cbf0d8376ec117d6e8d79f9e/src/hotspot/cpu/x86/macroAssembler_x86.cpp#L7163-L7381", sha1 = "72f9b7a60b75ecabf09fc10cb01a9504be97957a") // @formatter:on @Opcode("VECTORIZED_MISMATCH") diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/ArithmeticLIRGeneratorTool.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/ArithmeticLIRGeneratorTool.java index 264b8f3246e8..b3270a02e44c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/ArithmeticLIRGeneratorTool.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/gen/ArithmeticLIRGeneratorTool.java @@ -154,6 +154,11 @@ default Value emitMathTan(Value input) { throw GraalError.unimplemented("No specialized implementation available"); // ExcludeFromJacocoGeneratedReport } + @SuppressWarnings("unused") + default Value emitMathTanh(Value input) { + throw GraalError.unimplemented("No specialized implementation available"); // ExcludeFromJacocoGeneratedReport + } + @SuppressWarnings("unused") default Value emitMathExp(Value input) { throw GraalError.unimplemented("No specialized implementation available"); // ExcludeFromJacocoGeneratedReport diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java index 7d51a41efcfb..a5cddee872e2 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java @@ -25,6 +25,7 @@ package jdk.graal.compiler.replacements; import static jdk.graal.compiler.core.common.GraalOptions.EmitStringSubstitutions; +import static jdk.graal.compiler.core.common.GraalOptions.InlineGraalStubs; import static jdk.graal.compiler.core.common.SpectrePHTMitigations.Options.SpectrePHTIndexMasking; import static jdk.graal.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION; import static jdk.graal.compiler.nodes.calc.BinaryArithmeticNode.branchlessMax; @@ -410,6 +411,9 @@ private void lowerBinaryMath(BinaryMathIntrinsicNode math, LoweringTool tool) { // implementation. return; } + if (InlineGraalStubs.getValue(math.graph().getOptions())) { + return; + } } StructuredGraph graph = math.graph(); ForeignCallNode call = graph.add(new ForeignCallNode(foreignCalls, math.getOperation().foreignCallSignature, math.getX(), math.getY())); @@ -428,6 +432,9 @@ private void lowerUnaryMath(UnaryMathIntrinsicNode math, LoweringTool tool) { // implementation. return; } + if (InlineGraalStubs.getValue(math.graph().getOptions())) { + return; + } } lowerUnaryMathToForeignCall(math, tool); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java index 4945ee5ed9b9..bdd1c084cd0f 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java @@ -31,6 +31,7 @@ import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10; import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN; import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN; +import static jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TANH; import java.lang.reflect.Type; import java.util.Arrays; @@ -83,6 +84,7 @@ import jdk.graal.compiler.replacements.nodes.HalfFloatToFloatNode; import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode; import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64.CPUFeature; import jdk.vm.ci.code.Architecture; @@ -203,6 +205,9 @@ private static void registerMathPlugins(InvocationPlugins plugins, AMD64 arch, R registerUnaryMath(r, "sin", SIN); registerUnaryMath(r, "cos", COS); registerUnaryMath(r, "tan", TAN); + if (JavaVersionUtil.JAVA_SPEC >= 24) { + registerUnaryMath(r, "tanh", TANH); + } registerFMA(r, arch); registerMinMax(r, arch); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/UnaryMathIntrinsicNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/UnaryMathIntrinsicNode.java index c23a7b1dbe04..908af0a1c64a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/UnaryMathIntrinsicNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/nodes/UnaryMathIntrinsicNode.java @@ -60,6 +60,7 @@ public enum UnaryOperation { SIN(new ForeignCallSignature("arithmeticSin", double.class, double.class)), COS(new ForeignCallSignature("arithmeticCos", double.class, double.class)), TAN(new ForeignCallSignature("arithmeticTan", double.class, double.class)), + TANH(new ForeignCallSignature("arithmeticTanh", double.class, double.class)), EXP(new ForeignCallSignature("arithmeticExp", double.class, double.class)); public final ForeignCallSignature foreignCallSignature; @@ -82,6 +83,8 @@ public static double compute(UnaryOperation op, double value) { return Math.cos(value); case TAN: return Math.tan(value); + case TANH: + return Math.tanh(value); default: throw new GraalError("unknown op %s", op); } @@ -94,6 +97,7 @@ public static Stamp computeStamp(UnaryOperation op, Stamp valueStamp) { if (valueStamp instanceof FloatStamp) { FloatStamp floatStamp = (FloatStamp) valueStamp; switch (op) { + case TANH: case COS: case SIN: { boolean nonNaN = floatStamp.lowerBound() != Double.NEGATIVE_INFINITY && floatStamp.upperBound() != Double.POSITIVE_INFINITY && floatStamp.isNonNaN(); @@ -183,6 +187,9 @@ public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool case TAN: result = gen.emitMathTan(input); break; + case TANH: + result = gen.emitMathTanh(input); + break; default: throw GraalError.shouldNotReachHereUnexpectedValue(getOperation()); // ExcludeFromJacocoGeneratedReport } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java index 675356454f70..0e414850543c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java @@ -461,6 +461,13 @@ public boolean getAsBoolean() { } } +final class IsAMD64 implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + return Platform.includedIn(Platform.AMD64.class); + } +} + /** * When the intrinsics below are used outside of {@link java.lang.Math}, they are lowered to a * foreign call. This foreign call must be uninterruptible as it results from lowering a floating @@ -489,6 +496,14 @@ public static double tan(double a) { return UnaryMathIntrinsicNode.compute(a, UnaryOperation.TAN); } + @Substitute + @Uninterruptible(reason = "Must not contain a safepoint.") + @SubstrateForeignCallTarget(fullyUninterruptible = true, stubCallingConvention = false) + @TargetElement(onlyWith = IsAMD64.class) + public static double tanh(double a) { + return UnaryMathIntrinsicNode.compute(a, UnaryOperation.TANH); + } + @Substitute @Uninterruptible(reason = "Must not contain a safepoint.") @SubstrateForeignCallTarget(fullyUninterruptible = true, stubCallingConvention = false) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/SnippetRuntime.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/SnippetRuntime.java index 4f1cb153214c..f3f6713ef613 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/SnippetRuntime.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/SnippetRuntime.java @@ -29,10 +29,6 @@ import java.lang.reflect.Method; -import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; -import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor.CallSideEffect; -import jdk.graal.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation; -import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.word.LocationIdentity; @@ -40,6 +36,10 @@ import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; import com.oracle.svm.core.util.VMError; +import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; +import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor.CallSideEffect; +import jdk.graal.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation; +import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -57,13 +57,14 @@ public class SnippetRuntime { private static final SubstrateForeignCallDescriptor ARITHMETIC_SIN = findForeignJdkCall(UnaryOperation.SIN.foreignCallSignature.getName(), Math.class, "sin", NO_SIDE_EFFECT, true, true); private static final SubstrateForeignCallDescriptor ARITHMETIC_COS = findForeignJdkCall(UnaryOperation.COS.foreignCallSignature.getName(), Math.class, "cos", NO_SIDE_EFFECT, true, true); private static final SubstrateForeignCallDescriptor ARITHMETIC_TAN = findForeignJdkCall(UnaryOperation.TAN.foreignCallSignature.getName(), Math.class, "tan", NO_SIDE_EFFECT, true, true); + private static final SubstrateForeignCallDescriptor ARITHMETIC_TANH = findForeignJdkCall(UnaryOperation.TANH.foreignCallSignature.getName(), Math.class, "tanh", NO_SIDE_EFFECT, true, true); private static final SubstrateForeignCallDescriptor ARITHMETIC_LOG = findForeignJdkCall(UnaryOperation.LOG.foreignCallSignature.getName(), Math.class, "log", NO_SIDE_EFFECT, true, true); private static final SubstrateForeignCallDescriptor ARITHMETIC_LOG10 = findForeignJdkCall(UnaryOperation.LOG10.foreignCallSignature.getName(), Math.class, "log10", NO_SIDE_EFFECT, true, true); private static final SubstrateForeignCallDescriptor ARITHMETIC_EXP = findForeignJdkCall(UnaryOperation.EXP.foreignCallSignature.getName(), Math.class, "exp", NO_SIDE_EFFECT, true, true); private static final SubstrateForeignCallDescriptor ARITHMETIC_POW = findForeignJdkCall(BinaryOperation.POW.foreignCallSignature.getName(), Math.class, "pow", NO_SIDE_EFFECT, true, true); private static final SubstrateForeignCallDescriptor[] FOREIGN_CALLS = new SubstrateForeignCallDescriptor[]{UNSUPPORTED_FEATURE, REGISTER_FINALIZER, ARITHMETIC_SIN, ARITHMETIC_COS, ARITHMETIC_TAN, - ARITHMETIC_LOG, ARITHMETIC_LOG10, ARITHMETIC_EXP, ARITHMETIC_POW}; + ARITHMETIC_TANH, ARITHMETIC_LOG, ARITHMETIC_LOG10, ARITHMETIC_EXP, ARITHMETIC_POW}; public static void registerForeignCalls(SubstrateForeignCallsProvider foreignCalls) { foreignCalls.register(FOREIGN_CALLS); From 85ef98c4b332edca2ac782fe3bd19d08e8fcaed0 Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Fri, 25 Oct 2024 14:09:21 +0200 Subject: [PATCH 096/105] remove old GC prevention mechanism which is now replaced by object pinning --- .../espresso/jdwp/impl/DebuggerController.java | 1 - .../truffle/espresso/jdwp/impl/GCPrevention.java | 12 ------------ .../com/oracle/truffle/espresso/jdwp/impl/JDWP.java | 8 +------- 3 files changed, 1 insertion(+), 20 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java index 1431ce8a9d05..937f5c3b70a0 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java @@ -711,7 +711,6 @@ private void lockThread(Object thread, boolean forceSuspend, List } checkThreadJobsAndRun(thread); } - getGCPrevention().releaseActiveWhileSuspended(thread); fine(() -> "lock wakeup for thread: " + getThreadName(thread)); } diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/GCPrevention.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/GCPrevention.java index 2d9547d3b7fe..910066cb9d1f 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/GCPrevention.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/GCPrevention.java @@ -22,8 +22,6 @@ */ package com.oracle.truffle.espresso.jdwp.impl; -import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; public final class GCPrevention { @@ -31,7 +29,6 @@ public final class GCPrevention { // simply hold a strong reference to all objects for which // GC should be disabled private final HashSet prevent = new HashSet<>(); - private final HashMap> activeWhileSuspended = new HashMap<>(); public void disableGC(Object object) { prevent.add(object); @@ -45,13 +42,4 @@ public void clearAll() { prevent.clear(); } - public synchronized void setActiveWhileSuspended(Object guestThread, Object obj) { - activeWhileSuspended.putIfAbsent(guestThread, new ArrayList<>()); - activeWhileSuspended.get(guestThread).add(obj); - } - - public synchronized void releaseActiveWhileSuspended(Object guestThread) { - activeWhileSuspended.remove(guestThread); - } - } diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java index de2e3bb761a4..ed5b5f0a7ae9 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java @@ -1587,7 +1587,7 @@ static CommandResult createReply(Packet packet, JDWPContext context) { Object object = context.getIds().fromId((int) objectId); - if (object == context.getNullObject()) { + if (object == null || object == context.getNullObject()) { reply.errorCode(ErrorCodes.INVALID_OBJECT); return new CommandResult(reply); } @@ -3049,17 +3049,11 @@ private static void writeMethodResult(PacketStream reply, JDWPContext context, T reply.writeByte(TagConstants.OBJECT); Object guestException = context.getGuestException(result.getException()); reply.writeLong(context.getIds().getIdAsLong(guestException)); - if (controller.getThreadSuspension().getSuspensionCount(thread) > 0) { - controller.getGCPrevention().setActiveWhileSuspended(thread, guestException); - } } else { Object value = result.getResult(); if (value != null) { byte tag = context.getTag(value); writeValue(tag, value, reply, true, context); - if (controller.getThreadSuspension().getSuspensionCount(thread) > 0) { - controller.getGCPrevention().setActiveWhileSuspended(thread, value); - } } else { // return value is null reply.writeByte(TagConstants.OBJECT); reply.writeLong(0); From 4638e9fc3c913c8229eaf700b6842e6e350abf30 Mon Sep 17 00:00:00 2001 From: Marouane El Hallaoui Date: Fri, 25 Oct 2024 17:07:11 +0100 Subject: [PATCH 097/105] deploy snapshots --- common.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common.json b/common.json index a0696b7c599e..25be40131e1c 100644 --- a/common.json +++ b/common.json @@ -46,12 +46,12 @@ "oraclejdk23": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+37", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+21", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+21-jvmci-b01-20241024162317-915c0f22fd", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+21-jvmci-b01-20241024162317-915c0f22fd-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+21-jvmci-b01-20241024162317-915c0f22fd-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+21-jvmci-b01-20241024162317-915c0f22fd+20567b785f", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+21-jvmci-b01-20241024162317-915c0f22fd+20567b785f-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+21-jvmci-b01-20241024162317-915c0f22fd+20567b785f-sulong", "platformspecific": true } + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+21-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+21-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+21-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+21-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+21-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+21-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From fb8ef1519b3a2df993708d4873476c2b869e9f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfonso=C2=B2=20Peterssen?= Date: Thu, 15 Aug 2024 19:29:29 +0200 Subject: [PATCH 098/105] Extract the .class file parser into a standalone component. --- espresso/mx.espresso/suite.py | 14 + .../espresso/classfile/ClassfileParser.java | 760 +++++++++++------- .../espresso/classfile/ClassfileStream.java | 34 +- .../espresso/classfile/ClasspathEntry.java | 69 ++ .../espresso/classfile}/ClasspathFile.java | 19 +- .../espresso/classfile/ConstantPool.java | 385 +++++++++ .../truffle/espresso/classfile/Constants.java | 162 ++++ .../espresso/classfile}/ExceptionHandler.java | 6 +- .../classfile/ImmutableConstantPool.java | 32 +- .../truffle/espresso/classfile}/JavaKind.java | 177 +--- .../espresso/classfile}/JavaVersion.java | 7 +- .../espresso/classfile/ParserException.java | 64 ++ .../espresso/classfile}/ParserField.java | 45 +- .../espresso/classfile}/ParserKlass.java | 20 +- .../espresso/classfile}/ParserMethod.java | 19 +- .../espresso/classfile/ParsingContext.java | 79 ++ .../classfile/attributes}/Attribute.java | 6 +- .../attributes/BootstrapMethodsAttribute.java | 72 ++ .../classfile/attributes/CodeAttribute.java | 37 +- .../attributes/ConstantValueAttribute.java | 5 +- .../attributes/EnclosingMethodAttribute.java | 5 +- .../attributes/ExceptionsAttribute.java | 5 +- .../attributes/InnerClassesAttribute.java | 5 +- .../attributes/LineNumberTableAttribute.java | 6 +- .../attributes}/LineNumberTableRef.java | 2 +- .../espresso/classfile/attributes/Local.java | 31 +- .../classfile/attributes}/LocalRef.java | 2 +- .../attributes/LocalVariableTable.java | 6 +- .../attributes}/LocalVariableTableRef.java | 2 +- .../attributes/MethodParametersAttribute.java | 5 +- .../attributes/NestHostAttribute.java | 5 +- .../attributes/NestMembersAttribute.java | 5 +- .../PermittedSubclassesAttribute.java | 5 +- .../classfile/attributes/RecordAttribute.java | 74 ++ .../attributes/SignatureAttribute.java | 5 +- .../SourceDebugExtensionAttribute.java | 5 +- .../attributes/SourceFileAttribute.java | 5 +- .../attributes/StackMapTableAttribute.java | 5 +- .../bytecode/BytecodeLookupSwitch.java | 4 +- .../classfile}/bytecode/BytecodeStream.java | 112 +-- .../classfile}/bytecode/BytecodeSwitch.java | 6 +- .../bytecode/BytecodeTableSwitch.java | 4 +- .../classfile}/bytecode/Bytecodes.java | 34 +- .../espresso/classfile}/bytecode/Bytes.java | 4 +- .../bytecode}/VolatileArrayAccess.java | 2 +- .../constantpool/BootstrapMethodConstant.java | 4 +- .../classfile/constantpool/ClassConstant.java | 112 +++ .../constantpool/ClassMethodRefConstant.java | 66 ++ .../constantpool/DoubleConstant.java | 0 .../constantpool/DynamicConstant.java | 69 ++ .../constantpool/FieldRefConstant.java | 60 ++ .../classfile/constantpool/FloatConstant.java | 0 .../constantpool/IntegerConstant.java | 0 .../InterfaceMethodRefConstant.java | 43 + .../constantpool/InvalidConstant.java | 0 .../constantpool/InvokeDynamicConstant.java | 82 ++ .../classfile/constantpool/LongConstant.java | 0 .../constantpool/MemberRefConstant.java | 107 +++ .../constantpool/MethodHandleConstant.java | 173 ++++ .../constantpool/MethodRefConstant.java | 15 +- .../constantpool/MethodTypeConstant.java | 83 ++ .../constantpool/NameAndTypeConstant.java | 19 +- .../classfile/constantpool/PoolConstant.java | 19 +- .../classfile/constantpool/Resolvable.java | 9 +- .../constantpool/StringConstant.java | 61 +- .../classfile/constantpool/Utf8Constant.java | 93 ++- .../classfile}/descriptors/ByteSequence.java | 11 +- .../classfile/descriptors/ErrorUtil.java | 44 + .../classfile/descriptors}/ModifiedUtf8.java | 2 +- .../classfile}/descriptors/Names.java | 4 +- .../classfile}/descriptors/Signatures.java | 31 +- .../classfile}/descriptors/StaticSymbols.java | 17 +- .../classfile}/descriptors/Symbol.java | 17 +- .../classfile}/descriptors/SymbolKey.java | 2 +- .../classfile}/descriptors/Symbols.java | 2 +- .../classfile}/descriptors/Types.java | 49 +- .../descriptors/Utf8ConstantTable.java | 11 +- .../classfile}/descriptors/Validation.java | 5 +- .../descriptors/ValidationException.java | 47 ++ .../classfile}/perf/DebugCloseable.java | 2 +- .../classfile}/perf/DebugCounter.java | 22 +- .../espresso/classfile}/perf/DebugTimer.java | 8 +- .../classfile}/perf/TimerCollection.java | 2 +- .../classfile}/perf/TimerCollectionImpl.java | 2 +- .../truffle/espresso/jdwp/api/MethodRef.java | 2 + .../espresso/jdwp/api/TagConstants.java | 27 + .../truffle/espresso/jdwp/impl/JDWP.java | 4 +- .../processor/SubstitutionProcessor.java | 2 +- .../.checkstyle_checks.xml | 2 +- .../truffle/espresso/EspressoLanguage.java | 22 +- .../truffle/espresso/EspressoOptions.java | 6 +- .../truffle/espresso/EspressoScope.java | 9 +- .../espresso/analysis/BlockIterator.java | 2 +- .../analysis/BlockIteratorClosure.java | 2 +- .../espresso/analysis/GraphBuilder.java | 18 +- .../frame/EspressoFrameDescriptor.java | 6 +- .../analysis/frame/FrameAnalysis.java | 422 +++++----- .../espresso/analysis/frame/FrameType.java | 8 +- .../graph/EspressoExecutionGraph.java | 2 +- .../DefaultClassHierarchyOracle.java | 2 +- .../liveness/BlockBoundaryFinder.java | 2 +- .../analysis/liveness/LivenessAnalysis.java | 8 +- .../analysis/liveness/LoadStoreFinder.java | 92 +-- .../liveness/LoopPropagatorClosure.java | 2 +- .../espresso/bytecode/BytecodePrinter.java | 142 ++++ .../truffle/espresso/bytecode/MapperBCI.java | 1 + .../espresso/classfile/ConstantPool.java | 656 --------------- .../truffle/espresso/classfile/Constants.java | 711 ---------------- .../classfile/RuntimeConstantPool.java | 244 ------ .../attributes/BootstrapMethodsAttribute.java | 123 --- .../classfile/attributes/RecordAttribute.java | 108 --- .../classfile/constantpool/ClassConstant.java | 291 ------- .../constantpool/ClassMethodRefConstant.java | 255 ------ .../constantpool/DynamicConstant.java | 328 -------- .../constantpool/FieldRefConstant.java | 245 ------ .../InterfaceMethodRefConstant.java | 151 ---- .../constantpool/InvokeDynamicConstant.java | 397 --------- .../constantpool/MemberRefConstant.java | 184 ----- .../constantpool/MethodHandleConstant.java | 310 ------- .../constantpool/MethodTypeConstant.java | 147 ---- .../espresso/constantpool/CallSiteLink.java | 63 ++ .../constantpool/CallSiteLinkingFailure.java | 45 ++ .../FailInvokeDynamicConstant.java | 90 +++ .../LinkableInvokeDynamicConstant.java | 32 + .../constantpool/MissingFieldRefConstant.java | 80 ++ .../NeedsFreshResolutionException.java | 2 +- .../PreResolvedClassConstant.java | 62 ++ .../constantpool/PreResolvedConstant.java | 54 ++ .../espresso/constantpool/Resolution.java | 760 ++++++++++++++++++ .../constantpool/ResolvedClassConstant.java | 50 ++ .../ResolvedClassMethodRefConstant.java | 62 ++ .../ResolvedDoubleDynamicConstant.java | 51 ++ .../constantpool/ResolvedDynamicConstant.java | 54 ++ .../ResolvedFailDynamicConstant.java | 60 ++ .../ResolvedFieldRefConstant.java | 68 ++ .../ResolvedFloatDynamicConstant.java | 51 ++ .../ResolvedIntDynamicConstant.java | 51 ++ .../ResolvedInterfaceMethodRefConstant.java | 63 ++ .../ResolvedInvokeDynamicConstant.java | 219 +++++ .../ResolvedLongDynamicConstant.java | 51 ++ .../ResolvedMethodHandleConstant.java | 53 ++ .../ResolvedMethodTypeConstant.java | 53 ++ .../ResolvedObjectDynamicConstant.java | 52 ++ .../constantpool/ResolvedStringConstant.java | 53 ++ ...lvedWithInvokerClassMethodRefConstant.java | 48 ++ .../constantpool/RuntimeConstantPool.java | 381 +++++++++ .../truffle/espresso/ffi/NativeAccess.java | 2 +- .../espresso/ffi/TruffleByteBuffer.java | 2 +- .../espresso/ffi/nfi/NFINativeAccess.java | 2 +- .../truffle/espresso/ffi/nfi/NativeUtils.java | 4 +- .../truffle/espresso/impl/ArrayKlass.java | 10 +- .../espresso/impl/BootClassRegistry.java | 14 +- .../espresso/impl/ClassLoadingEnv.java | 96 ++- .../espresso/impl/ClassRegistries.java | 6 +- .../truffle/espresso/impl/ClassRegistry.java | 47 +- .../espresso/impl/ConstantPoolPatcher.java | 15 +- .../espresso/impl/ContextDescription.java | 2 +- .../truffle/espresso/impl/EntryTable.java | 4 +- .../espresso/impl/EnumConstantField.java | 4 +- .../impl/ExtensionFieldsMetadata.java | 5 +- .../oracle/truffle/espresso/impl/Field.java | 17 +- .../espresso/impl/GuestClassRegistry.java | 12 +- .../espresso/impl/InterfaceTables.java | 6 +- .../oracle/truffle/espresso/impl/Klass.java | 19 +- .../truffle/espresso/impl/LanguageAccess.java | 8 +- .../truffle/espresso/impl/LinkedField.java | 42 +- .../truffle/espresso/impl/LinkedKlass.java | 23 +- .../espresso/impl/LinkedKlassFieldLayout.java | 14 +- .../truffle/espresso/impl/LinkedMethod.java | 9 +- .../espresso/impl/LoadingConstraints.java | 8 +- .../oracle/truffle/espresso/impl/Member.java | 6 +- .../oracle/truffle/espresso/impl/Method.java | 46 +- .../truffle/espresso/impl/ModuleTable.java | 4 +- .../truffle/espresso/impl/ObjectKlass.java | 25 +- .../truffle/espresso/impl/PackageTable.java | 4 +- .../truffle/espresso/impl/PrimitiveKlass.java | 8 +- .../espresso/impl/RedefineAddedEnumField.java | 2 +- .../espresso/impl/RedefineAddedField.java | 4 +- .../truffle/espresso/impl/VirtualTable.java | 2 +- .../oracle/truffle/espresso/jni/JniEnv.java | 17 +- .../truffle/espresso/jni/JniVersion.java | 2 +- .../oracle/truffle/espresso/jni/Mangle.java | 6 +- .../truffle/espresso/jni/RawBuffer.java | 2 +- .../espresso/meta/DiffVersionLoadHelper.java | 10 +- .../espresso/meta/ExceptionDispatch.java | 2 +- .../oracle/truffle/espresso/meta/Meta.java | 27 +- .../truffle/espresso/meta/MetaUtil.java | 1 + .../AbstractInstrumentableBytecodeNode.java | 28 +- .../truffle/espresso/nodes/BytecodeNode.java | 457 +++++------ .../truffle/espresso/nodes/EspressoFrame.java | 10 +- .../truffle/espresso/nodes/EspressoNode.java | 8 +- .../nodes/IntrinsicSubstitutorNode.java | 2 +- .../espresso/nodes/NativeMethodNode.java | 10 +- .../espresso/nodes/SubstitutionScope.java | 4 +- .../nodes/commands/ReferenceProcessCache.java | 6 +- .../nodes/helper/AbstractGetFieldNode.java | 2 +- .../nodes/helper/AbstractSetFieldNode.java | 2 +- .../interop/AbstractLookupFieldNode.java | 4 +- .../nodes/interop/AbstractLookupNode.java | 6 +- .../EspressoForeignProxyGenerator.java | 4 +- .../nodes/interop/LookupFieldNode.java | 4 +- .../nodes/interop/LookupProxyKlassNode.java | 2 +- .../nodes/interop/PolyglotTypeMappings.java | 2 +- .../methodhandle/MHInvokeGenericNode.java | 8 +- .../methodhandle/MHLinkToNativeNode.java | 2 +- .../nodes/methodhandle/MHLinkToNode.java | 8 +- .../MethodHandleIntrinsicNode.java | 4 +- .../nodes/quick/CheckCastQuickNode.java | 2 +- .../nodes/quick/InstanceOfQuickNode.java | 2 +- .../quick/interop/ArrayLengthQuickNode.java | 2 +- .../quick/interop/ByteArrayLoadQuickNode.java | 2 +- .../interop/ByteArrayStoreQuickNode.java | 2 +- .../quick/interop/CharArrayLoadQuickNode.java | 2 +- .../interop/CharArrayStoreQuickNode.java | 2 +- .../interop/DoubleArrayLoadQuickNode.java | 2 +- .../interop/DoubleArrayStoreQuickNode.java | 2 +- .../interop/FloatArrayLoadQuickNode.java | 2 +- .../interop/FloatArrayStoreQuickNode.java | 2 +- .../quick/interop/IntArrayLoadQuickNode.java | 2 +- .../quick/interop/IntArrayStoreQuickNode.java | 2 +- .../quick/interop/LongArrayLoadQuickNode.java | 2 +- .../interop/LongArrayStoreQuickNode.java | 2 +- .../interop/ReferenceArrayLoadQuickNode.java | 2 +- .../interop/ReferenceArrayStoreQuickNode.java | 2 +- .../interop/ShortArrayLoadQuickNode.java | 2 +- .../interop/ShortArrayStoreQuickNode.java | 2 +- .../invoke/InvokeDynamicCallSiteNode.java | 10 +- .../nodes/quick/invoke/InvokeQuickNode.java | 2 +- .../quick/invoke/InvokeStaticQuickNode.java | 2 +- .../inline/bodies/InlinedFieldAccessNode.java | 2 +- .../preinit/CachedLinkedKlassProvider.java | 2 +- .../preinit/CachedParserKlassProvider.java | 4 +- .../preinit/ContextPatchingException.java | 2 +- .../preinit/DefaultLinkedKlassProvider.java | 2 +- .../preinit/DefaultParserKlassProvider.java | 14 +- .../preinit/EspressoLanguageCache.java | 4 +- .../espresso/preinit/LinkedKlassProvider.java | 2 +- .../espresso/preinit/ParserKlassProvider.java | 47 +- .../espresso/redefinition/ChangePacket.java | 2 +- .../espresso/redefinition/ClassInfo.java | 32 +- .../redefinition/ClassRedefinition.java | 64 +- .../espresso/redefinition/DetectedChange.java | 6 +- .../redefinition/HotSwapClassInfo.java | 2 +- .../redefinition/ImmutableClassInfo.java | 2 +- .../redefinition/InnerClassRedefiner.java | 37 +- .../plugins/enums/EnumRedefinitionPlugin.java | 2 +- .../impl/RedefinitionPluginHandler.java | 2 +- .../espresso/ref/FinalizationSupport.java | 2 +- .../espresso/resolver/CallSiteType.java | 2 +- .../espresso/resolver/LinkResolver.java | 10 +- .../truffle/espresso/runtime/Classpath.java | 89 +- .../espresso/runtime/EspressoContext.java | 21 +- .../truffle/espresso/runtime/EspressoEnv.java | 2 +- .../runtime/EspressoShutdownHandler.java | 4 +- .../espresso/runtime/GuestAllocator.java | 2 +- .../espresso/runtime/JDWPContextImpl.java | 6 +- .../espresso/runtime/JImageHelper.java | 2 +- .../espresso/runtime/JImageLibrary.java | 8 +- .../espresso/runtime/JavaJImageHelper.java | 4 +- .../espresso/runtime/LazyContextCaches.java | 2 +- .../runtime/MethodHandleIntrinsics.java | 10 +- .../espresso/runtime/NativeJImageHelper.java | 2 +- .../truffle/espresso/runtime/StringTable.java | 2 +- .../dispatch/staticobject/BaseInterop.java | 6 +- .../staticobject/ThrowableInterop.java | 2 +- .../runtime/jimage/BasicImageReader.java | 2 +- .../runtime/jimage/ImageLocation.java | 2 +- .../runtime/jimage/ImageStringsReader.java | 6 +- .../runtime/staticobject/StaticObject.java | 2 +- .../substitutions/JImageExtensions.java | 2 +- .../substitutions/JavaSubstitution.java | 2 +- .../espresso/substitutions/Substitutions.java | 12 +- .../Target_java_lang_System.java | 2 +- ..._java_lang_invoke_MethodHandleNatives.java | 77 +- .../Target_java_lang_reflect_Array.java | 2 +- .../Target_java_util_regex_Matcher.java | 2 +- ..._jdk_internal_misc_ScopedMemoryAccess.java | 3 +- ...ternal_module_ModuleLoaderMap_Modules.java | 6 +- .../substitutions/Target_sun_misc_Unsafe.java | 8 +- ..._sun_reflect_NativeMethodAccessorImpl.java | 10 +- .../espresso/substitutions/VersionFilter.java | 2 +- .../threads/EspressoThreadRegistry.java | 2 +- .../espresso/verifier/MethodVerifier.java | 473 +++++------ .../truffle/espresso/verifier/Operand.java | 6 +- .../truffle/espresso/verifier/StackFrame.java | 2 +- .../verifier/StackMapFrameParser.java | 12 +- .../verifier/VerificationTypeInfo.java | 8 +- .../truffle/espresso/vm/InterpreterToVM.java | 2 +- .../truffle/espresso/vm/Management.java | 4 +- .../truffle/espresso/vm/ModulesHelperVM.java | 2 +- .../oracle/truffle/espresso/vm/StackWalk.java | 6 +- .../com/oracle/truffle/espresso/vm/VM.java | 161 ++-- .../vm/continuation/HostFrameRecord.java | 14 +- .../truffle/espresso/vm/npe/Analysis.java | 418 +++++----- .../espresso/vm/npe/ExtendedNPEMessage.java | 2 +- .../espresso/vm/npe/MessageBuildHelper.java | 110 +-- .../truffle/espresso/vm/npe/StackType.java | 232 +++--- .../espresso/vm/structs/StructsAccess.java | 4 +- 298 files changed, 7426 insertions(+), 6930 deletions(-) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java (71%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/ClassfileStream.java (80%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClasspathEntry.java rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/ClasspathFile.java (80%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ConstantPool.java create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/Constants.java rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/ExceptionHandler.java (95%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/ImmutableConstantPool.java (84%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/JavaKind.java (71%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/JavaVersion.java (98%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserException.java rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/ParserField.java (65%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/ParserKlass.java (87%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/ParserMethod.java (83%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParsingContext.java rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes}/Attribute.java (92%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/BootstrapMethodsAttribute.java rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/CodeAttribute.java (82%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/ConstantValueAttribute.java (94%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/EnclosingMethodAttribute.java (90%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/ExceptionsAttribute.java (90%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/InnerClassesAttribute.java (92%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/LineNumberTableAttribute.java (95%) rename espresso/src/{com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes}/LineNumberTableRef.java (96%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/Local.java (78%) rename espresso/src/{com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes}/LocalRef.java (97%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/LocalVariableTable.java (93%) rename espresso/src/{com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes}/LocalVariableTableRef.java (95%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/MethodParametersAttribute.java (94%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/NestHostAttribute.java (89%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/NestMembersAttribute.java (90%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/PermittedSubclassesAttribute.java (91%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/RecordAttribute.java rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/SignatureAttribute.java (89%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/SourceDebugExtensionAttribute.java (90%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/SourceFileAttribute.java (89%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/attributes/StackMapTableAttribute.java (89%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/bytecode/BytecodeLookupSwitch.java (94%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/bytecode/BytecodeStream.java (67%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/bytecode/BytecodeSwitch.java (95%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/bytecode/BytecodeTableSwitch.java (95%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/bytecode/Bytecodes.java (97%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/bytecode/Bytes.java (97%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode}/VolatileArrayAccess.java (97%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/constantpool/BootstrapMethodConstant.java (94%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/ClassConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/ClassMethodRefConstant.java rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/constantpool/DoubleConstant.java (100%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/DynamicConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/FieldRefConstant.java rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/constantpool/FloatConstant.java (100%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/constantpool/IntegerConstant.java (100%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/InterfaceMethodRefConstant.java rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/constantpool/InvalidConstant.java (100%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/InvokeDynamicConstant.java rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/constantpool/LongConstant.java (100%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MemberRefConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MethodHandleConstant.java rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/constantpool/MethodRefConstant.java (79%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MethodTypeConstant.java rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/constantpool/NameAndTypeConstant.java (85%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/constantpool/PoolConstant.java (85%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/constantpool/Resolvable.java (81%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/constantpool/StringConstant.java (55%) rename espresso/src/{com.oracle.truffle.espresso => com.oracle.truffle.espresso.classfile}/src/com/oracle/truffle/espresso/classfile/constantpool/Utf8Constant.java (53%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/descriptors/ByteSequence.java (94%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ErrorUtil.java rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors}/ModifiedUtf8.java (99%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/descriptors/Names.java (93%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/descriptors/Signatures.java (91%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/descriptors/StaticSymbols.java (79%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/descriptors/Symbol.java (99%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/descriptors/SymbolKey.java (97%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/descriptors/Symbols.java (98%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/descriptors/Types.java (87%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/descriptors/Utf8ConstantTable.java (92%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/descriptors/Validation.java (98%) create mode 100644 espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ValidationException.java rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/perf/DebugCloseable.java (95%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/perf/DebugCounter.java (80%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/perf/DebugTimer.java (94%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/perf/TimerCollection.java (96%) rename espresso/src/{com.oracle.truffle.espresso/src/com/oracle/truffle/espresso => com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile}/perf/TimerCollectionImpl.java (98%) create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodePrinter.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ConstantPool.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/Constants.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/RuntimeConstantPool.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/BootstrapMethodsAttribute.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/RecordAttribute.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/ClassConstant.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/ClassMethodRefConstant.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/DynamicConstant.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/FieldRefConstant.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/InterfaceMethodRefConstant.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/InvokeDynamicConstant.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MemberRefConstant.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MethodHandleConstant.java delete mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MethodTypeConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/CallSiteLink.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/CallSiteLinkingFailure.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/FailInvokeDynamicConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/LinkableInvokeDynamicConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/MissingFieldRefConstant.java rename espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/{classfile => }/constantpool/NeedsFreshResolutionException.java (95%) create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/PreResolvedClassConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/PreResolvedConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/Resolution.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedClassConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedClassMethodRefConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedDoubleDynamicConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedDynamicConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedFailDynamicConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedFieldRefConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedFloatDynamicConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedIntDynamicConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedInterfaceMethodRefConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedInvokeDynamicConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedLongDynamicConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedMethodHandleConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedMethodTypeConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedObjectDynamicConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedStringConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedWithInvokerClassMethodRefConstant.java create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/RuntimeConstantPool.java diff --git a/espresso/mx.espresso/suite.py b/espresso/mx.espresso/suite.py index d873664eb3b7..6d1ebdbf66bb 100644 --- a/espresso/mx.espresso/suite.py +++ b/espresso/mx.espresso/suite.py @@ -116,6 +116,19 @@ "license": "UPL", }, + # Shared .class file parser + "com.oracle.truffle.espresso.classfile": { + "subDir": "src", + "sourceDirs": ["src"], + "dependencies": [ + "truffle:TRUFFLE_API", + ], + "requires": [ + ], + "javaCompliance" : "17+", + "checkstyle": "com.oracle.truffle.espresso", + }, + "com.oracle.truffle.espresso": { "subDir": "src", "sourceDirs": ["src"], @@ -189,6 +202,7 @@ "subDir": "src", "sourceDirs": ["src"], "dependencies": [ + "com.oracle.truffle.espresso.classfile", "truffle:TRUFFLE_API", "truffle:TRUFFLE_NFI", ], diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java similarity index 71% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java index d407c84b9b49..942978f7985d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClassfileParser.java @@ -22,7 +22,67 @@ */ package com.oracle.truffle.espresso.classfile; -import static com.oracle.truffle.espresso.EspressoOptions.SpecComplianceMode.STRICT; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.ModifiedUtf8; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; +import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; +import com.oracle.truffle.espresso.classfile.attributes.Attribute; +import com.oracle.truffle.espresso.classfile.attributes.BootstrapMethodsAttribute; +import com.oracle.truffle.espresso.classfile.attributes.CodeAttribute; +import com.oracle.truffle.espresso.classfile.attributes.ConstantValueAttribute; +import com.oracle.truffle.espresso.classfile.attributes.EnclosingMethodAttribute; +import com.oracle.truffle.espresso.classfile.attributes.ExceptionsAttribute; +import com.oracle.truffle.espresso.classfile.attributes.InnerClassesAttribute; +import com.oracle.truffle.espresso.classfile.attributes.LineNumberTableAttribute; +import com.oracle.truffle.espresso.classfile.attributes.Local; +import com.oracle.truffle.espresso.classfile.attributes.LocalVariableTable; +import com.oracle.truffle.espresso.classfile.attributes.MethodParametersAttribute; +import com.oracle.truffle.espresso.classfile.attributes.NestHostAttribute; +import com.oracle.truffle.espresso.classfile.attributes.NestMembersAttribute; +import com.oracle.truffle.espresso.classfile.attributes.PermittedSubclassesAttribute; +import com.oracle.truffle.espresso.classfile.attributes.RecordAttribute; +import com.oracle.truffle.espresso.classfile.attributes.SignatureAttribute; +import com.oracle.truffle.espresso.classfile.attributes.SourceDebugExtensionAttribute; +import com.oracle.truffle.espresso.classfile.attributes.SourceFileAttribute; +import com.oracle.truffle.espresso.classfile.attributes.StackMapTableAttribute; +import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; +import com.oracle.truffle.espresso.classfile.constantpool.ClassMethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.DoubleConstant; +import com.oracle.truffle.espresso.classfile.constantpool.DynamicConstant; +import com.oracle.truffle.espresso.classfile.constantpool.FieldRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.FloatConstant; +import com.oracle.truffle.espresso.classfile.constantpool.IntegerConstant; +import com.oracle.truffle.espresso.classfile.constantpool.InterfaceMethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.InvalidConstant; +import com.oracle.truffle.espresso.classfile.constantpool.InvokeDynamicConstant; +import com.oracle.truffle.espresso.classfile.constantpool.LongConstant; +import com.oracle.truffle.espresso.classfile.constantpool.MethodHandleConstant; +import com.oracle.truffle.espresso.classfile.constantpool.MethodTypeConstant; +import com.oracle.truffle.espresso.classfile.constantpool.NameAndTypeConstant; +import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant; +import com.oracle.truffle.espresso.classfile.constantpool.StringConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Utf8Constant; +import com.oracle.truffle.espresso.classfile.perf.DebugCloseable; +import com.oracle.truffle.espresso.classfile.perf.DebugCounter; +import com.oracle.truffle.espresso.classfile.perf.DebugTimer; +import org.graalvm.collections.EconomicMap; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.MODULE; +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.PACKAGE; import static com.oracle.truffle.espresso.classfile.Constants.ACC_ABSTRACT; import static com.oracle.truffle.espresso.classfile.Constants.ACC_ANNOTATION; import static com.oracle.truffle.espresso.classfile.Constants.ACC_CALLER_SENSITIVE; @@ -51,60 +111,6 @@ import static com.oracle.truffle.espresso.classfile.Constants.JVM_RECOGNIZED_CLASS_MODIFIERS; import static com.oracle.truffle.espresso.classfile.Constants.JVM_RECOGNIZED_METHOD_MODIFIERS; -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -import org.graalvm.collections.EconomicMap; - -import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; -import com.oracle.truffle.espresso.classfile.attributes.BootstrapMethodsAttribute; -import com.oracle.truffle.espresso.classfile.attributes.CodeAttribute; -import com.oracle.truffle.espresso.classfile.attributes.ConstantValueAttribute; -import com.oracle.truffle.espresso.classfile.attributes.EnclosingMethodAttribute; -import com.oracle.truffle.espresso.classfile.attributes.ExceptionsAttribute; -import com.oracle.truffle.espresso.classfile.attributes.InnerClassesAttribute; -import com.oracle.truffle.espresso.classfile.attributes.LineNumberTableAttribute; -import com.oracle.truffle.espresso.classfile.attributes.Local; -import com.oracle.truffle.espresso.classfile.attributes.LocalVariableTable; -import com.oracle.truffle.espresso.classfile.attributes.MethodParametersAttribute; -import com.oracle.truffle.espresso.classfile.attributes.NestHostAttribute; -import com.oracle.truffle.espresso.classfile.attributes.NestMembersAttribute; -import com.oracle.truffle.espresso.classfile.attributes.PermittedSubclassesAttribute; -import com.oracle.truffle.espresso.classfile.attributes.RecordAttribute; -import com.oracle.truffle.espresso.classfile.attributes.SignatureAttribute; -import com.oracle.truffle.espresso.classfile.attributes.SourceDebugExtensionAttribute; -import com.oracle.truffle.espresso.classfile.attributes.SourceFileAttribute; -import com.oracle.truffle.espresso.classfile.attributes.StackMapTableAttribute; -import com.oracle.truffle.espresso.classfile.constantpool.Utf8Constant; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.ModifiedUTF8; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; -import com.oracle.truffle.espresso.impl.ClassLoadingEnv; -import com.oracle.truffle.espresso.impl.ClassRegistry; -import com.oracle.truffle.espresso.impl.ParserField; -import com.oracle.truffle.espresso.impl.ParserKlass; -import com.oracle.truffle.espresso.impl.ParserMethod; -import com.oracle.truffle.espresso.jni.ModifiedUtf8; -import com.oracle.truffle.espresso.meta.ExceptionHandler; -import com.oracle.truffle.espresso.meta.JavaKind; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.perf.DebugCloseable; -import com.oracle.truffle.espresso.perf.DebugTimer; -import com.oracle.truffle.espresso.runtime.Attribute; -import com.oracle.truffle.espresso.runtime.ClasspathFile; -import com.oracle.truffle.espresso.runtime.EspressoContext; -import com.oracle.truffle.espresso.runtime.EspressoException; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; -import com.oracle.truffle.espresso.verifier.MethodVerifier; - @SuppressWarnings("try") public final class ClassfileParser { @@ -125,6 +131,8 @@ public final class ClassfileParser { private static final DebugTimer CODE_READ = DebugTimer.create("code read", CODE_PARSE); private static final DebugTimer EXCEPTION_HANDLERS = DebugTimer.create("exception handlers", CODE_PARSE); + private static final DebugCounter UTF8_ENTRY_COUNT = DebugCounter.create("UTF8 Constant Pool entries"); + public static final int MAGIC = 0xCAFEBABE; public static final int JAVA_1_1_VERSION = 45; @@ -145,6 +153,14 @@ public final class ClassfileParser { public static final int JAVA_15_VERSION = 59; public static final int JAVA_16_VERSION = 60; public static final int JAVA_17_VERSION = 61; + public static final int JAVA_18_VERSION = 62; + public static final int JAVA_19_VERSION = 63; + public static final int JAVA_20_VERSION = 64; + public static final int JAVA_21_VERSION = 65; + public static final int JAVA_22_VERSION = 66; + public static final int JAVA_23_VERSION = 67; + public static final int JAVA_24_VERSION = 68; + public static final int JAVA_25_VERSION = 69; public static final int STRICTER_ACCESS_CTRL_CHECK_VERSION = JAVA_1_5_VERSION; public static final int STACKMAP_ATTRIBUTE_MAJOR_VERSION = JAVA_6_VERSION; @@ -156,16 +172,14 @@ public final class ClassfileParser { public static final char JAVA_MAX_SUPPORTED_MINOR_VERSION = 0; public static final char JAVA_PREVIEW_MINOR_VERSION = 65535; - private final ClasspathFile classfile; - private final Symbol requestedClassType; - private final ClassLoadingEnv env; + private final ParsingContext parsingContext; private final ClassfileStream stream; - private final ClassRegistry.ClassDefinitionInfo classDefinitionInfo; private final boolean loaderIsBootOrPlatform; + private final boolean isHidden; private Symbol classType; @@ -176,23 +190,24 @@ public final class ClassfileParser { private int maxBootstrapMethodAttrIndex = -1; private Tag badConstantSeen; - boolean verifiable; + private final boolean verifiable; private ImmutableConstantPool pool; + private final boolean validate; - private ClassfileParser(ClassLoadingEnv env, ClassfileStream stream, boolean verifiable, boolean loaderIsBootOrPlatform, Symbol requestedClassType, ClassRegistry.ClassDefinitionInfo info) { + private ClassfileParser(ParsingContext parsingContext, ClassfileStream stream, boolean verifiable, boolean loaderIsBootOrPlatform, Symbol requestedClassType, boolean isHidden) { this.requestedClassType = requestedClassType; - this.env = env; - this.classfile = null; + this.parsingContext = parsingContext; this.stream = Objects.requireNonNull(stream); this.verifiable = verifiable; this.loaderIsBootOrPlatform = loaderIsBootOrPlatform; - this.classDefinitionInfo = info; + this.isHidden = isHidden; + this.validate = true; // always validate } // Note: only used for reading the class name from class bytes - private ClassfileParser(ClassLoadingEnv env, ClassfileStream stream) { - this(env, stream, false, false, null, ClassRegistry.ClassDefinitionInfo.EMPTY); + private ClassfileParser(ParsingContext parsingContext, ClassfileStream stream) { + this(parsingContext, stream, false, false, null, false); } void handleBadConstant(Tag tag, ClassfileStream s) { @@ -202,10 +217,18 @@ void handleBadConstant(Tag tag, ClassfileStream s) { badConstantSeen = tag; } } else { - throw stream.classFormatError("Unknown constant tag %d", tag.getValue()); + throw classFormatError("Unknown constant tag " + tag.getValue()); } } + private static ParserException classFormatError(String message) { + throw new ParserException.ClassFormatError(message); + } + + private static ParserException noClassDefFoundError(String message) { + throw new ParserException.NoClassDefFoundError(message); + } + void updateMaxBootstrapMethodAttrIndex(int bsmAttrIndex) { if (maxBootstrapMethodAttrIndex < bsmAttrIndex) { maxBootstrapMethodAttrIndex = bsmAttrIndex; @@ -214,33 +237,28 @@ void updateMaxBootstrapMethodAttrIndex(int bsmAttrIndex) { void checkInvokeDynamicSupport(Tag tag) { if (majorVersion < INVOKEDYNAMIC_MAJOR_VERSION) { - throw stream.classFormatError("Class file version does not support constant tag %d", tag.getValue()); + throw classFormatError("Class file version does not support constant tag " + tag.getValue()); } } void checkDynamicConstantSupport(Tag tag) { if (majorVersion < DYNAMICCONSTANT_MAJOR_VERSION) { - throw stream.classFormatError("Class file version does not support constant tag %d", tag.getValue()); + throw classFormatError("Class file version does not support constant tag " + tag.getValue()); } } - public static ParserKlass parse(ClassLoadingEnv env, ClassfileStream stream, StaticObject loader, Symbol requestedClassName) { - boolean verifiable = MethodVerifier.needsVerify(env.getLanguage(), loader); - return parse(env, stream, verifiable, env.loaderIsBootOrPlatform(loader), requestedClassName, ClassRegistry.ClassDefinitionInfo.EMPTY); - } - - public static ParserKlass parse(ClassLoadingEnv env, ClassfileStream stream, boolean verifiable, boolean loaderIsBootOrPlatform, Symbol requestedClassType, - ClassRegistry.ClassDefinitionInfo info) { - return new ClassfileParser(env, stream, verifiable, loaderIsBootOrPlatform, requestedClassType, info).parseClass(); + public static ParserKlass parse(ParsingContext parsingContext, ClassfileStream stream, boolean verifiable, boolean loaderIsBootOrPlatform, Symbol requestedClassType, boolean isHidden) + throws ValidationException { + return new ClassfileParser(parsingContext, stream, verifiable, loaderIsBootOrPlatform, requestedClassType, isHidden).parseClass(); } - private ParserKlass parseClass() { - try (DebugCloseable parse = KLASS_PARSE.scope(env.getTimers())) { + private ParserKlass parseClass() throws ValidationException { + try (DebugCloseable parse = KLASS_PARSE.scope(parsingContext.getTimers())) { return parseClassImpl(); - } catch (EspressoException e) { + } catch (ParserException | ValidationException e) { throw e; } catch (Throwable e) { - env.getLogger().severe("Unexpected host exception " + e + " thrown during class parsing."); + parsingContext.getLogger().log("Unexpected host exception thrown during class parsing", e); throw e; } } @@ -248,7 +266,7 @@ private ParserKlass parseClass() { private void readMagic() { int magic = stream.readS4(); if (magic != MAGIC) { - throw ConstantPool.classFormatError("Invalid magic number 0x" + Integer.toHexString(magic)); + throw classFormatError("Invalid magic number 0x" + Integer.toHexString(magic)); } } @@ -259,12 +277,12 @@ private void readMagic() { * @param minor the minor version number */ private void verifyVersion(int major, int minor) { - if (env.getJavaVersion().java8OrEarlier()) { - versionCheck8OrEarlier(env.getJavaVersion().classFileVersion(), major, minor); - } else if (env.getJavaVersion().java11OrEarlier()) { - versionCheck11OrEarlier(env.getJavaVersion().classFileVersion(), major, minor); + if (parsingContext.getJavaVersion().java8OrEarlier()) { + versionCheck8OrEarlier(parsingContext.getJavaVersion().classFileVersion(), major, minor); + } else if (parsingContext.getJavaVersion().java11OrEarlier()) { + versionCheck11OrEarlier(parsingContext.getJavaVersion().classFileVersion(), major, minor); } else { - versionCheck12OrLater(env.getJavaVersion().classFileVersion(), major, minor, env.isPreviewEnabled()); + versionCheck12OrLater(parsingContext.getJavaVersion().classFileVersion(), major, minor, parsingContext.isPreviewEnabled()); } } @@ -313,7 +331,6 @@ private static void versionCheck11OrEarlier(int maxMajor, int major, int minor) * 0. *
    • Major_version = JVM_CLASSFILE_MAJOR_VERSION and minor_version = 65535 and * --enable-preview is present. - * */ private static void versionCheck12OrLater(int maxMajor, int major, int minor, boolean previewEnabled) { if (major >= JAVA_12_VERSION && major <= maxMajor && minor == 0) { @@ -328,16 +345,15 @@ private static void versionCheck12OrLater(int maxMajor, int major, int minor, bo throw unsupportedClassVersionError("Unsupported major.minor version " + major + "." + minor); } - private static EspressoException unsupportedClassVersionError(String message) { - Meta meta = EspressoContext.get(null).getMeta(); - throw meta.throwExceptionWithMessage(meta.java_lang_UnsupportedClassVersionError, message); + private static ParserException unsupportedClassVersionError(String message) { + return new ParserException.UnsupportedClassVersionError(message); } /** * Verifies that the flags for a class are valid. * * @param flags the flags to test - * @throws ClassFormatError if the flags are invalid + * @throws ParserException.ClassFormatError if the flags are invalid */ private static void verifyClassFlags(int flags, int majorVersion) { final boolean isInterface = (flags & ACC_INTERFACE) != 0; @@ -352,7 +368,7 @@ private static void verifyClassFlags(int flags, int majorVersion) { (isInterface && !isAbstract) || (isInterface && majorGte15 && (isSuper || isEnum)) || (!isInterface && majorGte15 && isAnnotation)) { - throw ConstantPool.classFormatError("Invalid class flags 0x" + Integer.toHexString(flags)); + throw classFormatError("Invalid class flags 0x" + Integer.toHexString(flags)); } } @@ -360,15 +376,173 @@ boolean hasSeenBadConstant() { return badConstantSeen != null; } - private ParserKlass parseClassImpl() { + /** + * Parses a constant pool from a class file. + */ + private ImmutableConstantPool parseConstantPool() throws ValidationException { + final int length = stream.readU2(); + if (length < 1) { + throw classFormatError("Invalid constant pool size (" + length + ")"); + } + int rawPoolStartPosition = stream.getPosition(); + final PoolConstant[] entries = new PoolConstant[length]; + entries[0] = InvalidConstant.VALUE; + + int i = 1; + while (i < length) { + final int tagByte = stream.readU1(); + final Tag tag = Tag.fromValue(tagByte); + if (tag == null) { + throw ValidationException.raise("Invalid constant pool entry type at index " + i); + } + // check version for the tag except for module/package entries which must cause NDCFE + if (!tag.isValidForVersion(getMajorVersion()) && tag != MODULE && tag != PACKAGE) { + throw ValidationException.raise("Class file version does not support constant tag " + tagByte + " in class file"); + } + switch (tag) { + case CLASS: { + int classNameIndex = stream.readU2(); + entries[i] = ClassConstant.create(classNameIndex); + break; + } + case STRING: { + int index = stream.readU2(); + if (index == 0 || index >= length) { + throw ValidationException.raise("Invalid String constant index " + (i - 1)); + } + entries[i] = StringConstant.create(index); + break; + } + case FIELD_REF: { + int classIndex = stream.readU2(); + int nameAndTypeIndex = stream.readU2(); + entries[i] = FieldRefConstant.create(classIndex, nameAndTypeIndex); + break; + } + case METHOD_REF: { + int classIndex = stream.readU2(); + int nameAndTypeIndex = stream.readU2(); + entries[i] = ClassMethodRefConstant.create(classIndex, nameAndTypeIndex); + break; + } + case INTERFACE_METHOD_REF: { + int classIndex = stream.readU2(); + int nameAndTypeIndex = stream.readU2(); + entries[i] = InterfaceMethodRefConstant.create(classIndex, nameAndTypeIndex); + break; + } + case NAME_AND_TYPE: { + int nameIndex = stream.readU2(); + int typeIndex = stream.readU2(); + entries[i] = NameAndTypeConstant.create(nameIndex, typeIndex); + break; + } + case INTEGER: { + entries[i] = IntegerConstant.create(stream.readS4()); + break; + } + case FLOAT: { + entries[i] = FloatConstant.create(stream.readFloat()); + break; + } + case LONG: { + entries[i] = LongConstant.create(stream.readS8()); + ++i; + try { + entries[i] = InvalidConstant.VALUE; + } catch (ArrayIndexOutOfBoundsException e) { + throw ValidationException.raise("Invalid long constant index " + (i - 1)); + } + break; + } + case DOUBLE: { + entries[i] = DoubleConstant.create(stream.readDouble()); + ++i; + try { + entries[i] = InvalidConstant.VALUE; + } catch (ArrayIndexOutOfBoundsException e) { + throw ValidationException.raise("Invalid double constant index " + (i - 1)); + } + break; + } + case UTF8: { + // Copy-less UTF8 constant. + // A new symbol is spawned (copy) only if doesn't already exists. + UTF8_ENTRY_COUNT.inc(); + ByteSequence bytes = stream.readByteSequenceUTF(); + entries[i] = parsingContext.getOrCreateUtf8Constant(bytes); + break; + } + case METHODHANDLE: { + checkInvokeDynamicSupport(tag); + int refKind = stream.readU1(); + int refIndex = stream.readU2(); + entries[i] = MethodHandleConstant.create(refKind, refIndex); + break; + } + case METHODTYPE: { + checkInvokeDynamicSupport(tag); + entries[i] = MethodTypeConstant.create(stream.readU2()); + break; + } + case DYNAMIC: { + checkDynamicConstantSupport(tag); + int bootstrapMethodAttrIndex = stream.readU2(); + int nameAndTypeIndex = stream.readU2(); + entries[i] = DynamicConstant.create(bootstrapMethodAttrIndex, nameAndTypeIndex); + updateMaxBootstrapMethodAttrIndex(bootstrapMethodAttrIndex); + break; + } + case INVOKEDYNAMIC: { + checkInvokeDynamicSupport(tag); + int bootstrapMethodAttrIndex = stream.readU2(); + int nameAndTypeIndex = stream.readU2(); + entries[i] = InvokeDynamicConstant.create(bootstrapMethodAttrIndex, nameAndTypeIndex); + updateMaxBootstrapMethodAttrIndex(bootstrapMethodAttrIndex); + break; + } + default: { + handleBadConstant(tag, stream); + break; + } + } + i++; + } + int rawPoolLength = stream.getPosition() - rawPoolStartPosition; + + ImmutableConstantPool constantPool = new ImmutableConstantPool(entries, majorVersion, minorVersion, rawPoolLength); + + if (hasSeenBadConstant()) { + return constantPool; + } + + // Cannot faithfully reconstruct patched pools. obtaining raw pool of patched/hidden class + // is meaningless anyway. + assert sameRawPool(constantPool, stream, rawPoolStartPosition, rawPoolLength); + + // Validation + if (validate) { + for (int j = 1; j < constantPool.length(); ++j) { + entries[j].validate(constantPool); + } + } + + return constantPool; + } + + private static boolean sameRawPool(ConstantPool constantPool, ClassfileStream stream, int rawPoolStartPosition, int rawPoolLength) { + return Arrays.equals(constantPool.getRawBytes(), stream.getByteRange(rawPoolStartPosition, rawPoolLength)); + } + + private ParserKlass parseClassImpl() throws ValidationException { readMagic(); minorVersion = stream.readU2(); majorVersion = stream.readU2(); verifyVersion(majorVersion, minorVersion); - try (DebugCloseable closeable = CONSTANT_POOL.scope(env.getTimers())) { - this.pool = ConstantPool.parse(env, stream, this, classDefinitionInfo.patches, majorVersion, minorVersion); + try (DebugCloseable closeable = CONSTANT_POOL.scope(parsingContext.getTimers())) { + this.pool = parseConstantPool(); } // JVM_ACC_MODULE is defined in JDK-9 and later. @@ -385,14 +559,14 @@ private ParserKlass parseClassImpl() { boolean isModule = (classFlags & ACC_MODULE) != 0; if (isModule) { - throw ConstantPool.noClassDefFoundError(classType + " is not a class because access_flag ACC_MODULE is set"); + throw noClassDefFoundError(classType + " is not a class because access_flag ACC_MODULE is set"); } if (hasSeenBadConstant()) { // Do not throw CFE until after the access_flags are checked because if // ACC_MODULE is set in the access flags, then NCDFE must be thrown, not CFE. // https://bugs.openjdk.java.net/browse/JDK-8175383 - throw ConstantPool.classFormatError(String.format("Unknown constant tag %s [in class file %s]", badConstantSeen, classfile)); + throw stream.classFormatError("Unknown constant tag " + badConstantSeen); } verifyClassFlags(classFlags, majorVersion); @@ -406,90 +580,80 @@ private ParserKlass parseClassImpl() { // TODO(peterssen): Verify class names. - Symbol thisKlassType = env.getTypes().fromName(thisKlassName); + Symbol thisKlassType = parsingContext.getOrCreateTypeFromName(thisKlassName); if (Types.isPrimitive(thisKlassType) || Types.isArray(thisKlassType)) { - throw ConstantPool.classFormatError(".this_class cannot be array nor primitive " + classType); + throw classFormatError(".this_class cannot be array nor primitive " + classType); } // Update classType which could be null previously to reflect the name in the constant pool. classType = thisKlassType; // Checks if name in class file matches requested name - if (requestedClassType != null && !classDefinitionInfo.isHidden() && !requestedClassType.equals(classType)) { - throw ConstantPool.noClassDefFoundError(classType + " (wrong name: " + requestedClassType + ")"); + if (requestedClassType != null && !isHidden && !requestedClassType.equals(classType)) { + throw noClassDefFoundError(classType + " (wrong name: " + requestedClassType + ")"); } Symbol superKlass = parseSuperKlass(); if (!Type.java_lang_Object.equals(classType) && superKlass == null) { - throw ConstantPool.classFormatError("Class " + classType + " must have a superclass"); + throw classFormatError("Class " + classType + " must have a superclass"); } if (isInterface && !Type.java_lang_Object.equals(superKlass)) { - throw ConstantPool.classFormatError("Interface " + classType + " must extend java.lang.Object"); + throw classFormatError("Interface " + classType + " must extend java.lang.Object"); } Symbol[] superInterfaces; - try (DebugCloseable closeable = PARSE_INTERFACES.scope(env.getTimers())) { + try (DebugCloseable closeable = PARSE_INTERFACES.scope(parsingContext.getTimers())) { superInterfaces = parseInterfaces(); } final ParserField[] fields; - try (DebugCloseable closeable = PARSE_FIELD.scope(env.getTimers())) { + try (DebugCloseable closeable = PARSE_FIELD.scope(parsingContext.getTimers())) { fields = parseFields(isInterface); } final ParserMethod[] methods; - try (DebugCloseable closeable = PARSE_METHODS.scope(env.getTimers())) { + try (DebugCloseable closeable = PARSE_METHODS.scope(parsingContext.getTimers())) { methods = parseMethods(isInterface); } final Attribute[] attributes; - try (DebugCloseable closeable = PARSE_CLASSATTR.scope(env.getTimers())) { + try (DebugCloseable closeable = PARSE_CLASSATTR.scope(parsingContext.getTimers())) { attributes = parseClassAttributes(); } // Ensure there are no trailing bytes stream.checkEndOfFile(); - if (classDefinitionInfo.isHidden()) { + long hiddenKlassId = -1; // no id + if (isHidden) { assert requestedClassType != null; - long futureKlassID = env.getNewKlassId(); - classDefinitionInfo.initKlassID(futureKlassID); - thisKlassName = env.getNames().getOrCreate(Types.hiddenClassName(requestedClassType, futureKlassID)); - thisKlassType = env.getTypes().fromName(thisKlassName); + hiddenKlassId = parsingContext.getNewKlassId(); + thisKlassName = parsingContext.getOrCreateName(Types.hiddenClassName(requestedClassType, hiddenKlassId)); + thisKlassType = parsingContext.getOrCreateTypeFromName(thisKlassName); pool = pool.patchForHiddenClass(thisKlassIndex, thisKlassName); + classFlags |= Constants.ACC_IS_HIDDEN_CLASS; } - return new ParserKlass(pool, classDefinitionInfo.patchFlags(classFlags), thisKlassName, thisKlassType, superKlass, superInterfaces, methods, fields, attributes, thisKlassIndex); + return new ParserKlass(pool, classFlags, thisKlassName, thisKlassType, superKlass, superInterfaces, methods, fields, attributes, thisKlassIndex, hiddenKlassId); } - public static Symbol getClassName(ClassLoadingEnv env, byte[] bytes) { - return new ClassfileParser(env, new ClassfileStream(bytes, null)).getClassName(); + public static Symbol getClassName(ParsingContext parsingContext, byte[] bytes) throws ValidationException { + return new ClassfileParser(parsingContext, new ClassfileStream(bytes, null)).getClassName(); } - private Symbol getClassName() { - + private Symbol getClassName() throws ValidationException { readMagic(); - minorVersion = stream.readU2(); majorVersion = stream.readU2(); verifyVersion(majorVersion, minorVersion); - - try (DebugCloseable closeable = CONSTANT_POOL.scope(env.getTimers())) { - this.pool = ConstantPool.parse(env, stream, this, classDefinitionInfo.patches, majorVersion, minorVersion); - } - - // JVM_ACC_MODULE is defined in JDK-9 and later. - if (majorVersion >= JAVA_9_VERSION) { - classFlags = stream.readU2() & (JVM_RECOGNIZED_CLASS_MODIFIERS | ACC_MODULE); - } else { - classFlags = stream.readU2() & (JVM_RECOGNIZED_CLASS_MODIFIERS); + try (DebugCloseable closeable = CONSTANT_POOL.scope(parsingContext.getTimers())) { + this.pool = parseConstantPool(); } - + stream.readU2(); // access flags int thisKlassIndex = stream.readU2(); - return pool.classAt(thisKlassIndex).getName(pool); } - private ParserMethod[] parseMethods(boolean isInterface) { + private ParserMethod[] parseMethods(boolean isInterface) throws ValidationException { int methodCount = stream.readU2(); if (methodCount == 0) { return ParserMethod.EMPTY_ARRAY; @@ -499,16 +663,16 @@ private ParserMethod[] parseMethods(boolean isInterface) { * Classes in general have lots of methods: use a hash set rather than array lookup for dup * check. */ - final HashSet dup = new HashSet<>(methodCount); + final HashSet dup = HashSet.newHashSet(methodCount); for (int i = 0; i < methodCount; ++i) { ParserMethod method; - try (DebugCloseable closeable = PARSE_SINGLE_METHOD.scope(env.getTimers())) { + try (DebugCloseable closeable = PARSE_SINGLE_METHOD.scope(parsingContext.getTimers())) { method = parseMethod(isInterface); } methods[i] = method; - try (DebugCloseable closeable = NO_DUP_CHECK.scope(env.getTimers())) { + try (DebugCloseable closeable = NO_DUP_CHECK.scope(parsingContext.getTimers())) { if (!dup.add(new MethodKey(method))) { - throw ConstantPool.classFormatError("Duplicate method name and signature: " + method.getName() + " " + method.getSignature()); + throw classFormatError("Duplicate method name and signature: " + method.getName() + " " + method.getSignature()); } } } @@ -523,7 +687,7 @@ private ParserMethod[] parseMethods(boolean isInterface) { * @param isInit true if the method is "" * @param isClinit true if the method is "" * @param majorVersion the version of the class file - * @throws ClassFormatError if the flags are invalid + * @throws ParserException.ClassFormatError if the flags are invalid */ private static void verifyMethodFlags(int flags, boolean isInterface, boolean isInit, boolean isClinit, int majorVersion) { // The checks below are based on JVMS8 4.6 @@ -591,7 +755,7 @@ private static void verifyMethodFlags(int flags, boolean isInterface, boolean is } } if (!valid) { - throw ConstantPool.classFormatError("Invalid method flags 0x" + Integer.toHexString(flags)); + throw classFormatError("Invalid method flags 0x" + Integer.toHexString(flags)); } } @@ -661,48 +825,48 @@ private class CommonAttributeParser { Attribute annotationDefault = null; Attribute signature = null; - Attribute parseCommonAttribute(Symbol attributeName, int attributeSize) { + Attribute parseCommonAttribute(Symbol attributeName, int attributeSize) throws ValidationException { if (infoType.supports(RUNTIME_VISIBLE_ANNOTATIONS) && attributeName.equals(Name.RuntimeVisibleAnnotations)) { if (runtimeVisibleAnnotations != null) { - throw ConstantPool.classFormatError("Duplicate RuntimeVisibleAnnotations attribute"); + throw classFormatError("Duplicate RuntimeVisibleAnnotations attribute"); } return runtimeVisibleAnnotations = new Attribute(attributeName, stream.readByteArray(attributeSize)); } else if (infoType.supports(RUNTIME_VISIBLE_TYPE_ANNOTATIONS) && attributeName.equals(Name.RuntimeVisibleTypeAnnotations)) { if (runtimeVisibleTypeAnnotations != null) { - throw ConstantPool.classFormatError("Duplicate RuntimeVisibleTypeAnnotations attribute"); + throw classFormatError("Duplicate RuntimeVisibleTypeAnnotations attribute"); } return runtimeVisibleTypeAnnotations = new Attribute(attributeName, stream.readByteArray(attributeSize)); } else if (infoType.supports(RUNTIME_INVISIBLE_ANNOTATIONS) && attributeName.equals(Name.RuntimeInvisibleAnnotations)) { if (runtimeInvisibleAnnotations != null) { - throw ConstantPool.classFormatError("Duplicate RuntimeVisibleTypeAnnotations attribute"); + throw classFormatError("Duplicate RuntimeVisibleTypeAnnotations attribute"); } return runtimeInvisibleAnnotations = new Attribute(attributeName, stream.readByteArray(attributeSize)); } else if (infoType.supports(RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) && attributeName.equals(Name.RuntimeInvisibleTypeAnnotations)) { if (runtimeInvisibleTypeAnnotations != null) { - throw ConstantPool.classFormatError("Duplicate RuntimeInvisibleTypeAnnotations attribute"); + throw classFormatError("Duplicate RuntimeInvisibleTypeAnnotations attribute"); } return runtimeInvisibleTypeAnnotations = new Attribute(attributeName, stream.readByteArray(attributeSize)); } else if (infoType.supports(RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS) && attributeName.equals(Name.RuntimeVisibleParameterAnnotations)) { if (runtimeVisibleParameterAnnotations != null) { - throw ConstantPool.classFormatError("Duplicate RuntimeVisibleParameterAnnotations attribute"); + throw classFormatError("Duplicate RuntimeVisibleParameterAnnotations attribute"); } return runtimeVisibleParameterAnnotations = new Attribute(attributeName, stream.readByteArray(attributeSize)); } else if (infoType.supports(RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS) && attributeName.equals(Name.RuntimeInvisibleParameterAnnotations)) { if (runtimeInvisibleParameterAnnotations != null) { - throw ConstantPool.classFormatError("Duplicate RuntimeVisibleParameterAnnotations attribute"); + throw classFormatError("Duplicate RuntimeVisibleParameterAnnotations attribute"); } return runtimeInvisibleParameterAnnotations = new Attribute(attributeName, stream.readByteArray(attributeSize)); } else if (infoType.supports(ANNOTATION_DEFAULT) && attributeName.equals(Name.AnnotationDefault)) { if (annotationDefault != null) { - throw ConstantPool.classFormatError("Duplicate AnnotationDefault attribute"); + throw classFormatError("Duplicate AnnotationDefault attribute"); } return annotationDefault = new Attribute(attributeName, stream.readByteArray(attributeSize)); } else if (infoType.supports(SIGNATURE) && attributeName.equals(Name.Signature)) { - if (env.getJavaVersion().java9OrLater() && signature != null) { - throw ConstantPool.classFormatError("Duplicate AnnotationDefault attribute"); + if (parsingContext.getJavaVersion().java9OrLater() && signature != null) { + throw classFormatError("Duplicate AnnotationDefault attribute"); } if (attributeSize != 2) { - throw ConstantPool.classFormatError("Invalid attribute_length value for signature attribute: " + attributeSize + " != 2"); + throw classFormatError("Invalid attribute_length value for signature attribute: " + attributeSize + " != 2"); } return signature = parseSignatureAttribute(attributeName); } @@ -712,14 +876,14 @@ Attribute parseCommonAttribute(Symbol attributeName, int attributeSize) { RuntimeVisibleAnnotationsAttribute parseRuntimeVisibleAnnotations(int attributeSize, AnnotationLocation location) { assert infoType.supports(RUNTIME_VISIBLE_ANNOTATIONS); if (runtimeVisibleAnnotations != null) { - throw ConstantPool.classFormatError("Duplicate RuntimeVisibleAnnotations attribute"); + throw classFormatError("Duplicate RuntimeVisibleAnnotations attribute"); } // Check for special internal annotations byte[] data = stream.readByteArray(attributeSize); - ClassfileStream subStream = new ClassfileStream(data, classfile); + ClassfileStream subStream = new ClassfileStream(data, stream.getClasspathFile()); int flags = 0; - if (loaderIsBootOrPlatform || classDefinitionInfo.forceAllowVMAnnotations()) { + if (loaderIsBootOrPlatform) { flags = switch (location) { case Method -> parseMethodVMAnnotations(subStream); case Field -> parseFieldVMAnnotations(subStream); @@ -739,7 +903,7 @@ private int parseMethodVMAnnotations(ClassfileStream subStream) { int typeIndex = parseAnnotation(subStream); Utf8Constant constant = pool.utf8At(typeIndex, "annotation type"); // Validation of the type is done at runtime by guest java code. - Symbol annotType = constant.value(); + Symbol annotType = constant.unsafeSymbolValue(); if (Type.java_lang_invoke_LambdaForm$Compiled.equals(annotType)) { flags |= ACC_LAMBDA_FORM_COMPILED; } else if (Type.java_lang_invoke_LambdaForm$Hidden.equals(annotType) || @@ -768,7 +932,7 @@ private int parseFieldVMAnnotations(ClassfileStream subStream) { int typeIndex = parseAnnotation(subStream); Utf8Constant constant = pool.utf8At(typeIndex, "annotation type"); // Validation of the type is done at runtime by guest java code. - Symbol annotType = constant.value(); + Symbol annotType = constant.unsafeSymbolValue(); if (Type.jdk_internal_vm_annotation_Stable.equals(annotType)) { flags |= ACC_STABLE; } @@ -777,7 +941,7 @@ private int parseFieldVMAnnotations(ClassfileStream subStream) { } } - private ParserMethod parseMethod(boolean isInterface) { + private ParserMethod parseMethod(boolean isInterface) throws ValidationException { int methodFlags = stream.readU2(); int nameIndex = stream.readU2(); int signatureIndex = stream.readU2(); @@ -790,11 +954,10 @@ private ParserMethod parseMethod(boolean isInterface) { boolean isClinit = false; boolean isInit = false; - try (DebugCloseable closeable = METHOD_INIT.scope(env.getTimers())) { + try (DebugCloseable closeable = METHOD_INIT.scope(parsingContext.getTimers())) { - try (DebugCloseable nameCheck = NAME_CHECK.scope(env.getTimers())) { - pool.utf8At(nameIndex).validateMethodName(true); - name = pool.symbolAt(nameIndex, "method name"); + try (DebugCloseable nameCheck = NAME_CHECK.scope(parsingContext.getTimers())) { + name = validateMethodName(pool.utf8At(nameIndex, "method name"), true); if (name.equals(Name._clinit_)) { // Class and interface initialization methods (3.9) are called @@ -806,14 +969,14 @@ private ParserMethod parseMethod(boolean isInterface) { methodFlags = ACC_STATIC; } else if ((methodFlags & ACC_STATIC) == ACC_STATIC) { methodFlags &= (ACC_STRICT | ACC_STATIC); - } else if (env.getJavaVersion().java9OrLater()) { - throw ConstantPool.classFormatError("Method is not static."); + } else if (parsingContext.getJavaVersion().java9OrLater()) { + throw classFormatError("Method is not static."); } // extraFlags = INITIALIZER | methodFlags; isClinit = true; } else if (name.equals(Name._init_)) { if (isInterface) { - throw ConstantPool.classFormatError("Method is not valid in an interface."); + throw classFormatError("Method is not valid in an interface."); } isInit = true; } @@ -834,7 +997,7 @@ private ParserMethod parseMethod(boolean isInterface) { * In a class file whose version number is 51.0 or above, the method has its ACC_STATIC * flag set and takes no arguments (4.6). */ - try (DebugCloseable signatureCheck = SIGNATURE_CHECK.scope(env.getTimers())) { + try (DebugCloseable signatureCheck = SIGNATURE_CHECK.scope(parsingContext.getTimers())) { // Checks for void method if init or clinit. /* * Obtain slot number for the signature. Forces a validation, but better in startup @@ -846,12 +1009,12 @@ private ParserMethod parseMethod(boolean isInterface) { if (isClinit && majorVersion >= JAVA_7_VERSION) { // Checks clinit takes no arguments. if (!signature.equals(Signature._void)) { - throw ConstantPool.classFormatError("Method has invalid signature: " + signature); + throw classFormatError("Method has invalid signature: " + signature); } } if (slots + (isStatic ? 0 : 1) > 255) { - throw ConstantPool.classFormatError("Too many arguments in method signature: " + signature); + throw classFormatError("Too many arguments in method signature: " + signature); } if (name.equals(Name.finalize) && signature.equals(Signature._void) && !Modifier.isStatic(methodFlags) && !Type.java_lang_Object.equals(classType)) { @@ -878,14 +1041,14 @@ private ParserMethod parseMethod(boolean isInterface) { final int startPosition = stream.getPosition(); if (attributeName.equals(Name.Code)) { if (codeAttribute != null) { - throw ConstantPool.classFormatError("Duplicate Code attribute"); + throw classFormatError("Duplicate Code attribute"); } - try (DebugCloseable code = CODE_PARSE.scope(env.getTimers())) { + try (DebugCloseable code = CODE_PARSE.scope(parsingContext.getTimers())) { methodAttributes[i] = codeAttribute = parseCodeAttribute(attributeName); } } else if (attributeName.equals(Name.Exceptions)) { if (checkedExceptions != null) { - throw ConstantPool.classFormatError("Duplicate Exceptions attribute"); + throw classFormatError("Duplicate Exceptions attribute"); } methodAttributes[i] = checkedExceptions = parseExceptions(attributeName); } else if (attributeName.equals(Name.Synthetic)) { @@ -898,7 +1061,7 @@ private ParserMethod parseMethod(boolean isInterface) { methodAttributes[i] = annotations.attribute; } else if (attributeName.equals(Name.MethodParameters)) { if (methodParameters != null) { - throw ConstantPool.classFormatError("Duplicate MethodParameters attribute"); + throw classFormatError("Duplicate MethodParameters attribute"); } methodAttributes[i] = methodParameters = parseMethodParameters(attributeName); } else { @@ -912,21 +1075,21 @@ private ParserMethod parseMethod(boolean isInterface) { final int distance = stream.getPosition() - startPosition; if (attributeSize != distance) { final String message = "Invalid attribute_length for " + attributeName + " attribute (reported " + attributeSize + " != parsed " + distance + ")"; - throw ConstantPool.classFormatError(message); + throw classFormatError(message); } } if (Modifier.isAbstract(methodFlags) || Modifier.isNative(methodFlags)) { if (codeAttribute != null) { - throw ConstantPool.classFormatError("Code attribute supplied for native or abstract method"); + throw classFormatError("Code attribute supplied for native or abstract method"); } } else { if (codeAttribute == null) { - throw ConstantPool.classFormatError("Missing Code attribute"); + throw classFormatError("Missing Code attribute"); } } - if (classDefinitionInfo.isHidden()) { + if (isHidden) { methodFlags |= ACC_HIDDEN; } @@ -941,7 +1104,8 @@ private static int parseAnnotation(ClassfileStream subStream) { int typeIndex = subStream.readU2(); int numElementValuePairs = subStream.readU2(); for (int k = 0; k < numElementValuePairs; k++) { - /* elementNameIndex */ subStream.readU2(); + /* elementNameIndex */ + subStream.readU2(); skipElementValue(subStream); } return typeIndex; @@ -959,17 +1123,22 @@ private static void skipElementValue(ClassfileStream subStream) { case 'S': case 'Z': case 's': - /* constValueIndex */ subStream.readU2(); + /* constValueIndex */ + subStream.readU2(); break; case 'e': - /* typeNameIndex */ subStream.readU2(); - /* constNameIndex */ subStream.readU2(); + /* typeNameIndex */ + subStream.readU2(); + /* constNameIndex */ + subStream.readU2(); break; case 'c': - /* classInfoIndex */ subStream.readU2(); + /* classInfoIndex */ + subStream.readU2(); break; case '@': - /* ignore */ parseAnnotation(subStream); + /* ignore */ + parseAnnotation(subStream); break; case '[': int numValues = subStream.readU2(); @@ -978,16 +1147,16 @@ private static void skipElementValue(ClassfileStream subStream) { } break; default: - throw ConstantPool.classFormatError("Invalid annotation tag: " + tag); + throw classFormatError("Invalid annotation tag: " + tag); } } - private Attribute[] parseClassAttributes() { + private Attribute[] parseClassAttributes() throws ValidationException { int attributeCount = stream.readU2(); if (attributeCount == 0) { if (maxBootstrapMethodAttrIndex >= 0) { - throw ConstantPool.classFormatError("BootstrapMethods attribute is missing"); + throw classFormatError("BootstrapMethods attribute is missing"); } return Attribute.EMPTY_ARRAY; } @@ -1012,12 +1181,12 @@ private Attribute[] parseClassAttributes() { final int startPosition = stream.getPosition(); if (attributeName.equals(Name.SourceFile)) { if (sourceFileName != null) { - throw ConstantPool.classFormatError("Duplicate SourceFile attribute"); + throw classFormatError("Duplicate SourceFile attribute"); } classAttributes[i] = sourceFileName = parseSourceFileAttribute(attributeName); } else if (attributeName.equals(Name.SourceDebugExtension)) { if (sourceDebugExtensionAttribute != null) { - throw ConstantPool.classFormatError("Duplicate SourceDebugExtension attribute"); + throw classFormatError("Duplicate SourceDebugExtension attribute"); } classAttributes[i] = sourceDebugExtensionAttribute = parseSourceDebugExtensionAttribute(attributeName, attributeSize); } else if (attributeName.equals(Name.Synthetic)) { @@ -1025,47 +1194,47 @@ private Attribute[] parseClassAttributes() { classAttributes[i] = new Attribute(attributeName, null); } else if (attributeName.equals(Name.InnerClasses)) { if (innerClasses != null) { - throw ConstantPool.classFormatError("Duplicate InnerClasses attribute"); + throw classFormatError("Duplicate InnerClasses attribute"); } classAttributes[i] = innerClasses = parseInnerClasses(attributeName); } else if (majorVersion >= JAVA_1_5_VERSION) { if (majorVersion >= JAVA_7_VERSION && attributeName.equals(Name.BootstrapMethods)) { if (bootstrapMethods != null) { - throw ConstantPool.classFormatError("Duplicate BootstrapMethods attribute"); + throw classFormatError("Duplicate BootstrapMethods attribute"); } classAttributes[i] = bootstrapMethods = parseBootstrapMethods(attributeName); } else if (attributeName.equals(Name.EnclosingMethod)) { if (enclosingMethod != null) { - throw ConstantPool.classFormatError("Duplicate EnclosingMethod attribute"); + throw classFormatError("Duplicate EnclosingMethod attribute"); } classAttributes[i] = enclosingMethod = parseEnclosingMethodAttribute(attributeName); } else if (majorVersion >= JAVA_11_VERSION && attributeName.equals(Name.NestHost)) { if (nestHost != null) { - throw ConstantPool.classFormatError("Duplicate NestHost attribute"); + throw classFormatError("Duplicate NestHost attribute"); } if (nestMembers != null) { - throw ConstantPool.classFormatError("Classfile cannot have both a nest members and a nest host attribute."); + throw classFormatError("Classfile cannot have both a nest members and a nest host attribute."); } if (attributeSize != 2) { - throw ConstantPool.classFormatError("Attribute length of NestHost must be 2"); + throw classFormatError("Attribute length of NestHost must be 2"); } classAttributes[i] = nestHost = parseNestHostAttribute(attributeName); } else if (majorVersion >= JAVA_11_VERSION && attributeName.equals(Name.NestMembers)) { if (nestMembers != null) { - throw ConstantPool.classFormatError("Duplicate NestMembers attribute"); + throw classFormatError("Duplicate NestMembers attribute"); } if (nestHost != null) { - throw ConstantPool.classFormatError("Classfile cannot have both a nest members and a nest host attribute."); + throw classFormatError("Classfile cannot have both a nest members and a nest host attribute."); } classAttributes[i] = nestMembers = parseNestMembers(attributeName); } else if (majorVersion >= JAVA_14_VERSION && attributeName.equals(Name.Record)) { if (record != null) { - throw ConstantPool.classFormatError("Duplicate Record attribute"); + throw classFormatError("Duplicate Record attribute"); } classAttributes[i] = record = parseRecord(attributeName); } else if (majorVersion >= JAVA_17_VERSION && attributeName.equals(Name.PermittedSubclasses)) { if (permittedSubclasses != null) { - throw ConstantPool.classFormatError("Duplicate PermittedSubclasses attribute"); + throw classFormatError("Duplicate PermittedSubclasses attribute"); } classAttributes[i] = permittedSubclasses = parsePermittedSubclasses(attributeName); } else { @@ -1079,12 +1248,12 @@ private Attribute[] parseClassAttributes() { } if (attributeSize != stream.getPosition() - startPosition) { - throw ConstantPool.classFormatError("Invalid attribute length for " + attributeName + " attribute"); + throw classFormatError("Invalid attribute length for " + attributeName + " attribute"); } } if (maxBootstrapMethodAttrIndex >= 0 && bootstrapMethods == null) { - throw ConstantPool.classFormatError("BootstrapMethods attribute is missing"); + throw classFormatError("BootstrapMethods attribute is missing"); } return classAttributes; @@ -1127,17 +1296,17 @@ private LineNumberTableAttribute parseLineNumberTable(Symbol name) { return new LineNumberTableAttribute(name, entries); } - private LocalVariableTable parseLocalVariableAttribute(Symbol name, int codeLength, int maxLocals) { + private LocalVariableTable parseLocalVariableAttribute(Symbol name, int codeLength, int maxLocals) throws ValidationException { assert Name.LocalVariableTable.equals(name); return parseLocalVariableTable(name, codeLength, maxLocals); } - private LocalVariableTable parseLocalVariableTypeAttribute(Symbol name, int codeLength, int maxLocals) { + private LocalVariableTable parseLocalVariableTypeAttribute(Symbol name, int codeLength, int maxLocals) throws ValidationException { assert Name.LocalVariableTypeTable.equals(name); return parseLocalVariableTable(name, codeLength, maxLocals); } - private LocalVariableTable parseLocalVariableTable(Symbol name, int codeLength, int maxLocals) { + private LocalVariableTable parseLocalVariableTable(Symbol name, int codeLength, int maxLocals) throws ValidationException { boolean isLVTT = Name.LocalVariableTypeTable.equals(name); int entryCount = stream.readU2(); if (entryCount == 0) { @@ -1152,41 +1321,41 @@ private LocalVariableTable parseLocalVariableTable(Symbol name, int codeLe int slot = stream.readU2(); if (bci < 0 || bci >= codeLength) { - throw ConstantPool.classFormatError("Invalid local variable table attribute entry: start_pc out of bounds: " + bci); + throw classFormatError("Invalid local variable table attribute entry: start_pc out of bounds: " + bci); } if (bci + length > codeLength) { - throw ConstantPool.classFormatError("Invalid local variable table attribute entry: start_pc + length out of bounds: " + (bci + length)); + throw classFormatError("Invalid local variable table attribute entry: start_pc + length out of bounds: " + (bci + length)); } Utf8Constant poolName = pool.utf8At(nameIndex); - Utf8Constant typeName = pool.utf8At(descIndex); - - typeName.validateUTF8(); - poolName.validateFieldName(); + Utf8Constant typeNameOrSignature = pool.utf8At(descIndex); int extraSlot = 0; if (!isLVTT) { - typeName.validateType(false); - Symbol type = typeName.value(); + Symbol type = validateType(typeNameOrSignature, false); if (type == Type._long || type == Type._double) { extraSlot = 1; } } if (slot + extraSlot >= maxLocals) { - throw ConstantPool.classFormatError("Invalid local variable table attribute entry: index points to an invalid frame slot: " + slot); + throw classFormatError("Invalid local variable table attribute entry: index points to an invalid frame slot: " + slot); } - locals[i] = new Local(poolName, typeName, bci, bci + length - 1, slot); + locals[i] = new Local( + validateFieldName(poolName), + isLVTT ? null : validateType(typeNameOrSignature, false), + isLVTT ? typeNameOrSignature.unsafeSymbolValue() : null, + bci, bci + length - 1, slot); } return new LocalVariableTable(name, locals); } - private SignatureAttribute parseSignatureAttribute(Symbol name) { + private SignatureAttribute parseSignatureAttribute(Symbol name) throws ValidationException { assert Name.Signature.equals(name); int signatureIndex = stream.readU2(); - pool.utf8At(signatureIndex).validateUTF8(); + validateEncoding(pool.utf8At(signatureIndex, "signature attribute")); return new SignatureAttribute(name, signatureIndex); } @@ -1211,13 +1380,13 @@ private ExceptionsAttribute parseExceptions(Symbol name) { for (int i = 0; i < entryCount; ++i) { int index = stream.readU2(); if (index >= pool.length()) { - throw ConstantPool.classFormatError("Invalid exception_index_table: out of bounds."); + throw classFormatError("Invalid exception_index_table: out of bounds."); } if (index == 0) { - throw ConstantPool.classFormatError("Invalid exception_index_table: 0."); + throw classFormatError("Invalid exception_index_table: 0."); } if (pool.tagAt(index) != Tag.CLASS) { - throw ConstantPool.classFormatError("Invalid exception_index_table: not a CONSTANT_Class_info structure."); + throw classFormatError("Invalid exception_index_table: not a CONSTANT_Class_info structure."); } entries[i] = index; } @@ -1227,29 +1396,29 @@ private ExceptionsAttribute parseExceptions(Symbol name) { private BootstrapMethodsAttribute parseBootstrapMethods(Symbol name) { int entryCount = stream.readU2(); if (maxBootstrapMethodAttrIndex >= entryCount) { - throw ConstantPool.classFormatError("Invalid bootstrapMethod index: " + maxBootstrapMethodAttrIndex + ", actual bootstrap methods size: " + entryCount); + throw classFormatError("Invalid bootstrapMethod index: " + maxBootstrapMethodAttrIndex + ", actual bootstrap methods size: " + entryCount); } BootstrapMethodsAttribute.Entry[] entries = new BootstrapMethodsAttribute.Entry[entryCount]; for (int i = 0; i < entryCount; ++i) { int bootstrapMethodRef = stream.readU2(); if (bootstrapMethodRef == 0) { - throw ConstantPool.classFormatError("Invalid bootstrapMethodRefIndex: 0"); + throw classFormatError("Invalid bootstrapMethodRefIndex: 0"); } if (bootstrapMethodRef >= pool.length()) { - throw ConstantPool.classFormatError("Invalid bootstrapMethodRefIndex: out of bounds."); + throw classFormatError("Invalid bootstrapMethodRefIndex: out of bounds."); } if (pool.tagAt(bootstrapMethodRef) != Tag.METHODHANDLE) { - throw ConstantPool.classFormatError("Invalid bootstrapMethodRefIndex: not a CONSTANT_MethodHandle_info structure."); + throw classFormatError("Invalid bootstrapMethodRefIndex: not a CONSTANT_MethodHandle_info structure."); } if (maxBootstrapMethodAttrIndex >= entryCount) { - throw ConstantPool.classFormatError("bootstrap_method_attr_index is greater than maximum valid index in the BootstrapMethods attribute."); + throw classFormatError("bootstrap_method_attr_index is greater than maximum valid index in the BootstrapMethods attribute."); } int numBootstrapArguments = stream.readU2(); char[] bootstrapArguments = new char[numBootstrapArguments]; for (int j = 0; j < numBootstrapArguments; ++j) { char cpIndex = (char) stream.readU2(); if (!pool.tagAt(cpIndex).isLoadable()) { - throw ConstantPool.classFormatError("Invalid constant pool constant for BootstrapMethodAttribute. Not a loadable constant"); + throw classFormatError("Invalid constant pool constant for BootstrapMethodAttribute. Not a loadable constant"); } bootstrapArguments[j] = cpIndex; } @@ -1258,7 +1427,7 @@ private BootstrapMethodsAttribute parseBootstrapMethods(Symbol name) { return new BootstrapMethodsAttribute(name, entries); } - private InnerClassesAttribute parseInnerClasses(Symbol name) { + private InnerClassesAttribute parseInnerClasses(Symbol name) throws ValidationException { assert Name.InnerClasses.equals(name); final int entryCount = stream.readU2(); @@ -1274,14 +1443,14 @@ private InnerClassesAttribute parseInnerClasses(Symbol name) { * HotSpot does not perform this check. Enforcing the spec here break some applications * in the wild e.g. Intellij IDEA. */ - if (env.getLanguage().getSpecComplianceMode() == STRICT) { + if (parsingContext.isStrictJavaCompliance()) { if (majorVersion >= JAVA_7_VERSION && innerClassInfo.innerNameIndex == 0 && outerClassIndex != 0) { - throw ConstantPool.classFormatError("InnerClassesAttribute: the value of the outer_class_info_index item must be zero if the value of the inner_name_index item is zero."); + throw classFormatError("InnerClassesAttribute: the value of the outer_class_info_index item must be zero if the value of the inner_name_index item is zero."); } } if (innerClassIndex == outerClassIndex) { - throw ConstantPool.classFormatError("Class is both outer and inner class"); + throw classFormatError("Class is both outer and inner class"); } Symbol innerClassName = null; @@ -1294,7 +1463,7 @@ private InnerClassesAttribute parseInnerClasses(Symbol name) { final InnerClassesAttribute.Entry otherInnerClassInfo = innerClassInfos[j]; if (otherInnerClassInfo != null) { if (innerClassIndex == otherInnerClassInfo.innerClassIndex && outerClassIndex == otherInnerClassInfo.outerClassIndex) { - throw ConstantPool.classFormatError("Duplicate entry in InnerClasses attribute"); + throw classFormatError("Duplicate entry in InnerClasses attribute"); } if (innerClassIndex == otherInnerClassInfo.innerClassIndex || // The same class can be referenced by two different CP indices, @@ -1313,7 +1482,7 @@ private InnerClassesAttribute parseInnerClasses(Symbol name) { final String cause = duplicateInnerClass ? "Duplicate inner_class_info_index (class names)" : "Cycle detected"; - env.getLogger().warning(cause + " in InnerClassesAttribute, in class " + classType); + parsingContext.getLogger().log(() -> cause + " in InnerClassesAttribute, in class " + classType); return new InnerClassesAttribute(name, new InnerClassesAttribute.Entry[0]); } @@ -1373,13 +1542,13 @@ private StackMapTableAttribute parseStackMapTableAttribute(Symbol attribut return StackMapTableAttribute.EMPTY; } - private NestHostAttribute parseNestHostAttribute(Symbol attributeName) { + private NestHostAttribute parseNestHostAttribute(Symbol attributeName) throws ValidationException { int hostClassIndex = stream.readU2(); pool.classAt(hostClassIndex).validate(pool); return new NestHostAttribute(attributeName, hostClassIndex); } - private NestMembersAttribute parseNestMembers(Symbol attributeName) { + private NestMembersAttribute parseNestMembers(Symbol attributeName) throws ValidationException { assert NestMembersAttribute.NAME.equals(attributeName); int numberOfClasses = stream.readU2(); int[] classes = new int[numberOfClasses]; @@ -1391,10 +1560,10 @@ private NestMembersAttribute parseNestMembers(Symbol attributeName) { return new NestMembersAttribute(attributeName, classes); } - private PermittedSubclassesAttribute parsePermittedSubclasses(Symbol attributeName) { + private PermittedSubclassesAttribute parsePermittedSubclasses(Symbol attributeName) throws ValidationException { assert PermittedSubclassesAttribute.NAME.equals(attributeName); if ((classFlags & ACC_FINAL) != 0) { - throw ConstantPool.classFormatError("A final class may not declare a permitted subclasses attribute."); + throw classFormatError("A final class may not declare a permitted subclasses attribute."); } int numberOfClasses = stream.readU2(); if (numberOfClasses == 0) { @@ -1409,22 +1578,22 @@ private PermittedSubclassesAttribute parsePermittedSubclasses(Symbol attri return new PermittedSubclassesAttribute(attributeName, classes); } - private RecordAttribute parseRecord(Symbol recordAttributeName) { + private RecordAttribute parseRecord(Symbol recordAttributeName) throws ValidationException { assert RecordAttribute.NAME.equals(recordAttributeName); int count = stream.readU2(); RecordAttribute.RecordComponentInfo[] components = new RecordAttribute.RecordComponentInfo[count]; for (int i = 0; i < count; i++) { - final int name = stream.readU2(); - final int descriptor = stream.readU2(); - pool.utf8At(name).validateUTF8(); - pool.utf8At(descriptor).validateType(false); + final int nameIndex = stream.readU2(); + final int descriptorIndex = stream.readU2(); + pool.utf8At(nameIndex).validateUTF8(); + pool.utf8At(descriptorIndex).validateType(false); Attribute[] componentAttributes = parseRecordComponentAttributes(); - components[i] = new RecordAttribute.RecordComponentInfo(name, descriptor, componentAttributes); + components[i] = new RecordAttribute.RecordComponentInfo(nameIndex, descriptorIndex, componentAttributes); } return new RecordAttribute(recordAttributeName, components); } - private Attribute[] parseRecordComponentAttributes() { + private Attribute[] parseRecordComponentAttributes() throws ValidationException { final int size = stream.readU2(); Attribute[] componentAttributes = new Attribute[size]; CommonAttributeParser commonAttributeParser = new CommonAttributeParser(InfoType.Record); @@ -1437,7 +1606,7 @@ private Attribute[] parseRecordComponentAttributes() { return componentAttributes; } - private InnerClassesAttribute.Entry parseInnerClassEntry() { + private InnerClassesAttribute.Entry parseInnerClassEntry() throws ValidationException { int innerClassIndex = stream.readU2(); int outerClassIndex = stream.readU2(); int innerNameIndex = stream.readU2(); @@ -1448,7 +1617,7 @@ private InnerClassesAttribute.Entry parseInnerClassEntry() { innerClassAccessFlags |= ACC_ABSTRACT; } - if (innerClassIndex != 0 || env.getJavaVersion().java9OrLater()) { + if (innerClassIndex != 0 || parsingContext.getJavaVersion().java9OrLater()) { pool.classAt(innerClassIndex).validate(pool); } if (outerClassIndex != 0) { @@ -1468,23 +1637,23 @@ private EnclosingMethodAttribute parseEnclosingMethodAttribute(Symbol name return new EnclosingMethodAttribute(name, classIndex, methodIndex); } - private CodeAttribute parseCodeAttribute(Symbol name) { + private CodeAttribute parseCodeAttribute(Symbol name) throws ValidationException { int maxStack = stream.readU2(); int maxLocals = stream.readU2(); final int codeLength = stream.readS4(); if (codeLength <= 0) { - throw ConstantPool.classFormatError("code_length must be > than 0"); + throw classFormatError("code_length must be > than 0"); } else if (codeLength > 0xFFFF) { - throw ConstantPool.classFormatError("code_length > than 64 KB"); + throw classFormatError("code_length > than 64 KB"); } byte[] code; - try (DebugCloseable codeRead = CODE_READ.scope(env.getTimers())) { + try (DebugCloseable codeRead = CODE_READ.scope(parsingContext.getTimers())) { code = stream.readByteArray(codeLength); } ExceptionHandler[] entries; - try (DebugCloseable handlers = EXCEPTION_HANDLERS.scope(env.getTimers())) { + try (DebugCloseable handlers = EXCEPTION_HANDLERS.scope(parsingContext.getTimers())) { entries = parseExceptionHandlerEntries(); } @@ -1512,7 +1681,7 @@ private CodeAttribute parseCodeAttribute(Symbol name) { codeAttributes[i] = parseLocalVariableTypeAttribute(attributeName, codeLength, maxLocals); } else if (attributeName.equals(Name.StackMapTable)) { if (stackMapTable != null) { - throw ConstantPool.classFormatError("Duplicate StackMapTable attribute"); + throw classFormatError("Duplicate StackMapTable attribute"); } codeAttributes[i] = stackMapTable = parseStackMapTableAttribute(attributeName, attributeSize); } else { @@ -1522,7 +1691,7 @@ private CodeAttribute parseCodeAttribute(Symbol name) { } if (attributeSize != stream.getPosition() - startPosition) { - throw ConstantPool.classFormatError("Invalid attribute length for " + attributeName + " attribute"); + throw classFormatError("Invalid attribute length for " + attributeName + " attribute"); } } @@ -1544,7 +1713,7 @@ private void validateLocalTables(Attribute[] codeAttributes) { LocalVariableTable localTable = (LocalVariableTable) attr; for (Local local : localTable.getLocals()) { if (table.put(local, false) != null) { - throw ConstantPool.classFormatError("Duplicate local in local variable table: " + local); + throw classFormatError("Duplicate local in local variable table: " + local); } } } else if (attr.getName() == Name.LocalVariableTypeTable) { @@ -1555,10 +1724,10 @@ private void validateLocalTables(Attribute[] codeAttributes) { for (Local local : typeTable.getLocals()) { Boolean present = table.put(local, true); if (present == null) { - throw ConstantPool.classFormatError("Local in local variable type table does not match any local variable table entry: " + local); + throw classFormatError("Local in local variable type table does not match any local variable table entry: " + local); } if (present) { - throw ConstantPool.classFormatError("Duplicate local in local variable type table: " + local); + throw classFormatError("Duplicate local in local variable type table: " + local); } } } @@ -1577,7 +1746,7 @@ private ExceptionHandler[] parseExceptionHandlerEntries() { int catchTypeIndex = stream.readU2(); Symbol catchType = null; if (catchTypeIndex != 0) { - catchType = env.getTypes().fromName(pool.classAt(catchTypeIndex).getName(pool)); + catchType = parsingContext.getOrCreateTypeFromName(pool.classAt(catchTypeIndex).getName(pool)); } entries[i] = new ExceptionHandler(startPc, endPc, handlerPc, catchTypeIndex, catchType); } @@ -1590,7 +1759,7 @@ private ExceptionHandler[] parseExceptionHandlerEntries() { * @param name the name of the field * @param flags the flags to test * @param isInterface if the field flags are being tested for an interface - * @throws ClassFormatError if the flags are invalid + * @throws ParserException.ClassFormatError if the flags are invalid */ private static void verifyFieldFlags(Symbol name, int flags, boolean isInterface) { boolean valid; @@ -1613,27 +1782,21 @@ private static void verifyFieldFlags(Symbol name, int flags, boolean isInt valid = (flags & ~ACC_SYNTHETIC) == (ACC_STATIC | ACC_FINAL | ACC_PUBLIC); } if (!valid) { - throw ConstantPool.classFormatError(name + ": invalid field flags 0x" + Integer.toHexString(flags)); + throw classFormatError(name + ": invalid field flags 0x" + Integer.toHexString(flags)); } } - private ParserField parseField(boolean isInterface) { + private ParserField parseField(boolean isInterface) throws ValidationException { int fieldFlags = stream.readU2(); int nameIndex = stream.readU2(); int typeIndex = stream.readU2(); - pool.utf8At(nameIndex).validateFieldName(); - final Symbol name = pool.symbolAt(nameIndex, "field name"); + final Symbol name = validateFieldName(pool.utf8At(nameIndex, "field name")); verifyFieldFlags(name, fieldFlags, isInterface); final boolean isStatic = Modifier.isStatic(fieldFlags); - pool.utf8At(typeIndex).validateType(false); - Symbol rawDescriptor = pool.symbolAt(typeIndex, "field descriptor"); - final Symbol descriptor = Types.fromSymbol(rawDescriptor); - if (descriptor == null) { - throw ConstantPool.classFormatError("Invalid descriptor: " + rawDescriptor); - } + final Symbol descriptor = validateType(pool.utf8At(typeIndex, "field descriptor"), false); final int attributeCount = stream.readU2(); final Attribute[] fieldAttributes = spawnAttributesArray(attributeCount); @@ -1648,11 +1811,11 @@ private ParserField parseField(boolean isInterface) { final int startPosition = stream.getPosition(); if (isStatic && attributeName.equals(Name.ConstantValue)) { if (constantValue != null) { - throw ConstantPool.classFormatError("Duplicate ConstantValue attribute"); + throw classFormatError("Duplicate ConstantValue attribute"); } fieldAttributes[i] = constantValue = new ConstantValueAttribute(stream.readU2()); if (constantValue.getConstantValueIndex() == 0) { - throw ConstantPool.classFormatError("Invalid ConstantValue index"); + throw classFormatError("Invalid ConstantValue index"); } } else if (attributeName.equals(Name.Synthetic)) { fieldFlags |= ACC_SYNTHETIC; @@ -1673,13 +1836,13 @@ private ParserField parseField(boolean isInterface) { } if (attributeSize != stream.getPosition() - startPosition) { - throw ConstantPool.classFormatError("Invalid attribute_length for " + attributeName + " attribute"); + throw classFormatError("Invalid attribute_length for " + attributeName + " attribute"); } } final JavaKind kind = Types.getJavaKind(descriptor); if (kind == JavaKind.Void) { - throw ConstantPool.classFormatError("Fields cannot be of type void"); + throw classFormatError("Fields cannot be of type void"); } if (constantValue != null) { @@ -1708,19 +1871,19 @@ private ParserField parseField(boolean isInterface) { valid = (tag == Tag.STRING) && descriptor.equals(Type.java_lang_String); break; default: { - throw ConstantPool.classFormatError("Cannot have ConstantValue for fields of type " + kind); + throw classFormatError("Cannot have ConstantValue for fields of type " + kind); } } if (!valid) { - throw ConstantPool.classFormatError("ConstantValue attribute does not match field type"); + throw classFormatError("ConstantValue attribute does not match field type"); } } return new ParserField(fieldFlags, name, descriptor, fieldAttributes); } - private ParserField[] parseFields(boolean isInterface) { + private ParserField[] parseFields(boolean isInterface) throws ValidationException { int fieldCount = stream.readU2(); if (fieldCount == 0) { return ParserField.EMPTY_ARRAY; @@ -1730,7 +1893,7 @@ private ParserField[] parseFields(boolean isInterface) { fields[i] = parseField(isInterface); for (int j = 0; j < i; ++j) { if (fields[j].getName().equals(fields[i].getName()) && fields[j].getType().equals(fields[i].getType())) { - throw ConstantPool.classFormatError("Duplicate field name and signature: " + fields[j].getName() + " " + fields[j].getType()); + throw classFormatError("Duplicate field name and signature: " + fields[j].getName() + " " + fields[j].getType()); } } } @@ -1746,11 +1909,11 @@ private Symbol parseSuperKlass() { int index = stream.readU2(); if (index == 0) { if (!classType.equals(Type.java_lang_Object)) { - throw ConstantPool.classFormatError("Invalid superclass index 0"); + throw classFormatError("Invalid superclass index 0"); } return null; } - return env.getTypes().fromName(pool.classAt(index).getName(pool)); + return parsingContext.getOrCreateTypeFromName(pool.classAt(index).getName(pool)); } @SuppressWarnings({"unchecked", "rawtypes"}) @@ -1763,20 +1926,20 @@ private Symbol[] parseInterfaces() { for (int i = 0; i < interfaceCount; i++) { int interfaceIndex = stream.readU2(); Symbol interfaceName = pool.classAt(interfaceIndex).getName(pool); - Symbol interfaceType = env.getTypes().fromName(interfaceName); + Symbol interfaceType = parsingContext.getOrCreateTypeFromName(interfaceName); if (interfaceType == null) { - throw ConstantPool.classFormatError(classType + " contains invalid superinterface name: " + interfaceName); + throw classFormatError(classType + " contains invalid superinterface name: " + interfaceName); } if (Types.isPrimitive(interfaceType) || Types.isArray(interfaceType)) { - throw ConstantPool.classFormatError(classType + " superinterfaces cannot contain arrays nor primitives"); + throw classFormatError(classType + " superinterfaces cannot contain arrays nor primitives"); } interfaces[i] = interfaceType; } // Check for duplicate interfaces in the interface array. - Set> present = new HashSet<>(interfaces.length); + Set> present = HashSet.newHashSet(interfaces.length); for (Symbol t : interfaces) { if (!present.add(t)) { - throw ConstantPool.classFormatError("Duplicate interface name in classfile: " + t); + throw classFormatError("Duplicate interface name in classfile: " + t); } } return interfaces; @@ -1813,4 +1976,49 @@ public int hashCode() { } } + // region Validation (throwing) methods + + // Encoding (Modified UTF8) + + private Symbol validateEncoding(Utf8Constant utf8Constant) throws ValidationException { + if (!validate) { + return utf8Constant.unsafeSymbolValue(); + } + return utf8Constant.validateUTF8(); + } + + // Names + + private Symbol validateFieldName(Utf8Constant utf8Constant) throws ValidationException { + if (!validate) { + return utf8Constant.unsafeSymbolValue(); + } + return utf8Constant.validateFieldName(); + } + + private Symbol validateMethodName(Utf8Constant utf8Constant, boolean allowClinit) throws ValidationException { + if (!validate) { + return utf8Constant.unsafeSymbolValue(); + } + return utf8Constant.validateMethodName(allowClinit); + } + + @SuppressWarnings("unused") + private Symbol validateClassName(Utf8Constant utf8Constant) throws ValidationException { + if (!validate) { + return utf8Constant.unsafeSymbolValue(); + } + return utf8Constant.validateClassName(); + } + + // Types + + private Symbol validateType(Utf8Constant utf8Constant, boolean allowVoid) throws ValidationException { + if (!validate) { + return utf8Constant.unsafeSymbolValue(); + } + return utf8Constant.validateType(allowVoid); + } + + // endregion Validation (throwing) methods } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileStream.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClassfileStream.java similarity index 80% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileStream.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClassfileStream.java index 616eba938d4a..cc2015f0e15e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ClassfileStream.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClassfileStream.java @@ -22,20 +22,16 @@ */ package com.oracle.truffle.espresso.classfile; -import java.io.IOException; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; + import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.runtime.ClasspathFile; -import com.oracle.truffle.espresso.runtime.EspressoContext; - /** * Operations for sequentially scanning data items in a class file. Any IO exceptions that occur - * during scanning are converted to {@link ClassFormatError}s. + * during scanning are converted to {@link ParserException.ClassFormatError}s. */ public final class ClassfileStream { private final ClasspathFile classfile; @@ -161,7 +157,7 @@ public boolean isAtEndOfFile() { public void checkEndOfFile() { if (!isAtEndOfFile()) { - throw classFormatError("Extra bytes", classfile); + throw classFormatError("Extra bytes"); } } @@ -169,19 +165,21 @@ public int getPosition() { return data.position(); } - public ClassFormatError classFormatError(String format, Object... args) { - Meta meta = EspressoContext.get(null).getMeta(); - if (meta.java_lang_ClassFormatError == null) { - throw EspressoError.fatal("ClassFormatError during early startup: " + String.format(format, args) + " in classfile " + classfile); + @TruffleBoundary + public ParserException classFormatError(String message) { + String extendedMessage = message; + if (classfile != null) { + extendedMessage += " [in .class file " + classfile + "]"; } - throw meta.throwExceptionWithMessage(meta.java_lang_ClassFormatError, String.format(format, args) + " in classfile " + classfile); + throw new ParserException.ClassFormatError(extendedMessage); } - public ClassFormatError ioError(IOException ioException) { - throw classFormatError("%s", ioException); + @TruffleBoundary + public ParserException eofError() { + throw classFormatError("Truncated class file"); } - public ClassFormatError eofError() { - throw classFormatError("Truncated class file"); + ClasspathFile getClasspathFile() { + return classfile; } } diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClasspathEntry.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClasspathEntry.java new file mode 100644 index 000000000000..283c184b0a8d --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClasspathEntry.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile; + +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; + +import java.io.File; + +/** + * An entry in a classpath is a file system path that denotes an existing directory, an existing + * zip/jar file or a file. + */ +public abstract class ClasspathEntry { + + /** + * Gets the string representing the underlying path of this entry. + */ + public final String path() { + return file().getPath(); + } + + /** + * Gets the File object representing the underlying path of this entry. + */ + public abstract File file(); + + /** + * Gets the contents of a file denoted by a given path that is relative to this classpath entry. + * If the denoted file does not exist under this classpath entry then {@code null} is returned. + * Any IO exception that occurs when reading is silently ignored. + * + * @param archiveName name of the file in an archive with {@code '/'} as the separator + */ + public abstract ClasspathFile readFile(ByteSequence archiveName); + + public boolean isDirectory() { + return false; + } + + public boolean isArchive() { + return false; + } + + @Override + public String toString() { + return path(); + } + +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/ClasspathFile.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClasspathFile.java similarity index 80% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/ClasspathFile.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClasspathFile.java index 967f11984396..64d72520a66b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/ClasspathFile.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ClasspathFile.java @@ -20,16 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.runtime; +package com.oracle.truffle.espresso.classfile; -import java.io.File; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.runtime.Classpath.Entry; +import java.io.File; /** - * Encapsulates the contents of a file loaded from an {@linkplain Entry entry} on a - * {@linkplain Classpath classpath}. + * Encapsulates the contents of a file loaded from an {@linkplain ClasspathEntry entry} on a + * classpath. */ public final class ClasspathFile { @@ -41,7 +40,7 @@ public final class ClasspathFile { /** * The classpath entry from which the file represented by this object was read. */ - public final Entry classpathEntry; + public final ClasspathEntry classpathEntry; /** * Name of the file relative to {@link #classpathEntry}. @@ -54,7 +53,7 @@ public final class ClasspathFile { * @param contents the bytes of the file that was read * @param classpathEntry the entry from which the file was read */ - public ClasspathFile(byte[] contents, Entry classpathEntry, ByteSequence name) { + public ClasspathFile(byte[] contents, ClasspathEntry classpathEntry, ByteSequence name) { this.classpathEntry = classpathEntry; this.contents = contents; this.name = name; @@ -67,8 +66,4 @@ public String toString() { } return classpathEntry.file().getAbsolutePath() + File.separatorChar + name; } - - public ClassFormatError classFormatError(String format, Object... args) { - throw new ClassFormatError(String.format(format, args) + " [in class file " + this + "]"); - } } diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ConstantPool.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ConstantPool.java new file mode 100644 index 000000000000..9ae53512c30f --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ConstantPool.java @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.ModifiedUTF8; +import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; +import com.oracle.truffle.espresso.classfile.constantpool.ClassMethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.DoubleConstant; +import com.oracle.truffle.espresso.classfile.constantpool.FieldRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.FloatConstant; +import com.oracle.truffle.espresso.classfile.constantpool.IntegerConstant; +import com.oracle.truffle.espresso.classfile.constantpool.InterfaceMethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.InvokeDynamicConstant; +import com.oracle.truffle.espresso.classfile.constantpool.LongConstant; +import com.oracle.truffle.espresso.classfile.constantpool.MemberRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.MethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.NameAndTypeConstant; +import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant; +import com.oracle.truffle.espresso.classfile.constantpool.StringConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Utf8Constant; + +import java.util.Arrays; +import java.util.Formatter; + +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.CLASS; +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.DOUBLE; +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.FIELD_REF; +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.FLOAT; +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.INTEGER; +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.INTERFACE_METHOD_REF; +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.INVOKEDYNAMIC; +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.LONG; +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.METHOD_REF; +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.NAME_AND_TYPE; +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.STRING; +import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.UTF8; + +/** + * Immutable, shareable constant-pool representation. + */ +public abstract class ConstantPool { + + // @formatter:off + public static final byte CONSTANT_Utf8 = 1; + public static final byte CONSTANT_Integer = 3; + public static final byte CONSTANT_Float = 4; + public static final byte CONSTANT_Long = 5; + public static final byte CONSTANT_Double = 6; + public static final byte CONSTANT_Class = 7; + public static final byte CONSTANT_String = 8; + public static final byte CONSTANT_Fieldref = 9; + public static final byte CONSTANT_Methodref = 10; + public static final byte CONSTANT_InterfaceMethodref = 11; + public static final byte CONSTANT_NameAndType = 12; + public static final byte CONSTANT_MethodHandle = 15; + public static final byte CONSTANT_MethodType = 16; + public static final byte CONSTANT_Dynamic = 17; + public static final byte CONSTANT_InvokeDynamic = 18; + public static final byte CONSTANT_Module = 19; + public static final byte CONSTANT_Package = 20; + // @formatter:on + + public enum Tag { + INVALID(0), + UTF8(CONSTANT_Utf8), + INTEGER(CONSTANT_Integer, true), + FLOAT(CONSTANT_Float, true), + LONG(CONSTANT_Long, true), + DOUBLE(CONSTANT_Double, true), + CLASS(CONSTANT_Class, true), + STRING(CONSTANT_String, true), + FIELD_REF(CONSTANT_Fieldref), + METHOD_REF(CONSTANT_Methodref), + INTERFACE_METHOD_REF(CONSTANT_InterfaceMethodref), + NAME_AND_TYPE(CONSTANT_NameAndType), + METHODHANDLE(CONSTANT_MethodHandle, true), + METHODTYPE(CONSTANT_MethodType, true), + DYNAMIC(CONSTANT_Dynamic, true), + INVOKEDYNAMIC(CONSTANT_InvokeDynamic), + MODULE(CONSTANT_Module), + PACKAGE(CONSTANT_Package); + + private final byte value; + private final boolean loadable; + + Tag(int value) { + this(value, false); + } + + Tag(int value, boolean isLoadable) { + assert (byte) value == value; + this.value = (byte) value; + this.loadable = isLoadable; + } + + public final int getValue() { + return value; + } + + public final boolean isLoadable() { + return loadable; + } + + public static Tag fromValue(int value) { + // @formatter:off + switch (value) { + case 1: return UTF8; + case 3: return INTEGER; + case 4: return FLOAT; + case 5: return LONG; + case 6: return DOUBLE; + case 7: return CLASS; + case 8: return STRING; + case 9: return FIELD_REF; + case 10: return METHOD_REF; + case 11: return INTERFACE_METHOD_REF; + case 12: return NAME_AND_TYPE; + case 15: return METHODHANDLE; + case 16: return METHODTYPE; + case 17: return DYNAMIC; + case 18: return INVOKEDYNAMIC; + case 19: return MODULE; + case 20: return PACKAGE; + default: return null; + } + // @formatter:on + } + + public boolean isValidForVersion(int major) { + return switch (this) { + case INVALID -> true; + case UTF8, INTEGER, FLOAT, LONG, DOUBLE, CLASS, STRING, FIELD_REF, METHOD_REF, INTERFACE_METHOD_REF, NAME_AND_TYPE -> major >= 45; + case METHODHANDLE, METHODTYPE, INVOKEDYNAMIC -> major >= 51; + case DYNAMIC -> major >= 55; + case MODULE, PACKAGE -> major >= 53; + }; + } + } + + public abstract int getMajorVersion(); + + public abstract int getMinorVersion(); + + public abstract int length(); + + public abstract PoolConstant at(int index, String description); + + public final PoolConstant at(int index) { + return at(index, null); + } + + public abstract byte[] getRawBytes(); + + @TruffleBoundary + RuntimeException unexpectedEntry(int index, Tag tag, String description, Tag... expected) { + throw classFormatError("Constant pool entry" + (description == null ? "" : " for " + description) + " at " + index + " is a " + tag + ", expected " + Arrays.toString(expected)); + } + + @TruffleBoundary + RuntimeException unexpectedEntry(int index, String description, Tag... expected) { + throw unexpectedEntry(index, tagAt(index), description, expected); + } + + @TruffleBoundary + public abstract RuntimeException classFormatError(String message); + + /** + * Gets the tag at a given index. If {@code index == 0} or there is no valid entry at + * {@code index} (e.g. it denotes the slot following a double or long entry), then + * {@link Tag#INVALID} is returned. + */ + public final Tag tagAt(int index) { + return at(index).tag(); + } + + public final int intAt(int index) { + return intAt(index, null); + } + + public final int intAt(int index, String description) { + try { + final IntegerConstant constant = (IntegerConstant) at(index); + return constant.value(); + } catch (ClassCastException e) { + throw unexpectedEntry(index, description, INTEGER); + } + } + + public final long longAt(int index) { + return longAt(index, null); + } + + public final long longAt(int index, String description) { + try { + final LongConstant constant = (LongConstant) at(index); + return constant.value(); + } catch (ClassCastException e) { + throw unexpectedEntry(index, description, LONG); + } + } + + public final float floatAt(int index) { + return floatAt(index, null); + } + + public final float floatAt(int index, String description) { + try { + final FloatConstant constant = (FloatConstant) at(index); + return constant.value(); + } catch (ClassCastException e) { + throw unexpectedEntry(index, description, FLOAT); + } + } + + public final double doubleAt(int index) { + return doubleAt(index, null); + } + + public final double doubleAt(int index, String description) { + try { + final DoubleConstant constant = (DoubleConstant) at(index); + return constant.value(); + } catch (ClassCastException e) { + throw unexpectedEntry(index, description, DOUBLE); + } + } + + public final Symbol symbolAt(int index) { + return symbolAt(index, null); + } + + public final Symbol symbolAt(int index, String description) { + try { + final Utf8Constant constant = (Utf8Constant) at(index); + return constant.unsafeSymbolValue(); + } catch (ClassCastException e) { + throw unexpectedEntry(index, description, UTF8); + } + } + + public final Utf8Constant utf8At(int index) { + return utf8At(index, null); + } + + public final Utf8Constant utf8At(int index, String description) { + try { + return (Utf8Constant) at(index); + } catch (ClassCastException e) { + throw unexpectedEntry(index, description, UTF8); + } + } + + public final Symbol stringAt(int index) { + return stringAt(index, null); + } + + public final Symbol stringAt(int index, String description) { + try { + final StringConstant constant = (StringConstant) at(index); + return constant.getSymbol(this); + } catch (ClassCastException e) { + throw unexpectedEntry(index, description, STRING); + } + } + + // region unresolved constants + + public final NameAndTypeConstant nameAndTypeAt(int index) { + return nameAndTypeAt(index, null); + } + + public final NameAndTypeConstant nameAndTypeAt(int index, String description) { + try { + return (NameAndTypeConstant) at(index); + } catch (ClassCastException e) { + throw unexpectedEntry(index, description, NAME_AND_TYPE); + } + } + + public final ClassConstant classAt(int index) { + return classAt(index, null); + } + + public final ClassConstant classAt(int index, String description) { + try { + return (ClassConstant) at(index); + } catch (ClassCastException e) { + throw unexpectedEntry(index, description, CLASS); + } + } + + public final MemberRefConstant memberAt(int index) { + return memberAt(index, null); + } + + public final MemberRefConstant memberAt(int index, String description) { + try { + return (MemberRefConstant) at(index); + } catch (ClassCastException e) { + throw unexpectedEntry(index, description, METHOD_REF, INTERFACE_METHOD_REF, FIELD_REF); + } + } + + public final MethodRefConstant methodAt(int index) { + try { + return (MethodRefConstant) at(index); + } catch (ClassCastException e) { + throw unexpectedEntry(index, null, METHOD_REF, INTERFACE_METHOD_REF); + } + } + + public final ClassMethodRefConstant classMethodAt(int index) { + try { + return (ClassMethodRefConstant) at(index); + } catch (ClassCastException e) { + throw unexpectedEntry(index, null, METHOD_REF); + } + } + + public final InterfaceMethodRefConstant interfaceMethodAt(int index) { + try { + return (InterfaceMethodRefConstant) at(index); + } catch (ClassCastException e) { + throw unexpectedEntry(index, null, INTERFACE_METHOD_REF); + } + } + + public final FieldRefConstant fieldAt(int index) { + try { + return (FieldRefConstant) at(index); + } catch (ClassCastException e) { + throw unexpectedEntry(index, null, FIELD_REF); + } + } + + public final StringConstant stringConstantAt(int index) { + try { + return (StringConstant) at(index); + } catch (ClassCastException e) { + throw unexpectedEntry(index, null, STRING); + } + } + + public final InvokeDynamicConstant indyAt(int index) { + try { + return (InvokeDynamicConstant) at(index); + } catch (ClassCastException e) { + throw unexpectedEntry(index, null, INVOKEDYNAMIC); + } + } + + // endregion unresolved constants + + @Override + public String toString() { + Formatter buf = new Formatter(); + for (int i = 0; i < length(); i++) { + PoolConstant c = at(i); + buf.format("#%d = %-15s // %s%n", i, c.tag(), c.toString(this)); + } + return buf.toString(); + } +} diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/Constants.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/Constants.java new file mode 100644 index 000000000000..7001edacbbfc --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/Constants.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile; + +public final class Constants { + + /* Access Flags */ + // @formatter:off + public static final int ACC_PUBLIC = 0x00000001; + public static final int ACC_PRIVATE = 0x00000002; + public static final int ACC_PROTECTED = 0x00000004; + public static final int ACC_STATIC = 0x00000008; + public static final int ACC_FINAL = 0x00000010; + public static final int ACC_SYNCHRONIZED = 0x00000020; + public static final int ACC_SUPER = 0x00000020; + public static final int ACC_VOLATILE = 0x00000040; + public static final int ACC_TRANSIENT = 0x00000080; + public static final int ACC_NATIVE = 0x00000100; + public static final int ACC_INTERFACE = 0x00000200; + public static final int ACC_ABSTRACT = 0x00000400; + public static final int ACC_STRICT = 0x00000800; + public static final int ACC_EXPLICIT = 0x00001000; + + public static final int ACC_BRIDGE = 0x00000040; + public static final int ACC_VARARGS = 0x00000080; + public static final int ACC_SYNTHETIC = 0x00001000; + public static final int ACC_ANNOTATION = 0x00002000; + public static final int ACC_ENUM = 0x00004000; + public static final int ACC_MANDATED = 0x00008000; + public static final int ACC_MODULE = 0x00008000; + + // Not part of the spec, used internally by the VM. + // Methods + public static final int ACC_FINALIZER = 0x00010000; + public static final int ACC_FORCE_INLINE = 0x00020000; + public static final int ACC_LAMBDA_FORM_COMPILED = 0x00040000; + public static final int ACC_CALLER_SENSITIVE = 0x00080000; + public static final int ACC_HIDDEN = 0x00100000; // also for fields + public static final int ACC_SCOPED = 0x00200000; + public static final int ACC_DONT_INLINE = 0x00400000; + // Classes + public static final int ACC_IS_HIDDEN_CLASS = 0x04000000; // synchronized with JVM_ACC_IS_HIDDEN_CLASS + // Fields + public static final int ACC_STABLE = 0x00010000; + + public static final int FIELD_ID_TYPE = 0x01000000; + public static final int FIELD_ID_OBFUSCATE = 0x02000000; + + public static final int JVM_ACC_WRITTEN_FLAGS = 0x00007FFF; + // @formatter:on + + // Table 4.1-A. Class access and property modifiers. + public static final int JVM_RECOGNIZED_CLASS_MODIFIERS = ACC_PUBLIC | + ACC_FINAL | + ACC_SUPER | // Only very old compilers. + ACC_INTERFACE | + ACC_ABSTRACT | + ACC_ANNOTATION | + ACC_ENUM | + ACC_SYNTHETIC; + + // Inner classes can be static, private or protected (classic VM does this) + public static final int RECOGNIZED_INNER_CLASS_MODIFIERS = (JVM_RECOGNIZED_CLASS_MODIFIERS | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC); + + // Table 4.5-A. Field access and property flags. + public static final int JVM_RECOGNIZED_FIELD_MODIFIERS = ACC_PUBLIC | + ACC_PRIVATE | + ACC_PROTECTED | + ACC_STATIC | + ACC_FINAL | + ACC_VOLATILE | + ACC_TRANSIENT | + ACC_ENUM | + ACC_SYNTHETIC; + + // Table 4.6-A. Method access and property flags. + public static final int JVM_RECOGNIZED_METHOD_MODIFIERS = ACC_PUBLIC | + ACC_PRIVATE | + ACC_PROTECTED | + ACC_STATIC | + ACC_FINAL | + ACC_SYNCHRONIZED | + ACC_BRIDGE | + ACC_VARARGS | + ACC_NATIVE | + ACC_ABSTRACT | + ACC_STRICT | + ACC_SYNTHETIC; + + /* Type codes for StackMap attribute */ + public static final int ITEM_Bogus = 0; // an unknown or uninitialized value + public static final int ITEM_Integer = 1; // a 32-bit integer + public static final int ITEM_Float = 2; // not used + public static final int ITEM_Double = 3; // not used + public static final int ITEM_Long = 4; // a 64-bit integer + public static final int ITEM_Null = 5; // the type of null + public static final int ITEM_InitObject = 6; // "this" in constructor + public static final int ITEM_Object = 7; // followed by 2-byte index of class name + public static final int ITEM_NewObject = 8; // followed by 2-byte ref to "new" + + /* Constants used in StackMapTable attribute */ + public static final int SAME_FRAME_BOUND = 64; + public static final int SAME_LOCALS_1_STACK_ITEM_BOUND = 128; + public static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247; + public static final int CHOP_BOUND = 251; + public static final int SAME_FRAME_EXTENDED = 251; + public static final int APPEND_FRAME_BOUND = 255; + public static final int FULL_FRAME = 255; + + public static final int MAX_ARRAY_DIMENSIONS = 255; + + /** + * Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries. + */ + public static final byte REF_NONE = 0; // null value + public static final byte REF_getField = 1; + public static final byte REF_getStatic = 2; + public static final byte REF_putField = 3; + public static final byte REF_putStatic = 4; + public static final byte REF_invokeVirtual = 5; + public static final byte REF_invokeStatic = 6; + public static final byte REF_invokeSpecial = 7; + public static final byte REF_newInvokeSpecial = 8; + public static final byte REF_invokeInterface = 9; + public static final byte REF_LIMIT = 10; + + /* ArrayType constants */ + + public static final int JVM_ArrayType_Boolean = 4; + public static final int JVM_ArrayType_Char = 5; + public static final int JVM_ArrayType_Float = 6; + public static final int JVM_ArrayType_Double = 7; + public static final int JVM_ArrayType_Byte = 8; + public static final int JVM_ArrayType_Short = 9; + public static final int JVM_ArrayType_Int = 10; + public static final int JVM_ArrayType_Long = 11; + public static final int JVM_ArrayType_Object = 12; + public static final int JVM_ArrayType_Void = 14; + public static final int JVM_ArrayType_ReturnAddress = 98; + public static final int JVM_ArrayType_Illegal = 99; + +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/ExceptionHandler.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ExceptionHandler.java similarity index 95% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/ExceptionHandler.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ExceptionHandler.java index 1966c1dd55e7..34639aa85fd4 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/ExceptionHandler.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ExceptionHandler.java @@ -20,12 +20,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.meta; +package com.oracle.truffle.espresso.classfile; import java.util.Objects; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; /** * Represents an exception handler within the bytecodes. diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ImmutableConstantPool.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ImmutableConstantPool.java similarity index 84% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ImmutableConstantPool.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ImmutableConstantPool.java index 98808ced82b6..d34e707718cf 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ImmutableConstantPool.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ImmutableConstantPool.java @@ -22,18 +22,16 @@ */ package com.oracle.truffle.espresso.classfile; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Objects; - -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant; import com.oracle.truffle.espresso.classfile.constantpool.Utf8Constant; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.runtime.EspressoException; -import com.oracle.truffle.espresso.substitutions.JavaType; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Objects; /** * Immutable constant pool implementation backed by an array of constants. @@ -70,20 +68,26 @@ public byte[] getRawBytes() { return bytes; } + @Override + @TruffleBoundary + public RuntimeException classFormatError(String message) { + throw new ParserException.ClassFormatError(message); + } + + @TruffleBoundary + public RuntimeException classFormatError(int index, String description) { + throw classFormatError("Constant pool index (" + index + ")" + (description == null ? "" : " for " + description) + " is out of range"); + } + @Override public PoolConstant at(int index, String description) { try { return constants[index]; } catch (IndexOutOfBoundsException exception) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw classFormaterror(index, description); + throw classFormatError(index, description); } } - private static @JavaType(ClassFormatError.class) EspressoException classFormaterror(int index, String description) { - return ConstantPool.classFormatError("Constant pool index (" + index + ")" + (description == null ? "" : " for " + description) + " is out of range"); - } - @Override public int getMajorVersion() { return majorVersion; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/JavaKind.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaKind.java similarity index 71% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/JavaKind.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaKind.java index 989d85643a51..cdc861df3031 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/JavaKind.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaKind.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.meta; +package com.oracle.truffle.espresso.classfile; import static com.oracle.truffle.espresso.classfile.Constants.JVM_ArrayType_Boolean; import static com.oracle.truffle.espresso.classfile.Constants.JVM_ArrayType_Byte; @@ -35,15 +35,12 @@ import static com.oracle.truffle.espresso.classfile.Constants.JVM_ArrayType_Short; import static com.oracle.truffle.espresso.classfile.Constants.JVM_ArrayType_Void; -import java.lang.reflect.Array; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.espresso.descriptors.StaticSymbols; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.jdwp.api.TagConstants; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.espresso.classfile.descriptors.ErrorUtil; +import com.oracle.truffle.espresso.classfile.descriptors.StaticSymbols; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; /** * Denotes the basic kinds of types in CRI, including the all the Java primitive types, for example, @@ -257,59 +254,24 @@ public static JavaKind fromWordSize(int wordSizeInBytes) { * @return the kind */ public static JavaKind fromPrimitiveOrVoidTypeChar(char ch) { - switch (ch) { - case 'Z': - return Boolean; - case 'C': - return Char; - case 'F': - return Float; - case 'D': - return Double; - case 'B': - return Byte; - case 'S': - return Short; - case 'I': - return Int; - case 'J': - return Long; - case 'V': - return Void; - default: - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw new IllegalArgumentException("unknown primitive or void type character: " + ch); - } + return switch (ch) { + case 'Z' -> Boolean; + case 'C' -> Char; + case 'F' -> Float; + case 'D' -> Double; + case 'B' -> Byte; + case 'S' -> Short; + case 'I' -> Int; + case 'J' -> Long; + case 'V' -> Void; + default -> + throw new IllegalStateException(invalidTypeCharMessage(ch)); + }; } - /** - * Returns the Kind representing the given Java class. - * - * @param klass the class - * @return the kind - */ - public static JavaKind fromJavaClass(Class klass) { - if (klass == Boolean.primitiveJavaClass) { - return Boolean; - } else if (klass == Byte.primitiveJavaClass) { - return Byte; - } else if (klass == Short.primitiveJavaClass) { - return Short; - } else if (klass == Char.primitiveJavaClass) { - return Char; - } else if (klass == Int.primitiveJavaClass) { - return Int; - } else if (klass == Long.primitiveJavaClass) { - return Long; - } else if (klass == Float.primitiveJavaClass) { - return Float; - } else if (klass == Double.primitiveJavaClass) { - return Double; - } else if (klass == Void.primitiveJavaClass) { - return Void; - } else { - return Object; - } + @TruffleBoundary + private static String invalidTypeCharMessage(char ch) { + return "unknown primitive or void type character: " + ch; } /** @@ -444,7 +406,7 @@ public Symbol getType() { } public Symbol getPrimitiveBinaryName() { - EspressoError.guarantee(isPrimitive(), "not a primitive"); + ErrorUtil.guarantee(isPrimitive(), "not a primitive"); return name; } @@ -460,87 +422,13 @@ public String getWrapperValueOfDesc() { return wrapperValueOfDesc; } - /** - * Marker interface for types that should be {@linkplain JavaKind#format(Object) formatted} with - * their {@link Object#toString()} value. Calling {@link Object#toString()} on other objects - * poses a security risk because it can potentially call user code. - */ - public interface FormatWithToString { - } - /** * Classes for which invoking {@link Object#toString()} does not run user code. */ - private static boolean isToStringSafe(Class c) { + public static boolean isToStringSafe(Class c) { return c == Boolean.class || c == Byte.class || c == Character.class || c == Short.class || c == Integer.class || c == Float.class || c == Long.class || c == Double.class; } - /** - * Gets a formatted string for a given value of this kind. - * - * @param value a value of this kind - * @return a formatted string for {@code value} based on this kind - */ - public String format(Object value) { - if (isPrimitive()) { - assert isToStringSafe(value.getClass()); - return value.toString(); - } else { - if (value == null) { - return "null"; - } else { - if (value instanceof String) { - String s = (String) value; - if (s.length() > 50) { - return "String:\"" + s.substring(0, 30) + "...\""; - } else { - return "String:\"" + s + '"'; - } - } else if (value instanceof Klass) { - return "JavaType:" + ((Klass) value).getType(); - } else if (value instanceof Enum) { - return MetaUtil.getSimpleName(value.getClass(), true) + ":" + ((Enum) value).name(); - } else if (value instanceof FormatWithToString) { - return MetaUtil.getSimpleName(value.getClass(), true) + ":" + String.valueOf(value); - } else if (value instanceof Class) { - return "Class:" + ((Class) value).getName(); - } else if (isToStringSafe(value.getClass())) { - return value.toString(); - } else if (value.getClass().isArray()) { - return formatArray(value); - } else { - return MetaUtil.getSimpleName(value.getClass(), true) + "@" + System.identityHashCode(value); - } - } - } - } - - private static final int MAX_FORMAT_ARRAY_LENGTH = 5; - - private static String formatArray(Object array) { - Class componentType = array.getClass().getComponentType(); - assert componentType != null; - int arrayLength = Array.getLength(array); - StringBuilder buf = new StringBuilder(MetaUtil.getSimpleName(componentType, true)).append('[').append(arrayLength).append("]{"); - int length = Math.min(MAX_FORMAT_ARRAY_LENGTH, arrayLength); - boolean primitive = componentType.isPrimitive(); - for (int i = 0; i < length; i++) { - if (primitive) { - buf.append(Array.get(array, i)); - } else { - Object o = ((Object[]) array)[i]; - buf.append(JavaKind.Object.format(o)); - } - if (i != length - 1) { - buf.append(", "); - } - } - if (arrayLength != length) { - buf.append(", ..."); - } - return buf.append('}').toString(); - } - public boolean isSubWord() { return isStackInt || this == Float; } @@ -548,19 +436,4 @@ public boolean isSubWord() { public boolean isStackInt() { return isStackInt; } - - public byte toTagConstant() { - return switch (this) { - case Boolean -> TagConstants.BOOLEAN; - case Byte -> TagConstants.BYTE; - case Short -> TagConstants.SHORT; - case Char -> TagConstants.CHAR; - case Int -> TagConstants.INT; - case Float -> TagConstants.FLOAT; - case Long -> TagConstants.LONG; - case Double -> TagConstants.DOUBLE; - case Object -> TagConstants.OBJECT; - default -> -1; - }; - } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JavaVersion.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java similarity index 98% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JavaVersion.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java index f0d0f3d59e94..65cb9618f5b7 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JavaVersion.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/JavaVersion.java @@ -21,12 +21,11 @@ * questions. */ -package com.oracle.truffle.espresso.runtime; +package com.oracle.truffle.espresso.classfile; /** - * Utility class to provide version checking predicates for clarity in the code base. Avoids - * cluttering {@link EspressoContext}. - * + * Utility class to provide version checking predicates for clarity in the code base. + *

      * Makes it harder to access the raw int version: please add new predicates instead. */ public final class JavaVersion implements Comparable { diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserException.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserException.java new file mode 100644 index 000000000000..1214ead35208 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserException.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile; + +import java.io.Serial; + +public abstract sealed class ParserException extends RuntimeException permits ParserException.ClassFormatError, ParserException.NoClassDefFoundError, ParserException.UnsupportedClassVersionError { + + @Serial private static final long serialVersionUID = -198220634150786215L; + + public ParserException(String message) { + super(message); + } + + public static final class ClassFormatError extends ParserException { + @Serial private static final long serialVersionUID = 8526425503590655600L; + + public ClassFormatError(String message) { + super(message); + } + } + + public static final class UnsupportedClassVersionError extends ParserException { + @Serial private static final long serialVersionUID = 842124216349055395L; + + public UnsupportedClassVersionError(String message) { + super(message); + } + } + + public static final class NoClassDefFoundError extends ParserException { + @Serial private static final long serialVersionUID = 2283932446927965805L; + + public NoClassDefFoundError(String message) { + super(message); + } + } + + @SuppressWarnings("sync-override") + @Override + public Throwable fillInStackTrace() { + return this; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserField.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserField.java similarity index 65% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserField.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserField.java index a1a697898cea..a2f039c7b8a8 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserField.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserField.java @@ -20,20 +20,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.impl; - -import static com.oracle.truffle.espresso.classfile.Constants.ACC_HIDDEN; +package com.oracle.truffle.espresso.classfile; import java.lang.reflect.Modifier; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; -import com.oracle.truffle.espresso.meta.JavaKind; -import com.oracle.truffle.espresso.runtime.Attribute; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; +import com.oracle.truffle.espresso.classfile.attributes.Attribute; + +import static com.oracle.truffle.espresso.classfile.Constants.ACC_HIDDEN; public final class ParserField { public static final ParserField[] EMPTY_ARRAY = new ParserField[0]; @@ -89,31 +87,4 @@ public boolean isFinal() { public JavaKind getKind() { return Types.getJavaKind(type); } - - public Class getPropertyType() { - if (type.length() == 1) { - char ch = (char) type.byteAt(0); - switch (ch) { - case 'Z': - return boolean.class; - case 'C': - return char.class; - case 'F': - return float.class; - case 'D': - return double.class; - case 'B': - return byte.class; - case 'S': - return short.class; - case 'I': - return int.class; - case 'J': - return long.class; - default: - throw new IllegalArgumentException("unknown primitive or void type character: " + ch); - } - } - return isHidden() ? Object.class : StaticObject.class; - } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserKlass.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserKlass.java similarity index 87% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserKlass.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserKlass.java index e88f30056fc9..a3108e3a8e45 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserKlass.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserKlass.java @@ -20,14 +20,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.impl; +package com.oracle.truffle.espresso.classfile; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.classfile.ImmutableConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.attributes.Attribute; /** * Immutable raw representation of classes in Espresso, this is the output of the parser, super @@ -59,6 +58,7 @@ public final class ParserKlass { private final ImmutableConstantPool pool; private final int thisKlassIndex; + private final long hiddenKlassId; public ParserKlass(ImmutableConstantPool pool, int flags, @@ -69,7 +69,8 @@ public ParserKlass(ImmutableConstantPool pool, ParserMethod[] methods, ParserField[] fields, Attribute[] attributes, - int thisKlassIndex) { + int thisKlassIndex, + long hiddenKlassId) { this.pool = pool; this.flags = flags; this.name = name; @@ -80,6 +81,7 @@ public ParserKlass(ImmutableConstantPool pool, this.fields = fields; this.attributes = attributes; this.thisKlassIndex = thisKlassIndex; + this.hiddenKlassId = hiddenKlassId; } /** @@ -135,6 +137,10 @@ public int getThisKlassIndex() { return thisKlassIndex; } + public long getHiddenKlassId() { + return hiddenKlassId; + } + @Override public String toString() { return "ParserKlass<" + getType() + ">"; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserMethod.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserMethod.java similarity index 83% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserMethod.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserMethod.java index fc88599a8614..5ff6c818ca62 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ParserMethod.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParserMethod.java @@ -20,13 +20,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.impl; +package com.oracle.truffle.espresso.classfile; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.attributes.Attribute; /** * Immutable raw representation of methods in Espresso, this is the output of the parser. @@ -46,11 +46,6 @@ public int getFlags() { @CompilationFinal(dimensions = 1) // private final Attribute[] attributes; - // Shared quickening recipes. - // Stores BC + arguments in compact form. - @CompilationFinal(dimensions = 1) // - private long[] recipes; - public static ParserMethod create(int flags, Symbol name, Symbol signature, Attribute[] attributes) { return new ParserMethod(flags, name, signature, attributes); } @@ -72,10 +67,6 @@ public Attribute getAttribute(Symbol attributeName) { return null; } - public long[] getRecipes() { - return recipes; - } - ParserMethod(int flags, Symbol name, Symbol signature, Attribute[] attributes) { this.flags = flags; this.name = name; diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParsingContext.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParsingContext.java new file mode 100644 index 000000000000..fb7ce43dd9cf --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/ParsingContext.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile; + +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.constantpool.Utf8Constant; +import com.oracle.truffle.espresso.classfile.perf.TimerCollection; + +import java.util.function.Supplier; + +public interface ParsingContext { + + JavaVersion getJavaVersion(); + + boolean isStrictJavaCompliance(); + + TimerCollection getTimers(); + + boolean isPreviewEnabled(); + + Logger getLogger(); + + Symbol getOrCreateName(ByteSequence byteSequence); + + // symbolify(Types.nameToType(byteSequence)) + Symbol getOrCreateTypeFromName(ByteSequence byteSequence); + + Utf8Constant getOrCreateUtf8Constant(ByteSequence bytes); + + long getNewKlassId(); + + interface Logger { + void log(String message); + + void log(Supplier messageSupplier); + + void log(String message, Throwable throwable); + + Logger NOP = new Logger() { + @Override + public void log(String message) { + // nop + } + + @Override + public void log(Supplier messageSupplier) { + // nop + } + + @Override + public void log(String message, Throwable throwable) { + // nop + } + }; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/Attribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/Attribute.java similarity index 92% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/Attribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/Attribute.java index 460697db6b64..50186e7a1ffd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/Attribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/Attribute.java @@ -20,14 +20,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.runtime; +package com.oracle.truffle.espresso.classfile.attributes; import java.util.Arrays; import java.util.Objects; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public class Attribute { diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/BootstrapMethodsAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/BootstrapMethodsAttribute.java new file mode 100644 index 000000000000..c6995ee9c93f --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/BootstrapMethodsAttribute.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile.attributes; + +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; + +public final class BootstrapMethodsAttribute extends Attribute { + + public static final Symbol NAME = Name.BootstrapMethods; + + public Entry[] getEntries() { + return entries; + } + + public static final class Entry { + final char bootstrapMethodRef; + + @CompilationFinal(dimensions = 1) // + final char[] bootstrapArguments; + + public int numBootstrapArguments() { + return bootstrapArguments.length; + } + + public Entry(char bootstrapMethodRef, char[] bootstrapArguments) { + this.bootstrapMethodRef = bootstrapMethodRef; + this.bootstrapArguments = bootstrapArguments; + } + + public char argAt(int index) { + return bootstrapArguments[index]; + } + + public char getBootstrapMethodRef() { + return bootstrapMethodRef; + } + + } + + private final Entry[] entries; + + public BootstrapMethodsAttribute(Symbol name, Entry[] entries) { + super(name, null); + this.entries = entries; + } + + public Entry at(int index) { + return entries[index]; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/CodeAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/CodeAttribute.java similarity index 82% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/CodeAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/CodeAttribute.java index 5cf3d39cd2b0..094613b8727e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/CodeAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/CodeAttribute.java @@ -23,24 +23,19 @@ package com.oracle.truffle.espresso.classfile.attributes; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.JSR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.JSR_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MONITORENTER; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MONITOREXIT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.RET; -import static com.oracle.truffle.espresso.classfile.ClassfileParser.JAVA_6_VERSION; - -import java.io.PrintStream; - import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.ExceptionHandler; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.ClassfileParser; +import com.oracle.truffle.espresso.classfile.ExceptionHandler; + +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.JSR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.JSR_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MONITORENTER; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MONITOREXIT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.RET; public final class CodeAttribute extends Attribute { @@ -183,18 +178,10 @@ public int bciToLineNumber(int bci) { } public boolean useStackMaps() { - return majorVersion >= JAVA_6_VERSION; + return majorVersion >= ClassfileParser.JAVA_6_VERSION; } public int getMajorVersion() { return majorVersion; } - - public static void print(Klass klass, byte[] code, PrintStream out) { - try { - new BytecodeStream(code).printBytecode(klass, out); - } catch (Throwable e) { - throw EspressoError.shouldNotReachHere("Throw during printing. Aborting...", e); - } - } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/ConstantValueAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/ConstantValueAttribute.java similarity index 94% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/ConstantValueAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/ConstantValueAttribute.java index 61111ea3e14a..c0d639aa25e0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/ConstantValueAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/ConstantValueAttribute.java @@ -22,9 +22,8 @@ */ package com.oracle.truffle.espresso.classfile.attributes; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; /** * The ConstantValue attribute is a fixed-length attribute in the attributes table of a field_info diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/EnclosingMethodAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/EnclosingMethodAttribute.java similarity index 90% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/EnclosingMethodAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/EnclosingMethodAttribute.java index a86cca28ce4d..76106d3ccf25 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/EnclosingMethodAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/EnclosingMethodAttribute.java @@ -23,9 +23,8 @@ package com.oracle.truffle.espresso.classfile.attributes; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public final class EnclosingMethodAttribute extends Attribute { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/ExceptionsAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/ExceptionsAttribute.java similarity index 90% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/ExceptionsAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/ExceptionsAttribute.java index 564800faa355..97a0258cbfb3 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/ExceptionsAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/ExceptionsAttribute.java @@ -22,9 +22,8 @@ */ package com.oracle.truffle.espresso.classfile.attributes; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public final class ExceptionsAttribute extends Attribute { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/InnerClassesAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/InnerClassesAttribute.java similarity index 92% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/InnerClassesAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/InnerClassesAttribute.java index 4ab59c4ac20d..5c457f4c5d13 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/InnerClassesAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/InnerClassesAttribute.java @@ -25,9 +25,8 @@ import static com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public final class InnerClassesAttribute extends Attribute { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/LineNumberTableAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LineNumberTableAttribute.java similarity index 95% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/LineNumberTableAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LineNumberTableAttribute.java index 1022c8139fec..fbcfca86b76e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/LineNumberTableAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LineNumberTableAttribute.java @@ -25,10 +25,8 @@ import java.util.AbstractList; import java.util.List; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.jdwp.api.LineNumberTableRef; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; /** * Maps bytecode indexes to source line numbers. diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/LineNumberTableRef.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LineNumberTableRef.java similarity index 96% rename from espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/LineNumberTableRef.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LineNumberTableRef.java index dea39365c221..0e616a0c7d25 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/LineNumberTableRef.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LineNumberTableRef.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.jdwp.api; +package com.oracle.truffle.espresso.classfile.attributes; import java.util.List; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/Local.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/Local.java similarity index 78% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/Local.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/Local.java index 4ef7fc2e1f9a..a21f881dde7a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/Local.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/Local.java @@ -22,12 +22,14 @@ */ package com.oracle.truffle.espresso.classfile.attributes; -import java.util.Objects; - +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; +import com.oracle.truffle.espresso.classfile.JavaKind; import org.graalvm.collections.Equivalence; -import com.oracle.truffle.espresso.classfile.constantpool.Utf8Constant; -import com.oracle.truffle.espresso.jdwp.api.LocalRef; +import java.util.Objects; /** * Describes the type and bytecode index range in which a local variable is live. @@ -54,18 +56,21 @@ public int hashCode(Object o) { public static final Local[] EMPTY_ARRAY = new Local[0]; - private final Utf8Constant name; - private final Utf8Constant type; + private final Symbol name; + private final Symbol type; + private final Symbol typeSignature; private final int startBci; private final int endBci; private final int slot; - public Local(Utf8Constant name, Utf8Constant type, int startBci, int endBci, int slot) { + public Local(Symbol name, Symbol type, Symbol typeSignature, int startBci, int endBci, int slot) { + assert type != null || typeSignature != null; this.name = name; this.startBci = startBci; this.endBci = endBci; this.slot = slot; this.type = type; + this.typeSignature = typeSignature; } public int getStartBCI() { @@ -76,14 +81,18 @@ public int getEndBCI() { return endBci; } - public Utf8Constant getName() { + public Symbol getName() { return name; } - public Utf8Constant getType() { + public Symbol getType() { return type; } + public JavaKind getJavaKind() { + return type == null ? JavaKind.Object : Types.getJavaKind(type); + } + public int getSlot() { return slot; } @@ -122,6 +131,10 @@ public String getNameAsString() { @Override public String getTypeAsString() { + // Keep compatibility with the old behavior. + if (type == null) { + return typeSignature.toString(); + } return type.toString(); } } diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/LocalRef.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LocalRef.java similarity index 97% rename from espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/LocalRef.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LocalRef.java index 71a6403136c6..37907ad85f25 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/LocalRef.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LocalRef.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.jdwp.api; +package com.oracle.truffle.espresso.classfile.attributes; /** * Interface representing a local variable, e.g. a method parameter or a variable declared within a diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/LocalVariableTable.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LocalVariableTable.java similarity index 93% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/LocalVariableTable.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LocalVariableTable.java index dc26e7576eb2..da6597116299 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/LocalVariableTable.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LocalVariableTable.java @@ -26,10 +26,8 @@ import java.util.List; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.jdwp.api.LocalVariableTableRef; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; /** * Describes the {@link Local}s for a Java method. diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/LocalVariableTableRef.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LocalVariableTableRef.java similarity index 95% rename from espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/LocalVariableTableRef.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LocalVariableTableRef.java index 031b9659b326..732d32f38b2d 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/LocalVariableTableRef.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/LocalVariableTableRef.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.jdwp.api; +package com.oracle.truffle.espresso.classfile.attributes; /** * An interface representing a local variable table. diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/MethodParametersAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/MethodParametersAttribute.java similarity index 94% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/MethodParametersAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/MethodParametersAttribute.java index 8bd42b994feb..7644e26a5727 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/MethodParametersAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/MethodParametersAttribute.java @@ -22,9 +22,8 @@ */ package com.oracle.truffle.espresso.classfile.attributes; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public final class MethodParametersAttribute extends Attribute { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/NestHostAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/NestHostAttribute.java similarity index 89% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/NestHostAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/NestHostAttribute.java index 4e07faf7cd10..a2822bb5ab79 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/NestHostAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/NestHostAttribute.java @@ -23,9 +23,8 @@ package com.oracle.truffle.espresso.classfile.attributes; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public class NestHostAttribute extends Attribute { public static final Symbol NAME = Name.NestHost; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/NestMembersAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/NestMembersAttribute.java similarity index 90% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/NestMembersAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/NestMembersAttribute.java index e8333ab5d539..b0f129c93b40 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/NestMembersAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/NestMembersAttribute.java @@ -24,9 +24,8 @@ package com.oracle.truffle.espresso.classfile.attributes; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public class NestMembersAttribute extends Attribute { public static final Symbol NAME = Name.NestMembers; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/PermittedSubclassesAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/PermittedSubclassesAttribute.java similarity index 91% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/PermittedSubclassesAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/PermittedSubclassesAttribute.java index ad81e16e5da1..305402ae7295 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/PermittedSubclassesAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/PermittedSubclassesAttribute.java @@ -24,9 +24,8 @@ package com.oracle.truffle.espresso.classfile.attributes; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public class PermittedSubclassesAttribute extends Attribute { public static final Symbol NAME = Name.PermittedSubclasses; diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/RecordAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/RecordAttribute.java new file mode 100644 index 000000000000..a4a7c983c8a2 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/RecordAttribute.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.espresso.classfile.attributes; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; + +public class RecordAttribute extends Attribute { + public static final Symbol NAME = Name.Record; + + @CompilerDirectives.CompilationFinal(dimensions = 1) // + private final RecordComponentInfo[] components; + + public RecordAttribute(Symbol name, RecordComponentInfo[] components) { + super(name, null); + this.components = components; + } + + public static class RecordComponentInfo { + final char name; + final char descriptor; + @CompilerDirectives.CompilationFinal(dimensions = 1)// + final Attribute[] attributes; + + public char getNameIndex() { + return name; + } + + public char getDescriptorIndex() { + return descriptor; + } + + public RecordComponentInfo(int name, int descriptor, Attribute[] attributes) { + this.name = (char) name; + this.descriptor = (char) descriptor; + this.attributes = attributes; + } + + public Attribute getAttribute(Symbol attributeName) { + for (Attribute attr : attributes) { + if (attr.getName().equals(attributeName)) { + return attr; + } + } + return null; + } + } + + public RecordComponentInfo[] getComponents() { + return components; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/SignatureAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/SignatureAttribute.java similarity index 89% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/SignatureAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/SignatureAttribute.java index 6659c293d91b..07738ebc3d41 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/SignatureAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/SignatureAttribute.java @@ -22,9 +22,8 @@ */ package com.oracle.truffle.espresso.classfile.attributes; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public final class SignatureAttribute extends Attribute { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/SourceDebugExtensionAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/SourceDebugExtensionAttribute.java similarity index 90% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/SourceDebugExtensionAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/SourceDebugExtensionAttribute.java index 761ec136e9e8..0ee8a4a15d84 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/SourceDebugExtensionAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/SourceDebugExtensionAttribute.java @@ -22,9 +22,8 @@ */ package com.oracle.truffle.espresso.classfile.attributes; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public final class SourceDebugExtensionAttribute extends Attribute { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/SourceFileAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/SourceFileAttribute.java similarity index 89% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/SourceFileAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/SourceFileAttribute.java index 42d83f625cbf..dfc75792a9ae 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/SourceFileAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/SourceFileAttribute.java @@ -22,9 +22,8 @@ */ package com.oracle.truffle.espresso.classfile.attributes; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public final class SourceFileAttribute extends Attribute { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/StackMapTableAttribute.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/StackMapTableAttribute.java similarity index 89% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/StackMapTableAttribute.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/StackMapTableAttribute.java index 3041118cd72a..cf03734c8611 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/StackMapTableAttribute.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/attributes/StackMapTableAttribute.java @@ -23,9 +23,8 @@ package com.oracle.truffle.espresso.classfile.attributes; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public class StackMapTableAttribute extends Attribute { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodeLookupSwitch.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/BytecodeLookupSwitch.java similarity index 94% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodeLookupSwitch.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/BytecodeLookupSwitch.java index b42820f4096b..f09a7e583a4a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodeLookupSwitch.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/BytecodeLookupSwitch.java @@ -20,9 +20,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.bytecode; +package com.oracle.truffle.espresso.classfile.bytecode; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LOOKUPSWITCH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LOOKUPSWITCH; /** * A utility for processing {@link Bytecodes#LOOKUPSWITCH} bytecodes. diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodeStream.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/BytecodeStream.java similarity index 67% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodeStream.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/BytecodeStream.java index b6ba4c019937..96c9659d9ad9 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodeStream.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/BytecodeStream.java @@ -20,19 +20,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.bytecode; +package com.oracle.truffle.espresso.classfile.bytecode; -import java.io.PrintStream; -import java.util.Arrays; - -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; -import com.oracle.truffle.espresso.classfile.constantpool.InvokeDynamicConstant; -import com.oracle.truffle.espresso.classfile.constantpool.MethodRefConstant; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; /** * A utility class that makes iterating over bytecodes and reading operands simpler and less error @@ -352,109 +343,14 @@ private int lengthOf(int curBCI) { } } default: - // Should rather be CompilerAsserts.neverPartOfCompilation() but this is - // reachable in SVM. - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere(unknownVariableLengthBytecodeMessage(opcode)); + throw new IllegalStateException(unknownVariableLengthBytecodeMessage(opcode)); } } return length; } + @TruffleBoundary private static String unknownVariableLengthBytecodeMessage(int opcode) { return "unknown variable-length bytecode: " + Bytecodes.nameOf(opcode); } - - public void printBytecode(Klass klass, PrintStream out) { - try { - ConstantPool pool = klass.getConstantPool(); - int bci = 0; - int nextBCI = 0; - StringBuilder str = new StringBuilder(); - while (nextBCI < endBCI()) { - str.setLength(0); - bci = nextBCI; - int opcode = currentBC(bci); - str.append(bci).append(": ").append(Bytecodes.nameOf(opcode)).append(" "); - nextBCI = nextBCI(bci); - if (Bytecodes.isBranch(opcode)) { - // {bci}: {branch bytecode} {target} - str.append(readBranchDest(bci)); - } else if (opcode == Bytecodes.NEW) { - // {bci}: new {class name} - int cpi = readCPI(bci); - ClassConstant cc = (ClassConstant) pool.at(cpi); - str.append(cc.getName(pool)); - } else if (opcode == Bytecodes.INVOKEDYNAMIC) { - // {bci}: #{bootstrap method index} -> {name}:{signature} - int cpi = readCPI(bci); - InvokeDynamicConstant idc = (InvokeDynamicConstant) pool.at(cpi); - str.append("#").append(idc.getBootstrapMethodAttrIndex()).append(" -> ").append(idc.getName(pool)).append(":").append(idc.getSignature(pool)); - } else if (Bytecodes.isInvoke(opcode)) { - // {bci}: invoke{} {class}.{method name}:{method signature} - int cpi = readCPI(bci); - MethodRefConstant mrc = (MethodRefConstant) pool.at(cpi); - str.append(mrc.getHolderKlassName(pool)).append(".").append(mrc.getName(pool)).append(":").append(mrc.getDescriptor(pool)); - } else if (opcode == Bytecodes.TABLESWITCH) { - // @formatter:off - // checkstyle: stop - - // {bci}: tableswitch - // {key1}: {target1} - // ... - // {keyN}: {targetN} - - // @formatter:on - // Checkstyle: resume - str.append('\n'); - BytecodeTableSwitch helper = BytecodeTableSwitch.INSTANCE; - int low = helper.lowKey(this, bci); - int high = helper.highKey(this, bci); - for (int i = low; i != high + 1; i++) { - str.append('\t').append(i).append(": ").append(helper.targetAt(this, bci, i)).append('\n'); - } - str.append("\tdefault: ").append(helper.defaultTarget(this, bci)); - } else if (opcode == Bytecodes.LOOKUPSWITCH) { - // @formatter:off - // checkstyle: stop - - // {bci}: lookupswitch - // {key1}: {target1} - // ... - // {keyN}: {targetN} - - // @formatter:on - // Checkstyle: resume - str.append('\n'); - BytecodeLookupSwitch helper = BytecodeLookupSwitch.INSTANCE; - int low = 0; - int high = helper.numberOfCases(this, bci) - 1; - for (int i = low; i <= high; i++) { - str.append('\t').append(helper.keyAt(this, bci, i)).append(": ").append(helper.targetAt(this, bci, i)); - } - str.append("\tdefault: ").append(helper.defaultTarget(this, bci)); - } else if (opcode == Bytecodes.IINC) { - str.append(" ").append(readLocalIndex(bci)).append(" ").append(readIncrement(bci)); - } else { - // {bci}: {opcode} {corresponding value} - if (nextBCI - bci == 2) { - str.append(readUByte(bci + 1)); - } - if (nextBCI - bci == 3) { - str.append(readShort(bci)); - } - if (nextBCI - bci == 5) { - str.append(readInt(bci + 1)); - } - } - out.println(str.toString()); - } - } catch (Throwable e) { - throw EspressoError.shouldNotReachHere("Exception thrown during bytecode printing, aborting...", e); - } - } - - public void printRawBytecode(PrintStream out) { - out.println(Arrays.toString(code)); - } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodeSwitch.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/BytecodeSwitch.java similarity index 95% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodeSwitch.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/BytecodeSwitch.java index d882ef26d7b5..a46dfb9aabfb 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodeSwitch.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/BytecodeSwitch.java @@ -20,9 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.bytecode; - -import com.oracle.truffle.espresso.meta.EspressoError; +package com.oracle.truffle.espresso.classfile.bytecode; /** * An abstract class that provides the state and methods common to {@link Bytecodes#LOOKUPSWITCH} @@ -41,7 +39,7 @@ public static BytecodeSwitch get(int opcode) { if (opcode == Bytecodes.LOOKUPSWITCH) { return BytecodeLookupSwitch.INSTANCE; } - throw EspressoError.shouldNotReachHere("Invalid switch bytecode: " + Bytecodes.nameOf(opcode)); + throw new IllegalArgumentException("Invalid switch bytecode: " + Bytecodes.nameOf(opcode)); } /** diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodeTableSwitch.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/BytecodeTableSwitch.java similarity index 95% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodeTableSwitch.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/BytecodeTableSwitch.java index 0ebdcecca3bc..ec24784d49dd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodeTableSwitch.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/BytecodeTableSwitch.java @@ -20,9 +20,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.bytecode; +package com.oracle.truffle.espresso.classfile.bytecode; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.TABLESWITCH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.TABLESWITCH; /** * A utility for processing {@link Bytecodes#TABLESWITCH} bytecodes. diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/Bytecodes.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/Bytecodes.java similarity index 97% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/Bytecodes.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/Bytecodes.java index 51b8784ba241..2c7ee1c32dbd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/Bytecodes.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/Bytecodes.java @@ -21,23 +21,23 @@ * questions. */ -package com.oracle.truffle.espresso.bytecode; - -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.ASSOCIATIVE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.BRANCH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.COMMUTATIVE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.FALL_THROUGH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.FIELD_READ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.FIELD_WRITE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.INVOKE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.LOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.PRODUCE_FOREIGN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.QUICKENABLE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.QUICKENED; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.RECEIVE_FOREIGN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.STOP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.STORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.Flags.TRAP; +package com.oracle.truffle.espresso.classfile.bytecode; + +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.ASSOCIATIVE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.BRANCH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.COMMUTATIVE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.FALL_THROUGH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.FIELD_READ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.FIELD_WRITE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.INVOKE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.LOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.PRODUCE_FOREIGN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.QUICKENABLE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.QUICKENED; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.RECEIVE_FOREIGN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.STOP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.STORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.Flags.TRAP; import java.lang.reflect.Field; import java.lang.reflect.Modifier; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/Bytes.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/Bytes.java similarity index 97% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/Bytes.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/Bytes.java index 177e3766a41a..df74ec7d58bd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/Bytes.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/Bytes.java @@ -20,9 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.bytecode; - -import com.oracle.truffle.espresso.nodes.quick.VolatileArrayAccess; +package com.oracle.truffle.espresso.classfile.bytecode; /** * A collection of utility methods for dealing with bytes, particularly in byte arrays. diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/VolatileArrayAccess.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/VolatileArrayAccess.java similarity index 97% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/VolatileArrayAccess.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/VolatileArrayAccess.java index 60dfa0dbf693..8a5bfd01de77 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/VolatileArrayAccess.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/VolatileArrayAccess.java @@ -21,7 +21,7 @@ * questions. */ -package com.oracle.truffle.espresso.nodes.quick; +package com.oracle.truffle.espresso.classfile.bytecode; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/BootstrapMethodConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/BootstrapMethodConstant.java similarity index 94% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/BootstrapMethodConstant.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/BootstrapMethodConstant.java index b62d120a4469..6be2ec021cae 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/BootstrapMethodConstant.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/BootstrapMethodConstant.java @@ -23,8 +23,8 @@ package com.oracle.truffle.espresso.classfile.constantpool; import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; /** * Interface denoting a bootstrap method constant entry in a constant pool. diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/ClassConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/ClassConstant.java new file mode 100644 index 000000000000..9ec794128b54 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/ClassConstant.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile.constantpool; + +import java.nio.ByteBuffer; + +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Validation; + +/** + * Interface denoting a class entry in a constant pool. + */ +public interface ClassConstant extends PoolConstant { + + static ClassConstant create(int classNameIndex) { + return new Index(classNameIndex); + } + + static ClassConstant withString(Symbol name) { + return new WithString(name); + } + + @Override + default Tag tag() { + return Tag.CLASS; + } + + /** + * Gets the type descriptor of the class represented by this constant. + * + * @param pool container of this constant + */ + Symbol getName(ConstantPool pool); + + @Override + default String toString(ConstantPool pool) { + return getName(pool).toString(); + } + + final class Index implements ClassConstant, Resolvable { + private final char classNameIndex; + + Index(int classNameIndex) { + this.classNameIndex = PoolConstant.u2(classNameIndex); + } + + @Override + public Symbol getName(ConstantPool pool) { + return pool.symbolAt(classNameIndex); + } + + @Override + public void validate(ConstantPool pool) throws ValidationException { + pool.utf8At(classNameIndex).validateClassName(); + } + + @Override + public void dump(ByteBuffer buf) { + buf.putChar(classNameIndex); + } + } + + final class WithString implements ClassConstant, Resolvable { + private final Symbol name; + + WithString(Symbol name) { + this.name = name; + } + + @Override + public Symbol getName(ConstantPool pool) { + return name; + } + + @Override + public void validate(ConstantPool pool) throws ValidationException { + // No UTF8 entry: cannot cache validation. + if (!Validation.validModifiedUTF8(name) || !Validation.validClassNameEntry(name)) { + throw ValidationException.raise("Invalid class name entry: " + name); + } + } + + @Override + public void dump(ByteBuffer buf) { + buf.putChar((char) 0); + } + } +} diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/ClassMethodRefConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/ClassMethodRefConstant.java new file mode 100644 index 000000000000..a647a9d83c67 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/ClassMethodRefConstant.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile.constantpool; + +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Descriptor; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; + +public interface ClassMethodRefConstant extends MethodRefConstant { + + static ClassMethodRefConstant create(int classIndex, int nameAndTypeIndex) { + return new Indexes(classIndex, nameAndTypeIndex); + } + + @Override + default Tag tag() { + return Tag.METHOD_REF; + } + + final class Indexes extends MethodRefConstant.Indexes implements ClassMethodRefConstant, Resolvable { + Indexes(int classIndex, int nameAndTypeIndex) { + super(classIndex, nameAndTypeIndex); + } + + @Override + public void validate(ConstantPool pool) throws ValidationException { + super.validate(pool); + // If the name of the method of a CONSTANT_Methodref_info structure begins with a '<' + // ('\u003c'), then the name must be the special name , representing an instance + // initialization method (§2.9). The return type of such a method must be void. + pool.nameAndTypeAt(nameAndTypeIndex).validateMethod(pool, false, true); + Symbol name = pool.nameAndTypeAt(nameAndTypeIndex).getName(pool); + if (Name._init_.equals(name)) { + Symbol descriptor = pool.nameAndTypeAt(nameAndTypeIndex).getDescriptor(pool); + int len = descriptor.length(); + if (len <= 2 || (descriptor.byteAt(len - 2) != ')' || descriptor.byteAt(len - 1) != 'V')) { + throw ValidationException.raise(" method should have ()V signature"); + } + } + } + } + +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/DoubleConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/DoubleConstant.java similarity index 100% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/DoubleConstant.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/DoubleConstant.java diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/DynamicConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/DynamicConstant.java new file mode 100644 index 000000000000..21ea079c80a0 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/DynamicConstant.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile.constantpool; + +import java.nio.ByteBuffer; + +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; + +public interface DynamicConstant extends PoolConstant { + + static DynamicConstant create(int bootstrapMethodAttrIndex, int nameAndTypeIndex) { + return new Indexes(bootstrapMethodAttrIndex, nameAndTypeIndex); + } + + @Override + default Tag tag() { + return Tag.DYNAMIC; + } + + Symbol getTypeSymbol(ConstantPool pool); + + final class Indexes extends BootstrapMethodConstant.Indexes implements DynamicConstant, Resolvable { + Indexes(int bootstrapMethodAttrIndex, int nameAndTypeIndex) { + super(bootstrapMethodAttrIndex, nameAndTypeIndex); + } + + @Override + public Symbol getTypeSymbol(ConstantPool pool) { + return Types.fromSymbol(pool.nameAndTypeAt(nameAndTypeIndex).getDescriptor(pool)); + } + + @Override + public void validate(ConstantPool pool) throws ValidationException { + pool.nameAndTypeAt(nameAndTypeIndex).validateField(pool); + } + + @Override + public void dump(ByteBuffer buf) { + buf.putChar(bootstrapMethodAttrIndex); + buf.putChar(nameAndTypeIndex); + } + } + +} diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/FieldRefConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/FieldRefConstant.java new file mode 100644 index 000000000000..a5d8ae5c1c43 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/FieldRefConstant.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile.constantpool; + +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; + +public interface FieldRefConstant extends MemberRefConstant { + + static FieldRefConstant create(int classIndex, int nameAndTypeIndex) { + return new Indexes(classIndex, nameAndTypeIndex); + } + + @Override + default Tag tag() { + return Tag.FIELD_REF; + } + + @SuppressWarnings("uncheked") + default Symbol getType(ConstantPool pool) { + return Types.fromDescriptor(getDescriptor(pool)); + } + + final class Indexes extends MemberRefConstant.Indexes implements FieldRefConstant, Resolvable { + Indexes(int classIndex, int nameAndTypeIndex) { + super(classIndex, nameAndTypeIndex); + } + + @Override + public void validate(ConstantPool pool) throws ValidationException { + super.validate(pool); + pool.nameAndTypeAt(nameAndTypeIndex).validateField(pool); + } + } + +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/FloatConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/FloatConstant.java similarity index 100% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/FloatConstant.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/FloatConstant.java diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/IntegerConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/IntegerConstant.java similarity index 100% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/IntegerConstant.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/IntegerConstant.java diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/InterfaceMethodRefConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/InterfaceMethodRefConstant.java new file mode 100644 index 000000000000..a95cad294749 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/InterfaceMethodRefConstant.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile.constantpool; + +import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; + +public interface InterfaceMethodRefConstant extends MethodRefConstant { + + static InterfaceMethodRefConstant create(int classIndex, int nameAndTypeIndex) { + return new Indexes(classIndex, nameAndTypeIndex); + } + + @Override + default Tag tag() { + return Tag.INTERFACE_METHOD_REF; + } + + final class Indexes extends MethodRefConstant.Indexes implements InterfaceMethodRefConstant, Resolvable { + Indexes(int classIndex, int nameAndTypeIndex) { + super(classIndex, nameAndTypeIndex); + } + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/InvalidConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/InvalidConstant.java similarity index 100% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/InvalidConstant.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/InvalidConstant.java diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/InvokeDynamicConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/InvokeDynamicConstant.java new file mode 100644 index 000000000000..77893446521a --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/InvokeDynamicConstant.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile.constantpool; + +import java.nio.ByteBuffer; + +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; + +public interface InvokeDynamicConstant extends BootstrapMethodConstant { + + static InvokeDynamicConstant create(int bootstrapMethodAttrIndex, int nameAndTypeIndex) { + return new Indexes(bootstrapMethodAttrIndex, nameAndTypeIndex); + } + + @Override + default Tag tag() { + return Tag.INVOKEDYNAMIC; + } + + Symbol getSignature(ConstantPool pool); + + default Symbol[] getParsedSignature() { + throw new IllegalStateException("Not resolved yet"); + } + + default boolean isResolved() { + return false; + } + + final class Indexes extends BootstrapMethodConstant.Indexes implements InvokeDynamicConstant, Resolvable { + Indexes(int bootstrapMethodAttrIndex, int nameAndTypeIndex) { + super(bootstrapMethodAttrIndex, nameAndTypeIndex); + } + + @Override + public void dump(ByteBuffer buf) { + buf.putChar(bootstrapMethodAttrIndex); + buf.putChar(nameAndTypeIndex); + } + + @Override + public void validate(ConstantPool pool) throws ValidationException { + pool.nameAndTypeAt(nameAndTypeIndex).validateMethod(pool, false); + } + + @Override + public Symbol getSignature(ConstantPool pool) { + return Signatures.check(pool.nameAndTypeAt(nameAndTypeIndex).getDescriptor(pool)); + } + + @Override + public String toString(ConstantPool pool) { + return "bsmIndex:" + getBootstrapMethodAttrIndex() + " " + getSignature(pool); + } + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/LongConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/LongConstant.java similarity index 100% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/LongConstant.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/LongConstant.java diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MemberRefConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MemberRefConstant.java new file mode 100644 index 000000000000..cc3df961371f --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MemberRefConstant.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile.constantpool; + +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Descriptor; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; +import com.oracle.truffle.espresso.classfile.ConstantPool; + +import java.nio.ByteBuffer; + +/** + * Interface denoting a field or method entry in a constant pool. + */ +public interface MemberRefConstant extends PoolConstant { + + /** + * Gets the class in which this method or field is declared. Note that the actual holder after + * resolution may be a super class of the class described by the one returned by this method. + */ + Symbol getHolderKlassName(ConstantPool pool); + + /** + * Gets the name of this field or method. + * + * @param pool the constant pool that maybe be required to convert a constant pool index to a + * name + */ + Symbol getName(ConstantPool pool); + + /** + * Gets the descriptor (type or signature) of this field or method. + * + * @param pool the constant pool that maybe be required to convert a constant pool index to a + * name + */ + Symbol getDescriptor(ConstantPool pool); + + @Override + default String toString(ConstantPool pool) { + return getHolderKlassName(pool) + "." + getName(pool) + getDescriptor(pool); + } + + abstract class Indexes implements MemberRefConstant { + + final char classIndex; + + final char nameAndTypeIndex; + + Indexes(int classIndex, int nameAndTypeIndex) { + this.classIndex = PoolConstant.u2(classIndex); + this.nameAndTypeIndex = PoolConstant.u2(nameAndTypeIndex); + } + + public char getClassIndex() { + return classIndex; + } + + @Override + public Symbol getHolderKlassName(ConstantPool pool) { + return pool.classAt(classIndex).getName(pool); + } + + @Override + public Symbol getName(ConstantPool pool) { + return pool.nameAndTypeAt(nameAndTypeIndex).getName(pool); + } + + @Override + public Symbol getDescriptor(ConstantPool pool) { + return pool.nameAndTypeAt(nameAndTypeIndex).getDescriptor(pool); + } + + @Override + public void validate(ConstantPool pool) throws ValidationException { + pool.classAt(classIndex).validate(pool); + pool.nameAndTypeAt(nameAndTypeIndex).validate(pool); + } + + @Override + public void dump(ByteBuffer buf) { + buf.putChar(classIndex); + buf.putChar(nameAndTypeIndex); + } + } +} diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MethodHandleConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MethodHandleConstant.java new file mode 100644 index 000000000000..65cfc78c24fb --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MethodHandleConstant.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile.constantpool; + +import java.nio.ByteBuffer; + +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; +import com.oracle.truffle.espresso.classfile.ClassfileParser; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; + +public interface MethodHandleConstant extends PoolConstant { + + static MethodHandleConstant create(int refKind, int refIndex) { + return new Index(refKind, refIndex); + } + + default Tag tag() { + return Tag.METHODHANDLE; + } + + int GETFIELD = 1; + int GETSTATIC = 2; + int PUTFIELD = 3; + int PUTSTATIC = 4; + int INVOKEVIRTUAL = 5; + int INVOKESTATIC = 6; + int INVOKESPECIAL = 7; + int NEWINVOKESPECIAL = 8; + int INVOKEINTERFACE = 9; + + int getRefKind(); + + char getRefIndex(); + + @Override + default String toString(ConstantPool pool) { + return getRefKind() + " " + pool.at(getRefIndex()).toString(pool); + } + + final class Index implements MethodHandleConstant, Resolvable { + + private final byte refKind; + private final char refIndex; + + Index(int refKind, int refIndex) { + this.refKind = PoolConstant.u1(refKind); + this.refIndex = PoolConstant.u2(refIndex); + } + + @Override + public int getRefKind() { + return refKind; + } + + @Override + public char getRefIndex() { + return refIndex; + } + + @Override + public void validate(ConstantPool pool) throws ValidationException { + pool.memberAt(refIndex).validate(pool); + + Symbol memberName = pool.memberAt(refIndex).getName(pool); + if (Name._clinit_.equals(memberName)) { + throw ValidationException.raise("Ill-formed constant: " + tag()); + } + + // If the value is 8 (REF_newInvokeSpecial), the name of the method represented by a + // CONSTANT_Methodref_info structure must be . + if (Name._init_.equals(memberName) && refKind != NEWINVOKESPECIAL) { + throw ValidationException.raise("Ill-formed constant: " + tag()); + } + + if (!(GETFIELD <= refKind && refKind <= INVOKEINTERFACE)) { + throw ValidationException.raise("Ill-formed constant: " + tag()); + } + + // If the value of the reference_kind item is 5 (REF_invokeVirtual), 6 + // (REF_invokeStatic), 7 (REF_invokeSpecial), or 9 (REF_invokeInterface), the name of + // the method represented by a CONSTANT_Methodref_info structure or a + // CONSTANT_InterfaceMethodref_info structure must not be or . + if (memberName.equals(Name._init_) || memberName.equals(Name._clinit_)) { + if (refKind == INVOKEVIRTUAL || + refKind == INVOKESTATIC || + refKind == INVOKESPECIAL || + refKind == INVOKEINTERFACE) { + throw ValidationException.raise("Ill-formed constant: " + tag()); + } + } + + boolean valid = false; + Tag tag = pool.at(refIndex).tag(); + switch (getRefKind()) { + case GETFIELD: // fall-through + case GETSTATIC: // fall-through + case PUTFIELD: // fall-through + case PUTSTATIC: + // If the value of the reference_kind item is 1 (REF_getField), 2 + // (REF_getStatic), 3 (REF_putField), or 4 (REF_putStatic), then the + // constant_pool entry at that index must be a CONSTANT_Fieldref_info + // (§4.4.2) + // structure representing a field for which a method handle is to be created. + valid = (tag == Tag.FIELD_REF); + break; + case INVOKEVIRTUAL: // fall-through + case NEWINVOKESPECIAL: + // If the value of the reference_kind item is 5 (REF_invokeVirtual) or 8 + // (REF_newInvokeSpecial), then the constant_pool entry at that index must be a + // CONSTANT_Methodref_info structure (§4.4.2) representing a class's method + // or constructor (§2.9) for which a method handle is to be created. + valid = tag == Tag.METHOD_REF; + break; + case INVOKESTATIC: // fall-through + case INVOKESPECIAL: + // If the value of the reference_kind item is 6 (REF_invokeStatic) or 7 + // (REF_invokeSpecial), then if the class file version number is less than 52.0, + // the constant_pool entry at that index must be a CONSTANT_Methodref_info + // structure representing a class's method for which a method handle is to be + // created; if the class file version number is 52.0 or above, the constant_pool + // entry at that index must be either a CONSTANT_Methodref_info structure or a + // CONSTANT_InterfaceMethodref_info structure (§4.4.2) representing a + // class's or interface's method for which a method handle is to be created. + valid = (tag == Tag.METHOD_REF) || + (pool.getMajorVersion() >= ClassfileParser.JAVA_8_VERSION && tag == Tag.INTERFACE_METHOD_REF); + break; + + case INVOKEINTERFACE: + // If the value of the reference_kind item is 9 (REF_invokeInterface), then the + // constant_pool entry at that index must be a CONSTANT_InterfaceMethodref_info + // structure representing an interface's method for which a method handle is to + // be created. + valid = (tag == Tag.INTERFACE_METHOD_REF); + break; + } + + if (!valid) { + throw ValidationException.raise("Ill-formed constant: " + tag()); + } + + } + + @Override + public void dump(ByteBuffer buf) { + buf.put(refKind); + buf.putChar(refIndex); + } + } + +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MethodRefConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MethodRefConstant.java similarity index 79% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MethodRefConstant.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MethodRefConstant.java index 9d5f8fdcfc46..2f09edc282ab 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MethodRefConstant.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MethodRefConstant.java @@ -22,16 +22,13 @@ */ package com.oracle.truffle.espresso.classfile.constantpool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode; -import com.oracle.truffle.espresso.perf.DebugCounter; public interface MethodRefConstant extends MemberRefConstant { - /* static final */ DebugCounter METHODREF_RESOLVE_COUNT = DebugCounter.create("MethodRef.resolve calls"); - /** * Gets the signature descriptor of the method represented by this constant. * @@ -42,17 +39,13 @@ default Symbol getSignature(ConstantPool pool) { return (Symbol) getDescriptor(pool); } - default MHInvokeGenericNode.MethodHandleInvoker invoker() { - return null; - } - abstract class Indexes extends MemberRefConstant.Indexes implements MethodRefConstant { Indexes(int classIndex, int nameAndTypeIndex) { super(classIndex, nameAndTypeIndex); } @Override - public void validate(ConstantPool pool) { + public void validate(ConstantPool pool) throws ValidationException { super.validate(pool); // method name is allowed here. pool.nameAndTypeAt(nameAndTypeIndex).validateMethod(pool, true); diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MethodTypeConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MethodTypeConstant.java new file mode 100644 index 000000000000..c07850d3963b --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/MethodTypeConstant.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile.constantpool; + +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; + +import java.nio.ByteBuffer; + +import static com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; + +public interface MethodTypeConstant extends PoolConstant { + + static MethodTypeConstant create(int descriptorIndex) { + return new Index(descriptorIndex); + } + + @Override + default Tag tag() { + return Tag.METHODTYPE; + } + + /** + * Gets the signature of this method type constant. + * + * @param pool the constant pool that maybe be required to convert a constant pool index to a + * name + */ + Symbol getSignature(ConstantPool pool); + + @Override + default String toString(ConstantPool pool) { + return getSignature(pool).toString(); + } + + final class Index implements MethodTypeConstant, Resolvable { + + private final char descriptorIndex; + + Index(int descriptorIndex) { + this.descriptorIndex = PoolConstant.u2(descriptorIndex); + } + + @Override + public Symbol getSignature(ConstantPool pool) { + // TODO(peterssen): Assert valid signature. + return pool.symbolAt(descriptorIndex); + } + + @Override + public void validate(ConstantPool pool) throws ValidationException { + pool.utf8At(descriptorIndex).validateSignature(); + } + + @Override + public void dump(ByteBuffer buf) { + buf.putChar(descriptorIndex); + } + } + +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/NameAndTypeConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/NameAndTypeConstant.java similarity index 85% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/NameAndTypeConstant.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/NameAndTypeConstant.java index e3ac445ae7d4..d35eea5d998d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/NameAndTypeConstant.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/NameAndTypeConstant.java @@ -24,11 +24,12 @@ import java.nio.ByteBuffer; +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; import com.oracle.truffle.espresso.classfile.ConstantPool; import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Descriptor; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Descriptor; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public interface NameAndTypeConstant extends PoolConstant { @@ -52,13 +53,13 @@ static NameAndTypeConstant create(int nameIndex, int typeIndex) { */ Symbol getDescriptor(ConstantPool pool); - default void validateMethod(ConstantPool pool, boolean checkVoidInitOrClinit) { + default void validateMethod(ConstantPool pool, boolean checkVoidInitOrClinit) throws ValidationException { validateMethod(pool, true, checkVoidInitOrClinit); } - void validateMethod(ConstantPool pool, boolean allowClinit, boolean checkVoidInitOrClinit); + void validateMethod(ConstantPool pool, boolean allowClinit, boolean checkVoidInitOrClinit) throws ValidationException; - void validateField(ConstantPool pool); + void validateField(ConstantPool pool) throws ValidationException; @Override default Tag tag() { @@ -91,7 +92,7 @@ public Symbol getDescriptor(ConstantPool pool) { } @Override - public void validate(ConstantPool pool) { + public void validate(ConstantPool pool) throws ValidationException { Symbol descriptor = getDescriptor(pool); if (descriptor.length() > 0 && descriptor.byteAt(0) == '(') { validateMethod(pool, false); @@ -102,7 +103,7 @@ public void validate(ConstantPool pool) { } @Override - public void validateMethod(ConstantPool pool, boolean allowClinit, boolean checkVoidInitOrClinit) { + public void validateMethod(ConstantPool pool, boolean allowClinit, boolean checkVoidInitOrClinit) throws ValidationException { pool.utf8At(nameIndex).validateMethodName(allowClinit); Symbol symbol = pool.symbolAt(nameIndex); boolean isInitOrClinit = checkVoidInitOrClinit && (Name._init_.equals(symbol) || Name._clinit_.equals(symbol)); @@ -110,7 +111,7 @@ public void validateMethod(ConstantPool pool, boolean allowClinit, boolean check } @Override - public void validateField(ConstantPool pool) { + public void validateField(ConstantPool pool) throws ValidationException { pool.utf8At(nameIndex).validateFieldName(); pool.utf8At(typeIndex).validateType(false); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/PoolConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/PoolConstant.java similarity index 85% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/PoolConstant.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/PoolConstant.java index b0b43cdf764b..50ddef4d8dff 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/PoolConstant.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/PoolConstant.java @@ -22,14 +22,15 @@ */ package com.oracle.truffle.espresso.classfile.constantpool; -import java.nio.ByteBuffer; - +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; import com.oracle.truffle.espresso.classfile.ConstantPool; import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; +import java.nio.ByteBuffer; + /** * Base interface for entries in a constant pool. - * + *

      * There is exactly one subclass representing the final or resolved version of a constant type. For * some constant types, there are one or more additional subclasses representing unresolved * version(s) of the constant. The process of resolving a constant will always result with relevant @@ -43,15 +44,15 @@ public interface PoolConstant { String toString(ConstantPool pool); /** - * Throws guest ClassFormatError if the constant is ill-formed (/ex: a StringConstant does not - * refer to an UTF8Constant). - * + * Throws {@link ValidationException} if the constant is ill-formed (/ex: a StringConstant does + * not refer to an UTF8Constant). + *

      * Resolved entries are not validated. * * @param pool The constant pool in which this constant appears. */ @SuppressWarnings("unused") - default void validate(ConstantPool pool) { + default void validate(ConstantPool pool) throws ValidationException { /* nop */ } @@ -75,4 +76,8 @@ static char u2(int i) { assert (char) i == i; return (char) i; } + + static RuntimeException shouldNotReachHere(String message) { + throw new IllegalStateException(message); + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/Resolvable.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/Resolvable.java similarity index 81% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/Resolvable.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/Resolvable.java index 89eaf18a7f96..0da0d0025852 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/Resolvable.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/Resolvable.java @@ -24,25 +24,18 @@ import java.nio.ByteBuffer; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.EspressoError; - public interface Resolvable extends PoolConstant { - ResolvedConstant resolve(RuntimeConstantPool pool, int thisIndex, ObjectKlass accessingKlass); - interface ResolvedConstant extends PoolConstant { Object value(); @Override default void dump(ByteBuffer buf) { - throw EspressoError.shouldNotReachHere(); + throw new IllegalStateException(); } default boolean isSuccess() { return true; } - } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/StringConstant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/StringConstant.java similarity index 55% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/StringConstant.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/StringConstant.java index f0fba0c70122..2f2bf693df4e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/StringConstant.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/StringConstant.java @@ -24,14 +24,11 @@ import java.nio.ByteBuffer; +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; import com.oracle.truffle.espresso.classfile.ConstantPool; import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.ModifiedUTF8; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.ModifiedUTF8; public interface StringConstant extends PoolConstant { @@ -39,10 +36,6 @@ static StringConstant create(int utf8Index) { return new Index(utf8Index); } - static StringConstant preResolved(StaticObject resolved) { - return new PreResolved(resolved); - } - @Override default Tag tag() { return Tag.STRING; @@ -74,12 +67,7 @@ public Symbol getSymbol(ConstantPool pool) { } @Override - public ResolvedConstant resolve(RuntimeConstantPool pool, int thisIndex, ObjectKlass accessingKlass) { - return new Resolved(pool.getContext().getStrings().intern(getSymbol(pool))); - } - - @Override - public void validate(ConstantPool pool) { + public void validate(ConstantPool pool) throws ValidationException { pool.utf8At(utf8Index).validateUTF8(); } @@ -89,45 +77,4 @@ public void dump(ByteBuffer buf) { } } - final class Resolved implements StringConstant, Resolvable.ResolvedConstant { - - private final StaticObject resolved; - - Resolved(StaticObject resolved) { - this.resolved = resolved; - } - - @Override - public StaticObject value() { - return resolved; - } - - @Override - public Symbol getSymbol(ConstantPool pool) { - throw EspressoError.shouldNotReachHere("String already resolved"); - } - } - - final class PreResolved implements StringConstant, Resolvable { - private final StaticObject resolved; - - @Override - public Symbol getSymbol(ConstantPool pool) { - throw EspressoError.shouldNotReachHere("String already Pre-Resolved"); - } - - PreResolved(StaticObject resolved) { - this.resolved = resolved; - } - - @Override - public ResolvedConstant resolve(RuntimeConstantPool pool, int thisIndex, ObjectKlass accessingKlass) { - return new Resolved(resolved); - } - - @Override - public void dump(ByteBuffer buf) { - buf.putChar((char) 0); - } - } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/Utf8Constant.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/Utf8Constant.java similarity index 53% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/Utf8Constant.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/Utf8Constant.java index aa8eb4afd194..aa9a7db76bbb 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/Utf8Constant.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/constantpool/Utf8Constant.java @@ -24,25 +24,32 @@ import java.nio.ByteBuffer; +import com.oracle.truffle.espresso.classfile.descriptors.ModifiedUtf8; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; import com.oracle.truffle.espresso.classfile.ConstantPool; import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Validation; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Validation; public final class Utf8Constant implements PoolConstant { - private static final byte VALID_CLASS_NAME = 0x01; - private static final byte VALID_METHOD_NAME = 0x02; - private static final byte VALID_METHOD_NAME_OR_CLINIT = 0x4; - private static final byte VALID_FIELD_NAME = 0x08; - private static final byte VALID_SIGNATURE = 0x10; + private static final short VALID_CLASS_NAME = 0x01; + private static final short VALID_METHOD_NAME = 0x02; + private static final short VALID_METHOD_NAME_OR_CLINIT = 0x4; + private static final short VALID_FIELD_NAME = 0x08; + private static final short VALID_SIGNATURE = 0x10; - private static final byte VALID_UTF8 = 0x20; - private static final byte VALID_TYPE = 0x40; + private static final short VALID_UTF8 = 0x20; + private static final short VALID_TYPE = 0x40; - private static final byte VALID_INIT_SIGNATURE = (byte) 0x80; + private static final short VALID_INIT_SIGNATURE = 0x80; - private byte validationCache; + private static final short VALID_TYPE_NO_VOID = 0x100; + + private short validationCache; @Override public Tag tag() { @@ -56,73 +63,78 @@ public Utf8Constant(Symbol value) { } @SuppressWarnings("unchecked") - public Symbol value() { - // TODO(peterssen): Maybe assert signature/type is valid. + public Symbol unsafeSymbolValue() { return (Symbol) value; } @Override - public void validate(ConstantPool pool) { + public void validate(ConstantPool pool) throws ValidationException { validateUTF8(); } - public void validateUTF8() { + public Symbol validateUTF8() throws ValidationException { if ((validationCache & VALID_UTF8) == 0) { - if (!Validation.validModifiedUTF8(value())) { - throw ConstantPool.classFormatError("Ill-formed modified-UTF8 entry"); + if (!Validation.validModifiedUTF8(unsafeSymbolValue())) { + throw ValidationException.raise("Ill-formed modified-UTF8 entry"); } validationCache |= VALID_UTF8; } + return unsafeSymbolValue(); } - public void validateClassName() { + public Symbol validateClassName() throws ValidationException { validateUTF8(); if ((validationCache & VALID_CLASS_NAME) == 0) { if (!Validation.validClassNameEntry(value)) { - throw ConstantPool.classFormatError("Invalid class name entry: " + value); + throw ValidationException.raise("Invalid class name entry: " + value); } validationCache |= VALID_CLASS_NAME; } + return unsafeSymbolValue(); } - public void validateType(boolean allowVoid) { + public Symbol validateType(boolean allowVoid) throws ValidationException { validateUTF8(); - if ((validationCache & VALID_TYPE) == 0) { + short mask = allowVoid ? VALID_TYPE : VALID_TYPE_NO_VOID; + if ((validationCache & mask) == 0) { if (!Validation.validTypeDescriptor(value, allowVoid)) { - throw ConstantPool.classFormatError("Invalid type descriptor: " + value); + throw ValidationException.raise("Invalid type descriptor: " + value); } - validationCache |= VALID_TYPE; + validationCache |= mask; } + return unsafeSymbolValue(); } - public void validateMethodName(boolean allowClinit) { + public Symbol validateMethodName(boolean allowClinit) throws ValidationException { validateUTF8(); - byte mask = allowClinit ? VALID_METHOD_NAME_OR_CLINIT : VALID_METHOD_NAME; + short mask = allowClinit ? VALID_METHOD_NAME_OR_CLINIT : VALID_METHOD_NAME; if ((validationCache & mask) == 0) { if (!Validation.validMethodName(value, allowClinit)) { - throw ConstantPool.classFormatError("Invalid method name: " + value); + throw ValidationException.raise("Invalid method name: " + value); } validationCache |= mask; } + return unsafeSymbolValue(); } - public void validateFieldName() { + public Symbol validateFieldName() throws ValidationException { validateUTF8(); if ((validationCache & VALID_FIELD_NAME) == 0) { if (!Validation.validUnqualifiedName(value)) { - throw ConstantPool.classFormatError("Invalid field name: " + value); + throw ValidationException.raise("Invalid field name: " + value); } validationCache |= VALID_FIELD_NAME; } + return unsafeSymbolValue(); } - public void validateSignature() { + public void validateSignature() throws ValidationException { validateSignature(false); } - public void validateSignature(boolean isInitOrClinit) { + public Symbol validateSignature(boolean isInitOrClinit) throws ValidationException { validateUTF8(); - byte mask; + short mask; if (isInitOrClinit) { mask = VALID_INIT_SIGNATURE; } else { @@ -130,15 +142,16 @@ public void validateSignature(boolean isInitOrClinit) { } if ((validationCache & mask) == 0) { if (!Validation.validSignatureDescriptor(value, isInitOrClinit)) { - throw ConstantPool.classFormatError("Invalid signature descriptor: " + value); + throw ValidationException.raise("Invalid signature descriptor: " + value); } - validationCache |= (byte) (mask | VALID_SIGNATURE); + validationCache |= (short) (mask | VALID_SIGNATURE); } + return unsafeSymbolValue(); } - public int validateSignatureGetSlots(boolean isInitOrClinit) { + public int validateSignatureGetSlots(boolean isInitOrClinit) throws ValidationException { validateUTF8(); - byte mask; + short mask; if (isInitOrClinit) { mask = VALID_INIT_SIGNATURE; } else { @@ -146,9 +159,9 @@ public int validateSignatureGetSlots(boolean isInitOrClinit) { } int slots = Validation.validSignatureDescriptorGetSlots(value, isInitOrClinit); if (slots < 0) { - throw ConstantPool.classFormatError("Invalid signature descriptor: " + value); + throw ValidationException.raise("Invalid signature descriptor: " + value); } - validationCache |= (byte) (mask | VALID_SIGNATURE); + validationCache |= (short) (mask | VALID_SIGNATURE); return slots; } @@ -164,9 +177,9 @@ public String toString(ConstantPool pool) { @Override public void dump(ByteBuffer buf) { - buf.putChar((char) value().length()); - for (int i = 0; i < value().length(); i++) { - buf.put(value().byteAt(i)); + buf.putChar((char) value.length()); + for (int i = 0; i < value.length(); i++) { + buf.put(value.byteAt(i)); } } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/ByteSequence.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ByteSequence.java similarity index 94% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/ByteSequence.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ByteSequence.java index 4446020e388e..613c6f6e7db4 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/ByteSequence.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ByteSequence.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.descriptors; +package com.oracle.truffle.espresso.classfile.descriptors; import java.io.IOException; import java.nio.ByteBuffer; @@ -28,8 +28,7 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.jni.ModifiedUtf8; -import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; /** * A ByteSequence is a readable sequence of byte values. This interface @@ -68,7 +67,7 @@ public static ByteSequence wrap(final byte[] underlyingBytes) { public static ByteSequence wrap(final byte[] underlyingBytes, int offset, int length) { if ((length > 0 && offset >= underlyingBytes.length) || offset + (long) length > underlyingBytes.length || length < 0 || offset < 0) { CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("ByteSequence illegal bounds: offset: " + offset + " length: " + length + " bytes length: " + underlyingBytes.length); + throw new IndexOutOfBoundsException("ByteSequence illegal bounds: offset: " + offset + " length: " + length + " bytes length: " + underlyingBytes.length); } return new ByteSequence(underlyingBytes, hashOfRange(underlyingBytes, offset, length)) { @Override @@ -171,13 +170,13 @@ public final boolean contentStartsWith(ByteSequence other) { return true; } + @TruffleBoundary @Override public String toString() { try { return ModifiedUtf8.toJavaString(getUnderlyingBytes(), offset(), length()); } catch (IOException e) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere(e); + throw new IllegalStateException(e); } } diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ErrorUtil.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ErrorUtil.java new file mode 100644 index 000000000000..73c5c72a8508 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ErrorUtil.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile.descriptors; + +public final class ErrorUtil { + + private ErrorUtil() { + } + + /** + * Checks a given condition and throws a {@link IllegalStateException} if it is false. + * Guarantees are stronger than assertions in that they are always checked. Error messages for + * guarantee violations should clearly indicate the nature of the problem as well as a suggested + * solution if possible. + * + * @param condition the condition to check + * @param message the message that will be associated with the error + */ + public static void guarantee(boolean condition, String message) { + if (!condition) { + throw new IllegalStateException(message); + } + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/ModifiedUtf8.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ModifiedUtf8.java similarity index 99% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/ModifiedUtf8.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ModifiedUtf8.java index 35cbb5d44acc..6a7a386aa14f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/ModifiedUtf8.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ModifiedUtf8.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.jni; +package com.oracle.truffle.espresso.classfile.descriptors; import java.io.IOException; import java.io.UTFDataFormatException; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Names.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Names.java similarity index 93% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Names.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Names.java index 94924e27cd50..ec56ec62e875 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Names.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Names.java @@ -20,9 +20,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.descriptors; +package com.oracle.truffle.espresso.classfile.descriptors; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; /** * Manages access to "name" symbols. diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Signatures.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Signatures.java similarity index 91% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Signatures.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Signatures.java index 61d2c9cb2194..62ab7072e6cd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Signatures.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Signatures.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.descriptors; +package com.oracle.truffle.espresso.classfile.descriptors; import static java.lang.Math.max; @@ -32,10 +32,11 @@ import java.util.function.Function; import com.oracle.truffle.api.nodes.ExplodeLoop; -import com.oracle.truffle.espresso.descriptors.Symbol.Descriptor; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.ParserException; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Descriptor; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.JavaKind; /** * Represents a method signature provided by the runtime. @@ -125,12 +126,12 @@ public Types getTypes() { * Parses a signature descriptor string into its parameter and return type components. * * @return the parsed parameter types followed by the return type. - * @throws ClassFormatError if {@code string} is not well formed + * @throws ParserException.ClassFormatError if {@code string} is not well formed */ @SuppressWarnings({"rawtypes", "unchecked"}) - static Symbol[] parse(Types typeDescriptors, Symbol signature, int startIndex) throws ClassFormatError { + static Symbol[] parse(Types typeDescriptors, Symbol signature, int startIndex) throws ParserException.ClassFormatError { if ((startIndex > signature.length() - 3) || signature.byteAt(startIndex) != '(') { - throw new ClassFormatError("Invalid method signature: " + signature); + throw new ParserException.ClassFormatError("Invalid method signature: " + signature); } final List> buf = new ArrayList<>(); int i = startIndex + 1; @@ -139,13 +140,13 @@ static Symbol[] parse(Types typeDescriptors, Symbol signature, buf.add(descriptor); i = i + descriptor.length(); if (i >= signature.length()) { - throw new ClassFormatError("Invalid method signature: " + signature); + throw new ParserException.ClassFormatError("Invalid method signature: " + signature); } } i++; final Symbol descriptor = typeDescriptors.parse(signature, i, true); if (i + descriptor.length() != signature.length()) { - throw new ClassFormatError("Invalid method signature: " + signature); + throw new ParserException.ClassFormatError("Invalid method signature: " + signature); } final Symbol[] descriptors = buf.toArray(new Symbol[buf.size() + 1]); descriptors[buf.size()] = descriptor; @@ -156,17 +157,17 @@ static Symbol[] parse(Types typeDescriptors, Symbol signature, * Parses a raw signature descriptor into its parameter and return type components. * * @return the parsed parameter types followed by the return type. - * @throws ClassFormatError if {@code string} is not well formed + * @throws ParserException.ClassFormatError if {@code string} is not well formed */ - public static int skipValidSignature(Symbol signature, int beginIndex) throws ClassFormatError { + public static int skipValidSignature(Symbol signature, int beginIndex) throws ParserException.ClassFormatError { if ((beginIndex > signature.length() - 3) || signature.byteAt(beginIndex) != '(') { - throw new ClassFormatError("Invalid method signature: " + signature); + throw new ParserException.ClassFormatError("Invalid method signature: " + signature); } int i = beginIndex + 1; while (signature.byteAt(i) != ')') { int endIndex = Types.skipValidTypeDescriptor(signature, i, true); if (i >= signature.length()) { - throw new ClassFormatError("Invalid method signature: " + signature); + throw new ParserException.ClassFormatError("Invalid method signature: " + signature); } i = endIndex; } @@ -307,7 +308,7 @@ public static boolean isValid(@SuppressWarnings("unused") ByteSequence signature public static Symbol verify(Symbol signature) { int endIndex = skipValidSignature(signature, 0); if (endIndex != signature.length()) { - throw new ClassFormatError("Invalid signature descriptor " + signature); + throw new ParserException.ClassFormatError("Invalid signature descriptor " + signature); } return signature; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/StaticSymbols.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/StaticSymbols.java similarity index 79% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/StaticSymbols.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/StaticSymbols.java index d4a4b26e9178..8f7eecceb34f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/StaticSymbols.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/StaticSymbols.java @@ -20,12 +20,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.descriptors; +package com.oracle.truffle.espresso.classfile.descriptors; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; /** * Global symbols for Espresso. @@ -46,19 +45,19 @@ private StaticSymbols() { private static final Symbols symbols = new Symbols(); public static Symbol putName(String name) { - EspressoError.guarantee(!isFrozen(), "static symbols are frozen"); - EspressoError.guarantee(!name.isEmpty(), "empty name"); + ErrorUtil.guarantee(!isFrozen(), "static symbols are frozen"); + ErrorUtil.guarantee(!name.isEmpty(), "empty name"); return symbols.symbolify(ByteSequence.create(name)); } public static Symbol putType(String internalName) { - EspressoError.guarantee(!isFrozen(), "static symbols are frozen"); + ErrorUtil.guarantee(!isFrozen(), "static symbols are frozen"); return symbols.symbolify(ByteSequence.create(Types.checkType(internalName))); } @SafeVarargs public static Symbol putSignature(Symbol returnType, Symbol... parameterTypes) { - EspressoError.guarantee(!isFrozen(), "static symbols are frozen"); + ErrorUtil.guarantee(!isFrozen(), "static symbols are frozen"); return symbols.symbolify(ByteSequence.wrap(Signatures.buildSignatureBytes(returnType, parameterTypes))); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Symbol.java similarity index 99% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Symbol.java index 6e90f74a7e47..d6d754931c4a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Symbol.java @@ -20,14 +20,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.descriptors; - -import java.io.IOException; +package com.oracle.truffle.espresso.classfile.descriptors; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.espresso.jni.ModifiedUtf8; -import com.oracle.truffle.espresso.meta.EspressoError; /** * An immutable byte string (modified-UTF8) for internal use in Espresso.
      @@ -95,16 +90,6 @@ public byte byteAt(int index) { return value[index]; } - @TruffleBoundary - @Override - public String toString() { - try { - return ModifiedUtf8.toJavaString(value); - } catch (IOException e) { - throw EspressoError.shouldNotReachHere(e); - } - } - @Override public int length() { return value.length; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/SymbolKey.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/SymbolKey.java similarity index 97% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/SymbolKey.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/SymbolKey.java index 4504152c2a24..7304beac80e3 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/SymbolKey.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/SymbolKey.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.descriptors; +package com.oracle.truffle.espresso.classfile.descriptors; final class SymbolKey { private final int hash; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbols.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Symbols.java similarity index 98% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbols.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Symbols.java index 426552f4e56c..9957a67c4ab8 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbols.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Symbols.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.descriptors; +package com.oracle.truffle.espresso.classfile.descriptors; import java.util.Arrays; import java.util.concurrent.ConcurrentHashMap; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Types.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Types.java similarity index 87% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Types.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Types.java index d0b38b52691a..2146c6588772 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Types.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Types.java @@ -20,20 +20,19 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.descriptors; +package com.oracle.truffle.espresso.classfile.descriptors; -import static com.oracle.truffle.espresso.descriptors.ByteSequence.EMPTY; -import static com.oracle.truffle.espresso.descriptors.ByteSequence.wrap; +import static com.oracle.truffle.espresso.classfile.descriptors.ByteSequence.EMPTY; +import static com.oracle.truffle.espresso.classfile.descriptors.ByteSequence.wrap; import java.util.Arrays; -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.espresso.descriptors.Symbol.Descriptor; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.ParserException; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Descriptor; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.JavaKind; /** * Manages creation and parsing of type descriptors ("field descriptors" in the JVMS). @@ -131,15 +130,15 @@ public static Symbol forPrimitive(JavaKind kind) { * @param beginIndex the index within the string from which to start parsing * @param slashes specifies if package components in {@code string} are separated by {@code '/'} * or {@code '.'} - * @throws ClassFormatError if the type descriptor is not valid + * @throws ParserException.ClassFormatError if the type descriptor is not valid */ - Symbol parse(Symbol descriptor, int beginIndex, boolean slashes) throws ClassFormatError { + Symbol parse(Symbol descriptor, int beginIndex, boolean slashes) throws ParserException.ClassFormatError { int endIndex = skipValidTypeDescriptor(descriptor, beginIndex, slashes); if (endIndex == beginIndex + 1) { try { return forPrimitive(JavaKind.fromPrimitiveOrVoidTypeChar((char) descriptor.byteAt(beginIndex))); } catch (IllegalArgumentException e) { - throw new ClassFormatError("invalid descriptor: " + descriptor); + throw new ParserException.ClassFormatError("invalid descriptor: " + descriptor); } } return symbols.symbolify(descriptor.substring(beginIndex, endIndex)); @@ -150,12 +149,12 @@ Symbol parse(Symbol descriptor, int beginIndex, bool * * @param slashes specifies if package components are separated by {@code '/'} or {@code '.'} * @return the index one past the valid type descriptor starting at {@code beginIndex} - * @throws ClassFormatError if there is no valid type descriptor + * @throws ParserException.ClassFormatError if there is no valid type descriptor */ @TruffleBoundary - static int skipValidTypeDescriptor(Symbol descriptor, int beginIndex, boolean slashes) throws ClassFormatError { + static int skipValidTypeDescriptor(Symbol descriptor, int beginIndex, boolean slashes) throws ParserException.ClassFormatError { if (beginIndex >= descriptor.length()) { - throw new ClassFormatError("invalid type descriptor: " + descriptor); + throw new ParserException.ClassFormatError("invalid type descriptor: " + descriptor); } char ch = (char) descriptor.byteAt(beginIndex); if (ch != '[' && ch != 'L') { @@ -167,7 +166,7 @@ static int skipValidTypeDescriptor(Symbol descriptor, int if (endIndex > beginIndex + 1 && endIndex < descriptor.length() && descriptor.byteAt(endIndex) == ';') { return endIndex + 1; } - throw new ClassFormatError("Invalid Java name " + descriptor.substring(beginIndex)); + throw new ParserException.ClassFormatError("Invalid Java name " + descriptor.substring(beginIndex)); } case '[': { // compute the number of dimensions @@ -177,12 +176,12 @@ static int skipValidTypeDescriptor(Symbol descriptor, int } final int dimensions = index - beginIndex; if (dimensions > 255) { - throw new ClassFormatError("Array with more than 255 dimensions " + descriptor.substring(beginIndex)); + throw new ParserException.ClassFormatError("Array with more than 255 dimensions " + descriptor.substring(beginIndex)); } return skipValidTypeDescriptor(descriptor, index, slashes); } } - throw new ClassFormatError("Invalid type descriptor " + descriptor.substring(beginIndex)); + throw new ParserException.ClassFormatError("Invalid type descriptor " + descriptor.substring(beginIndex)); } /** @@ -198,7 +197,7 @@ static int skipValidTypeDescriptor(Symbol descriptor, int public Symbol arrayOf(Symbol type, int dimensions) { assert dimensions > 0; if (Types.getArrayDimensions(type) + dimensions > 255) { - throw new ClassFormatError("Array type with more than 255 dimensions"); + throw new ParserException.ClassFormatError("Array type with more than 255 dimensions"); } // Prepend #dimensions '[' to type descriptor. byte[] bytes = new byte[type.length() + dimensions]; @@ -211,7 +210,7 @@ public Symbol arrayOf(Symbol type) { return arrayOf(type, 1); } - private static int skipClassName(Symbol descriptor, int from, final char separator) throws ClassFormatError { + private static int skipClassName(Symbol descriptor, int from, final char separator) throws ParserException.ClassFormatError { assert separator == '.' || separator == '/'; int index = from; final int length = descriptor.length(); @@ -320,9 +319,9 @@ public Symbol getElementalType(Symbol type) { } public Symbol fromClass(Class clazz) { - // TODO(peterssen): checkType is not needed here, just testing Class to Symbol - // conversion. - return symbols.symbolify(ByteSequence.create(checkType(internalFromClassName(clazz.getName())))); + ByteSequence descriptor = ByteSequence.create(internalFromClassName(clazz.getName())); + assert Validation.validTypeDescriptor(descriptor, true); + return symbols.symbolify(descriptor); } static ByteSequence checkType(ByteSequence sequence) { @@ -333,11 +332,9 @@ static ByteSequence checkType(ByteSequence sequence) { public static String checkType(String type) { // FIXME(peterssen): Do check. if (type.length() <= 0) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.unimplemented(); + throw new IllegalStateException(type); } return type; - // throw EspressoError.unimplemented(); } public static String binaryName(Symbol type) { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Utf8ConstantTable.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Utf8ConstantTable.java similarity index 92% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Utf8ConstantTable.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Utf8ConstantTable.java index 8b4cc3a74f84..bd33f42a0f01 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Utf8ConstantTable.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Utf8ConstantTable.java @@ -20,14 +20,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.descriptors; +package com.oracle.truffle.espresso.classfile.descriptors; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.espresso.classfile.constantpool.Utf8Constant; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.espresso.classfile.constantpool.Utf8Constant; - /** * Global Utf8Constant table. */ @@ -41,8 +41,9 @@ public Utf8ConstantTable(Symbols symbols) { this.symbols = symbols; } + @TruffleBoundary public Utf8Constant getOrCreate(ByteSequence bytes) { - CompilerAsserts.neverPartOfCompilation(); + return cache.computeIfAbsent(symbols.symbolify(bytes), new Function, Utf8Constant>() { @Override public Utf8Constant apply(Symbol value) { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Validation.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Validation.java similarity index 98% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Validation.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Validation.java index 0b8090da9b77..3bb07fe333f4 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Validation.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Validation.java @@ -20,11 +20,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.descriptors; +package com.oracle.truffle.espresso.classfile.descriptors; import com.oracle.truffle.espresso.classfile.Constants; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.jni.ModifiedUtf8; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; public final class Validation { private Validation() { diff --git a/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ValidationException.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ValidationException.java new file mode 100644 index 000000000000..9eee88a53917 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/ValidationException.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.classfile.descriptors; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; + +import java.io.Serial; + +public final class ValidationException extends Exception { + + @Serial private static final long serialVersionUID = 3253956176818294799L; + + ValidationException(String message) { + super(message); + } + + @Override + @SuppressWarnings("sync-override") + public Throwable fillInStackTrace() { + return this; + } + + @TruffleBoundary + public static ValidationException raise(String message) throws ValidationException { + throw new ValidationException(message); + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/DebugCloseable.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/DebugCloseable.java similarity index 95% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/DebugCloseable.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/DebugCloseable.java index c3a898b01325..0a67658ebb76 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/DebugCloseable.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/DebugCloseable.java @@ -21,7 +21,7 @@ * questions. */ -package com.oracle.truffle.espresso.perf; +package com.oracle.truffle.espresso.classfile.perf; /** * An {@link AutoCloseable} whose {@link #close()} does not throw a checked exception. diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/DebugCounter.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/DebugCounter.java similarity index 80% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/DebugCounter.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/DebugCounter.java index cd1bd593a2cc..d4f1f6a4f03c 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/DebugCounter.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/DebugCounter.java @@ -21,15 +21,23 @@ * questions. */ -package com.oracle.truffle.espresso.perf; - -import com.oracle.truffle.espresso.EspressoOptions; +package com.oracle.truffle.espresso.classfile.perf; import java.io.PrintStream; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicLong; public abstract class DebugCounter { + + private static boolean booleanProperty(String name, boolean defaultValue) { + String value = System.getProperty(name); + return value == null ? defaultValue : value.equalsIgnoreCase("true"); + } + + // These are host properties e.g. use --vm.Despresso.DebugCounters=true . + public static final boolean DebugCounters = booleanProperty("espresso.DebugCounters", false); + public static final boolean DumpDebugCounters = booleanProperty("espresso.DumpDebugCounters", true); + private DebugCounter() { } @@ -38,11 +46,11 @@ private DebugCounter() { public abstract void inc(); public static DebugCounter create(String name) { - return EspressoOptions.DebugCounters ? DebugCounterImpl.createImpl(name) : Dummy.INSTANCE; + return DebugCounters ? DebugCounterImpl.createImpl(name) : Dummy.INSTANCE; } public static void dumpCounters() { - if (EspressoOptions.DebugCounters) { + if (DebugCounters) { DebugCounterImpl.dumpCounters(System.out); } } @@ -85,8 +93,8 @@ private static void dumpCounters(PrintStream out) { } static { - assert EspressoOptions.DebugCounters; - if (EspressoOptions.DumpDebugCounters) { + assert DebugCounters; + if (DumpDebugCounters) { Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { public void run() { dumpCounters(System.out); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/DebugTimer.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/DebugTimer.java similarity index 94% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/DebugTimer.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/DebugTimer.java index e1420d07a987..269c7fe8fc97 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/DebugTimer.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/DebugTimer.java @@ -21,7 +21,7 @@ * questions. */ -package com.oracle.truffle.espresso.perf; +package com.oracle.truffle.espresso.classfile.perf; import java.util.ArrayList; import java.util.List; @@ -29,7 +29,7 @@ import java.util.function.Supplier; import com.oracle.truffle.api.TruffleLogger; -import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.descriptors.ErrorUtil; public final class DebugTimer { final String name; @@ -106,7 +106,7 @@ public Boolean get() { @Override void tick(long tick) { - EspressoError.guarantee(entered.get(), "Not entered scope."); + ErrorUtil.guarantee(entered.get(), "Not entered scope."); counter.getAndIncrement(); clock.getAndAdd(tick); entered.set(false); @@ -124,7 +124,7 @@ void report(TruffleLogger logger, String name) { @Override void enter() { // Ensure we are not counting twice. - EspressoError.guarantee(!entered.get(), "Counting twice for timer."); + ErrorUtil.guarantee(!entered.get(), "Counting twice for timer."); entered.set(true); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/TimerCollection.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/TimerCollection.java similarity index 96% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/TimerCollection.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/TimerCollection.java index 45981b91a327..7f4a601502f7 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/TimerCollection.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/TimerCollection.java @@ -21,7 +21,7 @@ * questions. */ -package com.oracle.truffle.espresso.perf; +package com.oracle.truffle.espresso.classfile.perf; import com.oracle.truffle.api.TruffleLogger; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/TimerCollectionImpl.java b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/TimerCollectionImpl.java similarity index 98% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/TimerCollectionImpl.java rename to espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/TimerCollectionImpl.java index 796300208737..eabae1383b5c 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/perf/TimerCollectionImpl.java +++ b/espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/perf/TimerCollectionImpl.java @@ -21,7 +21,7 @@ * questions. */ -package com.oracle.truffle.espresso.perf; +package com.oracle.truffle.espresso.classfile.perf; import java.util.HashSet; import java.util.Map; diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/MethodRef.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/MethodRef.java index a7ddc903237d..1dd094003325 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/MethodRef.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/MethodRef.java @@ -23,6 +23,8 @@ package com.oracle.truffle.espresso.jdwp.api; import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.espresso.classfile.attributes.LineNumberTableRef; +import com.oracle.truffle.espresso.classfile.attributes.LocalVariableTableRef; /** * A representation of a method. diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/TagConstants.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/TagConstants.java index 2116109c5e20..28c99b8802f5 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/TagConstants.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/api/TagConstants.java @@ -22,6 +22,8 @@ */ package com.oracle.truffle.espresso.jdwp.api; +import com.oracle.truffle.espresso.classfile.JavaKind; + public final class TagConstants { public static final byte ARRAY = '['; @@ -81,4 +83,29 @@ public static byte getTagFromPrimitive(Object boxed) { } throw new RuntimeException("boxed object: " + boxed.getClass() + " is not a primitive"); } + + public static byte toTagConstant(JavaKind kind) { + switch (kind) { + case Boolean: + return TagConstants.BOOLEAN; + case Byte: + return TagConstants.BYTE; + case Short: + return TagConstants.SHORT; + case Char: + return TagConstants.CHAR; + case Int: + return TagConstants.INT; + case Float: + return TagConstants.FLOAT; + case Long: + return TagConstants.LONG; + case Double: + return TagConstants.DOUBLE; + case Object: + return TagConstants.OBJECT; + default: + return -1; + } + } } diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java index 420c67d0f5b0..2e799106cb91 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java @@ -37,8 +37,8 @@ import com.oracle.truffle.espresso.jdwp.api.JDWPConstantPool; import com.oracle.truffle.espresso.jdwp.api.JDWPContext; import com.oracle.truffle.espresso.jdwp.api.KlassRef; -import com.oracle.truffle.espresso.jdwp.api.LineNumberTableRef; -import com.oracle.truffle.espresso.jdwp.api.LocalRef; +import com.oracle.truffle.espresso.classfile.attributes.LineNumberTableRef; +import com.oracle.truffle.espresso.classfile.attributes.LocalRef; import com.oracle.truffle.espresso.jdwp.api.MethodRef; import com.oracle.truffle.espresso.jdwp.api.ModuleRef; import com.oracle.truffle.espresso.jdwp.api.MonitorStackInfo; diff --git a/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionProcessor.java b/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionProcessor.java index f2ebd15bfbf7..cb6280aa054d 100644 --- a/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionProcessor.java +++ b/espresso/src/com.oracle.truffle.espresso.processor/src/com/oracle/truffle/espresso/processor/SubstitutionProcessor.java @@ -84,7 +84,7 @@ public final class SubstitutionProcessor extends EspressoProcessor { private static final String SUBSTITUTION_CLASS_NAMES = "substitutionClassNames"; private static final String VERSION_FILTER_METHOD = "isValidFor"; private static final String INLINE_IN_BYTECODE_METHOD = "inlineInBytecode"; - private static final String JAVA_VERSION = "com.oracle.truffle.espresso.runtime.JavaVersion"; + private static final String JAVA_VERSION = "com.oracle.truffle.espresso.classfile.JavaVersion"; private static final String INSTANCE = "INSTANCE"; diff --git a/espresso/src/com.oracle.truffle.espresso/.checkstyle_checks.xml b/espresso/src/com.oracle.truffle.espresso/.checkstyle_checks.xml index 3891d4738941..c34e25ad18b8 100644 --- a/espresso/src/com.oracle.truffle.espresso/.checkstyle_checks.xml +++ b/espresso/src/com.oracle.truffle.espresso/.checkstyle_checks.xml @@ -226,7 +226,7 @@ - + diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoLanguage.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoLanguage.java index 171a4e67ac48..9916a8b93ca3 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoLanguage.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoLanguage.java @@ -59,18 +59,18 @@ import com.oracle.truffle.api.staticobject.DefaultStaticProperty; import com.oracle.truffle.api.staticobject.StaticProperty; import com.oracle.truffle.api.staticobject.StaticShape; -import com.oracle.truffle.espresso.descriptors.Names; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.StaticSymbols; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Symbols; -import com.oracle.truffle.espresso.descriptors.Types; -import com.oracle.truffle.espresso.descriptors.Utf8ConstantTable; +import com.oracle.truffle.espresso.classfile.descriptors.Names; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.StaticSymbols; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbols; +import com.oracle.truffle.espresso.classfile.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Utf8ConstantTable; import com.oracle.truffle.espresso.impl.SuppressFBWarnings; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.nodes.commands.ExitCodeNode; import com.oracle.truffle.espresso.nodes.commands.GetBindingsNode; import com.oracle.truffle.espresso.nodes.commands.ReferenceProcessRootNode; @@ -80,7 +80,7 @@ import com.oracle.truffle.espresso.runtime.EspressoException; import com.oracle.truffle.espresso.runtime.EspressoThreadLocalState; import com.oracle.truffle.espresso.runtime.GuestAllocator; -import com.oracle.truffle.espresso.runtime.JavaVersion; +import com.oracle.truffle.espresso.classfile.JavaVersion; import com.oracle.truffle.espresso.runtime.OS; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject.StaticObjectFactory; 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 a1bbf6b3244b..04aaa99a7e62 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 @@ -42,7 +42,7 @@ import com.oracle.truffle.api.Option; import com.oracle.truffle.espresso.jdwp.api.JDWPOptions; -import com.oracle.truffle.espresso.runtime.JavaVersion; +import com.oracle.truffle.espresso.classfile.JavaVersion; @Option.Group(EspressoLanguage.ID) public final class EspressoOptions { @@ -697,10 +697,6 @@ public enum GuestFieldOffsetStrategyEnum { stability = OptionStability.EXPERIMENTAL, // usageSyntax = "false|true") public static final OptionKey EagerFrameAnalysis = new OptionKey<>(false); - // These are host properties e.g. use --vm.Despresso.DebugCounters=true . - public static final boolean DebugCounters = booleanProperty("espresso.DebugCounters", false); - public static final boolean DumpDebugCounters = booleanProperty("espresso.DumpDebugCounters", true); - // Properties for FinalizationSupport e.g. --vm.Despresso.finalization.UnsafeOverride=false . public static final boolean UnsafeOverride = booleanProperty("espresso.finalization.UnsafeOverride", true); public static final boolean InjectClasses = booleanProperty("espresso.finalization.InjectClasses", !JavaVersion.HOST_VERSION.java19OrLater()); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoScope.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoScope.java index 34fe0a857c96..b26892cdde9f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoScope.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoScope.java @@ -42,10 +42,9 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.espresso.classfile.attributes.Local; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; @@ -62,7 +61,7 @@ public static Object createVariables(Local[] liveLocals, Frame frame, Symbol build(Method method) { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/EspressoFrameDescriptor.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/EspressoFrameDescriptor.java index 3dde9cebb563..ab329a070817 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/EspressoFrameDescriptor.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/EspressoFrameDescriptor.java @@ -34,12 +34,12 @@ import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.verifier.StackMapFrameParser; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/FrameAnalysis.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/FrameAnalysis.java index 5a888f94d2d3..6dcdafa1337b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/FrameAnalysis.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/FrameAnalysis.java @@ -23,207 +23,207 @@ package com.oracle.truffle.espresso.analysis.frame; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.AALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.AASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ACONST_NULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ANEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ARETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ARRAYLENGTH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ATHROW; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BIPUSH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CHECKCAST; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCMPG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCMPL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP2_X1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP2_X2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP_X1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP_X2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCMPG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCMPL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GETFIELD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GETSTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GOTO; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GOTO_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2B; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2C; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2S; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IAND; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_4; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_5; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_M1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFEQ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFGE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFGT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFLE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFLT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFNE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFNONNULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFNULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ACMPEQ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ACMPNE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPEQ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPGE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPGT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPLE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPLT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPNE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IINC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INSTANCEOF; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEDYNAMIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEINTERFACE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKESPECIAL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKESTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEVIRTUAL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISHL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IUSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IXOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.JSR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.JSR_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LAND; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCMP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDC2_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDC_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LOOKUPSWITCH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSHL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LUSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LXOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MONITORENTER; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MONITOREXIT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MULTIANEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NEW; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NOP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.POP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.POP2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTFIELD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTSTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.RET; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.RETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SIPUSH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SWAP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.TABLESWITCH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.AALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.AASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ACONST_NULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ANEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ARETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ARRAYLENGTH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ATHROW; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BIPUSH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CHECKCAST; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCMPG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCMPL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP2_X1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP2_X2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP_X1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP_X2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCMPG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCMPL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GETFIELD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GETSTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GOTO; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GOTO_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2B; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2C; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2S; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IAND; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_4; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_5; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_M1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFEQ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFGE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFGT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFLE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFLT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFNE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFNONNULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFNULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ACMPEQ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ACMPNE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPEQ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPGE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPGT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPLE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPLT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPNE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IINC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INSTANCEOF; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEDYNAMIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEINTERFACE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKESPECIAL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKESTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEVIRTUAL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISHL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IUSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IXOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.JSR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.JSR_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LAND; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCMP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDC2_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDC_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LOOKUPSWITCH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSHL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LUSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LXOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MONITORENTER; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MONITOREXIT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MULTIANEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NEW; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NOP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.POP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.POP2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.PUTFIELD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.PUTSTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.RET; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.RETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SIPUSH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SWAP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.TABLESWITCH; import java.util.ArrayDeque; import java.util.BitSet; @@ -233,25 +233,25 @@ import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.analysis.frame.EspressoFrameDescriptor.Builder; import com.oracle.truffle.espresso.analysis.liveness.LivenessAnalysis; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; -import com.oracle.truffle.espresso.bytecode.BytecodeSwitch; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeSwitch; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.classfile.ClassfileParser; import com.oracle.truffle.espresso.classfile.ConstantPool; import com.oracle.truffle.espresso.classfile.Constants; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; +import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool; import com.oracle.truffle.espresso.classfile.attributes.StackMapTableAttribute; import com.oracle.truffle.espresso.classfile.constantpool.DynamicConstant; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.ExceptionHandler; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.ExceptionHandler; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.verifier.StackMapFrameParser; import com.oracle.truffle.espresso.verifier.VerificationTypeInfo; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/FrameType.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/FrameType.java index e54bf9b7c0d5..1afa70dd64d4 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/FrameType.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/FrameType.java @@ -23,11 +23,11 @@ package com.oracle.truffle.espresso.analysis.frame; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; public abstract class FrameType { public static final FrameType INT = new PrimitiveFrameType(JavaKind.Int); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/graph/EspressoExecutionGraph.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/graph/EspressoExecutionGraph.java index 1e730b7e1cdb..e0b79409114a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/graph/EspressoExecutionGraph.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/graph/EspressoExecutionGraph.java @@ -25,7 +25,7 @@ import java.util.BitSet; -import com.oracle.truffle.espresso.meta.ExceptionHandler; +import com.oracle.truffle.espresso.classfile.ExceptionHandler; public final class EspressoExecutionGraph implements Graph { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/DefaultClassHierarchyOracle.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/DefaultClassHierarchyOracle.java index a288273ee0e2..1d48904e29b7 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/DefaultClassHierarchyOracle.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/hierarchy/DefaultClassHierarchyOracle.java @@ -23,7 +23,7 @@ package com.oracle.truffle.espresso.analysis.hierarchy; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.impl.ObjectKlass; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/BlockBoundaryFinder.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/BlockBoundaryFinder.java index 3865f3d903e7..6d19bd31a2b0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/BlockBoundaryFinder.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/BlockBoundaryFinder.java @@ -38,7 +38,7 @@ import com.oracle.truffle.espresso.analysis.BlockLogger; import com.oracle.truffle.espresso.analysis.Util; import com.oracle.truffle.espresso.analysis.graph.LinkedBlock; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; import com.oracle.truffle.espresso.impl.Method; /** diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LivenessAnalysis.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LivenessAnalysis.java index a08dc2df904d..10f81ce0ac3b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LivenessAnalysis.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LivenessAnalysis.java @@ -45,12 +45,12 @@ import com.oracle.truffle.espresso.analysis.liveness.actions.MultiAction; import com.oracle.truffle.espresso.analysis.liveness.actions.NullOutAction; import com.oracle.truffle.espresso.analysis.liveness.actions.SelectEdgeAction; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.perf.DebugCloseable; -import com.oracle.truffle.espresso.perf.DebugTimer; -import com.oracle.truffle.espresso.perf.TimerCollection; +import com.oracle.truffle.espresso.classfile.perf.DebugCloseable; +import com.oracle.truffle.espresso.classfile.perf.DebugTimer; +import com.oracle.truffle.espresso.classfile.perf.TimerCollection; public final class LivenessAnalysis { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LoadStoreFinder.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LoadStoreFinder.java index b13da65c55d1..45bfa823f0dc 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LoadStoreFinder.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LoadStoreFinder.java @@ -23,55 +23,55 @@ package com.oracle.truffle.espresso.analysis.liveness; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IINC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.RET; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.isLoad; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.isStore; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IINC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.RET; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.isLoad; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.isStore; import com.oracle.truffle.espresso.analysis.graph.Graph; import com.oracle.truffle.espresso.analysis.graph.LinkedBlock; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.impl.Method; /** diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LoopPropagatorClosure.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LoopPropagatorClosure.java index 530e45810e7a..5d40fd1f6122 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LoopPropagatorClosure.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LoopPropagatorClosure.java @@ -38,7 +38,7 @@ import com.oracle.truffle.espresso.analysis.Util; import com.oracle.truffle.espresso.analysis.graph.Graph; import com.oracle.truffle.espresso.analysis.graph.LinkedBlock; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; /** * Glues together loop entries and loop ends by forcing loop ends to have an end state that is a diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodePrinter.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodePrinter.java new file mode 100644 index 000000000000..72f96b28a4bf --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/BytecodePrinter.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.bytecode; + +import com.oracle.truffle.espresso.impl.Klass; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeLookupSwitch; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeTableSwitch; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; +import com.oracle.truffle.espresso.classfile.constantpool.InvokeDynamicConstant; +import com.oracle.truffle.espresso.classfile.constantpool.MethodRefConstant; + +import java.io.PrintStream; +import java.util.Arrays; + +public class BytecodePrinter { + + public static void printBytecode(Klass klass, PrintStream out, byte[] code) { + BytecodeStream stream = new BytecodeStream(code); + try { + ConstantPool pool = klass.getConstantPool(); + int bci = 0; + int nextBCI = 0; + StringBuilder str = new StringBuilder(); + while (nextBCI < stream.endBCI()) { + str.setLength(0); + bci = nextBCI; + int opcode = stream.currentBC(bci); + str.append(bci).append(": ").append(Bytecodes.nameOf(opcode)).append(" "); + nextBCI = stream.nextBCI(bci); + if (Bytecodes.isBranch(opcode)) { + // {bci}: {branch bytecode} {target} + str.append(stream.readBranchDest(bci)); + } else if (opcode == Bytecodes.NEW) { + // {bci}: new {class name} + int cpi = stream.readCPI(bci); + ClassConstant cc = (ClassConstant) pool.at(cpi); + str.append(cc.getName(pool)); + } else if (opcode == Bytecodes.INVOKEDYNAMIC) { + // {bci}: #{bootstrap method index} -> {name}:{signature} + int cpi = stream.readCPI(bci); + InvokeDynamicConstant idc = (InvokeDynamicConstant) pool.at(cpi); + str.append("#").append(idc.getBootstrapMethodAttrIndex()).append(" -> ").append(idc.getName(pool)).append(":").append(idc.getSignature(pool)); + } else if (Bytecodes.isInvoke(opcode)) { + // {bci}: invoke{} {class}.{method name}:{method signature} + int cpi = stream.readCPI(bci); + MethodRefConstant mrc = (MethodRefConstant) pool.at(cpi); + str.append(mrc.getHolderKlassName(pool)).append(".").append(mrc.getName(pool)).append(":").append(mrc.getDescriptor(pool)); + } else if (opcode == Bytecodes.TABLESWITCH) { + // @formatter:off + // checkstyle: stop + + // {bci}: tableswitch + // {key1}: {target1} + // ... + // {keyN}: {targetN} + + // @formatter:on + // Checkstyle: resume + str.append('\n'); + BytecodeTableSwitch helper = BytecodeTableSwitch.INSTANCE; + int low = helper.lowKey(stream, bci); + int high = helper.highKey(stream, bci); + for (int i = low; i != high + 1; i++) { + str.append('\t').append(i).append(": ").append(helper.targetAt(stream, bci, i)).append('\n'); + } + str.append("\tdefault: ").append(helper.defaultTarget(stream, bci)); + } else if (opcode == Bytecodes.LOOKUPSWITCH) { + // @formatter:off + // checkstyle: stop + + // {bci}: lookupswitch + // {key1}: {target1} + // ... + // {keyN}: {targetN} + + // @formatter:on + // Checkstyle: resume + str.append('\n'); + BytecodeLookupSwitch helper = BytecodeLookupSwitch.INSTANCE; + int low = 0; + int high = helper.numberOfCases(stream, bci) - 1; + for (int i = low; i <= high; i++) { + str.append('\t').append(helper.keyAt(stream, bci, i)).append(": ").append(helper.targetAt(stream, bci, i)); + } + str.append("\tdefault: ").append(helper.defaultTarget(stream, bci)); + } else if (opcode == Bytecodes.IINC) { + str.append(" ").append(stream.readLocalIndex(bci)).append(" ").append(stream.readIncrement(bci)); + } else { + // {bci}: {opcode} {corresponding value} + if (nextBCI - bci == 2) { + str.append(stream.readUByte(bci + 1)); + } + if (nextBCI - bci == 3) { + str.append(stream.readShort(bci)); + } + if (nextBCI - bci == 5) { + str.append(stream.readInt(bci + 1)); + } + } + out.println(str.toString()); + } + } catch (Throwable e) { + throw EspressoError.shouldNotReachHere("Exception thrown during bytecode printing, aborting...", e); + } + } + + public static void printRawBytecode(PrintStream out, byte[] code) { + out.println(Arrays.toString(code)); + } + + public static void print(Klass klass, byte[] code, PrintStream out) { + try { + printBytecode(klass, out, code); + } catch (Throwable e) { + throw EspressoError.shouldNotReachHere("Throw during printing. Aborting...", e); + } + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/MapperBCI.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/MapperBCI.java index 15bc575bd66f..b7e1c7b4f5c2 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/MapperBCI.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/bytecode/MapperBCI.java @@ -30,6 +30,7 @@ import com.oracle.truffle.espresso.classfile.attributes.LineNumberTableAttribute; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.nodes.EspressoNode; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; /** * lightweight map from BCI to array index. The contract is easy, upon lookup, returns the index of diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ConstantPool.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ConstantPool.java deleted file mode 100644 index f506e48accbe..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/ConstantPool.java +++ /dev/null @@ -1,656 +0,0 @@ -/* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile; - -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.CLASS; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.DOUBLE; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.FIELD_REF; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.FLOAT; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.INTEGER; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.INTERFACE_METHOD_REF; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.INVOKEDYNAMIC; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.LONG; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.METHOD_REF; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.MODULE; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.NAME_AND_TYPE; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.PACKAGE; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.STRING; -import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.UTF8; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Formatter; -import java.util.List; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; -import com.oracle.truffle.espresso.classfile.constantpool.ClassMethodRefConstant; -import com.oracle.truffle.espresso.classfile.constantpool.DoubleConstant; -import com.oracle.truffle.espresso.classfile.constantpool.DynamicConstant; -import com.oracle.truffle.espresso.classfile.constantpool.FieldRefConstant; -import com.oracle.truffle.espresso.classfile.constantpool.FloatConstant; -import com.oracle.truffle.espresso.classfile.constantpool.IntegerConstant; -import com.oracle.truffle.espresso.classfile.constantpool.InterfaceMethodRefConstant; -import com.oracle.truffle.espresso.classfile.constantpool.InvalidConstant; -import com.oracle.truffle.espresso.classfile.constantpool.InvokeDynamicConstant; -import com.oracle.truffle.espresso.classfile.constantpool.LongConstant; -import com.oracle.truffle.espresso.classfile.constantpool.MemberRefConstant; -import com.oracle.truffle.espresso.classfile.constantpool.MethodHandleConstant; -import com.oracle.truffle.espresso.classfile.constantpool.MethodRefConstant; -import com.oracle.truffle.espresso.classfile.constantpool.MethodTypeConstant; -import com.oracle.truffle.espresso.classfile.constantpool.NameAndTypeConstant; -import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant; -import com.oracle.truffle.espresso.classfile.constantpool.StringConstant; -import com.oracle.truffle.espresso.classfile.constantpool.Utf8Constant; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.ModifiedUTF8; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.impl.ClassLoadingEnv; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.perf.DebugCounter; -import com.oracle.truffle.espresso.runtime.EspressoContext; -import com.oracle.truffle.espresso.runtime.EspressoException; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; -import com.oracle.truffle.espresso.substitutions.JavaType; - -/** - * Immutable, shareable constant-pool representation. - */ -public abstract class ConstantPool { - - // @formatter:off - public static final byte CONSTANT_Utf8 = 1; - public static final byte CONSTANT_Integer = 3; - public static final byte CONSTANT_Float = 4; - public static final byte CONSTANT_Long = 5; - public static final byte CONSTANT_Double = 6; - public static final byte CONSTANT_Class = 7; - public static final byte CONSTANT_String = 8; - public static final byte CONSTANT_Fieldref = 9; - public static final byte CONSTANT_Methodref = 10; - public static final byte CONSTANT_InterfaceMethodref = 11; - public static final byte CONSTANT_NameAndType = 12; - public static final byte CONSTANT_MethodHandle = 15; - public static final byte CONSTANT_MethodType = 16; - public static final byte CONSTANT_Dynamic = 17; - public static final byte CONSTANT_InvokeDynamic = 18; - public static final byte CONSTANT_Module = 19; - public static final byte CONSTANT_Package = 20; - // @formatter:on - - private static final DebugCounter UTF8_ENTRY_COUNT = DebugCounter.create("UTF8 Constant Pool entries"); - - public enum Tag { - INVALID(0), - UTF8(CONSTANT_Utf8), - INTEGER(CONSTANT_Integer, true), - FLOAT(CONSTANT_Float, true), - LONG(CONSTANT_Long, true), - DOUBLE(CONSTANT_Double, true), - CLASS(CONSTANT_Class, true), - STRING(CONSTANT_String, true), - FIELD_REF(CONSTANT_Fieldref), - METHOD_REF(CONSTANT_Methodref), - INTERFACE_METHOD_REF(CONSTANT_InterfaceMethodref), - NAME_AND_TYPE(CONSTANT_NameAndType), - METHODHANDLE(CONSTANT_MethodHandle, true), - METHODTYPE(CONSTANT_MethodType, true), - DYNAMIC(CONSTANT_Dynamic, true), - INVOKEDYNAMIC(CONSTANT_InvokeDynamic), - MODULE(CONSTANT_Module), - PACKAGE(CONSTANT_Package); - - private final byte value; - private final boolean loadable; - - Tag(int value) { - this(value, false); - } - - Tag(int value, boolean isLoadable) { - assert (byte) value == value; - this.value = (byte) value; - this.loadable = isLoadable; - } - - public final int getValue() { - return value; - } - - public final boolean isLoadable() { - return loadable; - } - - public static Tag fromValue(int value) { - // @formatter:off - switch (value) { - case 1: return UTF8; - case 3: return INTEGER; - case 4: return FLOAT; - case 5: return LONG; - case 6: return DOUBLE; - case 7: return CLASS; - case 8: return STRING; - case 9: return FIELD_REF; - case 10: return METHOD_REF; - case 11: return INTERFACE_METHOD_REF; - case 12: return NAME_AND_TYPE; - case 15: return METHODHANDLE; - case 16: return METHODTYPE; - case 17: return DYNAMIC; - case 18: return INVOKEDYNAMIC; - case 19: return MODULE; - case 20: return PACKAGE; - default: return null; - } - // @formatter:on - } - - public boolean isValidForVersion(int major) { - switch (this) { - case UTF8: // fall-through - case INTEGER: // fall-through - case FLOAT: // fall-through - case LONG: // fall-through - case DOUBLE: // fall-through - case CLASS: // fall-through - case STRING: // fall-through - case FIELD_REF: // fall-through - case METHOD_REF: // fall-through - case INTERFACE_METHOD_REF: // fall-through - case NAME_AND_TYPE: // fall-through - return major >= 45; - case METHODHANDLE: // fall-through - case METHODTYPE: - case INVOKEDYNAMIC: - return major >= 51; - case DYNAMIC: - return major >= 55; - case MODULE: - case PACKAGE: - return major >= 53; - default: - throw EspressoError.shouldNotReachHere("Cannot validate tag version for" + this); - } - } - - public static final List VALUES = Collections.unmodifiableList(Arrays.asList(values())); - - } - - public abstract int getMajorVersion(); - - public abstract int getMinorVersion(); - - public abstract int length(); - - public abstract PoolConstant at(int index, String description); - - public final PoolConstant at(int index) { - return at(index, null); - } - - public abstract byte[] getRawBytes(); - - static @JavaType(ClassFormatError.class) EspressoException unexpectedEntry(int index, ConstantPool.Tag tag, String description, ConstantPool.Tag... expected) { - CompilerDirectives.transferToInterpreter(); - throw classFormatError("Constant pool entry" + (description == null ? "" : " for " + description) + " at " + index + " is a " + tag + ", expected " + Arrays.toString(expected)); - } - - final @JavaType(ClassFormatError.class) EspressoException unexpectedEntry(int index, String description, ConstantPool.Tag... expected) { - CompilerDirectives.transferToInterpreter(); - throw unexpectedEntry(index, tagAt(index), description, expected); - } - - static @JavaType(VerifyError.class) EspressoException verifyError(String message) { - CompilerDirectives.transferToInterpreter(); - Meta meta = EspressoContext.get(null).getMeta(); - if (meta.java_lang_VerifyError == null) { - throw EspressoError.fatal("VerifyError during early startup: ", message); - } - throw meta.throwExceptionWithMessage(meta.java_lang_VerifyError, message); - } - - public static @JavaType(ClassFormatError.class) EspressoException classFormatError(String message) { - CompilerDirectives.transferToInterpreter(); - Meta meta = EspressoContext.get(null).getMeta(); - if (meta.java_lang_ClassFormatError == null) { - throw EspressoError.fatal("ClassFormatError during early startup: ", message); - } - throw meta.throwExceptionWithMessage(meta.java_lang_ClassFormatError, message); - } - - static @JavaType(NoClassDefFoundError.class) EspressoException noClassDefFoundError(String message) { - CompilerDirectives.transferToInterpreter(); - Meta meta = EspressoContext.get(null).getMeta(); - if (meta.java_lang_NoClassDefFoundError == null) { - throw EspressoError.fatal("NoClassDefFoundError during early startup: ", message); - } - throw meta.throwExceptionWithMessage(meta.java_lang_NoClassDefFoundError, message); - } - - /** - * Gets the tag at a given index. If {@code index == 0} or there is no valid entry at - * {@code index} (e.g. it denotes the slot following a double or long entry), then - * {@link ConstantPool.Tag#INVALID} is returned. - */ - public final Tag tagAt(int index) { - return at(index).tag(); - } - - public final int intAt(int index) { - return intAt(index, null); - } - - public final int intAt(int index, String description) { - try { - final IntegerConstant constant = (IntegerConstant) at(index); - return constant.value(); - } catch (ClassCastException e) { - throw unexpectedEntry(index, description, INTEGER); - } - } - - public final long longAt(int index) { - return longAt(index, null); - } - - public final long longAt(int index, String description) { - try { - final LongConstant constant = (LongConstant) at(index); - return constant.value(); - } catch (ClassCastException e) { - throw unexpectedEntry(index, description, LONG); - } - } - - public final float floatAt(int index) { - return floatAt(index, null); - } - - public final float floatAt(int index, String description) { - try { - final FloatConstant constant = (FloatConstant) at(index); - return constant.value(); - } catch (ClassCastException e) { - throw unexpectedEntry(index, description, FLOAT); - } - } - - public final double doubleAt(int index) { - return doubleAt(index, null); - } - - public final double doubleAt(int index, String description) { - try { - final DoubleConstant constant = (DoubleConstant) at(index); - return constant.value(); - } catch (ClassCastException e) { - throw unexpectedEntry(index, description, DOUBLE); - } - } - - public final Symbol symbolAt(int index) { - return symbolAt(index, null); - } - - @SuppressWarnings("unchecked") - public final Symbol symbolAt(int index, String description) { - try { - final Utf8Constant constant = (Utf8Constant) at(index); - return (Symbol) constant.value(); - } catch (ClassCastException e) { - throw unexpectedEntry(index, description, UTF8); - } - } - - public final Utf8Constant utf8At(int index) { - return utf8At(index, null); - } - - public final Utf8Constant utf8At(int index, String description) { - try { - return (Utf8Constant) at(index); - } catch (ClassCastException e) { - throw unexpectedEntry(index, description, UTF8); - } - } - - public final Symbol stringAt(int index) { - return stringAt(index, null); - } - - public final Symbol stringAt(int index, String description) { - try { - final StringConstant constant = (StringConstant) at(index); - return constant.getSymbol(this); - } catch (ClassCastException e) { - throw unexpectedEntry(index, description, STRING); - } - } - - // region unresolved constants - - public final NameAndTypeConstant nameAndTypeAt(int index) { - return nameAndTypeAt(index, null); - } - - public final NameAndTypeConstant nameAndTypeAt(int index, String description) { - try { - return (NameAndTypeConstant) at(index); - } catch (ClassCastException e) { - throw unexpectedEntry(index, description, NAME_AND_TYPE); - } - } - - public final ClassConstant classAt(int index) { - return classAt(index, null); - } - - public final ClassConstant classAt(int index, String description) { - try { - return (ClassConstant) at(index); - } catch (ClassCastException e) { - throw unexpectedEntry(index, description, CLASS); - } - } - - public final MemberRefConstant memberAt(int index) { - return memberAt(index, null); - } - - public final MemberRefConstant memberAt(int index, String description) { - try { - return (MemberRefConstant) at(index); - } catch (ClassCastException e) { - throw unexpectedEntry(index, description, METHOD_REF, INTERFACE_METHOD_REF, FIELD_REF); - } - } - - public final MethodRefConstant methodAt(int index) { - try { - return (MethodRefConstant) at(index); - } catch (ClassCastException e) { - throw unexpectedEntry(index, null, METHOD_REF, INTERFACE_METHOD_REF); - } - } - - public final ClassMethodRefConstant classMethodAt(int index) { - try { - return (ClassMethodRefConstant) at(index); - } catch (ClassCastException e) { - throw unexpectedEntry(index, null, METHOD_REF); - } - } - - public final InterfaceMethodRefConstant interfaceMethodAt(int index) { - try { - return (InterfaceMethodRefConstant) at(index); - } catch (ClassCastException e) { - throw unexpectedEntry(index, null, INTERFACE_METHOD_REF); - } - } - - public final FieldRefConstant fieldAt(int index) { - try { - return (FieldRefConstant) at(index); - } catch (ClassCastException e) { - throw unexpectedEntry(index, null, FIELD_REF); - } - } - - public final StringConstant stringConstantAt(int index) { - try { - return (StringConstant) at(index); - } catch (ClassCastException e) { - throw unexpectedEntry(index, null, STRING); - } - } - - public final InvokeDynamicConstant indyAt(int index) { - try { - return (InvokeDynamicConstant) at(index); - } catch (ClassCastException e) { - throw unexpectedEntry(index, null, INVOKEDYNAMIC); - } - } - - // endregion unresolved constants - - @Override - public String toString() { - Formatter buf = new Formatter(); - for (int i = 0; i < length(); i++) { - PoolConstant c = at(i); - buf.format("#%d = %-15s // %s%n", i, c.tag(), c.toString(this)); - } - return buf.toString(); - } - - /** - * Creates a constant pool from a class file. - */ - public static ImmutableConstantPool parse(ClassLoadingEnv env, ClassfileStream stream, ClassfileParser parser, int majorVersion, int minorVersion) { - return parse(env, stream, parser, null, majorVersion, minorVersion); - } - - /** - * Creates a constant pool from a class file. - */ - public static ImmutableConstantPool parse(ClassLoadingEnv env, ClassfileStream stream, ClassfileParser parser, StaticObject[] patches, int majorVersion, int minorVersion) { - final int length = stream.readU2(); - if (length < 1) { - throw stream.classFormatError("Invalid constant pool size (" + length + ")"); - } - int rawPoolStartPosition = stream.getPosition(); - final PoolConstant[] entries = new PoolConstant[length]; - entries[0] = InvalidConstant.VALUE; - - int i = 1; - while (i < length) { - final int tagByte = stream.readU1(); - final Tag tag = Tag.fromValue(tagByte); - if (tag == null) { - throw classFormatError("Invalid constant pool entry type at index " + i); - } - // check version for the tag except for module/package entries which must cause NDCFE - if (!tag.isValidForVersion(parser.getMajorVersion()) && tag != MODULE && tag != PACKAGE) { - throw classFormatError("Class file version does not support constant tag " + tagByte + " in class file"); - } - switch (tag) { - case CLASS: { - if (existsAt(patches, i)) { - StaticObject classSpecifier = patches[i]; - int index = stream.readU2(); - if (index == 0 || index >= length) { - throw classFormatError("Invalid Class constant index " + (i - 1)); - } - if (classSpecifier.getKlass().getType() == Type.java_lang_Class) { - entries[i] = ClassConstant.preResolved(classSpecifier.getMirrorKlass()); - } else { - entries[i] = ClassConstant.withString(env.getNames().lookup(env.getMeta().toHostString(patches[i]))); - } - - break; - } - int classNameIndex = stream.readU2(); - entries[i] = ClassConstant.create(classNameIndex); - break; - } - case STRING: { - int index = stream.readU2(); - if (index == 0 || index >= length) { - throw classFormatError("Invalid String constant index " + (i - 1)); - } - if (existsAt(patches, i)) { - entries[i] = StringConstant.preResolved(patches[i]); - } else { - entries[i] = StringConstant.create(index); - } - break; - } - case FIELD_REF: { - int classIndex = stream.readU2(); - int nameAndTypeIndex = stream.readU2(); - entries[i] = FieldRefConstant.create(classIndex, nameAndTypeIndex); - break; - } - case METHOD_REF: { - int classIndex = stream.readU2(); - int nameAndTypeIndex = stream.readU2(); - entries[i] = ClassMethodRefConstant.create(classIndex, nameAndTypeIndex); - break; - } - case INTERFACE_METHOD_REF: { - int classIndex = stream.readU2(); - int nameAndTypeIndex = stream.readU2(); - entries[i] = InterfaceMethodRefConstant.create(classIndex, nameAndTypeIndex); - break; - } - case NAME_AND_TYPE: { - int nameIndex = stream.readU2(); - int typeIndex = stream.readU2(); - entries[i] = NameAndTypeConstant.create(nameIndex, typeIndex); - break; - } - case INTEGER: { - if (existsAt(patches, i)) { - entries[i] = IntegerConstant.create(env.getMeta().unboxInteger(patches[i])); - stream.readS4(); - break; - } - entries[i] = IntegerConstant.create(stream.readS4()); - break; - } - case FLOAT: { - if (existsAt(patches, i)) { - entries[i] = FloatConstant.create(env.getMeta().unboxFloat(patches[i])); - stream.readFloat(); - break; - } - entries[i] = FloatConstant.create(stream.readFloat()); - break; - } - case LONG: { - if (existsAt(patches, i)) { - entries[i] = LongConstant.create(env.getMeta().unboxLong(patches[i])); - stream.readS8(); - } else { - entries[i] = LongConstant.create(stream.readS8()); - } - ++i; - try { - entries[i] = InvalidConstant.VALUE; - } catch (ArrayIndexOutOfBoundsException e) { - throw classFormatError("Invalid long constant index " + (i - 1)); - } - break; - } - case DOUBLE: { - if (existsAt(patches, i)) { - entries[i] = DoubleConstant.create(env.getMeta().unboxDouble(patches[i])); - stream.readDouble(); - } else { - entries[i] = DoubleConstant.create(stream.readDouble()); - } - ++i; - try { - entries[i] = InvalidConstant.VALUE; - } catch (ArrayIndexOutOfBoundsException e) { - throw classFormatError("Invalid double constant index " + (i - 1)); - } - break; - } - case UTF8: { - // Copy-less UTF8 constant. - // A new symbol is spawned (copy) only if doesn't already exists. - UTF8_ENTRY_COUNT.inc(); - ByteSequence bytes = stream.readByteSequenceUTF(); - entries[i] = env.getLanguage().getUtf8ConstantTable().getOrCreate(bytes); - break; - } - case METHODHANDLE: { - parser.checkInvokeDynamicSupport(tag); - int refKind = stream.readU1(); - int refIndex = stream.readU2(); - entries[i] = MethodHandleConstant.create(refKind, refIndex); - break; - } - case METHODTYPE: { - parser.checkInvokeDynamicSupport(tag); - entries[i] = MethodTypeConstant.create(stream.readU2()); - break; - } - case DYNAMIC: { - parser.checkDynamicConstantSupport(tag); - int bootstrapMethodAttrIndex = stream.readU2(); - int nameAndTypeIndex = stream.readU2(); - entries[i] = DynamicConstant.create(bootstrapMethodAttrIndex, nameAndTypeIndex); - parser.updateMaxBootstrapMethodAttrIndex(bootstrapMethodAttrIndex); - break; - } - case INVOKEDYNAMIC: { - parser.checkInvokeDynamicSupport(tag); - int bootstrapMethodAttrIndex = stream.readU2(); - int nameAndTypeIndex = stream.readU2(); - entries[i] = InvokeDynamicConstant.create(bootstrapMethodAttrIndex, nameAndTypeIndex); - parser.updateMaxBootstrapMethodAttrIndex(bootstrapMethodAttrIndex); - break; - } - default: { - parser.handleBadConstant(tag, stream); - break; - } - } - i++; - } - int rawPoolLength = stream.getPosition() - rawPoolStartPosition; - - ImmutableConstantPool constantPool = new ImmutableConstantPool(entries, majorVersion, minorVersion, rawPoolLength); - - if (parser.hasSeenBadConstant()) { - return constantPool; - } - - // Cannot faithfully reconstruct patched pools. obtaining raw pool of patched/hidden class - // is meaningless anyway. - assert patches != null || sameRawPool(constantPool, stream, rawPoolStartPosition, rawPoolLength); - - // Validation - for (int j = 1; j < constantPool.length(); ++j) { - entries[j].validate(constantPool); - } - - return constantPool; - } - - private static boolean sameRawPool(ConstantPool constantPool, ClassfileStream stream, int rawPoolStartPosition, int rawPoolLength) { - return Arrays.equals(constantPool.getRawBytes(), stream.getByteRange(rawPoolStartPosition, rawPoolLength)); - } - - private static boolean existsAt(StaticObject[] patches, int index) { - return patches != null && 0 <= index && index < patches.length && StaticObject.notNull(patches[index]); - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/Constants.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/Constants.java deleted file mode 100644 index 4965e91283d2..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/Constants.java +++ /dev/null @@ -1,711 +0,0 @@ -/* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile; - -public final class Constants { - - /* Access Flags */ - // @formatter:off - public static final int ACC_PUBLIC = 0x00000001; - public static final int ACC_PRIVATE = 0x00000002; - public static final int ACC_PROTECTED = 0x00000004; - public static final int ACC_STATIC = 0x00000008; - public static final int ACC_FINAL = 0x00000010; - public static final int ACC_SYNCHRONIZED = 0x00000020; - public static final int ACC_SUPER = 0x00000020; - public static final int ACC_VOLATILE = 0x00000040; - public static final int ACC_TRANSIENT = 0x00000080; - public static final int ACC_NATIVE = 0x00000100; - public static final int ACC_INTERFACE = 0x00000200; - public static final int ACC_ABSTRACT = 0x00000400; - public static final int ACC_STRICT = 0x00000800; - public static final int ACC_EXPLICIT = 0x00001000; - - public static final int ACC_BRIDGE = 0x00000040; - public static final int ACC_VARARGS = 0x00000080; - public static final int ACC_SYNTHETIC = 0x00001000; - public static final int ACC_ANNOTATION = 0x00002000; - public static final int ACC_ENUM = 0x00004000; - public static final int ACC_MANDATED = 0x00008000; - public static final int ACC_MODULE = 0x00008000; - - // Not part of the spec, used internally by the VM. - // Methods - public static final int ACC_FINALIZER = 0x00010000; - public static final int ACC_FORCE_INLINE = 0x00020000; - public static final int ACC_LAMBDA_FORM_COMPILED = 0x00040000; - public static final int ACC_CALLER_SENSITIVE = 0x00080000; - public static final int ACC_HIDDEN = 0x00100000; // also for fields - public static final int ACC_SCOPED = 0x00200000; - public static final int ACC_DONT_INLINE = 0x00400000; - // Classes - public static final int ACC_IS_HIDDEN_CLASS = 0x04000000; // synchronized with JVM_ACC_IS_HIDDEN_CLASS - // Fields - public static final int ACC_STABLE = 0x00010000; - - public static final int FIELD_ID_TYPE = 0x01000000; - public static final int FIELD_ID_OBFUSCATE = 0x02000000; - - public static final int JVM_ACC_WRITTEN_FLAGS = 0x00007FFF; - // @formatter:on - - // Table 4.1-A. Class access and property modifiers. - public static final int JVM_RECOGNIZED_CLASS_MODIFIERS = ACC_PUBLIC | - ACC_FINAL | - ACC_SUPER | // Only very old compilers. - ACC_INTERFACE | - ACC_ABSTRACT | - ACC_ANNOTATION | - ACC_ENUM | - ACC_SYNTHETIC; - - // Inner classes can be static, private or protected (classic VM does this) - public static final int RECOGNIZED_INNER_CLASS_MODIFIERS = (JVM_RECOGNIZED_CLASS_MODIFIERS | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC); - - // Table 4.5-A. Field access and property flags. - public static final int JVM_RECOGNIZED_FIELD_MODIFIERS = ACC_PUBLIC | - ACC_PRIVATE | - ACC_PROTECTED | - ACC_STATIC | - ACC_FINAL | - ACC_VOLATILE | - ACC_TRANSIENT | - ACC_ENUM | - ACC_SYNTHETIC; - - // Table 4.6-A. Method access and property flags. - public static final int JVM_RECOGNIZED_METHOD_MODIFIERS = ACC_PUBLIC | - ACC_PRIVATE | - ACC_PROTECTED | - ACC_STATIC | - ACC_FINAL | - ACC_SYNCHRONIZED | - ACC_BRIDGE | - ACC_VARARGS | - ACC_NATIVE | - ACC_ABSTRACT | - ACC_STRICT | - ACC_SYNTHETIC; - - /* Type codes for StackMap attribute */ - public static final int ITEM_Bogus = 0; // an unknown or uninitialized value - public static final int ITEM_Integer = 1; // a 32-bit integer - public static final int ITEM_Float = 2; // not used - public static final int ITEM_Double = 3; // not used - public static final int ITEM_Long = 4; // a 64-bit integer - public static final int ITEM_Null = 5; // the type of null - public static final int ITEM_InitObject = 6; // "this" in constructor - public static final int ITEM_Object = 7; // followed by 2-byte index of class name - public static final int ITEM_NewObject = 8; // followed by 2-byte ref to "new" - - /* Constants used in StackMapTable attribute */ - public static final int SAME_FRAME_BOUND = 64; - public static final int SAME_LOCALS_1_STACK_ITEM_BOUND = 128; - public static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247; - public static final int CHOP_BOUND = 251; - public static final int SAME_FRAME_EXTENDED = 251; - public static final int APPEND_FRAME_BOUND = 255; - public static final int FULL_FRAME = 255; - - public static final int MAX_ARRAY_DIMENSIONS = 255; - - //@formatter:off - - /** - * Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries. - */ - public static final byte REF_NONE = 0; // null value - public static final byte REF_getField = 1; - public static final byte REF_getStatic = 2; - public static final byte REF_putField = 3; - public static final byte REF_putStatic = 4; - public static final byte REF_invokeVirtual = 5; - public static final byte REF_invokeStatic = 6; - public static final byte REF_invokeSpecial = 7; - public static final byte REF_newInvokeSpecial = 8; - public static final byte REF_invokeInterface = 9; - public static final byte REF_LIMIT = 10; - - - public static final String[] mnemonics = new String[]{ - /*0: */"nop", - /*1: */"aconst_null", - /*2: */"iconst_m1", - /*3: */"iconst_0", - /*4: */"iconst_1", - /*5: */"iconst_2", - /*6: */"iconst_3", - /*7: */"iconst_4", - /*8: */"iconst_5", - /*9: */"lconst_0", - /*10: */"lconst_1", - /*11: */"fconst_0", - /*12: */"fconst_1", - /*13: */"fconst_2", - /*14: */"dconst_0", - /*15: */"dconst_1", - /*16: */"bipush", - /*17: */"sipush", - /*18: */"ldc", - /*19: */"ldc_w", - /*20: */"ldc2_w", - /*21: */"iload", - /*22: */"lload", - /*23: */"fload", - /*24: */"dload", - /*25: */"aload", - /*26: */"iload_0", - /*27: */"iload_1", - /*28: */"iload_2", - /*29: */"iload_3", - /*30: */"lload_0", - /*31: */"lload_1", - /*32: */"lload_2", - /*33: */"lload_3", - /*34: */"fload_0", - /*35: */"fload_1", - /*36: */"fload_2", - /*37: */"fload_3", - /*38: */"dload_0", - /*39: */"dload_1", - /*40: */"dload_2", - /*41: */"dload_3", - /*42: */"aload_0", - /*43: */"aload_1", - /*44: */"aload_2", - /*45: */"aload_3", - /*46: */"iaload", - /*47: */"laload", - /*48: */"faload", - /*49: */"daload", - /*50: */"aaload", - /*51: */"baload", - /*52: */"caload", - /*53: */"saload", - /*54: */"istore", - /*55: */"lstore", - /*56: */"fstore", - /*57: */"dstore", - /*58: */"astore", - /*59: */"istore_0", - /*60: */"istore_1", - /*61: */"istore_2", - /*62: */"istore_3", - /*63: */"lstore_0", - /*64: */"lstore_1", - /*65: */"lstore_2", - /*66: */"lstore_3", - /*67: */"fstore_0", - /*68: */"fstore_1", - /*69: */"fstore_2", - /*70: */"fstore_3", - /*71: */"dstore_0", - /*72: */"dstore_1", - /*73: */"dstore_2", - /*74: */"dstore_3", - /*75: */"astore_0", - /*76: */"astore_1", - /*77: */"astore_2", - /*78: */"astore_3", - /*79: */"iastore", - /*80: */"lastore", - /*81: */"fastore", - /*82: */"dastore", - /*83: */"aastore", - /*84: */"bastore", - /*85: */"castore", - /*86: */"sastore", - /*87: */"pop", - /*88: */"pop2", - /*89: */"dup", - /*90: */"dup_x1", - /*91: */"dup_x2", - /*92: */"dup2", - /*93: */"dup2_x1", - /*94: */"dup2_x2", - /*95: */"swap", - /*96: */"iadd", - /*97: */"ladd", - /*98: */"fadd", - /*99: */"dadd", - /*100: */"isub", - /*101: */"lsub", - /*102: */"fsub", - /*103: */"dsub", - /*104: */"imul", - /*105: */"lmul", - /*106: */"fmul", - /*107: */"dmul", - /*108: */"idiv", - /*109: */"ldiv", - /*110: */"fdiv", - /*111: */"ddiv", - /*112: */"irem", - /*113: */"lrem", - /*114: */"frem", - /*115: */"drem", - /*116: */"ineg", - /*117: */"lneg", - /*118: */"fneg", - /*119: */"dneg", - /*120: */"ishl", - /*121: */"lshl", - /*122: */"ishr", - /*123: */"lshr", - /*124: */"iushr", - /*125: */"lushr", - /*126: */"iand", - /*127: */"land", - /*128: */"ior", - /*129: */"lor", - /*130: */"ixor", - /*131: */"lxor", - /*132: */"iinc", - /*133: */"i2l", - /*134: */"i2f", - /*135: */"i2d", - /*136: */"l2i", - /*137: */"l2f", - /*138: */"l2d", - /*139: */"f2i", - /*140: */"f2l", - /*141: */"f2d", - /*142: */"d2i", - /*143: */"d2l", - /*144: */"d2f", - /*145: */"i2b", - /*146: */"i2c", - /*147: */"i2s", - /*148: */"lcmp", - /*149: */"fcmpl", - /*150: */"fcmpg", - /*151: */"dcmpl", - /*152: */"dcmpg", - /*153: */"ifeq", - /*154: */"ifne", - /*155: */"iflt", - /*156: */"ifge", - /*157: */"ifgt", - /*158: */"ifle", - /*159: */"if_icmpeq", - /*160: */"if_icmpne", - /*161: */"if_icmplt", - /*162: */"if_icmpge", - /*163: */"if_icmpgt", - /*164: */"if_icmple", - /*165: */"if_acmpeq", - /*166: */"if_acmpne", - /*167: */"goto", - /*168: */"jsr", - /*169: */"ret", - /*170: */"tableswitch", - /*171: */"lookupswitch", - /*172: */"ireturn", - /*173: */"lreturn", - /*174: */"freturn", - /*175: */"dreturn", - /*176: */"areturn", - /*177: */"return", - /*178: */"getstatic", - /*179: */"putstatic", - /*180: */"getfield", - /*181: */"putfield", - /*182: */"invokevirtual", - /*183: */"invokespecial", - /*184: */"invokestatic", - /*185: */"invokeinterface", - /*186: */"invokedynamic", - /*187: */"new", - /*188: */"newarray", - /*189: */"anewarray", - /*190: */"arraylength", - /*191: */"athrow", - /*192: */"checkcast", - /*193: */"instanceof", - /*194: */"monitorenter", - /*195: */"monitorexit", - /*196: */"wide", - /*197: */"multianewarray", - /*198: */"ifnull", - /*199: */"ifnonnull", - /*200: */"goto_w", - /*201: */"jsr_w"}; - //@formatter:on - - /* Opcodes */ - public static final int opc_dead = -2; - public static final int opc_label = -1; - public static final int opc_nop = 0; - public static final int opc_aconst_null = 1; - public static final int opc_iconst_m1 = 2; - public static final int opc_iconst_0 = 3; - public static final int opc_iconst_1 = 4; - public static final int opc_iconst_2 = 5; - public static final int opc_iconst_3 = 6; - public static final int opc_iconst_4 = 7; - public static final int opc_iconst_5 = 8; - public static final int opc_lconst_0 = 9; - public static final int opc_lconst_1 = 10; - public static final int opc_fconst_0 = 11; - public static final int opc_fconst_1 = 12; - public static final int opc_fconst_2 = 13; - public static final int opc_dconst_0 = 14; - public static final int opc_dconst_1 = 15; - public static final int opc_bipush = 16; - public static final int opc_sipush = 17; - public static final int opc_ldc = 18; - public static final int opc_ldc_w = 19; - public static final int opc_ldc2_w = 20; - public static final int opc_iload = 21; - public static final int opc_lload = 22; - public static final int opc_fload = 23; - public static final int opc_dload = 24; - public static final int opc_aload = 25; - public static final int opc_iload_0 = 26; - public static final int opc_iload_1 = 27; - public static final int opc_iload_2 = 28; - public static final int opc_iload_3 = 29; - public static final int opc_lload_0 = 30; - public static final int opc_lload_1 = 31; - public static final int opc_lload_2 = 32; - public static final int opc_lload_3 = 33; - public static final int opc_fload_0 = 34; - public static final int opc_fload_1 = 35; - public static final int opc_fload_2 = 36; - public static final int opc_fload_3 = 37; - public static final int opc_dload_0 = 38; - public static final int opc_dload_1 = 39; - public static final int opc_dload_2 = 40; - public static final int opc_dload_3 = 41; - public static final int opc_aload_0 = 42; - public static final int opc_aload_1 = 43; - public static final int opc_aload_2 = 44; - public static final int opc_aload_3 = 45; - public static final int opc_iaload = 46; - public static final int opc_laload = 47; - public static final int opc_faload = 48; - public static final int opc_daload = 49; - public static final int opc_aaload = 50; - public static final int opc_baload = 51; - public static final int opc_caload = 52; - public static final int opc_saload = 53; - public static final int opc_istore = 54; - public static final int opc_lstore = 55; - public static final int opc_fstore = 56; - public static final int opc_dstore = 57; - public static final int opc_astore = 58; - public static final int opc_istore_0 = 59; - public static final int opc_istore_1 = 60; - public static final int opc_istore_2 = 61; - public static final int opc_istore_3 = 62; - public static final int opc_lstore_0 = 63; - public static final int opc_lstore_1 = 64; - public static final int opc_lstore_2 = 65; - public static final int opc_lstore_3 = 66; - public static final int opc_fstore_0 = 67; - public static final int opc_fstore_1 = 68; - public static final int opc_fstore_2 = 69; - public static final int opc_fstore_3 = 70; - public static final int opc_dstore_0 = 71; - public static final int opc_dstore_1 = 72; - public static final int opc_dstore_2 = 73; - public static final int opc_dstore_3 = 74; - public static final int opc_astore_0 = 75; - public static final int opc_astore_1 = 76; - public static final int opc_astore_2 = 77; - public static final int opc_astore_3 = 78; - public static final int opc_iastore = 79; - public static final int opc_lastore = 80; - public static final int opc_fastore = 81; - public static final int opc_dastore = 82; - public static final int opc_aastore = 83; - public static final int opc_bastore = 84; - public static final int opc_castore = 85; - public static final int opc_sastore = 86; - public static final int opc_pop = 87; - public static final int opc_pop2 = 88; - public static final int opc_dup = 89; - public static final int opc_dup_x1 = 90; - public static final int opc_dup_x2 = 91; - public static final int opc_dup2 = 92; - public static final int opc_dup2_x1 = 93; - public static final int opc_dup2_x2 = 94; - public static final int opc_swap = 95; - public static final int opc_iadd = 96; - public static final int opc_ladd = 97; - public static final int opc_fadd = 98; - public static final int opc_dadd = 99; - public static final int opc_isub = 100; - public static final int opc_lsub = 101; - public static final int opc_fsub = 102; - public static final int opc_dsub = 103; - public static final int opc_imul = 104; - public static final int opc_lmul = 105; - public static final int opc_fmul = 106; - public static final int opc_dmul = 107; - public static final int opc_idiv = 108; - public static final int opc_ldiv = 109; - public static final int opc_fdiv = 110; - public static final int opc_ddiv = 111; - public static final int opc_irem = 112; - public static final int opc_lrem = 113; - public static final int opc_frem = 114; - public static final int opc_drem = 115; - public static final int opc_ineg = 116; - public static final int opc_lneg = 117; - public static final int opc_fneg = 118; - public static final int opc_dneg = 119; - public static final int opc_ishl = 120; - public static final int opc_lshl = 121; - public static final int opc_ishr = 122; - public static final int opc_lshr = 123; - public static final int opc_iushr = 124; - public static final int opc_lushr = 125; - public static final int opc_iand = 126; - public static final int opc_land = 127; - public static final int opc_ior = 128; - public static final int opc_lor = 129; - public static final int opc_ixor = 130; - public static final int opc_lxor = 131; - public static final int opc_iinc = 132; - public static final int opc_i2l = 133; - public static final int opc_i2f = 134; - public static final int opc_i2d = 135; - public static final int opc_l2i = 136; - public static final int opc_l2f = 137; - public static final int opc_l2d = 138; - public static final int opc_f2i = 139; - public static final int opc_f2l = 140; - public static final int opc_f2d = 141; - public static final int opc_d2i = 142; - public static final int opc_d2l = 143; - public static final int opc_d2f = 144; - public static final int opc_i2b = 145; - public static final int opc_int2byte = 145; - public static final int opc_i2c = 146; - public static final int opc_int2char = 146; - public static final int opc_i2s = 147; - public static final int opc_int2short = 147; - public static final int opc_lcmp = 148; - public static final int opc_fcmpl = 149; - public static final int opc_fcmpg = 150; - public static final int opc_dcmpl = 151; - public static final int opc_dcmpg = 152; - public static final int opc_ifeq = 153; - public static final int opc_ifne = 154; - public static final int opc_iflt = 155; - public static final int opc_ifge = 156; - public static final int opc_ifgt = 157; - public static final int opc_ifle = 158; - public static final int opc_if_icmpeq = 159; - public static final int opc_if_icmpne = 160; - public static final int opc_if_icmplt = 161; - public static final int opc_if_icmpge = 162; - public static final int opc_if_icmpgt = 163; - public static final int opc_if_icmple = 164; - public static final int opc_if_acmpeq = 165; - public static final int opc_if_acmpne = 166; - public static final int opc_goto = 167; - public static final int opc_jsr = 168; - public static final int opc_ret = 169; - public static final int opc_tableswitch = 170; - public static final int opc_lookupswitch = 171; - public static final int opc_ireturn = 172; - public static final int opc_lreturn = 173; - public static final int opc_freturn = 174; - public static final int opc_dreturn = 175; - public static final int opc_areturn = 176; - public static final int opc_return = 177; - public static final int opc_getstatic = 178; - public static final int opc_putstatic = 179; - public static final int opc_getfield = 180; - public static final int opc_putfield = 181; - public static final int opc_invokevirtual = 182; - public static final int opc_invokenonvirtual = 183; - public static final int opc_invokespecial = 183; - public static final int opc_invokestatic = 184; - public static final int opc_invokeinterface = 185; - public static final int opc_invokedynamic = 186; - public static final int opc_new = 187; - public static final int opc_newarray = 188; - public static final int opc_anewarray = 189; - public static final int opc_arraylength = 190; - public static final int opc_athrow = 191; - public static final int opc_checkcast = 192; - public static final int opc_instanceof = 193; - public static final int opc_monitorenter = 194; - public static final int opc_monitorexit = 195; - public static final int opc_wide = 196; - public static final int opc_multianewarray = 197; - public static final int opc_ifnull = 198; - public static final int opc_ifnonnull = 199; - public static final int opc_goto_w = 200; - public static final int opc_jsr_w = 201; - - /* Pseudo-instructions */ - public static final int opc_bytecode = 203; - public static final int opc_try = 204; - public static final int opc_endtry = 205; - public static final int opc_catch = 206; - public static final int opc_var = 207; - public static final int opc_endvar = 208; - public static final int opc_localsmap = 209; - public static final int opc_stackmap = 210; - - /* PicoJava prefixes */ - public static final int opc_nonpriv = 254; - public static final int opc_priv = 255; - - /* ArrayType constants */ - - public static final int JVM_ArrayType_Boolean = 4; - public static final int JVM_ArrayType_Char = 5; - public static final int JVM_ArrayType_Float = 6; - public static final int JVM_ArrayType_Double = 7; - public static final int JVM_ArrayType_Byte = 8; - public static final int JVM_ArrayType_Short = 9; - public static final int JVM_ArrayType_Int = 10; - public static final int JVM_ArrayType_Long = 11; - public static final int JVM_ArrayType_Object = 12; - public static final int JVM_ArrayType_Void = 14; - public static final int JVM_ArrayType_ReturnAddress = 98; - public static final int JVM_ArrayType_Illegal = 99; - - public static byte atype(final Class clazz) { - if (clazz == boolean.class) { - return JVM_ArrayType_Boolean; - } else if (clazz == char.class) { - return JVM_ArrayType_Char; - } else if (clazz == float.class) { - return JVM_ArrayType_Float; - } else if (clazz == double.class) { - return JVM_ArrayType_Double; - } else if (clazz == byte.class) { - return JVM_ArrayType_Byte; - } else if (clazz == short.class) { - return JVM_ArrayType_Short; - } else if (clazz == int.class) { - return JVM_ArrayType_Int; - } else if (clazz == long.class) { - return JVM_ArrayType_Long; - } - - throw new IllegalArgumentException(); - } - - public static Class arrayType(byte atype) { - switch (atype) { - case JVM_ArrayType_Boolean: - return boolean.class; - case JVM_ArrayType_Char: - return char.class; - case JVM_ArrayType_Float: - return float.class; - case JVM_ArrayType_Double: - return double.class; - case JVM_ArrayType_Byte: - return byte.class; - case JVM_ArrayType_Short: - return short.class; - case JVM_ArrayType_Int: - return int.class; - case JVM_ArrayType_Long: - return long.class; - default: - throw new IllegalArgumentException(); - } - } - - /** - * - * @param bytecode the instruction - * @return the size of the instruction in bytes - */ - public static int getInstructionSize(int bytecode) { - switch (bytecode) { - case opc_tableswitch: - case opc_lookupswitch: - case opc_wide: - throw new RuntimeException("not implemented"); - case opc_aload: - case opc_astore: - case opc_bipush: - case opc_dload: - case opc_fload: - case opc_fstore: - case opc_istore: - case opc_ldc: - case opc_lload: - case opc_lstore: - case opc_newarray: - case opc_ret: - return 2; - case opc_anewarray: - case opc_checkcast: - case opc_getfield: - case opc_getstatic: - case opc_goto: - case opc_if_acmpeq: - case opc_if_acmpne: - case opc_if_icmpeq: - case opc_if_icmpge: - case opc_if_icmpgt: - case opc_if_icmple: - case opc_if_icmplt: - case opc_if_icmpne: - case opc_ifeq: - case opc_ifne: - case opc_ifge: - case opc_ifle: - case opc_ifgt: - case opc_iflt: - case opc_ifnonnull: - case opc_ifnull: - case opc_iinc: - case opc_iload: - case opc_instanceof: - case opc_invokespecial: - case opc_invokestatic: - case opc_invokevirtual: - case opc_jsr: - case opc_ldc_w: - case opc_ldc2_w: - case opc_new: - case opc_putfield: - case opc_putstatic: - case opc_sipush: - return 3; - case opc_multianewarray: - return 4; - case opc_goto_w: - case opc_invokedynamic: - case opc_invokeinterface: - case opc_jsr_w: - return 5; - - default: - // all other instructions are size 1 - return 1; - } - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/RuntimeConstantPool.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/RuntimeConstantPool.java deleted file mode 100644 index 46c5c0b1ca4a..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/RuntimeConstantPool.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile; - -import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; -import com.oracle.truffle.espresso.classfile.constantpool.DynamicConstant; -import com.oracle.truffle.espresso.classfile.constantpool.FieldRefConstant; -import com.oracle.truffle.espresso.classfile.constantpool.InvokeDynamicConstant; -import com.oracle.truffle.espresso.classfile.constantpool.MethodRefConstant; -import com.oracle.truffle.espresso.classfile.constantpool.NeedsFreshResolutionException; -import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant; -import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; -import com.oracle.truffle.espresso.impl.Field; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.impl.Method; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.runtime.EspressoContext; -import com.oracle.truffle.espresso.runtime.EspressoException; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; - -public final class RuntimeConstantPool extends ConstantPool { - - private final EspressoContext context; - private final ImmutableConstantPool pool; - private final StaticObject classLoader; - - @CompilationFinal(dimensions = 1) // - private final Resolvable.ResolvedConstant[] constants; - - public RuntimeConstantPool(EspressoContext context, ImmutableConstantPool pool, StaticObject classLoader) { - this.context = context; - this.pool = pool; - this.constants = new Resolvable.ResolvedConstant[pool.length()]; - this.classLoader = classLoader; - } - - @Override - public int length() { - return pool.length(); - } - - @Override - public byte[] getRawBytes() { - return pool.getRawBytes(); - } - - @Override - public PoolConstant at(int index, String description) { - return pool.at(index, description); - } - - private Resolvable.ResolvedConstant outOfLockResolvedAt(ObjectKlass accessingKlass, int index, String description) { - Resolvable.ResolvedConstant c = constants[index]; - if (c == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - // double check: deopt is a heavy operation. - c = constants[index]; - if (c == null) { - Resolvable.ResolvedConstant locallyResolved = ((Resolvable) pool.at(index, description)).resolve(this, index, accessingKlass); - synchronized (this) { - // Triple check: non-trivial resolution - c = constants[index]; - if (c == null) { - constants[index] = c = locallyResolved; - } - } - } - } - return c; - } - - private Resolvable.ResolvedConstant resolvedAt(ObjectKlass accessingKlass, int index, String description) { - Resolvable.ResolvedConstant c = constants[index]; - if (c == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - synchronized (this) { - // fence += 1; - // FIXME(peterssen): Add memory fence for array read. - c = constants[index]; - if (c == null) { - constants[index] = c = ((Resolvable) pool.at(index, description)).resolve(this, index, accessingKlass); - } - } - } - return c; - } - - private Resolvable.ResolvedConstant resolvedAtNoCache(ObjectKlass accessingKlass, int index, String description) { - CompilerAsserts.neverPartOfCompilation(); - return ((Resolvable) pool.at(index, description)).resolve(this, index, accessingKlass); - } - - public StaticObject resolvedStringAt(int index) { - Resolvable.ResolvedConstant resolved = resolvedAt(null, index, "string"); - return (StaticObject) resolved.value(); - } - - public Klass resolvedKlassAt(ObjectKlass accessingKlass, int index) { - Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "klass"); - return (Klass) resolved.value(); - } - - public Field resolvedFieldAt(ObjectKlass accessingKlass, int index) { - Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "field"); - try { - return ((Field) resolved.value()); - } catch (NeedsFreshResolutionException e) { - // clear the constants cache and re-resolve - CompilerDirectives.transferToInterpreterAndInvalidate(); - synchronized (this) { - constants[index] = null; - } - return resolvedFieldAt(accessingKlass, index); - } - } - - public Field resolveFieldAndUpdate(ObjectKlass accessingKlass, int index, Field field) { - CompilerAsserts.neverPartOfCompilation(); - try { - Resolvable.ResolvedConstant resolved = resolvedAtNoCache(accessingKlass, index, "field"); - // a compatible field was found, so update the entry - synchronized (this) { - constants[index] = resolved; - } - return ((Field) resolved.value()); - } catch (EspressoException e) { - Field realField = field; - if (realField.hasCompatibleField()) { - realField = realField.getCompatibleField(); - } - // A new compatible field was not found, but we still allow - // obsolete code to use the latest known resolved field. - // To avoid a de-opt loop here, we create a compatible delegation - // field that actually uses the latest known resolved field - // underneath. - synchronized (this) { - Field delegationField = context.getClassRedefinition().createDelegationFrom(realField); - Resolvable.ResolvedConstant resolved = FieldRefConstant.fromPreResolved(delegationField); - constants[index] = resolved; - return delegationField; - } - } - } - - public boolean isResolutionSuccessAt(int index) { - Resolvable.ResolvedConstant constant = constants[index]; - return constant != null && constant.isSuccess(); - } - - public Method resolvedMethodAt(ObjectKlass accessingKlass, int index) { - Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "method"); - return (Method) resolved.value(); - } - - public MethodRefConstant resolvedMethodRefAt(ObjectKlass accessingKlass, int index) { - Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "method"); - return (MethodRefConstant) resolved; - } - - public Method resolvedMethodAtNoCache(ObjectKlass accessingKlass, int index) { - CompilerAsserts.neverPartOfCompilation(); - Resolvable.ResolvedConstant resolved = resolvedAtNoCache(accessingKlass, index, "method"); - return (Method) resolved.value(); - } - - public StaticObject resolvedMethodHandleAt(ObjectKlass accessingKlass, int index) { - Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "method handle"); - return (StaticObject) resolved.value(); - } - - public StaticObject resolvedMethodTypeAt(ObjectKlass accessingKlass, int index) { - Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "method type"); - return (StaticObject) resolved.value(); - } - - public InvokeDynamicConstant.CallSiteLink linkInvokeDynamic(ObjectKlass accessingKlass, int index, int bci, Method method) { - InvokeDynamicConstant indy = (InvokeDynamicConstant) resolvedAt(accessingKlass, index, "indy"); - try { - return indy.link(this, accessingKlass, index, method, bci); - } catch (InvokeDynamicConstant.CallSiteLinkingFailure failure) { - // On failure, shortcut subsequent linking operations. - CompilerDirectives.transferToInterpreterAndInvalidate(); - synchronized (this) { - constants[index] = failure.failConstant(); - } - throw failure.cause; - } - } - - public InvokeDynamicConstant.Resolved peekResolvedInvokeDynamic(int index) { - return (InvokeDynamicConstant.Resolved) constants[index]; - } - - public DynamicConstant.Resolved resolvedDynamicConstantAt(ObjectKlass accessingKlass, int index) { - DynamicConstant.Resolved dynamicConstant = (DynamicConstant.Resolved) outOfLockResolvedAt(accessingKlass, index, "dynamic constant"); - dynamicConstant.checkFail(); - return dynamicConstant; - } - - public StaticObject getClassLoader() { - return classLoader; - } - - public EspressoContext getContext() { - return context; - } - - public void setKlassAt(int index, ObjectKlass klass) { - constants[index] = ClassConstant.resolved(klass); - } - - @Override - public int getMajorVersion() { - return pool.getMajorVersion(); - } - - @Override - public int getMinorVersion() { - return pool.getMinorVersion(); - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/BootstrapMethodsAttribute.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/BootstrapMethodsAttribute.java deleted file mode 100644 index 8b1be21d1b87..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/BootstrapMethodsAttribute.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile.attributes; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.runtime.Attribute; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; - -public final class BootstrapMethodsAttribute extends Attribute { - - public static final Symbol NAME = Name.BootstrapMethods; - - public Entry[] getEntries() { - return entries; - } - - public static final class Entry { - final char bootstrapMethodRef; - @CompilerDirectives.CompilationFinal(dimensions = 1) final char[] bootstrapArguments; - - public int numBootstrapArguments() { - return bootstrapArguments.length; - } - - public Entry(char bootstrapMethodRef, char[] bootstrapArguments) { - this.bootstrapMethodRef = bootstrapMethodRef; - this.bootstrapArguments = bootstrapArguments; - } - - public char argAt(int index) { - return bootstrapArguments[index]; - } - - public char getBootstrapMethodRef() { - return bootstrapMethodRef; - } - - public StaticObject getMethodHandle(ObjectKlass accessingKlass, RuntimeConstantPool pool) { - return pool.resolvedMethodHandleAt(accessingKlass, getBootstrapMethodRef()); - } - - public StaticObject[] getStaticArguments(ObjectKlass accessingKlass, RuntimeConstantPool pool) { - Meta meta = accessingKlass.getMeta(); - StaticObject[] args = new StaticObject[numBootstrapArguments()]; - // @formatter:off - for (int i = 0; i < numBootstrapArguments(); i++) { - PoolConstant pc = pool.at(argAt(i)); - switch (pc.tag()) { - case METHODHANDLE: - args[i] = pool.resolvedMethodHandleAt(accessingKlass, argAt(i)); - break; - case METHODTYPE: - args[i] = pool.resolvedMethodTypeAt(accessingKlass, argAt(i)); - break; - case DYNAMIC: - args[i] = pool.resolvedDynamicConstantAt(accessingKlass, argAt(i)).guestBoxedValue(meta); - break; - case CLASS: - args[i] = pool.resolvedKlassAt(accessingKlass, argAt(i)).mirror(); - break; - case STRING: - args[i] = pool.resolvedStringAt(argAt(i)); - break; - case INTEGER: - args[i] = meta.boxInteger(pool.intAt(argAt(i))); - break; - case LONG: - args[i] = meta.boxLong(pool.longAt(argAt(i))); - break; - case DOUBLE: - args[i] = meta.boxDouble(pool.doubleAt(argAt(i))); - break; - case FLOAT: - args[i] = meta.boxFloat(pool.floatAt(argAt(i))); - break; - default: - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere(); - } - } - return args; - // @formatter:on - } - } - - private final Entry[] entries; - - public BootstrapMethodsAttribute(Symbol name, Entry[] entries) { - super(name, null); - this.entries = entries; - } - - public Entry at(int index) { - return entries[index]; - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/RecordAttribute.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/RecordAttribute.java deleted file mode 100644 index 5e90059daf7c..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/attributes/RecordAttribute.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.truffle.espresso.classfile.attributes; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.impl.Field; -import com.oracle.truffle.espresso.impl.Method; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.runtime.Attribute; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; - -public class RecordAttribute extends Attribute { - public static final Symbol NAME = Name.Record; - - @CompilerDirectives.CompilationFinal(dimensions = 1) // - private final RecordComponentInfo[] components; - - public RecordAttribute(Symbol name, RecordComponentInfo[] components) { - super(name, null); - this.components = components; - } - - public static class RecordComponentInfo { - final char name; - final char descriptor; - @CompilerDirectives.CompilationFinal(dimensions = 1)// - final Attribute[] attributes; - - public RecordComponentInfo(int name, int descriptor, Attribute[] attributes) { - this.name = (char) name; - this.descriptor = (char) descriptor; - this.attributes = attributes; - } - - public StaticObject toGuestComponent(Meta meta, ObjectKlass klass) { - assert meta.getJavaVersion().java16OrLater(); - RuntimeConstantPool pool = klass.getConstantPool(); - StaticObject component = meta.java_lang_reflect_RecordComponent.allocateInstance(meta.getContext()); - Symbol nameSymbol = pool.symbolAt(name); - Symbol typeSymbol = pool.symbolAt(descriptor); - Symbol signature = meta.getSignatures().makeRaw(typeSymbol); - meta.java_lang_reflect_RecordComponent_clazz.setObject(component, klass.mirror()); - meta.java_lang_reflect_RecordComponent_name.setObject(component, meta.toGuestString(nameSymbol)); - meta.java_lang_reflect_RecordComponent_type.setObject(component, meta.resolveSymbolAndAccessCheck(typeSymbol, klass).mirror()); - - // Find and set accessor - Method m = klass.lookupMethod(nameSymbol, signature); - boolean validMethod = m != null && !m.isStatic() && !m.isConstructor(); - meta.java_lang_reflect_RecordComponent_accessor.setObject(component, validMethod ? m.makeMirror(meta) : StaticObject.NULL); - - // Find and set generic signature - SignatureAttribute genericSignatureAttribute = (SignatureAttribute) getAttribute(SignatureAttribute.NAME); - meta.java_lang_reflect_RecordComponent_signature.setObject(component, - genericSignatureAttribute != null ? meta.toGuestString(pool.symbolAt(genericSignatureAttribute.getSignatureIndex())) : StaticObject.NULL); - - // Find and set annotations - doAnnotation(component, Name.RuntimeVisibleAnnotations, meta.java_lang_reflect_RecordComponent_annotations, meta); - doAnnotation(component, Name.RuntimeVisibleTypeAnnotations, meta.java_lang_reflect_RecordComponent_typeAnnotations, meta); - - return component; - } - - private void doAnnotation(StaticObject component, Symbol attrName, Field f, Meta meta) { - Attribute attr = getAttribute(attrName); - f.setObject(component, attr == null ? StaticObject.NULL : StaticObject.wrap(attr.getData(), meta)); - } - - public Attribute getAttribute(Symbol attributeName) { - for (Attribute attr : attributes) { - if (attr.getName().equals(attributeName)) { - return attr; - } - } - return null; - } - } - - public RecordComponentInfo[] getComponents() { - return components; - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/ClassConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/ClassConstant.java deleted file mode 100644 index 21f7d84880e3..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/ClassConstant.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile.constantpool; - -import static com.oracle.truffle.espresso.impl.ClassRegistry.classInModuleOfLoader; - -import java.nio.ByteBuffer; -import java.util.Objects; -import java.util.logging.Level; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Validation; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.perf.DebugCounter; -import com.oracle.truffle.espresso.runtime.EspressoContext; -import com.oracle.truffle.espresso.runtime.EspressoException; - -/** - * Interface denoting a class entry in a constant pool. - */ -public interface ClassConstant extends PoolConstant { - - /* static final */ DebugCounter CLASS_RESOLVE_COUNT = DebugCounter.create("ClassConstant.resolve calls"); - - static ClassConstant create(int classNameIndex) { - return new Index(classNameIndex); - } - - static ClassConstant preResolved(Klass klass) { - return new PreResolved(klass); - } - - static ClassConstant withString(Symbol name) { - return new WithString(name); - } - - static Resolvable.ResolvedConstant resolved(Klass klass) { - return new Resolved(klass); - } - - @Override - default Tag tag() { - return Tag.CLASS; - } - - /** - * Gets the type descriptor of the class represented by this constant. - * - * @param pool container of this constant - */ - Symbol getName(ConstantPool pool); - - @Override - default String toString(ConstantPool pool) { - return getName(pool).toString(); - } - - final class Index implements ClassConstant, Resolvable { - private final char classNameIndex; - - Index(int classNameIndex) { - this.classNameIndex = PoolConstant.u2(classNameIndex); - } - - @Override - public Symbol getName(ConstantPool pool) { - return pool.symbolAt(classNameIndex); - } - - /** - *

      5.4.3.1. Class and Interface Resolution

      - * - * To resolve an unresolved symbolic reference from D to a class or interface C denoted by - * N, the following steps are performed: - *
        - *
      1. The defining class loader of D is used to create a class or interface denoted by N. - * This class or interface is C. The details of the process are given in §5.3. Any - * exception that can be thrown as a result of failure of class or interface creation can - * thus be thrown as a result of failure of class and interface resolution. - *
      2. If C is an array class and its element type is a reference type, then a symbolic - * reference to the class or interface representing the element type is resolved by invoking - * the algorithm in §5.4.3.1 recursively. - *
      3. Finally, access permissions to C are checked. - *
          - *
        • If C is not accessible (§5.4.4) to D, class or interface resolution throws an - * IllegalAccessError. This condition can occur, for example, if C is a class that was - * originally declared to be public but was changed to be non-public after D was compiled. - *
        - *
      - * If steps 1 and 2 succeed but step 3 fails, C is still valid and usable. Nevertheless, - * resolution fails, and D is prohibited from accessing C. - */ - @SuppressWarnings("try") - @Override - public Resolved resolve(RuntimeConstantPool pool, int thisIndex, ObjectKlass accessingKlass) { - try (EspressoLanguage.DisableSingleStepping ignored = accessingKlass.getLanguage().disableStepping()) { - CLASS_RESOLVE_COUNT.inc(); - assert accessingKlass != null; - CompilerDirectives.transferToInterpreterAndInvalidate(); - Symbol klassName = getName(pool); - try { - EspressoContext context = pool.getContext(); - Symbol type = context.getTypes().fromName(klassName); - Klass klass = context.getMeta().resolveSymbolOrFail(type, accessingKlass.getDefiningClassLoader(), accessingKlass.protectionDomain()); - Klass checkedKlass = klass.getElementalType(); - if (!Klass.checkAccess(checkedKlass, accessingKlass, false)) { - Meta meta = context.getMeta(); - context.getLogger().log(Level.FINE, - "Access check of: " + checkedKlass.getType() + " from " + accessingKlass.getType() + " throws IllegalAccessError"); - StringBuilder errorMessage = new StringBuilder("failed to access class "); - errorMessage.append(checkedKlass.getExternalName()).append(" from class ").append(accessingKlass.getExternalName()); - if (context.getJavaVersion().modulesEnabled()) { - errorMessage.append(" ("); - if (accessingKlass.module() == checkedKlass.module()) { - errorMessage.append(checkedKlass.getExternalName()); - errorMessage.append(" and "); - classInModuleOfLoader(accessingKlass, true, errorMessage, meta); - } else { - // checkedKlass is not an array type (getElementalType) nor a - // primitive - // type (it would have passed the access checks) - classInModuleOfLoader((ObjectKlass) checkedKlass, false, errorMessage, meta); - errorMessage.append("; "); - classInModuleOfLoader(accessingKlass, false, errorMessage, meta); - } - errorMessage.append(")"); - } - throw meta.throwExceptionWithMessage(meta.java_lang_IllegalAccessError, errorMessage.toString()); - } - - return new Resolved(klass); - - } catch (EspressoException e) { - CompilerDirectives.transferToInterpreter(); - Meta meta = pool.getContext().getMeta(); - if (meta.java_lang_ClassNotFoundException.isAssignableFrom(e.getGuestException().getKlass())) { - throw meta.throwExceptionWithMessage(meta.java_lang_NoClassDefFoundError, meta.toGuestString(klassName)); - } - throw e; - } catch (VirtualMachineError e) { - // Comment from Hotspot: - // Just throw the exception and don't prevent these classes from - // being loaded for virtual machine errors like StackOverflow - // and OutOfMemoryError, etc. - // Needs clarification to section 5.4.3 of the JVM spec (see 6308271) - throw e; - } - } - } - - @Override - public void validate(ConstantPool pool) { - pool.utf8At(classNameIndex).validateClassName(); - } - - @Override - public void dump(ByteBuffer buf) { - buf.putChar(classNameIndex); - } - } - - final class Resolved implements ClassConstant, Resolvable.ResolvedConstant { - private final Klass resolved; - - Resolved(Klass resolved) { - this.resolved = Objects.requireNonNull(resolved); - } - - @Override - public Symbol getName(ConstantPool pool) { - return resolved.getName(); - } - - @Override - public Klass value() { - return resolved; - } - } - - final class WithString implements ClassConstant, Resolvable { - private final Symbol name; - - WithString(Symbol name) { - this.name = name; - } - - @Override - public Symbol getName(ConstantPool pool) { - return name; - } - - @Override - public Resolved resolve(RuntimeConstantPool pool, int thisIndex, ObjectKlass accessingKlass) { - CLASS_RESOLVE_COUNT.inc(); - assert accessingKlass != null; - CompilerDirectives.transferToInterpreterAndInvalidate(); - Symbol klassName = getName(pool); - try { - EspressoContext context = pool.getContext(); - Meta meta = context.getMeta(); - Klass klass = meta.resolveSymbolOrFail(context.getTypes().fromName(klassName), accessingKlass.getDefiningClassLoader(), accessingKlass.protectionDomain()); - if (!Klass.checkAccess(klass.getElementalType(), accessingKlass, false)) { - context.getLogger().log(Level.FINE, - "Access check of: " + klass.getType() + " from " + accessingKlass.getType() + " throws IllegalAccessError"); - throw meta.throwExceptionWithMessage(meta.java_lang_IllegalAccessError, meta.toGuestString(klassName)); - } - - return new Resolved(klass); - - } catch (VirtualMachineError e) { - // Comment from Hotspot: - // Just throw the exception and don't prevent these classes from - // being loaded for virtual machine errors like StackOverflow - // and OutOfMemoryError, etc. - // Needs clarification to section 5.4.3 of the JVM spec (see 6308271) - throw e; - } - } - - @Override - public void validate(ConstantPool pool) { - // No UTF8 entry: cannot cache validation. - if (!Validation.validModifiedUTF8(name) || !Validation.validClassNameEntry(name)) { - throw ConstantPool.classFormatError("Invalid class name entry: " + name); - } - } - - @Override - public void dump(ByteBuffer buf) { - buf.putChar((char) 0); - } - } - - /** - * Constant Pool patching inserts already resolved constants in the constant pool. However, at - * the time of patching, we do not have a Runtime CP. Therefore, we help the CP by inserting a - * Pre-Resolved constant. - * - * This is also used to Pre-resolve anonymous classes. - */ - final class PreResolved implements ClassConstant, Resolvable { - private final Klass resolved; - - PreResolved(Klass resolved) { - this.resolved = Objects.requireNonNull(resolved); - } - - @Override - public Symbol getName(ConstantPool pool) { - return resolved.getName(); - } - - @Override - public Resolved resolve(RuntimeConstantPool pool, int thisIndex, ObjectKlass accessingKlass) { - return new Resolved(resolved); - } - - @Override - public void dump(ByteBuffer buf) { - buf.putChar((char) 0); - } - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/ClassMethodRefConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/ClassMethodRefConstant.java deleted file mode 100644 index db0ef1dc5d34..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/ClassMethodRefConstant.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile.constantpool; - -import java.util.Objects; - -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Descriptor; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.impl.Method; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode; -import com.oracle.truffle.espresso.resolver.LinkResolver; -import com.oracle.truffle.espresso.runtime.EspressoContext; - -public interface ClassMethodRefConstant extends MethodRefConstant { - - static ClassMethodRefConstant create(int classIndex, int nameAndTypeIndex) { - return new Indexes(classIndex, nameAndTypeIndex); - } - - @Override - default Tag tag() { - return Tag.METHOD_REF; - } - - final class Indexes extends MethodRefConstant.Indexes implements ClassMethodRefConstant, Resolvable { - Indexes(int classIndex, int nameAndTypeIndex) { - super(classIndex, nameAndTypeIndex); - } - - /** - *

      5.4.3.3. Method Resolution

      - * - * To resolve an unresolved symbolic reference from D to a method in a class C, the symbolic - * reference to C given by the method reference is first resolved (§5.4.3.1). - * Therefore, any exception that can be thrown as a result of failure of resolution of a - * class reference can be thrown as a result of failure of method resolution. If the - * reference to C can be successfully resolved, exceptions relating to the resolution of the - * method reference itself can be thrown. - * - * When resolving a method reference: - *
        - * - *
      1. If C is an interface, method resolution throws an IncompatibleClassChangeError. - * - *
      2. Otherwise, method resolution attempts to locate the referenced method in C and its - * superclasses: - *
          - * - *
        • If C declares exactly one method with the name specified by the method reference, and - * the declaration is a signature polymorphic method (§2.9), then method lookup - * succeeds. All the class names mentioned in the descriptor are resolved (§5.4.3.1). - * - *
        • The resolved method is the signature polymorphic method declaration. It is not - * necessary for C to declare a method with the descriptor specified by the method - * reference. - * - *
        • Otherwise, if C declares a method with the name and descriptor specified by the - * method reference, method lookup succeeds. - * - *
        • Otherwise, if C has a superclass, step 2 of method resolution is recursively invoked - * on the direct superclass of C. - *
        - * - *
      3. Otherwise, method resolution attempts to locate the referenced method in the - * superinterfaces of the specified class C: - *
          - *
        • If the maximally-specific superinterface methods of C for the name and descriptor - * specified by the method reference include exactly one method that does not have its - * ACC_ABSTRACT flag set, then this method is chosen and method lookup succeeds. - * - *
        • Otherwise, if any superinterface of C declares a method with the name and descriptor - * specified by the method reference that has neither its ACC_PRIVATE flag nor its - * ACC_STATIC flag set, one of these is arbitrarily chosen and method lookup succeeds. - * - *
        • Otherwise, method lookup fails. - *
        - *
      - * - * A maximally-specific superinterface method of a class or interface C for a particular - * method name and descriptor is any method for which all of the following are true: - * - *
        - *
      • The method is declared in a superinterface (direct or indirect) of C. - * - *
      • The method is declared with the specified name and descriptor. - * - *
      • The method has neither its ACC_PRIVATE flag nor its ACC_STATIC flag set. - * - *
      • Where the method is declared in interface I, there exists no other maximally-specific - * superinterface method of C with the specified name and descriptor that is declared in a - * subinterface of I. - *
      - * The result of method resolution is determined by whether method lookup succeeds or fails: - *
        - *
      • If method lookup fails, method resolution throws a NoSuchMethodError. - * - *
      • Otherwise, if method lookup succeeds and the referenced method is not accessible - * (§5.4.4) to D, method resolution throws an IllegalAccessError. - * - * Otherwise, let < E, L1 > be the class or interface in which the referenced method m is - * actually declared, and let L2 be the defining loader of D. - * - * Given that the return type of m is Tr, and that the formal parameter types of m are Tf1, - * ..., Tfn, then: - * - * If Tr is not an array type, let T0 be Tr; otherwise, let T0 be the element type - * (§2.4) of Tr. - * - * For i = 1 to n: If Tfi is not an array type, let Ti be Tfi; otherwise, let Ti be the - * element type (§2.4) of Tfi. - * - * The Java Virtual Machine must impose the loading constraints TiL1 = TiL2 for i = 0 to n - * (§5.3.4). - *
      - * When resolution searches for a method in the class's superinterfaces, the best outcome is - * to identify a maximally-specific non-abstract method. It is possible that this method - * will be chosen by method selection, so it is desirable to add class loader constraints - * for it. - * - * Otherwise, the result is nondeterministic. This is not new: The Java® Virtual Machine - * Specification has never identified exactly which method is chosen, and how "ties" should - * be broken. Prior to Java SE 8, this was mostly an unobservable distinction. However, - * beginning with Java SE 8, the set of interface methods is more heterogenous, so care must - * be taken to avoid problems with nondeterministic behavior. Thus: - * - *
        - *
      • Superinterface methods that are private and static are ignored by resolution. This is - * consistent with the Java programming language, where such interface methods are not - * inherited. - * - *
      • Any behavior controlled by the resolved method should not depend on whether the - * method is abstract or not. - *
      - * Note that if the result of resolution is an abstract method, the referenced class C may - * be non-abstract. Requiring C to be abstract would conflict with the nondeterministic - * choice of superinterface methods. Instead, resolution assumes that the run time class of - * the invoked object has a concrete implementation of the method. - */ - - @Override - public ResolvedConstant resolve(RuntimeConstantPool pool, int thisIndex, ObjectKlass accessingKlass) { - METHODREF_RESOLVE_COUNT.inc(); - EspressoContext context = pool.getContext(); - Meta meta = context.getMeta(); - - Klass holderKlass = getResolvedHolderKlass(accessingKlass, pool); - Symbol name = getName(pool); - Symbol signature = getSignature(pool); - - Method method = LinkResolver.resolveSymbol(meta, accessingKlass, name, signature, holderKlass, false, true, true); - - if (method.isInvokeIntrinsic()) { - MHInvokeGenericNode.MethodHandleInvoker invoker = MHInvokeGenericNode.linkMethod(meta.getLanguage(), meta, accessingKlass, method, name, signature); - return new ResolvedWithInvoker(method, invoker); - } - - return new Resolved(method); - } - - @Override - public void validate(ConstantPool pool) { - super.validate(pool); - // If the name of the method of a CONSTANT_Methodref_info structure begins with a '<' - // ('\u003c'), then the name must be the special name , representing an instance - // initialization method (§2.9). The return type of such a method must be void. - pool.nameAndTypeAt(nameAndTypeIndex).validateMethod(pool, false, true); - Symbol name = pool.nameAndTypeAt(nameAndTypeIndex).getName(pool); - if (Name._init_.equals(name)) { - Symbol descriptor = pool.nameAndTypeAt(nameAndTypeIndex).getDescriptor(pool); - int len = descriptor.length(); - if (len <= 2 || (descriptor.byteAt(len - 2) != ')' || descriptor.byteAt(len - 1) != 'V')) { - throw ConstantPool.classFormatError(" method should have ()V signature"); - } - } - } - } - - class Resolved implements ClassMethodRefConstant, Resolvable.ResolvedConstant { - private final Method resolved; - - Resolved(Method resolved) { - this.resolved = Objects.requireNonNull(resolved); - } - - @Override - public final Method value() { - return resolved; - } - - @Override - public final Symbol getHolderKlassName(ConstantPool pool) { - throw EspressoError.shouldNotReachHere("Method already resolved"); - } - - @Override - public final Symbol getName(ConstantPool pool) { - return resolved.getName(); - } - - @Override - public final Symbol getDescriptor(ConstantPool pool) { - return resolved.getRawSignature(); - } - } - - /** - * This is used for - * {@link com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics.PolySigIntrinsics#InvokeGeneric} - * polymorphic signature methods. The invoker object contains the method and appendix that - * should be used to implement the intrinsic's behaviour. This is provided by the JDK - * ({@code MethodHandleNatives.linkMethod}). - */ - final class ResolvedWithInvoker extends Resolved { - private final MHInvokeGenericNode.MethodHandleInvoker invoker; - - ResolvedWithInvoker(Method resolved, MHInvokeGenericNode.MethodHandleInvoker invoker) { - super(resolved); - this.invoker = Objects.requireNonNull(invoker); - } - - @Override - public MHInvokeGenericNode.MethodHandleInvoker invoker() { - return invoker; - } - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/DynamicConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/DynamicConstant.java deleted file mode 100644 index 3bcda06a00eb..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/DynamicConstant.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile.constantpool; - -import java.nio.ByteBuffer; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.classfile.attributes.BootstrapMethodsAttribute; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.nodes.BytecodeNode; -import com.oracle.truffle.espresso.nodes.EspressoFrame; -import com.oracle.truffle.espresso.nodes.methodhandle.MHLinkToNode; -import com.oracle.truffle.espresso.runtime.EspressoException; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; - -public interface DynamicConstant extends PoolConstant { - - static DynamicConstant create(int bootstrapMethodAttrIndex, int nameAndTypeIndex) { - return new Indexes(bootstrapMethodAttrIndex, nameAndTypeIndex); - } - - @Override - default Tag tag() { - return Tag.DYNAMIC; - } - - Symbol getTypeSymbol(ConstantPool pool); - - final class Indexes extends BootstrapMethodConstant.Indexes implements DynamicConstant, Resolvable { - Indexes(int bootstrapMethodAttrIndex, int nameAndTypeIndex) { - super(bootstrapMethodAttrIndex, nameAndTypeIndex); - } - - @Override - public Symbol getTypeSymbol(ConstantPool pool) { - return Types.fromSymbol(pool.nameAndTypeAt(nameAndTypeIndex).getDescriptor(pool)); - } - - private static Resolved makeResolved(Klass type, StaticObject result) { - switch (type.getJavaKind()) { - case Boolean: - case Byte: - case Short: - case Char: { - int value = (int) MHLinkToNode.rebasic(type.getMeta().unboxGuest(result), type.getJavaKind()); - return new ResolvedInt(value); - } - case Int: { - int value = type.getMeta().unboxInteger(result); - return new ResolvedInt(value); - } - case Float: { - float value = type.getMeta().unboxFloat(result); - return new ResolvedFloat(value); - } - case Long: { - long value = type.getMeta().unboxLong(result); - return new ResolvedLong(value); - } - case Double: { - double value = type.getMeta().unboxDouble(result); - return new ResolvedDouble(value); - } - case Object: - return new ResolvedObject(result); - } - throw EspressoError.shouldNotReachHere(); - } - - @Override - public void validate(ConstantPool pool) { - pool.nameAndTypeAt(nameAndTypeIndex).validateField(pool); - } - - @Override - public void dump(ByteBuffer buf) { - buf.putChar(bootstrapMethodAttrIndex); - buf.putChar(nameAndTypeIndex); - } - - @Override - public ResolvedConstant resolve(RuntimeConstantPool pool, int thisIndex, ObjectKlass accessingKlass) { - Meta meta = accessingKlass.getMeta(); - - // Condy constant resolving. - BootstrapMethodsAttribute bms = (BootstrapMethodsAttribute) accessingKlass.getAttribute(BootstrapMethodsAttribute.NAME); - - assert (bms != null); - // TODO(garcia) cache bootstrap method resolution - // Bootstrap method resolution - try { - BootstrapMethodsAttribute.Entry bsEntry = bms.at(getBootstrapMethodAttrIndex()); - - StaticObject bootstrapmethodMethodHandle = bsEntry.getMethodHandle(accessingKlass, pool); - StaticObject[] args = bsEntry.getStaticArguments(accessingKlass, pool); - - StaticObject fieldName = meta.toGuestString(getName(pool)); - Klass fieldType = meta.resolveSymbolOrFail(getTypeSymbol(pool), - accessingKlass.getDefiningClassLoader(), - accessingKlass.protectionDomain()); - - Object result = null; - if (!meta.getJavaVersion().java19OrLater()) { - result = meta.java_lang_invoke_MethodHandleNatives_linkDynamicConstant.invokeDirectStatic( - accessingKlass.mirror(), - thisIndex, - bootstrapmethodMethodHandle, - fieldName, fieldType.mirror(), - StaticObject.wrap(args, meta)); - } else { - result = meta.java_lang_invoke_MethodHandleNatives_linkDynamicConstant.invokeDirectStatic( - accessingKlass.mirror(), - bootstrapmethodMethodHandle, - fieldName, fieldType.mirror(), - StaticObject.wrap(args, meta)); - } - try { - return makeResolved(fieldType, (StaticObject) result); - } catch (ClassCastException | NullPointerException e) { - throw meta.throwException(meta.java_lang_BootstrapMethodError); - } catch (EspressoException e) { - if (meta.java_lang_NullPointerException.isAssignableFrom(e.getGuestException().getKlass()) || - meta.java_lang_ClassCastException.isAssignableFrom(e.getGuestException().getKlass())) { - throw meta.throwExceptionWithCause(meta.java_lang_BootstrapMethodError, e.getGuestException()); - } - throw e; - } - } catch (EspressoException e) { - return new ResolvedFail(e); - } - } - } - - interface Resolved extends DynamicConstant, Resolvable.ResolvedConstant { - void putResolved(VirtualFrame frame, int top, BytecodeNode node); - - @Override - default Symbol getTypeSymbol(ConstantPool pool) { - throw EspressoError.shouldNotReachHere("Getting type symbol of a resolved dynamic constant"); - } - - default StaticObject guestBoxedValue(Meta meta) { - Object value = value(); - if (value instanceof StaticObject) { - return (StaticObject) value; - } - return Meta.box(meta, value); - } - - default void checkFail() { - } - } - - final class ResolvedObject implements Resolved { - final StaticObject resolved; - - public ResolvedObject(StaticObject resolved) { - this.resolved = resolved; - } - - @Override - public void putResolved(VirtualFrame frame, int top, BytecodeNode node) { - EspressoFrame.putObject(frame, top, resolved); - } - - @Override - public Object value() { - return resolved; - } - - @Override - public String toString(ConstantPool pool) { - return "ResolvedDynamicConstant(" + resolved + ")"; - } - } - - final class ResolvedInt implements Resolved { - final int resolved; - - public ResolvedInt(int resolved) { - this.resolved = resolved; - } - - @Override - public void putResolved(VirtualFrame frame, int top, BytecodeNode node) { - EspressoFrame.putInt(frame, top, resolved); - } - - @Override - public Object value() { - return resolved; - } - - @Override - public String toString(ConstantPool pool) { - return "ResolvedDynamicConstant(" + resolved + ")"; - } - } - - final class ResolvedLong implements Resolved { - final long resolved; - - public ResolvedLong(long resolved) { - this.resolved = resolved; - } - - @Override - public void putResolved(VirtualFrame frame, int top, BytecodeNode node) { - EspressoFrame.putLong(frame, top, resolved); - } - - @Override - public Object value() { - return resolved; - } - - @Override - public String toString(ConstantPool pool) { - return "ResolvedDynamicConstant(" + resolved + ")"; - } - } - - final class ResolvedDouble implements Resolved { - final double resolved; - - public ResolvedDouble(double resolved) { - this.resolved = resolved; - } - - @Override - public void putResolved(VirtualFrame frame, int top, BytecodeNode node) { - EspressoFrame.putDouble(frame, top, resolved); - } - - @Override - public Object value() { - return resolved; - } - - @Override - public String toString(ConstantPool pool) { - return "ResolvedDynamicConstant(" + resolved + ")"; - } - } - - final class ResolvedFloat implements Resolved { - final float resolved; - - public ResolvedFloat(float resolved) { - this.resolved = resolved; - } - - @Override - public void putResolved(VirtualFrame frame, int top, BytecodeNode node) { - EspressoFrame.putFloat(frame, top, resolved); - } - - @Override - public Object value() { - return resolved; - } - - @Override - public String toString(ConstantPool pool) { - return "ResolvedDynamicConstant(" + resolved + ")"; - } - } - - final class ResolvedFail implements Resolved { - final EspressoException failure; - - public ResolvedFail(EspressoException failure) { - this.failure = failure; - } - - @Override - public void checkFail() { - throw failure; - } - - @Override - public void putResolved(VirtualFrame frame, int top, BytecodeNode node) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("Failure should have arose earlier."); - } - - @Override - public Object value() { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("Failure should have arose earlier."); - } - - @Override - public String toString(ConstantPool pool) { - return "ResolvedDynamicConstant(" + failure + ")"; - } - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/FieldRefConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/FieldRefConstant.java deleted file mode 100644 index 6103308fd5eb..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/FieldRefConstant.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile.constantpool; - -import java.util.Objects; - -import com.oracle.truffle.api.Assumption; -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Descriptor; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; -import com.oracle.truffle.espresso.impl.Field; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.perf.DebugCounter; -import com.oracle.truffle.espresso.redefinition.ClassRedefinition; -import com.oracle.truffle.espresso.runtime.EspressoException; - -public interface FieldRefConstant extends MemberRefConstant { - - /* static final */ DebugCounter FIELDREF_RESOLVE_COUNT = DebugCounter.create("FieldREf.resolve calls"); - - static FieldRefConstant create(int classIndex, int nameAndTypeIndex) { - return new Indexes(classIndex, nameAndTypeIndex); - } - - static Resolvable.ResolvedConstant fromPreResolved(Field field) { - return new Resolved(field); - } - - @Override - default Tag tag() { - return Tag.FIELD_REF; - } - - @SuppressWarnings("uncheked") - default Symbol getType(ConstantPool pool) { - // TODO(peterssen): Validate type descriptor. - return Types.fromDescriptor(getDescriptor(pool)); - } - - final class Indexes extends MemberRefConstant.Indexes implements FieldRefConstant, Resolvable { - Indexes(int classIndex, int nameAndTypeIndex) { - super(classIndex, nameAndTypeIndex); - } - - /** - *

      5.4.3.2. Field Resolution

      - * - * To resolve an unresolved symbolic reference from D to a field in a class or interface C, - * the symbolic reference to C given by the field reference must first be resolved - * (§5.4.3.1). Therefore, any exception that can be thrown as a result of failure of - * resolution of a class or interface reference can be thrown as a result of failure of - * field resolution. If the reference to C can be successfully resolved, an exception - * relating to the failure of resolution of the field reference itself can be thrown. - * - * When resolving a field reference, field resolution first attempts to look up the - * referenced field in C and its superclasses: - *
        - *
      1. If C declares a field with the name and descriptor specified by the field reference, - * field lookup succeeds. The declared field is the result of the field lookup. - *
      2. Otherwise, field lookup is applied recursively to the direct superinterfaces of the - * specified class or interface C. - *
      3. Otherwise, if C has a superclass S, field lookup is applied recursively to S. - *
      4. Otherwise, field lookup fails. - *
      - * - * Then: - *
        - *
      • If field lookup fails, field resolution throws a NoSuchFieldError. - *
      • Otherwise, if field lookup succeeds but the referenced field is not accessible - * (§5.4.4) to D, field resolution throws an IllegalAccessError. - *
      • Otherwise, let < E, L1 > be the class or interface in which the referenced field is - * actually declared and let L2 be the defining loader of D. - *
      • Given that the type of the referenced field is Tf, let T be Tf if Tf is not an array - * type, and let T be the element type (§2.4) of Tf otherwise. - *
      • The Java Virtual Machine must impose the loading constraint that TL1 = TL2 - * (§5.3.4). - *
      - */ - private static Field lookupField(Klass seed, Symbol name, Symbol type) { - Field f = seed.lookupDeclaredField(name, type); - if (f != null) { - return f; - } - for (Klass i : seed.getSuperInterfaces()) { - f = lookupField(i, name, type); - if (f != null) { - return f; - } - } - if (seed.getSuperKlass() != null) { - return lookupField(seed.getSuperKlass(), name, type); - } - return null; - } - - @Override - public ResolvedConstant resolve(RuntimeConstantPool pool, int thisIndex, ObjectKlass accessingKlass) { - FIELDREF_RESOLVE_COUNT.inc(); - Klass holderKlass = getResolvedHolderKlass(accessingKlass, pool); - Symbol name = getName(pool); - Symbol type = getType(pool); - - Field field = lookupField(holderKlass, name, type); - if (field == null) { - ClassRedefinition classRedefinition = pool.getContext().getClassRedefinition(); - if (classRedefinition != null) { - // could be due to ongoing redefinition - classRedefinition.check(); - field = lookupField(holderKlass, name, type); - } - if (field == null) { - Meta meta = pool.getContext().getMeta(); - EspressoException failure = EspressoException.wrap(Meta.initExceptionWithMessage(meta.java_lang_NoSuchFieldError, name.toString()), meta); - Assumption missingFieldAssumption; - if (classRedefinition != null) { - missingFieldAssumption = classRedefinition.getMissingFieldAssumption(); - } else { - missingFieldAssumption = Assumption.ALWAYS_VALID; - } - return new Missing(failure, missingFieldAssumption); - } - } - - MemberRefConstant.doAccessCheck(accessingKlass, holderKlass, field, pool.getContext().getMeta()); - - field.checkLoadingConstraints(accessingKlass.getDefiningClassLoader(), field.getDeclaringKlass().getDefiningClassLoader()); - - return new Resolved(field); - } - - @Override - public void validate(ConstantPool pool) { - super.validate(pool); - pool.nameAndTypeAt(nameAndTypeIndex).validateField(pool); - } - } - - final class Resolved implements FieldRefConstant, Resolvable.ResolvedConstant { - private final Field resolved; - - Resolved(Field resolvedField) { - Objects.requireNonNull(resolvedField); - this.resolved = resolvedField; - } - - @Override - public Symbol getType(ConstantPool pool) { - return resolved.getType(); - } - - @Override - public Field value() { - return resolved; - } - - @Override - public Symbol getHolderKlassName(ConstantPool pool) { - throw EspressoError.shouldNotReachHere("Field already resolved"); - } - - @Override - public Symbol getName(ConstantPool pool) { - return resolved.getName(); - } - - @Override - public Symbol getDescriptor(ConstantPool pool) { - return getType(pool); - } - } - - final class Missing implements FieldRefConstant, Resolvable.ResolvedConstant { - private final EspressoException failure; - private final Assumption assumption; - - public Missing(EspressoException failure, Assumption missingFieldAssumption) { - this.failure = failure; - this.assumption = missingFieldAssumption; - } - - @Override - public Symbol getType(ConstantPool pool) { - throw EspressoError.shouldNotReachHere(); - } - - @Override - public Field value() { - if (assumption.isValid()) { - throw failure; - } else { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw new NeedsFreshResolutionException(); - } - } - - @Override - public Symbol getHolderKlassName(ConstantPool pool) { - throw EspressoError.shouldNotReachHere(); - } - - @Override - public Symbol getName(ConstantPool pool) { - throw EspressoError.shouldNotReachHere(); - } - - @Override - public Symbol getDescriptor(ConstantPool pool) { - throw EspressoError.shouldNotReachHere(); - } - - @Override - public boolean isSuccess() { - return false; - } - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/InterfaceMethodRefConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/InterfaceMethodRefConstant.java deleted file mode 100644 index a5c47517c2ee..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/InterfaceMethodRefConstant.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile.constantpool; - -import java.util.Objects; - -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Descriptor; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.impl.Method; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.resolver.LinkResolver; - -public interface InterfaceMethodRefConstant extends MethodRefConstant { - - static InterfaceMethodRefConstant create(int classIndex, int nameAndTypeIndex) { - return new Indexes(classIndex, nameAndTypeIndex); - } - - @Override - default Tag tag() { - return Tag.INTERFACE_METHOD_REF; - } - - final class Indexes extends MethodRefConstant.Indexes implements InterfaceMethodRefConstant, Resolvable { - Indexes(int classIndex, int nameAndTypeIndex) { - super(classIndex, nameAndTypeIndex); - } - - /** - *

      5.4.3.4. Interface Method Resolution

      - * - * To resolve an unresolved symbolic reference from D to an interface method in an interface - * C, the symbolic reference to C given by the interface method reference is first resolved - * (§5.4.3.1). Therefore, any exception that can be thrown as a result of failure of - * resolution of an interface reference can be thrown as a result of failure of interface - * method resolution. If the reference to C can be successfully resolved, exceptions - * relating to the resolution of the interface method reference itself can be thrown. - * - * When resolving an interface method reference: - *
        - *
      1. If C is not an interface, interface method resolution throws an - * IncompatibleClassChangeError. - *
      2. Otherwise, if C declares a method with the name and descriptor specified by the - * interface method reference, method lookup succeeds. - *
      3. Otherwise, if the class Object declares a method with the name and descriptor - * specified by the interface method reference, which has its ACC_PUBLIC flag set and does - * not have its ACC_STATIC flag set, method lookup succeeds. - *
      4. Otherwise, if the maximally-specific superinterface methods (§5.4.3.3) of C for - * the name and descriptor specified by the method reference include exactly one method that - * does not have its ACC_ABSTRACT flag set, then this method is chosen and method lookup - * succeeds. - *
      5. Otherwise, if any superinterface of C declares a method with the name and descriptor - * specified by the method reference that has neither its ACC_PRIVATE flag nor its - * ACC_STATIC flag set, one of these is arbitrarily chosen and method lookup succeeds. - *
      6. Otherwise, method lookup fails. - *
      - * - * The result of interface method resolution is determined by whether method lookup succeeds - * or fails: - *
        - *
      • If method lookup fails, interface method resolution throws a - * NoSuchMethodError. - *
      • If method lookup succeeds and the referenced method is not accessible - * (§5.4.4) to D, interface method resolution throws an IllegalAccessError. - *
      • Otherwise, let < E, L1 > be the class or interface in which the referenced interface - * method m is actually declared, and let L2 be the defining loader of D. - *
      • Given that the return type of m is Tr, and that the formal parameter types of m are - * Tf1, ..., Tfn, then: - *
      • If Tr is not an array type, let T0 be Tr; otherwise, let T0 be the element type - * (§2.4) of Tr. - *
      • For i = 1 to n: If Tfi is not an array type, let Ti be Tfi; otherwise, let Ti be the - * element type (§2.4) of Tfi. - *
      • The Java Virtual Machine must impose the loading constraints TiL1 = TiL2 for i = 0 to - * n (§5.3.4). - *
      - * The clause about accessibility is necessary because interface method resolution may pick - * a private method of interface C. (Prior to Java SE 8, the result of interface method - * resolution could be a non-public method of class Object or a static method of class - * Object; such results were not consistent with the inheritance model of the Java - * programming language, and are disallowed in Java SE 8 and above.) - */ - @Override - public ResolvedConstant resolve(RuntimeConstantPool pool, int thisIndex, ObjectKlass accessingKlass) { - METHODREF_RESOLVE_COUNT.inc(); - - Klass holderInterface = getResolvedHolderKlass(accessingKlass, pool); - Symbol name = getName(pool); - Symbol signature = getSignature(pool); - - Method method = LinkResolver.resolveSymbol(pool.getContext().getMeta(), accessingKlass, name, signature, holderInterface, true, true, true); - - return new Resolved(method); - } - } - - final class Resolved implements InterfaceMethodRefConstant, Resolvable.ResolvedConstant { - private final Method resolved; - - Resolved(Method resolved) { - this.resolved = Objects.requireNonNull(resolved); - } - - @Override - public Method value() { - return resolved; - } - - @Override - public Symbol getHolderKlassName(ConstantPool pool) { - // return resolved.getDeclaringKlass().getName(); - throw EspressoError.shouldNotReachHere("Method already resolved"); - } - - @Override - public Symbol getName(ConstantPool pool) { - return resolved.getName(); - } - - @Override - public Symbol getDescriptor(ConstantPool pool) { - return resolved.getRawSignature(); - } - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/InvokeDynamicConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/InvokeDynamicConstant.java deleted file mode 100644 index f39a470cf67b..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/InvokeDynamicConstant.java +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile.constantpool; - -import java.nio.ByteBuffer; -import java.util.Arrays; - -import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.classfile.attributes.BootstrapMethodsAttribute; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.impl.Method; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.runtime.EspressoException; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; - -public interface InvokeDynamicConstant extends BootstrapMethodConstant { - - static InvokeDynamicConstant create(int bootstrapMethodAttrIndex, int nameAndTypeIndex) { - return new Indexes(bootstrapMethodAttrIndex, nameAndTypeIndex); - } - - @Override - default Tag tag() { - return Tag.INVOKEDYNAMIC; - } - - Symbol getSignature(ConstantPool pool); - - default Symbol[] getParsedSignature() { - throw EspressoError.shouldNotReachHere("Not resolved yet"); - } - - default boolean isResolved() { - return false; - } - - CallSiteLink link(RuntimeConstantPool pool, ObjectKlass accessingKlass, int thisIndex, Method method, int bci); - - final class Indexes extends BootstrapMethodConstant.Indexes implements InvokeDynamicConstant, Resolvable { - Indexes(int bootstrapMethodAttrIndex, int nameAndTypeIndex) { - super(bootstrapMethodAttrIndex, nameAndTypeIndex); - } - - @Override - public void dump(ByteBuffer buf) { - buf.putChar(bootstrapMethodAttrIndex); - buf.putChar(nameAndTypeIndex); - } - - @Override - public void validate(ConstantPool pool) { - pool.nameAndTypeAt(nameAndTypeIndex).validateMethod(pool, false); - } - - @Override - public Symbol getSignature(ConstantPool pool) { - return Signatures.check(pool.nameAndTypeAt(nameAndTypeIndex).getDescriptor(pool)); - } - - @Override - public ResolvedConstant resolve(RuntimeConstantPool pool, int thisIndex, ObjectKlass accessingKlass) { - CompilerAsserts.neverPartOfCompilation(); - BootstrapMethodsAttribute bms = (BootstrapMethodsAttribute) accessingKlass.getAttribute(BootstrapMethodsAttribute.NAME); - BootstrapMethodsAttribute.Entry bsEntry = bms.at(getBootstrapMethodAttrIndex()); - - Meta meta = accessingKlass.getMeta(); - Symbol invokeSignature = getSignature(pool); - Symbol[] parsedInvokeSignature = meta.getSignatures().parsed(invokeSignature); - return new Resolved(bsEntry, parsedInvokeSignature, getName(pool)); - } - - @Override - public String toString(ConstantPool pool) { - return "bsmIndex:" + getBootstrapMethodAttrIndex() + " " + getSignature(pool); - } - - @Override - public CallSiteLink link(RuntimeConstantPool pool, ObjectKlass accessingKlass, int thisIndex, Method method, int bci) { - throw EspressoError.shouldNotReachHere("Not resolved yet"); - } - } - - final class Resolved implements InvokeDynamicConstant, Resolvable.ResolvedConstant { - private final BootstrapMethodsAttribute.Entry bootstrapMethod; - private final Symbol[] parsedInvokeSignature; - private final Symbol nameSymbol; - private volatile InvokeDynamicConstant.CallSiteLink[] callSiteLinks; - - public Resolved(BootstrapMethodsAttribute.Entry bootstrapMethod, Symbol[] parsedInvokeSignature, Symbol name) { - this.bootstrapMethod = bootstrapMethod; - this.parsedInvokeSignature = parsedInvokeSignature; - this.nameSymbol = name; - } - - @Override - public Object value() { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("Use indy.link() rather than Resolved.value()"); - } - - @Override - public boolean isResolved() { - return true; - } - - /** - * The call site linking operation must be executed once per {@code invokedynamic} - * instruction, rather than once per {@code invokedynamic_constant}. - *

      - * Furthermore, a previously failed call site linking from the constant pool must - * immediately fail again on subsequent linking operations, independently of the - * invokedynamic instruction involved. - *

      - * For example: - * - *

      -         * method1:
      -         *     0: invokedynamic #0 // calls MHN.linkCallSite successfully
      -         *     4: invokedynamic #0 // Also calls MHM.linkCallSite, resulting in a *different* CallSite
      -         *     
      -         * method2:
      -         *     0: invokedynamic #1 // Fails during MHN.linkCallSite upcall
      -         *     4: invokedynamic #1 // Immediately fails without calling MHN.linkCallSite
      -         * 
      - * - * @see RuntimeConstantPool#linkInvokeDynamic(ObjectKlass, int, int, - * com.oracle.truffle.espresso.impl.Method) - */ - @Override - public CallSiteLink link(RuntimeConstantPool pool, ObjectKlass accessingKlass, int thisIndex, Method method, int bci) { - int existingIndex = findCallSiteLinkIndex(method, bci); - if (existingIndex >= 0) { - return getCallSiteLink(existingIndex); - } - // The call site linking must not happen under the lock, it is racy - // However insertion should be done under a lock - // see JVMS sect. 5.4.3.6 & ConstantPoolCache::set_dynamic_call - InvokeDynamicConstant.CallSiteLink newLink = createCallSiteLink(pool, accessingKlass, thisIndex, method, bci); - synchronized (this) { - InvokeDynamicConstant.CallSiteLink[] existingLinks = callSiteLinks; - if (existingLinks == null) { - InvokeDynamicConstant.CallSiteLink[] newLinks = new InvokeDynamicConstant.CallSiteLink[1]; - newLinks[0] = newLink; - callSiteLinks = newLinks; - return newLink; - } else { - int i = 0; - for (; i < existingLinks.length; i++) { - InvokeDynamicConstant.CallSiteLink link = existingLinks[i]; - if (link == null) { - existingLinks[i] = newLink; - return existingLinks[i]; - } - if (link.matchesCallSite(method, bci)) { - return link; - } - } - // we didn't find an existing link nor an available slot - // the array growth is limited by the max number of possible bcis for a method - // (which is a power of 2). - InvokeDynamicConstant.CallSiteLink[] newLinks = Arrays.copyOf(existingLinks, existingLinks.length * 2); - newLinks[i] = newLink; - callSiteLinks = newLinks; - return newLink; - } - } - } - - private CallSiteLink createCallSiteLink(RuntimeConstantPool pool, ObjectKlass accessingKlass, int thisIndex, Method method, int bci) { - // Per-callsite linking - CompilerAsserts.neverPartOfCompilation(); - Meta meta = accessingKlass.getMeta(); - try { - StaticObject bootstrapmethodMethodHandle = bootstrapMethod.getMethodHandle(accessingKlass, pool); - StaticObject[] args = bootstrapMethod.getStaticArguments(accessingKlass, pool); - - StaticObject name = meta.toGuestString(nameSymbol); - StaticObject methodType = MethodTypeConstant.signatureToMethodType(parsedInvokeSignature, accessingKlass, meta.getContext().getJavaVersion().java8OrEarlier(), meta); - /* - * the 4 objects resolved above are not actually call-site specific. We don't cache - * them to minimize footprint since most indy constant are only used by one - * call-site - */ - - StaticObject appendix = StaticObject.createArray(meta.java_lang_Object_array, new StaticObject[1], meta.getContext()); - StaticObject memberName; - if (meta.getJavaVersion().varHandlesEnabled() && !meta.getJavaVersion().java19OrLater()) { - memberName = (StaticObject) meta.java_lang_invoke_MethodHandleNatives_linkCallSite.invokeDirectStatic( - accessingKlass.mirror(), - thisIndex, - bootstrapmethodMethodHandle, - name, methodType, - StaticObject.createArray(meta.java_lang_Object_array, args.clone(), meta.getContext()), - appendix); - } else { - memberName = (StaticObject) meta.java_lang_invoke_MethodHandleNatives_linkCallSite.invokeDirectStatic( - accessingKlass.mirror(), - bootstrapmethodMethodHandle, - name, methodType, - StaticObject.createArray(meta.java_lang_Object_array, args.clone(), meta.getContext()), - appendix); - } - StaticObject unboxedAppendix = appendix.get(meta.getLanguage(), 0); - - return new CallSiteLink(method, bci, memberName, unboxedAppendix, parsedInvokeSignature); - } catch (EspressoException e) { - throw new CallSiteLinkingFailure(e); - } - } - - public int findCallSiteLinkIndex(Method method, int bci) { - InvokeDynamicConstant.CallSiteLink[] existingLinks = callSiteLinks; - if (existingLinks == null) { - return -1; - } - for (int i = 0; i < existingLinks.length; i++) { - InvokeDynamicConstant.CallSiteLink link = existingLinks[i]; - if (link == null) { - break; - } - if (link.matchesCallSite(method, bci)) { - return i; - } - } - return -1; - } - - public InvokeDynamicConstant.CallSiteLink getCallSiteLink(int index) { - return callSiteLinks[index]; - } - - @Override - public int getBootstrapMethodAttrIndex() { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("String already resolved"); - } - - @Override - public Symbol getName(ConstantPool pool) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("String already resolved"); - } - - @Override - public Symbol getSignature(ConstantPool pool) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("String already resolved"); - } - - @Override - public NameAndTypeConstant getNameAndType(ConstantPool pool) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("String already resolved"); - } - - @Override - public Symbol[] getParsedSignature() { - return parsedInvokeSignature; - } - } - - final class CallSiteLink { - private final Method method; - private final int bci; - final StaticObject memberName; - final StaticObject unboxedAppendix; - @CompilerDirectives.CompilationFinal(dimensions = 1) final Symbol[] parsedSignature; - - public CallSiteLink(Method method, int bci, StaticObject memberName, StaticObject unboxedAppendix, Symbol[] parsedSignature) { - this.method = method; - this.bci = bci; - this.memberName = memberName; - this.unboxedAppendix = unboxedAppendix; - this.parsedSignature = parsedSignature; - } - - public StaticObject getMemberName() { - return memberName; - } - - public StaticObject getUnboxedAppendix() { - return unboxedAppendix; - } - - public Symbol[] getParsedSignature() { - return parsedSignature; - } - - public boolean matchesCallSite(Method siteMethod, int siteBci) { - return bci == siteBci && method == siteMethod; - } - } - - final class CallSiteLinkingFailure extends RuntimeException { - private static final long serialVersionUID = 2567495832103023693L; - - public EspressoException cause; - - public CallSiteLinkingFailure(EspressoException cause) { - this.cause = cause; - } - - public Fail failConstant() { - return new Fail(cause); - } - - @Override - @SuppressWarnings("sync-override") - public Throwable fillInStackTrace() { - return this; - } - } - - final class Fail implements InvokeDynamicConstant, Resolvable.ResolvedConstant { - private final EspressoException failure; - - public Fail(EspressoException failure) { - this.failure = failure; - } - - @Override - public CallSiteLink link(RuntimeConstantPool pool, ObjectKlass accessingKlass, int thisIndex, Method method, int bci) { - throw failure; - } - - @Override - public Object value() { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("Use indy.link() rather than Resolved.value()"); - } - - @Override - public int getBootstrapMethodAttrIndex() { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("Invoke dynamic already resolved."); - } - - @Override - public Symbol getName(ConstantPool pool) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("Invoke dynamic already resolved."); - } - - @Override - public Symbol getSignature(ConstantPool pool) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("Invoke dynamic already resolved."); - } - - @Override - public NameAndTypeConstant getNameAndType(ConstantPool pool) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("Invoke dynamic already resolved."); - } - - @Override - public void dump(ByteBuffer buf) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - throw EspressoError.shouldNotReachHere("Invoke dynamic already resolved."); - } - - @Override - public boolean isSuccess() { - return false; - } - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MemberRefConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MemberRefConstant.java deleted file mode 100644 index 46bd6c76127b..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MemberRefConstant.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile.constantpool; - -import java.nio.ByteBuffer; - -import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Descriptor; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.impl.Member; -import com.oracle.truffle.espresso.impl.Method; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.Meta; - -/** - * Interface denoting a field or method entry in a constant pool. - */ -public interface MemberRefConstant extends PoolConstant { - - /** - * Gets the class in which this method or field is declared. Note that the actual holder after - * resolution may be a super class of the class described by the one returned by this method. - */ - Symbol getHolderKlassName(ConstantPool pool); - - /** - * Gets the name of this field or method. - * - * @param pool the constant pool that maybe be required to convert a constant pool index to a - * name - */ - Symbol getName(ConstantPool pool); - - /** - * Gets the descriptor (type or signature) of this field or method. - * - * @param pool the constant pool that maybe be required to convert a constant pool index to a - * name - */ - Symbol getDescriptor(ConstantPool pool); - - @Override - default String toString(ConstantPool pool) { - return getHolderKlassName(pool) + "." + getName(pool) + getDescriptor(pool); - } - - abstract class Indexes implements MemberRefConstant { - - final char classIndex; - - final char nameAndTypeIndex; - - Indexes(int classIndex, int nameAndTypeIndex) { - this.classIndex = PoolConstant.u2(classIndex); - this.nameAndTypeIndex = PoolConstant.u2(nameAndTypeIndex); - } - - @Override - public Symbol getHolderKlassName(ConstantPool pool) { - return pool.classAt(classIndex).getName(pool); - } - - public Klass getResolvedHolderKlass(ObjectKlass accessingKlass, RuntimeConstantPool pool) { - return pool.resolvedKlassAt(accessingKlass, classIndex); - } - - @Override - public Symbol getName(ConstantPool pool) { - return pool.nameAndTypeAt(nameAndTypeIndex).getName(pool); - } - - @Override - public Symbol getDescriptor(ConstantPool pool) { - return pool.nameAndTypeAt(nameAndTypeIndex).getDescriptor(pool); - } - - @Override - public void validate(ConstantPool pool) { - pool.classAt(classIndex).validate(pool); - pool.nameAndTypeAt(nameAndTypeIndex).validate(pool); - } - - @Override - public void dump(ByteBuffer buf) { - buf.putChar(classIndex); - buf.putChar(nameAndTypeIndex); - } - } - - @TruffleBoundary - static void doAccessCheck(ObjectKlass accessingKlass, Klass resolvedKlass, Member member, Meta meta) { - if (!MemberRefConstant.checkAccess(accessingKlass, resolvedKlass, member)) { - String message = "Class " + accessingKlass.getExternalName() + " cannot access method " + resolvedKlass.getExternalName() + "#" + member.getName(); - throw meta.throwExceptionWithMessage(meta.java_lang_IllegalAccessError, meta.toGuestString(message)); - } - } - - /** - *

      5.4.4. Access Control

      - * - * A field or method R is accessible to a class or interface D if and only if any of the - * following is true: - *
        - *
      • R is public. - *
      • R is protected and is declared in a class C, and D is either a subclass of C or C itself. - * Furthermore, if R is not static, then the symbolic reference to R must contain a symbolic - * reference to a class T, such that T is either a subclass of D, a superclass of D, or D - * itself. - *
      • R is either protected or has default access (that is, neither public nor protected nor - * private), and is declared by a class in the same run-time package as D. - *
      • R is private and is declared in D. - *
      - */ - static boolean checkAccess(ObjectKlass accessingKlass, Klass resolvedKlass, Member member) { - if (member.isPublic()) { - return true; - } - Klass memberKlass = member.getDeclaringKlass(); - if (member instanceof Method && Name.clone.equals(member.getName()) && memberKlass.isJavaLangObject()) { - if (resolvedKlass.isArray()) { - return true; - } - } - if (member.isProtected()) { - if (!member.isStatic()) { - if (resolvedKlass.isAssignableFrom(accessingKlass) || accessingKlass.isAssignableFrom(resolvedKlass)) { - return true; - } - } else { - if (memberKlass.isAssignableFrom(accessingKlass)) { - return true; - } - } - } - if (member.isProtected() || member.isPackagePrivate()) { - if (accessingKlass.sameRuntimePackage(memberKlass)) { - return true; - } - } - if (member.isPrivate() && nestMateTest(accessingKlass, memberKlass)) { - return true; - } - // MagicAccessorImpl marks internal reflection classes that have access to everything. - if (accessingKlass.getMeta().sun_reflect_MagicAccessorImpl.isAssignableFrom(accessingKlass)) { - return true; - } - - if (accessingKlass.getHostClass() != null) { - CompilerAsserts.partialEvaluationConstant(accessingKlass); - return checkAccess(accessingKlass.getHostClass(), resolvedKlass, member); - } - return false; - } - - static boolean nestMateTest(Klass k1, Klass k2) { - return k1 == k2 || k1.nest() == k2.nest(); - } - -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MethodHandleConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MethodHandleConstant.java deleted file mode 100644 index 96d6db8e5891..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MethodHandleConstant.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile.constantpool; - -import java.nio.ByteBuffer; - -import com.oracle.truffle.espresso.EspressoOptions; -import com.oracle.truffle.espresso.classfile.ClassfileParser; -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.impl.Field; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.impl.Method; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; - -public interface MethodHandleConstant extends PoolConstant { - - static MethodHandleConstant create(int refKind, int refIndex) { - return new Index(refKind, refIndex); - } - - default Tag tag() { - return Tag.METHODHANDLE; - } - - enum RefKind { - GETFIELD(1), - GETSTATIC(2), - PUTFIELD(3), - PUTSTATIC(4), - INVOKEVIRTUAL(5), - INVOKESTATIC(6), - INVOKESPECIAL(7), - NEWINVOKESPECIAL(8), - INVOKEINTERFACE(9); - - public final int value; - - RefKind(int value) { - this.value = value; - } - - public static RefKind forValue(int value) { - // @formatter:off - switch(value) { - case 1: return GETFIELD; - case 2: return GETSTATIC; - case 3: return PUTFIELD; - case 4: return PUTSTATIC; - case 5: return INVOKEVIRTUAL; - case 6: return INVOKESTATIC; - case 7: return INVOKESPECIAL; - case 8: return NEWINVOKESPECIAL; - case 9: return INVOKEINTERFACE; - default: return null; - } - // @formatter:on - } - } - - RefKind getRefKind(); - - char getRefIndex(); - - @Override - default String toString(ConstantPool pool) { - return getRefKind() + " " + pool.at(getRefIndex()).toString(pool); - } - - final class Index implements MethodHandleConstant, Resolvable { - - private final byte refKind; - private final char refIndex; - - Index(int refKind, int refIndex) { - this.refKind = PoolConstant.u1(refKind); - this.refIndex = PoolConstant.u2(refIndex); - } - - @Override - public RefKind getRefKind() { - // not yet validated! Could be null - return RefKind.forValue(refKind); - } - - @Override - public char getRefIndex() { - return refIndex; - } - - @Override - public ResolvedConstant resolve(RuntimeConstantPool pool, int thisIndex, ObjectKlass accessingKlass) { - Meta meta = pool.getContext().getMeta(); - if (meta.getLanguage().getSpecComplianceMode() == EspressoOptions.SpecComplianceMode.STRICT || meta.getJavaVersion().java9OrLater()) { - return specCompliantResolution(pool, accessingKlass, meta); - } else { - return hotspotResolutionBehavior(pool, accessingKlass, meta); - } - } - - private ResolvedConstant specCompliantResolution(RuntimeConstantPool pool, ObjectKlass accessingKlass, Meta meta) { - StaticObject mtype; - Klass mklass; - Symbol refName; - - Tag refTag = pool.tagAt(getRefIndex()); - if (refTag == Tag.METHOD_REF || refTag == Tag.INTERFACE_METHOD_REF) { - Method target = pool.resolvedMethodAt(accessingKlass, refIndex); - Symbol[] parsed = target.getParsedSignature(); - - mtype = MethodTypeConstant.signatureToMethodType(parsed, accessingKlass, false, meta); - MethodRefConstant ref = pool.methodAt(getRefIndex()); - /* - * we should use the klass from the method ref here rather than the declaring klass - * of the target this is because the resolved target might come from a default - * method and have an interface as declaring klass however if the refKind is - * invokeVirtual, it would be illegal to use the interface type - */ - mklass = pool.resolvedKlassAt(accessingKlass, ((MemberRefConstant.Indexes) ref).classIndex); - refName = target.getName(); - } else { - assert refTag == Tag.FIELD_REF; - Field field = pool.resolvedFieldAt(accessingKlass, refIndex); - mtype = meta.resolveSymbolAndAccessCheck(field.getType(), accessingKlass).mirror(); - mklass = field.getDeclaringKlass(); - refName = field.getName(); - } - - return linkMethodHandleConstant(accessingKlass, meta, mtype, mklass, refName); - } - - /** - * Resolves a method handle without resolving the method reference, which is not the - * behavior described in the specs {5.4.3.5. Method Type and Method Handle Resolution } - *

      - * see {@code JDK-8188145} - */ - private ResolvedConstant hotspotResolutionBehavior(RuntimeConstantPool pool, ObjectKlass accessingKlass, Meta meta) { - StaticObject mtype; - Klass mklass; - Symbol refName; - - Tag refTag = pool.tagAt(getRefIndex()); - if (refTag == Tag.METHOD_REF || refTag == Tag.INTERFACE_METHOD_REF) { - MethodRefConstant ref = pool.methodAt(getRefIndex()); - Symbol signature = ref.getSignature(pool); - Symbol[] parsed = meta.getSignatures().parsed(signature); - - mtype = MethodTypeConstant.signatureToMethodType(parsed, accessingKlass, false, meta); - mklass = pool.resolvedKlassAt(accessingKlass, ((MemberRefConstant.Indexes) ref).classIndex); - refName = ref.getName(pool); - } else { - assert refTag == Tag.FIELD_REF; - assert pool.fieldAt(getRefIndex()) instanceof FieldRefConstant.Indexes; - FieldRefConstant.Indexes ref = (FieldRefConstant.Indexes) pool.fieldAt(getRefIndex()); - - Symbol type = ref.getType(pool); - mtype = meta.resolveSymbolAndAccessCheck(type, accessingKlass).mirror(); - mklass = ref.getResolvedHolderKlass(accessingKlass, pool); - refName = ref.getName(pool); - } - - return linkMethodHandleConstant(accessingKlass, meta, mtype, mklass, refName); - } - - private ResolvedConstant linkMethodHandleConstant(Klass accessingKlass, Meta meta, StaticObject mtype, Klass mklass, Symbol refName) { - StaticObject mname = meta.toGuestString(refName); - return new Resolved((StaticObject) meta.java_lang_invoke_MethodHandleNatives_linkMethodHandleConstant.invokeDirectStatic( - accessingKlass.mirror(), (int) refKind, - mklass.mirror(), mname, mtype)); - } - - @Override - public void validate(ConstantPool pool) { - pool.memberAt(refIndex).validate(pool); - - RefKind kind = getRefKind(); - - Symbol memberName = pool.memberAt(refIndex).getName(pool); - if (Name._clinit_.equals(memberName)) { - throw ConstantPool.classFormatError("Ill-formed constant: " + tag()); - } - - // If the value is 8 (REF_newInvokeSpecial), the name of the method represented by a - // CONSTANT_Methodref_info structure must be . - if (Name._init_.equals(memberName) && kind != RefKind.NEWINVOKESPECIAL) { - throw ConstantPool.classFormatError("Ill-formed constant: " + tag()); - } - if (getRefKind() == null) { - throw ConstantPool.classFormatError("Ill-formed constant: " + tag()); - } - - // If the value of the reference_kind item is 5 (REF_invokeVirtual), 6 - // (REF_invokeStatic), 7 (REF_invokeSpecial), or 9 (REF_invokeInterface), the name of - // the method represented by a CONSTANT_Methodref_info structure or a - // CONSTANT_InterfaceMethodref_info structure must not be or . - if (memberName.equals(Name._init_) || memberName.equals(Name._clinit_)) { - if (kind == RefKind.INVOKEVIRTUAL || - kind == RefKind.INVOKESTATIC || - kind == RefKind.INVOKESPECIAL || - kind == RefKind.INVOKEINTERFACE) { - throw ConstantPool.classFormatError("Ill-formed constant: " + tag()); - } - } - - boolean valid = false; - Tag tag = pool.at(refIndex).tag(); - switch (getRefKind()) { - case GETFIELD: // fall-through - case GETSTATIC: // fall-through - case PUTFIELD: // fall-through - case PUTSTATIC: - // If the value of the reference_kind item is 1 (REF_getField), 2 - // (REF_getStatic), 3 (REF_putField), or 4 (REF_putStatic), then the - // constant_pool entry at that index must be a CONSTANT_Fieldref_info - // (§4.4.2) - // structure representing a field for which a method handle is to be created. - valid = (tag == Tag.FIELD_REF); - break; - case INVOKEVIRTUAL: // fall-through - case NEWINVOKESPECIAL: - // If the value of the reference_kind item is 5 (REF_invokeVirtual) or 8 - // (REF_newInvokeSpecial), then the constant_pool entry at that index must be a - // CONSTANT_Methodref_info structure (§4.4.2) representing a class's method - // or constructor (§2.9) for which a method handle is to be created. - valid = tag == Tag.METHOD_REF; - break; - case INVOKESTATIC: // fall-through - case INVOKESPECIAL: - // If the value of the reference_kind item is 6 (REF_invokeStatic) or 7 - // (REF_invokeSpecial), then if the class file version number is less than 52.0, - // the constant_pool entry at that index must be a CONSTANT_Methodref_info - // structure representing a class's method for which a method handle is to be - // created; if the class file version number is 52.0 or above, the constant_pool - // entry at that index must be either a CONSTANT_Methodref_info structure or a - // CONSTANT_InterfaceMethodref_info structure (§4.4.2) representing a - // class's or interface's method for which a method handle is to be created. - valid = (tag == Tag.METHOD_REF) || - (pool.getMajorVersion() >= ClassfileParser.JAVA_8_VERSION && tag == Tag.INTERFACE_METHOD_REF); - break; - - case INVOKEINTERFACE: - // If the value of the reference_kind item is 9 (REF_invokeInterface), then the - // constant_pool entry at that index must be a CONSTANT_InterfaceMethodref_info - // structure representing an interface's method for which a method handle is to - // be created. - valid = (tag == Tag.INTERFACE_METHOD_REF); - break; - } - - if (!valid) { - throw ConstantPool.classFormatError("Ill-formed constant: " + tag()); - } - - } - - @Override - public void dump(ByteBuffer buf) { - buf.put(refKind); - buf.putChar(refIndex); - } - } - - final class Resolved implements Resolvable.ResolvedConstant { - private StaticObject payload; - - Resolved(StaticObject payload) { - this.payload = payload; - } - - @Override - public Object value() { - return payload; - } - - public Tag tag() { - return Tag.METHODHANDLE; - } - - @Override - public String toString(ConstantPool pool) { - return payload.toString(); - } - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MethodTypeConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MethodTypeConstant.java deleted file mode 100644 index d36539b5ffed..000000000000 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/MethodTypeConstant.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.espresso.classfile.constantpool; - -import static com.oracle.truffle.espresso.descriptors.Symbol.Signature; - -import java.nio.ByteBuffer; - -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.runtime.EspressoException; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; - -public interface MethodTypeConstant extends PoolConstant { - - static MethodTypeConstant create(int descriptorIndex) { - return new Index(descriptorIndex); - } - - @Override - default Tag tag() { - return Tag.METHODTYPE; - } - - static StaticObject signatureToMethodType(Symbol[] signature, ObjectKlass accessingKlass, boolean failWithBME, Meta meta) { - Symbol rt = Signatures.returnType(signature); - int pcount = Signatures.parameterCount(signature); - - StaticObject[] ptypes = new StaticObject[pcount]; - StaticObject rtype; - try { - for (int i = 0; i < pcount; i++) { - Symbol paramType = Signatures.parameterType(signature, i); - ptypes[i] = meta.resolveSymbolAndAccessCheck(paramType, accessingKlass).mirror(); - } - } catch (EspressoException e) { - if (meta.java_lang_ClassNotFoundException.isAssignableFrom(e.getGuestException().getKlass())) { - throw meta.throwExceptionWithMessage(meta.java_lang_NoClassDefFoundError, e.getGuestMessage()); - } - throw e; - } - try { - rtype = meta.resolveSymbolAndAccessCheck(rt, accessingKlass).mirror(); - } catch (EspressoException e) { - EspressoException rethrow = e; - if (meta.java_lang_ClassNotFoundException.isAssignableFrom(e.getGuestException().getKlass())) { - rethrow = EspressoException.wrap(Meta.initExceptionWithMessage(meta.java_lang_NoClassDefFoundError, e.getGuestMessage()), meta); - } - if (failWithBME) { - rethrow = EspressoException.wrap(Meta.initExceptionWithCause(meta.java_lang_BootstrapMethodError, rethrow.getGuestException()), meta); - } - throw rethrow; - } - - return (StaticObject) meta.java_lang_invoke_MethodHandleNatives_findMethodHandleType.invokeDirectStatic(rtype, StaticObject.createArray(meta.java_lang_Class_array, ptypes, meta.getContext())); - } - - /** - * Gets the signature of this method type constant. - * - * @param pool the constant pool that maybe be required to convert a constant pool index to a - * name - */ - Symbol getSignature(ConstantPool pool); - - @Override - default String toString(ConstantPool pool) { - return getSignature(pool).toString(); - } - - final class Index implements MethodTypeConstant, Resolvable { - - private final char descriptorIndex; - - Index(int descriptorIndex) { - this.descriptorIndex = PoolConstant.u2(descriptorIndex); - } - - @Override - public Symbol getSignature(ConstantPool pool) { - // TODO(peterssen): Assert valid signature. - return pool.symbolAt(descriptorIndex); - } - - @Override - public Resolved resolve(RuntimeConstantPool pool, int index, ObjectKlass accessingKlass) { - Symbol sig = getSignature(pool); - Meta meta = accessingKlass.getContext().getMeta(); - return new Resolved(signatureToMethodType(meta.getSignatures().parsed(sig), accessingKlass, false, meta)); - } - - @Override - public void validate(ConstantPool pool) { - pool.utf8At(descriptorIndex).validateSignature(); - } - - @Override - public void dump(ByteBuffer buf) { - buf.putChar(descriptorIndex); - } - } - - final class Resolved implements MethodTypeConstant, Resolvable.ResolvedConstant { - private final StaticObject resolved; - - Resolved(StaticObject resolved) { - this.resolved = resolved; - } - - @Override - public Symbol getSignature(ConstantPool pool) { - // TODO(peterssen): Assert valid signature. - throw EspressoError.shouldNotReachHere("Method type already resolved !"); - } - - @Override - public Object value() { - return resolved; - } - } -} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/CallSiteLink.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/CallSiteLink.java new file mode 100644 index 000000000000..f5a2f80ac166 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/CallSiteLink.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; + +public final class CallSiteLink { + private final Method method; + private final int bci; + final StaticObject memberName; + final StaticObject unboxedAppendix; + + @CompilationFinal(dimensions = 1) // + final Symbol[] parsedSignature; + + public CallSiteLink(Method method, int bci, StaticObject memberName, StaticObject unboxedAppendix, Symbol[] parsedSignature) { + this.method = method; + this.bci = bci; + this.memberName = memberName; + this.unboxedAppendix = unboxedAppendix; + this.parsedSignature = parsedSignature; + } + + public StaticObject getMemberName() { + return memberName; + } + + public StaticObject getUnboxedAppendix() { + return unboxedAppendix; + } + + public Symbol[] getParsedSignature() { + return parsedSignature; + } + + public boolean matchesCallSite(Method siteMethod, int siteBci) { + return bci == siteBci && method == siteMethod; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/CallSiteLinkingFailure.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/CallSiteLinkingFailure.java new file mode 100644 index 000000000000..561fc5a00056 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/CallSiteLinkingFailure.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.espresso.runtime.EspressoException; + +public final class CallSiteLinkingFailure extends RuntimeException { + private static final long serialVersionUID = 2567495832103023693L; + + public final EspressoException cause; + + public CallSiteLinkingFailure(EspressoException cause) { + this.cause = cause; + } + + public FailInvokeDynamicConstant failConstant() { + return new FailInvokeDynamicConstant(cause); + } + + @Override + @SuppressWarnings("sync-override") + public Throwable fillInStackTrace() { + return this; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/FailInvokeDynamicConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/FailInvokeDynamicConstant.java new file mode 100644 index 000000000000..3d81be70393c --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/FailInvokeDynamicConstant.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.impl.ObjectKlass; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.constantpool.NameAndTypeConstant; +import com.oracle.truffle.espresso.runtime.EspressoException; + +import java.nio.ByteBuffer; + +public final class FailInvokeDynamicConstant implements LinkableInvokeDynamicConstant { + private final EspressoException failure; + + public FailInvokeDynamicConstant(EspressoException failure) { + this.failure = failure; + } + + @Override + public CallSiteLink link(RuntimeConstantPool pool, ObjectKlass accessingKlass, int thisIndex, Method method, int bci) { + throw failure; + } + + @Override + public Object value() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("Use indy.link() rather than Resolved.value()"); + } + + @Override + public int getBootstrapMethodAttrIndex() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("Invoke dynamic already resolved."); + } + + @Override + public Symbol getName(ConstantPool pool) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("Invoke dynamic already resolved."); + } + + @Override + public Symbol getSignature(ConstantPool pool) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("Invoke dynamic already resolved."); + } + + @Override + public NameAndTypeConstant getNameAndType(ConstantPool pool) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("Invoke dynamic already resolved."); + } + + @Override + public void dump(ByteBuffer buf) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("Invoke dynamic already resolved."); + } + + @Override + public boolean isSuccess() { + return false; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/LinkableInvokeDynamicConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/LinkableInvokeDynamicConstant.java new file mode 100644 index 000000000000..f5fe7a1ed6b2 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/LinkableInvokeDynamicConstant.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.impl.ObjectKlass; +import com.oracle.truffle.espresso.classfile.constantpool.InvokeDynamicConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; + +interface LinkableInvokeDynamicConstant extends InvokeDynamicConstant, Resolvable.ResolvedConstant { + CallSiteLink link(RuntimeConstantPool pool, ObjectKlass accessingKlass, int thisIndex, Method method, int bci); +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/MissingFieldRefConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/MissingFieldRefConstant.java new file mode 100644 index 000000000000..8f9d4c267bb4 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/MissingFieldRefConstant.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.Assumption; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.impl.Field; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.constantpool.FieldRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; +import com.oracle.truffle.espresso.runtime.EspressoException; + +public final class MissingFieldRefConstant implements FieldRefConstant, Resolvable.ResolvedConstant { + private final EspressoException failure; + private final Assumption assumption; + + public MissingFieldRefConstant(EspressoException failure, Assumption missingFieldAssumption) { + this.failure = failure; + this.assumption = missingFieldAssumption; + } + + @Override + public Symbol getType(ConstantPool pool) { + throw EspressoError.shouldNotReachHere(); + } + + @Override + public Field value() { + if (assumption.isValid()) { + throw failure; + } else { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new NeedsFreshResolutionException(); + } + } + + @Override + public Symbol getHolderKlassName(ConstantPool pool) { + throw EspressoError.shouldNotReachHere(); + } + + @Override + public Symbol getName(ConstantPool pool) { + throw EspressoError.shouldNotReachHere(); + } + + @Override + public Symbol getDescriptor(ConstantPool pool) { + throw EspressoError.shouldNotReachHere(); + } + + @Override + public boolean isSuccess() { + return false; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/NeedsFreshResolutionException.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/NeedsFreshResolutionException.java similarity index 95% rename from espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/NeedsFreshResolutionException.java rename to espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/NeedsFreshResolutionException.java index 963885a49bb4..bee8b5dd15e9 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/classfile/constantpool/NeedsFreshResolutionException.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/NeedsFreshResolutionException.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.espresso.classfile.constantpool; +package com.oracle.truffle.espresso.constantpool; public class NeedsFreshResolutionException extends RuntimeException { private static final long serialVersionUID = -1567457542377424585L; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/PreResolvedClassConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/PreResolvedClassConstant.java new file mode 100644 index 000000000000..06c617012eb5 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/PreResolvedClassConstant.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.impl.Klass; +import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; + +import java.nio.ByteBuffer; +import java.util.Objects; + +/** + * Constant Pool patching inserts already resolved constants in the constant pool. However, at the + * time of patching, we do not have a Runtime CP. Therefore, we help the CP by inserting a + * Pre-Resolved constant. + *

      + * This is also used to Pre-resolve anonymous classes. + */ +public final class PreResolvedClassConstant implements ClassConstant, Resolvable { + private final Klass resolved; + + PreResolvedClassConstant(Klass resolved) { + this.resolved = Objects.requireNonNull(resolved); + } + + public Klass getResolved() { + return resolved; + } + + @Override + public Symbol getName(ConstantPool pool) { + return resolved.getName(); + } + + @Override + public void dump(ByteBuffer buf) { + buf.putChar((char) 0); + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/PreResolvedConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/PreResolvedConstant.java new file mode 100644 index 000000000000..55ce671a12ef --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/PreResolvedConstant.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; +import com.oracle.truffle.espresso.substitutions.JavaType; + +public final class PreResolvedConstant implements Resolvable.ResolvedConstant { + + private final ConstantPool.Tag tag; + private final StaticObject resolved; + + public PreResolvedConstant(@JavaType(Object.class) StaticObject resolved, ConstantPool.Tag tag) { + this.resolved = resolved; + this.tag = tag; + } + + @Override + public @JavaType(Object.class) StaticObject value() { + return resolved; + } + + @Override + public ConstantPool.Tag tag() { + return tag; + } + + @Override + public String toString(ConstantPool pool) { + return "pre-resolved"; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/Resolution.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/Resolution.java new file mode 100644 index 000000000000..239052f3c1ca --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/Resolution.java @@ -0,0 +1,760 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.Assumption; +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.espresso.EspressoLanguage; +import com.oracle.truffle.espresso.EspressoOptions; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Descriptor; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.impl.ClassRegistry; +import com.oracle.truffle.espresso.impl.Field; +import com.oracle.truffle.espresso.impl.Klass; +import com.oracle.truffle.espresso.impl.Member; +import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.impl.ObjectKlass; +import com.oracle.truffle.espresso.meta.Meta; +import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode; +import com.oracle.truffle.espresso.nodes.methodhandle.MHLinkToNode; +import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.attributes.BootstrapMethodsAttribute; +import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; +import com.oracle.truffle.espresso.classfile.constantpool.ClassMethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.DynamicConstant; +import com.oracle.truffle.espresso.classfile.constantpool.FieldRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.InterfaceMethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.InvokeDynamicConstant; +import com.oracle.truffle.espresso.classfile.constantpool.MemberRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.MethodHandleConstant; +import com.oracle.truffle.espresso.classfile.constantpool.MethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.MethodTypeConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; +import com.oracle.truffle.espresso.classfile.constantpool.StringConstant; +import com.oracle.truffle.espresso.classfile.perf.DebugCounter; +import com.oracle.truffle.espresso.redefinition.ClassRedefinition; +import com.oracle.truffle.espresso.resolver.LinkResolver; +import com.oracle.truffle.espresso.runtime.EspressoContext; +import com.oracle.truffle.espresso.runtime.EspressoException; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; +import com.oracle.truffle.espresso.substitutions.JavaType; + +import java.util.logging.Level; + +public final class Resolution { + static final DebugCounter CLASS_RESOLVE_COUNT = DebugCounter.create("ClassConstant.resolve calls"); + static final DebugCounter FIELDREF_RESOLVE_COUNT = DebugCounter.create("FieldRef.resolve calls"); + static final DebugCounter METHODREF_RESOLVE_COUNT = DebugCounter.create("MethodRef.resolve calls"); + + public static ResolvedStringConstant resolveStringConstant(StringConstant.Index thiz, RuntimeConstantPool pool, @SuppressWarnings("unused") int thisIndex, + @SuppressWarnings("unused") ObjectKlass accessingKlass) { + return new ResolvedStringConstant(pool.getContext().getStrings().intern(thiz.getSymbol(pool))); + } + + public static Resolvable.ResolvedConstant preResolvedConstant(@JavaType(Object.class) StaticObject resolved, Tag tag) { + return new PreResolvedConstant(resolved, tag); + } + + /** + *

      5.4.3.1. Class and Interface Resolution

      + *

      + * To resolve an unresolved symbolic reference from D to a class or interface C denoted by N, + * the following steps are performed: + *

        + *
      1. The defining class loader of D is used to create a class or interface denoted by N. This + * class or interface is C. The details of the process are given in §5.3. Any exception + * that can be thrown as a result of failure of class or interface creation can thus be thrown + * as a result of failure of class and interface resolution. + *
      2. If C is an array class and its element type is a reference type, then a symbolic + * reference to the class or interface representing the element type is resolved by invoking the + * algorithm in §5.4.3.1 recursively. + *
      3. Finally, access permissions to C are checked. + *
          + *
        • If C is not accessible (§5.4.4) to D, class or interface resolution throws an + * IllegalAccessError. This condition can occur, for example, if C is a class that was + * originally declared to be public but was changed to be non-public after D was compiled. + *
        + *
      + * If steps 1 and 2 succeed but step 3 fails, C is still valid and usable. Nevertheless, + * resolution fails, and D is prohibited from accessing C. + */ + @SuppressWarnings("try") + public static ResolvedClassConstant resolveClassConstant(ClassConstant.Index thiz, RuntimeConstantPool pool, @SuppressWarnings("unused") int thisIndex, ObjectKlass accessingKlass) { + try (EspressoLanguage.DisableSingleStepping ignored = accessingKlass.getLanguage().disableStepping()) { + CLASS_RESOLVE_COUNT.inc(); + assert accessingKlass != null; + CompilerDirectives.transferToInterpreterAndInvalidate(); + Symbol klassName = thiz.getName(pool); + try { + EspressoContext context = pool.getContext(); + Symbol type = context.getTypes().fromName(klassName); + Klass klass = context.getMeta().resolveSymbolOrFail(type, accessingKlass.getDefiningClassLoader(), accessingKlass.protectionDomain()); + Klass checkedKlass = klass.getElementalType(); + if (!Klass.checkAccess(checkedKlass, accessingKlass, false)) { + Meta meta = context.getMeta(); + context.getLogger().log(Level.FINE, + "Access check of: " + checkedKlass.getType() + " from " + accessingKlass.getType() + " throws IllegalAccessError"); + StringBuilder errorMessage = new StringBuilder("failed to access class "); + errorMessage.append(checkedKlass.getExternalName()).append(" from class ").append(accessingKlass.getExternalName()); + if (context.getJavaVersion().modulesEnabled()) { + errorMessage.append(" ("); + if (accessingKlass.module() == checkedKlass.module()) { + errorMessage.append(checkedKlass.getExternalName()); + errorMessage.append(" and "); + ClassRegistry.classInModuleOfLoader(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); + errorMessage.append("; "); + ClassRegistry.classInModuleOfLoader(accessingKlass, false, errorMessage, meta); + } + errorMessage.append(")"); + } + throw meta.throwExceptionWithMessage(meta.java_lang_IllegalAccessError, errorMessage.toString()); + } + + return new ResolvedClassConstant(klass); + + } catch (EspressoException e) { + CompilerDirectives.transferToInterpreter(); + Meta meta = pool.getContext().getMeta(); + if (meta.java_lang_ClassNotFoundException.isAssignableFrom(e.getGuestException().getKlass())) { + throw meta.throwExceptionWithMessage(meta.java_lang_NoClassDefFoundError, meta.toGuestString(klassName)); + } + throw e; + } catch (VirtualMachineError e) { + // Comment from Hotspot: + // Just throw the exception and don't prevent these classes from + // being loaded for virtual machine errors like StackOverflow + // and OutOfMemoryError, etc. + // Needs clarification to section 5.4.3 of the JVM spec (see 6308271) + throw e; + } + } + } + + @SuppressWarnings("unused") + public static ResolvedClassConstant resolveClassConstant(PreResolvedClassConstant thiz, @SuppressWarnings("unused") RuntimeConstantPool pool, @SuppressWarnings("unused") int thisIndex, + @SuppressWarnings("unused") ObjectKlass accessingKlass) { + return new ResolvedClassConstant(thiz.getResolved()); + } + + public static ResolvedClassConstant resolveClassConstant(ClassConstant.WithString thiz, RuntimeConstantPool pool, @SuppressWarnings("unused") int thisIndex, ObjectKlass accessingKlass) { + CLASS_RESOLVE_COUNT.inc(); + assert accessingKlass != null; + CompilerDirectives.transferToInterpreterAndInvalidate(); + Symbol klassName = thiz.getName(pool); + try { + EspressoContext context = pool.getContext(); + Meta meta = context.getMeta(); + Klass klass = meta.resolveSymbolOrFail(context.getTypes().fromName(klassName), accessingKlass.getDefiningClassLoader(), accessingKlass.protectionDomain()); + if (!Klass.checkAccess(klass.getElementalType(), accessingKlass, false)) { + context.getLogger().log(Level.FINE, + "Access check of: " + klass.getType() + " from " + accessingKlass.getType() + " throws IllegalAccessError"); + throw meta.throwExceptionWithMessage(meta.java_lang_IllegalAccessError, meta.toGuestString(klassName)); + } + + return new ResolvedClassConstant(klass); + + } catch (VirtualMachineError e) { + // Comment from Hotspot: + // Just throw the exception and don't prevent these classes from + // being loaded for virtual machine errors like StackOverflow + // and OutOfMemoryError, etc. + // Needs clarification to section 5.4.3 of the JVM spec (see 6308271) + throw e; + } + } + + /** + *

      5.4.3.2. Field Resolution

      + * + * To resolve an unresolved symbolic reference from D to a field in a class or interface C, the + * symbolic reference to C given by the field reference must first be resolved (§5.4.3.1). + * Therefore, any exception that can be thrown as a result of failure of resolution of a class + * or interface reference can be thrown as a result of failure of field resolution. If the + * reference to C can be successfully resolved, an exception relating to the failure of + * resolution of the field reference itself can be thrown. + * + * When resolving a field reference, field resolution first attempts to look up the referenced + * field in C and its superclasses: + *
        + *
      1. If C declares a field with the name and descriptor specified by the field reference, + * field lookup succeeds. The declared field is the result of the field lookup. + *
      2. Otherwise, field lookup is applied recursively to the direct superinterfaces of the + * specified class or interface C. + *
      3. Otherwise, if C has a superclass S, field lookup is applied recursively to S. + *
      4. Otherwise, field lookup fails. + *
      + * + * Then: + *
        + *
      • If field lookup fails, field resolution throws a NoSuchFieldError. + *
      • Otherwise, if field lookup succeeds but the referenced field is not accessible + * (§5.4.4) to D, field resolution throws an IllegalAccessError. + *
      • Otherwise, let < E, L1 > be the class or interface in which the referenced field is + * actually declared and let L2 be the defining loader of D. + *
      • Given that the type of the referenced field is Tf, let T be Tf if Tf is not an array + * type, and let T be the element type (§2.4) of Tf otherwise. + *
      • The Java Virtual Machine must impose the loading constraint that TL1 = TL2 (§5.3.4). + *
      + */ + private static Field lookupField(Klass seed, Symbol name, Symbol type) { + Field f = seed.lookupDeclaredField(name, type); + if (f != null) { + return f; + } + for (Klass i : seed.getSuperInterfaces()) { + f = lookupField(i, name, type); + if (f != null) { + return f; + } + } + if (seed.getSuperKlass() != null) { + return lookupField(seed.getSuperKlass(), name, type); + } + return null; + } + + public static Resolvable.ResolvedConstant resolveFieldRefConstant(FieldRefConstant.Indexes thiz, RuntimeConstantPool pool, @SuppressWarnings("unused") int thisIndex, ObjectKlass accessingKlass) { + FIELDREF_RESOLVE_COUNT.inc(); + Klass holderKlass = getResolvedHolderKlass(thiz, pool, accessingKlass); + Symbol name = thiz.getName(pool); + Symbol type = thiz.getType(pool); + + Field field = lookupField(holderKlass, name, type); + if (field == null) { + ClassRedefinition classRedefinition = pool.getContext().getClassRedefinition(); + if (classRedefinition != null) { + // could be due to ongoing redefinition + classRedefinition.check(); + field = lookupField(holderKlass, name, type); + } + if (field == null) { + Meta meta = pool.getContext().getMeta(); + EspressoException failure = EspressoException.wrap(Meta.initExceptionWithMessage(meta.java_lang_NoSuchFieldError, name.toString()), meta); + Assumption missingFieldAssumption; + if (classRedefinition != null) { + missingFieldAssumption = classRedefinition.getMissingFieldAssumption(); + } else { + missingFieldAssumption = Assumption.ALWAYS_VALID; + } + return new MissingFieldRefConstant(failure, missingFieldAssumption); + } + } + + memberDoAccessCheck(accessingKlass, holderKlass, field, pool.getContext().getMeta()); + + field.checkLoadingConstraints(accessingKlass.getDefiningClassLoader(), field.getDeclaringKlass().getDefiningClassLoader()); + + return new ResolvedFieldRefConstant(field); + } + + public static Klass getResolvedHolderKlass(MemberRefConstant.Indexes thiz, RuntimeConstantPool pool, ObjectKlass accessingKlass) { + return pool.resolvedKlassAt(accessingKlass, thiz.getClassIndex()); + } + + @TruffleBoundary + public static void memberDoAccessCheck(ObjectKlass accessingKlass, Klass resolvedKlass, Member member, Meta meta) { + if (!memberCheckAccess(accessingKlass, resolvedKlass, member)) { + String message = "Class " + accessingKlass.getExternalName() + " cannot access method " + resolvedKlass.getExternalName() + "#" + member.getName(); + throw meta.throwExceptionWithMessage(meta.java_lang_IllegalAccessError, meta.toGuestString(message)); + } + } + + /** + *

      5.4.4. Access Control

      + * + * A field or method R is accessible to a class or interface D if and only if any of the + * following is true: + *
        + *
      • R is public. + *
      • R is protected and is declared in a class C, and D is either a subclass of C or C itself. + * Furthermore, if R is not static, then the symbolic reference to R must contain a symbolic + * reference to a class T, such that T is either a subclass of D, a superclass of D, or D + * itself. + *
      • R is either protected or has default access (that is, neither public nor protected nor + * private), and is declared by a class in the same run-time package as D. + *
      • R is private and is declared in D. + *
      + */ + static boolean memberCheckAccess(ObjectKlass accessingKlass, Klass resolvedKlass, Member member) { + if (member.isPublic()) { + return true; + } + Klass memberKlass = member.getDeclaringKlass(); + if (member instanceof Method && Name.clone.equals(member.getName()) && memberKlass.isJavaLangObject()) { + if (resolvedKlass.isArray()) { + return true; + } + } + if (member.isProtected()) { + if (!member.isStatic()) { + if (resolvedKlass.isAssignableFrom(accessingKlass) || accessingKlass.isAssignableFrom(resolvedKlass)) { + return true; + } + } else { + if (memberKlass.isAssignableFrom(accessingKlass)) { + return true; + } + } + } + if (member.isProtected() || member.isPackagePrivate()) { + if (accessingKlass.sameRuntimePackage(memberKlass)) { + return true; + } + } + if (member.isPrivate() && nestMateTest(accessingKlass, memberKlass)) { + return true; + } + // MagicAccessorImpl marks internal reflection classes that have access to everything. + if (accessingKlass.getMeta().sun_reflect_MagicAccessorImpl.isAssignableFrom(accessingKlass)) { + return true; + } + + if (accessingKlass.getHostClass() != null) { + CompilerAsserts.partialEvaluationConstant(accessingKlass); + return memberCheckAccess(accessingKlass.getHostClass(), resolvedKlass, member); + } + return false; + } + + static boolean nestMateTest(Klass k1, Klass k2) { + return k1 == k2 || k1.nest() == k2.nest(); + } + + /** + *

      5.4.3.4. Interface Method Resolution

      + * + * To resolve an unresolved symbolic reference from D to an interface method in an interface C, + * the symbolic reference to C given by the interface method reference is first resolved + * (§5.4.3.1). Therefore, any exception that can be thrown as a result of failure of + * resolution of an interface reference can be thrown as a result of failure of interface method + * resolution. If the reference to C can be successfully resolved, exceptions relating to the + * resolution of the interface method reference itself can be thrown. + * + * When resolving an interface method reference: + *
        + *
      1. If C is not an interface, interface method resolution throws an + * IncompatibleClassChangeError. + *
      2. Otherwise, if C declares a method with the name and descriptor specified by the interface + * method reference, method lookup succeeds. + *
      3. Otherwise, if the class Object declares a method with the name and descriptor specified + * by the interface method reference, which has its ACC_PUBLIC flag set and does not have its + * ACC_STATIC flag set, method lookup succeeds. + *
      4. Otherwise, if the maximally-specific superinterface methods (§5.4.3.3) of C for the + * name and descriptor specified by the method reference include exactly one method that does + * not have its ACC_ABSTRACT flag set, then this method is chosen and method lookup succeeds. + *
      5. Otherwise, if any superinterface of C declares a method with the name and descriptor + * specified by the method reference that has neither its ACC_PRIVATE flag nor its ACC_STATIC + * flag set, one of these is arbitrarily chosen and method lookup succeeds. + *
      6. Otherwise, method lookup fails. + *
      + * + * The result of interface method resolution is determined by whether method lookup succeeds or + * fails: + *
        + *
      • If method lookup fails, interface method resolution throws a NoSuchMethodError. + *
      • If method lookup succeeds and the referenced method is not accessible (§5.4.4) to + * D, interface method resolution throws an IllegalAccessError. + *
      • Otherwise, let < E, L1 > be the class or interface in which the referenced interface + * method m is actually declared, and let L2 be the defining loader of D. + *
      • Given that the return type of m is Tr, and that the formal parameter types of m are Tf1, + * ..., Tfn, then: + *
      • If Tr is not an array type, let T0 be Tr; otherwise, let T0 be the element type + * (§2.4) of Tr. + *
      • For i = 1 to n: If Tfi is not an array type, let Ti be Tfi; otherwise, let Ti be the + * element type (§2.4) of Tfi. + *
      • The Java Virtual Machine must impose the loading constraints TiL1 = TiL2 for i = 0 to n + * (§5.3.4). + *
      + * The clause about accessibility is necessary because interface method resolution may pick a + * private method of interface C. (Prior to Java SE 8, the result of interface method resolution + * could be a non-public method of class Object or a static method of class Object; such results + * were not consistent with the inheritance model of the Java programming language, and are + * disallowed in Java SE 8 and above.) + */ + public static Resolvable.ResolvedConstant resolveInterfaceMethodRefConstant(InterfaceMethodRefConstant.Indexes thiz, RuntimeConstantPool pool, @SuppressWarnings("unused") int thisIndex, + ObjectKlass accessingKlass) { + METHODREF_RESOLVE_COUNT.inc(); + + Klass holderInterface = getResolvedHolderKlass(thiz, pool, accessingKlass); + Symbol name = thiz.getName(pool); + Symbol signature = thiz.getSignature(pool); + + Method method = LinkResolver.resolveSymbol(pool.getContext().getMeta(), accessingKlass, name, signature, holderInterface, true, true, true); + + return new ResolvedInterfaceMethodRefConstant(method); + } + + /** + *

      5.4.3.3. Method Resolution

      + * + * To resolve an unresolved symbolic reference from D to a method in a class C, the symbolic + * reference to C given by the method reference is first resolved (§5.4.3.1). Therefore, + * any exception that can be thrown as a result of failure of resolution of a class reference + * can be thrown as a result of failure of method resolution. If the reference to C can be + * successfully resolved, exceptions relating to the resolution of the method reference itself + * can be thrown. + * + * When resolving a method reference: + *
        + * + *
      1. If C is an interface, method resolution throws an IncompatibleClassChangeError. + * + *
      2. Otherwise, method resolution attempts to locate the referenced method in C and its + * superclasses: + *
          + * + *
        • If C declares exactly one method with the name specified by the method reference, and the + * declaration is a signature polymorphic method (§2.9), then method lookup succeeds. All + * the class names mentioned in the descriptor are resolved (§5.4.3.1). + * + *
        • The resolved method is the signature polymorphic method declaration. It is not necessary + * for C to declare a method with the descriptor specified by the method reference. + * + *
        • Otherwise, if C declares a method with the name and descriptor specified by the method + * reference, method lookup succeeds. + * + *
        • Otherwise, if C has a superclass, step 2 of method resolution is recursively invoked on + * the direct superclass of C. + *
        + * + *
      3. Otherwise, method resolution attempts to locate the referenced method in the + * superinterfaces of the specified class C: + *
          + *
        • If the maximally-specific superinterface methods of C for the name and descriptor + * specified by the method reference include exactly one method that does not have its + * ACC_ABSTRACT flag set, then this method is chosen and method lookup succeeds. + * + *
        • Otherwise, if any superinterface of C declares a method with the name and descriptor + * specified by the method reference that has neither its ACC_PRIVATE flag nor its ACC_STATIC + * flag set, one of these is arbitrarily chosen and method lookup succeeds. + * + *
        • Otherwise, method lookup fails. + *
        + *
      + * + * A maximally-specific superinterface method of a class or interface C for a particular method + * name and descriptor is any method for which all of the following are true: + * + *
        + *
      • The method is declared in a superinterface (direct or indirect) of C. + * + *
      • The method is declared with the specified name and descriptor. + * + *
      • The method has neither its ACC_PRIVATE flag nor its ACC_STATIC flag set. + * + *
      • Where the method is declared in interface I, there exists no other maximally-specific + * superinterface method of C with the specified name and descriptor that is declared in a + * subinterface of I. + *
      + * The result of method resolution is determined by whether method lookup succeeds or fails: + *
        + *
      • If method lookup fails, method resolution throws a NoSuchMethodError. + * + *
      • Otherwise, if method lookup succeeds and the referenced method is not accessible + * (§5.4.4) to D, method resolution throws an IllegalAccessError. + * + * Otherwise, let < E, L1 > be the class or interface in which the referenced method m is + * actually declared, and let L2 be the defining loader of D. + * + * Given that the return type of m is Tr, and that the formal parameter types of m are Tf1, ..., + * Tfn, then: + * + * If Tr is not an array type, let T0 be Tr; otherwise, let T0 be the element type (§2.4) + * of Tr. + * + * For i = 1 to n: If Tfi is not an array type, let Ti be Tfi; otherwise, let Ti be the element + * type (§2.4) of Tfi. + * + * The Java Virtual Machine must impose the loading constraints TiL1 = TiL2 for i = 0 to n + * (§5.3.4). + *
      + * When resolution searches for a method in the class's superinterfaces, the best outcome is to + * identify a maximally-specific non-abstract method. It is possible that this method will be + * chosen by method selection, so it is desirable to add class loader constraints for it. + * + * Otherwise, the result is nondeterministic. This is not new: The Java® Virtual Machine + * Specification has never identified exactly which method is chosen, and how "ties" should be + * broken. Prior to Java SE 8, this was mostly an unobservable distinction. However, beginning + * with Java SE 8, the set of interface methods is more heterogenous, so care must be taken to + * avoid problems with nondeterministic behavior. Thus: + * + *
        + *
      • Superinterface methods that are private and static are ignored by resolution. This is + * consistent with the Java programming language, where such interface methods are not + * inherited. + * + *
      • Any behavior controlled by the resolved method should not depend on whether the method is + * abstract or not. + *
      + * Note that if the result of resolution is an abstract method, the referenced class C may be + * non-abstract. Requiring C to be abstract would conflict with the nondeterministic choice of + * superinterface methods. Instead, resolution assumes that the run time class of the invoked + * object has a concrete implementation of the method. + */ + public static Resolvable.ResolvedConstant resolveClassMethodRefConstant(ClassMethodRefConstant.Indexes thiz, RuntimeConstantPool pool, @SuppressWarnings("unused") int thisIndex, + ObjectKlass accessingKlass) { + METHODREF_RESOLVE_COUNT.inc(); + EspressoContext context = pool.getContext(); + Meta meta = context.getMeta(); + + Klass holderKlass = getResolvedHolderKlass(thiz, pool, accessingKlass); + Symbol name = thiz.getName(pool); + Symbol signature = thiz.getSignature(pool); + + Method method = LinkResolver.resolveSymbol(meta, accessingKlass, name, signature, holderKlass, false, true, true); + + if (method.isInvokeIntrinsic()) { + MHInvokeGenericNode.MethodHandleInvoker invoker = MHInvokeGenericNode.linkMethod(meta.getLanguage(), meta, accessingKlass, method, name, signature); + return new ResolvedWithInvokerClassMethodRefConstant(method, invoker); + } + + return new ResolvedClassMethodRefConstant(method); + } + + static StaticObject signatureToMethodType(Symbol[] signature, ObjectKlass accessingKlass, boolean failWithBME, Meta meta) { + Symbol rt = Signatures.returnType(signature); + int pcount = Signatures.parameterCount(signature); + + StaticObject[] ptypes = new StaticObject[pcount]; + StaticObject rtype; + try { + for (int i = 0; i < pcount; i++) { + Symbol paramType = Signatures.parameterType(signature, i); + ptypes[i] = meta.resolveSymbolAndAccessCheck(paramType, accessingKlass).mirror(); + } + } catch (EspressoException e) { + if (meta.java_lang_ClassNotFoundException.isAssignableFrom(e.getGuestException().getKlass())) { + throw meta.throwExceptionWithMessage(meta.java_lang_NoClassDefFoundError, e.getGuestMessage()); + } + throw e; + } + try { + rtype = meta.resolveSymbolAndAccessCheck(rt, accessingKlass).mirror(); + } catch (EspressoException e) { + EspressoException rethrow = e; + if (meta.java_lang_ClassNotFoundException.isAssignableFrom(e.getGuestException().getKlass())) { + rethrow = EspressoException.wrap(Meta.initExceptionWithMessage(meta.java_lang_NoClassDefFoundError, e.getGuestMessage()), meta); + } + if (failWithBME) { + rethrow = EspressoException.wrap(Meta.initExceptionWithCause(meta.java_lang_BootstrapMethodError, rethrow.getGuestException()), meta); + } + throw rethrow; + } + + return (StaticObject) meta.java_lang_invoke_MethodHandleNatives_findMethodHandleType.invokeDirectStatic(rtype, StaticObject.createArray(meta.java_lang_Class_array, ptypes, meta.getContext())); + } + + public static ResolvedMethodTypeConstant resolveMethodTypeConstant(MethodTypeConstant.Index thiz, RuntimeConstantPool pool, @SuppressWarnings("unused") int thisIndex, ObjectKlass accessingKlass) { + Symbol sig = thiz.getSignature(pool); + Meta meta = accessingKlass.getContext().getMeta(); + return new ResolvedMethodTypeConstant(signatureToMethodType(meta.getSignatures().parsed(sig), accessingKlass, false, meta)); + } + + public static Resolvable.ResolvedConstant resolveInvokeDynamicConstant(InvokeDynamicConstant.Indexes thiz, RuntimeConstantPool pool, @SuppressWarnings("unused") int thisIndex, + ObjectKlass accessingKlass) { + CompilerAsserts.neverPartOfCompilation(); + BootstrapMethodsAttribute bms = (BootstrapMethodsAttribute) accessingKlass.getAttribute(BootstrapMethodsAttribute.NAME); + BootstrapMethodsAttribute.Entry bsEntry = bms.at(thiz.getBootstrapMethodAttrIndex()); + + Meta meta = accessingKlass.getMeta(); + Symbol invokeSignature = thiz.getSignature(pool); + Symbol[] parsedInvokeSignature = meta.getSignatures().parsed(invokeSignature); + return new ResolvedInvokeDynamicConstant(bsEntry, parsedInvokeSignature, thiz.getName(pool)); + } + + private static ResolvedDynamicConstant makeResolved(Klass type, StaticObject result) { + switch (type.getJavaKind()) { + case Boolean: + case Byte: + case Short: + case Char: { + int value = (int) MHLinkToNode.rebasic(type.getMeta().unboxGuest(result), type.getJavaKind()); + return new ResolvedIntDynamicConstant(value); + } + case Int: { + int value = type.getMeta().unboxInteger(result); + return new ResolvedIntDynamicConstant(value); + } + case Float: { + float value = type.getMeta().unboxFloat(result); + return new ResolvedFloatDynamicConstant(value); + } + case Long: { + long value = type.getMeta().unboxLong(result); + return new ResolvedLongDynamicConstant(value); + } + case Double: { + double value = type.getMeta().unboxDouble(result); + return new ResolvedDoubleDynamicConstant(value); + } + case Object: + return new ResolvedObjectDynamicConstant(result); + } + throw EspressoError.shouldNotReachHere(); + } + + public static Resolvable.ResolvedConstant resolveDynamicConstant(DynamicConstant.Indexes thiz, RuntimeConstantPool pool, @SuppressWarnings("unused") int thisIndex, ObjectKlass accessingKlass) { + Meta meta = accessingKlass.getMeta(); + + // Condy constant resolving. + BootstrapMethodsAttribute bms = (BootstrapMethodsAttribute) accessingKlass.getAttribute(BootstrapMethodsAttribute.NAME); + + assert (bms != null); + // TODO(garcia) cache bootstrap method resolution + // Bootstrap method resolution + try { + BootstrapMethodsAttribute.Entry bsEntry = bms.at(thiz.getBootstrapMethodAttrIndex()); + + StaticObject bootstrapmethodMethodHandle = pool.getMethodHandle(bsEntry, accessingKlass); + StaticObject[] args = pool.getStaticArguments(bsEntry, accessingKlass); + + StaticObject fieldName = meta.toGuestString(thiz.getName(pool)); + Klass fieldType = meta.resolveSymbolOrFail(thiz.getTypeSymbol(pool), + accessingKlass.getDefiningClassLoader(), + accessingKlass.protectionDomain()); + + Object result = null; + if (!meta.getJavaVersion().java19OrLater()) { + result = meta.java_lang_invoke_MethodHandleNatives_linkDynamicConstant.invokeDirectStatic( + accessingKlass.mirror(), + thisIndex, + bootstrapmethodMethodHandle, + fieldName, fieldType.mirror(), + StaticObject.wrap(args, meta)); + } else { + result = meta.java_lang_invoke_MethodHandleNatives_linkDynamicConstant.invokeDirectStatic( + accessingKlass.mirror(), + bootstrapmethodMethodHandle, + fieldName, fieldType.mirror(), + StaticObject.wrap(args, meta)); + } + try { + return makeResolved(fieldType, (StaticObject) result); + } catch (ClassCastException | NullPointerException e) { + throw meta.throwException(meta.java_lang_BootstrapMethodError); + } catch (EspressoException e) { + if (meta.java_lang_NullPointerException.isAssignableFrom(e.getGuestException().getKlass()) || + meta.java_lang_ClassCastException.isAssignableFrom(e.getGuestException().getKlass())) { + throw meta.throwExceptionWithCause(meta.java_lang_BootstrapMethodError, e.getGuestException()); + } + throw e; + } + } catch (EspressoException e) { + return new ResolvedFailDynamicConstant(e); + } + } + + public static Resolvable.ResolvedConstant resolveMethodHandleConstant(MethodHandleConstant.Index thiz, RuntimeConstantPool pool, @SuppressWarnings("unused") int thisIndex, + ObjectKlass accessingKlass) { + Meta meta = pool.getContext().getMeta(); + if (meta.getLanguage().getSpecComplianceMode() == EspressoOptions.SpecComplianceMode.STRICT || meta.getJavaVersion().java9OrLater()) { + return specCompliantResolution(thiz, pool, accessingKlass, meta); + } else { + return hotspotResolutionBehavior(thiz, pool, accessingKlass, meta); + } + } + + private static Resolvable.ResolvedConstant specCompliantResolution(MethodHandleConstant.Index thiz, RuntimeConstantPool pool, ObjectKlass accessingKlass, Meta meta) { + StaticObject mtype; + Klass mklass; + Symbol refName; + + Tag refTag = pool.tagAt(thiz.getRefIndex()); + if (refTag == Tag.METHOD_REF || refTag == Tag.INTERFACE_METHOD_REF) { + Method target = pool.resolvedMethodAt(accessingKlass, thiz.getRefIndex()); + Symbol[] parsed = target.getParsedSignature(); + + mtype = signatureToMethodType(parsed, accessingKlass, false, meta); + MethodRefConstant ref = pool.methodAt(thiz.getRefIndex()); + /* + * we should use the klass from the method ref here rather than the declaring klass of + * the target this is because the resolved target might come from a default method and + * have an interface as declaring klass however if the refKind is invokeVirtual, it + * would be illegal to use the interface type + */ + mklass = pool.resolvedKlassAt(accessingKlass, ((MemberRefConstant.Indexes) ref).getClassIndex()); + refName = target.getName(); + } else { + assert refTag == Tag.FIELD_REF; + Field field = pool.resolvedFieldAt(accessingKlass, thiz.getRefIndex()); + mtype = meta.resolveSymbolAndAccessCheck(field.getType(), accessingKlass).mirror(); + mklass = field.getDeclaringKlass(); + refName = field.getName(); + } + + return linkMethodHandleConstant(thiz, accessingKlass, meta, mtype, mklass, refName); + } + + /** + * Resolves a method handle without resolving the method reference, which is not the behavior + * described in the specs {5.4.3.5. Method Type and Method Handle Resolution } + *

      + * see {@code JDK-8188145} + */ + private static Resolvable.ResolvedConstant hotspotResolutionBehavior(MethodHandleConstant.Index thiz, RuntimeConstantPool pool, ObjectKlass accessingKlass, Meta meta) { + StaticObject mtype; + Klass mklass; + Symbol refName; + + Tag refTag = pool.tagAt(thiz.getRefIndex()); + if (refTag == Tag.METHOD_REF || refTag == Tag.INTERFACE_METHOD_REF) { + MethodRefConstant ref = pool.methodAt(thiz.getRefIndex()); + Symbol signature = ref.getSignature(pool); + Symbol[] parsed = meta.getSignatures().parsed(signature); + + mtype = signatureToMethodType(parsed, accessingKlass, false, meta); + mklass = pool.resolvedKlassAt(accessingKlass, ((MemberRefConstant.Indexes) ref).getClassIndex()); + refName = ref.getName(pool); + } else { + assert refTag == Tag.FIELD_REF; + assert pool.fieldAt(thiz.getRefIndex()) instanceof FieldRefConstant.Indexes; + FieldRefConstant.Indexes ref = (FieldRefConstant.Indexes) pool.fieldAt(thiz.getRefIndex()); + + Symbol type = ref.getType(pool); + mtype = meta.resolveSymbolAndAccessCheck(type, accessingKlass).mirror(); + mklass = getResolvedHolderKlass(ref, pool, accessingKlass); + refName = ref.getName(pool); + } + + return linkMethodHandleConstant(thiz, accessingKlass, meta, mtype, mklass, refName); + } + + private static Resolvable.ResolvedConstant linkMethodHandleConstant(MethodHandleConstant.Index thiz, Klass accessingKlass, Meta meta, StaticObject mtype, Klass mklass, Symbol refName) { + StaticObject mname = meta.toGuestString(refName); + return new ResolvedMethodHandleConstant((StaticObject) meta.java_lang_invoke_MethodHandleNatives_linkMethodHandleConstant.invokeDirectStatic( + accessingKlass.mirror(), thiz.getRefKind(), + mklass.mirror(), mname, mtype)); + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedClassConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedClassConstant.java new file mode 100644 index 000000000000..a56ce37b0505 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedClassConstant.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.impl.Klass; +import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; + +import java.util.Objects; + +public final class ResolvedClassConstant implements ClassConstant, Resolvable.ResolvedConstant { + private final Klass resolved; + + public ResolvedClassConstant(Klass resolved) { + this.resolved = Objects.requireNonNull(resolved); + } + + @Override + public Symbol getName(ConstantPool pool) { + return resolved.getName(); + } + + @Override + public Klass value() { + return resolved; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedClassMethodRefConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedClassMethodRefConstant.java new file mode 100644 index 000000000000..db75a45ab3bc --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedClassMethodRefConstant.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.constantpool.ClassMethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; + +import java.util.Objects; + +public class ResolvedClassMethodRefConstant implements ClassMethodRefConstant, Resolvable.ResolvedConstant { + private final Method resolved; + + ResolvedClassMethodRefConstant(Method resolved) { + this.resolved = Objects.requireNonNull(resolved); + } + + @Override + public final Method value() { + return resolved; + } + + @Override + public final Symbol getHolderKlassName(ConstantPool pool) { + throw EspressoError.shouldNotReachHere("Method already resolved"); + } + + @Override + public final Symbol getName(ConstantPool pool) { + return resolved.getName(); + } + + @Override + public final Symbol getDescriptor(ConstantPool pool) { + return resolved.getRawSignature(); + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedDoubleDynamicConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedDoubleDynamicConstant.java new file mode 100644 index 000000000000..0dcfcd44736d --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedDoubleDynamicConstant.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.nodes.BytecodeNode; +import com.oracle.truffle.espresso.nodes.EspressoFrame; + +public final class ResolvedDoubleDynamicConstant implements ResolvedDynamicConstant { + final double resolved; + + public ResolvedDoubleDynamicConstant(double resolved) { + this.resolved = resolved; + } + + @Override + public void putResolved(VirtualFrame frame, int top, BytecodeNode node) { + EspressoFrame.putDouble(frame, top, resolved); + } + + @Override + public Object value() { + return resolved; + } + + @Override + public String toString(ConstantPool pool) { + return "ResolvedDynamicConstant(" + resolved + ")"; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedDynamicConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedDynamicConstant.java new file mode 100644 index 000000000000..1746eda86472 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedDynamicConstant.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.meta.Meta; +import com.oracle.truffle.espresso.nodes.BytecodeNode; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.constantpool.DynamicConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; + +public interface ResolvedDynamicConstant extends DynamicConstant, Resolvable.ResolvedConstant { + void putResolved(VirtualFrame frame, int top, BytecodeNode node); + + @Override + default Symbol getTypeSymbol(ConstantPool pool) { + throw EspressoError.shouldNotReachHere("Getting type symbol of a resolved dynamic constant"); + } + + default StaticObject guestBoxedValue(Meta meta) { + Object value = value(); + if (value instanceof StaticObject) { + return (StaticObject) value; + } + return Meta.box(meta, value); + } + + default void checkFail() { + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedFailDynamicConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedFailDynamicConstant.java new file mode 100644 index 000000000000..0642254f4555 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedFailDynamicConstant.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.nodes.BytecodeNode; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.runtime.EspressoException; + +public final class ResolvedFailDynamicConstant implements ResolvedDynamicConstant { + final EspressoException failure; + + public ResolvedFailDynamicConstant(EspressoException failure) { + this.failure = failure; + } + + @Override + public void checkFail() { + throw failure; + } + + @Override + public void putResolved(VirtualFrame frame, int top, BytecodeNode node) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("Failure should have arose earlier."); + } + + @Override + public Object value() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("Failure should have arose earlier."); + } + + @Override + public String toString(ConstantPool pool) { + return "ResolvedDynamicConstant(" + failure + ")"; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedFieldRefConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedFieldRefConstant.java new file mode 100644 index 000000000000..bf7894a8ce86 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedFieldRefConstant.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.impl.Field; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.constantpool.FieldRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; + +import java.util.Objects; + +public final class ResolvedFieldRefConstant implements FieldRefConstant, Resolvable.ResolvedConstant { + private final Field resolved; + + ResolvedFieldRefConstant(Field resolvedField) { + Objects.requireNonNull(resolvedField); + this.resolved = resolvedField; + } + + @Override + public Symbol getType(ConstantPool pool) { + return resolved.getType(); + } + + @Override + public Field value() { + return resolved; + } + + @Override + public Symbol getHolderKlassName(ConstantPool pool) { + throw EspressoError.shouldNotReachHere("Field already resolved"); + } + + @Override + public Symbol getName(ConstantPool pool) { + return resolved.getName(); + } + + @Override + public Symbol getDescriptor(ConstantPool pool) { + return getType(pool); + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedFloatDynamicConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedFloatDynamicConstant.java new file mode 100644 index 000000000000..ebd4d9dc4e9f --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedFloatDynamicConstant.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.nodes.BytecodeNode; +import com.oracle.truffle.espresso.nodes.EspressoFrame; + +public final class ResolvedFloatDynamicConstant implements ResolvedDynamicConstant { + final float resolved; + + public ResolvedFloatDynamicConstant(float resolved) { + this.resolved = resolved; + } + + @Override + public void putResolved(VirtualFrame frame, int top, BytecodeNode node) { + EspressoFrame.putFloat(frame, top, resolved); + } + + @Override + public Object value() { + return resolved; + } + + @Override + public String toString(ConstantPool pool) { + return "ResolvedDynamicConstant(" + resolved + ")"; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedIntDynamicConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedIntDynamicConstant.java new file mode 100644 index 000000000000..f5612d4c79e3 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedIntDynamicConstant.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.nodes.BytecodeNode; +import com.oracle.truffle.espresso.nodes.EspressoFrame; + +public final class ResolvedIntDynamicConstant implements ResolvedDynamicConstant { + final int resolved; + + public ResolvedIntDynamicConstant(int resolved) { + this.resolved = resolved; + } + + @Override + public void putResolved(VirtualFrame frame, int top, BytecodeNode node) { + EspressoFrame.putInt(frame, top, resolved); + } + + @Override + public Object value() { + return resolved; + } + + @Override + public String toString(ConstantPool pool) { + return "ResolvedDynamicConstant(" + resolved + ")"; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedInterfaceMethodRefConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedInterfaceMethodRefConstant.java new file mode 100644 index 000000000000..0e3be2b4e600 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedInterfaceMethodRefConstant.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.constantpool.InterfaceMethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; + +import java.util.Objects; + +public final class ResolvedInterfaceMethodRefConstant implements InterfaceMethodRefConstant, Resolvable.ResolvedConstant { + private final Method resolved; + + ResolvedInterfaceMethodRefConstant(Method resolved) { + this.resolved = Objects.requireNonNull(resolved); + } + + @Override + public Method value() { + return resolved; + } + + @Override + public Symbol getHolderKlassName(ConstantPool pool) { + // return resolved.getDeclaringKlass().getName(); + throw EspressoError.shouldNotReachHere("Method already resolved"); + } + + @Override + public Symbol getName(ConstantPool pool) { + return resolved.getName(); + } + + @Override + public Symbol getDescriptor(ConstantPool pool) { + return resolved.getRawSignature(); + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedInvokeDynamicConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedInvokeDynamicConstant.java new file mode 100644 index 000000000000..9e195fc89fd7 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedInvokeDynamicConstant.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.impl.ObjectKlass; +import com.oracle.truffle.espresso.meta.Meta; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.attributes.BootstrapMethodsAttribute; +import com.oracle.truffle.espresso.classfile.constantpool.NameAndTypeConstant; +import com.oracle.truffle.espresso.runtime.EspressoException; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; + +import java.util.Arrays; + +public final class ResolvedInvokeDynamicConstant implements LinkableInvokeDynamicConstant { + private final BootstrapMethodsAttribute.Entry bootstrapMethod; + private final Symbol[] parsedInvokeSignature; + private final Symbol nameSymbol; + private volatile CallSiteLink[] callSiteLinks; + + public ResolvedInvokeDynamicConstant(BootstrapMethodsAttribute.Entry bootstrapMethod, Symbol[] parsedInvokeSignature, Symbol name) { + this.bootstrapMethod = bootstrapMethod; + this.parsedInvokeSignature = parsedInvokeSignature; + this.nameSymbol = name; + } + + @Override + public Object value() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("Use indy.link() rather than Resolved.value()"); + } + + @Override + public boolean isResolved() { + return true; + } + + /** + * The call site linking operation must be executed once per {@code invokedynamic} instruction, + * rather than once per {@code invokedynamic_constant}. + *

      + * Furthermore, a previously failed call site linking from the constant pool must immediately + * fail again on subsequent linking operations, independently of the invokedynamic instruction + * involved. + *

      + * For example: + * + *

      +     * method1:
      +     *     0: invokedynamic #0 // calls MHN.linkCallSite successfully
      +     *     4: invokedynamic #0 // Also calls MHM.linkCallSite, resulting in a *different* CallSite
      +     *
      +     * method2:
      +     *     0: invokedynamic #1 // Fails during MHN.linkCallSite upcall
      +     *     4: invokedynamic #1 // Immediately fails without calling MHN.linkCallSite
      +     * 
      + * + * @see RuntimeConstantPool#linkInvokeDynamic(ObjectKlass, int, int, + * com.oracle.truffle.espresso.impl.Method) + */ + @Override + public CallSiteLink link(RuntimeConstantPool pool, ObjectKlass accessingKlass, int thisIndex, Method method, int bci) { + int existingIndex = findCallSiteLinkIndex(method, bci); + if (existingIndex >= 0) { + return getCallSiteLink(existingIndex); + } + // The call site linking must not happen under the lock, it is racy + // However insertion should be done under a lock + // see JVMS sect. 5.4.3.6 & ConstantPoolCache::set_dynamic_call + CallSiteLink newLink = createCallSiteLink(pool, accessingKlass, thisIndex, method, bci); + synchronized (this) { + CallSiteLink[] existingLinks = callSiteLinks; + if (existingLinks == null) { + CallSiteLink[] newLinks = new CallSiteLink[1]; + newLinks[0] = newLink; + callSiteLinks = newLinks; + return newLink; + } else { + int i = 0; + for (; i < existingLinks.length; i++) { + CallSiteLink link = existingLinks[i]; + if (link == null) { + existingLinks[i] = newLink; + return existingLinks[i]; + } + if (link.matchesCallSite(method, bci)) { + return link; + } + } + // we didn't find an existing link nor an available slot + // the array growth is limited by the max number of possible bcis for a method + // (which is a power of 2). + CallSiteLink[] newLinks = Arrays.copyOf(existingLinks, existingLinks.length * 2); + newLinks[i] = newLink; + callSiteLinks = newLinks; + return newLink; + } + } + } + + private CallSiteLink createCallSiteLink(RuntimeConstantPool pool, ObjectKlass accessingKlass, int thisIndex, Method method, int bci) { + // Per-callsite linking + CompilerAsserts.neverPartOfCompilation(); + Meta meta = accessingKlass.getMeta(); + try { + StaticObject bootstrapmethodMethodHandle = pool.getMethodHandle(bootstrapMethod, accessingKlass); + StaticObject[] args = pool.getStaticArguments(bootstrapMethod, accessingKlass); + + StaticObject name = meta.toGuestString(nameSymbol); + StaticObject methodType = Resolution.signatureToMethodType(parsedInvokeSignature, accessingKlass, meta.getContext().getJavaVersion().java8OrEarlier(), meta); + /* + * the 4 objects resolved above are not actually call-site specific. We don't cache them + * to minimize footprint since most indy constant are only used by one call-site + */ + + StaticObject appendix = StaticObject.createArray(meta.java_lang_Object_array, new StaticObject[1], meta.getContext()); + StaticObject memberName; + if (meta.getJavaVersion().varHandlesEnabled() && !meta.getJavaVersion().java19OrLater()) { + memberName = (StaticObject) meta.java_lang_invoke_MethodHandleNatives_linkCallSite.invokeDirectStatic( + accessingKlass.mirror(), + thisIndex, + bootstrapmethodMethodHandle, + name, methodType, + StaticObject.createArray(meta.java_lang_Object_array, args.clone(), meta.getContext()), + appendix); + } else { + memberName = (StaticObject) meta.java_lang_invoke_MethodHandleNatives_linkCallSite.invokeDirectStatic( + accessingKlass.mirror(), + bootstrapmethodMethodHandle, + name, methodType, + StaticObject.createArray(meta.java_lang_Object_array, args.clone(), meta.getContext()), + appendix); + } + StaticObject unboxedAppendix = appendix.get(meta.getLanguage(), 0); + + return new CallSiteLink(method, bci, memberName, unboxedAppendix, parsedInvokeSignature); + } catch (EspressoException e) { + throw new CallSiteLinkingFailure(e); + } + } + + public int findCallSiteLinkIndex(Method method, int bci) { + CallSiteLink[] existingLinks = callSiteLinks; + if (existingLinks == null) { + return -1; + } + for (int i = 0; i < existingLinks.length; i++) { + CallSiteLink link = existingLinks[i]; + if (link == null) { + break; + } + if (link.matchesCallSite(method, bci)) { + return i; + } + } + return -1; + } + + public CallSiteLink getCallSiteLink(int index) { + return callSiteLinks[index]; + } + + @Override + public int getBootstrapMethodAttrIndex() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("String already resolved"); + } + + @Override + public Symbol getName(ConstantPool pool) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("String already resolved"); + } + + @Override + public Symbol getSignature(ConstantPool pool) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("String already resolved"); + } + + @Override + public NameAndTypeConstant getNameAndType(ConstantPool pool) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere("String already resolved"); + } + + @Override + public Symbol[] getParsedSignature() { + return parsedInvokeSignature; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedLongDynamicConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedLongDynamicConstant.java new file mode 100644 index 000000000000..f2936d56f669 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedLongDynamicConstant.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.nodes.BytecodeNode; +import com.oracle.truffle.espresso.nodes.EspressoFrame; + +public final class ResolvedLongDynamicConstant implements ResolvedDynamicConstant { + final long resolved; + + public ResolvedLongDynamicConstant(long resolved) { + this.resolved = resolved; + } + + @Override + public void putResolved(VirtualFrame frame, int top, BytecodeNode node) { + EspressoFrame.putLong(frame, top, resolved); + } + + @Override + public Object value() { + return resolved; + } + + @Override + public String toString(ConstantPool pool) { + return "ResolvedDynamicConstant(" + resolved + ")"; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedMethodHandleConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedMethodHandleConstant.java new file mode 100644 index 000000000000..83b59786825c --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedMethodHandleConstant.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.ConstantPool.Tag; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; +import com.oracle.truffle.espresso.substitutions.JavaType; + +import java.lang.invoke.MethodHandle; + +public final class ResolvedMethodHandleConstant implements Resolvable.ResolvedConstant { + private final @JavaType(MethodHandle.class) StaticObject payload; + + ResolvedMethodHandleConstant(StaticObject payload) { + this.payload = payload; + } + + @Override + public @JavaType(MethodHandle.class) StaticObject value() { + return payload; + } + + public Tag tag() { + return Tag.METHODHANDLE; + } + + @Override + public String toString(ConstantPool pool) { + return payload.toString(); + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedMethodTypeConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedMethodTypeConstant.java new file mode 100644 index 000000000000..82d6a26d2482 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedMethodTypeConstant.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.constantpool.MethodTypeConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; +import com.oracle.truffle.espresso.substitutions.JavaType; + +import java.lang.invoke.MethodType; + +public final class ResolvedMethodTypeConstant implements MethodTypeConstant, Resolvable.ResolvedConstant { + private final @JavaType(MethodType.class) StaticObject resolved; + + ResolvedMethodTypeConstant(@JavaType(MethodType.class) StaticObject resolved) { + this.resolved = resolved; + } + + @Override + public Symbol getSignature(ConstantPool pool) { + // TODO(peterssen): Assert valid signature. + throw EspressoError.shouldNotReachHere("Method type already resolved !"); + } + + @Override + public @JavaType(MethodType.class) StaticObject value() { + return resolved; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedObjectDynamicConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedObjectDynamicConstant.java new file mode 100644 index 000000000000..53e360576a19 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedObjectDynamicConstant.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.nodes.BytecodeNode; +import com.oracle.truffle.espresso.nodes.EspressoFrame; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; + +public final class ResolvedObjectDynamicConstant implements ResolvedDynamicConstant { + final StaticObject resolved; + + public ResolvedObjectDynamicConstant(StaticObject resolved) { + this.resolved = resolved; + } + + @Override + public void putResolved(VirtualFrame frame, int top, BytecodeNode node) { + EspressoFrame.putObject(frame, top, resolved); + } + + @Override + public Object value() { + return resolved; + } + + @Override + public String toString(ConstantPool pool) { + return "ResolvedDynamicConstant(" + resolved + ")"; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedStringConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedStringConstant.java new file mode 100644 index 000000000000..fc5522ed6223 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedStringConstant.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.ModifiedUTF8; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; +import com.oracle.truffle.espresso.classfile.constantpool.StringConstant; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; +import com.oracle.truffle.espresso.substitutions.JavaType; + +public class ResolvedStringConstant implements StringConstant, Resolvable.ResolvedConstant { + + private final @JavaType(String.class) StaticObject resolved; + + ResolvedStringConstant(@JavaType(String.class) StaticObject resolved) { + assert Type.java_lang_String == resolved.getKlass().getType(); + this.resolved = resolved; + } + + @Override + public @JavaType(String.class) StaticObject value() { + return resolved; + } + + @Override + public Symbol getSymbol(ConstantPool pool) { + throw EspressoError.shouldNotReachHere("String already resolved"); + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedWithInvokerClassMethodRefConstant.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedWithInvokerClassMethodRefConstant.java new file mode 100644 index 000000000000..76fac543f4f4 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/ResolvedWithInvokerClassMethodRefConstant.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode; + +import java.util.Objects; + +/** + * This is used for + * {@link com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics.PolySigIntrinsics#InvokeGeneric} + * polymorphic signature methods. The invoker object contains the method and appendix that should be + * used to implement the intrinsic's behaviour. This is provided by the JDK + * ({@code MethodHandleNatives.linkMethod}). + */ +public final class ResolvedWithInvokerClassMethodRefConstant extends ResolvedClassMethodRefConstant { + private final MHInvokeGenericNode.MethodHandleInvoker invoker; + + ResolvedWithInvokerClassMethodRefConstant(Method resolved, MHInvokeGenericNode.MethodHandleInvoker invoker) { + super(resolved); + this.invoker = Objects.requireNonNull(invoker); + } + + public MHInvokeGenericNode.MethodHandleInvoker invoker() { + return invoker; + } +} 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 new file mode 100644 index 000000000000..0ef687c9a5bb --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/constantpool/RuntimeConstantPool.java @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.espresso.constantpool; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.ImmutableConstantPool; +import com.oracle.truffle.espresso.classfile.ParserException; +import com.oracle.truffle.espresso.classfile.attributes.BootstrapMethodsAttribute; +import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; +import com.oracle.truffle.espresso.classfile.constantpool.ClassMethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.DynamicConstant; +import com.oracle.truffle.espresso.classfile.constantpool.FieldRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.InterfaceMethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.InvokeDynamicConstant; +import com.oracle.truffle.espresso.classfile.constantpool.MethodHandleConstant; +import com.oracle.truffle.espresso.classfile.constantpool.MethodRefConstant; +import com.oracle.truffle.espresso.classfile.constantpool.MethodTypeConstant; +import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant; +import com.oracle.truffle.espresso.classfile.constantpool.Resolvable; +import com.oracle.truffle.espresso.classfile.constantpool.StringConstant; +import com.oracle.truffle.espresso.impl.Field; +import com.oracle.truffle.espresso.impl.Klass; +import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.impl.ObjectKlass; +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.EspressoException; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; +import com.oracle.truffle.espresso.substitutions.JavaType; + +public final class RuntimeConstantPool extends ConstantPool { + + private final EspressoContext context; + private final ImmutableConstantPool immutableConstantPool; + private final StaticObject classLoader; + + @CompilationFinal(dimensions = 1) // + private final Resolvable.ResolvedConstant[] resolvedConstants; + + public RuntimeConstantPool(EspressoContext context, ImmutableConstantPool immutableConstantPool, StaticObject classLoader) { + this.context = context; + this.immutableConstantPool = immutableConstantPool; + this.resolvedConstants = new Resolvable.ResolvedConstant[immutableConstantPool.length()]; + this.classLoader = classLoader; + } + + @Override + public int length() { + return immutableConstantPool.length(); + } + + @Override + public byte[] getRawBytes() { + return immutableConstantPool.getRawBytes(); + } + + @Override + public PoolConstant at(int index, String description) { + try { + return immutableConstantPool.at(index, description); + } catch (ParserException.ClassFormatError e) { + throw classFormatError(e.getMessage()); + } + } + + private Resolvable.ResolvedConstant outOfLockResolvedAt(ObjectKlass accessingKlass, int index, String description) { + Resolvable.ResolvedConstant c = resolvedConstants[index]; + if (c == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + // double check: deopt is a heavy operation. + c = resolvedConstants[index]; + if (c == null) { + Resolvable resolvable = (Resolvable) at(index, description); + Resolvable.ResolvedConstant locallyResolved = resolve(resolvable, index, accessingKlass); + synchronized (this) { + // Triple check: non-trivial resolution + c = resolvedConstants[index]; + if (c == null) { + resolvedConstants[index] = c = locallyResolved; + } + } + } + } + return c; + } + + private Resolvable.ResolvedConstant resolvedAt(ObjectKlass accessingKlass, int index, String description) { + Resolvable.ResolvedConstant c = resolvedConstants[index]; + if (c == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + synchronized (this) { + // fence += 1; + // FIXME(peterssen): Add memory fence for array read. + c = resolvedConstants[index]; + if (c == null) { + Resolvable resolvable = (Resolvable) at(index, description); + resolvedConstants[index] = c = resolve(resolvable, index, accessingKlass); + } + } + } + return c; + } + + private Resolvable.ResolvedConstant resolvedAtNoCache(ObjectKlass accessingKlass, int index, String description) { + CompilerAsserts.neverPartOfCompilation(); + Resolvable resolvable = (Resolvable) immutableConstantPool.at(index, description); + return resolve(resolvable, index, accessingKlass); + } + + public StaticObject resolvedStringAt(int index) { + Resolvable.ResolvedConstant resolved = resolvedAt(null, index, "string"); + return (StaticObject) resolved.value(); + } + + public Klass resolvedKlassAt(ObjectKlass accessingKlass, int index) { + Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "klass"); + return (Klass) resolved.value(); + } + + public Field resolvedFieldAt(ObjectKlass accessingKlass, int index) { + Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "field"); + try { + return ((Field) resolved.value()); + } catch (NeedsFreshResolutionException e) { + // clear the constants cache and re-resolve + CompilerDirectives.transferToInterpreterAndInvalidate(); + synchronized (this) { + resolvedConstants[index] = null; + } + return resolvedFieldAt(accessingKlass, index); + } + } + + public Field resolveFieldAndUpdate(ObjectKlass accessingKlass, int index, Field field) { + CompilerAsserts.neverPartOfCompilation(); + try { + Resolvable.ResolvedConstant resolved = resolvedAtNoCache(accessingKlass, index, "field"); + // a compatible field was found, so update the entry + synchronized (this) { + resolvedConstants[index] = resolved; + } + return ((Field) resolved.value()); + } catch (EspressoException e) { + Field realField = field; + if (realField.hasCompatibleField()) { + realField = realField.getCompatibleField(); + } + // A new compatible field was not found, but we still allow + // obsolete code to use the latest known resolved field. + // To avoid a de-opt loop here, we create a compatible delegation + // field that actually uses the latest known resolved field + // underneath. + synchronized (this) { + Field delegationField = context.getClassRedefinition().createDelegationFrom(realField); + Resolvable.ResolvedConstant resolved = new ResolvedFieldRefConstant(delegationField); + resolvedConstants[index] = resolved; + return delegationField; + } + } + } + + public boolean isResolutionSuccessAt(int index) { + Resolvable.ResolvedConstant constant = resolvedConstants[index]; + return constant != null && constant.isSuccess(); + } + + public Method resolvedMethodAt(ObjectKlass accessingKlass, int index) { + Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "method"); + return (Method) resolved.value(); + } + + public MethodRefConstant resolvedMethodRefAt(ObjectKlass accessingKlass, int index) { + Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "method"); + return (MethodRefConstant) resolved; + } + + public Method resolvedMethodAtNoCache(ObjectKlass accessingKlass, int index) { + CompilerAsserts.neverPartOfCompilation(); + Resolvable.ResolvedConstant resolved = resolvedAtNoCache(accessingKlass, index, "method"); + return (Method) resolved.value(); + } + + public StaticObject resolvedMethodHandleAt(ObjectKlass accessingKlass, int index) { + Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "method handle"); + return (StaticObject) resolved.value(); + } + + public StaticObject resolvedMethodTypeAt(ObjectKlass accessingKlass, int index) { + Resolvable.ResolvedConstant resolved = resolvedAt(accessingKlass, index, "method type"); + return (StaticObject) resolved.value(); + } + + public CallSiteLink linkInvokeDynamic(ObjectKlass accessingKlass, int index, int bci, Method method) { + LinkableInvokeDynamicConstant indy = (LinkableInvokeDynamicConstant) resolvedAt(accessingKlass, index, "indy"); + try { + return indy.link(this, accessingKlass, index, method, bci); + } catch (CallSiteLinkingFailure failure) { + // On failure, shortcut subsequent linking operations. + CompilerDirectives.transferToInterpreterAndInvalidate(); + synchronized (this) { + resolvedConstants[index] = failure.failConstant(); + } + throw failure.cause; + } + } + + public ResolvedInvokeDynamicConstant peekResolvedInvokeDynamic(int index) { + return (ResolvedInvokeDynamicConstant) resolvedConstants[index]; + } + + public ResolvedDynamicConstant resolvedDynamicConstantAt(ObjectKlass accessingKlass, int index) { + ResolvedDynamicConstant dynamicConstant = (ResolvedDynamicConstant) outOfLockResolvedAt(accessingKlass, index, "dynamic constant"); + dynamicConstant.checkFail(); + return dynamicConstant; + } + + public StaticObject getClassLoader() { + return classLoader; + } + + public EspressoContext getContext() { + return context; + } + + public void setKlassAt(int index, ObjectKlass klass) { + resolvedConstants[index] = new ResolvedClassConstant(klass); + } + + @Override + public int getMajorVersion() { + return immutableConstantPool.getMajorVersion(); + } + + @Override + public int getMinorVersion() { + return immutableConstantPool.getMinorVersion(); + } + + public StaticObject getMethodHandle(BootstrapMethodsAttribute.Entry entry, ObjectKlass accessingKlass) { + return this.resolvedMethodHandleAt(accessingKlass, entry.getBootstrapMethodRef()); + } + + public StaticObject[] getStaticArguments(BootstrapMethodsAttribute.Entry entry, ObjectKlass accessingKlass) { + Meta meta = accessingKlass.getMeta(); + StaticObject[] args = new StaticObject[entry.numBootstrapArguments()]; + // @formatter:off + for (int i = 0; i < entry.numBootstrapArguments(); i++) { + PoolConstant pc = this.at(entry.argAt(i)); + switch (pc.tag()) { + case METHODHANDLE: + args[i] = this.resolvedMethodHandleAt(accessingKlass, entry.argAt(i)); + break; + case METHODTYPE: + args[i] = this.resolvedMethodTypeAt(accessingKlass, entry.argAt(i)); + break; + case DYNAMIC: + args[i] = this.resolvedDynamicConstantAt(accessingKlass, entry.argAt(i)).guestBoxedValue(meta); + break; + case CLASS: + args[i] = this.resolvedKlassAt(accessingKlass, entry.argAt(i)).mirror(); + break; + case STRING: + args[i] = this.resolvedStringAt(entry.argAt(i)); + break; + case INTEGER: + args[i] = meta.boxInteger(this.intAt(entry.argAt(i))); + break; + case LONG: + args[i] = meta.boxLong(this.longAt(entry.argAt(i))); + break; + case DOUBLE: + args[i] = meta.boxDouble(this.doubleAt(entry.argAt(i))); + break; + case FLOAT: + args[i] = meta.boxFloat(this.floatAt(entry.argAt(i))); + break; + default: + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw EspressoError.shouldNotReachHere(); + } + } + return args; + // @formatter:on + } + + Resolvable.ResolvedConstant resolve(Resolvable resolvable, int thisIndex, ObjectKlass accessingKlass) { + + switch (resolvable.tag()) { + case STRING: + if (resolvable instanceof StringConstant.Index fromIndex) { + return Resolution.resolveStringConstant(fromIndex, this, thisIndex, accessingKlass); + } + break; + case FIELD_REF: + if (resolvable instanceof FieldRefConstant.Indexes fromIndex) { + return Resolution.resolveFieldRefConstant(fromIndex, this, thisIndex, accessingKlass); + } + break; + case INTERFACE_METHOD_REF: + if (resolvable instanceof InterfaceMethodRefConstant.Indexes fromIndex) { + return Resolution.resolveInterfaceMethodRefConstant(fromIndex, this, thisIndex, accessingKlass); + } + break; + case METHOD_REF: + if (resolvable instanceof ClassMethodRefConstant.Indexes fromIndex) { + return Resolution.resolveClassMethodRefConstant(fromIndex, this, thisIndex, accessingKlass); + } + break; + case METHODTYPE: + if (resolvable instanceof MethodTypeConstant.Index fromIndex) { + return Resolution.resolveMethodTypeConstant(fromIndex, this, thisIndex, accessingKlass); + } + break; + case INVOKEDYNAMIC: + if (resolvable instanceof InvokeDynamicConstant.Indexes fromIndex) { + return Resolution.resolveInvokeDynamicConstant(fromIndex, this, thisIndex, accessingKlass); + } + break; + case DYNAMIC: + if (resolvable instanceof DynamicConstant.Indexes fromIndex) { + return Resolution.resolveDynamicConstant(fromIndex, this, thisIndex, accessingKlass); + } + break; + case METHODHANDLE: + if (resolvable instanceof MethodHandleConstant.Index fromIndex) { + return Resolution.resolveMethodHandleConstant(fromIndex, this, thisIndex, accessingKlass); + } + break; + case CLASS: + if (resolvable instanceof ClassConstant.Index fromIndex) { + return Resolution.resolveClassConstant(fromIndex, this, thisIndex, accessingKlass); + } else if (resolvable instanceof ClassConstant.WithString fromString) { + return Resolution.resolveClassConstant(fromString, this, thisIndex, accessingKlass); + } + break; + } + throw EspressoError.shouldNotReachHere("Unexpected CP entry: " + resolvable); + } + + @Override + @TruffleBoundary + public @JavaType(ClassFormatError.class) EspressoException classFormatError(String message) { + CompilerAsserts.neverPartOfCompilation(); + Meta meta = EspressoContext.get(null).getMeta(); + if (meta.java_lang_ClassFormatError == null) { + throw EspressoError.fatal("ClassFormatError during early startup: ", message); + } + throw meta.throwExceptionWithMessage(meta.java_lang_ClassFormatError, message); + } + + public void patchAt(int index, Resolvable.ResolvedConstant resolvedConstant) { + assert resolvedConstant != null; + assert resolvedConstant.value() != null; + resolvedConstants[index] = resolvedConstant; + } +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NativeAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NativeAccess.java index ec4bb738071a..45787139b9ed 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NativeAccess.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NativeAccess.java @@ -36,7 +36,7 @@ import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.espresso.EspressoOptions; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.runtime.EspressoProperties; /** diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/TruffleByteBuffer.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/TruffleByteBuffer.java index 04b5dc19934c..2326387fa9dd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/TruffleByteBuffer.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/TruffleByteBuffer.java @@ -40,7 +40,7 @@ import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.espresso.ffi.nfi.NativeUtils; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; @ExportLibrary(InteropLibrary.class) public final class TruffleByteBuffer implements TruffleObject { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFINativeAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFINativeAccess.java index 2c2c4ec82f0d..f6d0f4922069 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFINativeAccess.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NFINativeAccess.java @@ -59,7 +59,7 @@ import com.oracle.truffle.espresso.ffi.SignatureCallNode; import com.oracle.truffle.espresso.ffi.TruffleByteBuffer; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.perf.DebugCounter; +import com.oracle.truffle.espresso.classfile.perf.DebugCounter; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.substitutions.Collect; import com.oracle.truffle.espresso.vm.UnsafeAccess; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NativeUtils.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NativeUtils.java index 0c2f93d6a48c..9e2f7004becf 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NativeUtils.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/nfi/NativeUtils.java @@ -35,9 +35,9 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.espresso.ffi.Pointer; import com.oracle.truffle.espresso.ffi.RawPointer; -import com.oracle.truffle.espresso.jni.ModifiedUtf8; +import com.oracle.truffle.espresso.classfile.descriptors.ModifiedUtf8; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.vm.UnsafeAccess; import sun.misc.Unsafe; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ArrayKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ArrayKlass.java index 7ce69aa0a8ba..20b99ddad302 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ArrayKlass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ArrayKlass.java @@ -35,15 +35,15 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.ModuleTable.ModuleEntry; import com.oracle.truffle.espresso.impl.PackageTable.PackageEntry; import com.oracle.truffle.espresso.jdwp.api.MethodRef; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.substitutions.JavaType; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/BootClassRegistry.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/BootClassRegistry.java index 36fce83ce4a5..3996813e87e2 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/BootClassRegistry.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/BootClassRegistry.java @@ -27,13 +27,13 @@ import java.util.concurrent.ConcurrentHashMap; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; -import com.oracle.truffle.espresso.perf.DebugCloseable; -import com.oracle.truffle.espresso.perf.DebugCounter; -import com.oracle.truffle.espresso.perf.DebugTimer; -import com.oracle.truffle.espresso.runtime.ClasspathFile; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; +import com.oracle.truffle.espresso.classfile.perf.DebugCloseable; +import com.oracle.truffle.espresso.classfile.perf.DebugCounter; +import com.oracle.truffle.espresso.classfile.perf.DebugTimer; +import com.oracle.truffle.espresso.classfile.ClasspathFile; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.substitutions.JavaType; 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 a3f953a75901..5891397886b7 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 @@ -22,16 +22,27 @@ */ package com.oracle.truffle.espresso.impl; -import java.util.concurrent.atomic.AtomicLong; - import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.EspressoOptions; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.perf.TimerCollection; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.JavaVersion; +import com.oracle.truffle.espresso.classfile.ParsingContext; +import com.oracle.truffle.espresso.classfile.constantpool.Utf8Constant; +import com.oracle.truffle.espresso.classfile.perf.TimerCollection; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; +import java.util.logging.Level; + public class ClassLoadingEnv implements LanguageAccess { private final AtomicLong klassIdProvider = new AtomicLong(); private final AtomicLong loaderIdProvider = new AtomicLong(); @@ -39,6 +50,7 @@ public class ClassLoadingEnv implements LanguageAccess { private final EspressoLanguage language; private final TruffleLogger logger; private final TimerCollection timers; + private final ParsingContext parsingContext; @CompilationFinal private Meta meta; @@ -46,6 +58,11 @@ public ClassLoadingEnv(EspressoLanguage language, TruffleLogger logger, TimerCol this.language = language; this.logger = logger; this.timers = timers; + this.parsingContext = createParsingContext(this); + } + + public ParsingContext getParsingContext() { + return parsingContext; } @Override @@ -108,4 +125,75 @@ public long getNewLoaderId() { } return id; } + + public boolean isStrictComplianceMode() { + return getLanguage().getSpecComplianceMode() == EspressoOptions.SpecComplianceMode.STRICT; + } + + private static ParsingContext createParsingContext(ClassLoadingEnv env) { + return new ParsingContext() { + + final Logger truffleEnvLogger = new Logger() { + @Override + public void log(String message) { + env.getLogger().warning(message); + } + + @Override + public void log(Supplier messageSupplier) { + env.getLogger().warning(messageSupplier); + } + + @Override + public void log(String message, Throwable throwable) { + env.getLogger().log(Level.SEVERE, message, throwable); + } + }; + + @Override + public JavaVersion getJavaVersion() { + return env.getJavaVersion(); + } + + @Override + public boolean isStrictJavaCompliance() { + return env.getLanguage().getSpecComplianceMode() == EspressoOptions.SpecComplianceMode.STRICT; + } + + @Override + public TimerCollection getTimers() { + return env.getTimers(); + } + + @Override + public boolean isPreviewEnabled() { + return env.isPreviewEnabled(); + } + + @Override + public Logger getLogger() { + return truffleEnvLogger; + } + + @Override + public Symbol getOrCreateName(ByteSequence byteSequence) { + return env.getNames().getOrCreate(byteSequence); + } + + @Override + public Symbol getOrCreateTypeFromName(ByteSequence byteSequence) { + return env.getTypes().getOrCreate(Types.nameToType(byteSequence)); + } + + @Override + public Utf8Constant getOrCreateUtf8Constant(ByteSequence bytes) { + return env.getLanguage().getUtf8ConstantTable().getOrCreate(bytes); + } + + @Override + public long getNewKlassId() { + return env.getNewKlassId(); + } + }; + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistries.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistries.java index 8739380eb1d0..3a5727b72cdd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistries.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ClassRegistries.java @@ -34,9 +34,9 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.jdwp.api.ModuleRef; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.meta.Meta; 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 3575a1914fd0..acc6c42bc96e 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 @@ -26,20 +26,26 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.espresso.classfile.Constants; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.constantpool.Resolution; +import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.ModuleTable.ModuleEntry; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.perf.DebugCloseable; -import com.oracle.truffle.espresso.perf.DebugTimer; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.Constants; +import com.oracle.truffle.espresso.classfile.ParserKlass; +import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant; +import com.oracle.truffle.espresso.classfile.perf.DebugCloseable; +import com.oracle.truffle.espresso.classfile.perf.DebugTimer; import com.oracle.truffle.espresso.redefinition.DefineKlassListener; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.EspressoException; @@ -146,10 +152,6 @@ public int patchFlags(int classFlags) { } return flags; } - - public void initKlassID(long futureKlassID) { - this.klassID = futureKlassID; - } } private static final DebugTimer KLASS_PROBE = DebugTimer.create("klass probe"); @@ -380,6 +382,11 @@ public ObjectKlass defineKlass(EspressoContext context, Symbol typeOrNull, Symbol superKlassType = parserKlass.getSuperKlass(); ObjectKlass klass = createKlass(context, parserKlass, type, superKlassType, info); + + if (info.isAnonymousClass() && info.patches != null) { + patchAnonymousClass(klass.getConstantPool(), info.patches); + } + if (info.addedToRegistry()) { registerKlass(klass, type); } else if (info.isStrongHidden()) { @@ -388,6 +395,26 @@ public ObjectKlass defineKlass(EspressoContext context, Symbol typeOrNull, return klass; } + private static void patchAnonymousClass(RuntimeConstantPool constantPool, StaticObject[] patches) { + int maxCPIndex = Math.min(patches.length, constantPool.length()); + for (int i = 1; i < maxCPIndex; i++) { + if (patches[i] != null && StaticObject.notNull(patches[i])) { + PoolConstant poolConstant = constantPool.at(i); + ConstantPool.Tag tag = poolConstant.tag(); + if (Objects.requireNonNull(tag) == ConstantPool.Tag.STRING) { + /* + * The runtime CP entry tag may be different from the actual constant that is + * pre-resolved. Pre-resolved/patched entries may contain arbitrary guest + * objects, like classes. + */ + constantPool.patchAt(i, Resolution.preResolvedConstant(patches[i], tag)); + } else { + throw EspressoError.unimplemented("Patching anonymous class CP entry with: " + tag); + } + } + } + } + private ParserKlass parseKlass(ClassLoadingEnv env, byte[] bytes, Symbol typeOrNull, ClassDefinitionInfo info) throws EspressoClassLoadingException.SecurityException { // May throw guest ClassFormatError, NoClassDefFoundError. ParserKlass parserKlass = env.getLanguage().getLanguageCache().getOrCreateParserKlass(env, getClassLoader(), typeOrNull, bytes, info); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ConstantPoolPatcher.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ConstantPoolPatcher.java index 4e3bc44b5aa8..3a5da0cbbcaa 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ConstantPoolPatcher.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ConstantPoolPatcher.java @@ -28,15 +28,16 @@ import com.oracle.truffle.espresso.classfile.ClassfileStream; import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.ParserException; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; import com.oracle.truffle.espresso.redefinition.InnerClassRedefiner; import com.oracle.truffle.espresso.runtime.EspressoContext; public class ConstantPoolPatcher { public static void getDirectInnerAnonymousClassNames(Symbol fileSystemName, byte[] bytes, Set> innerNames, EspressoContext context) - throws ClassFormatError { + throws ParserException.ClassFormatError { ClassfileStream stream = new ClassfileStream(bytes, null); // skip magic and version - 8 bytes stream.skip(8); @@ -88,7 +89,7 @@ public static void getDirectInnerAnonymousClassNames(Symbol fileSystemName stream.readU2(); break; default: - throw new ClassFormatError(); + throw new ParserException.ClassFormatError("Unexpected tag: " + tag); } i++; } @@ -114,7 +115,7 @@ private static boolean isDecimalDigit(byte c) { return '0' <= c && c <= '9'; } - public static byte[] patchConstantPool(byte[] bytes, Map, Symbol> rules, EspressoContext context) throws ClassFormatError { + public static byte[] patchConstantPool(byte[] bytes, Map, Symbol> rules, EspressoContext context) throws ParserException.ClassFormatError { byte[] result = Arrays.copyOf(bytes, bytes.length); ClassfileStream stream = new ClassfileStream(bytes, null); @@ -194,7 +195,7 @@ public static byte[] patchConstantPool(byte[] bytes, Map, Symbol { private final HashMap, T> entries = new HashMap<>(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EnumConstantField.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EnumConstantField.java index 0dca0c6d6b23..8cdc59619c1b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EnumConstantField.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EnumConstantField.java @@ -24,8 +24,8 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; public final class EnumConstantField extends Field { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ExtensionFieldsMetadata.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ExtensionFieldsMetadata.java index f25e5f6136c4..f37d01ff29d5 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ExtensionFieldsMetadata.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ExtensionFieldsMetadata.java @@ -30,8 +30,9 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.ParserField; import com.oracle.truffle.espresso.redefinition.ClassRedefinition; final class ExtensionFieldsMetadata { 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 6fdbc03a4b87..ded453b7d10a 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 @@ -27,19 +27,20 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.espresso.jdwp.api.TagConstants; import com.oracle.truffle.espresso.classfile.Constants; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; +import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool; import com.oracle.truffle.espresso.classfile.attributes.SignatureAttribute; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.ModifiedUTF8; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.ModifiedUTF8; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.jdwp.api.FieldBreakpoint; import com.oracle.truffle.espresso.jdwp.api.FieldRef; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.attributes.Attribute; import com.oracle.truffle.espresso.runtime.EspressoException; import com.oracle.truffle.espresso.runtime.staticobject.FieldStorageObject; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; @@ -841,7 +842,7 @@ public short compareAndExchangeShort(StaticObject obj, short before, short after // region jdwp-specific @Override public final byte getTagConstant() { - return getKind().toTagConstant(); + return TagConstants.toTagConstant(getKind()); } @Override diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/GuestClassRegistry.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/GuestClassRegistry.java index 8e6778914ddc..0e4fb9fd238c 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/GuestClassRegistry.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/GuestClassRegistry.java @@ -23,12 +23,12 @@ package com.oracle.truffle.espresso.impl; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; -import com.oracle.truffle.espresso.perf.DebugCounter; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; +import com.oracle.truffle.espresso.classfile.perf.DebugCounter; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.substitutions.JavaType; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/InterfaceTables.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/InterfaceTables.java index 79cd0937991f..a1a5a590828f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/InterfaceTables.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/InterfaceTables.java @@ -27,9 +27,9 @@ import java.util.Comparator; import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.runtime.EspressoContext; 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 a85461d850f7..f0930de4f2f2 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 @@ -30,6 +30,7 @@ import java.util.Comparator; import java.util.function.IntFunction; +import com.oracle.truffle.espresso.jdwp.api.TagConstants; import org.graalvm.collections.EconomicSet; import com.oracle.truffle.api.Assumption; @@ -62,12 +63,12 @@ import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.classfile.ConstantPool; import com.oracle.truffle.espresso.classfile.Constants; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.ModuleTable.ModuleEntry; import com.oracle.truffle.espresso.impl.PackageTable.PackageEntry; import com.oracle.truffle.espresso.jdwp.api.ClassStatusConstants; @@ -77,7 +78,7 @@ import com.oracle.truffle.espresso.jdwp.api.ModuleRef; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.meta.InteropKlassesDispatch; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.meta.MetaUtil; import com.oracle.truffle.espresso.meta.ModifiersProvider; @@ -89,7 +90,7 @@ import com.oracle.truffle.espresso.nodes.interop.ToEspressoNodeFactory; import com.oracle.truffle.espresso.nodes.interop.ToPrimitive; import com.oracle.truffle.espresso.nodes.interop.ToPrimitiveFactory; -import com.oracle.truffle.espresso.perf.DebugCounter; +import com.oracle.truffle.espresso.classfile.perf.DebugCounter; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.EspressoException; import com.oracle.truffle.espresso.runtime.EspressoFunction; @@ -1793,7 +1794,7 @@ public KlassRef getSuperClass() { @Override public byte getTagConstant() { - return getJavaKind().toTagConstant(); + return TagConstants.toTagConstant(getJavaKind()); } @Override diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LanguageAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LanguageAccess.java index 9b1faa73c2d6..8ca819d04470 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LanguageAccess.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LanguageAccess.java @@ -24,10 +24,10 @@ import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.EspressoOptions; -import com.oracle.truffle.espresso.descriptors.Names; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Types; -import com.oracle.truffle.espresso.runtime.JavaVersion; +import com.oracle.truffle.espresso.classfile.descriptors.Names; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Types; +import com.oracle.truffle.espresso.classfile.JavaVersion; public interface LanguageAccess { EspressoLanguage getLanguage(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedField.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedField.java index a49c089c964e..7257f170edf1 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedField.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedField.java @@ -22,20 +22,23 @@ */ package com.oracle.truffle.espresso.impl; -import static com.oracle.truffle.espresso.classfile.Constants.FIELD_ID_OBFUSCATE; -import static com.oracle.truffle.espresso.classfile.Constants.FIELD_ID_TYPE; - import com.oracle.truffle.api.staticobject.StaticProperty; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.JavaKind; +import com.oracle.truffle.espresso.classfile.ParserField; +import com.oracle.truffle.espresso.classfile.attributes.Attribute; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; + +import static com.oracle.truffle.espresso.classfile.Constants.FIELD_ID_OBFUSCATE; +import static com.oracle.truffle.espresso.classfile.Constants.FIELD_ID_TYPE; final class LinkedField extends StaticProperty { + enum IdMode { REGULAR, WITH_TYPE, @@ -161,4 +164,23 @@ public boolean isHidden() { ParserField getParserField() { return parserField; } + + public static Class getPropertyType(ParserField parserField) { + Symbol type = parserField.getType(); + if (type.length() == 1) { + char ch = (char) type.byteAt(0); + return switch (ch) { + case 'Z' -> boolean.class; + case 'C' -> char.class; + case 'F' -> float.class; + case 'D' -> double.class; + case 'B' -> byte.class; + case 'S' -> short.class; + case 'I' -> int.class; + case 'J' -> long.class; + default -> throw EspressoError.shouldNotReachHere("unknown primitive or void type character: " + ch); + }; + } + return parserField.isHidden() ? Object.class : StaticObject.class; + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlass.java index b28c238dcb77..575eddc5d2a2 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedKlass.java @@ -22,20 +22,21 @@ */ package com.oracle.truffle.espresso.impl; -import static com.oracle.truffle.espresso.classfile.Constants.ACC_FINALIZER; - -import java.lang.reflect.Modifier; - -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.staticobject.StaticShape; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.classfile.ImmutableConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParserMethod; +import com.oracle.truffle.espresso.classfile.attributes.Attribute; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject.StaticObjectFactory; +import java.lang.reflect.Modifier; + +import static com.oracle.truffle.espresso.classfile.Constants.ACC_FINALIZER; + // Structural shareable klass (superklass in superinterfaces resolved and linked) // contains shape, field locations. // Klass shape, vtable and field locations can be computed at the structural level. @@ -59,10 +60,10 @@ public final class LinkedKlass { private final StaticShape staticShape; // instance fields declared in the corresponding LinkedKlass (includes hidden fields) - @CompilerDirectives.CompilationFinal(dimensions = 1) // + @CompilationFinal(dimensions = 1) // final LinkedField[] instanceFields; // static fields declared in the corresponding LinkedKlass (no hidden fields) - @CompilerDirectives.CompilationFinal(dimensions = 1) // + @CompilationFinal(dimensions = 1) // final LinkedField[] staticFields; final int fieldTableLength; 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 bde0330e5736..9bcd738909b7 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 @@ -33,11 +33,13 @@ import com.oracle.truffle.api.staticobject.StaticShape; import com.oracle.truffle.api.staticobject.StaticShape.Builder; import com.oracle.truffle.espresso.classfile.Constants; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.runtime.JavaVersion; -import com.oracle.truffle.espresso.runtime.JavaVersion.VersionRange; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.JavaVersion; +import com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange; +import com.oracle.truffle.espresso.classfile.ParserField; +import com.oracle.truffle.espresso.classfile.ParserKlass; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject.StaticObjectFactory; @@ -126,7 +128,7 @@ static LinkedField.IdMode getIdMode(ParserKlass parserKlass) { private static void createAndRegisterLinkedField(ParserKlass parserKlass, ParserField parserField, int slot, int index, LinkedField.IdMode idMode, Builder builder, LinkedField[] linkedFields) { LinkedField field = new LinkedField(parserField, slot, idMode); - builder.property(field, parserField.getPropertyType(), storeAsFinal(parserKlass, parserField)); + builder.property(field, LinkedField.getPropertyType(parserField), storeAsFinal(parserKlass, parserField)); linkedFields[index] = field; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedMethod.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedMethod.java index 2e64c433a84c..9ab52d175ba2 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedMethod.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LinkedMethod.java @@ -22,10 +22,11 @@ */ package com.oracle.truffle.espresso.impl; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.ParserMethod; +import com.oracle.truffle.espresso.classfile.attributes.Attribute; public final class LinkedMethod { private final ParserMethod parserMethod; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LoadingConstraints.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LoadingConstraints.java index e353d10ac364..27b95dd4cb6a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LoadingConstraints.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/LoadingConstraints.java @@ -27,12 +27,12 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.perf.DebugCloseable; -import com.oracle.truffle.espresso.perf.DebugTimer; +import com.oracle.truffle.espresso.classfile.perf.DebugCloseable; +import com.oracle.truffle.espresso.classfile.perf.DebugTimer; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Member.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Member.java index 525c22943a28..19dabdd3af5f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Member.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Member.java @@ -22,9 +22,9 @@ */ package com.oracle.truffle.espresso.impl; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Descriptor; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Descriptor; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; import com.oracle.truffle.espresso.meta.ModifiersProvider; public abstract class Member implements ModifiersProvider { 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 4c0804decfb4..47cae403eba4 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 @@ -22,12 +22,12 @@ */ package com.oracle.truffle.espresso.impl; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GETFIELD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GETSTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTFIELD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTSTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.RETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GETFIELD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GETSTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.PUTFIELD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.PUTSTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.RETURN; import static com.oracle.truffle.espresso.classfile.Constants.ACC_CALLER_SENSITIVE; import static com.oracle.truffle.espresso.classfile.Constants.ACC_DONT_INLINE; import static com.oracle.truffle.espresso.classfile.Constants.ACC_FINAL; @@ -70,22 +70,24 @@ import com.oracle.truffle.espresso.analysis.hierarchy.ClassHierarchyAssumption; import com.oracle.truffle.espresso.analysis.hierarchy.ClassHierarchyOracle; import com.oracle.truffle.espresso.analysis.liveness.LivenessAnalysis; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.bytecode.BytecodePrinter; +import com.oracle.truffle.espresso.classfile.ParserException; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.classfile.ConstantPool; import com.oracle.truffle.espresso.classfile.Constants; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; +import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool; import com.oracle.truffle.espresso.classfile.attributes.CodeAttribute; import com.oracle.truffle.espresso.classfile.attributes.ExceptionsAttribute; import com.oracle.truffle.espresso.classfile.attributes.LineNumberTableAttribute; import com.oracle.truffle.espresso.classfile.attributes.LocalVariableTable; import com.oracle.truffle.espresso.classfile.attributes.SignatureAttribute; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.ffi.NativeAccess; import com.oracle.truffle.espresso.ffi.NativeSignature; import com.oracle.truffle.espresso.ffi.NativeType; @@ -96,8 +98,8 @@ import com.oracle.truffle.espresso.jdwp.api.MethodRef; import com.oracle.truffle.espresso.jni.Mangle; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.ExceptionHandler; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.ExceptionHandler; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.meta.MetaUtil; import com.oracle.truffle.espresso.meta.ModifiersProvider; @@ -105,7 +107,9 @@ import com.oracle.truffle.espresso.nodes.interop.AbstractLookupNode; import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode.MethodHandleInvoker; import com.oracle.truffle.espresso.nodes.methodhandle.MethodHandleIntrinsicNode; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParserMethod; +import com.oracle.truffle.espresso.classfile.attributes.Attribute; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.EspressoThreadLocalState; import com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics; @@ -159,7 +163,7 @@ private Method(Method method, CodeAttribute split) { try { this.parsedSignature = getSignatures().parsed(this.getRawSignature()); - } catch (IllegalArgumentException | ClassFormatError e) { + } catch (IllegalArgumentException | ParserException.ClassFormatError e) { CompilerDirectives.transferToInterpreterAndInvalidate(); Meta meta = getMeta(); throw meta.throwExceptionWithMessage(meta.java_lang_ClassFormatError, e.getMessage()); @@ -182,7 +186,7 @@ private Method(Method method, CodeAttribute split) { try { this.parsedSignature = getSignatures().parsed(this.getRawSignature()); - } catch (IllegalArgumentException | ClassFormatError e) { + } catch (IllegalArgumentException | ParserException.ClassFormatError e) { CompilerDirectives.transferToInterpreterAndInvalidate(); Meta meta = getMeta(); throw meta.throwExceptionWithMessage(meta.java_lang_ClassFormatError, e.getMessage()); @@ -846,7 +850,7 @@ public void unregisterNative() { @SuppressWarnings("unused") public void printBytecodes(PrintStream out) { - new BytecodeStream(getOriginalCode()).printBytecode(declaringKlass, out); + BytecodePrinter.printBytecode(declaringKlass, out, getOriginalCode()); } public LocalVariableTable getLocalVariableTable() { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ModuleTable.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ModuleTable.java index 8ea3eb0af862..6ab872303cc4 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ModuleTable.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ModuleTable.java @@ -26,8 +26,8 @@ import java.util.ArrayList; import java.util.concurrent.locks.ReadWriteLock; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; import com.oracle.truffle.espresso.jdwp.api.ModuleRef; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; 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 1ef91e05069b..c6b667bf66ea 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 @@ -58,10 +58,10 @@ import com.oracle.truffle.espresso.analysis.hierarchy.ClassHierarchyOracle.ClassHierarchyAccessor; import com.oracle.truffle.espresso.analysis.hierarchy.SingleImplementor; import com.oracle.truffle.espresso.blocking.EspressoLock; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; +import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool; import com.oracle.truffle.espresso.classfile.attributes.ConstantValueAttribute; import com.oracle.truffle.espresso.classfile.attributes.EnclosingMethodAttribute; import com.oracle.truffle.espresso.classfile.attributes.InnerClassesAttribute; @@ -72,22 +72,25 @@ import com.oracle.truffle.espresso.classfile.attributes.SignatureAttribute; import com.oracle.truffle.espresso.classfile.attributes.SourceDebugExtensionAttribute; import com.oracle.truffle.espresso.classfile.attributes.SourceFileAttribute; -import com.oracle.truffle.espresso.descriptors.Names; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Names; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.ModuleTable.ModuleEntry; import com.oracle.truffle.espresso.impl.PackageTable.PackageEntry; import com.oracle.truffle.espresso.jdwp.api.Ids; import com.oracle.truffle.espresso.jdwp.api.MethodRef; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.meta.Meta; +import com.oracle.truffle.espresso.classfile.ParserField; +import com.oracle.truffle.espresso.classfile.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParserMethod; import com.oracle.truffle.espresso.redefinition.ChangePacket; import com.oracle.truffle.espresso.redefinition.ClassRedefinition; import com.oracle.truffle.espresso.redefinition.DetectedChange; -import com.oracle.truffle.espresso.runtime.Attribute; +import com.oracle.truffle.espresso.classfile.attributes.Attribute; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.EspressoException; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; @@ -174,7 +177,7 @@ public Attribute getAttribute(Symbol attrName) { } public ObjectKlass(EspressoContext context, LinkedKlass linkedKlass, ObjectKlass superKlass, ObjectKlass[] superInterfaces, StaticObject classLoader, ClassRegistry.ClassDefinitionInfo info) { - super(context, linkedKlass.getName(), linkedKlass.getType(), linkedKlass.getFlags(), info.klassID); + super(context, linkedKlass.getName(), linkedKlass.getType(), linkedKlass.getFlags(), linkedKlass.getParserKlass().getHiddenKlassId()); this.nest = info.dynamicNest; this.hostKlass = info.hostKlass; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PackageTable.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PackageTable.java index c9116d9135ce..de008afdbc2d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PackageTable.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PackageTable.java @@ -26,8 +26,8 @@ import java.util.ArrayList; import java.util.concurrent.locks.ReadWriteLock; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; import com.oracle.truffle.espresso.impl.ModuleTable.ModuleEntry; public class PackageTable extends EntryTable { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PrimitiveKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PrimitiveKlass.java index 93e3864dd380..acce598fcbb2 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PrimitiveKlass.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PrimitiveKlass.java @@ -27,14 +27,14 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; import com.oracle.truffle.espresso.impl.ModuleTable.ModuleEntry; import com.oracle.truffle.espresso.impl.ObjectKlass.KlassVersion; import com.oracle.truffle.espresso.impl.PackageTable.PackageEntry; import com.oracle.truffle.espresso.jdwp.api.MethodRef; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.GuestAllocator; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/RedefineAddedEnumField.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/RedefineAddedEnumField.java index 52fe91795d5e..a9f99e15ca12 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/RedefineAddedEnumField.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/RedefineAddedEnumField.java @@ -24,7 +24,7 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; +import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; public final class RedefineAddedEnumField extends RedefineAddedField { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/RedefineAddedField.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/RedefineAddedField.java index b54e2a8e1eb4..dddbdea307e3 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/RedefineAddedField.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/RedefineAddedField.java @@ -26,7 +26,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.staticobject.StaticShape; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; +import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool; import com.oracle.truffle.espresso.runtime.staticobject.ExtensionFieldObjectFactory; import com.oracle.truffle.espresso.runtime.staticobject.FieldStorageObject; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; @@ -43,7 +43,7 @@ public RedefineAddedField(ObjectKlass.KlassVersion holder, LinkedField linkedFie super(holder, linkedField, pool); if (!isDelegation) { StaticShape.Builder shapeBuilder = StaticShape.newBuilder(holder.getKlass().getLanguage()); - shapeBuilder.property(linkedField, linkedField.getParserField().getPropertyType(), linkedField.getParserField().isFinal()); + shapeBuilder.property(linkedField, LinkedField.getPropertyType(linkedField.getParserField()), linkedField.getParserField().isFinal()); this.extensionShape = shapeBuilder.build(FieldStorageObject.class, ExtensionFieldObjectFactory.class); } if (linkedField.getParserField().isStatic() && !isDelegation) { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/VirtualTable.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/VirtualTable.java index 77c4094722fc..50b6c025f888 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/VirtualTable.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/VirtualTable.java @@ -25,7 +25,7 @@ import java.util.ArrayList; import java.util.Arrays; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; import com.oracle.truffle.espresso.meta.Meta; /** 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 5fd5b4417ae7..c637fbeb6553 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 @@ -50,14 +50,15 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Validation; import com.oracle.truffle.espresso.ffi.NativeAccess; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.ModifiedUtf8; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Validation; import com.oracle.truffle.espresso.ffi.NativeSignature; import com.oracle.truffle.espresso.ffi.NativeType; import com.oracle.truffle.espresso.ffi.Pointer; @@ -69,7 +70,7 @@ import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.nodes.EspressoRootNode; import com.oracle.truffle.espresso.nodes.bytecodes.ArrayLength; 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 47ce17d8ab39..6c32446a82bc 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 @@ -22,7 +22,7 @@ */ package com.oracle.truffle.espresso.jni; -import com.oracle.truffle.espresso.runtime.JavaVersion; +import com.oracle.truffle.espresso.classfile.JavaVersion; public enum JniVersion { JNI_VERSION_1_1(0x00010001), diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/Mangle.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/Mangle.java index f1f49d3fd977..5481fdf53427 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/Mangle.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/Mangle.java @@ -23,9 +23,9 @@ package com.oracle.truffle.espresso.jni; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.meta.MetaUtil; 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 76d9a31daf22..22bcf3e796c9 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 @@ -30,7 +30,7 @@ import java.nio.charset.StandardCharsets; import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.espresso.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; import com.oracle.truffle.espresso.ffi.nfi.NativeUtils; import com.oracle.truffle.espresso.meta.EspressoError; 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 755db9a06ae3..7bd8cbbb516f 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 @@ -23,14 +23,14 @@ package com.oracle.truffle.espresso.meta; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.runtime.JavaVersion.VersionRange; +import com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange; final class DiffVersionLoadHelper { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/ExceptionDispatch.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/ExceptionDispatch.java index 02ef2a0be519..2da54755f127 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/ExceptionDispatch.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/ExceptionDispatch.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.meta; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ContextAccessImpl; import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.runtime.EspressoContext; 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 458bcdbdd328..dfd0d1204572 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 @@ -23,14 +23,14 @@ package com.oracle.truffle.espresso.meta; import static com.oracle.truffle.espresso.EspressoOptions.SpecComplianceMode.HOTSPOT; -import static com.oracle.truffle.espresso.runtime.JavaVersion.VersionRange.ALL; -import static com.oracle.truffle.espresso.runtime.JavaVersion.VersionRange.VERSION_16_OR_HIGHER; -import static com.oracle.truffle.espresso.runtime.JavaVersion.VersionRange.VERSION_17_OR_HIGHER; -import static com.oracle.truffle.espresso.runtime.JavaVersion.VersionRange.VERSION_19_OR_HIGHER; -import static com.oracle.truffle.espresso.runtime.JavaVersion.VersionRange.VERSION_8_OR_LOWER; -import static com.oracle.truffle.espresso.runtime.JavaVersion.VersionRange.VERSION_9_OR_HIGHER; -import static com.oracle.truffle.espresso.runtime.JavaVersion.VersionRange.higher; -import static com.oracle.truffle.espresso.runtime.JavaVersion.VersionRange.lower; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.ALL; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_16_OR_HIGHER; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_17_OR_HIGHER; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.VERSION_19_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.higher; +import static com.oracle.truffle.espresso.classfile.JavaVersion.VersionRange.lower; import java.util.Arrays; import java.util.Collection; @@ -45,11 +45,11 @@ import com.oracle.truffle.api.HostCompilerDirectives; import com.oracle.truffle.espresso.EspressoOptions; import com.oracle.truffle.espresso.EspressoOptions.SpecComplianceMode; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.ArrayKlass; import com.oracle.truffle.espresso.impl.ContextAccessImpl; import com.oracle.truffle.espresso.impl.EspressoClassLoadingException; @@ -59,6 +59,7 @@ import com.oracle.truffle.espresso.impl.ModuleTable; import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.impl.PrimitiveKlass; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.EspressoException; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/MetaUtil.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/MetaUtil.java index 63a5c467050f..63cf048618ce 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/MetaUtil.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/MetaUtil.java @@ -25,6 +25,7 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.espresso.EspressoLanguage; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; /** diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/AbstractInstrumentableBytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/AbstractInstrumentableBytecodeNode.java index a1d1a63021ea..d4a28adc4f1f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/AbstractInstrumentableBytecodeNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/AbstractInstrumentableBytecodeNode.java @@ -22,9 +22,6 @@ */ package com.oracle.truffle.espresso.nodes; -import java.util.ArrayList; -import java.util.HashMap; - import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.MaterializedFrame; @@ -38,14 +35,18 @@ import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.espresso.EspressoScope; -import com.oracle.truffle.espresso.classfile.attributes.Local; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Utf8ConstantTable; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.classfile.attributes.Local; import com.oracle.truffle.espresso.vm.continuation.UnwindContinuationException; +import java.util.ArrayList; +import java.util.HashMap; + @GenerateWrapper(yieldExceptions = UnwindContinuationException.class, resumeMethodPrefix = "resumeContinuation") @ExportLibrary(NodeLibrary.class) abstract class AbstractInstrumentableBytecodeNode extends EspressoInstrumentableNode { @@ -103,25 +104,24 @@ private Object getScopeSlowPath(MaterializedFrame frame) { int localCount = hasReceiver ? 1 : 0; localCount += method.getParameterCount(); - Utf8ConstantTable utf8Constants = method.getLanguage().getUtf8ConstantTable(); int startslot = 0; - if (hasReceiver) { // include 'this' and method arguments if not already included if (!slotToLocal.containsKey(startslot)) { - constructedLiveLocals.add(new Local(utf8Constants.getOrCreate(Symbol.Name.thiz), utf8Constants.getOrCreate(method.getDeclaringKlass().getType()), 0, 0xffff, 0)); + constructedLiveLocals.add(new Local(Name.thiz, method.getDeclaringKlass().getType(), null, 0, 0xffff, 0)); } else { constructedLiveLocals.add(slotToLocal.get(startslot)); } slotToLocal.remove(startslot); startslot++; } - Symbol[] parsedSignature = method.getParsedSignature(); + Symbol[] parsedSignature = method.getParsedSignature(); // include method parameters if not already included for (int i = startslot; i < localCount; i++) { - Symbol paramType = hasReceiver ? Signatures.parameterType(parsedSignature, i - 1) : Signatures.parameterType(parsedSignature, i); + Symbol paramType = hasReceiver ? Signatures.parameterType(parsedSignature, i - 1) : Signatures.parameterType(parsedSignature, i); if (!slotToLocal.containsKey(i)) { - constructedLiveLocals.add(new Local(utf8Constants.getOrCreate(ByteSequence.create("arg_" + i)), utf8Constants.getOrCreate(paramType), 0, 0xffff, i)); + Symbol localName = getLanguage().getNames().getOrCreate(ByteSequence.create("arg_" + i)); + constructedLiveLocals.add(new Local(localName, paramType, null, 0, 0xffff, i)); slotToLocal.remove(i); } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java index 1dd2f74daff1..d3d45e68d890 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java @@ -23,213 +23,213 @@ package com.oracle.truffle.espresso.nodes; import static com.oracle.truffle.espresso.EspressoOptions.SpecComplianceMode.STRICT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.AALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.AASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ACONST_NULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ANEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ARETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ARRAYLENGTH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ATHROW; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BIPUSH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BREAKPOINT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CHECKCAST; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCMPG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCMPL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP2_X1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP2_X2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP_X1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP_X2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCMPG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCMPL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GETFIELD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GETSTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GOTO; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GOTO_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2B; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2C; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2S; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IAND; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_4; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_5; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_M1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFEQ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFGE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFGT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFLE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFLT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFNE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFNONNULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFNULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ACMPEQ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ACMPNE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPEQ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPGE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPGT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPLE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPLT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPNE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IINC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INSTANCEOF; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEDYNAMIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEINTERFACE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKESPECIAL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKESTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEVIRTUAL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISHL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IUSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IXOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.JSR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.JSR_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LAND; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCMP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDC2_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDC_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LOOKUPSWITCH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSHL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LUSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LXOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MONITORENTER; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MONITOREXIT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MULTIANEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NEW; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NOP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.POP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.POP2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTFIELD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTSTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.QUICK; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.RET; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.RETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.RETURN_VALUE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SIPUSH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SLIM_QUICK; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SWAP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.TABLESWITCH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.THROW_VALUE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.WIDE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.AALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.AASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ACONST_NULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ANEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ARETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ARRAYLENGTH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ATHROW; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BIPUSH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BREAKPOINT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CHECKCAST; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCMPG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCMPL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP2_X1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP2_X2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP_X1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP_X2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCMPG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCMPL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GETFIELD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GETSTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GOTO; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GOTO_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2B; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2C; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2S; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IAND; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_4; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_5; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_M1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFEQ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFGE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFGT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFLE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFLT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFNE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFNONNULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFNULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ACMPEQ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ACMPNE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPEQ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPGE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPGT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPLE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPLT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPNE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IINC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INSTANCEOF; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEDYNAMIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEINTERFACE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKESPECIAL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKESTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEVIRTUAL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISHL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IUSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IXOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.JSR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.JSR_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LAND; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCMP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDC2_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDC_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LOOKUPSWITCH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSHL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LUSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LXOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MONITORENTER; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MONITOREXIT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MULTIANEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NEW; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NOP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.POP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.POP2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.PUTFIELD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.PUTSTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.QUICK; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.RET; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.RETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.RETURN_VALUE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SIPUSH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SLIM_QUICK; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SWAP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.TABLESWITCH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.THROW_VALUE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.WIDE; import static com.oracle.truffle.espresso.nodes.EspressoFrame.clear; import static com.oracle.truffle.espresso.nodes.EspressoFrame.createFrameDescriptor; import static com.oracle.truffle.espresso.nodes.EspressoFrame.dup1; @@ -305,13 +305,17 @@ import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.analysis.liveness.LivenessAnalysis; -import com.oracle.truffle.espresso.bytecode.BytecodeLookupSwitch; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; -import com.oracle.truffle.espresso.bytecode.BytecodeTableSwitch; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeLookupSwitch; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeTableSwitch; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.bytecode.MapperBCI; +import com.oracle.truffle.espresso.constantpool.CallSiteLink; +import com.oracle.truffle.espresso.constantpool.Resolution; +import com.oracle.truffle.espresso.constantpool.ResolvedDynamicConstant; +import com.oracle.truffle.espresso.constantpool.ResolvedWithInvokerClassMethodRefConstant; import com.oracle.truffle.espresso.classfile.ClassfileParser; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; +import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool; import com.oracle.truffle.espresso.classfile.attributes.BootstrapMethodsAttribute; import com.oracle.truffle.espresso.classfile.attributes.LineNumberTableAttribute; import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; @@ -319,16 +323,15 @@ import com.oracle.truffle.espresso.classfile.constantpool.DynamicConstant; import com.oracle.truffle.espresso.classfile.constantpool.FloatConstant; import com.oracle.truffle.espresso.classfile.constantpool.IntegerConstant; -import com.oracle.truffle.espresso.classfile.constantpool.InvokeDynamicConstant; import com.oracle.truffle.espresso.classfile.constantpool.LongConstant; import com.oracle.truffle.espresso.classfile.constantpool.MethodHandleConstant; import com.oracle.truffle.espresso.classfile.constantpool.MethodRefConstant; import com.oracle.truffle.espresso.classfile.constantpool.MethodTypeConstant; import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant; import com.oracle.truffle.espresso.classfile.constantpool.StringConstant; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.ArrayKlass; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Klass; @@ -336,8 +339,8 @@ import com.oracle.truffle.espresso.impl.Method.MethodVersion; import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.ExceptionHandler; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.ExceptionHandler; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.nodes.helper.EspressoReferenceArrayStoreNode; import com.oracle.truffle.espresso.nodes.methodhandle.MHInvokeGenericNode.MethodHandleInvoker; @@ -345,7 +348,7 @@ import com.oracle.truffle.espresso.nodes.quick.CheckCastQuickNode; import com.oracle.truffle.espresso.nodes.quick.InstanceOfQuickNode; import com.oracle.truffle.espresso.nodes.quick.QuickNode; -import com.oracle.truffle.espresso.nodes.quick.VolatileArrayAccess; +import com.oracle.truffle.espresso.classfile.bytecode.VolatileArrayAccess; import com.oracle.truffle.espresso.nodes.quick.interop.ArrayLengthQuickNode; import com.oracle.truffle.espresso.nodes.quick.interop.ByteArrayLoadQuickNode; import com.oracle.truffle.espresso.nodes.quick.interop.ByteArrayStoreQuickNode; @@ -374,7 +377,7 @@ import com.oracle.truffle.espresso.nodes.quick.invoke.InvokeStaticQuickNode; import com.oracle.truffle.espresso.nodes.quick.invoke.InvokeVirtualQuickNode; import com.oracle.truffle.espresso.nodes.quick.invoke.inline.InlinedMethodNode; -import com.oracle.truffle.espresso.perf.DebugCounter; +import com.oracle.truffle.espresso.classfile.perf.DebugCounter; import com.oracle.truffle.espresso.resolver.CallKind; import com.oracle.truffle.espresso.resolver.CallSiteType; import com.oracle.truffle.espresso.resolver.LinkResolver; @@ -2101,7 +2104,7 @@ private void putPoolConstant(VirtualFrame frame, int top, char cpi, int opcode) StaticObject methodType = pool.resolvedMethodTypeAt(getDeclaringKlass(), cpi); putObject(frame, top, methodType); } else if (constant instanceof DynamicConstant) { - DynamicConstant.Resolved dynamicConstant = pool.resolvedDynamicConstantAt(getDeclaringKlass(), cpi); + ResolvedDynamicConstant dynamicConstant = pool.resolvedDynamicConstantAt(getDeclaringKlass(), cpi); dynamicConstant.putResolved(frame, top, this); } else { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -2398,7 +2401,7 @@ private int quickenArrayStore(final VirtualFrame frame, int top, int curBCI, int private InvokeQuickNode dispatchQuickened(int top, int curBCI, char cpi, int opcode, int statementIndex, Method resolutionSeed, boolean allowBytecodeInlining) { - Klass symbolicRef = ((MethodRefConstant.Indexes) getConstantPool().methodAt(cpi)).getResolvedHolderKlass(getDeclaringKlass(), getConstantPool()); + Klass symbolicRef = Resolution.getResolvedHolderKlass((MethodRefConstant.Indexes) getConstantPool().methodAt(cpi), getConstantPool(), getDeclaringKlass()); ResolvedCall resolvedCall = LinkResolver.resolveCallSite(getMeta(), getDeclaringKlass(), resolutionSeed, CallSiteType.fromOpCode(opcode), symbolicRef); Method resolved = resolvedCall.getResolvedMethod(); @@ -2416,8 +2419,12 @@ private InvokeQuickNode dispatchQuickened(int top, int curBCI, char cpi, int opc } if (resolved.isPolySignatureIntrinsic()) { - MethodHandleInvoker invoker = getConstantPool().resolvedMethodRefAt(getDeclaringKlass(), cpi).invoker(); - assert invoker == null || ((opcode == INVOKEVIRTUAL || opcode == INVOKESPECIAL) && resolved.isInvokeIntrinsic()); + MethodHandleInvoker invoker = null; + // There might be an invoker if it's an InvokeGeneric + if (getConstantPool().resolvedMethodRefAt(getDeclaringKlass(), cpi) instanceof ResolvedWithInvokerClassMethodRefConstant withInvoker) { + invoker = withInvoker.invoker(); + assert invoker == null || ((opcode == INVOKEVIRTUAL || opcode == INVOKESPECIAL) && resolved.isInvokeIntrinsic()); + } return new InvokeHandleNode(resolved, invoker, top, curBCI); } else { // @formatter:off @@ -2470,7 +2477,7 @@ private int quickenInvokeDynamic(final VirtualFrame frame, int top, int curBCI, return quick.execute(frame, false) - Bytecodes.stackEffectOf(opcode); } // Resolution should happen outside of the bytecode patching lock. - InvokeDynamicConstant.CallSiteLink link = pool.linkInvokeDynamic(getMethod().getDeclaringKlass(), indyIndex, curBCI, getMethod()); + CallSiteLink link = pool.linkInvokeDynamic(getMethod().getDeclaringKlass(), indyIndex, curBCI, getMethod()); // re-lock to check if someone did the job for us, since this was a heavy operation. quick = atomic(() -> { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoFrame.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoFrame.java index 8170cf106fef..b697fc135fe0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoFrame.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoFrame.java @@ -29,13 +29,13 @@ import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.runtime.ReturnAddress; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.vm.continuation.HostFrameRecord; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoNode.java index 1e341f38ce2e..e483dac52aa0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/EspressoNode.java @@ -26,15 +26,15 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.descriptors.Names; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Names; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.ffi.NativeAccess; import com.oracle.truffle.espresso.impl.ClassRegistries; import com.oracle.truffle.espresso.impl.ContextAccess; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.EspressoContext; -import com.oracle.truffle.espresso.runtime.JavaVersion; +import com.oracle.truffle.espresso.classfile.JavaVersion; import com.oracle.truffle.espresso.runtime.StringTable; import com.oracle.truffle.espresso.substitutions.Substitutions; import com.oracle.truffle.espresso.threads.ThreadsAccess; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/IntrinsicSubstitutorNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/IntrinsicSubstitutorNode.java index 8d678b02853b..498a1a744f20 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/IntrinsicSubstitutorNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/IntrinsicSubstitutorNode.java @@ -33,7 +33,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.perf.DebugCounter; +import com.oracle.truffle.espresso.classfile.perf.DebugCounter; import com.oracle.truffle.espresso.runtime.EspressoThreadLocalState; import com.oracle.truffle.espresso.substitutions.JavaSubstitution; import com.oracle.truffle.espresso.vm.VM; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/NativeMethodNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/NativeMethodNode.java index c71a9b134b9d..adc5f551bf91 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/NativeMethodNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/NativeMethodNode.java @@ -37,16 +37,16 @@ import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.ffi.nfi.NativeUtils; import com.oracle.truffle.espresso.impl.Method.MethodVersion; import com.oracle.truffle.espresso.jni.JNIHandles; import com.oracle.truffle.espresso.jni.JniEnv; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.perf.DebugCounter; +import com.oracle.truffle.espresso.classfile.perf.DebugCounter; import com.oracle.truffle.espresso.runtime.EspressoException; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.vm.VM; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/SubstitutionScope.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/SubstitutionScope.java index b261786e3d7f..3f23f7eeba44 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/SubstitutionScope.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/SubstitutionScope.java @@ -32,10 +32,10 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.espresso.EspressoLanguage; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.classfile.ConstantPool; import com.oracle.truffle.espresso.classfile.attributes.MethodParametersAttribute; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.impl.Method; @ExportLibrary(InteropLibrary.class) final class SubstitutionScope implements TruffleObject { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/commands/ReferenceProcessCache.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/commands/ReferenceProcessCache.java index 8854b5bbc5b8..f647b3bcab31 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/commands/ReferenceProcessCache.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/commands/ReferenceProcessCache.java @@ -26,9 +26,9 @@ import java.util.List; import com.oracle.truffle.api.nodes.DirectCallNode; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Method; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/helper/AbstractGetFieldNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/helper/AbstractGetFieldNode.java index 48e2676869c7..f33ed744b6be 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/helper/AbstractGetFieldNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/helper/AbstractGetFieldNode.java @@ -37,7 +37,7 @@ import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.nodes.BytecodeNode; import com.oracle.truffle.espresso.nodes.EspressoFrame; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/helper/AbstractSetFieldNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/helper/AbstractSetFieldNode.java index 620eee085e99..d37155d7c5b7 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/helper/AbstractSetFieldNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/helper/AbstractSetFieldNode.java @@ -35,7 +35,7 @@ import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.nodes.BytecodeNode; import com.oracle.truffle.espresso.nodes.EspressoFrame; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/AbstractLookupFieldNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/AbstractLookupFieldNode.java index 7c5e23a2aa8e..0d3de3ff8cd0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/AbstractLookupFieldNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/AbstractLookupFieldNode.java @@ -24,8 +24,8 @@ package com.oracle.truffle.espresso.nodes.interop; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.nodes.EspressoNode; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/AbstractLookupNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/AbstractLookupNode.java index 2428c637cbc7..709250d6c9a3 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/AbstractLookupNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/AbstractLookupNode.java @@ -31,9 +31,9 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.ArityException; import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.nodes.EspressoNode; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/EspressoForeignProxyGenerator.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/EspressoForeignProxyGenerator.java index 577277aa7feb..cf00a38ecaea 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/EspressoForeignProxyGenerator.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/EspressoForeignProxyGenerator.java @@ -66,7 +66,7 @@ import java.util.concurrent.atomic.AtomicLong; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ArrayKlass; import com.oracle.truffle.espresso.impl.ClassRegistry; import com.oracle.truffle.espresso.impl.Klass; @@ -76,7 +76,7 @@ import com.oracle.truffle.espresso.impl.PackageTable; import com.oracle.truffle.espresso.jni.Mangle; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.EspressoException; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/LookupFieldNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/LookupFieldNode.java index e26724681584..06a1a031103a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/LookupFieldNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/LookupFieldNode.java @@ -27,8 +27,8 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateUncached; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.nodes.EspressoNode; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/LookupProxyKlassNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/LookupProxyKlassNode.java index 65ab4bd59460..c979d707cd4d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/LookupProxyKlassNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/LookupProxyKlassNode.java @@ -33,7 +33,7 @@ import com.oracle.truffle.api.interop.InvalidArrayIndexException; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ClassRegistry; import com.oracle.truffle.espresso.impl.EspressoClassLoadingException; import com.oracle.truffle.espresso.impl.Klass; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java index e91f775bb61c..182b87c59dda 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java @@ -40,7 +40,7 @@ import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ArrayKlass; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Method; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHInvokeGenericNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHInvokeGenericNode.java index 45be86405e0c..d5e0a938d24a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHInvokeGenericNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHInvokeGenericNode.java @@ -26,12 +26,12 @@ import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; 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 0ff63fd2b304..5189c2ee333b 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 @@ -24,7 +24,7 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.espresso.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.meta.Meta; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHLinkToNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHLinkToNode.java index df22627d8f43..0e9a060fb860 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHLinkToNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MHLinkToNode.java @@ -32,14 +32,14 @@ import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.IndirectCallNode; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.nodes.quick.invoke.InvokeDynamicCallSiteNode; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MethodHandleIntrinsicNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MethodHandleIntrinsicNode.java index 5b6a8b559c8e..844a5416c414 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MethodHandleIntrinsicNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/methodhandle/MethodHandleIntrinsicNode.java @@ -25,9 +25,9 @@ import com.oracle.truffle.api.dsl.Idempotent; import com.oracle.truffle.espresso.impl.Method; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.nodes.EspressoNode; -import com.oracle.truffle.espresso.perf.DebugCounter; +import com.oracle.truffle.espresso.classfile.perf.DebugCounter; /** * Top of the method handle intrinsic behavior implementation hierarchy. diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/CheckCastQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/CheckCastQuickNode.java index eb634c8cafa0..3217d62a2d60 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/CheckCastQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/CheckCastQuickNode.java @@ -24,7 +24,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.nodes.BytecodeNode; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/InstanceOfQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/InstanceOfQuickNode.java index 4876d8bcd81a..1b9480b3a83a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/InstanceOfQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/InstanceOfQuickNode.java @@ -23,7 +23,7 @@ package com.oracle.truffle.espresso.nodes.quick; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.InstanceOf; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ArrayLengthQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ArrayLengthQuickNode.java index 87bea668dd7b..d792ed1ab3a6 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ArrayLengthQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ArrayLengthQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.ArrayLength; import com.oracle.truffle.espresso.nodes.bytecodes.ArrayLengthFactory; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ByteArrayLoadQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ByteArrayLoadQuickNode.java index 74d35327ffdf..aa126ba16ba4 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ByteArrayLoadQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ByteArrayLoadQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.ByteArrayLoad; import com.oracle.truffle.espresso.nodes.bytecodes.ByteArrayLoadNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ByteArrayStoreQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ByteArrayStoreQuickNode.java index 33a83b197786..2617bd784966 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ByteArrayStoreQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ByteArrayStoreQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.ByteArrayStore; import com.oracle.truffle.espresso.nodes.bytecodes.ByteArrayStoreNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/CharArrayLoadQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/CharArrayLoadQuickNode.java index 4caa2f30c749..14ad543f970e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/CharArrayLoadQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/CharArrayLoadQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.CharArrayLoad; import com.oracle.truffle.espresso.nodes.bytecodes.CharArrayLoadNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/CharArrayStoreQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/CharArrayStoreQuickNode.java index 1268a3547d9b..bb511fdab408 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/CharArrayStoreQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/CharArrayStoreQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.CharArrayStore; import com.oracle.truffle.espresso.nodes.bytecodes.CharArrayStoreNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/DoubleArrayLoadQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/DoubleArrayLoadQuickNode.java index 078fc85277e9..058ee8799120 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/DoubleArrayLoadQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/DoubleArrayLoadQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.DoubleArrayLoad; import com.oracle.truffle.espresso.nodes.bytecodes.DoubleArrayLoadNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/DoubleArrayStoreQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/DoubleArrayStoreQuickNode.java index 18f54d4cd6d2..3c280453bd12 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/DoubleArrayStoreQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/DoubleArrayStoreQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.DoubleArrayStore; import com.oracle.truffle.espresso.nodes.bytecodes.DoubleArrayStoreNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/FloatArrayLoadQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/FloatArrayLoadQuickNode.java index 9220ad84db0f..f51075a65190 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/FloatArrayLoadQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/FloatArrayLoadQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.FloatArrayLoad; import com.oracle.truffle.espresso.nodes.bytecodes.FloatArrayLoadNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/FloatArrayStoreQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/FloatArrayStoreQuickNode.java index 487b3fd19c40..87187ce5f961 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/FloatArrayStoreQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/FloatArrayStoreQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.FloatArrayStore; import com.oracle.truffle.espresso.nodes.bytecodes.FloatArrayStoreNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/IntArrayLoadQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/IntArrayLoadQuickNode.java index 87938a9713cd..b1175604a308 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/IntArrayLoadQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/IntArrayLoadQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.IntArrayLoad; import com.oracle.truffle.espresso.nodes.bytecodes.IntArrayLoadNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/IntArrayStoreQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/IntArrayStoreQuickNode.java index 6a7c4fc14195..d5aa505c9c4a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/IntArrayStoreQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/IntArrayStoreQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.IntArrayStore; import com.oracle.truffle.espresso.nodes.bytecodes.IntArrayStoreNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/LongArrayLoadQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/LongArrayLoadQuickNode.java index ed9a4bba76ae..e629ed0e932e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/LongArrayLoadQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/LongArrayLoadQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.LongArrayLoad; import com.oracle.truffle.espresso.nodes.bytecodes.LongArrayLoadNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/LongArrayStoreQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/LongArrayStoreQuickNode.java index 5679850baf72..938e0c5ac3a4 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/LongArrayStoreQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/LongArrayStoreQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.LongArrayStore; import com.oracle.truffle.espresso.nodes.bytecodes.LongArrayStoreNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ReferenceArrayLoadQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ReferenceArrayLoadQuickNode.java index 700c29d756db..e7ac5d7785f0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ReferenceArrayLoadQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ReferenceArrayLoadQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.ReferenceArrayLoad; import com.oracle.truffle.espresso.nodes.bytecodes.ReferenceArrayLoadNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ReferenceArrayStoreQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ReferenceArrayStoreQuickNode.java index 4ba3e971f82d..42c3d080d314 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ReferenceArrayStoreQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ReferenceArrayStoreQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.ReferenceArrayStore; import com.oracle.truffle.espresso.nodes.bytecodes.ReferenceArrayStoreNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ShortArrayLoadQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ShortArrayLoadQuickNode.java index 9e11c6c06b92..9e2db3cdac9d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ShortArrayLoadQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ShortArrayLoadQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.ShortArrayLoad; import com.oracle.truffle.espresso.nodes.bytecodes.ShortArrayLoadNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ShortArrayStoreQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ShortArrayStoreQuickNode.java index 21154576ee92..8d0b186619be 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ShortArrayStoreQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/interop/ShortArrayStoreQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.interop; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.bytecodes.ShortArrayStore; import com.oracle.truffle.espresso.nodes.bytecodes.ShortArrayStoreNodeGen; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeDynamicCallSiteNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeDynamicCallSiteNode.java index e0da34cd0cd3..76cc78fdf36d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeDynamicCallSiteNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeDynamicCallSiteNode.java @@ -25,12 +25,12 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.Method; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.quick.QuickNode; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeQuickNode.java index 4727dc819b4b..9a79f3688a29 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeQuickNode.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.nodes.quick.invoke; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.quick.QuickNode; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeStaticQuickNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeStaticQuickNode.java index 0f44df5b1b52..948cd51758ea 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeStaticQuickNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/InvokeStaticQuickNode.java @@ -23,7 +23,7 @@ package com.oracle.truffle.espresso.nodes.quick.invoke; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.nodes.EspressoRootNode; import com.oracle.truffle.espresso.nodes.bytecodes.InvokeStatic; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/inline/bodies/InlinedFieldAccessNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/inline/bodies/InlinedFieldAccessNode.java index 7da66f1d8e17..f4a5de00c443 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/inline/bodies/InlinedFieldAccessNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/quick/invoke/inline/bodies/InlinedFieldAccessNode.java @@ -30,7 +30,7 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.meta.EspressoError; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/CachedLinkedKlassProvider.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/CachedLinkedKlassProvider.java index 2e3e2b74e84f..c2fe7943eda6 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/CachedLinkedKlassProvider.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/CachedLinkedKlassProvider.java @@ -32,7 +32,7 @@ import com.oracle.truffle.espresso.impl.ClassRegistry; import com.oracle.truffle.espresso.impl.ContextDescription; import com.oracle.truffle.espresso.impl.LinkedKlass; -import com.oracle.truffle.espresso.impl.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParserKlass; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; public final class CachedLinkedKlassProvider extends AbstractCachedKlassProvider implements LinkedKlassProvider { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/CachedParserKlassProvider.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/CachedParserKlassProvider.java index f30eeded95d1..8ca6ba2e2a5d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/CachedParserKlassProvider.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/CachedParserKlassProvider.java @@ -27,10 +27,10 @@ import java.util.concurrent.ConcurrentHashMap; import com.oracle.truffle.api.TruffleLogger; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ClassLoadingEnv; import com.oracle.truffle.espresso.impl.ClassRegistry; -import com.oracle.truffle.espresso.impl.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParserKlass; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.verifier.MethodVerifier; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/ContextPatchingException.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/ContextPatchingException.java index 710929cc1392..38f5c09375db 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/ContextPatchingException.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/ContextPatchingException.java @@ -23,7 +23,7 @@ package com.oracle.truffle.espresso.preinit; import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.espresso.runtime.JavaVersion; +import com.oracle.truffle.espresso.classfile.JavaVersion; public final class ContextPatchingException extends Exception { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/DefaultLinkedKlassProvider.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/DefaultLinkedKlassProvider.java index 79a104189b63..422e5c5f9f61 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/DefaultLinkedKlassProvider.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/DefaultLinkedKlassProvider.java @@ -26,7 +26,7 @@ import com.oracle.truffle.espresso.impl.ClassRegistry; import com.oracle.truffle.espresso.impl.ContextDescription; import com.oracle.truffle.espresso.impl.LinkedKlass; -import com.oracle.truffle.espresso.impl.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParserKlass; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; public final class DefaultLinkedKlassProvider implements LinkedKlassProvider { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/DefaultParserKlassProvider.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/DefaultParserKlassProvider.java index 0beca02e070f..cfe926fe04fe 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/DefaultParserKlassProvider.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/DefaultParserKlassProvider.java @@ -22,19 +22,17 @@ */ package com.oracle.truffle.espresso.preinit; -import com.oracle.truffle.espresso.classfile.ClassfileParser; -import com.oracle.truffle.espresso.classfile.ClassfileStream; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ClassLoadingEnv; import com.oracle.truffle.espresso.impl.ClassRegistry; -import com.oracle.truffle.espresso.impl.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParserKlass; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; -import com.oracle.truffle.espresso.verifier.MethodVerifier; public final class DefaultParserKlassProvider implements ParserKlassProvider { + @Override - public ParserKlass getParserKlass(ClassLoadingEnv env, StaticObject loader, Symbol typeOrNull, byte[] bytes, ClassRegistry.ClassDefinitionInfo info) { - boolean verifiable = MethodVerifier.needsVerify(env.getLanguage(), loader); - return ClassfileParser.parse(env, new ClassfileStream(bytes, null), verifiable, env.loaderIsBootOrPlatform(loader), typeOrNull, info); + public ParserKlass getParserKlass(ClassLoadingEnv env, StaticObject loader, Symbol typeOrNull, byte[] bytes, ClassRegistry.ClassDefinitionInfo info) { + return ParserKlassProvider.parseKlass(info, env, loader, typeOrNull, bytes); } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/EspressoLanguageCache.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/EspressoLanguageCache.java index 3f0ebabc7396..fb6bb30f0395 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/EspressoLanguageCache.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/EspressoLanguageCache.java @@ -25,12 +25,12 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ClassLoadingEnv; import com.oracle.truffle.espresso.impl.ClassRegistry; import com.oracle.truffle.espresso.impl.ContextDescription; import com.oracle.truffle.espresso.impl.LinkedKlass; -import com.oracle.truffle.espresso.impl.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParserKlass; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/LinkedKlassProvider.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/LinkedKlassProvider.java index 7a079a888f68..ce9db65d8128 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/LinkedKlassProvider.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/LinkedKlassProvider.java @@ -26,7 +26,7 @@ import com.oracle.truffle.espresso.impl.ClassRegistry; import com.oracle.truffle.espresso.impl.ContextDescription; import com.oracle.truffle.espresso.impl.LinkedKlass; -import com.oracle.truffle.espresso.impl.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParserKlass; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; public interface LinkedKlassProvider { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/ParserKlassProvider.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/ParserKlassProvider.java index 1437ee8c065e..9e364e2d3f98 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/ParserKlassProvider.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/preinit/ParserKlassProvider.java @@ -22,16 +22,57 @@ */ package com.oracle.truffle.espresso.preinit; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.ClassfileParser; +import com.oracle.truffle.espresso.classfile.ClassfileStream; +import com.oracle.truffle.espresso.classfile.ParserException; +import com.oracle.truffle.espresso.classfile.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParsingContext; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; import com.oracle.truffle.espresso.impl.ClassLoadingEnv; import com.oracle.truffle.espresso.impl.ClassRegistry; -import com.oracle.truffle.espresso.impl.ParserKlass; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; +import com.oracle.truffle.espresso.verifier.MethodVerifier; public interface ParserKlassProvider { - ParserKlass getParserKlass(ClassLoadingEnv env, StaticObject loader, Symbol typeOrNull, byte[] bytes, ClassRegistry.ClassDefinitionInfo info); + ParserKlass getParserKlass(ClassLoadingEnv env, StaticObject loader, Symbol typeOrNull, byte[] bytes, ClassRegistry.ClassDefinitionInfo info); default int getCachedParserKlassCount() { return 0; } + + static ParserKlass parseKlass(ClassRegistry.ClassDefinitionInfo info, ClassLoadingEnv env, StaticObject loader, Symbol typeOrNull, byte[] bytes) { + boolean verifiable = MethodVerifier.needsVerify(env.getLanguage(), loader); + boolean loaderIsBootOrPlatform = env.loaderIsBootOrPlatform(loader); + Meta meta = env.getMeta(); + try { + return ClassfileParser.parse(env.getParsingContext(), new ClassfileStream(bytes, null), verifiable, loaderIsBootOrPlatform, typeOrNull, info.isHidden); + } catch (ValidationException | ParserException.ClassFormatError validationOrBadFormat) { + throw meta.throwExceptionWithMessage(meta.java_lang_ClassFormatError, validationOrBadFormat.getMessage()); + } catch (ParserException.UnsupportedClassVersionError unsupportedClassVersionError) { + throw meta.throwExceptionWithMessage(meta.java_lang_UnsupportedClassVersionError, unsupportedClassVersionError.getMessage()); + } catch (ParserException.NoClassDefFoundError noClassDefFoundError) { + throw meta.throwExceptionWithMessage(meta.java_lang_NoClassDefFoundError, noClassDefFoundError.getMessage()); + } catch (ParserException parserException) { + throw EspressoError.shouldNotReachHere("Not a validation nor parser exception", parserException); + } + } + + static Symbol getClassName(Meta meta, ParsingContext parsingContext, byte[] bytes) { + try { + return ClassfileParser.getClassName(parsingContext, bytes); + } catch (ValidationException | ParserException.ClassFormatError validationOrBadFormat) { + throw meta.throwExceptionWithMessage(meta.java_lang_ClassFormatError, validationOrBadFormat.getMessage()); + } catch (ParserException.UnsupportedClassVersionError unsupportedClassVersionError) { + throw meta.throwExceptionWithMessage(meta.java_lang_UnsupportedClassVersionError, unsupportedClassVersionError.getMessage()); + } catch (ParserException.NoClassDefFoundError noClassDefFoundError) { + throw meta.throwExceptionWithMessage(meta.java_lang_NoClassDefFoundError, noClassDefFoundError.getMessage()); + } catch (ParserException parserException) { + throw EspressoError.shouldNotReachHere("Not a validation nor parser exception", parserException); + } + } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ChangePacket.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ChangePacket.java index 5087b34525d1..7753b72fc99c 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ChangePacket.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ChangePacket.java @@ -22,7 +22,7 @@ */ package com.oracle.truffle.espresso.redefinition; -import com.oracle.truffle.espresso.impl.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParserKlass; public final class ChangePacket { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassInfo.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassInfo.java index 5cc748f52e9b..79d18c2bd081 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassInfo.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassInfo.java @@ -22,29 +22,29 @@ */ package com.oracle.truffle.espresso.redefinition; -import java.util.ArrayList; -import java.util.Set; -import java.util.regex.Matcher; - -import com.oracle.truffle.espresso.classfile.ClassfileParser; -import com.oracle.truffle.espresso.classfile.ClassfileStream; -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.attributes.EnclosingMethodAttribute; -import com.oracle.truffle.espresso.classfile.constantpool.NameAndTypeConstant; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.impl.ClassRegistry; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.impl.ParserField; -import com.oracle.truffle.espresso.impl.ParserKlass; -import com.oracle.truffle.espresso.impl.ParserMethod; import com.oracle.truffle.espresso.jdwp.api.RedefineInfo; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.ParserField; +import com.oracle.truffle.espresso.classfile.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParserMethod; +import com.oracle.truffle.espresso.classfile.attributes.EnclosingMethodAttribute; +import com.oracle.truffle.espresso.classfile.constantpool.NameAndTypeConstant; +import com.oracle.truffle.espresso.preinit.ParserKlassProvider; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; +import java.util.ArrayList; +import java.util.Set; +import java.util.regex.Matcher; + public abstract class ClassInfo { private final boolean isNewInnerTestKlass; @@ -127,7 +127,7 @@ public static HotSwapClassInfo create(Symbol name, byte[] bytes, StaticObj public static HotSwapClassInfo create(ObjectKlass klass, Symbol name, byte[] bytes, StaticObject definingLoader, EspressoContext context, boolean isNewInnerTestKlass) { Symbol type = context.getTypes().fromName(name); - ParserKlass parserKlass = ClassfileParser.parse(context.getClassLoadingEnv(), new ClassfileStream(bytes, null), definingLoader, type); + ParserKlass parserKlass = ParserKlassProvider.parseKlass(ClassRegistry.ClassDefinitionInfo.EMPTY, context.getClassLoadingEnv(), definingLoader, type, bytes); StringBuilder hierarchy = new StringBuilder(); StringBuilder methods = new StringBuilder(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java index 43c47f332a9c..60e122be3262 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java @@ -22,58 +22,56 @@ */ package com.oracle.truffle.espresso.redefinition; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.regex.Matcher; - -import org.graalvm.collections.EconomicMap; -import org.graalvm.collections.EconomicSet; - import com.oracle.truffle.api.Assumption; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.Truffle; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; -import com.oracle.truffle.espresso.bytecode.Bytecodes; -import com.oracle.truffle.espresso.classfile.ClassfileParser; -import com.oracle.truffle.espresso.classfile.ClassfileStream; -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.Constants; -import com.oracle.truffle.espresso.classfile.attributes.CodeAttribute; -import com.oracle.truffle.espresso.classfile.attributes.LineNumberTableAttribute; -import com.oracle.truffle.espresso.classfile.attributes.Local; -import com.oracle.truffle.espresso.classfile.attributes.LocalVariableTable; -import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.ClassRegistry; import com.oracle.truffle.espresso.impl.EspressoClassLoadingException; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.impl.ParserField; -import com.oracle.truffle.espresso.impl.ParserKlass; -import com.oracle.truffle.espresso.impl.ParserMethod; import com.oracle.truffle.espresso.impl.RedefineAddedField; import com.oracle.truffle.espresso.jdwp.api.ErrorCodes; import com.oracle.truffle.espresso.jdwp.api.Ids; import com.oracle.truffle.espresso.jdwp.api.RedefineInfo; import com.oracle.truffle.espresso.jdwp.impl.DebuggerController; import com.oracle.truffle.espresso.meta.Meta; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.Constants; +import com.oracle.truffle.espresso.classfile.ParserField; +import com.oracle.truffle.espresso.classfile.ParserKlass; +import com.oracle.truffle.espresso.classfile.ParserMethod; +import com.oracle.truffle.espresso.classfile.attributes.Attribute; +import com.oracle.truffle.espresso.classfile.attributes.CodeAttribute; +import com.oracle.truffle.espresso.classfile.attributes.LineNumberTableAttribute; +import com.oracle.truffle.espresso.classfile.attributes.Local; +import com.oracle.truffle.espresso.classfile.attributes.LocalVariableTable; +import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant; +import com.oracle.truffle.espresso.preinit.ParserKlassProvider; import com.oracle.truffle.espresso.redefinition.plugins.impl.RedefineListener; -import com.oracle.truffle.espresso.runtime.Attribute; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.EspressoException; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.vm.InterpreterToVM; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; public final class ClassRedefinition { @@ -210,12 +208,12 @@ public List detectClassChanges(HotSwapClassInfo[] classInfos) thro DetectedChange detectedChange = new DetectedChange(); StaticObject loader = klass.getDefiningClassLoader(); Types types = klass.getContext().getTypes(); - parserKlass = ClassfileParser.parse(context.getClassLoadingEnv(), new ClassfileStream(bytes, null), loader, types.fromName(hotSwapInfo.getName())); + parserKlass = ParserKlassProvider.parseKlass(ClassRegistry.ClassDefinitionInfo.EMPTY, context.getClassLoadingEnv(), loader, types.fromName(hotSwapInfo.getName()), bytes); if (hotSwapInfo.isPatched()) { byte[] patched = hotSwapInfo.getPatchedBytes(); newParserKlass = parserKlass; // we detect changes against the patched bytecode - parserKlass = ClassfileParser.parse(context.getClassLoadingEnv(), new ClassfileStream(patched, null), loader, types.fromName(hotSwapInfo.getNewName())); + parserKlass = ParserKlassProvider.parseKlass(ClassRegistry.ClassDefinitionInfo.EMPTY, context.getClassLoadingEnv(), loader, types.fromName(hotSwapInfo.getNewName()), patched); } classChange = detectClassChanges(parserKlass, klass, detectedChange, newParserKlass); if (classChange == ClassChange.CLASS_HIERARCHY_CHANGED && detectedChange.getSuperKlass() != null) { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/DetectedChange.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/DetectedChange.java index c936e3cc1c9a..a22343293df8 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/DetectedChange.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/DetectedChange.java @@ -30,12 +30,12 @@ import java.util.Map; import java.util.Set; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.impl.ParserField; -import com.oracle.truffle.espresso.impl.ParserMethod; +import com.oracle.truffle.espresso.classfile.ParserField; +import com.oracle.truffle.espresso.classfile.ParserMethod; public final class DetectedChange { private final List addedStaticFields = new ArrayList<>(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/HotSwapClassInfo.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/HotSwapClassInfo.java index 7a74b432b545..f4f354291689 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/HotSwapClassInfo.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/HotSwapClassInfo.java @@ -25,7 +25,7 @@ import java.util.ArrayList; import java.util.Arrays; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ImmutableClassInfo.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ImmutableClassInfo.java index 21ef93ecb3ed..1a63bab0c3a7 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ImmutableClassInfo.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ImmutableClassInfo.java @@ -22,7 +22,7 @@ */ package com.oracle.truffle.espresso.redefinition; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/InnerClassRedefiner.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/InnerClassRedefiner.java index 639609447c9b..0dd991ccdf37 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/InnerClassRedefiner.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/InnerClassRedefiner.java @@ -22,6 +22,21 @@ */ package com.oracle.truffle.espresso.redefinition; +import com.oracle.truffle.api.TruffleLogger; +import com.oracle.truffle.espresso.EspressoLanguage; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.impl.ClassRegistry; +import com.oracle.truffle.espresso.impl.ConstantPoolPatcher; +import com.oracle.truffle.espresso.impl.Klass; +import com.oracle.truffle.espresso.impl.ObjectKlass; +import com.oracle.truffle.espresso.jdwp.api.ErrorCodes; +import com.oracle.truffle.espresso.jdwp.api.RedefineInfo; +import com.oracle.truffle.espresso.classfile.ParserException; +import com.oracle.truffle.espresso.preinit.ParserKlassProvider; +import com.oracle.truffle.espresso.runtime.EspressoContext; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; @@ -36,20 +51,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.oracle.truffle.api.TruffleLogger; -import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.classfile.ClassfileParser; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.impl.ClassRegistry; -import com.oracle.truffle.espresso.impl.ConstantPoolPatcher; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.jdwp.api.ErrorCodes; -import com.oracle.truffle.espresso.jdwp.api.RedefineInfo; -import com.oracle.truffle.espresso.runtime.EspressoContext; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; - public final class InnerClassRedefiner { private static final TruffleLogger LOGGER = TruffleLogger.getLogger(EspressoLanguage.ID, InnerClassRedefiner.class); @@ -91,7 +92,7 @@ public HotSwapClassInfo[] matchAnonymousInnerClasses(List redefine Iterator it = unhandled.iterator(); while (it.hasNext()) { RedefineInfo redefineInfo = it.next(); - Symbol klassName = ClassfileParser.getClassName(context.getClassLoadingEnv(), redefineInfo.getClassBytes()); + Symbol klassName = ParserKlassProvider.getClassName(context.getMeta(), context.getClassLoadingEnv().getParsingContext(), redefineInfo.getClassBytes()); if (handled.containsKey(klassName)) { LOGGER.warning(() -> "Ignoring duplicate redefinition requests for name " + klassName); it.remove(); @@ -143,7 +144,7 @@ public HotSwapClassInfo[] matchAnonymousInnerClasses(List redefine if (rules != null && !rules.isEmpty()) { try { classInfo.patchBytes(ConstantPoolPatcher.patchConstantPool(classInfo.getBytes(), rules, context)); - } catch (ClassFormatError ex) { + } catch (ParserException.ClassFormatError ex) { throw new RedefinitionNotSupportedException(ErrorCodes.INVALID_CLASS_FORMAT); } } @@ -167,7 +168,7 @@ private void fetchMissingInnerClasses(HotSwapClassInfo hotswapInfo) throws Redef Set> innerNames = new HashSet<>(1); try { searchConstantPoolForDirectInnerAnonymousClassNames(hotswapInfo, innerNames); - } catch (ClassFormatError ex) { + } catch (ParserException.ClassFormatError ex) { throw new RedefinitionNotSupportedException(ErrorCodes.INVALID_CLASS_FORMAT); } @@ -215,7 +216,7 @@ private byte[] readAllBytes(StaticObject inputStream) { } } - private void searchConstantPoolForDirectInnerAnonymousClassNames(ClassInfo classInfo, Set> innerNames) throws ClassFormatError { + private void searchConstantPoolForDirectInnerAnonymousClassNames(ClassInfo classInfo, Set> innerNames) throws ParserException.ClassFormatError { byte[] bytes = classInfo.getBytes(); assert bytes != null; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/plugins/enums/EnumRedefinitionPlugin.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/plugins/enums/EnumRedefinitionPlugin.java index 8f247ebcaf64..810cdb22845e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/plugins/enums/EnumRedefinitionPlugin.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/plugins/enums/EnumRedefinitionPlugin.java @@ -26,7 +26,7 @@ import java.util.HashMap; import java.util.Map; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.impl.ObjectKlass; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/plugins/impl/RedefinitionPluginHandler.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/plugins/impl/RedefinitionPluginHandler.java index c70de206fc46..6bf6d47b9a9a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/plugins/impl/RedefinitionPluginHandler.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/plugins/impl/RedefinitionPluginHandler.java @@ -32,7 +32,7 @@ import java.util.Set; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.jdwp.api.RedefineInfo; import com.oracle.truffle.espresso.jdwp.impl.DebuggerController; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ref/FinalizationSupport.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ref/FinalizationSupport.java index 9a97b4fbeb8b..d78015a0be56 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ref/FinalizationSupport.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ref/FinalizationSupport.java @@ -35,7 +35,7 @@ import com.oracle.truffle.espresso.EspressoOptions; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.runtime.EspressoContext; -import com.oracle.truffle.espresso.runtime.JavaVersion; +import com.oracle.truffle.espresso.classfile.JavaVersion; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.vm.UnsafeAccess; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/resolver/CallSiteType.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/resolver/CallSiteType.java index e1dce80531cb..fa44c51af5a0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/resolver/CallSiteType.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/resolver/CallSiteType.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.resolver; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.classfile.Constants; import com.oracle.truffle.espresso.meta.EspressoError; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/resolver/LinkResolver.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/resolver/LinkResolver.java index f2ae618cd9d2..44c754b35356 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/resolver/LinkResolver.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/resolver/LinkResolver.java @@ -29,10 +29,10 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.espresso.classfile.constantpool.MemberRefConstant; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.constantpool.Resolution; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.impl.ObjectKlass; @@ -104,7 +104,7 @@ public static Method resolveSymbol(Meta meta, ObjectKlass accessingKlass, Symbol throw meta.throwExceptionWithMessage(meta.java_lang_NoSuchMethodError, symbolicHolder.getNameAsString() + "." + name + signature); } if (accessCheck) { - MemberRefConstant.doAccessCheck(accessingKlass, symbolicHolder, resolved, meta); + Resolution.memberDoAccessCheck(accessingKlass, symbolicHolder, resolved, meta); } if (loadingConstraints && !resolved.isPolySignatureIntrinsic()) { resolved.checkLoadingConstraints(accessingKlass.getDefiningClassLoader(), resolved.getDeclaringKlass().getDefiningClassLoader()); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/Classpath.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/Classpath.java index c7244a42d994..d1a563bc1768 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/Classpath.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/Classpath.java @@ -34,9 +34,11 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.ClasspathEntry; +import com.oracle.truffle.espresso.classfile.ClasspathFile; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.substitutions.JImageExtensions; @@ -45,11 +47,11 @@ public final class Classpath { private static final byte[] CLASS_SUFFIX = ".class".getBytes(StandardCharsets.UTF_8); /** - * Creates a classpath {@link Entry} from a given file system path. + * Creates a classpath {@link ClasspathEntry} from a given file system path. * * @param name a file system path denoting a classpath entry */ - public static Entry createEntry(String name) { + public static ClasspathEntry createEntry(String name) { final File pathFile = new File(name); if (pathFile.isDirectory()) { return new Directory(pathFile); @@ -65,62 +67,19 @@ public static Entry createEntry(String name) { try { ZipFile zipFile = new ZipFile(pathFile); return new Archive(pathFile, zipFile); - } catch (IOException e) { + } catch (IOException ignored) { } } return new PlainFile(pathFile); } - private final List entries; - - /** - * An entry in a classpath is a file system path that denotes an existing {@linkplain Directory - * directory}, an existing {@linkplain Archive zip/jar} file or a {@linkplain PlainFile neither} - * . - */ - public abstract static class Entry { - - /** - * Gets the string representing the underlying path of this entry. - */ - public final String path() { - return file().getPath(); - } - - /** - * Gets the File object representing the underlying path of this entry. - */ - public abstract File file(); - - /** - * Gets the contents of a file denoted by a given path that is relative to this classpath - * entry. If the denoted file does not exist under this classpath entry then {@code null} is - * returned. Any IO exception that occurs when reading is silently ignored. - * - * @param archiveName name of the file in an archive with {@code '/'} as the separator - */ - abstract ClasspathFile readFile(ByteSequence archiveName); - - public boolean isDirectory() { - return false; - } - - public boolean isArchive() { - return false; - } - - @Override - public String toString() { - return path(); - } - - } + private final List entries; /** * Represents a classpath entry that is neither an existing directory nor an existing zip/jar * archive file. */ - static final class PlainFile extends Entry { + static final class PlainFile extends ClasspathEntry { private final File file; PlainFile(File file) { @@ -128,7 +87,7 @@ static final class PlainFile extends Entry { } @Override - ClasspathFile readFile(ByteSequence archiveName) { + public ClasspathFile readFile(ByteSequence archiveName) { return null; } @@ -141,7 +100,7 @@ public File file() { /** * Represents a classpath entry that is a path to an existing directory. */ - public static final class Directory extends Entry { + public static final class Directory extends ClasspathEntry { private static final boolean REPLACE_SEPARATOR = File.separatorChar != '/'; private final File directory; @@ -152,7 +111,7 @@ public Directory(File directory) { } @Override - ClasspathFile readFile(ByteSequence archiveName) { + public ClasspathFile readFile(ByteSequence archiveName) { String fsPath = archiveName.toString(); if (REPLACE_SEPARATOR) { fsPath = fsPath.replace('/', File.separatorChar); @@ -182,7 +141,7 @@ public boolean isDirectory() { /** * Represents a classpath entry that is a path to an existing zip/jar archive file. */ - static final class Archive extends Entry { + static final class Archive extends ClasspathEntry { private final File file; private final ZipFile zipFile; @@ -192,13 +151,13 @@ static final class Archive extends Entry { } @Override - ClasspathFile readFile(ByteSequence archiveName) { + public ClasspathFile readFile(ByteSequence archiveName) { try { ZipEntry zipEntry = zipFile.getEntry(archiveName.toString()); if (zipEntry != null) { return new ClasspathFile(readZipEntry(zipFile, zipEntry), this, archiveName); } - } catch (IOException ioException) { + } catch (IOException ignored) { } return null; } @@ -218,7 +177,7 @@ public boolean isArchive() { /** * Represents a classpath entry that is a path to a jimage modules file. */ - static final class Modules extends Entry { + static final class Modules extends ClasspathEntry { private final File file; private final JImageHelper helper; private final JImageExtensions extensions; @@ -235,7 +194,7 @@ public File file() { } @Override - ClasspathFile readFile(ByteSequence archiveName) { + public ClasspathFile readFile(ByteSequence archiveName) { byte[] classBytes = null; if (this.extensions != null) { classBytes = extensions.getClassBytes(archiveName); @@ -256,7 +215,7 @@ ClasspathFile readFile(ByteSequence archiveName) { * * @return a sequence of {@code Entry} objects */ - public List entries() { + public List entries() { return entries; } @@ -266,7 +225,7 @@ public List entries() { * @param paths an array of classpath entries */ public Classpath(String[] paths) { - final Entry[] entryArray = new Entry[paths.length]; + final ClasspathEntry[] entryArray = new ClasspathEntry[paths.length]; for (int i = 0; i < paths.length; ++i) { final String path = paths[i]; entryArray[i] = createEntry(path); @@ -279,7 +238,7 @@ public Classpath(String[] paths) { * * @param entries a sequence of classpath entries */ - public Classpath(List entries) { + public Classpath(List entries) { this.entries = entries; } @@ -299,8 +258,8 @@ public Classpath(String paths) { * @param entry the entry to prepend to this classpath * @return the result of prepending {@code classpath} to this classpath */ - public Classpath prepend(Entry entry) { - ArrayList newEntries = new ArrayList<>(this.entries.size()); + public Classpath prepend(ClasspathEntry entry) { + ArrayList newEntries = new ArrayList<>(this.entries.size()); newEntries.add(entry); newEntries.addAll(this.entries); return new Classpath(newEntries); @@ -328,7 +287,7 @@ public ClasspathFile readClassFile(Symbol type) { } System.arraycopy(CLASS_SUFFIX, 0, archiveNameBytes, type.length() - 2, CLASS_SUFFIX.length); ByteSequence archiveName = ByteSequence.wrap(archiveNameBytes); - for (Entry entry : entries()) { + for (ClasspathEntry entry : entries()) { ClasspathFile classpathFile = entry.readFile(archiveName); if (classpathFile != null) { return classpathFile; 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 3dc5ff7f1406..36b2e7024a4f 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 @@ -66,13 +66,13 @@ import com.oracle.truffle.espresso.analysis.hierarchy.ClassHierarchyOracle; import com.oracle.truffle.espresso.blocking.BlockingSupport; import com.oracle.truffle.espresso.blocking.EspressoLock; -import com.oracle.truffle.espresso.descriptors.Names; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Names; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.ffi.NativeAccess; import com.oracle.truffle.espresso.ffi.NativeAccessCollector; import com.oracle.truffle.espresso.ffi.nfi.NFIIsolatedNativeAccess; @@ -92,9 +92,10 @@ import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.nodes.interop.EspressoForeignProxyGenerator; import com.oracle.truffle.espresso.nodes.interop.PolyglotTypeMappings; -import com.oracle.truffle.espresso.perf.DebugCloseable; -import com.oracle.truffle.espresso.perf.DebugTimer; -import com.oracle.truffle.espresso.perf.TimerCollection; +import com.oracle.truffle.espresso.classfile.JavaVersion; +import com.oracle.truffle.espresso.classfile.perf.DebugCloseable; +import com.oracle.truffle.espresso.classfile.perf.DebugTimer; +import com.oracle.truffle.espresso.classfile.perf.TimerCollection; import com.oracle.truffle.espresso.preinit.ContextPatchingException; import com.oracle.truffle.espresso.preinit.EspressoLanguageCache; import com.oracle.truffle.espresso.redefinition.ClassRedefinition; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoEnv.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoEnv.java index 107cbc732668..dc8df3c508dd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoEnv.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoEnv.java @@ -40,7 +40,7 @@ import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.nodes.interop.EspressoForeignProxyGenerator; import com.oracle.truffle.espresso.nodes.interop.PolyglotTypeMappings; -import com.oracle.truffle.espresso.perf.TimerCollection; +import com.oracle.truffle.espresso.classfile.perf.TimerCollection; import com.oracle.truffle.espresso.ref.FinalizationSupport; import com.oracle.truffle.espresso.threads.EspressoThreadRegistry; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoShutdownHandler.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoShutdownHandler.java index 509bdb4cfc41..41905d4e3b6d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoShutdownHandler.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoShutdownHandler.java @@ -33,8 +33,8 @@ import com.oracle.truffle.espresso.blocking.EspressoLock; import com.oracle.truffle.espresso.blocking.GuestInterruptedException; import com.oracle.truffle.espresso.impl.ContextAccessImpl; -import com.oracle.truffle.espresso.perf.DebugCloseable; -import com.oracle.truffle.espresso.perf.DebugTimer; +import com.oracle.truffle.espresso.classfile.perf.DebugCloseable; +import com.oracle.truffle.espresso.classfile.perf.DebugTimer; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.threads.EspressoThreadRegistry; import com.oracle.truffle.espresso.threads.ThreadsAccess; 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 b133d3f2cb39..4ed81c3f8014 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 @@ -51,7 +51,7 @@ import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.impl.PackageTable; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.substitutions.JavaType; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JDWPContextImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JDWPContextImpl.java index b81cc1f85b74..bf66d8479932 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JDWPContextImpl.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JDWPContextImpl.java @@ -47,8 +47,8 @@ import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.blocking.EspressoLock; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ArrayKlass; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Method.MethodVersion; @@ -446,7 +446,7 @@ public byte getArrayComponentTag(Object array) { if (arrayKlass.getDimension() > 1) { return TagConstants.ARRAY; } - return arrayKlass.getComponentType().getJavaKind().toTagConstant(); + return TagConstants.toTagConstant(arrayKlass.getComponentType().getJavaKind()); } // introspection diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JImageHelper.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JImageHelper.java index 8c7262e7fe10..6a80fe875807 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JImageHelper.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JImageHelper.java @@ -23,7 +23,7 @@ package com.oracle.truffle.espresso.runtime; -import com.oracle.truffle.espresso.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; public interface JImageHelper { void close(); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JImageLibrary.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JImageLibrary.java index d48551cfc706..d1939386e82b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JImageLibrary.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JImageLibrary.java @@ -33,9 +33,9 @@ import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; import com.oracle.truffle.espresso.ffi.NativeSignature; import com.oracle.truffle.espresso.ffi.NativeType; import com.oracle.truffle.espresso.ffi.nfi.NativeUtils; @@ -43,7 +43,7 @@ import com.oracle.truffle.espresso.impl.PackageTable.PackageEntry; import com.oracle.truffle.espresso.jni.RawBuffer; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; @SuppressWarnings("unused") final class JImageLibrary extends ContextAccessImpl { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JavaJImageHelper.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JavaJImageHelper.java index 9ac1f374fb9b..28b652eb712d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JavaJImageHelper.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/JavaJImageHelper.java @@ -26,8 +26,8 @@ import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.PackageTable; import com.oracle.truffle.espresso.runtime.jimage.BasicImageReader; import com.oracle.truffle.espresso.runtime.jimage.ImageLocation; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/LazyContextCaches.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/LazyContextCaches.java index 52f23038cfd3..cba7df04a5e5 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/LazyContextCaches.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/LazyContextCaches.java @@ -33,7 +33,7 @@ import com.oracle.truffle.espresso.meta.InteropKlassesDispatch; import com.oracle.truffle.espresso.nodes.commands.AddPathToBindingsCache; import com.oracle.truffle.espresso.nodes.commands.ReferenceProcessCache; -import com.oracle.truffle.espresso.nodes.quick.VolatileArrayAccess; +import com.oracle.truffle.espresso.classfile.bytecode.VolatileArrayAccess; import com.oracle.truffle.espresso.runtime.dispatch.messages.InteropMessage; import com.oracle.truffle.espresso.runtime.dispatch.messages.InteropMessageFactories; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/MethodHandleIntrinsics.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/MethodHandleIntrinsics.java index cb2c47f0110e..91855ee4222e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/MethodHandleIntrinsics.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/MethodHandleIntrinsics.java @@ -26,11 +26,11 @@ import java.util.concurrent.ConcurrentHashMap; import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.meta.EspressoError; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/NativeJImageHelper.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/NativeJImageHelper.java index 9d1a5acd213b..bb14ecee6937 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/NativeJImageHelper.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/NativeJImageHelper.java @@ -24,7 +24,7 @@ package com.oracle.truffle.espresso.runtime; import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.espresso.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; public class NativeJImageHelper implements JImageHelper { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/StringTable.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/StringTable.java index 84b8c70b8479..f9bf1df6366b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/StringTable.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/StringTable.java @@ -26,7 +26,7 @@ import java.util.function.Function; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.substitutions.JavaType; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/dispatch/staticobject/BaseInterop.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/dispatch/staticobject/BaseInterop.java index ca05089f3be7..d6408e6bb08a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/dispatch/staticobject/BaseInterop.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/dispatch/staticobject/BaseInterop.java @@ -23,8 +23,6 @@ package com.oracle.truffle.espresso.runtime.dispatch.staticobject; -import static com.oracle.truffle.espresso.vm.InterpreterToVM.instanceOf; - import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.dsl.Cached; @@ -40,13 +38,15 @@ import com.oracle.truffle.api.utilities.TriState; import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.meta.Meta; +import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.runtime.dispatch.messages.GenerateInteropNodes; import com.oracle.truffle.espresso.runtime.dispatch.messages.Shareable; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.vm.VM; +import static com.oracle.truffle.espresso.vm.InterpreterToVM.instanceOf; + /** * BaseInterop (isNull, is/asString, meta-instance, identity, exceptions, toDisplayString) Support * Espresso and foreign objects and null. diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/dispatch/staticobject/ThrowableInterop.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/dispatch/staticobject/ThrowableInterop.java index 53f07247ae28..473bd868db08 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/dispatch/staticobject/ThrowableInterop.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/dispatch/staticobject/ThrowableInterop.java @@ -28,7 +28,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/jimage/BasicImageReader.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/jimage/BasicImageReader.java index 98867b4a2890..d8aadbf9ba09 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/jimage/BasicImageReader.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/jimage/BasicImageReader.java @@ -32,7 +32,7 @@ import java.util.Objects; import com.oracle.truffle.api.TruffleLogger; -import com.oracle.truffle.espresso.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; import com.oracle.truffle.espresso.runtime.jimage.decompressor.Decompressor; import com.oracle.truffle.espresso.runtime.jimage.decompressor.ResourceDecompressor; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/jimage/ImageLocation.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/jimage/ImageLocation.java index 8b7b40fa2817..6d07b3696a46 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/jimage/ImageLocation.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/jimage/ImageLocation.java @@ -26,7 +26,7 @@ import java.nio.ByteBuffer; import java.util.Objects; -import com.oracle.truffle.espresso.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; public class ImageLocation { private static final int ATTRIBUTE_END = 0; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/jimage/ImageStringsReader.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/jimage/ImageStringsReader.java index d9baf3e296aa..d08d74cbd650 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/jimage/ImageStringsReader.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/jimage/ImageStringsReader.java @@ -27,9 +27,9 @@ import java.nio.ByteBuffer; import java.util.Objects; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Validation; -import com.oracle.truffle.espresso.jni.ModifiedUtf8; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Validation; +import com.oracle.truffle.espresso.classfile.descriptors.ModifiedUtf8; public class ImageStringsReader { public static final int HASH_MULTIPLIER = 0x01000193; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/staticobject/StaticObject.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/staticobject/StaticObject.java index 0a401c361980..453fd12b49c9 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/staticobject/StaticObject.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/staticobject/StaticObject.java @@ -34,7 +34,7 @@ import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.blocking.BlockingSupport; import com.oracle.truffle.espresso.blocking.EspressoLock; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.ArrayKlass; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.impl.Klass; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/JImageExtensions.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/JImageExtensions.java index 43eb3a270ed1..b43991f564c6 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/JImageExtensions.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/JImageExtensions.java @@ -30,7 +30,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import com.oracle.truffle.espresso.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.runtime.Classpath; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/JavaSubstitution.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/JavaSubstitution.java index eb2ffcecc1f0..3457e0dc54f7 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/JavaSubstitution.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/JavaSubstitution.java @@ -28,7 +28,7 @@ import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.nodes.quick.invoke.inline.InlinedFrameAccess; import com.oracle.truffle.espresso.nodes.quick.invoke.inline.InlinedMethodPredicate; -import com.oracle.truffle.espresso.runtime.JavaVersion; +import com.oracle.truffle.espresso.classfile.JavaVersion; public abstract class JavaSubstitution extends SubstitutionProfiler { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Substitutions.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Substitutions.java index aba09ee23fab..c698ec9e0c10 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Substitutions.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Substitutions.java @@ -37,12 +37,12 @@ import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.descriptors.StaticSymbols; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.StaticSymbols; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.ClassLoadingEnv; import com.oracle.truffle.espresso.impl.ContextAccessImpl; import com.oracle.truffle.espresso.impl.Method; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_System.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_System.java index 931552cd69a4..05b8de3605fe 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_System.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_System.java @@ -42,7 +42,7 @@ import com.oracle.truffle.espresso.nodes.helper.TypeCheckNodeGen; import com.oracle.truffle.espresso.nodes.interop.ToEspressoNode; import com.oracle.truffle.espresso.nodes.interop.ToEspressoNodeFactory; -import com.oracle.truffle.espresso.perf.DebugCounter; +import com.oracle.truffle.espresso.classfile.perf.DebugCounter; import com.oracle.truffle.espresso.runtime.EspressoException; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.vm.VM; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_invoke_MethodHandleNatives.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_invoke_MethodHandleNatives.java index 093bb246b067..7ad863eb1564 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_invoke_MethodHandleNatives.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_invoke_MethodHandleNatives.java @@ -22,6 +22,43 @@ */ package com.oracle.truffle.espresso.substitutions; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.BranchProfile; +import com.oracle.truffle.espresso.EspressoLanguage; +import com.oracle.truffle.espresso.constantpool.Resolution; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; +import com.oracle.truffle.espresso.impl.Field; +import com.oracle.truffle.espresso.impl.Klass; +import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.impl.ObjectKlass; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.meta.Meta; +import com.oracle.truffle.espresso.nodes.EspressoNode; +import com.oracle.truffle.espresso.resolver.CallSiteType; +import com.oracle.truffle.espresso.resolver.LinkResolver; +import com.oracle.truffle.espresso.resolver.ResolvedCall; +import com.oracle.truffle.espresso.runtime.EspressoContext; +import com.oracle.truffle.espresso.runtime.EspressoException; +import com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics; +import com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics.PolySigIntrinsics; +import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; +import org.graalvm.collections.Pair; + +import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandle; +import java.util.ArrayList; +import java.util.List; + +import static com.oracle.truffle.espresso.meta.EspressoError.cat; import static com.oracle.truffle.espresso.classfile.Constants.ACC_STATIC; import static com.oracle.truffle.espresso.classfile.Constants.REF_LIMIT; import static com.oracle.truffle.espresso.classfile.Constants.REF_NONE; @@ -34,7 +71,6 @@ import static com.oracle.truffle.espresso.classfile.Constants.REF_newInvokeSpecial; import static com.oracle.truffle.espresso.classfile.Constants.REF_putField; import static com.oracle.truffle.espresso.classfile.Constants.REF_putStatic; -import static com.oracle.truffle.espresso.meta.EspressoError.cat; import static com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics.PolySigIntrinsics.InvokeGeneric; import static com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics.PolySigIntrinsics.None; import static com.oracle.truffle.espresso.substitutions.Target_java_lang_invoke_MethodHandleNatives.Constants.ALL_KINDS; @@ -48,43 +84,6 @@ import static com.oracle.truffle.espresso.substitutions.Target_java_lang_invoke_MethodHandleNatives.Constants.MN_REFERENCE_KIND_MASK; import static com.oracle.truffle.espresso.substitutions.Target_java_lang_invoke_MethodHandleNatives.Constants.MN_REFERENCE_KIND_SHIFT; -import java.lang.invoke.CallSite; -import java.lang.invoke.MethodHandle; -import java.util.ArrayList; -import java.util.List; - -import org.graalvm.collections.Pair; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Bind; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.profiles.BranchProfile; -import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.classfile.constantpool.MemberRefConstant; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; -import com.oracle.truffle.espresso.impl.Field; -import com.oracle.truffle.espresso.impl.Klass; -import com.oracle.truffle.espresso.impl.Method; -import com.oracle.truffle.espresso.impl.ObjectKlass; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.Meta; -import com.oracle.truffle.espresso.nodes.EspressoNode; -import com.oracle.truffle.espresso.resolver.CallSiteType; -import com.oracle.truffle.espresso.resolver.LinkResolver; -import com.oracle.truffle.espresso.resolver.ResolvedCall; -import com.oracle.truffle.espresso.runtime.EspressoContext; -import com.oracle.truffle.espresso.runtime.EspressoException; -import com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics; -import com.oracle.truffle.espresso.runtime.MethodHandleIntrinsics.PolySigIntrinsics; -import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; - @EspressoSubstitutions public final class Target_java_lang_invoke_MethodHandleNatives { /** @@ -627,7 +626,7 @@ private static void plantFieldMemberName(StaticObject memberName, throw meta.throwExceptionWithMessage(meta.java_lang_NoSuchFieldError, cat("Failed lookup for field ", resolutionKlass.getName(), "#", name, ":", type)); } if (accessCheck) { - MemberRefConstant.doAccessCheck(callerKlass, field.getDeclaringKlass(), field, meta); + Resolution.memberDoAccessCheck(callerKlass, field.getDeclaringKlass(), field, meta); } if (constraintsCheck) { field.checkLoadingConstraints(callerKlass.getDefiningClassLoader(), resolutionKlass.getDefiningClassLoader()); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_Array.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_Array.java index 8437785a30ab..14fe60aaf697 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_Array.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_reflect_Array.java @@ -32,7 +32,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.ArrayKlass; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.meta.EspressoError; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_util_regex_Matcher.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_util_regex_Matcher.java index 1aa2bd4ff63a..64f234cdbbfd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_util_regex_Matcher.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_util_regex_Matcher.java @@ -59,7 +59,7 @@ import com.oracle.truffle.espresso.nodes.EspressoInlineNode; import com.oracle.truffle.espresso.nodes.bytecodes.InvokeInterface; import com.oracle.truffle.espresso.runtime.EspressoContext; -import com.oracle.truffle.espresso.runtime.JavaVersion; +import com.oracle.truffle.espresso.classfile.JavaVersion; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; @EspressoSubstitutions diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_jdk_internal_misc_ScopedMemoryAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_jdk_internal_misc_ScopedMemoryAccess.java index 2734ad955306..24c5fed5b084 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_jdk_internal_misc_ScopedMemoryAccess.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_jdk_internal_misc_ScopedMemoryAccess.java @@ -100,8 +100,7 @@ public Object visitFrame(FrameInstance frameInstance) { assert method.getLocalVariableTable() != LocalVariableTable.EMPTY_LVT; Local[] locals = method.getLocalVariableTable().getLocalsAt(bci); for (Local local : locals) { - // primitive types have length 1, object types have length > 1 - if (local.getType().value().length() > 1) { + if (local.getJavaKind().isObject()) { if (EspressoFrame.getLocalObject(frame, local.getSlot()) == value) { found = true; return this; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_jdk_internal_module_ModuleLoaderMap_Modules.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_jdk_internal_module_ModuleLoaderMap_Modules.java index 6d67e5727b17..615ab5a2c811 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_jdk_internal_module_ModuleLoaderMap_Modules.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_jdk_internal_module_ModuleLoaderMap_Modules.java @@ -31,9 +31,9 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.DirectCallNode; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.Field; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.EspressoContext; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_misc_Unsafe.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_misc_Unsafe.java index 7cae2a88def8..da0ec3e054fe 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_misc_Unsafe.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_misc_Unsafe.java @@ -45,8 +45,8 @@ import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.blocking.EspressoLock; import com.oracle.truffle.espresso.blocking.GuestInterruptedException; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; import com.oracle.truffle.espresso.ffi.Buffer; import com.oracle.truffle.espresso.ffi.RawPointer; import com.oracle.truffle.espresso.impl.ArrayKlass; @@ -56,14 +56,14 @@ import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.meta.MetaUtil; import com.oracle.truffle.espresso.nodes.EspressoInlineNode; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.EspressoException; import com.oracle.truffle.espresso.runtime.GuestAllocator; -import com.oracle.truffle.espresso.runtime.JavaVersion; +import com.oracle.truffle.espresso.classfile.JavaVersion; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.threads.State; import com.oracle.truffle.espresso.threads.Transition; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java index 57d8a113f9b5..5055ce17a767 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java @@ -30,13 +30,13 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Method; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.nodes.interop.ToEspressoNode; import com.oracle.truffle.espresso.resolver.CallKind; 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 5a5cb3fd6818..d993bc73e692 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 @@ -22,7 +22,7 @@ */ package com.oracle.truffle.espresso.substitutions; -import com.oracle.truffle.espresso.runtime.JavaVersion; +import com.oracle.truffle.espresso.classfile.JavaVersion; @FunctionalInterface public interface VersionFilter { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/EspressoThreadRegistry.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/EspressoThreadRegistry.java index 0e8ad4b678e8..06b66b4c4488 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/EspressoThreadRegistry.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/threads/EspressoThreadRegistry.java @@ -36,7 +36,7 @@ import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.blocking.EspressoLock; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ContextAccessImpl; import com.oracle.truffle.espresso.impl.SuppressFBWarnings; import com.oracle.truffle.espresso.meta.Meta; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/MethodVerifier.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/MethodVerifier.java index c39024e4a899..7102a500debe 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/MethodVerifier.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/MethodVerifier.java @@ -22,211 +22,211 @@ */ package com.oracle.truffle.espresso.verifier; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.AALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.AASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ACONST_NULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ANEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ARETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ARRAYLENGTH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ATHROW; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BIPUSH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BREAKPOINT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CHECKCAST; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCMPG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCMPL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP2_X1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP2_X2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP_X1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP_X2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCMPG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCMPL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GETFIELD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GETSTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GOTO; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GOTO_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2B; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2C; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2S; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IAND; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_4; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_5; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_M1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFEQ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFGE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFGT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFLE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFLT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFNE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFNONNULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFNULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ACMPEQ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ACMPNE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPEQ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPGE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPGT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPLE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPLT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPNE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IINC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INSTANCEOF; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEDYNAMIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEINTERFACE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKESPECIAL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKESTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEVIRTUAL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISHL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IUSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IXOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.JSR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.JSR_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LAND; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCMP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDC2_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDC_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LOOKUPSWITCH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSHL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LUSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LXOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MONITORENTER; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MONITOREXIT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MULTIANEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NEW; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NOP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.POP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.POP2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTFIELD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTSTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.QUICK; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.RET; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.RETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SIPUSH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SLIM_QUICK; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SWAP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.TABLESWITCH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.WIDE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.AALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.AASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ACONST_NULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ANEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ARETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ARRAYLENGTH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ATHROW; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BIPUSH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BREAKPOINT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CHECKCAST; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCMPG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCMPL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP2_X1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP2_X2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP_X1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP_X2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCMPG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCMPL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GETFIELD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GETSTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GOTO; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GOTO_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2B; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2C; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2S; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IAND; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_4; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_5; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_M1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFEQ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFGE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFGT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFLE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFLT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFNE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFNONNULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFNULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ACMPEQ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ACMPNE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPEQ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPGE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPGT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPLE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPLT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPNE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IINC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INSTANCEOF; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEDYNAMIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEINTERFACE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKESPECIAL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKESTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEVIRTUAL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISHL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IUSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IXOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.JSR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.JSR_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LAND; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCMP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDC2_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDC_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LOOKUPSWITCH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSHL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LUSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LXOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MONITORENTER; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MONITOREXIT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MULTIANEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NEW; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NOP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.POP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.POP2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.PUTFIELD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.PUTSTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.QUICK; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.RET; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.RETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SIPUSH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SLIM_QUICK; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SWAP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.TABLESWITCH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.WIDE; import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.CLASS; import static com.oracle.truffle.espresso.classfile.ConstantPool.Tag.INTERFACE_METHOD_REF; import static com.oracle.truffle.espresso.classfile.Constants.ITEM_Bogus; @@ -244,14 +244,16 @@ import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.analysis.frame.EspressoFrameDescriptor; import com.oracle.truffle.espresso.analysis.frame.FrameType; -import com.oracle.truffle.espresso.bytecode.BytecodeLookupSwitch; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; -import com.oracle.truffle.espresso.bytecode.BytecodeSwitch; -import com.oracle.truffle.espresso.bytecode.BytecodeTableSwitch; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.ParserException; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeLookupSwitch; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeSwitch; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeTableSwitch; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.descriptors.ValidationException; import com.oracle.truffle.espresso.classfile.ClassfileParser; import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; +import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool; import com.oracle.truffle.espresso.classfile.attributes.CodeAttribute; import com.oracle.truffle.espresso.classfile.attributes.StackMapTableAttribute; import com.oracle.truffle.espresso.classfile.constantpool.ClassConstant; @@ -261,23 +263,23 @@ import com.oracle.truffle.espresso.classfile.constantpool.MemberRefConstant; import com.oracle.truffle.espresso.classfile.constantpool.MethodRefConstant; import com.oracle.truffle.espresso.classfile.constantpool.PoolConstant; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; -import com.oracle.truffle.espresso.descriptors.Validation; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Validation; import com.oracle.truffle.espresso.impl.ContextAccess; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Member; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.ExceptionHandler; -import com.oracle.truffle.espresso.meta.JavaKind; -import com.oracle.truffle.espresso.perf.DebugCloseable; -import com.oracle.truffle.espresso.perf.DebugTimer; +import com.oracle.truffle.espresso.classfile.ExceptionHandler; +import com.oracle.truffle.espresso.classfile.JavaKind; +import com.oracle.truffle.espresso.classfile.perf.DebugCloseable; +import com.oracle.truffle.espresso.classfile.perf.DebugTimer; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; @@ -664,6 +666,9 @@ public static MethodVerifier verify(Method m) { } else { throw e; } + } catch (ParserException.ClassFormatError e) { + // There was an error during parsing e.g. invalid StackMapTable attribute. + throw failFormat(e.getMessage()); } return verifier; } @@ -864,7 +869,7 @@ private void initSwitch(int bci, int opCode) { * attribute exists, it still constructs the first implicit StackFrame, with the method * arguments in the locals and an empty stack. */ - private void initStackFrames() { + private void initStackFrames() throws ParserException.ClassFormatError { // First implicit stack frame. StackFrame previous = new StackFrame(this); assert stackFrames.length > 0; @@ -1294,6 +1299,14 @@ private void startVerify(int bci, OperandStack seedStack, Locals seedLocals) { calledConstructor = constructorCalledStatus; } + static void validateOrFailVerification(PoolConstant poolConstant, ConstantPool pool) { + try { + poolConstant.validate(pool); + } catch (ValidationException e) { + throw failVerify(e.getMessage()); + } + } + /** * Checks that an instruction can merge into all its handlers. */ @@ -1409,7 +1422,7 @@ private int verify(int bci, OperandStack stack, Locals locals) { case LDC: case LDC_W: { PoolConstant pc = poolAt(code.readCPI(bci)); - pc.validate(pool); + validateOrFailVerification(pc, pool); Operand op = ldcFromTag(pc); verifyGuarantee(!isType2(op), "Loading Long or Double with LDC or LDC_W, please use LDC2_W."); if (earlierThan49()) { @@ -1420,7 +1433,7 @@ private int verify(int bci, OperandStack stack, Locals locals) { } case LDC2_W: { PoolConstant pc = poolAt(code.readCPI(bci)); - pc.validate(pool); + validateOrFailVerification(pc, pool); Operand op = ldcFromTag(pc); verifyGuarantee(isType2(op), "Loading non-Long or Double with LDC2_W, please use LDC or LDC_W."); stack.push(op); @@ -1714,7 +1727,7 @@ private void verifyInvokeDynamic(int bci, OperandStack stack) { // Check CP validity verifyGuarantee(pc.tag() == ConstantPool.Tag.INVOKEDYNAMIC, "Invalid CP constant for INVOKEDYNAMIC: " + pc.toString()); - pc.validate(pool); + validateOrFailVerification(pc, pool); InvokeDynamicConstant idc = (InvokeDynamicConstant) pc; Symbol name = idc.getName(pool); @@ -1739,7 +1752,7 @@ private void verifyInvokeDynamic(int bci, OperandStack stack) { private Symbol getTypeFromPool(int c, String s) { PoolConstant pc = poolAt(c); verifyGuarantee(pc.tag() == CLASS, s + pc.toString()); - pc.validate(pool); + validateOrFailVerification(pc, pool); ClassConstant cc = (ClassConstant) pc; assert Validation.validClassNameEntry(cc.getName(pool)); Symbol type = getTypes().fromName(cc.getName(pool)); @@ -1838,7 +1851,7 @@ private void verifyPutField(int bci, OperandStack stack, int curOpcode) { // Check CP validity PoolConstant pc = poolAt(code.readCPI(bci)); verifyGuarantee(pc.tag() == ConstantPool.Tag.FIELD_REF, "Invalid CP constant for PUTFIELD: " + pc.toString()); - pc.validate(pool); + validateOrFailVerification(pc, pool); // Obtain field info FieldRefConstant frc = (FieldRefConstant) pc; @@ -1864,7 +1877,7 @@ private void verifyGetField(int bci, OperandStack stack, int curOpcode) { // Check CP validity PoolConstant pc = poolAt(code.readCPI(bci)); verifyGuarantee(pc.tag() == ConstantPool.Tag.FIELD_REF, "Invalid CP constant for GETFIELD: " + pc.toString()); - pc.validate(pool); + validateOrFailVerification(pc, pool); // Obtain field info FieldRefConstant frc = (FieldRefConstant) pc; @@ -1972,7 +1985,7 @@ private void verifyRET(int bci, OperandStack stack, Locals locals) { private MethodRefConstant getMethodRefConstant(int bci) { PoolConstant pc = poolAt(code.readCPI(bci)); verifyGuarantee(pc instanceof MethodRefConstant, "Invalid CP constant for a MethodRef: " + pc.getClass().getName()); - pc.validate(pool); + validateOrFailVerification(pc, pool); return (MethodRefConstant) pc; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/Operand.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/Operand.java index 16e6e378195c..06dd7466fe71 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/Operand.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/Operand.java @@ -30,11 +30,11 @@ import java.util.ArrayList; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.runtime.EspressoException; abstract class Operand { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/StackFrame.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/StackFrame.java index 6c3dbc71c009..5c27d9f0e77f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/StackFrame.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/StackFrame.java @@ -33,7 +33,7 @@ import static com.oracle.truffle.espresso.verifier.MethodVerifier.isType2; import static com.oracle.truffle.espresso.verifier.MethodVerifier.verifyGuarantee; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; import com.oracle.truffle.espresso.meta.EspressoError; class StackFrame implements StackMapFrameParser.FrameState { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/StackMapFrameParser.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/StackMapFrameParser.java index a1fb774c5fdf..1dd9ba23d833 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/StackMapFrameParser.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/StackMapFrameParser.java @@ -37,9 +37,10 @@ import static com.oracle.truffle.espresso.verifier.MethodVerifier.failFormatNoFallback; import com.oracle.truffle.espresso.classfile.ClassfileStream; +import com.oracle.truffle.espresso.classfile.ParserException; import com.oracle.truffle.espresso.classfile.attributes.StackMapTableAttribute; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; public final class StackMapFrameParser { @@ -121,12 +122,13 @@ private StackMapFrameParser(FrameBuilder frameBuilder, StackMapTableAttribute this.stream = new ClassfileStream(stackMapTable.getData(), null); } - public static void parse(FrameBuilder builder, StackMapTableAttribute stackMapTable, State firstFrame, int initialLastLocal) { + public static void parse(FrameBuilder builder, StackMapTableAttribute stackMapTable, State firstFrame, int initialLastLocal) + throws ParserException.ClassFormatError { new StackMapFrameParser<>(builder, stackMapTable).parseStackMapTableAttribute(firstFrame, initialLastLocal); } @SuppressWarnings("unchecked") - private void parseStackMapTableAttribute(T firstFrame, int initialLastLocal) { + private void parseStackMapTableAttribute(T firstFrame, int initialLastLocal) throws ParserException.ClassFormatError { T previous = firstFrame; int bci = 0; boolean first = true; @@ -173,7 +175,7 @@ private FrameAndLocalEffect nextFrame(StackMapFrame entry, T previous, int lastL throw EspressoError.shouldNotReachHere(); } - private StackMapFrame parseStackMapFrame() { + private StackMapFrame parseStackMapFrame() throws ParserException.ClassFormatError { int frameType = stream.readU1(); if (frameType < SAME_FRAME_BOUND) { return new SameFrame(frameType); @@ -225,7 +227,7 @@ private StackMapFrame parseStackMapFrame() { throw failFormat("Unrecognized StackMapFrame tag: " + frameType); } - private VerificationTypeInfo parseVerificationTypeInfo() { + private VerificationTypeInfo parseVerificationTypeInfo() throws ParserException.ClassFormatError { int tag = stream.readU1(); if (tag < ITEM_InitObject) { return PrimitiveTypeInfo.get(tag); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/VerificationTypeInfo.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/VerificationTypeInfo.java index 0922953f6372..f170330552db 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/VerificationTypeInfo.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/verifier/VerificationTypeInfo.java @@ -33,11 +33,11 @@ import static com.oracle.truffle.espresso.classfile.Constants.ITEM_Null; import static com.oracle.truffle.espresso.classfile.Constants.ITEM_Object; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.ObjectKlass; import com.oracle.truffle.espresso.meta.EspressoError; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java index a37795d9047b..6abe4ab36d50 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java @@ -40,7 +40,7 @@ import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.blocking.EspressoLock; import com.oracle.truffle.espresso.blocking.GuestInterruptedException; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; import com.oracle.truffle.espresso.impl.ArrayKlass; import com.oracle.truffle.espresso.impl.ContextAccessImpl; import com.oracle.truffle.espresso.impl.Field; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/Management.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/Management.java index 7984a27a1250..bf1a0a95fd4e 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/Management.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/Management.java @@ -54,7 +54,7 @@ import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.ffi.NativeSignature; import com.oracle.truffle.espresso.ffi.NativeType; import com.oracle.truffle.espresso.ffi.Pointer; @@ -65,7 +65,7 @@ import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.jni.NativeEnv; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/ModulesHelperVM.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/ModulesHelperVM.java index 937c5f987ecb..7145dd32ef01 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/ModulesHelperVM.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/ModulesHelperVM.java @@ -25,7 +25,7 @@ import static com.oracle.truffle.espresso.meta.EspressoError.cat; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.impl.ModuleTable; import com.oracle.truffle.espresso.impl.PackageTable; import com.oracle.truffle.espresso.meta.Meta; 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 8ef96f5f9fdf..2d4ff68ec033 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 @@ -30,9 +30,9 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameInstance; import com.oracle.truffle.api.frame.FrameInstanceVisitor; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; import com.oracle.truffle.espresso.impl.Klass; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.meta.EspressoError; 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 ea4c12c3e0b0..c15063ff2023 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 @@ -22,48 +22,6 @@ */ package com.oracle.truffle.espresso.vm; -import static com.oracle.truffle.espresso.classfile.Constants.ACC_ABSTRACT; -import static com.oracle.truffle.espresso.classfile.Constants.ACC_FINAL; -import static com.oracle.truffle.espresso.classfile.Constants.ACC_LAMBDA_FORM_COMPILED; -import static com.oracle.truffle.espresso.classfile.Constants.ACC_PUBLIC; -import static com.oracle.truffle.espresso.jni.JniEnv.JNI_EDETACHED; -import static com.oracle.truffle.espresso.jni.JniEnv.JNI_ERR; -import static com.oracle.truffle.espresso.jni.JniEnv.JNI_EVERSION; -import static com.oracle.truffle.espresso.jni.JniEnv.JNI_OK; -import static com.oracle.truffle.espresso.meta.EspressoError.cat; -import static com.oracle.truffle.espresso.runtime.Classpath.JAVA_BASE; -import static com.oracle.truffle.espresso.runtime.EspressoContext.DEFAULT_STACK_SIZE; -import static com.oracle.truffle.espresso.substitutions.Target_java_lang_invoke_MethodHandleNatives.Constants.ACCESS_VM_ANNOTATIONS; -import static com.oracle.truffle.espresso.substitutions.Target_java_lang_invoke_MethodHandleNatives.Constants.HIDDEN_CLASS; -import static com.oracle.truffle.espresso.substitutions.Target_java_lang_invoke_MethodHandleNatives.Constants.NESTMATE_CLASS; -import static com.oracle.truffle.espresso.substitutions.Target_java_lang_invoke_MethodHandleNatives.Constants.STRONG_LOADER_LINK; - -import java.io.File; -import java.lang.ref.Reference; -import java.lang.reflect.Array; -import java.lang.reflect.Constructor; -import java.lang.reflect.Parameter; -import java.nio.ByteBuffer; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.StringJoiner; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicLongFieldUpdater; -import java.util.function.IntFunction; -import java.util.logging.Level; - -import org.graalvm.collections.EconomicMap; -import org.graalvm.options.OptionValues; - import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; @@ -85,23 +43,14 @@ import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.EspressoOptions; import com.oracle.truffle.espresso.blocking.GuestInterruptedException; -import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.classfile.Constants; -import com.oracle.truffle.espresso.classfile.RuntimeConstantPool; -import com.oracle.truffle.espresso.classfile.attributes.EnclosingMethodAttribute; -import com.oracle.truffle.espresso.classfile.attributes.InnerClassesAttribute; -import com.oracle.truffle.espresso.classfile.attributes.MethodParametersAttribute; -import com.oracle.truffle.espresso.classfile.attributes.PermittedSubclassesAttribute; -import com.oracle.truffle.espresso.classfile.attributes.RecordAttribute; -import com.oracle.truffle.espresso.classfile.attributes.SignatureAttribute; -import com.oracle.truffle.espresso.classfile.constantpool.NameAndTypeConstant; -import com.oracle.truffle.espresso.descriptors.ByteSequence; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; -import com.oracle.truffle.espresso.descriptors.Validation; +import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool; +import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Validation; import com.oracle.truffle.espresso.ffi.NativeSignature; import com.oracle.truffle.espresso.ffi.NativeType; import com.oracle.truffle.espresso.ffi.Pointer; @@ -125,16 +74,26 @@ import com.oracle.truffle.espresso.jni.NativeEnv; import com.oracle.truffle.espresso.jni.NoSafepoint; import com.oracle.truffle.espresso.jvmti.JVMTI; -import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.meta.MetaUtil; import com.oracle.truffle.espresso.nodes.EspressoFrame; import com.oracle.truffle.espresso.nodes.EspressoRootNode; import com.oracle.truffle.espresso.nodes.interop.ToEspressoNode; import com.oracle.truffle.espresso.nodes.interop.ToEspressoNodeFactory; +import com.oracle.truffle.espresso.classfile.ClasspathEntry; +import com.oracle.truffle.espresso.classfile.ConstantPool; +import com.oracle.truffle.espresso.classfile.Constants; +import com.oracle.truffle.espresso.meta.EspressoError; +import com.oracle.truffle.espresso.classfile.JavaKind; +import com.oracle.truffle.espresso.classfile.attributes.Attribute; +import com.oracle.truffle.espresso.classfile.attributes.EnclosingMethodAttribute; +import com.oracle.truffle.espresso.classfile.attributes.InnerClassesAttribute; +import com.oracle.truffle.espresso.classfile.attributes.MethodParametersAttribute; +import com.oracle.truffle.espresso.classfile.attributes.PermittedSubclassesAttribute; +import com.oracle.truffle.espresso.classfile.attributes.RecordAttribute; +import com.oracle.truffle.espresso.classfile.attributes.SignatureAttribute; +import com.oracle.truffle.espresso.classfile.constantpool.NameAndTypeConstant; import com.oracle.truffle.espresso.ref.EspressoReference; -import com.oracle.truffle.espresso.runtime.Attribute; import com.oracle.truffle.espresso.runtime.Classpath; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.EspressoException; @@ -159,6 +118,47 @@ import com.oracle.truffle.espresso.vm.structs.JavaVMAttachArgs; import com.oracle.truffle.espresso.vm.structs.Structs; import com.oracle.truffle.espresso.vm.structs.StructsAccess; +import org.graalvm.collections.EconomicMap; +import org.graalvm.options.OptionValues; + +import java.io.File; +import java.lang.ref.Reference; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Parameter; +import java.nio.ByteBuffer; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.StringJoiner; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; +import java.util.function.IntFunction; +import java.util.logging.Level; + +import static com.oracle.truffle.espresso.jni.JniEnv.JNI_EDETACHED; +import static com.oracle.truffle.espresso.jni.JniEnv.JNI_ERR; +import static com.oracle.truffle.espresso.jni.JniEnv.JNI_EVERSION; +import static com.oracle.truffle.espresso.jni.JniEnv.JNI_OK; +import static com.oracle.truffle.espresso.classfile.Constants.ACC_ABSTRACT; +import static com.oracle.truffle.espresso.classfile.Constants.ACC_FINAL; +import static com.oracle.truffle.espresso.classfile.Constants.ACC_LAMBDA_FORM_COMPILED; +import static com.oracle.truffle.espresso.classfile.Constants.ACC_PUBLIC; +import static com.oracle.truffle.espresso.meta.EspressoError.cat; +import static com.oracle.truffle.espresso.runtime.Classpath.JAVA_BASE; +import static com.oracle.truffle.espresso.runtime.EspressoContext.DEFAULT_STACK_SIZE; +import static com.oracle.truffle.espresso.substitutions.Target_java_lang_invoke_MethodHandleNatives.Constants.ACCESS_VM_ANNOTATIONS; +import static com.oracle.truffle.espresso.substitutions.Target_java_lang_invoke_MethodHandleNatives.Constants.HIDDEN_CLASS; +import static com.oracle.truffle.espresso.substitutions.Target_java_lang_invoke_MethodHandleNatives.Constants.NESTMATE_CLASS; +import static com.oracle.truffle.espresso.substitutions.Target_java_lang_invoke_MethodHandleNatives.Constants.STRONG_LOADER_LINK; /** * Espresso implementation of the VM interface (libjvm). @@ -1231,6 +1231,39 @@ public boolean JVM_DesiredAssertionStatus(@SuppressWarnings("unused") @JavaType( return StaticObject.NULL; } + public static StaticObject toGuestComponent(RecordAttribute.RecordComponentInfo recordInfo, Meta meta, ObjectKlass klass) { + assert meta.getJavaVersion().java16OrLater(); + RuntimeConstantPool pool = klass.getConstantPool(); + StaticObject component = meta.java_lang_reflect_RecordComponent.allocateInstance(meta.getContext()); + Symbol nameSymbol = pool.symbolAt(recordInfo.getNameIndex()); + Symbol typeSymbol = pool.symbolAt(recordInfo.getDescriptorIndex()); + Symbol signature = meta.getSignatures().makeRaw(typeSymbol); + meta.java_lang_reflect_RecordComponent_clazz.setObject(component, klass.mirror()); + meta.java_lang_reflect_RecordComponent_name.setObject(component, meta.toGuestString(nameSymbol)); + meta.java_lang_reflect_RecordComponent_type.setObject(component, meta.resolveSymbolAndAccessCheck(typeSymbol, klass).mirror()); + + // Find and set accessor + Method m = klass.lookupMethod(nameSymbol, signature); + boolean validMethod = m != null && !m.isStatic() && !m.isConstructor(); + meta.java_lang_reflect_RecordComponent_accessor.setObject(component, validMethod ? m.makeMirror(meta) : StaticObject.NULL); + + // Find and set generic signature + SignatureAttribute genericSignatureAttribute = (SignatureAttribute) recordInfo.getAttribute(SignatureAttribute.NAME); + meta.java_lang_reflect_RecordComponent_signature.setObject(component, + genericSignatureAttribute != null ? meta.toGuestString(pool.symbolAt(genericSignatureAttribute.getSignatureIndex())) : StaticObject.NULL); + + // Find and set annotations + doAnnotation(recordInfo, component, Name.RuntimeVisibleAnnotations, meta.java_lang_reflect_RecordComponent_annotations, meta); + doAnnotation(recordInfo, component, Name.RuntimeVisibleTypeAnnotations, meta.java_lang_reflect_RecordComponent_typeAnnotations, meta); + + return component; + } + + private static void doAnnotation(RecordAttribute.RecordComponentInfo recordInfo, StaticObject component, Symbol attrName, Field f, Meta meta) { + Attribute attr = recordInfo.getAttribute(attrName); + f.setObject(component, attr == null ? StaticObject.NULL : StaticObject.wrap(attr.getData(), meta)); + } + @VmImpl(isJni = true) @TruffleBoundary public @JavaType(internalName = "[Ljava/lang/reflect/RecordComponent;") StaticObject JVM_GetRecordComponents(@JavaType(Class.class) StaticObject self) { @@ -1244,7 +1277,7 @@ public boolean JVM_DesiredAssertionStatus(@SuppressWarnings("unused") @JavaType( return StaticObject.NULL; } RecordAttribute.RecordComponentInfo[] components = record.getComponents(); - return getMeta().java_lang_reflect_RecordComponent.allocateReferenceArray(components.length, (i) -> components[i].toGuestComponent(getMeta(), klass)); + return getMeta().java_lang_reflect_RecordComponent.allocateReferenceArray(components.length, (i) -> toGuestComponent(components[i], getMeta(), klass)); } @VmImpl(isJni = true) @@ -3532,7 +3565,7 @@ public void defineModule(StaticObject module, void prependModuleClasspath(String moduleName) { Path path = getContext().getVmProperties().javaHome().resolve(MODULES).resolve(moduleName); - Classpath.Entry newEntry = Classpath.createEntry(path.toString()); + ClasspathEntry newEntry = Classpath.createEntry(path.toString()); if (newEntry.isDirectory()) { getContext().getBootClasspath().prepend(newEntry); // TODO: prepend path to VM properties' bootClasspath diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/continuation/HostFrameRecord.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/continuation/HostFrameRecord.java index 5ab4d1ccb0af..b7c5e888d307 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/continuation/HostFrameRecord.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/continuation/HostFrameRecord.java @@ -31,15 +31,15 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.espresso.EspressoLanguage; import com.oracle.truffle.espresso.analysis.frame.EspressoFrameDescriptor; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.classfile.ConstantPool; import com.oracle.truffle.espresso.classfile.constantpool.MethodRefConstant; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.nodes.EspressoFrame; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/Analysis.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/Analysis.java index 5a89010699c8..a925a10ad418 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/Analysis.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/Analysis.java @@ -23,206 +23,206 @@ package com.oracle.truffle.espresso.vm.npe; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.AALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.AASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ACONST_NULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ANEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ARETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ARRAYLENGTH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ASTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ATHROW; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BIPUSH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCMPG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCMPL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP2_X1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP2_X2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP_X1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DUP_X2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCMPG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCMPL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GETFIELD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GETSTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GOTO; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GOTO_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2B; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2C; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2S; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IAND; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_4; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_5; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_M1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFEQ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFGE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFGT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFLE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFLT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFNE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFNONNULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IFNULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ACMPEQ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ACMPNE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPEQ; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPGE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPGT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPLE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPLT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IF_ICMPNE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IINC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INSTANCEOF; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEDYNAMIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEINTERFACE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKESPECIAL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKESTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEVIRTUAL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISHL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IUSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IXOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.JSR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.JSR_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LAND; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCMP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDC2_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDC_W; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LOOKUPSWITCH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LRETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSHL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSTORE_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LUSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LXOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MONITORENTER; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MONITOREXIT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MULTIANEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NEW; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.POP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.POP2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTFIELD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTSTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.RET; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.RETURN; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SIPUSH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SWAP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.TABLESWITCH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.stackEffectOf; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.AALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.AASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ACONST_NULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ANEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ARETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ARRAYLENGTH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ASTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ATHROW; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BIPUSH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCMPG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCMPL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP2_X1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP2_X2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP_X1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DUP_X2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCMPG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCMPL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GETFIELD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GETSTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GOTO; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GOTO_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2B; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2C; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2S; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IAND; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_4; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_5; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_M1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFEQ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFGE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFGT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFLE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFLT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFNE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFNONNULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IFNULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ACMPEQ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ACMPNE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPEQ; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPGE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPGT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPLE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPLT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IF_ICMPNE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IINC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INSTANCEOF; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEDYNAMIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEINTERFACE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKESPECIAL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKESTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEVIRTUAL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISHL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IUSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IXOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.JSR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.JSR_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LAND; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCMP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDC2_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDC_W; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LOOKUPSWITCH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LRETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSHL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSTORE_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LUSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LXOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MONITORENTER; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MONITOREXIT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MULTIANEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NEW; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.POP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.POP2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.PUTFIELD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.PUTSTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.RET; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.RETURN; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SIPUSH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SWAP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.TABLESWITCH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.stackEffectOf; import static com.oracle.truffle.espresso.vm.npe.StackObject.UNKNOWN_BCI; import static com.oracle.truffle.espresso.vm.npe.StackType.OBJECT; import static com.oracle.truffle.espresso.vm.npe.StackType.rtype; @@ -230,18 +230,18 @@ import java.util.ArrayList; import com.oracle.truffle.espresso.EspressoLanguage; -import com.oracle.truffle.espresso.bytecode.BytecodeStream; -import com.oracle.truffle.espresso.bytecode.BytecodeSwitch; -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeStream; +import com.oracle.truffle.espresso.classfile.bytecode.BytecodeSwitch; +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; import com.oracle.truffle.espresso.impl.LanguageAccess; import com.oracle.truffle.espresso.impl.Method; -import com.oracle.truffle.espresso.meta.ExceptionHandler; +import com.oracle.truffle.espresso.classfile.ExceptionHandler; final class Analysis implements LanguageAccess { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/ExtendedNPEMessage.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/ExtendedNPEMessage.java index fab1f57b130a..1ab7f9b8e6ab 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/ExtendedNPEMessage.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/ExtendedNPEMessage.java @@ -23,7 +23,7 @@ package com.oracle.truffle.espresso.vm.npe; -import com.oracle.truffle.espresso.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.staticobject.StaticObject; import com.oracle.truffle.espresso.vm.VM; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/MessageBuildHelper.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/MessageBuildHelper.java index 47375105c771..3ea869955d41 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/MessageBuildHelper.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/MessageBuildHelper.java @@ -23,66 +23,66 @@ package com.oracle.truffle.espresso.vm.npe; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.AALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.AASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ACONST_NULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ARRAYLENGTH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ATHROW; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BIPUSH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GETFIELD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.GETSTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_4; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_5; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_M1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEINTERFACE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKESPECIAL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKESTATIC; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INVOKEVIRTUAL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MONITORENTER; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MONITOREXIT; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.PUTFIELD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SASTORE; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SIPUSH; - -import com.oracle.truffle.espresso.bytecode.Bytecodes; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.AALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.AASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ACONST_NULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ARRAYLENGTH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ATHROW; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BIPUSH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GETFIELD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.GETSTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_4; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_5; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_M1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEINTERFACE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKESPECIAL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKESTATIC; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INVOKEVIRTUAL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MONITORENTER; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MONITOREXIT; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.PUTFIELD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SASTORE; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SIPUSH; + +import com.oracle.truffle.espresso.classfile.bytecode.Bytecodes; import com.oracle.truffle.espresso.classfile.ConstantPool; import com.oracle.truffle.espresso.classfile.attributes.Local; import com.oracle.truffle.espresso.classfile.attributes.LocalVariableTable; import com.oracle.truffle.espresso.classfile.constantpool.FieldRefConstant; import com.oracle.truffle.espresso.classfile.constantpool.MethodRefConstant; -import com.oracle.truffle.espresso.descriptors.Signatures; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Name; -import com.oracle.truffle.espresso.descriptors.Symbol.Signature; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Signatures; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.impl.Method; import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.meta.MetaUtil; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/StackType.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/StackType.java index 875c9ca9ed23..d75c7add9c61 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/StackType.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/npe/StackType.java @@ -23,125 +23,125 @@ package com.oracle.truffle.espresso.vm.npe; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.AALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ACONST_NULL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ALOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ANEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ARRAYLENGTH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.BIPUSH; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.CALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.D2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCMPG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCMPL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.DSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.F2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCMPG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCMPL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FCONST_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.FSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2B; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2C; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2L; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.I2S; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IAND; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_4; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_5; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ICONST_M1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ILOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.INSTANCEOF; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISHL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.ISUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IUSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.IXOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2D; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2F; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.L2I; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LADD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LAND; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCMP; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCONST_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LCONST_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LDIV; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_0; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_1; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_2; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LLOAD_3; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LMUL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LNEG; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LREM; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSHL; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LSUB; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LUSHR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.LXOR; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.MULTIANEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NEW; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.NEWARRAY; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SALOAD; -import static com.oracle.truffle.espresso.bytecode.Bytecodes.SIPUSH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.AALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ACONST_NULL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ALOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ANEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ARRAYLENGTH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.BIPUSH; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.CALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.D2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCMPG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCMPL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.DSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.F2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCMPG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCMPL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FCONST_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.FSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2B; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2C; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2L; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.I2S; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IAND; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_4; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_5; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ICONST_M1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ILOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.INSTANCEOF; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISHL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.ISUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IUSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.IXOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2D; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2F; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.L2I; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LADD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LAND; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCMP; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCONST_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LCONST_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LDIV; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_0; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_1; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_2; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LLOAD_3; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LMUL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LNEG; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LREM; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSHL; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LSUB; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LUSHR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.LXOR; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.MULTIANEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NEW; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.NEWARRAY; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SALOAD; +import static com.oracle.truffle.espresso.classfile.bytecode.Bytecodes.SIPUSH; import com.oracle.truffle.espresso.classfile.ConstantPool; -import com.oracle.truffle.espresso.descriptors.Symbol; -import com.oracle.truffle.espresso.descriptors.Symbol.Type; -import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol; +import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type; +import com.oracle.truffle.espresso.classfile.descriptors.Types; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.meta.JavaKind; +import com.oracle.truffle.espresso.classfile.JavaKind; enum StackType { VOID(0), diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructsAccess.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructsAccess.java index fe7bbc0af1e0..6484084b444a 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructsAccess.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructsAccess.java @@ -34,8 +34,8 @@ import com.oracle.truffle.espresso.ffi.Pointer; import com.oracle.truffle.espresso.ffi.RawPointer; import com.oracle.truffle.espresso.meta.EspressoError; -import com.oracle.truffle.espresso.perf.DebugCloseable; -import com.oracle.truffle.espresso.perf.DebugTimer; +import com.oracle.truffle.espresso.classfile.perf.DebugCloseable; +import com.oracle.truffle.espresso.classfile.perf.DebugTimer; import com.oracle.truffle.espresso.runtime.EspressoContext; public final class StructsAccess { From 85550c38e8fd3045b42c2f659c9d01c45f9aa07a Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Wed, 9 Oct 2024 17:15:01 +0200 Subject: [PATCH 099/105] Use JavaVersionUtil.JAVA_SPEC where applicable. --- .../core/test/CheckGraalInvariants.java | 3 +- .../compiler/core/test/ProfilingInfoTest.java | 3 +- .../test/VerifyRuntimeVersionFeature.java | 67 +++++++++++++++++++ .../replacements/test/CheckIndexTest.java | 14 +--- .../test/CastExactPartialEvaluationTest.java | 13 ++-- .../test/JFRPartialEvaluationTest.java | 21 +++--- .../truffle/test/PartialEvaluationTest.java | 39 +++-------- .../test/VarHandlePartialEvaluationTest.java | 8 +-- .../hotspot/GraalHotSpotVMConfigAccess.java | 3 +- .../meta/UnimplementedGraalIntrinsics.java | 3 +- .../aarch64/AArch64GraphBuilderPlugins.java | 4 +- .../amd64/AMD64GraphBuilderPlugins.java | 3 +- .../compiler/truffle/KnownTruffleTypes.java | 5 +- .../hosted/NativeImageGeneratorRunner.java | 2 +- 14 files changed, 114 insertions(+), 74 deletions(-) create mode 100644 compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyRuntimeVersionFeature.java diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java index 41fc2e0dc5b5..068758150e6e 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java @@ -51,7 +51,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import jdk.graal.compiler.test.SubprocessUtil; import org.graalvm.word.LocationIdentity; import org.junit.Assert; import org.junit.Assume; @@ -103,6 +102,7 @@ import jdk.graal.compiler.phases.util.Providers; import jdk.graal.compiler.runtime.RuntimeProvider; import jdk.graal.compiler.test.AddExports; +import jdk.graal.compiler.test.SubprocessUtil; import jdk.internal.misc.Unsafe; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.code.Register; @@ -344,6 +344,7 @@ public static void runTest(InvariantsTool tool) { verifiers.add(new VerifyStringCaseUsage()); verifiers.add(new VerifyMathAbs()); verifiers.add(new VerifyLoopInfo()); + verifiers.add(new VerifyRuntimeVersionFeature()); VerifyAssertionUsage assertionUsages = null; boolean checkAssertions = tool.checkAssertions(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ProfilingInfoTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ProfilingInfoTest.java index d45dc9d3a08c..5d09ef2bdf74 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ProfilingInfoTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ProfilingInfoTest.java @@ -26,11 +26,11 @@ import java.io.Serializable; -import jdk.graal.compiler.test.SubprocessUtil; import org.junit.Assert; import org.junit.Assume; import org.junit.Test; +import jdk.graal.compiler.test.SubprocessUtil; import jdk.vm.ci.meta.JavaTypeProfile; import jdk.vm.ci.meta.ProfilingInfo; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -196,7 +196,6 @@ public ProfilingInfoTest() { @Test public void testExceptionSeen() { - Assume.assumeTrue("GR-45918", Runtime.version().feature() < 21); // NullPointerException ProfilingInfo info = profile("nullPointerExceptionSnippet", 5); Assert.assertEquals(TriState.FALSE, info.getExceptionSeen(1)); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyRuntimeVersionFeature.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyRuntimeVersionFeature.java new file mode 100644 index 000000000000..7bd88b65c9e9 --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyRuntimeVersionFeature.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.graal.compiler.core.test; + +import java.lang.Runtime.Version; + +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.java.MethodCallTargetNode; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.graal.compiler.phases.VerifyPhase; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Verify that Graal fetches {@link Version#feature} only via {@link JavaVersionUtil}. + */ +public class VerifyRuntimeVersionFeature extends VerifyPhase { + + @Override + public boolean checkContract() { + return false; + } + + @Override + protected void verify(StructuredGraph graph, CoreProviders context) { + MetaAccessProvider metaAccess = context.getMetaAccess(); + ResolvedJavaMethod caller = graph.method(); + + if ("jdk.graal.compiler.serviceprovider.JavaVersionUtil.()".equals(caller.format("%H.%n(%p)"))) { + // JavaVersionUtil.JAVA_SPEC + return; + } + + final ResolvedJavaType typeRuntimeVersion = metaAccess.lookupJavaType(Runtime.Version.class); + + for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) { + ResolvedJavaMethod callee = t.targetMethod(); + if (typeRuntimeVersion.equals(callee.getDeclaringClass()) && "feature".equals(callee.getName())) { + throw new VerificationError("Call to %s at callsite %s is prohibited, use JavaVersionUtil.JAVA_SPEC", callee.format("%H.%n(%p)"), caller.format("%H.%n(%p)")); + } + } + } +} diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/CheckIndexTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/CheckIndexTest.java index 5d5018b4a6f7..c2506a93957a 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/CheckIndexTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/CheckIndexTest.java @@ -31,6 +31,9 @@ import java.util.List; import java.util.Objects; +import org.junit.Assume; +import org.junit.Test; + import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; @@ -40,9 +43,6 @@ import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; import jdk.graal.compiler.phases.OptimisticOptimizations; -import org.junit.Assume; -import org.junit.Test; - import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -170,14 +170,6 @@ public void testByteBufferViewVarHandleGetInt() { } catch (ClassNotFoundException e) { Assume.assumeNoException(e); } - Assume.assumeFalse(Runtime.version().feature() == 19); - if (Runtime.version().feature() == 20) { - try { - Class.forName("jdk.internal.foreign.Scoped"); - Assume.assumeFalse("Requires Foreign Function and Memory API (Second Preview)", true); - } catch (ClassNotFoundException e) { - } - } test("byteBufferViewVarHandleGetInt"); testGraph("byteBufferViewVarHandleGetInt"); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/CastExactPartialEvaluationTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/CastExactPartialEvaluationTest.java index 89b89f68592f..7d63a1de6274 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/CastExactPartialEvaluationTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/CastExactPartialEvaluationTest.java @@ -28,12 +28,7 @@ import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; -import jdk.graal.compiler.truffle.test.nodes.AbstractTestNode; -import jdk.graal.compiler.truffle.test.nodes.RootTestNode; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.java.MethodCallTargetNode; import org.junit.Assert; -import org.junit.Assume; import org.junit.Before; import org.junit.Test; @@ -45,6 +40,11 @@ import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.runtime.OptimizedCallTarget; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.java.MethodCallTargetNode; +import jdk.graal.compiler.truffle.test.nodes.AbstractTestNode; +import jdk.graal.compiler.truffle.test.nodes.RootTestNode; + public class CastExactPartialEvaluationTest extends PartialEvaluationTest { @Before @@ -104,14 +104,12 @@ public void exactClassProfile() { */ @Test public void byteBufferAccess() { - Assume.assumeTrue(isByteBufferPartialEvaluationSupported()); AbstractTestNode result = new BufferGetPutTestNode(bufferClass()); testCommon(result, "byteBufferAccess"); } @Test public void byteBufferAccessIndex() { - Assume.assumeTrue(isByteBufferPartialEvaluationSupported()); AbstractTestNode result = new BufferGetPutIndexTestNode(bufferClass()); testCommon(result, "byteBufferAccessIndex"); } @@ -140,7 +138,6 @@ public void byteBufferDuplicate() { } private void testExceptionSpeculationCommon(AbstractTestNode testNode, String testName, boolean expectException) { - Assume.assumeTrue(isByteBufferPartialEvaluationSupported()); RootNode rootNode = new RootTestNode(testName, testNode); OptimizedCallTarget callTarget = (OptimizedCallTarget) rootNode.getCallTarget(); Object[] arguments = {newBuffer()}; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/JFRPartialEvaluationTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/JFRPartialEvaluationTest.java index 8a756d951c2f..d57bf7dee456 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/JFRPartialEvaluationTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/JFRPartialEvaluationTest.java @@ -24,25 +24,28 @@ */ package jdk.graal.compiler.truffle.test; +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.Test; + import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.test.SubprocessTestUtils; import com.oracle.truffle.runtime.OptimizedCallTarget; + import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.java.MethodCallTargetNode; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.graal.compiler.truffle.test.nodes.AbstractTestNode; import jdk.graal.compiler.truffle.test.nodes.RootTestNode; import jdk.jfr.Event; import jdk.jfr.Name; import jdk.vm.ci.meta.ResolvedJavaMethod; -import org.junit.Test; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -import static org.junit.Assert.assertNotNull; public class JFRPartialEvaluationTest extends PartialEvaluationTest { @@ -66,7 +69,7 @@ public int execute(VirtualFrame frame) { } } }); - if (Runtime.version().feature() < 22) { + if (JavaVersionUtil.JAVA_SPEC == 21) { Class throwableTracer = findThrowableTracerClass(); ResolvedJavaMethod traceThrowable = getResolvedJavaMethod(throwableTracer, "traceThrowable"); OptimizedCallTarget callTarget = (OptimizedCallTarget) root.getCallTarget(); @@ -114,7 +117,7 @@ public int execute(VirtualFrame frame) { } } }); - if (Runtime.version().feature() < 22) { + if (JavaVersionUtil.JAVA_SPEC == 21) { Class throwableTracer = findThrowableTracerClass(); ResolvedJavaMethod traceThrowable = getResolvedJavaMethod(throwableTracer, "traceThrowable"); ResolvedJavaMethod traceError = getResolvedJavaMethod(throwableTracer, "traceError"); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PartialEvaluationTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PartialEvaluationTest.java index 1fff35d830c3..a184d783ff55 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PartialEvaluationTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PartialEvaluationTest.java @@ -30,6 +30,17 @@ import java.util.Set; import java.util.function.Supplier; +import org.junit.Assert; + +import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.ControlFlowException; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.compiler.TruffleCompilationTask; +import com.oracle.truffle.runtime.OptimizedCallTarget; +import com.oracle.truffle.runtime.OptimizedTruffleRuntime; + import jdk.graal.compiler.code.CompilationResult; import jdk.graal.compiler.core.common.CompilationIdentifier; import jdk.graal.compiler.debug.DebugContext; @@ -51,17 +62,6 @@ import jdk.graal.compiler.truffle.TruffleDebugJavaMethod; import jdk.graal.compiler.truffle.TruffleTierContext; import jdk.graal.compiler.truffle.phases.TruffleTier; -import org.junit.Assert; - -import com.oracle.truffle.api.CallTarget; -import com.oracle.truffle.api.Truffle; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.ControlFlowException; -import com.oracle.truffle.api.nodes.RootNode; -import com.oracle.truffle.compiler.TruffleCompilationTask; -import com.oracle.truffle.runtime.OptimizedTruffleRuntime; -import com.oracle.truffle.runtime.OptimizedCallTarget; - import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; @@ -378,23 +378,6 @@ private PhaseSuite getSuite(OptimizedCallTarget callTarget) { return result; } - /** - * Partial evaluation (of ByteBuffer code) only works with currently supported JDK versions. - */ - protected static boolean isByteBufferPartialEvaluationSupported() { - if (Runtime.version().feature() == 20) { - try { - Class.forName("jdk.internal.foreign.Scoped"); - // Unsupported early access version. - return false; - } catch (ClassNotFoundException e) { - return true; - } - } else { - return Runtime.version().feature() == 17 || Runtime.version().feature() >= 21; - } - } - /** * Error ignored when running before partially evaluating a root node. */ diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/VarHandlePartialEvaluationTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/VarHandlePartialEvaluationTest.java index 570efda4fac1..4d3227d35432 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/VarHandlePartialEvaluationTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/VarHandlePartialEvaluationTest.java @@ -29,10 +29,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; -import jdk.graal.compiler.truffle.test.nodes.AbstractTestNode; -import jdk.graal.compiler.truffle.test.nodes.RootTestNode; import org.junit.Assert; -import org.junit.Assume; import org.junit.Test; import com.oracle.truffle.api.RootCallTarget; @@ -40,6 +37,9 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.RootNode; +import jdk.graal.compiler.truffle.test.nodes.AbstractTestNode; +import jdk.graal.compiler.truffle.test.nodes.RootTestNode; + public class VarHandlePartialEvaluationTest extends PartialEvaluationTest { static final VarHandle byteArrayHandle = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.nativeOrder()); @@ -68,7 +68,6 @@ public void byteArrayHandleSet() { */ @Test public void byteBufferHandleGet() { - Assume.assumeTrue(isByteBufferPartialEvaluationSupported()); ByteBuffer byteBuffer = ByteBuffer.allocate(42).order(ByteOrder.nativeOrder()).putInt(0, 42); testCommon(new VarHandleTestNode(false, false), "byteBufferHandleGetInt", byteBuffer, 0); } @@ -78,7 +77,6 @@ public void byteBufferHandleGet() { */ @Test public void byteBufferHandleSet() { - Assume.assumeTrue(isByteBufferPartialEvaluationSupported()); ByteBuffer byteBuffer = ByteBuffer.allocate(42).order(ByteOrder.nativeOrder()).putInt(0, 42); testCommon(new VarHandleTestNode(false, true), "byteArrayHandleSetInt", byteBuffer, 0, 42); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfigAccess.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfigAccess.java index 96b619507531..e7ee7156d090 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfigAccess.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/GraalHotSpotVMConfigAccess.java @@ -36,6 +36,7 @@ import java.util.stream.Collectors; import jdk.graal.compiler.debug.Assertions; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; @@ -111,7 +112,7 @@ public static boolean jvmciGE(JVMCIVersionCheck.Version v) { return JVMCI && !JVMCI_VERSION.isLessThan(v); } - public static final int JDK = Runtime.version().feature(); + public static final int JDK = JavaVersionUtil.JAVA_SPEC; public static final JVMCIVersionCheck.Version JVMCI_VERSION; public static final boolean JVMCI; public static final boolean JDK_PRERELEASE; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java index db009653ccb2..199966c5180d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/UnimplementedGraalIntrinsics.java @@ -32,6 +32,7 @@ import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.code.Architecture; @@ -85,7 +86,7 @@ private static void add(Collection c, String... elements) { } public UnimplementedGraalIntrinsics(Architecture arch) { - int jdk = Runtime.version().feature(); + int jdk = JavaVersionUtil.JAVA_SPEC; add(toBeInvestigated, // @formatter:off // JDK-8309130: x86_64 AVX512 intrinsics for Arrays.sort methods (GR-48679) diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java index ad7e9cc434fb..b001d8dcb4cb 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java @@ -71,6 +71,7 @@ import jdk.graal.compiler.replacements.nodes.HalfFloatToFloatNode; import jdk.graal.compiler.replacements.nodes.MessageDigestNode; import jdk.graal.compiler.replacements.nodes.UnaryMathIntrinsicNode; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.meta.JavaKind; @@ -451,8 +452,7 @@ public SnippetTemplate.SnippetInfo getSnippet(StringUTF16Snippets.Templates temp return templates.indexOfUnsafe; } }); - int jdk = Runtime.version().feature(); - r.register(new InvocationPlugin(jdk == 21 ? "indexOfCharUnsafe" : "indexOfChar", byte[].class, int.class, int.class, int.class) { + r.register(new InvocationPlugin(JavaVersionUtil.JAVA_SPEC == 21 ? "indexOfCharUnsafe" : "indexOfChar", byte[].class, int.class, int.class, int.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value, ValueNode ch, ValueNode fromIndex, ValueNode max) { ZeroExtendNode toChar = b.add(new ZeroExtendNode(b.add(new NarrowNode(ch, JavaKind.Char.getBitCount())), JavaKind.Int.getBitCount())); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java index bdd1c084cd0f..8412780617e3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java @@ -519,8 +519,7 @@ public SnippetTemplate.SnippetInfo getSnippet(StringUTF16Snippets.Templates temp } }); - int jdk = Runtime.version().feature(); - r.register(new InvocationPlugin(jdk == 21 ? "indexOfCharUnsafe" : "indexOfChar", byte[].class, int.class, int.class, int.class) { + r.register(new InvocationPlugin(JavaVersionUtil.JAVA_SPEC == 21 ? "indexOfCharUnsafe" : "indexOfChar", byte[].class, int.class, int.class, int.class) { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value, ValueNode ch, ValueNode fromIndex, ValueNode max) { ZeroExtendNode toChar = b.add(new ZeroExtendNode(b.add(new NarrowNode(ch, JavaKind.Char.getBitCount())), JavaKind.Int.getBitCount())); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/KnownTruffleTypes.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/KnownTruffleTypes.java index ceadc720e595..2a27d2085a8d 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/KnownTruffleTypes.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/KnownTruffleTypes.java @@ -39,6 +39,7 @@ import com.oracle.truffle.compiler.TruffleCompilerRuntime; import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -215,10 +216,8 @@ public KnownTruffleTypes(TruffleCompilerRuntime runtime, MetaAccessProvider meta Throwable_jfrTracing = getThrowableJFRTracingField(metaAccess); } - public static final int JDK = Runtime.version().feature(); - private static boolean throwableUsesJFRTracing() { - return JDK >= 22; + return JavaVersionUtil.JAVA_SPEC >= 22; } private static ResolvedJavaField getThrowableJFRTracingField(MetaAccessProvider metaAccess) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index f2769768975f..1eac07ed6f98 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -461,7 +461,7 @@ private int buildImage(ImageClassLoader classLoader) { " 1) Recompile the source files for your application using Java %s, then try running native-image again%n" + " 2) Use a version of native-image corresponding to the version of Java with which you compiled the source files for your application%n%n" + "Root cause: %s", - className, Runtime.version().feature(), ex); + className, JavaVersionUtil.JAVA_SPEC, ex); } else { throw UserError.abort(ex.getMessage()); } From 28fd59752a143e487546d39b819828053d97fd37 Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Wed, 9 Oct 2024 19:00:44 +0200 Subject: [PATCH 100/105] Avoid direct reference to GuardsStage enums. --- .../core/test/CheckGraalInvariants.java | 1 + .../core/test/VerifyGuardsStageUsages.java | 82 +++++++++++++++++++ .../meta/DefaultHotSpotLoweringProvider.java | 17 ++-- .../compiler/hotspot/stubs/SnippetStub.java | 4 +- .../loop/phases/LoopTransformations.java | 3 +- .../compiler/nodes/ConditionAnchorNode.java | 2 +- .../jdk/graal/compiler/nodes/GraphState.java | 16 ++-- .../phases/common/TransplantGraphsPhase.java | 3 +- .../phases/common/inlining/InliningUtil.java | 5 +- .../phases/schedule/SchedulePhase.java | 3 +- .../compiler/phases/util/GraphOrder.java | 7 +- .../DefaultJavaLoweringProvider.java | 2 +- .../graal/GenScavengeAllocationSnippets.java | 41 +++++----- .../jdk/SubstrateObjectCloneSnippets.java | 3 +- .../snippets/SubstrateAllocationSnippets.java | 27 +++--- .../oracle/svm/hosted/code/CompileQueue.java | 3 +- 16 files changed, 145 insertions(+), 74 deletions(-) create mode 100644 compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyGuardsStageUsages.java diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java index 068758150e6e..e46047477c7f 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java @@ -345,6 +345,7 @@ public static void runTest(InvariantsTool tool) { verifiers.add(new VerifyMathAbs()); verifiers.add(new VerifyLoopInfo()); verifiers.add(new VerifyRuntimeVersionFeature()); + verifiers.add(new VerifyGuardsStageUsages()); VerifyAssertionUsage assertionUsages = null; boolean checkAssertions = tool.checkAssertions(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyGuardsStageUsages.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyGuardsStageUsages.java new file mode 100644 index 000000000000..1a821968336f --- /dev/null +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyGuardsStageUsages.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.graal.compiler.core.test; + +import jdk.graal.compiler.nodes.GraphState; +import jdk.graal.compiler.nodes.GraphState.GuardsStage; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.java.LoadFieldNode; +import jdk.graal.compiler.nodes.spi.CoreProviders; +import jdk.graal.compiler.phases.VerifyPhase; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Verify that {@link GuardsStage} enums are encapsulated. + */ +public class VerifyGuardsStageUsages extends VerifyPhase { + + @Override + public boolean checkContract() { + return false; + } + + @Override + protected void verify(StructuredGraph graph, CoreProviders context) { + MetaAccessProvider metaAccess = context.getMetaAccess(); + ResolvedJavaMethod caller = graph.method(); + + if (caller.getDeclaringClass().equals(metaAccess.lookupJavaType(GraphState.class))) { + return; + } + if (caller.getDeclaringClass().equals(metaAccess.lookupJavaType(GraphState.GuardsStage.class))) { + return; + } + + String callerName = caller.format("%H.%n"); + + switch (callerName) { + case "jdk.graal.compiler.phases.common.GuardLoweringPhase.updateGraphState": + case "jdk.graal.compiler.replacements.arraycopy.ArrayCopySnippets.delayedCheckcastArraycopySnippet": + case "jdk.graal.compiler.replacements.arraycopy.ArrayCopySnippets.delayedExactArraycopyWithExpandedLoopSnippet": + case "jdk.graal.compiler.replacements.arraycopy.ArrayCopySnippets.delayedGenericArraycopySnippet": + // Exempted cases + return; + default: + } + + final ResolvedJavaType typeGuardsStage = metaAccess.lookupJavaType(GraphState.GuardsStage.class); + + for (LoadFieldNode t : graph.getNodes().filter(LoadFieldNode.class)) { + if (typeGuardsStage.equals(t.field().getDeclaringClass())) { + throw new VerificationError("Access to %s fields at callsite %s is prohibited. Use API methods provided in %s.", + typeGuardsStage.toJavaName(true), + caller.format("%H.%n(%p)"), + typeGuardsStage.toJavaName(true)); + } + } + } +} diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java index c51b9d5131ab..ab2a145dab3c 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java @@ -113,7 +113,6 @@ import jdk.graal.compiler.nodes.FixedWithNextNode; import jdk.graal.compiler.nodes.FrameState; import jdk.graal.compiler.nodes.GetObjectAddressNode; -import jdk.graal.compiler.nodes.GraphState.GuardsStage; import jdk.graal.compiler.nodes.Invoke; import jdk.graal.compiler.nodes.LogicConstantNode; import jdk.graal.compiler.nodes.LogicNode; @@ -543,27 +542,27 @@ private boolean lowerWithoutDelegation(Node n, LoweringTool tool) { } else if (n instanceof HubGetClassNode) { lowerHubGetClassNode((HubGetClassNode) n, tool); } else if (n instanceof KlassLayoutHelperNode) { - if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { lowerKlassLayoutHelperNode((KlassLayoutHelperNode) n, tool); } } else if (n instanceof KlassBeingInitializedCheckNode) { - if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { getAllocationSnippets().lower((KlassBeingInitializedCheckNode) n, tool); } } else if (n instanceof KlassFullyInitializedCheckNode) { - if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { getAllocationSnippets().lower((KlassFullyInitializedCheckNode) n, tool); } } else if (n instanceof FastNotifyNode) { - if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { objectSnippets.lower(n, tool); } } else if (n instanceof UnsafeCopyMemoryNode) { - if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { unsafeSnippets.lower((UnsafeCopyMemoryNode) n, tool); } } else if (n instanceof UnsafeSetMemoryNode) { - if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { unsafeSnippets.lower((UnsafeSetMemoryNode) n, tool); } } else if (n instanceof RegisterFinalizerNode) { @@ -575,7 +574,7 @@ private boolean lowerWithoutDelegation(Node n, LoweringTool tool) { lowerIntegerDivRem((IntegerDivRemNode) n, tool); } } else if (n instanceof VirtualThreadUpdateJFRNode) { - if (graph.getGuardsStage() == GuardsStage.AFTER_FSA) { + if (graph.getGuardsStage().areFrameStatesAtDeopts()) { virtualThreadUpdateJFRSnippets.lower((VirtualThreadUpdateJFRNode) n, registers, tool); } } else { @@ -907,7 +906,7 @@ private void lowerStoreHubNode(StoreHubNode storeHub, StructuredGraph graph) { private void lowerOSRStartNode(OSRStartNode osrStart) { StructuredGraph graph = osrStart.graph(); - if (graph.getGuardsStage() == GuardsStage.FIXED_DEOPTS) { + if (graph.getGuardsStage().areDeoptsFixed()) { StartNode newStart = graph.add(new StartNode()); ParameterNode buffer = graph.addWithoutUnique(new ParameterNode(0, StampPair.createSingle(StampFactory.forKind(runtime.getTarget().wordJavaKind)))); ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(OSR_MIGRATION_END, buffer)); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/SnippetStub.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/SnippetStub.java index 5d9ddf9b19db..d232b91a492b 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/SnippetStub.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/stubs/SnippetStub.java @@ -33,7 +33,6 @@ import jdk.graal.compiler.debug.GraalError; import jdk.graal.compiler.hotspot.HotSpotForeignCallLinkage; import jdk.graal.compiler.hotspot.meta.HotSpotProviders; -import jdk.graal.compiler.nodes.GraphState.GuardsStage; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.ParameterNode; import jdk.graal.compiler.nodes.StructuredGraph; @@ -43,7 +42,6 @@ import jdk.graal.compiler.phases.common.HighTierLoweringPhase; import jdk.graal.compiler.replacements.SnippetTemplate; import jdk.graal.compiler.replacements.Snippets; - import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -99,7 +97,7 @@ protected StructuredGraph getGraph(DebugContext debug, CompilationIdentifier com } } - graph.getGraphState().setGuardsStage(GuardsStage.FLOATING_GUARDS); + graph.getGraphState().initGuardsStage(); CanonicalizerPhase canonicalizer = CanonicalizerPhase.create(); canonicalizer.apply(graph, providers); new HighTierLoweringPhase(canonicalizer).apply(graph, providers); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/LoopTransformations.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/LoopTransformations.java index 68f0a08719c1..0b7fdc694daf 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/LoopTransformations.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/loop/phases/LoopTransformations.java @@ -54,7 +54,6 @@ import jdk.graal.compiler.nodes.FixedNode; import jdk.graal.compiler.nodes.FixedWithNextNode; import jdk.graal.compiler.nodes.FrameState; -import jdk.graal.compiler.nodes.GraphState.GuardsStage; import jdk.graal.compiler.nodes.GraphState.StageFlag; import jdk.graal.compiler.nodes.GuardPhiNode; import jdk.graal.compiler.nodes.IfNode; @@ -250,7 +249,7 @@ public static void partialUnroll(Loop loop, EconomicMap= FIXED_DEOPTS.ordinal(); } - /** - * Checks if this guards stage indicates it is necessary to have value proxies in the graph. - */ - public boolean requiresValueProxies() { - return this != AFTER_FSA; - } - /** * Checks if this guards stage indicates a later or equivalent stage of the compilation than * the given stage. @@ -544,6 +537,13 @@ public GuardsStage getGuardsStage() { return guardsStage; } + /** + * Sets the {@linkplain #getGuardsStage() guards stage} to {@link GuardsStage#FLOATING_GUARDS}. + */ + public void initGuardsStage() { + setGuardsStage(GuardsStage.FLOATING_GUARDS); + } + /** * Sets the {@linkplain #getGuardsStage() guards stage} of this graph state. The new * {@link GuardsStage} needs to indicate a progression in the compilation, not a regression. @@ -580,7 +580,7 @@ public boolean isExplicitExceptionsNoDeopt() { public void configureExplicitExceptionsNoDeopt() { assert !isExplicitExceptionsNoDeopt(); assert stageFlags.isEmpty() : "Must not have set a stage flag before"; - assert guardsStage == GuardsStage.FLOATING_GUARDS : "Default guards stage is floating guards"; + assert guardsStage.allowsFloatingGuards() : "Default guards stage is floating guards"; setGuardsStage(GraphState.GuardsStage.FIXED_DEOPTS); setAfterStage(StageFlag.GUARD_LOWERING); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/TransplantGraphsPhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/TransplantGraphsPhase.java index 18eeac33b928..78c38c5eacde 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/TransplantGraphsPhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/TransplantGraphsPhase.java @@ -51,7 +51,6 @@ import jdk.graal.compiler.nodes.FixedWithNextNode; import jdk.graal.compiler.nodes.FrameState; import jdk.graal.compiler.nodes.GraphState; -import jdk.graal.compiler.nodes.GraphState.GuardsStage; import jdk.graal.compiler.nodes.GraphState.StageFlag; import jdk.graal.compiler.nodes.ParameterNode; import jdk.graal.compiler.nodes.PhiNode; @@ -507,7 +506,7 @@ private static boolean verifyTransplantedGraphAndSchedule(StructuredGraph graph, assert patchedFinalSchedule.getNodeToBlockMap().get(n) == b : Assertions.errorMessage("Node to block gives different block for node ", patchedFinalSchedule.getNodeToBlockMap().get(n), n, b); StructuredGraph g = (StructuredGraph) n.graph(); - if (g.hasLoops() && g.getGuardsStage() == GuardsStage.AFTER_FSA && n instanceof DeoptimizeNode) { + if (g.hasLoops() && g.getGuardsStage().areFrameStatesAtDeopts() && n instanceof DeoptimizeNode) { assert b.getLoopDepth() == 0 : n; } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/inlining/InliningUtil.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/inlining/InliningUtil.java index a1e726802da1..52dd9207aabd 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/inlining/InliningUtil.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/inlining/InliningUtil.java @@ -74,7 +74,6 @@ import jdk.graal.compiler.nodes.FixedGuardNode; import jdk.graal.compiler.nodes.FixedNode; import jdk.graal.compiler.nodes.FrameState; -import jdk.graal.compiler.nodes.GraphState.GuardsStage; import jdk.graal.compiler.nodes.GraphState.StageFlag; import jdk.graal.compiler.nodes.InliningLog; import jdk.graal.compiler.nodes.Invoke; @@ -910,7 +909,7 @@ public static FrameState processFrameState(FrameState frameState, Invoke invoke, } frameState.replaceAndDelete(stateAfterException); return stateAfterException; - } else if ((frameState.bci == BytecodeFrame.UNWIND_BCI && frameState.graph().getGuardsStage() == GuardsStage.FLOATING_GUARDS) || + } else if ((frameState.bci == BytecodeFrame.UNWIND_BCI && frameState.graph().getGuardsStage().allowsFloatingGuards()) || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { /* * This path converts the frame states relevant for exception unwinding to @@ -1074,7 +1073,7 @@ public static FrameState handleMissingAfterExceptionFrameState(FrameState nonRep } private static DeoptimizeNode addDeoptimizeNode(StructuredGraph graph, DeoptimizationAction action, DeoptimizationReason reason) { - GraalError.guarantee(graph.getGuardsStage() == GuardsStage.FLOATING_GUARDS, "Cannot introduce speculative deoptimization when Graal is used with fixed guards"); + GraalError.guarantee(graph.getGuardsStage().allowsFloatingGuards(), "Cannot introduce speculative deoptimization when Graal is used with fixed guards"); return graph.add(new DeoptimizeNode(action, reason)); } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/schedule/SchedulePhase.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/schedule/SchedulePhase.java index 4932e5752425..4a47fdd6f2a3 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/schedule/SchedulePhase.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/schedule/SchedulePhase.java @@ -65,7 +65,6 @@ import jdk.graal.compiler.nodes.FixedNode; import jdk.graal.compiler.nodes.FrameState; import jdk.graal.compiler.nodes.GraphState; -import jdk.graal.compiler.nodes.GraphState.GuardsStage; import jdk.graal.compiler.nodes.GraphState.StageFlag; import jdk.graal.compiler.nodes.GuardNode; import jdk.graal.compiler.nodes.IfNode; @@ -399,7 +398,7 @@ private static boolean verifySchedule(ControlFlowGraph cfg, BlockMap> assert n.isAlive(); assert nodeMap.get(n) == b : Assertions.errorMessage(n, b); StructuredGraph g = (StructuredGraph) n.graph(); - if (g.hasLoops() && g.getGuardsStage() == GuardsStage.AFTER_FSA && n instanceof DeoptimizeNode) { + if (g.hasLoops() && g.getGuardsStage().areFrameStatesAtDeopts() && n instanceof DeoptimizeNode) { assert b.getLoopDepth() == 0 : n; } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/GraphOrder.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/GraphOrder.java index bcf99d0df675..2237fb2c1058 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/GraphOrder.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/util/GraphOrder.java @@ -47,7 +47,6 @@ import jdk.graal.compiler.nodes.FixedNode; import jdk.graal.compiler.nodes.FrameState; import jdk.graal.compiler.nodes.FullInfopointNode; -import jdk.graal.compiler.nodes.GraphState.GuardsStage; import jdk.graal.compiler.nodes.GraphState.StageFlag; import jdk.graal.compiler.nodes.GuardNode; import jdk.graal.compiler.nodes.GuardPhiNode; @@ -220,8 +219,8 @@ private static void visitTransitiveInputs(ArrayList nodes, NodeBitMap visi public static boolean assertSchedulableGraph(StructuredGraph g) { assert GraphOrder.assertNonCyclicGraph(g); - assert g.getGuardsStage() == GuardsStage.AFTER_FSA || GraphOrder.assertScheduleableBeforeFSA(g); - if (g.getGuardsStage() == GuardsStage.AFTER_FSA && Assertions.detailedAssertionsEnabled(g.getOptions())) { + assert g.getGuardsStage().areFrameStatesAtDeopts() || GraphOrder.assertScheduleableBeforeFSA(g); + if (g.getGuardsStage().areFrameStatesAtDeopts() && Assertions.detailedAssertionsEnabled(g.getOptions())) { // we still want to do a memory verification of the schedule even if we can // no longer use assertSchedulableGraph after the floating reads phase SchedulePhase.runWithoutContextOptimizations(g, SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS, true); @@ -241,7 +240,7 @@ public static boolean assertSchedulableGraph(StructuredGraph g) { */ @SuppressWarnings("try") private static boolean assertScheduleableBeforeFSA(final StructuredGraph graph) { - assert graph.getGuardsStage() != GuardsStage.AFTER_FSA : "Cannot use the BlockIteratorClosure after FrameState Assignment, HIR Loop Data Structures are no longer valid."; + assert !graph.getGuardsStage().areFrameStatesAtDeopts() : "Cannot use the BlockIteratorClosure after FrameState Assignment, HIR Loop Data Structures are no longer valid."; try (DebugContext.Scope s = graph.getDebug().scope("AssertSchedulableGraph")) { SchedulePhase.runWithoutContextOptimizations(graph, getSchedulingPolicy(graph), true); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java index a5cddee872e2..9591581868ed 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/DefaultJavaLoweringProvider.java @@ -917,7 +917,7 @@ protected void lowerJavaWriteNode(JavaWriteNode write) { @SuppressWarnings("try") protected void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) { StructuredGraph graph = commit.graph(); - if (graph.getGuardsStage() != GraphState.GuardsStage.FIXED_DEOPTS) { + if (graph.getGuardsStage().allowsFloatingGuards()) { return; } diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSnippets.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSnippets.java index 05ace6f20f39..85c04c631740 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSnippets.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/graal/GenScavengeAllocationSnippets.java @@ -26,11 +26,26 @@ import java.util.Map; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.word.UnsignedWord; + +import com.oracle.svm.core.genscavenge.ObjectHeaderImpl; +import com.oracle.svm.core.genscavenge.graal.nodes.FormatArrayNode; +import com.oracle.svm.core.genscavenge.graal.nodes.FormatObjectNode; +import com.oracle.svm.core.genscavenge.graal.nodes.FormatPodNode; +import com.oracle.svm.core.genscavenge.graal.nodes.FormatStoredContinuationNode; +import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; +import com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets; +import com.oracle.svm.core.graal.snippets.SubstrateTemplates; +import com.oracle.svm.core.heap.Pod; +import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.hub.LayoutEncoding; +import com.oracle.svm.core.thread.ContinuationSupport; + import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.api.replacements.Snippet; import jdk.graal.compiler.api.replacements.Snippet.ConstantParameter; import jdk.graal.compiler.graph.Node; -import jdk.graal.compiler.nodes.GraphState; import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.nodes.PiNode; import jdk.graal.compiler.nodes.SnippetAnchorNode; @@ -44,22 +59,6 @@ import jdk.graal.compiler.replacements.SnippetTemplate.SnippetInfo; import jdk.graal.compiler.replacements.Snippets; import jdk.graal.compiler.word.Word; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.word.UnsignedWord; - -import com.oracle.svm.core.genscavenge.ObjectHeaderImpl; -import com.oracle.svm.core.genscavenge.graal.nodes.FormatArrayNode; -import com.oracle.svm.core.genscavenge.graal.nodes.FormatObjectNode; -import com.oracle.svm.core.genscavenge.graal.nodes.FormatPodNode; -import com.oracle.svm.core.genscavenge.graal.nodes.FormatStoredContinuationNode; -import com.oracle.svm.core.graal.snippets.NodeLoweringProvider; -import com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets; -import com.oracle.svm.core.graal.snippets.SubstrateTemplates; -import com.oracle.svm.core.heap.Pod; -import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.hub.LayoutEncoding; -import com.oracle.svm.core.thread.ContinuationSupport; - import jdk.vm.ci.meta.JavaKind; public final class GenScavengeAllocationSnippets implements Snippets { @@ -152,7 +151,7 @@ private class FormatObjectLowering implements NodeLoweringProvider { @Override public void lower(FormatPodNode node, LoweringTool tool) { StructuredGraph graph = node.graph(); - if (graph.getGuardsStage() != GraphState.GuardsStage.AFTER_FSA) { + if (graph.getGuardsStage().areFrameStatesAtSideEffects()) { return; } Arguments args = new Arguments(formatPod, graph.getGuardsStage(), tool.getLoweringStage()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateObjectCloneSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateObjectCloneSnippets.java index 99aa7eed79b6..ef396465107b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateObjectCloneSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/jdk/SubstrateObjectCloneSnippets.java @@ -60,7 +60,6 @@ import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.graph.Node.ConstantNodeParameter; import jdk.graal.compiler.graph.Node.NodeIntrinsic; -import jdk.graal.compiler.nodes.GraphState; import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.ValueNode; @@ -228,7 +227,7 @@ private SubstrateObjectCloneSnippets(OptionValues options, Providers providers, final class ObjectCloneLowering implements NodeLoweringProvider { @Override public void lower(SubstrateObjectCloneNode node, LoweringTool tool) { - if (node.graph().getGuardsStage() != GraphState.GuardsStage.AFTER_FSA) { + if (node.graph().getGuardsStage().areFrameStatesAtSideEffects()) { return; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java index 41b3aa3b2dfc..e1e1fbb46b7c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SubstrateAllocationSnippets.java @@ -79,7 +79,6 @@ import jdk.graal.compiler.graph.Node.ConstantNodeParameter; import jdk.graal.compiler.graph.Node.NodeIntrinsic; import jdk.graal.compiler.nodes.ConstantNode; -import jdk.graal.compiler.nodes.GraphState; import jdk.graal.compiler.nodes.NamedLocationIdentity; import jdk.graal.compiler.nodes.PiNode; import jdk.graal.compiler.nodes.SnippetAnchorNode; @@ -730,7 +729,7 @@ private class NewInstanceLowering implements NodeLoweringProvider { @Override public void lower(NewArrayNode node, LoweringTool tool) { StructuredGraph graph = node.graph(); - if (graph.getGuardsStage() != GraphState.GuardsStage.AFTER_FSA) { + if (graph.getGuardsStage().areFrameStatesAtSideEffects()) { return; } @@ -885,7 +884,7 @@ private class NewArrayWithExceptionLowering implements NodeLoweringProvider %s", graph, graph.getGraphState().getStageFlags(), graph.getGuardsStage()); From 22c6b08a1343133950b65f5cf9d61b15b56cb37e Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Fri, 25 Oct 2024 15:47:41 +0200 Subject: [PATCH 101/105] Add arithmetic optimizations around integer negation. --- .../core/test/NegateCanonicalizationTest.java | 31 +++++++++++++++---- .../graal/compiler/nodes/calc/NegateNode.java | 2 +- .../graal/compiler/nodes/calc/NotNode.java | 5 +++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NegateCanonicalizationTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NegateCanonicalizationTest.java index 0cb26e51759d..dea8ffed4141 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NegateCanonicalizationTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/NegateCanonicalizationTest.java @@ -25,11 +25,12 @@ */ package jdk.graal.compiler.core.test; +import org.junit.Test; + import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.calc.NegateNode; import jdk.graal.compiler.nodes.calc.RightShiftNode; import jdk.graal.compiler.nodes.calc.UnsignedRightShiftNode; -import org.junit.Test; public class NegateCanonicalizationTest extends GraalCompilerTest { @@ -49,7 +50,17 @@ public static long signExtractLong(long x) { return (x >> 63) >>> 63; } - private void checkNodes(String methodName) { + public static int negateNegate(int x) { + int var0 = -x; + int var1 = -(0 ^ var0); + return var1; + } + + public static int negateNotDecrement(int x) { + return -~(x - 1); + } + + private void checkNodesOnlyUnsignedRightShift(String methodName) { StructuredGraph graph = parseForCompile(getResolvedJavaMethod(methodName)); createCanonicalizerPhase().apply(graph, getProviders()); assertTrue(graph.getNodes().filter(NegateNode.class).count() == 0); @@ -57,11 +68,19 @@ private void checkNodes(String methodName) { assertTrue(graph.getNodes().filter(UnsignedRightShiftNode.class).count() == 1); } + private void checkNodesNoNegate(String methodName) { + StructuredGraph graph = parseForCompile(getResolvedJavaMethod(methodName)); + createCanonicalizerPhase().apply(graph, getProviders()); + assertTrue(graph.getNodes().filter(NegateNode.class).count() == 0); + } + @Test public void testNegate() { - checkNodes("negateInt"); - checkNodes("negateLong"); - checkNodes("signExtractInt"); - checkNodes("signExtractLong"); + checkNodesOnlyUnsignedRightShift("negateInt"); + checkNodesOnlyUnsignedRightShift("negateLong"); + checkNodesOnlyUnsignedRightShift("signExtractInt"); + checkNodesOnlyUnsignedRightShift("signExtractLong"); + checkNodesNoNegate("negateNegate"); + checkNodesNoNegate("negateNotDecrement"); } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/NegateNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/NegateNode.java index 19169334d5be..eb1eca136247 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/NegateNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/NegateNode.java @@ -73,7 +73,7 @@ protected UnaryOp getOp(ArithmeticOpTable table) { @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { - ValueNode synonym = findSynonym(forValue, getOp(forValue)); + ValueNode synonym = findSynonym(forValue, NodeView.DEFAULT); if (synonym != null) { return synonym; } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/NotNode.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/NotNode.java index 7ed049ab8a4a..59658185ddd8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/NotNode.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/calc/NotNode.java @@ -32,6 +32,7 @@ import jdk.graal.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Not; import jdk.graal.compiler.core.common.type.Stamp; import jdk.graal.compiler.graph.NodeClass; +import jdk.graal.compiler.nodes.NodeView; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.spi.ArithmeticLIRLowerable; import jdk.graal.compiler.nodes.spi.CanonicalizerTool; @@ -74,6 +75,10 @@ private static ValueNode canonicalize(NotNode node, ValueNode x) { if (x instanceof NotNode) { return ((NotNode) x).getValue(); } + if (x instanceof AddNode addNode && addNode.getY().isJavaConstant() && addNode.getY().asJavaConstant().asLong() == -1) { + // ~(x - 1) -> -x + return NegateNode.create(addNode.getX(), NodeView.DEFAULT); + } if (node != null) { return node; } From d3009380ce4991421b770f9216bbc6c8fc12d960 Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Tue, 17 Sep 2024 20:00:40 +0200 Subject: [PATCH 102/105] Add ApplicationLayerOnlySingletons flag to mark custom image singletons --- .../com/oracle/svm/core/SubstrateOptions.java | 3 ++ .../ApplicationLayerOnlyImageSingleton.java | 27 +++++++++++++++ .../LayeredImageSingletonBuilderFlags.java | 5 +-- .../hosted/ImageSingletonsSupportImpl.java | 6 ++-- .../svm/hosted/NativeImageGenerator.java | 4 +++ .../imagelayer/LoadImageSingletonFeature.java | 34 ++++++++++++------- .../SubstrateGraphBuilderPlugins.java | 5 +-- 7 files changed, 65 insertions(+), 19 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 42a553ded691..be2623c0b8cc 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -139,6 +139,9 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o @BundleMember(role = Role.Input) // public static final HostedOptionKey LayerUse = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Paths.build()); + @Option(help = "Mark singleton as application layer only")// + public static final HostedOptionKey ApplicationLayerOnlySingletons = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build()); + @APIOption(name = "libc")// @Option(help = "Selects the libc implementation to use. Available implementations: glibc, musl, bionic")// public static final HostedOptionKey UseLibC = new HostedOptionKey<>(null) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ApplicationLayerOnlyImageSingleton.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ApplicationLayerOnlyImageSingleton.java index beb330f64fb1..fb98dfe5d5c9 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ApplicationLayerOnlyImageSingleton.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/ApplicationLayerOnlyImageSingleton.java @@ -24,9 +24,36 @@ */ package com.oracle.svm.core.layeredimagesingleton; +import org.graalvm.nativeimage.ImageSingletons; + +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.option.HostedOptionValues; + /** * Identifies a singleton for which all lookups refer to a single singleton which will be created in * the application layer. See {@link LayeredImageSingleton} for full explanation. */ public interface ApplicationLayerOnlyImageSingleton extends LayeredImageSingleton { + + static boolean isSingletonInstanceOf(Object singleton) { + if (singleton instanceof ApplicationLayerOnlyImageSingleton) { + return true; + } + if (ImageSingletons.contains(HostedOptionValues.class)) { + return SubstrateOptions.ApplicationLayerOnlySingletons.getValue().contains(singleton.getClass().getName()); + } + + return false; + } + + static boolean isAssignableFrom(Class klass) { + if (ApplicationLayerOnlyImageSingleton.class.isAssignableFrom(klass)) { + return true; + } + if (ImageSingletons.contains(HostedOptionValues.class)) { + return SubstrateOptions.ApplicationLayerOnlySingletons.getValue().contains(klass.getName()); + } + + return false; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/LayeredImageSingletonBuilderFlags.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/LayeredImageSingletonBuilderFlags.java index 7a231fa0a302..6d8f2b264324 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/LayeredImageSingletonBuilderFlags.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/layeredimagesingleton/LayeredImageSingletonBuilderFlags.java @@ -65,12 +65,13 @@ public static boolean verifyImageBuilderFlags(LayeredImageSingleton singleton) { assert flags.equals(EnumSet.of(UNSUPPORTED)) : "Unsupported should be the only flag set " + flags; } - if (singleton instanceof MultiLayeredImageSingleton || singleton instanceof ApplicationLayerOnlyImageSingleton) { + if (singleton instanceof MultiLayeredImageSingleton || ApplicationLayerOnlyImageSingleton.isSingletonInstanceOf(singleton)) { assert flags.contains(RUNTIME_ACCESS) : String.format("%s must be set when implementing either %s or %s: %s", RUNTIME_ACCESS, MultiLayeredImageSingleton.class, ApplicationLayerOnlyImageSingleton.class, singleton); } - assert !(singleton instanceof MultiLayeredImageSingleton && singleton instanceof ApplicationLayerOnlyImageSingleton) : String.format("%s can only implement one of %s or %s", singleton, + assert !(singleton instanceof MultiLayeredImageSingleton && ApplicationLayerOnlyImageSingleton.isSingletonInstanceOf(singleton)) : String.format("%s can only implement one of %s or %s", + singleton, MultiLayeredImageSingleton.class, ApplicationLayerOnlyImageSingleton.class); return true; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java index 4ad1ce4bcb19..6d3f71ff82b3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ImageSingletonsSupportImpl.java @@ -210,17 +210,17 @@ private void doAddInternal(Class key, Object value) { throw UserError.abort("Unsupported image singleton is being installed %s %s", key.getTypeName(), singleton); } - if (singleton instanceof MultiLayeredImageSingleton || singleton instanceof ApplicationLayerOnlyImageSingleton) { + if (singleton instanceof MultiLayeredImageSingleton || ApplicationLayerOnlyImageSingleton.isSingletonInstanceOf(singleton)) { if (!key.equals(singleton.getClass())) { throw UserError.abort("The implementation class must be the same as the key class. key: %s, singleton: %s", key, singleton); } - if (singleton instanceof MultiLayeredImageSingleton && singleton instanceof ApplicationLayerOnlyImageSingleton) { + if (singleton instanceof MultiLayeredImageSingleton && ApplicationLayerOnlyImageSingleton.isSingletonInstanceOf(singleton)) { throw UserError.abort("Singleton cannot implement both %s and %s. singleton: %s", MultiLayeredImageSingleton.class, ApplicationLayerOnlyImageSingleton.class, singleton); } - if (singleton instanceof ApplicationLayerOnlyImageSingleton && !ImageLayerBuildingSupport.lastImageBuild()) { + if (ApplicationLayerOnlyImageSingleton.isSingletonInstanceOf(singleton) && !ImageLayerBuildingSupport.lastImageBuild()) { throw UserError.abort("Application layer only image singleton can only be installed in the final layer: %s", singleton); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 2b6428215d6c..10f68b9696fe 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -241,6 +241,7 @@ import com.oracle.svm.hosted.image.NativeImageCodeCacheFactory; import com.oracle.svm.hosted.image.NativeImageHeap; import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; +import com.oracle.svm.hosted.imagelayer.LoadImageSingletonFeature; import com.oracle.svm.hosted.jdk.localization.LocalizationFeature; import com.oracle.svm.hosted.meta.HostedConstantReflectionProvider; import com.oracle.svm.hosted.meta.HostedField; @@ -825,6 +826,9 @@ protected boolean runPointsToAnalysis(String imageName, OptionValues options, De featureHandler.forEachFeature(feature -> feature.beforeAnalysis(config)); ServiceCatalogSupport.singleton().seal(); bb.getHostVM().getClassInitializationSupport().setConfigurationSealed(true); + if (ImageLayerBuildingSupport.buildingImageLayer()) { + ImageSingletons.lookup(LoadImageSingletonFeature.class).processRegisteredSingletons(aUniverse); + } } try (ReporterClosable c = ProgressReporter.singleton().printAnalysis(bb.getUniverse(), nativeLibraries.getLibraries())) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java index 7f76723acf0a..db7d68f96b00 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java @@ -43,7 +43,9 @@ import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageHeapObjectArray; +import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.c.CGlobalData; import com.oracle.svm.core.c.CGlobalDataFactory; @@ -148,18 +150,26 @@ public void duringSetup(DuringSetupAccess access) { LayeredImageHeapObjectAdder.singleton().registerObjectAdder(this::addInitialObjects); } - @Override - public void beforeAnalysis(BeforeAnalysisAccess access) { - var config = (FeatureImpl.BeforeAnalysisAccessImpl) access; - loader = (SVMImageLayerLoader) config.getUniverse().getImageLayerLoader(); + /** + * This method needs to be called after all image singletons are registered. Currently, some + * singletons are registered in + * {@link org.graalvm.nativeimage.hosted.Feature#beforeAnalysis(BeforeAnalysisAccess)}, but the + * singleton registration might get restricted to only + * {@link org.graalvm.nativeimage.hosted.Feature#duringSetup(DuringSetupAccess)} or before. In + * this case, this method should override + * {@link org.graalvm.nativeimage.hosted.Feature#beforeAnalysis(BeforeAnalysisAccess)}. + */ + public void processRegisteredSingletons(AnalysisUniverse universe) { + AnalysisMetaAccess metaAccess = universe.getBigbang().getMetaAccess(); + loader = (SVMImageLayerLoader) universe.getImageLayerLoader(); LayeredImageSingletonSupport layeredImageSingletonSupport = LayeredImageSingletonSupport.singleton(); layeredImageSingletonSupport.freezeMultiLayeredImageSingletons(); Consumer multiLayerEmbeddedRootsRegistration = (objArray) -> { - var method = config.getMetaAccess().lookupJavaMethod(ReflectionUtil.lookupMethod(MultiLayeredImageSingleton.class, "getAllLayers", Class.class)); - var javaConstant = config.getUniverse().getSnippetReflection().forObject(objArray); - config.getUniverse().registerEmbeddedRoot(javaConstant, new BytecodePosition(null, method, BytecodeFrame.UNKNOWN_BCI)); + var method = metaAccess.lookupJavaMethod(ReflectionUtil.lookupMethod(MultiLayeredImageSingleton.class, "getAllLayers", Class.class)); + var javaConstant = universe.getSnippetReflection().forObject(objArray); + universe.registerEmbeddedRoot(javaConstant, new BytecodePosition(null, method, BytecodeFrame.UNKNOWN_BCI)); }; if (ImageLayerBuildingSupport.buildingSharedLayer()) { @@ -208,13 +218,13 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { * Within the application layer there will be an array created to hold all * multi-layered image singletons. We must record this type is in the heap. */ - config.registerAsInHeap(slotInfo.keyClass().arrayType()); + metaAccess.lookupJavaType(slotInfo.keyClass().arrayType()).registerAsInstantiated("Array holding multi-layered image singletons"); if (!getCrossLayerSingletonMappingInfo().getPriorLayerObjectIDs(slotInfo.keyClass()).isEmpty()) { /* * We also must ensure the type is registered as instantiated in this * heap if we know the array will refer to a prior object. */ - config.registerAsInHeap(slotInfo.keyClass()); + metaAccess.lookupJavaType(slotInfo.keyClass()).registerAsInstantiated("Refers to a prior singleton"); } /* * GR-55294: The constants have to be created before the end of the analysis @@ -228,9 +238,9 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { } if (!applicationLayerEmbeddedRoots.isEmpty()) { - var method = config.getMetaAccess().lookupJavaMethod(ReflectionUtil.lookupMethod(ImageSingletons.class, "lookup", Class.class)); - var javaConstant = config.getUniverse().getSnippetReflection().forObject(applicationLayerEmbeddedRoots.toArray()); - config.getUniverse().registerEmbeddedRoot(javaConstant, new BytecodePosition(null, method, BytecodeFrame.UNKNOWN_BCI)); + var method = metaAccess.lookupJavaMethod(ReflectionUtil.lookupMethod(ImageSingletons.class, "lookup", Class.class)); + var javaConstant = universe.getSnippetReflection().forObject(applicationLayerEmbeddedRoots.toArray()); + universe.registerEmbeddedRoot(javaConstant, new BytecodePosition(null, method, BytecodeFrame.UNKNOWN_BCI)); } if (!multiLayerEmbeddedRoots.isEmpty()) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index 28b134e0bdab..c5896aa05423 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -1131,7 +1131,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec Class key = constantObjectParameter(b, targetMethod, 0, Class.class, classNode); boolean result = ImageSingletons.contains(key); if (!result && ImageLayerBuildingSupport.buildingImageLayer()) { - if (ApplicationLayerOnlyImageSingleton.class.isAssignableFrom(key) || MultiLayeredImageSingleton.class.isAssignableFrom(key)) { + if (ApplicationLayerOnlyImageSingleton.isAssignableFrom(key) || MultiLayeredImageSingleton.class.isAssignableFrom(key)) { /* * ApplicationLayerOnlyImageSingletons and the array representation of a * MultiLayeredImageSingleton will only be created in the final layer. @@ -1151,7 +1151,8 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode classNode) { Class key = constantObjectParameter(b, targetMethod, 0, Class.class, classNode); - if (ApplicationLayerOnlyImageSingleton.class.isAssignableFrom(key) && ImageLayerBuildingSupport.buildingSharedLayer()) { + if (ApplicationLayerOnlyImageSingleton.isAssignableFrom(key) && + ImageLayerBuildingSupport.buildingSharedLayer()) { /* * This singleton is only installed in the application layer heap. All other * layers looks refer to this singleton. From ffa764a19ad09fdd0d9e10f6ac22a15604a1b22b Mon Sep 17 00:00:00 2001 From: Sacha Coppey Date: Mon, 7 Oct 2024 11:44:22 +0200 Subject: [PATCH 103/105] Manually register Glob pattern nodes as instantiated in the base layer to avoid missed types --- .../oracle/svm/hosted/ResourcesFeature.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java index b7971900bc4d..d7e8fd941741 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java @@ -91,6 +91,7 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.config.ConfigurationParserUtils; +import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport; import com.oracle.svm.hosted.jdk.localization.LocalizationFeature; import com.oracle.svm.hosted.reflect.NativeImageConditionResolver; import com.oracle.svm.hosted.snippets.SubstrateGraphBuilderPlugins; @@ -393,9 +394,10 @@ protected boolean collectEmbeddedResourcesInfo() { } @Override - public void beforeAnalysis(BeforeAnalysisAccess access) { + public void beforeAnalysis(BeforeAnalysisAccess a) { + FeatureImpl.BeforeAnalysisAccessImpl access = (FeatureImpl.BeforeAnalysisAccessImpl) a; /* load and parse resource configuration files */ - ConfigurationConditionResolver conditionResolver = new NativeImageConditionResolver(((FeatureImpl.BeforeAnalysisAccessImpl) access).getImageClassLoader(), + ConfigurationConditionResolver conditionResolver = new NativeImageConditionResolver(access.getImageClassLoader(), ClassInitializationSupport.singleton()); ResourceConfigurationParser parser = ResourceConfigurationParser.create(true, conditionResolver, ResourcesRegistry.singleton(), @@ -415,6 +417,21 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { GlobTrieNode trie = CompressedGlobTrie.CompressedGlobTrieBuilder.build(patternsWithInfo); Resources.singleton().setResourcesTrieRoot(trie); + /* + * GR-58701: The SVM core is currently not included in the base layer of a Layered Image. + * Those specific types can be reachable from Resources#resourcesTrieRoot, but they can be + * missed by the analysis because the GlobTrieNode#children field is only available after + * analysis and the only reference to those types is with ThrowMissingRegistrationErrors + * enabled. Until a clear SVM core separation is created and included in the base layer, + * those types should be manually registered as instantiated before the analysis. + */ + if (HostedImageLayerBuildingSupport.buildingSharedLayer()) { + String reason = "Included in the base image"; + access.getMetaAccess().lookupJavaType(ReflectionUtil.lookupClass(false, "com.oracle.svm.core.jdk.resources.CompressedGlobTrie.LiteralNode")).registerAsInstantiated(reason); + access.getMetaAccess().lookupJavaType(ReflectionUtil.lookupClass(false, "com.oracle.svm.core.jdk.resources.CompressedGlobTrie.DoubleStarNode")).registerAsInstantiated(reason); + access.getMetaAccess().lookupJavaType(ReflectionUtil.lookupClass(false, "com.oracle.svm.core.jdk.resources.CompressedGlobTrie.StarTrieNode")).registerAsInstantiated(reason); + } + /* prepare regex patterns for resource registration */ resourcePatternWorkSet.addAll(Options.IncludeResources.getValue() .getValuesWithOrigins() From ebd01c6b0b9779f01d1b6f6d178011ec6e40c1cf Mon Sep 17 00:00:00 2001 From: Allan Gregersen Date: Mon, 28 Oct 2024 09:31:50 +0100 Subject: [PATCH 104/105] rename from ThreadJob to InvokeJob to ease readability --- .../jdwp/impl/DebuggerController.java | 18 ++++----- .../impl/{ThreadJob.java => InvokeJob.java} | 6 +-- .../truffle/espresso/jdwp/impl/JDWP.java | 38 +++++++++---------- 3 files changed, 31 insertions(+), 31 deletions(-) rename espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/{ThreadJob.java => InvokeJob.java} (96%) diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java index 937f5c3b70a0..2e0ce619a512 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/DebuggerController.java @@ -75,7 +75,7 @@ public final class DebuggerController implements ContextsListener { private final Map suspendLocks = Collections.synchronizedMap(new HashMap<>()); private final Map suspendedInfos = Collections.synchronizedMap(new HashMap<>()); private final Map commandRequestIds = new HashMap<>(); - private final Map> threadJobs = new HashMap<>(); + private final Map> invokeJobs = new HashMap<>(); private final Map fieldBreakpointExpected = new HashMap<>(); private final Map methodBreakpointExpected = new HashMap<>(); private final Map breakpointInfos = new HashMap<>(); @@ -698,9 +698,9 @@ private void lockThread(Object thread, boolean forceSuspend, List // we have the actual suspension status and suspended information threadSuspension.removeHardSuspendedThread(thread); fine(() -> "lock.wait() for thread: " + getThreadName(thread)); - // Having the thread lock, we can check if a thread job was posted outside of + // Having the thread lock, we can check if an invoke job was posted outside of // locking, and if so, we postpone blocking the thread until next time around. - if (!threadJobs.containsKey(thread)) { + if (!invokeJobs.containsKey(thread)) { lock.wait(); } } @@ -709,22 +709,22 @@ private void lockThread(Object thread, boolean forceSuspend, List // make sure the interrupted flag is set though Thread.currentThread().interrupt(); } - checkThreadJobsAndRun(thread); + checkInvokeJobsAndRun(thread); } fine(() -> "lock wakeup for thread: " + getThreadName(thread)); } - private void checkThreadJobsAndRun(Object thread) { - if (threadJobs.containsKey(thread)) { - ThreadJob job = threadJobs.remove(thread); + private void checkInvokeJobsAndRun(Object thread) { + if (invokeJobs.containsKey(thread)) { + InvokeJob job = invokeJobs.remove(thread); job.runJob(this); } } - public void postJobForThread(ThreadJob job) { + public void postInvokeJobForThread(InvokeJob job) { SimpleLock lock = getSuspendLock(job.getThread()); synchronized (lock) { - threadJobs.put(job.getThread(), job); + invokeJobs.put(job.getThread(), job); lock.notifyAll(); } } diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/ThreadJob.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/InvokeJob.java similarity index 96% rename from espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/ThreadJob.java rename to espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/InvokeJob.java index 9fe7d47f90f8..e657ef303403 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/ThreadJob.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/InvokeJob.java @@ -24,7 +24,7 @@ import java.util.concurrent.Callable; -public final class ThreadJob { +public final class InvokeJob { private final Object jobLock = new Object(); private final Object thread; @@ -33,11 +33,11 @@ public final class ThreadJob { private boolean resultAvailable; private JobResult result; - public ThreadJob(Object guestThread, Callable task) { + public InvokeJob(Object guestThread, Callable task) { this(guestThread, task, SuspendStrategy.EVENT_THREAD); } - public ThreadJob(Object guestThread, Callable task, byte suspensionStrategy) { + public InvokeJob(Object guestThread, Callable task, byte suspensionStrategy) { this.thread = guestThread; this.callable = task; this.suspensionStrategy = suspensionStrategy; diff --git a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java index ed5b5f0a7ae9..c7e027eeb19d 100644 --- a/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java +++ b/espresso/src/com.oracle.truffle.espresso.jdwp/src/com/oracle/truffle/espresso/jdwp/impl/JDWP.java @@ -1163,8 +1163,8 @@ static CommandResult createReply(Packet packet, DebuggerController controller, D try { // we have to call the method in the correct thread, so post a // Callable to the controller and wait for the result to appear - ThreadJob job = new ThreadJob<>(thread, () -> method.invokeMethodStatic(args), suspensionStrategy); - controller.postJobForThread(job); + InvokeJob job = new InvokeJob<>(thread, () -> method.invokeMethodStatic(args), suspensionStrategy); + controller.postInvokeJobForThread(job); // invocation of a method can cause events with possible thread suspension // to happen, e.g. class prepare events for newly loaded classes @@ -1175,8 +1175,8 @@ static CommandResult createReply(Packet packet, DebuggerController controller, D public void run() { CommandResult commandResult = new CommandResult(reply); try { - ThreadJob.JobResult result = job.getResult(); - writeMethodResult(reply, context, result, thread, controller); + InvokeJob.JobResult result = job.getResult(); + writeMethodResult(reply, context, result); } catch (Throwable t) { reply.errorCode(ErrorCodes.INTERNAL); controller.severe(INVOKE_METHOD.class.getName() + ".createReply", t); @@ -1246,15 +1246,15 @@ static CommandResult createReply(Packet packet, DebuggerController controller) { try { // we have to call the constructor in the correct thread, so post a // Callable to the controller and wait for the result to appear - ThreadJob job = new ThreadJob<>(thread, () -> { + InvokeJob job = new InvokeJob<>(thread, () -> { args[0] = context.allocateInstance(klass); method.invokeMethodSpecial(args); return args[0]; }, suspensionStrategy); - controller.postJobForThread(job); - ThreadJob.JobResult result = job.getResult(); + controller.postInvokeJobForThread(job); + InvokeJob.JobResult result = job.getResult(); - writeMethodResult(reply, context, result, thread, controller); + writeMethodResult(reply, context, result); } catch (Throwable t) { throw new RuntimeException("not able to invoke static method through jdwp", t); } @@ -1350,8 +1350,8 @@ static CommandResult createReply(Packet packet, DebuggerController controller, D try { // we have to call the method in the correct thread, so post a // Callable to the controller and wait for the result to appear - ThreadJob job = new ThreadJob<>(thread, () -> method.invokeMethodStatic(args), suspensionStrategy); - controller.postJobForThread(job); + InvokeJob job = new InvokeJob<>(thread, () -> method.invokeMethodStatic(args), suspensionStrategy); + controller.postInvokeJobForThread(job); // invocation of a method can cause events with possible thread suspension // to happen, e.g. class prepare events for newly loaded classes // to avoid blocking here, we fire up a new thread that will post @@ -1361,8 +1361,8 @@ static CommandResult createReply(Packet packet, DebuggerController controller, D public void run() { CommandResult commandResult = new CommandResult(reply); try { - ThreadJob.JobResult result = job.getResult(); - writeMethodResult(reply, context, result, thread, controller); + InvokeJob.JobResult result = job.getResult(); + writeMethodResult(reply, context, result); } catch (Throwable t) { reply.errorCode(ErrorCodes.INTERNAL); controller.severe(INVOKE_METHOD.class.getName() + "." + "createReply", t); @@ -1807,7 +1807,7 @@ static CommandResult createReply(Packet packet, DebuggerController controller, D try { // we have to call the method in the correct thread, so post a // Callable to the controller and wait for the result to appear - ThreadJob job = new ThreadJob<>(thread, () -> { + InvokeJob job = new InvokeJob<>(thread, () -> { if (invokeNonvirtual) { return method.invokeMethodNonVirtual(args); } else if (Modifier.isPrivate(method.getModifiers())) { @@ -1818,7 +1818,7 @@ static CommandResult createReply(Packet packet, DebuggerController controller, D return method.invokeMethodVirtual(args); } }, suspensionStrategy); - controller.postJobForThread(job); + controller.postInvokeJobForThread(job); // invocation of a method can cause events with possible thread suspension // to happen, e.g. class prepare events for newly loaded classes // to avoid blocking here, we fire up a new thread that will post @@ -1828,8 +1828,8 @@ static CommandResult createReply(Packet packet, DebuggerController controller, D public void run() { CommandResult commandResult = new CommandResult(reply); try { - ThreadJob.JobResult result = job.getResult(); - writeMethodResult(reply, context, result, thread, controller); + InvokeJob.JobResult result = job.getResult(); + writeMethodResult(reply, context, result); } catch (Throwable t) { reply.errorCode(ErrorCodes.INTERNAL); controller.severe(INVOKE_METHOD.class.getName() + "." + "createReply", t); @@ -2393,11 +2393,11 @@ static CommandResult createReply(Packet packet, DebuggerController controller) { } // make sure owned monitors taken in frame are exited - ThreadJob job = new ThreadJob<>(thread, () -> { + InvokeJob job = new InvokeJob<>(thread, () -> { controller.getContext().clearFrameMonitors(topFrame); return null; }); - controller.postJobForThread(job); + controller.postInvokeJobForThread(job); // don't return here before job completed job.getResult(); @@ -3042,7 +3042,7 @@ public static void writeValue(byte tag, Object value, PacketStream reply, boolea } } - private static void writeMethodResult(PacketStream reply, JDWPContext context, ThreadJob.JobResult result, Object thread, DebuggerController controller) { + private static void writeMethodResult(PacketStream reply, JDWPContext context, InvokeJob.JobResult result) { if (result.getException() != null) { reply.writeByte(TagConstants.OBJECT); reply.writeLong(0); From f9fb072579af136671a85ffe8796bceae515618d Mon Sep 17 00:00:00 2001 From: Jirka Marsik Date: Mon, 28 Oct 2024 17:27:24 +0000 Subject: [PATCH 105/105] [GR-59352] Handle bigint when finding primitive constructor names for error msgs. PullRequest: js/3301 --- vm/mx.vm/suite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/mx.vm/suite.py b/vm/mx.vm/suite.py index 9d0d776288e8..5588f666f994 100644 --- a/vm/mx.vm/suite.py +++ b/vm/mx.vm/suite.py @@ -33,7 +33,7 @@ "name": "graal-nodejs", "subdir": True, "dynamic": True, - "version": "fd636bb71941edceafcd36f007944231dbf9022b", + "version": "50e8f835c1a88c7b64921daed543e7ca0865f8fb", "urls" : [ {"url" : "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ] @@ -42,7 +42,7 @@ "name": "graal-js", "subdir": True, "dynamic": True, - "version": "fd636bb71941edceafcd36f007944231dbf9022b", + "version": "50e8f835c1a88c7b64921daed543e7ca0865f8fb", "urls": [ {"url": "https://github.com/graalvm/graaljs.git", "kind" : "git"}, ]