diff --git a/compiler/src/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java b/compiler/src/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java index 27ff664df881..3051888f0af0 100644 --- a/compiler/src/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java +++ b/compiler/src/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java @@ -24,10 +24,14 @@ */ package org.graalvm.compiler.api.replacements; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; import java.util.Objects; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; /** @@ -93,4 +97,23 @@ default JavaConstant forBoxed(JavaKind kind, Object value) { * cannot map {@link ResolvedJavaType} instances to {@link Class} instances */ Class originalClass(ResolvedJavaType type); + + /** + * Get the original Java method/constructor corresponding to a {@link ResolvedJavaMethod}. + * + * @param method the method for which the original Java method/constructor is requested + * @return the original Java method corresponding to {@code method} or {@code null} if this + * object cannot map {@link ResolvedJavaMethod} instances to {@link Executable} + * instances + */ + Executable originalMethod(ResolvedJavaMethod method); + + /** + * Get the original Java field corresponding to a {@link ResolvedJavaField}. + * + * @param field the field for which the original Java field is requested + * @return the original Java field corresponding to {@code field} or {@code null} if this object + * cannot map {@link ResolvedJavaField} instances to {@link Field} instances. + */ + Field originalField(ResolvedJavaField field); } diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EncodedSnippets.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EncodedSnippets.java index 9016b86bed27..76b1ff5c96fc 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EncodedSnippets.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/EncodedSnippets.java @@ -29,6 +29,8 @@ import static org.graalvm.compiler.hotspot.HotSpotReplacementsImpl.isGraalClass; import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @@ -279,6 +281,16 @@ public T getInjectedNodeIntrinsicParameter(Class type) { public Class originalClass(ResolvedJavaType type) { return delegate.originalClass(type); } + + @Override + public Executable originalMethod(ResolvedJavaMethod method) { + return delegate.originalMethod(method); + } + + @Override + public Field originalField(ResolvedJavaField field) { + return delegate.originalField(field); + } } @SuppressWarnings("try") diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java index d628da8869d6..a992d69a83c5 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java @@ -26,7 +26,12 @@ import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.SnippetObjectConstant; @@ -36,7 +41,10 @@ import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.services.Services; public class HotSpotSnippetReflectionProvider implements SnippetReflectionProvider { @@ -44,10 +52,39 @@ public class HotSpotSnippetReflectionProvider implements SnippetReflectionProvid private final HotSpotConstantReflectionProvider constantReflection; private final WordTypes wordTypes; + /* + * GR-41976: JVMCI currently does not have public API to convert methods and fields back to + * reflection objects. So we do it via reflective invocation of JVMCI internals. + * + * These fields are intentionally not static, because we do not want libgraal to run with the + * state initialized at image build time. + */ + private final Method hotSpotJDKReflectionGetMethod; + private final Method hotSpotJDKReflectionGetField; + public HotSpotSnippetReflectionProvider(HotSpotGraalRuntimeProvider runtime, HotSpotConstantReflectionProvider constantReflection, WordTypes wordTypes) { this.runtime = runtime; this.constantReflection = constantReflection; this.wordTypes = wordTypes; + + if (Services.IS_IN_NATIVE_IMAGE) { + /* No access to method/field mirrors when running in libgraal. */ + hotSpotJDKReflectionGetMethod = null; + hotSpotJDKReflectionGetField = null; + } else { + try { + Class hsJDKReflection = Class.forName("jdk.vm.ci.hotspot.HotSpotJDKReflection"); + hotSpotJDKReflectionGetMethod = lookupMethod(hsJDKReflection, "getMethod", Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl")); + hotSpotJDKReflectionGetField = lookupMethod(hsJDKReflection, "getField", Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedJavaFieldImpl")); + } catch (ReflectiveOperationException ex) { + /* + * Note that older JVMCI versions do not have those methods even when running in JDK + * mode and not in libgraal mode. But that affects only OpenJDK 11, and we no longer + * support JDK 11 at all. OpenJDK 17 already has the necessary methods. + */ + throw GraalError.shouldNotReachHere(ex); + } + } } @Override @@ -112,4 +149,53 @@ public T getInjectedNodeIntrinsicParameter(Class type) { public Class originalClass(ResolvedJavaType type) { return runtime().getMirror(type); } + + private static Method lookupMethod(Class declaringClass, String methodName, Class... parameterTypes) throws ReflectiveOperationException { + Method result = declaringClass.getDeclaredMethod(methodName, parameterTypes); + result.setAccessible(true); + return result; + } + + @Override + public Executable originalMethod(ResolvedJavaMethod method) { + if (method.isClassInitializer()) { + /* methods never have a corresponding java.lang.reflect.Method. */ + return null; + } + + if (hotSpotJDKReflectionGetMethod == null) { + return null; + } + try { + return (Executable) hotSpotJDKReflectionGetMethod.invoke(null, method); + } catch (ReflectiveOperationException ex) { + throw rethrow(ex.getCause()); + } + } + + @Override + public Field originalField(ResolvedJavaField field) { + if (hotSpotJDKReflectionGetField == null) { + return null; + } + try { + return (Field) hotSpotJDKReflectionGetField.invoke(null, field); + } catch (ReflectiveOperationException ex) { + if (ex.getCause() instanceof IllegalArgumentException) { + /** + * GR-41974: A bug in JVMCI prevents the lookup of the java.lang.reflect.Field. + * Since even calling getName() on the ResolvedJavaField crashes for such fields, we + * also cannot use Class.getDeclaredField as a workaround for lookup. Our only + * option is to return null for now. + */ + return null; + } + throw rethrow(ex.getCause()); + } + } + + @SuppressWarnings({"unchecked"}) + private static RuntimeException rethrow(Throwable ex) throws E { + throw (E) ex; + } } diff --git a/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsTest.java b/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsTest.java index 9657c077162e..a57ccd727fd7 100644 --- a/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsTest.java +++ b/compiler/src/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsTest.java @@ -24,6 +24,9 @@ */ package org.graalvm.compiler.replacements.test; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; + import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.replacements.ReplacementsImpl; @@ -34,6 +37,8 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; public class ReplacementsTest extends GraalCompilerTest { @@ -58,6 +63,16 @@ public Class originalClass(ResolvedJavaType type) { return null; } + @Override + public Executable originalMethod(ResolvedJavaMethod method) { + return null; + } + + @Override + public Field originalField(ResolvedJavaField field) { + return null; + } + @Override public T getInjectedNodeIntrinsicParameter(Class type) { return null; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalFieldProvider.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalFieldProvider.java index 7d07e9162ce6..7b2ff5b3dfab 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalFieldProvider.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalFieldProvider.java @@ -35,16 +35,8 @@ public interface OriginalFieldProvider { static Field getJavaField(SnippetReflectionProvider reflectionProvider, ResolvedJavaField field) { if (field instanceof OriginalFieldProvider) { return ((OriginalFieldProvider) field).getJavaField(); - } - Class declaringClass = OriginalClassProvider.getJavaClass(reflectionProvider, field.getDeclaringClass()); - try { - return declaringClass.getDeclaredField(field.getName()); - } catch (Throwable e) { - /* - * Return null if there is some incomplete classpath issue or the field is either - * missing or hidden from reflection. - */ - return null; + } else { + return reflectionProvider.originalField(field); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalMethodProvider.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalMethodProvider.java index 631d6136fd7f..51d444062f95 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalMethodProvider.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/OriginalMethodProvider.java @@ -28,32 +28,15 @@ import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; -import com.oracle.graal.pointsto.util.AnalysisError; - import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; public interface OriginalMethodProvider { static Executable getJavaMethod(SnippetReflectionProvider reflectionProvider, ResolvedJavaMethod method) { if (method instanceof OriginalMethodProvider) { return ((OriginalMethodProvider) method).getJavaMethod(); - } - try { - ResolvedJavaMethod.Parameter[] parameters = method.getParameters(); - Class[] parameterTypes = new Class[parameters.length]; - ResolvedJavaType declaringClassType = method.getDeclaringClass(); - for (int i = 0; i < parameterTypes.length; i++) { - parameterTypes[i] = OriginalClassProvider.getJavaClass(reflectionProvider, parameters[i].getType().resolve(declaringClassType)); - } - Class declaringClass = OriginalClassProvider.getJavaClass(reflectionProvider, declaringClassType); - if (method.isConstructor()) { - return declaringClass.getDeclaredConstructor(parameterTypes); - } else { - return declaringClass.getDeclaredMethod(method.getName(), parameterTypes); - } - } catch (NoSuchMethodException e) { - throw AnalysisError.shouldNotReachHere(); + } else { + return reflectionProvider.originalMethod(method); } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java index 10cf1bc4ab2d..2f37314fcb25 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedConstantPool.java @@ -37,8 +37,8 @@ import com.oracle.graal.pointsto.constraints.UnresolvedElementException; import com.oracle.graal.pointsto.util.AnalysisError.TypeNotFoundError; import com.oracle.svm.util.ReflectionUtil; -import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError; +import jdk.vm.ci.hotspot.HotSpotConstantPool; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaField; @@ -64,83 +64,28 @@ public int length() { return wrapped.length(); } - /** - * The method loadReferencedType(int cpi, int opcode, boolean initialize) is present in - * HotSpotConstantPool both in the JVMCI-enabled JDK 8 (starting with JVMCI 0.47) and JDK 11, - * but it is not in the API (the {@link ConstantPool} interface). For JDK 11, it is also too - * late to change the API, so we need to invoke this method using reflection. - */ - private static final Method hsLoadReferencedType; - private static final Method hsLookupReferencedType; - /** * The method jdk.vm.ci.meta.ConstantPool#lookupBootstrapMethodInvocation(int cpi, int opcode) * was introduced in JVMCI 22.1. */ - private static final Method hsLookupBootstrapMethodInvocation; + private static final Method cpLookupBootstrapMethodInvocation = ReflectionUtil.lookupMethod(true, ConstantPool.class, "lookupBootstrapMethodInvocation", int.class, int.class); /** * {@code jdk.vm.ci.meta.ConstantPool.lookupMethod(int cpi, int opcode, ResolvedJavaMethod caller)} * was introduced in JVMCI 22.3. */ - private static final Method lookupMethodWithCaller; + private static final Method lookupMethodWithCaller = ReflectionUtil.lookupMethod(true, ConstantPool.class, "lookupMethod", int.class, int.class, ResolvedJavaMethod.class); /** * The interface jdk.vm.ci.meta.ConstantPool.BootstrapMethodInvocation was introduced in JVMCI * 22.1. */ - private static final Method bsmGetMethod; - private static final Method bsmIsInvokeDynamic; - private static final Method bsmGetName; - private static final Method bsmGetType; - private static final Method bsmGetStaticArguments; - - static { - try { - Class hsConstantPool = Class.forName("jdk.vm.ci.hotspot.HotSpotConstantPool"); - hsLoadReferencedType = ReflectionUtil.lookupMethod(hsConstantPool, "loadReferencedType", int.class, int.class, boolean.class); - } catch (ClassNotFoundException | ReflectionUtilError ex) { - throw GraalError.shouldNotReachHere("JVMCI 0.47 or later, or JDK 11 is required for Substrate VM: could not find method HotSpotConstantPool.loadReferencedType"); - } - - Method lookupReferencedType = null; - try { - Class hsConstantPool = Class.forName("jdk.vm.ci.hotspot.HotSpotConstantPool"); - lookupReferencedType = ReflectionUtil.lookupMethod(hsConstantPool, "lookupReferencedType", int.class, int.class); - } catch (ClassNotFoundException | ReflectionUtilError ex) { - } - hsLookupReferencedType = lookupReferencedType; - - Method lookupBootstrapMethodInvocation = null; - try { - Class hsConstantPool = Class.forName("jdk.vm.ci.hotspot.HotSpotConstantPool"); - lookupBootstrapMethodInvocation = ReflectionUtil.lookupMethod(hsConstantPool, "lookupBootstrapMethodInvocation", int.class, int.class); - } catch (ClassNotFoundException | ReflectionUtilError ex) { - } - hsLookupBootstrapMethodInvocation = lookupBootstrapMethodInvocation; - - lookupMethodWithCaller = ReflectionUtil.lookupMethod(true, ConstantPool.class, "lookupMethod", int.class, int.class, ResolvedJavaMethod.class); - - Method getMethod = null; - Method isInvokeDynamic = null; - Method getName = null; - Method getType = null; - Method getStaticArguments = null; - try { - Class bootstrapMethodInvocation = Class.forName("jdk.vm.ci.meta.ConstantPool$BootstrapMethodInvocation"); - getMethod = ReflectionUtil.lookupMethod(bootstrapMethodInvocation, "getMethod"); - isInvokeDynamic = ReflectionUtil.lookupMethod(bootstrapMethodInvocation, "isInvokeDynamic"); - getName = ReflectionUtil.lookupMethod(bootstrapMethodInvocation, "getName"); - getType = ReflectionUtil.lookupMethod(bootstrapMethodInvocation, "getType"); - getStaticArguments = ReflectionUtil.lookupMethod(bootstrapMethodInvocation, "getStaticArguments"); - } catch (ClassNotFoundException | ReflectionUtilError ex) { - } - bsmGetMethod = getMethod; - bsmIsInvokeDynamic = isInvokeDynamic; - bsmGetName = getName; - bsmGetType = getType; - bsmGetStaticArguments = getStaticArguments; - } + private static final Class bsmClass = ReflectionUtil.lookupClass(true, "jdk.vm.ci.meta.ConstantPool$BootstrapMethodInvocation"); + private static final Method bsmGetMethod = bsmClass == null ? null : ReflectionUtil.lookupMethod(bsmClass, "getMethod"); + private static final Method bsmIsInvokeDynamic = bsmClass == null ? null : ReflectionUtil.lookupMethod(bsmClass, "isInvokeDynamic"); + private static final Method bsmGetName = bsmClass == null ? null : ReflectionUtil.lookupMethod(bsmClass, "getName"); + private static final Method bsmGetType = bsmClass == null ? null : ReflectionUtil.lookupMethod(bsmClass, "getType"); + private static final Method bsmGetStaticArguments = bsmClass == null ? null : ReflectionUtil.lookupMethod(bsmClass, "getStaticArguments"); public static void loadReferencedType(ConstantPool cp, int cpi, int opcode, boolean initialize) { ConstantPool root = cp; @@ -149,16 +94,17 @@ public static void loadReferencedType(ConstantPool cp, int cpi, int opcode, bool } try { - hsLoadReferencedType.invoke(root, cpi, opcode, initialize); + /* + * GR-41975: loadReferencedType without triggering class initialization is available in + * HotSpotConstantPool, but not yet in ConstantPool. + */ + ((HotSpotConstantPool) root).loadReferencedType(cpi, opcode, initialize); } catch (Throwable ex) { Throwable cause = ex; - if (ex instanceof InvocationTargetException && ex.getCause() != null) { - cause = ex.getCause(); - if (cause instanceof BootstrapMethodError && cause.getCause() != null) { - cause = cause.getCause(); - } - } else if (ex instanceof ExceptionInInitializerError && ex.getCause() != null) { - cause = ex.getCause(); + if (cause instanceof BootstrapMethodError && cause.getCause() != null) { + cause = cause.getCause(); + } else if (cause instanceof ExceptionInInitializerError && cause.getCause() != null) { + cause = cause.getCause(); } throw new UnresolvedElementException("Error loading a referenced type: " + cause.toString(), cause); } @@ -205,39 +151,6 @@ public JavaMethod lookupMethod(int cpi, int opcode, ResolvedJavaMethod caller) { } } - /** - * Trying to get straight to the VM constant pool without going through the layers of universe - * lookups. The VM constant pool resolves a method without resolving its return/parameter/locals - * types, whereas the universe is usually eagerly tries to resolve return/parameter/locals. - * Thus, this method can be used when the JavaMethod is needed even when the universe resolution - * fails. Since there might be multiple constant pools that wrap each other for various stages - * in compilation, potentially each with a different universe, we go down until the constant - * pool found is not a WrappedConstantPool. - */ - public JavaMethod lookupMethodInWrapped(int cpi, int opcode) { - if (wrapped instanceof WrappedConstantPool) { - return ((WrappedConstantPool) wrapped).lookupMethodInWrapped(cpi, opcode); - } else { - return wrapped.lookupMethod(cpi, opcode); - } - } - - public JavaType lookupTypeInWrapped(int cpi, int opcode) { - if (wrapped instanceof WrappedConstantPool) { - return ((WrappedConstantPool) wrapped).lookupTypeInWrapped(cpi, opcode); - } else { - return wrapped.lookupType(cpi, opcode); - } - } - - public JavaField lookupFieldInWrapped(int cpi, ResolvedJavaMethod method, int opcode) { - if (wrapped instanceof WrappedConstantPool) { - return ((WrappedConstantPool) wrapped).lookupFieldInWrapped(cpi, method, opcode); - } else { - return wrapped.lookupField(cpi, method, opcode); - } - } - @Override public JavaType lookupType(int cpi, int opcode) { try { @@ -282,30 +195,20 @@ public Object lookupConstant(int cpi) { @Override public JavaType lookupReferencedType(int index, int opcode) { - if (hsLookupReferencedType != null) { - try { - JavaType type = null; - if (wrapped instanceof WrappedConstantPool) { - type = ((WrappedConstantPool) wrapped).lookupReferencedType(index, opcode); - } else { - try { - type = (JavaType) hsLookupReferencedType.invoke(wrapped, index, opcode); - } catch (Throwable ex) { - } - } - if (type != null) { - return universe.lookupAllowUnresolved(type); - } - } catch (TypeNotFoundError e) { + try { + JavaType type = wrapped.lookupReferencedType(index, opcode); + if (type != null) { + return universe.lookupAllowUnresolved(type); } + } catch (TypeNotFoundError e) { } return null; } public BootstrapMethodIntrospection lookupBootstrapMethodIntrospection(int cpi, int opcode) { - if (hsLookupBootstrapMethodInvocation != null) { + if (cpLookupBootstrapMethodInvocation != null) { try { - Object bootstrapMethodInvocation = hsLookupBootstrapMethodInvocation.invoke(wrapped, cpi, opcode); + Object bootstrapMethodInvocation = cpLookupBootstrapMethodInvocation.invoke(wrapped, cpi, opcode); return new WrappedBootstrapMethodInvocation(bootstrapMethodInvocation); } catch (Throwable ignored) { // GR-38955 - understand why exception is thrown diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/UninitializedStaticFieldValueReader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/UninitializedStaticFieldValueReader.java index 2c2ebdebf69a..c6fc08540be8 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/UninitializedStaticFieldValueReader.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/UninitializedStaticFieldValueReader.java @@ -59,6 +59,9 @@ public class UninitializedStaticFieldValueReader { * primitive types or the String type. By limiting the Unsafe read to these narrow cases, it is * pretty likely (although not guaranteed) that we are not returning an unintended value for a * class that is re-initialized at run time. + * + * GR-41856 should provide a proper JVMCI API to read the ConstantValue attribute of a field, + * which then makes this method unnecessary. */ public static JavaConstant readUninitializedStaticValue(AnalysisField field, Function function) { JavaKind kind = field.getJavaKind(); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/GraalAccess.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/GraalAccess.java index 5cf94bbe3c41..81ddc5be4fe3 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/GraalAccess.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/GraalAccess.java @@ -24,33 +24,52 @@ */ package com.oracle.graal.pointsto.util; +import java.util.Objects; + import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; +import org.graalvm.compiler.api.runtime.GraalRuntime; +import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.runtime.RuntimeProvider; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.runtime.JVMCI; +@Platforms(Platform.HOSTED_ONLY.class) public final class GraalAccess { + private static final GraalRuntime graalRuntime; + private static final TargetDescription originalTarget; + private static final Providers originalProviders; + private static final SnippetReflectionProvider originalSnippetReflection; + + static { + graalRuntime = ((GraalJVMCICompiler) JVMCI.getRuntime().getCompiler()).getGraalRuntime(); + Backend hostBackend = getGraalCapability(RuntimeProvider.class).getHostBackend(); + originalTarget = Objects.requireNonNull(hostBackend.getTarget()); + originalProviders = Objects.requireNonNull(hostBackend.getProviders()); + originalSnippetReflection = Objects.requireNonNull(getGraalCapability(SnippetReflectionProvider.class)); + } + private GraalAccess() { } public static TargetDescription getOriginalTarget() { - return getGraalCapability(RuntimeProvider.class).getHostBackend().getTarget(); + return originalTarget; } public static Providers getOriginalProviders() { - return getGraalCapability(RuntimeProvider.class).getHostBackend().getProviders(); + return originalProviders; } public static SnippetReflectionProvider getOriginalSnippetReflection() { - return getGraalCapability(SnippetReflectionProvider.class); + return originalSnippetReflection; } public static T getGraalCapability(Class clazz) { - GraalJVMCICompiler compiler = (GraalJVMCICompiler) JVMCI.getRuntime().getCompiler(); - return compiler.getGraalRuntime().getCapability(clazz); + return graalRuntime.getCapability(clazz); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateSnippetReflectionProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateSnippetReflectionProvider.java index 451e8eae732a..77e1e2ac98bc 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateSnippetReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateSnippetReflectionProvider.java @@ -24,6 +24,9 @@ */ package com.oracle.svm.core.graal.meta; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; + import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.word.WordTypes; @@ -32,6 +35,8 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; public class SubstrateSnippetReflectionProvider implements SnippetReflectionProvider { @@ -70,4 +75,14 @@ public T getInjectedNodeIntrinsicParameter(Class type) { public Class originalClass(ResolvedJavaType type) { throw VMError.shouldNotReachHere(); } + + @Override + public Executable originalMethod(ResolvedJavaMethod method) { + throw VMError.shouldNotReachHere(); + } + + @Override + public Field originalField(ResolvedJavaField field) { + throw VMError.shouldNotReachHere(); + } } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareSnippetReflectionProvider.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareSnippetReflectionProvider.java index 9440e2e5c496..ca51583a626d 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareSnippetReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareSnippetReflectionProvider.java @@ -24,6 +24,9 @@ */ package com.oracle.svm.graal.isolated; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; + import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import com.oracle.svm.core.SubstrateOptions; @@ -31,6 +34,8 @@ import com.oracle.svm.core.util.VMError; import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; final class IsolateAwareSnippetReflectionProvider implements SnippetReflectionProvider { @@ -56,4 +61,14 @@ public T getInjectedNodeIntrinsicParameter(Class type) { public Class originalClass(ResolvedJavaType type) { throw VMError.shouldNotReachHere(); } + + @Override + public Executable originalMethod(ResolvedJavaMethod method) { + throw VMError.shouldNotReachHere(); + } + + @Override + public Field originalField(ResolvedJavaField field) { + throw VMError.shouldNotReachHere(); + } } 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 198083671fcc..efeea91be7dd 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 @@ -57,7 +57,6 @@ import java.util.function.BooleanSupplier; import java.util.stream.Collectors; -import com.oracle.svm.hosted.c.libc.HostedLibCBase; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.MapCursor; @@ -259,6 +258,7 @@ import com.oracle.svm.hosted.c.OffsetOfSupportImpl; import com.oracle.svm.hosted.c.SizeOfSupportImpl; import com.oracle.svm.hosted.c.codegen.CCompilerInvoker; +import com.oracle.svm.hosted.c.libc.HostedLibCBase; import com.oracle.svm.hosted.cenum.CEnumCallWrapperSubstitutionProcessor; import com.oracle.svm.hosted.classinitialization.ClassInitializationFeature; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; @@ -1252,14 +1252,10 @@ public static void registerGraphBuilderPlugins(FeatureHandler featureHandler, Ru featureHandler.forEachGraalFeature(feature -> feature.registerGraphBuilderPlugins(providers, plugins, reason)); HostedSnippetReflectionProvider hostedSnippetReflection = new HostedSnippetReflectionProvider(new SubstrateWordTypes(aMetaAccess, FrameAccess.getWordKind())); - HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) HotSpotJVMCIRuntime.runtime().getCompiler(); NodeIntrinsificationProvider nodeIntrinsificationProvider; - if (!SubstrateUtil.isBuildingLibgraal()) { - nodeIntrinsificationProvider = new NodeIntrinsificationProvider(providers.getMetaAccess(), hostedSnippetReflection, providers.getForeignCalls(), - providers.getWordTypes(), target); - - } else { + if (SubstrateUtil.isBuildingLibgraal()) { + HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) HotSpotJVMCIRuntime.runtime().getCompiler(); nodeIntrinsificationProvider = new NodeIntrinsificationProvider(providers.getMetaAccess(), hostedSnippetReflection, providers.getForeignCalls(), providers.getWordTypes(), target) { @Override @@ -1273,6 +1269,9 @@ public T getInjectedArgument(Class type) { return super.getInjectedArgument(type); } }; + } else { + nodeIntrinsificationProvider = new NodeIntrinsificationProvider(providers.getMetaAccess(), hostedSnippetReflection, providers.getForeignCalls(), + providers.getWordTypes(), target); } for (Class factoryClass : loader.findSubclasses(GeneratedPluginFactory.class, true)) { if (!Modifier.isAbstract(factoryClass.getModifiers()) && !factoryClass.getName().contains("hotspot")) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java index 0f5e08a114b2..3a6f96846927 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java @@ -40,21 +40,21 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.graalvm.compiler.debug.GraalError; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.impl.AnnotationExtractor; +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; +import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; +import com.oracle.graal.pointsto.util.GraalAccess; import com.oracle.svm.hosted.annotation.AnnotationMetadata.AnnotationExtractionError; import com.oracle.svm.util.AnnotationWrapper; import com.oracle.svm.util.ReflectionUtil; import jdk.internal.reflect.ConstantPool; -import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaField; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; -import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; import sun.reflect.annotation.AnnotationParser; /** @@ -98,67 +98,11 @@ public class SubstrateAnnotationExtractor implements AnnotationExtractor { private static final Field methodParameterAnnotations = ReflectionUtil.lookupField(Method.class, "parameterAnnotations"); private static final Field methodAnnotationDefault = ReflectionUtil.lookupField(Method.class, "annotationDefault"); private static final Field constructorParameterAnnotations = ReflectionUtil.lookupField(Constructor.class, "parameterAnnotations"); - private static final Class recordComponentClass; - private static final Field recordComponentAnnotations; - private static final Field recordComponentTypeAnnotations; - private static final Method recordComponentGetDeclaringRecord; + private static final Class recordComponentClass = ReflectionUtil.lookupClass(true, "java.lang.reflect.RecordComponent"); + private static final Field recordComponentAnnotations = recordComponentClass == null ? null : ReflectionUtil.lookupField(recordComponentClass, "annotations"); + private static final Field recordComponentTypeAnnotations = recordComponentClass == null ? null : ReflectionUtil.lookupField(recordComponentClass, "typeAnnotations"); + private static final Method recordComponentGetDeclaringRecord = recordComponentClass == null ? null : ReflectionUtil.lookupMethod(recordComponentClass, "getDeclaringRecord"); private static final Method packageGetPackageInfo = ReflectionUtil.lookupMethod(Package.class, "getPackageInfo"); - private static final Object hotSpotJVMCIRuntimeReflection; - private static final Method hotSpotJDKReflectionGetMirror; - private static final Method hotSpotJDKReflectionGetMethod; - private static final Method hotSpotJDKReflectionGetField; - private static final boolean isHotSpotJDKReflectionAvailable; - private static final Method hotSpotResolvedObjectTypeImplMirror; - private static final Method hotSpotResolvedPrimitiveTypeMirror; - private static final Method hotSpotResolvedJavaMethodImplToJava; - private static final Method hotSpotResolvedJavaFieldImplToJava; - - static { - recordComponentClass = ReflectionUtil.lookupClass(true, "java.lang.reflect.RecordComponent"); - recordComponentAnnotations = recordComponentClass != null ? ReflectionUtil.lookupField(recordComponentClass, "annotations") : null; - recordComponentTypeAnnotations = recordComponentClass != null ? ReflectionUtil.lookupField(recordComponentClass, "typeAnnotations") : null; - recordComponentGetDeclaringRecord = recordComponentClass != null ? ReflectionUtil.lookupMethod(recordComponentClass, "getDeclaringRecord") : null; - - Object temporaryHotSpotJVMCIRuntimeReflection = null; - Method temporaryHotSpotJDKReflectionGetMirror = null; - Method temporaryHotSpotJDKReflectionGetMethod = null; - Method temporaryHotSpotJDKReflectionGetField = null; - boolean temporaryIsHotSpotJDKReflectionAvailable = true; - - try { - Object hotSpotJVMCIRuntime = ReflectionUtil.lookupMethod(HotSpotJVMCIRuntime.class, "runtime").invoke(null); - temporaryHotSpotJVMCIRuntimeReflection = ReflectionUtil.lookupMethod(HotSpotJVMCIRuntime.class, "getReflection").invoke(hotSpotJVMCIRuntime); - temporaryHotSpotJDKReflectionGetMirror = ReflectionUtil.lookupMethod(Class.forName("jdk.vm.ci.hotspot.HotSpotJDKReflection"), "getMirror", HotSpotResolvedJavaType.class); - temporaryHotSpotJDKReflectionGetMethod = ReflectionUtil.lookupMethod(Class.forName("jdk.vm.ci.hotspot.HotSpotJDKReflection"), "getMethod", - Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl")); - temporaryHotSpotJDKReflectionGetField = ReflectionUtil.lookupMethod(Class.forName("jdk.vm.ci.hotspot.HotSpotJDKReflection"), "getField", - Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedJavaFieldImpl")); - } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException | ReflectionUtil.ReflectionUtilError ex) { - temporaryIsHotSpotJDKReflectionAvailable = false; - } - - isHotSpotJDKReflectionAvailable = temporaryIsHotSpotJDKReflectionAvailable; - hotSpotJVMCIRuntimeReflection = temporaryHotSpotJVMCIRuntimeReflection; - hotSpotJDKReflectionGetMirror = temporaryHotSpotJDKReflectionGetMirror; - hotSpotJDKReflectionGetMethod = temporaryHotSpotJDKReflectionGetMethod; - hotSpotJDKReflectionGetField = temporaryHotSpotJDKReflectionGetField; - - if (isHotSpotJDKReflectionAvailable) { - hotSpotResolvedObjectTypeImplMirror = null; - hotSpotResolvedPrimitiveTypeMirror = null; - hotSpotResolvedJavaMethodImplToJava = null; - hotSpotResolvedJavaFieldImplToJava = null; - } else { - try { - hotSpotResolvedObjectTypeImplMirror = ReflectionUtil.lookupMethod(Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl"), "mirror"); - hotSpotResolvedPrimitiveTypeMirror = ReflectionUtil.lookupMethod(Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedPrimitiveType"), "mirror"); - hotSpotResolvedJavaMethodImplToJava = ReflectionUtil.lookupMethod(Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl"), "toJava"); - hotSpotResolvedJavaFieldImplToJava = ReflectionUtil.lookupMethod(Class.forName("jdk.vm.ci.hotspot.HotSpotResolvedJavaFieldImpl"), "toJava"); - } catch (ClassNotFoundException e) { - throw GraalError.shouldNotReachHere(e); - } - } - } @SuppressWarnings("unchecked") @Override @@ -443,40 +387,19 @@ private static AnnotatedElement getRoot(AnnotatedElement element) { try { if (element instanceof Package) { return (Class) packageGetPackageInfo.invoke(element); - } else if (element instanceof HotSpotResolvedObjectType || element instanceof HotSpotResolvedJavaType) { - if (isHotSpotJDKReflectionAvailable) { - return (AnnotatedElement) hotSpotJDKReflectionGetMirror.invoke(hotSpotJVMCIRuntimeReflection, element); - } else { - if (element instanceof HotSpotResolvedObjectType) { - return (AnnotatedElement) hotSpotResolvedObjectTypeImplMirror.invoke(element); - } else { - return (AnnotatedElement) hotSpotResolvedPrimitiveTypeMirror.invoke(element); - } - } - } else if (element instanceof HotSpotResolvedJavaMethod) { - if (((ResolvedJavaMethod) element).isClassInitializer()) { - return null; - } - if (isHotSpotJDKReflectionAvailable) { - return (AnnotatedElement) hotSpotJDKReflectionGetMethod.invoke(hotSpotJVMCIRuntimeReflection, element); - } else { - return (AnnotatedElement) hotSpotResolvedJavaMethodImplToJava.invoke(element); - } - } else if (element instanceof HotSpotResolvedJavaField) { - if (isHotSpotJDKReflectionAvailable) { - return (AnnotatedElement) hotSpotJDKReflectionGetField.invoke(hotSpotJVMCIRuntimeReflection, element); - } else { - return (AnnotatedElement) hotSpotResolvedJavaFieldImplToJava.invoke(element); - } } else if (element instanceof AnnotationWrapper) { return getRoot(((AnnotationWrapper) element).getAnnotationRoot()); + } else if (element instanceof ResolvedJavaType) { + return OriginalClassProvider.getJavaClass(GraalAccess.getOriginalSnippetReflection(), (ResolvedJavaType) element); + } else if (element instanceof ResolvedJavaMethod) { + return OriginalMethodProvider.getJavaMethod(GraalAccess.getOriginalSnippetReflection(), (ResolvedJavaMethod) element); + } else if (element instanceof ResolvedJavaField) { + return OriginalFieldProvider.getJavaField(GraalAccess.getOriginalSnippetReflection(), (ResolvedJavaField) element); } } catch (InvocationTargetException e) { Throwable targetException = e.getTargetException(); if (targetException instanceof LinkageError) { throw (LinkageError) targetException; - } else if (targetException instanceof IllegalArgumentException) { - return null; } throw new AnnotationExtractionError(e); } catch (IllegalAccessException e) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java index 3c27662a2021..ac3b4a973d19 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/serialize/SerializationFeature.java @@ -70,11 +70,11 @@ import com.oracle.svm.core.configure.ConfigurationFile; import com.oracle.svm.core.configure.ConfigurationFiles; import com.oracle.svm.core.configure.SerializationConfigurationParser; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.jdk.RecordSupport; import com.oracle.svm.core.reflect.serialize.SerializationRegistry; import com.oracle.svm.core.reflect.serialize.SerializationSupport; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ConditionalConfigurationRegistry; @@ -90,7 +90,6 @@ import com.oracle.svm.util.ReflectionUtil; import jdk.internal.reflect.ReflectionFactory; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -171,7 +170,7 @@ private static Class getLambdaClassFromMemberField(Constant constant) { return null; } - HotSpotObjectConstant fieldValue = (HotSpotObjectConstant) GraalAccess.getOriginalProviders().getConstantReflection().readFieldValue(targetField, (JavaConstant) constant); + JavaConstant fieldValue = GraalAccess.getOriginalProviders().getConstantReflection().readFieldValue(targetField, (JavaConstant) constant); Member memberField = GraalAccess.getOriginalProviders().getSnippetReflection().asObject(Member.class, fieldValue); return memberField.getDeclaringClass(); }