OSDN Git Service

ART: Add GetClassVersionNumbers.
authorAndreas Gampe <agampe@google.com>
Fri, 20 Jan 2017 06:04:46 +0000 (22:04 -0800)
committerAndreas Gampe <agampe@google.com>
Fri, 20 Jan 2017 08:07:19 +0000 (00:07 -0800)
Add support for GetClassVersionNumbers. Return the dex file version
as major, zero as minor. Add test.

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

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 e9b7cf5..a55f662 100644 (file)
@@ -593,7 +593,7 @@ class JvmtiFunctions {
                                            jclass klass,
                                            jint* minor_version_ptr,
                                            jint* major_version_ptr) {
-    return ERR(NOT_IMPLEMENTED);
+    return ClassUtil::GetClassVersionNumbers(env, klass, minor_version_ptr, major_version_ptr);
   }
 
   static jvmtiError GetConstantPool(jvmtiEnv* env,
index d1324bc..abcc849 100644 (file)
@@ -417,4 +417,35 @@ jvmtiError ClassUtil::GetClassLoaderClasses(jvmtiEnv* env,
   return ERR(NONE);
 }
 
+jvmtiError ClassUtil::GetClassVersionNumbers(jvmtiEnv* env ATTRIBUTE_UNUSED,
+                                             jclass jklass,
+                                             jint* minor_version_ptr,
+                                             jint* major_version_ptr) {
+  art::ScopedObjectAccess soa(art::Thread::Current());
+  if (jklass == nullptr) {
+    return ERR(INVALID_CLASS);
+  }
+  art::ObjPtr<art::mirror::Object> jklass_obj = soa.Decode<art::mirror::Object>(jklass);
+  if (!jklass_obj->IsClass()) {
+    return ERR(INVALID_CLASS);
+  }
+  art::ObjPtr<art::mirror::Class> klass = jklass_obj->AsClass();
+  if (klass->IsPrimitive() || klass->IsArrayClass()) {
+    return ERR(INVALID_CLASS);
+  }
+
+  if (minor_version_ptr == nullptr || major_version_ptr == nullptr) {
+    return ERR(NULL_POINTER);
+  }
+
+  // Note: proxies will show the dex file version of java.lang.reflect.Proxy, as that is
+  //       what their dex cache copies from.
+  uint32_t version = klass->GetDexFile().GetHeader().GetVersion();
+
+  *major_version_ptr = static_cast<jint>(version);
+  *minor_version_ptr = 0;
+
+  return ERR(NONE);
+}
+
 }  // namespace openjdkjvmti
index 7a0fafb..9558894 100644 (file)
@@ -72,6 +72,11 @@ class ClassUtil {
 
   static jvmtiError IsInterface(jvmtiEnv* env, jclass klass, jboolean* is_interface_ptr);
   static jvmtiError IsArrayClass(jvmtiEnv* env, jclass klass, jboolean* is_array_class_ptr);
+
+  static jvmtiError GetClassVersionNumbers(jvmtiEnv* env,
+                                           jclass klass,
+                                           jint* minor_version_ptr,
+                                           jint* major_version_ptr);
 };
 
 }  // namespace openjdkjvmti
index a22d1d7..29eeff6 100644 (file)
@@ -241,5 +241,23 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassLoaderClasses(
   return ret;
 }
 
+extern "C" JNIEXPORT jintArray JNICALL Java_Main_getClassVersion(
+    JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+  jint major, minor;
+  jvmtiError result = jvmti_env->GetClassVersionNumbers(klass, &minor, &major);
+  if (JvmtiErrorToException(env, result)) {
+    return nullptr;
+  }
+
+  jintArray int_array = env->NewIntArray(2);
+  if (int_array == nullptr) {
+    return nullptr;
+  }
+  jint buf[2] = { major, minor };
+  env->SetIntArrayRegion(int_array, 0, 2, buf);
+
+  return int_array;
+}
+
 }  // namespace Test912Classes
 }  // namespace art
index a95a465..f3cb261 100644 (file)
@@ -59,3 +59,5 @@ boot <- src (B) <- src-ex (A, List)
 boot <- src+src-ex (A,B)
 912-classes.jar+ -> 
 [class A, class B, class java.lang.Object]
+
+[37, 0]
index ea3c49c..cbf2392 100644 (file)
@@ -80,6 +80,10 @@ public class Main {
     testClassLoader(getProxyClass());
 
     testClassLoaderClasses();
+
+    System.out.println();
+
+    testClassVersion();
   }
 
   private static Class<?> proxyClass = null;
@@ -202,6 +206,10 @@ public class Main {
     }
   }
 
+  private static void testClassVersion() {
+    System.out.println(Arrays.toString(getClassVersion(Main.class)));
+  }
+
   private static void printClassLoaderClasses(ClassLoader cl) {
     for (;;) {
       if (cl == null || !cl.getClass().getName().startsWith("dalvik.system")) {
@@ -262,6 +270,8 @@ public class Main {
 
   private static native Class<?>[] getClassLoaderClasses(ClassLoader cl);
 
+  private static native int[] getClassVersion(Class<?> c);
+
   private static class TestForNonInit {
     public static double dummy = Math.random();  // So it can't be compile-time initialized.
   }