ART: Add GetClassVersionNumbers.
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
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index e9b7cf5..a55f662 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -593,7 +593,7 @@
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,
diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index d1324bc..abcc849 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -417,4 +417,35 @@
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
diff --git a/runtime/openjdkjvmti/ti_class.h b/runtime/openjdkjvmti/ti_class.h
index 7a0fafb..9558894 100644
--- a/runtime/openjdkjvmti/ti_class.h
+++ b/runtime/openjdkjvmti/ti_class.h
@@ -72,6 +72,11 @@
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
diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc
index a22d1d7..29eeff6 100644
--- a/test/912-classes/classes.cc
+++ b/test/912-classes/classes.cc
@@ -241,5 +241,23 @@
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
diff --git a/test/912-classes/expected.txt b/test/912-classes/expected.txt
index a95a465..f3cb261 100644
--- a/test/912-classes/expected.txt
+++ b/test/912-classes/expected.txt
@@ -59,3 +59,5 @@
boot <- src+src-ex (A,B)
912-classes.jar+ ->
[class A, class B, class java.lang.Object]
+
+[37, 0]
diff --git a/test/912-classes/src/Main.java b/test/912-classes/src/Main.java
index ea3c49c..cbf2392 100644
--- a/test/912-classes/src/Main.java
+++ b/test/912-classes/src/Main.java
@@ -80,6 +80,10 @@
testClassLoader(getProxyClass());
testClassLoaderClasses();
+
+ System.out.println();
+
+ testClassVersion();
}
private static Class<?> proxyClass = null;
@@ -202,6 +206,10 @@
}
}
+ 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 @@
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.
}