diff options
| -rw-r--r-- | runtime/openjdkjvmti/OpenjdkJvmTi.cc | 2 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_class.cc | 18 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_class.h | 2 | ||||
| -rw-r--r-- | test/912-classes/classes.cc | 14 | ||||
| -rw-r--r-- | test/912-classes/expected.txt | 4 | ||||
| -rw-r--r-- | test/912-classes/src/Main.java | 30 |
6 files changed, 69 insertions, 1 deletions
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc index d17376b77e..175dca2b41 100644 --- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc +++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc @@ -602,7 +602,7 @@ class JvmtiFunctions { } static jvmtiError GetClassLoader(jvmtiEnv* env, jclass klass, jobject* classloader_ptr) { - return ERR(NOT_IMPLEMENTED); + return ClassUtil::GetClassLoader(env, klass, classloader_ptr); } static jvmtiError GetSourceDebugExtension(jvmtiEnv* env, diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc index ce7e5ce7c2..0d1704ca4d 100644 --- a/runtime/openjdkjvmti/ti_class.cc +++ b/runtime/openjdkjvmti/ti_class.cc @@ -310,4 +310,22 @@ jvmtiError ClassUtil::GetClassModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED, return ERR(NONE); } +jvmtiError ClassUtil::GetClassLoader(jvmtiEnv* env ATTRIBUTE_UNUSED, + jclass jklass, + jobject* classloader_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 (classloader_ptr == nullptr) { + return ERR(NULL_POINTER); + } + + *classloader_ptr = soa.AddLocalReference<jobject>(klass->GetClassLoader()); + + return ERR(NONE); +} + } // namespace openjdkjvmti diff --git a/runtime/openjdkjvmti/ti_class.h b/runtime/openjdkjvmti/ti_class.h index 722c208e01..577fc8e866 100644 --- a/runtime/openjdkjvmti/ti_class.h +++ b/runtime/openjdkjvmti/ti_class.h @@ -63,6 +63,8 @@ class ClassUtil { static jvmtiError GetClassStatus(jvmtiEnv* env, jclass klass, jint* status_ptr); + static jvmtiError GetClassLoader(jvmtiEnv* env, jclass klass, jobject* classloader_ptr); + static jvmtiError IsInterface(jvmtiEnv* env, jclass klass, jboolean* is_interface_ptr); static jvmtiError IsArrayClass(jvmtiEnv* env, jclass klass, jboolean* is_array_class_ptr); }; diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc index 5674e7b9a3..bb3dee1ce0 100644 --- a/test/912-classes/classes.cc +++ b/test/912-classes/classes.cc @@ -191,6 +191,20 @@ extern "C" JNIEXPORT jint JNICALL Java_Main_getClassStatus( return status; } +extern "C" JNIEXPORT jobject JNICALL Java_Main_getClassLoader( + JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { + jobject classloader; + jvmtiError result = jvmti_env->GetClassLoader(klass, &classloader); + if (result != JVMTI_ERROR_NONE) { + char* err; + jvmti_env->GetErrorName(result, &err); + printf("Failure running GetClassLoader: %s\n", err); + jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); + return nullptr; + } + return classloader; +} + // Don't do anything jint OnLoad(JavaVM* vm, char* options ATTRIBUTE_UNUSED, diff --git a/test/912-classes/expected.txt b/test/912-classes/expected.txt index 9f5254c736..3507a1a676 100644 --- a/test/912-classes/expected.txt +++ b/test/912-classes/expected.txt @@ -39,3 +39,7 @@ 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] +class java.lang.String null +class [Ljava.lang.String; null +interface Main$InfA dalvik.system.PathClassLoader +class $Proxy0 dalvik.system.PathClassLoader diff --git a/test/912-classes/src/Main.java b/test/912-classes/src/Main.java index 7a7f4c0e2b..69e5a4cc58 100644 --- a/test/912-classes/src/Main.java +++ b/test/912-classes/src/Main.java @@ -71,6 +71,11 @@ public class Main { testInterfaces(ClassA.class); testInterfaces(ClassB.class); testInterfaces(ClassC.class); + + testClassLoader(String.class); + testClassLoader(String[].class); + testClassLoader(InfA.class); + testClassLoader(getProxyClass()); } private static Class<?> proxyClass = null; @@ -121,6 +126,29 @@ public class Main { System.out.println(c + " " + Arrays.toString(getImplementedInterfaces(c))); } + private static boolean IsBootClassLoader(ClassLoader l) { + // Hacky check for Android's fake boot classloader. + return l.getClass().getName().equals("java.lang.BootClassLoader"); + } + + private static void testClassLoader(Class<?> c) { + Object cl = getClassLoader(c); + System.out.println(c + " " + (cl != null ? cl.getClass().getName() : "null")); + if (cl == null) { + if (c.getClassLoader() != null && !IsBootClassLoader(c.getClassLoader())) { + throw new RuntimeException("Expected " + c.getClassLoader() + ", but got null."); + } + } else { + if (!(cl instanceof ClassLoader)) { + throw new RuntimeException("Unexpected \"classloader\": " + cl + " (" + cl.getClass() + + ")"); + } + if (cl != c.getClassLoader()) { + throw new RuntimeException("Unexpected classloader: " + c.getClassLoader() + " vs " + cl); + } + } + } + private static native String[] getClassSignature(Class<?> c); private static native boolean isInterface(Class<?> c); @@ -134,6 +162,8 @@ public class Main { private static native int getClassStatus(Class<?> c); + private static native Object getClassLoader(Class<?> c); + private static class TestForNonInit { public static double dummy = Math.random(); // So it can't be compile-time initialized. } |