OSDN Git Service

ART: Add GetClassLoader
authorAndreas Gampe <agampe@google.com>
Fri, 6 Jan 2017 23:50:55 +0000 (15:50 -0800)
committerAndreas Gampe <agampe@google.com>
Sat, 7 Jan 2017 00:16:16 +0000 (16:16 -0800)
Add support for GetClassLoader. Add a test.

Bug: 31684578
Test: m test-art-host-run-test-912-classes
Change-Id: I629ec2a1f4843bc3b28e40111805e250be44d993

runtime/openjdkjvmti/OpenjdkJvmTi.cc
runtime/openjdkjvmti/ti_class.cc
runtime/openjdkjvmti/ti_class.h
test/912-classes/classes.cc
test/912-classes/expected.txt
test/912-classes/src/Main.java

index d17376b..175dca2 100644 (file)
@@ -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,
index ce7e5ce..0d1704c 100644 (file)
@@ -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
index 722c208..577fc8e 100644 (file)
@@ -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);
 };
index 5674e7b..bb3dee1 100644 (file)
@@ -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,
index 9f5254c..3507a1a 100644 (file)
@@ -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
index 7a7f4c0..69e5a4c 100644 (file)
@@ -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.
   }