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);
|
return JVMCIENV->get_jobjectArray(methods);
|
||||||
C2V_END
|
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)))
|
C2V_VMENTRY_NULL(jobjectArray, getDeclaredFieldsInfo, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass)))
|
||||||
Klass* klass = UNPACK_PAIR(Klass, klass);
|
Klass* klass = UNPACK_PAIR(Klass, klass);
|
||||||
if (klass == nullptr) {
|
if (klass == nullptr) {
|
||||||
@ -3359,6 +3379,7 @@ JNINativeMethod CompilerToVM::methods[] = {
|
|||||||
{CC "boxPrimitive", CC "(" OBJECT ")" OBJECTCONSTANT, FN_PTR(boxPrimitive)},
|
{CC "boxPrimitive", CC "(" OBJECT ")" OBJECTCONSTANT, FN_PTR(boxPrimitive)},
|
||||||
{CC "getDeclaredConstructors", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredConstructors)},
|
{CC "getDeclaredConstructors", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredConstructors)},
|
||||||
{CC "getDeclaredMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredMethods)},
|
{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 "getDeclaredFieldsInfo", CC "(" HS_KLASS2 ")[" FIELDINFO, FN_PTR(getDeclaredFieldsInfo)},
|
||||||
{CC "readStaticFieldValue", CC "(" HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readStaticFieldValue)},
|
{CC "readStaticFieldValue", CC "(" HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readStaticFieldValue)},
|
||||||
{CC "readFieldValue", CC "(" OBJECTCONSTANT HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readFieldValue)},
|
{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_reserved_stack_access) \
|
||||||
declare_constant(ConstMethodFlags::_misc_changes_current_thread) \
|
declare_constant(ConstMethodFlags::_misc_changes_current_thread) \
|
||||||
declare_constant(ConstMethodFlags::_misc_is_scoped) \
|
declare_constant(ConstMethodFlags::_misc_is_scoped) \
|
||||||
|
declare_constant(ConstMethodFlags::_misc_is_overpass) \
|
||||||
\
|
\
|
||||||
declare_constant(CounterData::count_off) \
|
declare_constant(CounterData::count_off) \
|
||||||
\
|
\
|
||||||
|
@ -1148,7 +1148,8 @@ final class CompilerToVM {
|
|||||||
native ResolvedJavaMethod[] getDeclaredConstructors(HotSpotResolvedObjectTypeImpl klass, long klassPointer);
|
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) {
|
ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl klass) {
|
||||||
return getDeclaredMethods(klass, klass.getKlassPointer());
|
return getDeclaredMethods(klass, klass.getKlassPointer());
|
||||||
@ -1156,6 +1157,15 @@ final class CompilerToVM {
|
|||||||
|
|
||||||
native ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl klass, long klassPointer);
|
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) {
|
HotSpotResolvedObjectTypeImpl.FieldInfo[] getDeclaredFieldsInfo(HotSpotResolvedObjectTypeImpl klass) {
|
||||||
return getDeclaredFieldsInfo(klass, klass.getKlassPointer());
|
return getDeclaredFieldsInfo(klass, klass.getKlassPointer());
|
||||||
}
|
}
|
||||||
|
@ -573,6 +573,19 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
|
|||||||
return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface();
|
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
|
@Override
|
||||||
public Type[] getGenericParameterTypes() {
|
public Type[] getGenericParameterTypes() {
|
||||||
if (isClassInitializer()) {
|
if (isClassInitializer()) {
|
||||||
|
@ -1067,6 +1067,14 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
|
|||||||
return runtime().compilerToVm.getDeclaredMethods(this);
|
return runtime().compilerToVm.getDeclaredMethods(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ResolvedJavaMethod> getAllMethods(boolean forceLink) {
|
||||||
|
if (forceLink) {
|
||||||
|
link();
|
||||||
|
}
|
||||||
|
return List.of(runtime().compilerToVm.getAllMethods(this));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResolvedJavaMethod getClassInitializer() {
|
public ResolvedJavaMethod getClassInitializer() {
|
||||||
if (!isArray()) {
|
if (!isArray()) {
|
||||||
|
@ -296,6 +296,11 @@ public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType
|
|||||||
return new ResolvedJavaMethod[0];
|
return new ResolvedJavaMethod[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ResolvedJavaMethod> getAllMethods(boolean forceLink) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResolvedJavaMethod getClassInitializer() {
|
public ResolvedJavaMethod getClassInitializer() {
|
||||||
return null;
|
return null;
|
||||||
|
@ -196,6 +196,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess {
|
|||||||
final int constMethodFlagsCallerSensitive = getConstant("ConstMethodFlags::_misc_caller_sensitive", Integer.class);
|
final int constMethodFlagsCallerSensitive = getConstant("ConstMethodFlags::_misc_caller_sensitive", Integer.class);
|
||||||
final int constMethodFlagsIntrinsicCandidate = getConstant("ConstMethodFlags::_misc_intrinsic_candidate", Integer.class);
|
final int constMethodFlagsIntrinsicCandidate = getConstant("ConstMethodFlags::_misc_intrinsic_candidate", Integer.class);
|
||||||
final int constMethodFlagsIsScoped = getConstant("ConstMethodFlags::_misc_is_scoped", 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 constMethodHasLineNumberTable = getConstant("ConstMethodFlags::_misc_has_linenumber_table", Integer.class);
|
||||||
final int constMethodHasLocalVariableTable = getConstant("ConstMethodFlags::_misc_has_localvariable_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);
|
final int constMethodHasMethodAnnotations = getConstant("ConstMethodFlags::_misc_has_method_annotations", Integer.class);
|
||||||
|
@ -114,6 +114,12 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
|
|||||||
*/
|
*/
|
||||||
boolean isDefault();
|
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.
|
* Checks whether this method is a class initializer.
|
||||||
*
|
*
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
package jdk.vm.ci.meta;
|
package jdk.vm.ci.meta;
|
||||||
|
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import jdk.vm.ci.meta.Assumptions.AssumptionResult;
|
import jdk.vm.ci.meta.Assumptions.AssumptionResult;
|
||||||
|
|
||||||
@ -365,6 +366,17 @@ public interface ResolvedJavaType extends JavaType, ModifiersProvider, Annotated
|
|||||||
throw new UnsupportedOperationException();
|
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.
|
* 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
|
@Test
|
||||||
public void hasReceiverTest() {
|
public void hasReceiverTest() {
|
||||||
for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
|
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 class A {
|
||||||
static String name = "foo";
|
static String name = "foo";
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user