From 8b07e4704f6150efdf1aed9591d9f7e4a4b0708b Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Fri, 6 Jan 2017 14:20:39 -0800 Subject: [PATCH] ART: Add GetImplementedInterfaces Add support for GetImplementedInterfaces. Add a test. Add cleanup to some existing tests. Bug: 31684578 Test: m test-art-host-run-test-912-classes Change-Id: Ic75bf3bba3b568232178d8525501122826b5a430 --- runtime/openjdkjvmti/OpenjdkJvmTi.cc | 2 +- runtime/openjdkjvmti/ti_class.cc | 50 ++++++++++++++++++++++++++++++++++++ runtime/openjdkjvmti/ti_class.h | 5 ++++ test/912-classes/classes.cc | 34 ++++++++++++++++++++++-- test/912-classes/expected.txt | 9 +++++++ 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 75c314f01..d17376b77 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 76d070c79..ce7e5ce7c 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 klass = soa.Decode(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(out_ptr); + + art::StackHandleScope<1> hs(soa.Self()); + art::Handle h_klass(hs.NewHandle(klass)); + + for (uint32_t idx = 0; idx != array_size; ++idx) { + art::ObjPtr 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(inf_klass); + } + + *interface_count_ptr = static_cast(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 619f50e15..722c208e0 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 3383d0431..5674e7b9a 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(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(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(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 de23b7bc4..9f5254c73 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 cbcfe71aa..7a7f4c0e2 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 { + } } -- 2.11.0