Skip to content

8357987: [JVMCI] Add support for retrieving all methods of a ResolvedJavaType #25498

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
21 changes: 21 additions & 0 deletions src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2219,6 +2219,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) {
Expand Down Expand Up @@ -3354,6 +3374,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)},
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/jvmci/vmStructs_jvmci.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,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) \
\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1148,14 +1148,24 @@ ResolvedJavaMethod[] getDeclaredConstructors(HotSpotResolvedObjectTypeImpl klass
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());
}

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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,19 @@ public boolean isDefault() {
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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,18 @@ public ResolvedJavaMethod[] getDeclaredMethods(boolean forceLink) {
return runtime().compilerToVm.getDeclaredMethods(this);
}

@Override
public List<ResolvedJavaMethod> getAllMethods(boolean forceLink) {
if (forceLink) {
link();
}
ResolvedJavaMethod[] instanceMethods = runtime().compilerToVm.getAllMethods(this);
if (instanceMethods.length == 0) {
return List.of();
}
return Collections.unmodifiableList(Arrays.asList(instanceMethods));
Copy link
Contributor

Choose a reason for hiding this comment

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

return List.of(instanceMethods); should work. We can then replace the above with return List.of(runtime().compilerToVm.getAllMethods(this));

}

@Override
public ResolvedJavaMethod getClassInitializer() {
if (!isArray()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,11 @@ public ResolvedJavaMethod[] getDeclaredMethods() {
return new ResolvedJavaMethod[0];
}

@Override
public List<ResolvedJavaMethod> getAllMethods(boolean forceLink) {
return List.of();
}

@Override
public ResolvedJavaMethod getClassInitializer() {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ long prototypeMarkWord() {
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ default boolean isFinal() {
*/
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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -365,6 +366,17 @@ default ResolvedJavaMethod[] getDeclaredMethods(boolean forceLink) {
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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,19 @@ public void isDefaultTest() {
}
}

@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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,18 @@ public void getDeclaredMethodsTest() {
}
}

@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";
}
Expand Down