Skip to content

Commit

Permalink
Adding support for getDeclaredPatternDeclarations
Browse files Browse the repository at this point in the history
  • Loading branch information
biboudis committed Apr 2, 2024
1 parent 4289ed3 commit 68564f6
Show file tree
Hide file tree
Showing 11 changed files with 344 additions and 32 deletions.
3 changes: 3 additions & 0 deletions src/hotspot/share/include/jvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,9 @@ JVM_GetMethodTypeAnnotations(JNIEnv *env, jobject method);
JNIEXPORT jobjectArray JNICALL
JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, jboolean publicOnly);

JNIEXPORT jobjectArray JNICALL
JVM_GetClassDeclaredPatternDeclarations(JNIEnv *env, jclass ofClass, jboolean publicOnly);

JNIEXPORT jobjectArray JNICALL
JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, jboolean publicOnly);

Expand Down
28 changes: 28 additions & 0 deletions src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2161,6 +2161,33 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, ARGUME
return JVMCIENV->get_jobjectArray(methods);
C2V_END

C2V_VMENTRY_NULL(jobjectArray, getDeclaredPatternDeclarations, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass)))
Klass* klass = UNPACK_PAIR(Klass, klass);
if (klass == nullptr) {
JVMCI_THROW_0(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);
GrowableArray<Method*> methods_array;
for (int i = 0; i < iklass->methods()->length(); i++) {
Method* m = iklass->methods()->at(i);
if (!m->is_initializer() && !m->is_overpass()) {
methods_array.append(m);
}
}
JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(methods_array.length(), JVMCI_CHECK_NULL);
for (int i = 0; i < methods_array.length(); i++) {
methodHandle mh(THREAD, methods_array.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 @@ -3282,6 +3309,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 "getDeclaredPatternDeclarations", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredPatternDeclarations)},
{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
78 changes: 78 additions & 0 deletions src/hotspot/share/prims/jvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,84 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass,
}
JVM_END

static jobjectArray get_class_declared_pattern_declarations_helper(
JNIEnv *env,
jclass ofClass, jboolean publicOnly,
bool want_constructor,
Klass* klass, TRAPS) {

JvmtiVMObjectAllocEventCollector oam;

oop ofMirror = JNIHandles::resolve_non_null(ofClass);
// Exclude primitive types and array types
if (java_lang_Class::is_primitive(ofMirror)
|| java_lang_Class::as_Klass(ofMirror)->is_array_klass()) {
// Return empty array
oop res = oopFactory::new_objArray(klass, 0, CHECK_NULL);
return (jobjectArray) JNIHandles::make_local(THREAD, res);
}

InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(ofMirror));

// Ensure class is linked
k->link_class(CHECK_NULL);

Array<Method*>* methods = k->methods();
int methods_length = methods->length();

// Save original method_idnum in case of redefinition, which can change
// the idnum of obsolete methods. The new method will have the same idnum
// but if we refresh the methods array, the counts will be wrong.
ResourceMark rm(THREAD);
GrowableArray<int>* idnums = new GrowableArray<int>(methods_length);
int num_methods = 0;

for (int i = 0; i < methods_length; i++) {
methodHandle method(THREAD, methods->at(i));
if (select_method(method, want_constructor)) {
if (!publicOnly || method->is_public()) {
idnums->push(method->method_idnum());
++num_methods;
}
}
}

// Allocate result
objArrayOop r = oopFactory::new_objArray(klass, num_methods, CHECK_NULL);
objArrayHandle result (THREAD, r);

// Now just put the methods that we selected above, but go by their idnum
// in case of redefinition. The methods can be redefined at any safepoint,
// so above when allocating the oop array and below when creating reflect
// objects.
for (int i = 0; i < num_methods; i++) {
methodHandle method(THREAD, k->method_with_idnum(idnums->at(i)));
if (method.is_null()) {
// Method may have been deleted and seems this API can handle null
// Otherwise should probably put a method that throws NSME
result->obj_at_put(i, nullptr);
} else {
oop m;
if (want_constructor) {
m = Reflection::new_constructor(method, CHECK_NULL);
} else {
m = Reflection::new_method(method, false, CHECK_NULL);
}
result->obj_at_put(i, m);
}
}

return (jobjectArray) JNIHandles::make_local(THREAD, result());
}

JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredPatternDeclarations(JNIEnv *env, jclass ofClass, jboolean publicOnly))
{
return get_class_declared_pattern_declarations_helper(env, ofClass, publicOnly,
/*want_constructor*/ false,
vmClasses::reflect_Method_klass(), THREAD);
}
JVM_END

JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly))
{
return get_class_declared_methods_helper(env, ofClass, publicOnly,
Expand Down
67 changes: 65 additions & 2 deletions src/java.base/share/classes/java/lang/Class.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,8 @@
import java.util.Set;
import java.util.stream.Collectors;

import jdk.internal.javac.PreviewFeature;
import jdk.internal.loader.BootLoader;
import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.misc.PreviewFeatures;
import jdk.internal.misc.Unsafe;
import jdk.internal.module.Resources;
import jdk.internal.reflect.CallerSensitive;
Expand Down Expand Up @@ -2735,6 +2733,44 @@ public Method[] getDeclaredMethods() throws SecurityException {
return copyMethods(privateGetDeclaredMethods(false));
}

/**
* Obtains pattern declarations of a class
*
* @return the array of {@code Method} objects representing all the
* declared methods of this class
* @throws SecurityException
* If a security manager, <i>s</i>, is present and any of the
* following conditions is met:
*
* <ul>
*
* <li> the caller's class loader is not the same as the
* class loader of this class and invocation of
* {@link SecurityManager#checkPermission
* s.checkPermission} method with
* {@code RuntimePermission("accessDeclaredMembers")}
* denies access to the declared methods within this class
*
* <li> the caller's class loader is not the same as or an
* ancestor of the class loader for the current class and
* invocation of {@link SecurityManager#checkPackageAccess
* s.checkPackageAccess()} denies access to the package
* of this class
*
* </ul>
*
* @since 23
*/
@CallerSensitive
public Method[] getDeclaredPatternDeclarations() throws SecurityException {
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
}
return copyMethods(privateGetDeclaredPatternDeclarations(false));
}

/**
* Returns an array of {@code Constructor} objects reflecting all the
* constructors implicitly or explicitly declared by the class represented by this
Expand Down Expand Up @@ -3427,11 +3463,14 @@ private static class ReflectionData<T> {
volatile Field[] publicFields;
volatile Method[] declaredMethods;
volatile Method[] publicMethods;
volatile Method[] declaredPatternDeclarations;
volatile Method[] publicPatternDeclarations;
volatile Constructor<T>[] declaredConstructors;
volatile Constructor<T>[] publicConstructors;
// Intermediate results for getFields and getMethods
volatile Field[] declaredPublicFields;
volatile Method[] declaredPublicMethods;
volatile Method[] declaredPublicPatternDeclarations;
volatile Class<?>[] interfaces;

// Cached names
Expand Down Expand Up @@ -3658,6 +3697,29 @@ private Method[] privateGetDeclaredMethods(boolean publicOnly) {
return res;
}

// Returns an array of "root" methods. These Method objects must NOT
// be propagated to the outside world, but must instead be copied
// via ReflectionFactory.copyMethod.
private Method[] privateGetDeclaredPatternDeclarations(boolean publicOnly) {
Method[] res;
ReflectionData<T> rd = reflectionData();
if (rd != null) {
res = publicOnly ? rd.declaredPublicPatternDeclarations : rd.declaredPatternDeclarations;
if (res != null) return res;
}
// No cached value available; request value from VM
res = Reflection.filterMethods(this, getDeclaredPatternDeclarations0(publicOnly));
if (rd != null) {
if (publicOnly) {
rd.declaredPublicPatternDeclarations = res;
} else {
rd.declaredPatternDeclarations = res;
}
}
return res;
}


// Returns an array of "root" methods. These Method objects must NOT
// be propagated to the outside world, but must instead be copied
// via ReflectionFactory.copyMethod.
Expand Down Expand Up @@ -3888,6 +3950,7 @@ private static <U> Constructor<U>[] copyConstructors(Constructor<U>[] arg) {

private native Field[] getDeclaredFields0(boolean publicOnly);
private native Method[] getDeclaredMethods0(boolean publicOnly);
private native Method[] getDeclaredPatternDeclarations0(boolean publicOnly);
private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
private native Class<?>[] getDeclaredClasses0();

Expand Down
61 changes: 31 additions & 30 deletions src/java.base/share/native/libjava/Class.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,36 +54,37 @@ extern jboolean VerifyFixClassname(char *utf_name);
#define RC "Ljava/lang/reflect/RecordComponent;"

static JNINativeMethod methods[] = {
{"initClassName", "()" STR, (void *)&JVM_InitClassName},
{"getSuperclass", "()" CLS, NULL},
{"getInterfaces0", "()[" CLS, (void *)&JVM_GetClassInterfaces},
{"isInterface", "()Z", (void *)&JVM_IsInterface},
{"getSigners", "()[" OBJ, (void *)&JVM_GetClassSigners},
{"setSigners", "([" OBJ ")V", (void *)&JVM_SetClassSigners},
{"isArray", "()Z", (void *)&JVM_IsArrayClass},
{"isHidden", "()Z", (void *)&JVM_IsHiddenClass},
{"isPrimitive", "()Z", (void *)&JVM_IsPrimitiveClass},
{"getModifiers", "()I", (void *)&JVM_GetClassModifiers},
{"getDeclaredFields0","(Z)[" FLD, (void *)&JVM_GetClassDeclaredFields},
{"getDeclaredMethods0","(Z)[" MHD, (void *)&JVM_GetClassDeclaredMethods},
{"getDeclaredConstructors0","(Z)[" CTR, (void *)&JVM_GetClassDeclaredConstructors},
{"getProtectionDomain0", "()" PD, (void *)&JVM_GetProtectionDomain},
{"getDeclaredClasses0", "()[" CLS, (void *)&JVM_GetDeclaredClasses},
{"getDeclaringClass0", "()" CLS, (void *)&JVM_GetDeclaringClass},
{"getSimpleBinaryName0", "()" STR, (void *)&JVM_GetSimpleBinaryName},
{"getGenericSignature0", "()" STR, (void *)&JVM_GetClassSignature},
{"getRawAnnotations", "()" BA, (void *)&JVM_GetClassAnnotations},
{"getConstantPool", "()" CPL, (void *)&JVM_GetClassConstantPool},
{"desiredAssertionStatus0","("CLS")Z", (void *)&JVM_DesiredAssertionStatus},
{"getEnclosingMethod0", "()[" OBJ, (void *)&JVM_GetEnclosingMethodInfo},
{"getRawTypeAnnotations", "()" BA, (void *)&JVM_GetClassTypeAnnotations},
{"getNestHost0", "()" CLS, (void *)&JVM_GetNestHost},
{"getNestMembers0", "()[" CLS, (void *)&JVM_GetNestMembers},
{"getRecordComponents0", "()[" RC, (void *)&JVM_GetRecordComponents},
{"isRecord0", "()Z", (void *)&JVM_IsRecord},
{"getPermittedSubclasses0", "()[" CLS, (void *)&JVM_GetPermittedSubclasses},
{"getClassFileVersion0", "()I", (void *)&JVM_GetClassFileVersion},
{"getClassAccessFlagsRaw0", "()I", (void *)&JVM_GetClassAccessFlags},
{"initClassName", "()" STR, (void *)&JVM_InitClassName},
{"getSuperclass", "()" CLS, NULL},
{"getInterfaces0", "()[" CLS, (void *)&JVM_GetClassInterfaces},
{"isInterface", "()Z", (void *)&JVM_IsInterface},
{"getSigners", "()[" OBJ, (void *)&JVM_GetClassSigners},
{"setSigners", "([" OBJ ")V", (void *)&JVM_SetClassSigners},
{"isArray", "()Z", (void *)&JVM_IsArrayClass},
{"isHidden", "()Z", (void *)&JVM_IsHiddenClass},
{"isPrimitive", "()Z", (void *)&JVM_IsPrimitiveClass},
{"getModifiers", "()I", (void *)&JVM_GetClassModifiers},
{"getDeclaredFields0","(Z)[" FLD, (void *)&JVM_GetClassDeclaredFields},
{"getDeclaredMethods0","(Z)[" MHD, (void *)&JVM_GetClassDeclaredMethods},
{"getDeclaredPatternDeclarations0","(Z)[" MHD, (void *)&JVM_GetClassDeclaredPatternDeclarations},
{"getDeclaredConstructors0","(Z)[" CTR, (void *)&JVM_GetClassDeclaredConstructors},
{"getProtectionDomain0", "()" PD, (void *)&JVM_GetProtectionDomain},
{"getDeclaredClasses0", "()[" CLS, (void *)&JVM_GetDeclaredClasses},
{"getDeclaringClass0", "()" CLS, (void *)&JVM_GetDeclaringClass},
{"getSimpleBinaryName0", "()" STR, (void *)&JVM_GetSimpleBinaryName},
{"getGenericSignature0", "()" STR, (void *)&JVM_GetClassSignature},
{"getRawAnnotations", "()" BA, (void *)&JVM_GetClassAnnotations},
{"getConstantPool", "()" CPL, (void *)&JVM_GetClassConstantPool},
{"desiredAssertionStatus0","("CLS")Z", (void *)&JVM_DesiredAssertionStatus},
{"getEnclosingMethod0", "()[" OBJ, (void *)&JVM_GetEnclosingMethodInfo},
{"getRawTypeAnnotations", "()" BA, (void *)&JVM_GetClassTypeAnnotations},
{"getNestHost0", "()" CLS, (void *)&JVM_GetNestHost},
{"getNestMembers0", "()[" CLS, (void *)&JVM_GetNestMembers},
{"getRecordComponents0", "()[" RC, (void *)&JVM_GetRecordComponents},
{"isRecord0", "()Z", (void *)&JVM_IsRecord},
{"getPermittedSubclasses0", "()[" CLS, (void *)&JVM_GetPermittedSubclasses},
{"getClassFileVersion0", "()I", (void *)&JVM_GetClassFileVersion},
{"getClassAccessFlagsRaw0", "()I", (void *)&JVM_GetClassAccessFlags},
};

#undef OBJ
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1152,6 +1152,16 @@ ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl klass) {

native ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl klass, long klassPointer);

/**
* Gets the {@link ResolvedJavaMethod}s for all the pattern declarations of {@code klass}.
*/
ResolvedJavaMethod[] getDeclaredPatternDeclarations(HotSpotResolvedObjectTypeImpl klass) {
return getDeclaredPatternDeclarations(klass, klass.getKlassPointer());
}

native ResolvedJavaMethod[] getDeclaredPatternDeclarations(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 @@ -1071,6 +1071,19 @@ public ResolvedJavaMethod[] getDeclaredMethods(boolean forceLink) {
return runtime().compilerToVm.getDeclaredMethods(this);
}

@Override
public ResolvedJavaMethod[] getDeclaredPatternDeclarations() {
return getDeclaredPatternDeclarations(true);
}

@Override
public ResolvedJavaMethod[] getDeclaredPatternDeclarations(boolean forceLink) {
if (forceLink) {
link();
}
return runtime().compilerToVm.getDeclaredPatternDeclarations(this);
}

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

@Override
public ResolvedJavaMethod[] getDeclaredPatternDeclarations() {
return new ResolvedJavaMethod[0];
}

@Override
public ResolvedJavaMethod getClassInitializer() {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,23 @@ default ResolvedJavaMethod[] getDeclaredMethods(boolean forceLink) {
throw new UnsupportedOperationException();
}

/**
* Returns an array reflecting all the pattern declarations declared by this type. This method is similar to
* {@link Class#getDeclaredPatternDeclarations()} in terms of returned methods. Calling this method forces
* this type to be {@link #link linked}.
*/
ResolvedJavaMethod[] getDeclaredPatternDeclarations();

/**
* Returns an array reflecting all the methods declared by this type. This method is similar to
* {@link Class#getDeclaredMethods()} in terms of returned methods.
*
* @param forceLink if {@code true}, forces this type to be {@link #link linked}
*/
default ResolvedJavaMethod[] getDeclaredPatternDeclarations(boolean forceLink) {
throw new UnsupportedOperationException();
}

/**
* Returns the {@code <clinit>} method for this class if there is one.
*/
Expand Down
Loading

0 comments on commit 68564f6

Please sign in to comment.