Skip to content
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 @@ -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;

/**
Expand Down Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -279,6 +281,16 @@ public <T> T getInjectedNodeIntrinsicParameter(Class<T> 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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -36,18 +41,50 @@
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 {

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);
}
}
}

@Override
Expand Down Expand Up @@ -112,4 +149,53 @@ public <T> T getInjectedNodeIntrinsicParameter(Class<T> 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()) {
/* <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());
}
}

@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 <E extends Throwable> RuntimeException rethrow(Throwable ex) throws E {
throw (E) ex;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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> T getInjectedNodeIntrinsicParameter(Class<T> type) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do You need here now else statement, just after if statement

    if(){
    ...
    return ... 
    }
 return reflectionProvider.originalField(field);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case I find the code easier to read with the else statement.

return reflectionProvider.originalField(field);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
Loading