diff options
| -rw-r--r-- | runtime/openjdkjvmti/OpenjdkJvmTi.cc | 2 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_class.cc | 50 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_class.h | 5 | ||||
| -rw-r--r-- | test/912-classes/classes.cc | 34 | ||||
| -rw-r--r-- | test/912-classes/expected.txt | 9 | ||||
| -rw-r--r-- | test/912-classes/src/Main.java | 29 |
6 files changed, 126 insertions, 3 deletions
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc index 75c314f017..d17376b77e 100644 --- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc +++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc @@ -567,7 +567,7 @@ class JvmtiFunctions { jclass klass, jint* interface_count_ptr, jclass** interfaces_ptr) { - return ERR(NOT_IMPLEMENTED); + return ClassUtil::GetImplementedInterfaces(env, klass, interface_count_ptr, interfaces_ptr); } static jvmtiError GetClassVersionNumbers(jvmtiEnv* env, diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc index 76d070c799..ce7e5ce7c2 100644 --- a/runtime/openjdkjvmti/ti_class.cc +++ b/runtime/openjdkjvmti/ti_class.cc @@ -121,6 +121,56 @@ jvmtiError ClassUtil::GetClassMethods(jvmtiEnv* env, return ERR(NONE); } +jvmtiError ClassUtil::GetImplementedInterfaces(jvmtiEnv* env, + jclass jklass, + jint* interface_count_ptr, + jclass** interfaces_ptr) { + art::ScopedObjectAccess soa(art::Thread::Current()); + art::ObjPtr<art::mirror::Class> klass = soa.Decode<art::mirror::Class>(jklass); + if (klass == nullptr) { + return ERR(INVALID_CLASS); + } + + if (interface_count_ptr == nullptr || interfaces_ptr == nullptr) { + return ERR(NULL_POINTER); + } + + // Need to handle array specifically. Arrays implement Serializable and Cloneable, but the + // spec says these should not be reported. + if (klass->IsArrayClass()) { + *interface_count_ptr = 0; + *interfaces_ptr = nullptr; // TODO: Should we allocate a dummy here? + return ERR(NONE); + } + + size_t array_size = klass->NumDirectInterfaces(); + unsigned char* out_ptr; + jvmtiError allocError = env->Allocate(array_size * sizeof(jclass), &out_ptr); + if (allocError != ERR(NONE)) { + return allocError; + } + jclass* interface_array = reinterpret_cast<jclass*>(out_ptr); + + art::StackHandleScope<1> hs(soa.Self()); + art::Handle<art::mirror::Class> h_klass(hs.NewHandle(klass)); + + for (uint32_t idx = 0; idx != array_size; ++idx) { + art::ObjPtr<art::mirror::Class> inf_klass = + art::mirror::Class::ResolveDirectInterface(soa.Self(), h_klass, idx); + if (inf_klass == nullptr) { + soa.Self()->ClearException(); + env->Deallocate(out_ptr); + // TODO: What is the right error code here? + return ERR(INTERNAL); + } + interface_array[idx] = soa.AddLocalReference<jclass>(inf_klass); + } + + *interface_count_ptr = static_cast<jint>(array_size); + *interfaces_ptr = interface_array; + + return ERR(NONE); +} jvmtiError ClassUtil::GetClassSignature(jvmtiEnv* env, jclass jklass, diff --git a/runtime/openjdkjvmti/ti_class.h b/runtime/openjdkjvmti/ti_class.h index 619f50e15e..722c208e01 100644 --- a/runtime/openjdkjvmti/ti_class.h +++ b/runtime/openjdkjvmti/ti_class.h @@ -49,6 +49,11 @@ class ClassUtil { jint* method_count_ptr, jmethodID** methods_ptr); + static jvmtiError GetImplementedInterfaces(jvmtiEnv* env, + jclass klass, + jint* interface_count_ptr, + jclass** interfaces_ptr); + static jvmtiError GetClassModifiers(jvmtiEnv* env, jclass klass, jint* modifiers_ptr); static jvmtiError GetClassSignature(jvmtiEnv* env, diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc index 3383d04319..5674e7b9a3 100644 --- a/test/912-classes/classes.cc +++ b/test/912-classes/classes.cc @@ -121,7 +121,11 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassFields( fields[i], (modifiers & kStatic) != 0 ? JNI_TRUE : JNI_FALSE); }; - return CreateObjectArray(env, count, "java/lang/Object", callback); + jobjectArray ret = CreateObjectArray(env, count, "java/lang/Object", callback); + if (fields != nullptr) { + jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(fields)); + } + return ret; } extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassMethods( @@ -145,7 +149,33 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassMethods( methods[i], (modifiers & kStatic) != 0 ? JNI_TRUE : JNI_FALSE); }; - return CreateObjectArray(env, count, "java/lang/Object", callback); + jobjectArray ret = CreateObjectArray(env, count, "java/lang/Object", callback); + if (methods != nullptr) { + jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(methods)); + } + return ret; +} + +extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getImplementedInterfaces( + JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { + jint count = 0; + jclass* classes = nullptr; + jvmtiError result = jvmti_env->GetImplementedInterfaces(klass, &count, &classes); + if (result != JVMTI_ERROR_NONE) { + char* err; + jvmti_env->GetErrorName(result, &err); + printf("Failure running GetImplementedInterfaces: %s\n", err); + return nullptr; + } + + auto callback = [&](jint i) { + return classes[i]; + }; + jobjectArray ret = CreateObjectArray(env, count, "java/lang/Class", callback); + if (classes != nullptr) { + jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes)); + } + return ret; } extern "C" JNIEXPORT jint JNICALL Java_Main_getClassStatus( diff --git a/test/912-classes/expected.txt b/test/912-classes/expected.txt index de23b7bc4d..9f5254c736 100644 --- a/test/912-classes/expected.txt +++ b/test/912-classes/expected.txt @@ -30,3 +30,12 @@ class [Ljava.lang.String; 10000 class java.lang.Object 111 class Main$TestForNonInit 11 class Main$TestForInitFail 1001 +int [] +class [Ljava.lang.String; [] +class java.lang.Object [] +interface Main$InfA [] +interface Main$InfB [interface Main$InfA] +interface Main$InfC [interface Main$InfB] +class Main$ClassA [interface Main$InfA] +class Main$ClassB [interface Main$InfB] +class Main$ClassC [interface Main$InfA, interface Main$InfC] diff --git a/test/912-classes/src/Main.java b/test/912-classes/src/Main.java index cbcfe71aa6..7a7f4c0e2b 100644 --- a/test/912-classes/src/Main.java +++ b/test/912-classes/src/Main.java @@ -61,6 +61,16 @@ public class Main { } catch (ExceptionInInitializerError e) { } testClassStatus(TestForInitFail.class); + + testInterfaces(int.class); + testInterfaces(String[].class); + testInterfaces(Object.class); + testInterfaces(InfA.class); + testInterfaces(InfB.class); + testInterfaces(InfC.class); + testInterfaces(ClassA.class); + testInterfaces(ClassB.class); + testInterfaces(ClassC.class); } private static Class<?> proxyClass = null; @@ -107,6 +117,10 @@ public class Main { System.out.println(c + " " + Integer.toBinaryString(getClassStatus(c))); } + private static void testInterfaces(Class<?> c) { + System.out.println(c + " " + Arrays.toString(getImplementedInterfaces(c))); + } + private static native String[] getClassSignature(Class<?> c); private static native boolean isInterface(Class<?> c); @@ -116,6 +130,7 @@ public class Main { private static native Object[] getClassFields(Class<?> c); private static native Object[] getClassMethods(Class<?> c); + private static native Class[] getImplementedInterfaces(Class<?> c); private static native int getClassStatus(Class<?> c); @@ -126,4 +141,18 @@ public class Main { private static class TestForInitFail { public static int dummy = ((int)Math.random())/0; // So it throws when initializing. } + + public static interface InfA { + } + public static interface InfB extends InfA { + } + public static interface InfC extends InfB { + } + + public abstract static class ClassA implements InfA { + } + public abstract static class ClassB extends ClassA implements InfB { + } + public abstract static class ClassC implements InfA, InfC { + } } |