ART: Add IsInterface and IsArrayClass support
Add support for these two required calls. Add a test.
Bug: 31684578
Test: m test-art-host-run-test-912-classes
Change-Id: I2f9e5c62dd4c3d7f29aaf3dd08f1297aa3b2fd8b
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 5f97b60..f46c25c 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -585,13 +585,13 @@
}
static jvmtiError IsInterface(jvmtiEnv* env, jclass klass, jboolean* is_interface_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return ClassUtil::IsInterface(env, klass, is_interface_ptr);
}
static jvmtiError IsArrayClass(jvmtiEnv* env,
jclass klass,
jboolean* is_array_class_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return ClassUtil::IsArrayClass(env, klass, is_array_class_ptr);
}
static jvmtiError IsModifiableClass(jvmtiEnv* env,
diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index de2076a..fec8447 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -70,4 +70,38 @@
return ERR(NONE);
}
+template <typename T>
+static jvmtiError ClassIsT(jclass jklass, T test, jboolean* is_t_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 (is_t_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ *is_t_ptr = test(klass) ? JNI_TRUE : JNI_FALSE;
+ return ERR(NONE);
+}
+
+jvmtiError ClassUtil::IsInterface(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jclass jklass,
+ jboolean* is_interface_ptr) {
+ auto test = [](art::ObjPtr<art::mirror::Class> klass) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ return klass->IsInterface();
+ };
+ return ClassIsT(jklass, test, is_interface_ptr);
+}
+
+jvmtiError ClassUtil::IsArrayClass(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jclass jklass,
+ jboolean* is_array_class_ptr) {
+ auto test = [](art::ObjPtr<art::mirror::Class> klass) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ return klass->IsArrayClass();
+ };
+ return ClassIsT(jklass, test, is_array_class_ptr);
+}
+
} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_class.h b/runtime/openjdkjvmti/ti_class.h
index caa77d4..63c9a87 100644
--- a/runtime/openjdkjvmti/ti_class.h
+++ b/runtime/openjdkjvmti/ti_class.h
@@ -43,6 +43,9 @@
jclass klass,
char** signature_ptr,
char** generic_ptr);
+
+ static jvmtiError IsInterface(jvmtiEnv* env, jclass klass, jboolean* is_interface_ptr);
+ static jvmtiError IsArrayClass(jvmtiEnv* env, jclass klass, jboolean* is_array_class_ptr);
};
} // namespace openjdkjvmti
diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc
index 838a92a..5a265b8 100644
--- a/test/912-classes/classes.cc
+++ b/test/912-classes/classes.cc
@@ -61,6 +61,32 @@
return ret;
}
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterface(
+ JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+ jboolean is_interface = JNI_FALSE;
+ jvmtiError result = jvmti_env->IsInterface(klass, &is_interface);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running IsInterface: %s\n", err);
+ return JNI_FALSE;
+ }
+ return is_interface;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isArrayClass(
+ JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+ jboolean is_array_class = JNI_FALSE;
+ jvmtiError result = jvmti_env->IsArrayClass(klass, &is_array_class);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running IsArrayClass: %s\n", err);
+ return JNI_FALSE;
+ }
+ return is_array_class;
+}
+
// 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 71b22f4..909d47d 100644
--- a/test/912-classes/expected.txt
+++ b/test/912-classes/expected.txt
@@ -5,3 +5,10 @@
[L$Proxy0;, null]
[I, null]
[[D, null]
+int interface=false array=false
+$Proxy0 interface=false array=false
+java.lang.Runnable interface=true array=false
+java.lang.String interface=false array=false
+[I interface=false array=true
+[Ljava.lang.Runnable; interface=false array=true
+[Ljava.lang.String; interface=false array=true
diff --git a/test/912-classes/src/Main.java b/test/912-classes/src/Main.java
index 025584e..a2dc7e1 100644
--- a/test/912-classes/src/Main.java
+++ b/test/912-classes/src/Main.java
@@ -34,6 +34,15 @@
testClass(int.class);
testClass(double[].class);
+
+ testClassType(int.class);
+ testClassType(getProxyClass());
+ testClassType(Runnable.class);
+ testClassType(String.class);
+
+ testClassType(int[].class);
+ testClassType(Runnable[].class);
+ testClassType(String[].class);
}
private static Class<?> proxyClass = null;
@@ -57,5 +66,14 @@
System.out.println(Arrays.toString(result));
}
+ private static void testClassType(Class<?> c) throws Exception {
+ boolean isInterface = isInterface(c);
+ boolean isArray = isArrayClass(c);
+ System.out.println(c.getName() + " interface=" + isInterface + " array=" + isArray);
+ }
+
private static native String[] getClassSignature(Class<?> c);
+
+ private static native boolean isInterface(Class<?> c);
+ private static native boolean isArrayClass(Class<?> c);
}