Skip to content

[GR-43174] Use new JVMCI API. #6480

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Objects;

import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.debug.GraalError;
Expand All @@ -39,52 +39,24 @@

import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
import jdk.vm.ci.hotspot.HotSpotObjectConstant;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaField;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
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 {

private final HotSpotGraalRuntimeProvider runtime;
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); // ExcludeFromJacocoGeneratedReport
}
}
}

@Override
Expand Down Expand Up @@ -150,52 +122,23 @@ 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) {
Objects.requireNonNull(method);
GraalError.guarantee(method instanceof HotSpotResolvedJavaMethod, "Unexpected implementation class: %s", method.getClass());

if (method.isClassInitializer()) {
/* <clinit> 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());
}
return runtime().getMirror(method);
}

@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());
}
}
Objects.requireNonNull(field);
GraalError.guarantee(field instanceof HotSpotResolvedJavaField, "Unexpected implementation class: %s", field.getClass());

@SuppressWarnings({"unchecked"})
private static <E extends Throwable> RuntimeException rethrow(Throwable ex) throws E {
throw (E) ex;
return runtime().getMirror(field);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import com.oracle.graal.pointsto.constraints.UnresolvedElementException;
import com.oracle.svm.util.ReflectionUtil;

import jdk.vm.ci.hotspot.HotSpotConstantPool;
import jdk.vm.ci.meta.ConstantPool;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaField;
Expand Down Expand Up @@ -86,18 +85,11 @@ public int length() {
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;
while (root instanceof WrappedConstantPool) {
root = ((WrappedConstantPool) root).wrapped;
}

@Override
public void loadReferencedType(int cpi, int opcode, boolean initialize) {
GraalError.guarantee(!initialize, "Must not initialize classes");
try {
/*
* GR-41975: loadReferencedType without triggering class initialization is available in
* HotSpotConstantPool, but not yet in ConstantPool.
*/
((HotSpotConstantPool) root).loadReferencedType(cpi, opcode, initialize);
wrapped.loadReferencedType(cpi, opcode, initialize);
} catch (Throwable ex) {
Throwable cause = ex;
if (cause instanceof BootstrapMethodError && cause.getCause() != null) {
Expand All @@ -111,7 +103,7 @@ public static void loadReferencedType(ConstantPool cp, int cpi, int opcode, bool

@Override
public void loadReferencedType(int cpi, int opcode) {
loadReferencedType(wrapped, cpi, opcode, false);
loadReferencedType(cpi, opcode, false);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@
import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;

import com.oracle.graal.pointsto.constraints.UnresolvedElementException;
import com.oracle.graal.pointsto.infrastructure.WrappedConstantPool;

import jdk.vm.ci.meta.ConstantPool;
import jdk.vm.ci.meta.ResolvedJavaType;

Expand All @@ -52,8 +49,8 @@ public boolean supportsLazyInitialization(ConstantPool cp) {
public void loadReferencedType(GraphBuilderContext builder, ConstantPool cp, int cpi, int bytecode) {
/* Do not trigger class initialization. */
try {
WrappedConstantPool.loadReferencedType(cp, cpi, bytecode, false);
} catch (UnresolvedElementException uee) {
cp.loadReferencedType(cpi, bytecode, false);
} catch (Throwable ex) {
/* Plugin should be non-intrusive. Therefore we ignore missing class-path failures. */
}
}
Expand Down