8357987: [JVMCI] Add support for retrieving all methods of a ResolvedJavaType
Reviewed-by: dnsimon, yzheng, never
This commit is contained in:
parent
a44a470052
commit
e235b61a8b
@ -2224,6 +2224,26 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, ARGUME
|
||||
return JVMCIENV->get_jobjectArray(methods);
|
||||
C2V_END
|
||||
|
||||
C2V_VMENTRY_NULL(jobjectArray, getAllMethods, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass)))
|
||||
Klass* klass = UNPACK_PAIR(Klass, klass);
|
||||
if (klass == nullptr) {
|
||||
JVMCI_THROW_NULL(NullPointerException);
|
||||
}
|
||||
if (!klass->is_instance_klass()) {
|
||||
JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(0, JVMCI_CHECK_NULL);
|
||||
return JVMCIENV->get_jobjectArray(methods);
|
||||
}
|
||||
|
||||
InstanceKlass* iklass = InstanceKlass::cast(klass);
|
||||
JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(iklass->methods()->length(), JVMCI_CHECK_NULL);
|
||||
for (int i = 0; i < iklass->methods()->length(); i++) {
|
||||
methodHandle mh(THREAD, iklass->methods()->at(i));
|
||||
JVMCIObject method = JVMCIENV->get_jvmci_method(mh, JVMCI_CHECK_NULL);
|
||||
JVMCIENV->put_object_at(methods, i, method);
|
||||
}
|
||||
return JVMCIENV->get_jobjectArray(methods);
|
||||
C2V_END
|
||||
|
||||
C2V_VMENTRY_NULL(jobjectArray, getDeclaredFieldsInfo, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass)))
|
||||
Klass* klass = UNPACK_PAIR(Klass, klass);
|
||||
if (klass == nullptr) {
|
||||
@ -3359,6 +3379,7 @@ JNINativeMethod CompilerToVM::methods[] = {
|
||||
{CC "boxPrimitive", CC "(" OBJECT ")" OBJECTCONSTANT, FN_PTR(boxPrimitive)},
|
||||
{CC "getDeclaredConstructors", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredConstructors)},
|
||||
{CC "getDeclaredMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredMethods)},
|
||||
{CC "getAllMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getAllMethods)},
|
||||
{CC "getDeclaredFieldsInfo", CC "(" HS_KLASS2 ")[" FIELDINFO, FN_PTR(getDeclaredFieldsInfo)},
|
||||
{CC "readStaticFieldValue", CC "(" HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readStaticFieldValue)},
|
||||
{CC "readFieldValue", CC "(" OBJECTCONSTANT HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readFieldValue)},
|
||||
|
@ -693,6 +693,7 @@
|
||||
declare_constant(ConstMethodFlags::_misc_reserved_stack_access) \
|
||||
declare_constant(ConstMethodFlags::_misc_changes_current_thread) \
|
||||
declare_constant(ConstMethodFlags::_misc_is_scoped) \
|
||||
declare_constant(ConstMethodFlags::_misc_is_overpass) \
|
||||
\
|
||||
declare_constant(CounterData::count_off) \
|
||||
\
|
||||
|
@ -1148,7 +1148,8 @@ final class CompilerToVM {
|
||||
native ResolvedJavaMethod[] getDeclaredConstructors(HotSpotResolvedObjectTypeImpl klass, long klassPointer);
|
||||
|
||||
/**
|
||||
* Gets the {@link ResolvedJavaMethod}s for all the non-constructor methods of {@code klass}.
|
||||
* Gets the {@link ResolvedJavaMethod}s for all non-overpass and non-initializer
|
||||
* methods of {@code klass}.
|
||||
*/
|
||||
ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl klass) {
|
||||
return getDeclaredMethods(klass, klass.getKlassPointer());
|
||||
@ -1156,6 +1157,15 @@ final class CompilerToVM {
|
||||
|
||||
native ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl klass, long klassPointer);
|
||||
|
||||
/**
|
||||
* Gets the {@link ResolvedJavaMethod}s for all methods of {@code klass}.
|
||||
*/
|
||||
ResolvedJavaMethod[] getAllMethods(HotSpotResolvedObjectTypeImpl klass) {
|
||||
return getAllMethods(klass, klass.getKlassPointer());
|
||||
}
|
||||
|
||||
native ResolvedJavaMethod[] getAllMethods(HotSpotResolvedObjectTypeImpl klass, long klassPointer);
|
||||
|
||||
HotSpotResolvedObjectTypeImpl.FieldInfo[] getDeclaredFieldsInfo(HotSpotResolvedObjectTypeImpl klass) {
|
||||
return getDeclaredFieldsInfo(klass, klass.getKlassPointer());
|
||||
}
|
||||
|
@ -573,6 +573,19 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
|
||||
return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface();
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently in hotspot a method can either be a "normal" or an "overpass"
|
||||
* method. Overpass methods are instance methods which are created when
|
||||
* otherwise a valid candidate for method resolution would not be found.
|
||||
*/
|
||||
@Override
|
||||
public boolean isDeclared() {
|
||||
if (isConstructor() || isClassInitializer()) {
|
||||
return false;
|
||||
}
|
||||
return (getConstMethodFlags() & config().constMethodFlagsIsOverpass) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type[] getGenericParameterTypes() {
|
||||
if (isClassInitializer()) {
|
||||
|
@ -1067,6 +1067,14 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
|
||||
return runtime().compilerToVm.getDeclaredMethods(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResolvedJavaMethod> getAllMethods(boolean forceLink) {
|
||||
if (forceLink) {
|
||||
link();
|
||||
}
|
||||
return List.of(runtime().compilerToVm.getAllMethods(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolvedJavaMethod getClassInitializer() {
|
||||
if (!isArray()) {
|
||||
|
@ -296,6 +296,11 @@ public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType
|
||||
return new ResolvedJavaMethod[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResolvedJavaMethod> getAllMethods(boolean forceLink) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolvedJavaMethod getClassInitializer() {
|
||||
return null;
|
||||
|
@ -196,6 +196,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess {
|
||||
final int constMethodFlagsCallerSensitive = getConstant("ConstMethodFlags::_misc_caller_sensitive", Integer.class);
|
||||
final int constMethodFlagsIntrinsicCandidate = getConstant("ConstMethodFlags::_misc_intrinsic_candidate", Integer.class);
|
||||
final int constMethodFlagsIsScoped = getConstant("ConstMethodFlags::_misc_is_scoped", Integer.class);
|
||||
final int constMethodFlagsIsOverpass = getConstant("ConstMethodFlags::_misc_is_overpass", Integer.class);
|
||||
final int constMethodHasLineNumberTable = getConstant("ConstMethodFlags::_misc_has_linenumber_table", Integer.class);
|
||||
final int constMethodHasLocalVariableTable = getConstant("ConstMethodFlags::_misc_has_localvariable_table", Integer.class);
|
||||
final int constMethodHasMethodAnnotations = getConstant("ConstMethodFlags::_misc_has_method_annotations", Integer.class);
|
||||
|
@ -114,6 +114,12 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
|
||||
*/
|
||||
boolean isDefault();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this method is contained in the array returned by
|
||||
* {@code getDeclaringClass().getDeclaredMethods()}
|
||||
*/
|
||||
boolean isDeclared();
|
||||
|
||||
/**
|
||||
* Checks whether this method is a class initializer.
|
||||
*
|
||||
|
@ -23,6 +23,7 @@
|
||||
package jdk.vm.ci.meta;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.vm.ci.meta.Assumptions.AssumptionResult;
|
||||
|
||||
@ -365,6 +366,17 @@ public interface ResolvedJavaType extends JavaType, ModifiersProvider, Annotated
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all methods present within this type. This list can
|
||||
* include methods implicitly created and used by the VM that are not present in
|
||||
* {@link #getDeclaredMethods}. The returned List is unmodifiable; calls to any
|
||||
* mutator method will always cause {@code UnsupportedOperationException} to be
|
||||
* thrown.
|
||||
*
|
||||
* @param forceLink if {@code true}, forces this type to be {@link #link linked}
|
||||
*/
|
||||
List<ResolvedJavaMethod> getAllMethods(boolean forceLink);
|
||||
|
||||
/**
|
||||
* Returns the {@code <clinit>} method for this class if there is one.
|
||||
*/
|
||||
|
@ -425,6 +425,19 @@ public class TestResolvedJavaMethod extends MethodUniverse {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isDeclaredTest() {
|
||||
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
|
||||
ResolvedJavaMethod m = e.getValue();
|
||||
boolean expectedDeclared = Arrays.stream(m.getDeclaringClass().getDeclaredMethods()).anyMatch(i -> i.equals(m));
|
||||
assertEquals(expectedDeclared, m.isDeclared());
|
||||
}
|
||||
for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) {
|
||||
ResolvedJavaMethod m = e.getValue();
|
||||
assertFalse(m.isDeclared());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasReceiverTest() {
|
||||
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
|
||||
|
@ -1019,6 +1019,18 @@ public class TestResolvedJavaType extends TypeUniverse {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAllMethodsTest() {
|
||||
for (Class<?> c : classes) {
|
||||
ResolvedJavaType type = metaAccess.lookupJavaType(c);
|
||||
Set<ResolvedJavaMethod> allMethods = new HashSet<>(type.getAllMethods(true));
|
||||
Stream<ResolvedJavaMethod> allKnownMethods = Stream.concat(Arrays.stream(type.getDeclaredMethods()), Arrays.stream(type.getDeclaredConstructors()));
|
||||
allKnownMethods = Stream.concat(allKnownMethods, Stream.ofNullable(type.getClassInitializer()));
|
||||
List<ResolvedJavaMethod> missingMethods = allKnownMethods.filter(m -> !allMethods.contains(m)).toList();
|
||||
assertTrue(missingMethods.toString(), missingMethods.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
static class A {
|
||||
static String name = "foo";
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user