OSDN Git Service

Revert "Revert "ART: Add JIT + events test to run-test 912""
authorAndreas Gampe <agampe@google.com>
Wed, 8 Feb 2017 16:28:59 +0000 (16:28 +0000)
committerAndreas Gampe <agampe@google.com>
Thu, 9 Feb 2017 01:55:02 +0000 (17:55 -0800)
This reverts commit f833c5c551ec87f8d240b97142fd27b689613ccf.

Add NoSuchElementException to preparation.

Bug: 31684920
Test: m ART_TEST_JIT=true test-art-host-run-test-912-classes
Change-Id: Ied7c273194e77236e1df67a92c4a0086abcbcd46

test/912-classes/classes.cc
test/912-classes/src/Main.java
test/Android.run-test.mk

index d13436e..e659ea3 100644 (file)
 #include <stdio.h>
 
 #include "base/macros.h"
+#include "class_linker.h"
 #include "jni.h"
+#include "mirror/class_loader.h"
 #include "openjdkjvmti/jvmti.h"
+#include "runtime.h"
 #include "ScopedLocalRef.h"
+#include "ScopedUtfChars.h"
+#include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
 
 #include "ti-agent/common_helper.h"
@@ -278,69 +283,11 @@ static std::string GetClassName(jvmtiEnv* jenv, JNIEnv* jni_env, jclass klass) {
   return tmp;
 }
 
