OSDN Git Service

ART: Add GetClassStatus
authorAndreas Gampe <agampe@google.com>
Fri, 6 Jan 2017 17:12:49 +0000 (09:12 -0800)
committerAndreas Gampe <agampe@google.com>
Fri, 6 Jan 2017 17:13:56 +0000 (09:13 -0800)
Add support for GetClassStatus. Add a test.

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

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 b8f1500..98c4c3a 100644 (file)
@@ -538,7 +538,7 @@ class JvmtiFunctions {
   }
 
   static jvmtiError GetClassStatus(jvmtiEnv* env, jclass klass, jint* status_ptr) {
-    return ERR(NOT_IMPLEMENTED);
+    return ClassUtil::GetClassStatus(env, klass, status_ptr);
   }
 
   static jvmtiError GetSourceFileName(jvmtiEnv* env, jclass klass, char** source_name_ptr) {
index eea317a..7b30a9d 100644 (file)
@@ -113,6 +113,41 @@ jvmtiError ClassUtil::GetClassSignature(jvmtiEnv* env,
   return ERR(NONE);
 }
 
+jvmtiError ClassUtil::GetClassStatus(jvmtiEnv* env ATTRIBUTE_UNUSED,
+                                     jclass jklass,
+                                     jint* status_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 (status_ptr == nullptr) {
+    return ERR(NULL_POINTER);
+  }
+
+  if (klass->IsArrayClass()) {
+    *status_ptr = JVMTI_CLASS_STATUS_ARRAY;
+  } else if (klass->IsPrimitive()) {
+    *status_ptr = JVMTI_CLASS_STATUS_PRIMITIVE;
+  } else {
+    *status_ptr = JVMTI_CLASS_STATUS_VERIFIED;  // All loaded classes are structurally verified.
+    // This is finicky. If there's an error, we'll say it wasn't prepared.
+    if (klass->IsResolved()) {
+      *status_ptr |= JVMTI_CLASS_STATUS_PREPARED;
+    }
+    if (klass->IsInitialized()) {
+      *status_ptr |= JVMTI_CLASS_STATUS_INITIALIZED;
+    }
+    // Technically the class may be erroneous for other reasons, but we do not have enough info.
+    if (klass->IsErroneous()) {
+      *status_ptr |= JVMTI_CLASS_STATUS_ERROR;
+    }
+  }
+
+  return ERR(NONE);
+}
+
 template <typename T>
 static jvmtiError ClassIsT(jclass jklass, T test, jboolean* is_t_ptr) {
   art::ScopedObjectAccess soa(art::Thread::Current());
index 34edb16..5ee64be 100644 (file)
@@ -49,6 +49,8 @@ class ClassUtil {
                                       char** signature_ptr,
                                       char** generic_ptr);
 
+  static jvmtiError GetClassStatus(jvmtiEnv* env, jclass klass, jint* status_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 bad48a4..28c5931 100644 (file)
@@ -111,6 +111,19 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassFields(
   return CreateObjectArray(env, count, "java/lang/Object", callback);
 }
 
+extern "C" JNIEXPORT jint JNICALL Java_Main_getClassStatus(
+    JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+  jint status;
+  jvmtiError result = jvmti_env->GetClassStatus(klass, &status);
+  if (result != JVMTI_ERROR_NONE) {
+    char* err;
+    jvmti_env->GetErrorName(result, &err);
+    printf("Failure running GetClassStatus: %s\n", err);
+    return JNI_FALSE;
+  }
+  return status;
+}
+
 // Don't do anything
 jint OnLoad(JavaVM* vm,
             char* options ATTRIBUTE_UNUSED,
index bf591c7..44fed79 100644 (file)
@@ -15,3 +15,8 @@ java.lang.String interface=false array=false
 [public static final int java.lang.Integer.BYTES, static final char[] java.lang.Integer.DigitOnes, static final char[] java.lang.Integer.DigitTens, public static final int java.lang.Integer.MAX_VALUE, public static final int java.lang.Integer.MIN_VALUE, public static final int java.lang.Integer.SIZE, private static final java.lang.String[] java.lang.Integer.SMALL_NEG_VALUES, private static final java.lang.String[] java.lang.Integer.SMALL_NONNEG_VALUES, public static final java.lang.Class java.lang.Integer.TYPE, static final char[] java.lang.Integer.digits, private static final long java.lang.Integer.serialVersionUID, static final int[] java.lang.Integer.sizeTable, private final int java.lang.Integer.value]
 []
 []
+int 100000
+class [Ljava.lang.String; 10000
+class java.lang.Object 111
+class Main$TestForNonInit 11
+class Main$TestForInitFail 1001
index a7f3b3f..0b41113 100644 (file)
@@ -47,6 +47,16 @@ public class Main {
     testClassFields(Integer.class);
     testClassFields(int.class);
     testClassFields(String[].class);
+
+    testClassStatus(int.class);
+    testClassStatus(String[].class);
+    testClassStatus(Object.class);
+    testClassStatus(TestForNonInit.class);
+    try {
+      System.out.println(TestForInitFail.dummy);
+    } catch (ExceptionInInitializerError e) {
+    }
+    testClassStatus(TestForInitFail.class);
   }
 
   private static Class<?> proxyClass = null;
@@ -80,10 +90,24 @@ public class Main {
     System.out.println(Arrays.toString(getClassFields(c)));
   }
 
+  private static void testClassStatus(Class<?> c) {
+    System.out.println(c + " " + Integer.toBinaryString(getClassStatus(c)));
+  }
+
   private static native String[] getClassSignature(Class<?> c);
 
   private static native boolean isInterface(Class<?> c);
   private static native boolean isArrayClass(Class<?> c);
 
   private static native Object[] getClassFields(Class<?> c);
+
+  private static native int getClassStatus(Class<?> c);
+
+  private static class TestForNonInit {
+    public static double dummy = Math.random();  // So it can't be compile-time initialized.
+  }
+
+  private static class TestForInitFail {
+    public static int dummy = ((int)Math.random())/0;  // So it throws when initializing.
+  }
 }