-static std::string GetThreadName(jvmtiEnv* jenv, JNIEnv* jni_env, jthread thread) {
-  jvmtiThreadInfo info;
-  jvmtiError result = jenv->GetThreadInfo(thread, &info);
-  if (result != JVMTI_ERROR_NONE) {
-    if (jni_env != nullptr) {
-      JvmtiErrorToException(jni_env, result);
-    } else {
-      printf("Failed to get thread name.\n");
-    }
-    return "";
-  }
-
-  std::string tmp(info.name);
-  jenv->Deallocate(reinterpret_cast<unsigned char*>(info.name));
-  jni_env->DeleteLocalRef(info.context_class_loader);
-  jni_env->DeleteLocalRef(info.thread_group);
-
-  return tmp;
-}
-
-static std::string GetThreadName(Thread* thread) {
-  std::string tmp;
-  thread->GetThreadName(tmp);
-  return tmp;
-}
-
-static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv,
-                                         JNIEnv* jni_env,
-                                         jthread thread,
-                                         jclass klass) {
-  std::string name = GetClassName(jenv, jni_env, klass);
-  if (name == "") {
-    return;
-  }
-  std::string thread_name = GetThreadName(jenv, jni_env, thread);
-  if (thread_name == "") {
-    return;
-  }
-  std::string cur_thread_name = GetThreadName(Thread::Current());
-  printf("Prepare: %s on %s (cur=%s)\n",
-         name.c_str(),
-         thread_name.c_str(),
-         cur_thread_name.c_str());
-}
-
-static void JNICALL ClassLoadCallback(jvmtiEnv* jenv,
-                                      JNIEnv* jni_env,
-                                      jthread thread,
-                                      jclass klass) {
-  std::string name = GetClassName(jenv, jni_env, klass);
-  if (name == "") {
-    return;
-  }
-  std::string thread_name = GetThreadName(jenv, jni_env, thread);
-  if (thread_name == "") {
-    return;
-  }
-  printf("Load: %s on %s\n", name.c_str(), thread_name.c_str());
-}
-
-extern "C" JNIEXPORT void JNICALL Java_Main_enableClassLoadEvents(
-    JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) {
-  if (b == JNI_FALSE) {
+static void EnableEvents(JNIEnv* env,
+                         jboolean enable,
+                         decltype(jvmtiEventCallbacks().ClassLoad) class_load,
+                         decltype(jvmtiEventCallbacks().ClassPrepare) class_prepare) {
+  if (enable == JNI_FALSE) {
     jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
                                                          JVMTI_EVENT_CLASS_LOAD,
                                                          nullptr);
@@ -356,8 +303,8 @@ extern "C" JNIEXPORT void JNICALL Java_Main_enableClassLoadEvents(
 
   jvmtiEventCallbacks callbacks;
   memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
-  callbacks.ClassLoad = ClassLoadCallback;
-  callbacks.ClassPrepare = ClassPrepareCallback;
+  callbacks.ClassLoad = class_load;
+  callbacks.ClassPrepare = class_prepare;
   jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
   if (JvmtiErrorToException(env, ret)) {
     return;
@@ -375,5 +322,113 @@ extern "C" JNIEXPORT void JNICALL Java_Main_enableClassLoadEvents(
   JvmtiErrorToException(env, ret);
 }
 
+class ClassLoadPreparePrinter {
+ public:
+  static void JNICALL ClassLoadCallback(jvmtiEnv* jenv,
+                                        JNIEnv* jni_env,
+                                        jthread thread,
+                                        jclass klass) {
+    std::string name = GetClassName(jenv, jni_env, klass);
+    if (name == "") {
+      return;
+    }
+    std::string thread_name = GetThreadName(jenv, jni_env, thread);
+    if (thread_name == "") {
+      return;
+    }
+    printf("Load: %s on %s\n", name.c_str(), thread_name.c_str());
+  }
+
+  static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv,
+                                           JNIEnv* jni_env,
+                                           jthread thread,
+                                           jclass klass) {
+    std::string name = GetClassName(jenv, jni_env, klass);
+    if (name == "") {
+      return;
+    }
+    std::string thread_name = GetThreadName(jenv, jni_env, thread);
+    if (thread_name == "") {
+      return;
+    }
+    std::string cur_thread_name = GetThreadName(Thread::Current());
+    printf("Prepare: %s on %s (cur=%s)\n",
+           name.c_str(),
+           thread_name.c_str(),
+           cur_thread_name.c_str());
+  }
+
+ private:
+  static std::string GetThreadName(jvmtiEnv* jenv, JNIEnv* jni_env, jthread thread) {
+    jvmtiThreadInfo info;
+    jvmtiError result = jenv->GetThreadInfo(thread, &info);
+    if (result != JVMTI_ERROR_NONE) {
+      if (jni_env != nullptr) {
+        JvmtiErrorToException(jni_env, result);
+      } else {
+        printf("Failed to get thread name.\n");
+      }
+      return "";
+    }
+
+    std::string tmp(info.name);
+    jenv->Deallocate(reinterpret_cast<unsigned char*>(info.name));
+    jni_env->DeleteLocalRef(info.context_class_loader);
+    jni_env->DeleteLocalRef(info.thread_group);
+
+    return tmp;
+  }
+
+  static std::string GetThreadName(Thread* thread) {
+    std::string tmp;
+    thread->GetThreadName(tmp);
+    return tmp;
+  }
+};
+
+extern "C" JNIEXPORT void JNICALL Java_Main_enableClassLoadPreparePrintEvents(
+    JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean enable) {
+  EnableEvents(env,
+               enable,
+               ClassLoadPreparePrinter::ClassLoadCallback,
+               ClassLoadPreparePrinter::ClassPrepareCallback);
+}
+
+struct ClassLoadSeen {
+  static void JNICALL ClassLoadSeenCallback(jvmtiEnv* jenv ATTRIBUTE_UNUSED,
+                                            JNIEnv* jni_env ATTRIBUTE_UNUSED,
+                                            jthread thread ATTRIBUTE_UNUSED,
+                                            jclass klass ATTRIBUTE_UNUSED) {
+    saw_event = true;
+  }
+
+  static bool saw_event;
+};
+bool ClassLoadSeen::saw_event = false;
+
+extern "C" JNIEXPORT void JNICALL Java_Main_enableClassLoadSeenEvents(
+    JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) {
+  EnableEvents(env, b, ClassLoadSeen::ClassLoadSeenCallback, nullptr);
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_hadLoadEvent(
+    JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED) {
+  return ClassLoadSeen::saw_event ? JNI_TRUE : JNI_FALSE;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isLoadedClass(
+    JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring class_name) {
+  ScopedUtfChars name(env, class_name);
+  ScopedObjectAccess soa(Thread::Current());
+  Runtime* current = Runtime::Current();
+  ClassLinker* class_linker = current->GetClassLinker();
+  bool found =
+      class_linker->LookupClass(
+          soa.Self(),
+          name.c_str(),
+          soa.Decode<mirror::ClassLoader>(current->GetSystemClassLoader())) != nullptr;
+  return found ? JNI_TRUE : JNI_FALSE;
+}
+
 }  // namespace Test912Classes
 }  // namespace art
index 6ad23a4..e3aceb9 100644 (file)
@@ -219,6 +219,15 @@ public class Main {
     }
     final ClassLoader boot = cl;
 
+    // The JIT may deeply inline and load some classes. Preload these for test determinism.
+    final String PRELOAD_FOR_JIT[] = {
+        "java.nio.charset.CoderMalfunctionError",
+        "java.util.NoSuchElementException"
+    };
+    for (String s : PRELOAD_FOR_JIT) {
+      Class.forName(s);
+    }
+
     Runnable r = new Runnable() {
       @Override
       public void run() {
@@ -238,7 +247,7 @@ public class Main {
 
     ensureJitCompiled(Main.class, "testClassEvents");
 
-    enableClassLoadEvents(true);
+    enableClassLoadPreparePrintEvents(true);
 
     ClassLoader cl1 = create(boot, DEX1, DEX2);
     System.out.println("B, false");
@@ -270,7 +279,37 @@ public class Main {
     t.start();
     t.join();
 
-    enableClassLoadEvents(false);
+    enableClassLoadPreparePrintEvents(false);
+
+    // Note: the JIT part of this test is about the JIT pulling in a class not yet touched by
+    //       anything else in the system. This could be the verifier or the interpreter. We
+    //       block the interpreter by calling ensureJitCompiled. The verifier, however, must
+    //       run in configurations where dex2oat didn't verify the class itself. So explicitly
+    //       check whether the class has been already loaded, and skip then.
+    // TODO: Add multiple configurations to the run script once that becomes easier to do.
+    if (hasJit() && !isLoadedClass("Main$ClassD")) {
+      testClassEventsJit();
+    }
+  }
+
+  private static void testClassEventsJit() throws Exception {
+    enableClassLoadSeenEvents(true);
+
+    testClassEventsJitImpl();
+
+    enableClassLoadSeenEvents(false);
+
+    if (!hadLoadEvent()) {
+      throw new RuntimeException("Did not get expected load event.");
+    }
+  }
+
+  private static void testClassEventsJitImpl() throws Exception {
+    ensureJitCompiled(Main.class, "testClassEventsJitImpl");
+
+    if (ClassD.x != 1) {
+      throw new RuntimeException("Unexpected value");
+    }
   }
 
   private static void printClassLoaderClasses(ClassLoader cl) {
@@ -335,9 +374,14 @@ public class Main {
 
   private static native int[] getClassVersion(Class<?> c);
 
-  private static native void enableClassLoadEvents(boolean b);
+  private static native void enableClassLoadPreparePrintEvents(boolean b);
+
+  private static native void ensureJitCompiled(Class<?> c, String name);
 
-  private static native void ensureJitCompiled(Class c, String name);
+  private static native boolean hasJit();
+  private static native boolean isLoadedClass(String name);
+  private static native void enableClassLoadSeenEvents(boolean b);
+  private static native boolean hadLoadEvent();
 
   private static class TestForNonInit {
     public static double dummy = Math.random();  // So it can't be compile-time initialized.
@@ -361,6 +405,10 @@ public class Main {
   public abstract static class ClassC implements InfA, InfC {
   }
 
+  public static class ClassD {
+    static int x = 1;
+  }
+
   private static final String DEX1 = System.getenv("DEX_LOCATION") + "/912-classes.jar";
   private static final String DEX2 = System.getenv("DEX_LOCATION") + "/912-classes-ex.jar";
 
index b937c93..1938b92 100644 (file)
@@ -540,7 +540,6 @@ TEST_ART_BROKEN_JIT_RUN_TESTS := \
   629-vdex-speed \
   904-object-allocation \
   906-iterate-heap \
-  912-classes \
 
 ifneq (,$(filter jit,$(COMPILER_TYPES)))
   ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \