summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andreas Gampe <agampe@google.com> 2017-04-19 13:37:48 -0700
committer Andreas Gampe <agampe@google.com> 2017-04-19 13:44:34 -0700
commitd5f2ccc7ea09ae87ff704786daa6d20c10be21db (patch)
tree6c50e7624144a1670acb3d8dbd9f7ca34300df08
parent88b7c37163836b4c26dbd05733bfc116987e58bc (diff)
ART: Refactor run-test 912 (1/3)
Refactor the test for CTS. Break out the ART-specific part. Move the rest into the regular layout. Move class events to their own thread, and report them on the Java side. Use InMemoryDexClassLoader for classloaders to avoid explicit files. Bug: 32072923 Test: none Change-Id: I80e27cc9c21646bbecd1de1a246f583a0d388e05
-rw-r--r--test/912-classes/classes.cc219
-rw-r--r--test/912-classes/classes_art.cc146
-rw-r--r--test/912-classes/expected.txt75
-rw-r--r--test/912-classes/src-ex/A.java18
-rw-r--r--test/912-classes/src-ex/C.java18
-rw-r--r--test/912-classes/src/B.java18
-rw-r--r--test/912-classes/src/Main.java239
-rw-r--r--test/912-classes/src/art/DexData.java100
-rw-r--r--test/912-classes/src/art/Test912Art.java78
-rw-r--r--test/Android.bp3
-rw-r--r--test/Android.run-test-jvmti-java-library.mk3
11 files changed, 560 insertions, 357 deletions
diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc
index 2636367548..869eacd82c 100644
--- a/test/912-classes/classes.cc
+++ b/test/912-classes/classes.cc
@@ -16,50 +16,39 @@
#include <stdio.h>
+#include <mutex>
+#include <vector>
+
#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
-#include "class_linker.h"
#include "jni.h"
-#include "mirror/class_loader.h"
#include "jvmti.h"
-#include "runtime.h"
-#include "scoped_local_ref.h"
-#include "scoped_utf_chars.h"
-#include "scoped_thread_state_change-inl.h"
-#include "thread-inl.h"
// Test infrastructure
#include "jni_helper.h"
#include "jvmti_helper.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
#include "test_env.h"
namespace art {
namespace Test912Classes {
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_isModifiableClass(
- JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isModifiableClass(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
jboolean res = JNI_FALSE;
jvmtiError result = jvmti_env->IsModifiableClass(klass, &res);
- if (result != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result, &err);
- printf("Failure running IsModifiableClass: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- return JNI_FALSE;
- }
+ JvmtiErrorToException(env, jvmti_env, result);
return res;
}
-extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassSignature(
+extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassSignature(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
char* sig;
char* gen;
jvmtiError result = jvmti_env->GetClassSignature(klass, &sig, &gen);
- if (result != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result, &err);
- printf("Failure running GetClassSignature: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -83,57 +72,36 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassSignature(
return ret;
}
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterface(
- JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isInterface(
+ JNIEnv* env, 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);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- return JNI_FALSE;
- }
+ JvmtiErrorToException(env, jvmti_env, result);
return is_interface;
}
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_isArrayClass(
- JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isArrayClass(
+ JNIEnv* env, 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);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- return JNI_FALSE;
- }
+ JvmtiErrorToException(env, jvmti_env, result);
return is_array_class;
}
-extern "C" JNIEXPORT jint JNICALL Java_Main_getClassModifiers(
- JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+extern "C" JNIEXPORT jint JNICALL Java_art_Test912_getClassModifiers(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
jint mod;
jvmtiError result = jvmti_env->GetClassModifiers(klass, &mod);
- if (result != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result, &err);
- printf("Failure running GetClassModifiers: %s\n", err);
- return JNI_FALSE;
- }
+ JvmtiErrorToException(env, jvmti_env, result);
return mod;
}
-extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassFields(
+extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassFields(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
jint count = 0;
jfieldID* fields = nullptr;
jvmtiError result = jvmti_env->GetClassFields(klass, &count, &fields);
- if (result != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result, &err);
- printf("Failure running GetClassFields: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -153,15 +121,12 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassFields(
return ret;
}
-extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassMethods(
+extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassMethods(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
jint count = 0;
jmethodID* methods = nullptr;
jvmtiError result = jvmti_env->GetClassMethods(klass, &count, &methods);
- if (result != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result, &err);
- printf("Failure running GetClassMethods: %s\n", err);
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -181,15 +146,12 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassMethods(
return ret;
}
-extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getImplementedInterfaces(
+extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getImplementedInterfaces(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
jint count = 0;
jclass* classes = nullptr;
jvmtiError result = jvmti_env->GetImplementedInterfaces(klass, &count, &classes);
- if (result != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result, &err);
- printf("Failure running GetImplementedInterfaces: %s\n", err);
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -203,35 +165,23 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getImplementedInterfaces(
return ret;
}
-extern "C" JNIEXPORT jint JNICALL Java_Main_getClassStatus(
- JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+extern "C" JNIEXPORT jint JNICALL Java_art_Test912_getClassStatus(
+ JNIEnv* env, 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);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- return JNI_FALSE;
- }
+ JvmtiErrorToException(env, jvmti_env, result);
return status;
}
-extern "C" JNIEXPORT jobject JNICALL Java_Main_getClassLoader(
- JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
+extern "C" JNIEXPORT jobject JNICALL Java_art_Test912_getClassLoader(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
jobject classloader;
jvmtiError result = jvmti_env->GetClassLoader(klass, &classloader);
- if (result != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result, &err);
- printf("Failure running GetClassLoader: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- return nullptr;
- }
+ JvmtiErrorToException(env, jvmti_env, result);
return classloader;
}
-extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassLoaderClasses(
+extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassLoaderClasses(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jobject jclassloader) {
jint count = 0;
jclass* classes = nullptr;
@@ -250,7 +200,7 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getClassLoaderClasses(
return ret;
}
-extern "C" JNIEXPORT jintArray JNICALL Java_Main_getClassVersion(
+extern "C" JNIEXPORT jintArray JNICALL Java_art_Test912_getClassVersion(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
jint major, minor;
jvmtiError result = jvmti_env->GetClassVersionNumbers(klass, &minor, &major);
@@ -325,6 +275,22 @@ static void EnableEvents(JNIEnv* env,
JvmtiErrorToException(env, jvmti_env, ret);
}
+static std::mutex gEventsMutex;
+static std::vector<std::string> gEvents;
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassLoadMessages(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
+ std::lock_guard<std::mutex> guard(gEventsMutex);
+ jobjectArray ret = CreateObjectArray(env,
+ static_cast<jint>(gEvents.size()),
+ "java/lang/String",
+ [&](jint i) {
+ return env->NewStringUTF(gEvents[i].c_str());
+ });
+ gEvents.clear();
+ return ret;
+}
+
class ClassLoadPreparePrinter {
public:
static void JNICALL ClassLoadCallback(jvmtiEnv* jenv,
@@ -339,7 +305,14 @@ class ClassLoadPreparePrinter {
if (thread_name == "") {
return;
}
- printf("Load: %s on %s\n", name.c_str(), thread_name.c_str());
+ if (thread_name_filter_ != "" && thread_name_filter_ != thread_name) {
+ return;
+ }
+
+ std::lock_guard<std::mutex> guard(gEventsMutex);
+ gEvents.push_back(android::base::StringPrintf("Load: %s on %s",
+ name.c_str(),
+ thread_name.c_str()));
}
static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv,
@@ -354,14 +327,18 @@ class ClassLoadPreparePrinter {
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());
+ if (thread_name_filter_ != "" && thread_name_filter_ != thread_name) {
+ return;
+ }
+ std::string cur_thread_name = GetThreadName(jenv, jni_env, nullptr);
+
+ std::lock_guard<std::mutex> guard(gEventsMutex);
+ gEvents.push_back(android::base::StringPrintf("Prepare: %s on %s (cur=%s)",
+ 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);
@@ -382,60 +359,28 @@ class ClassLoadPreparePrinter {
return tmp;
}
- static std::string GetThreadName(Thread* thread) {
- std::string tmp;
- thread->GetThreadName(tmp);
- return tmp;
- }
+ static std::string thread_name_filter_;
};
+std::string ClassLoadPreparePrinter::thread_name_filter_;
+
+extern "C" JNIEXPORT void JNICALL Java_art_Test912_enableClassLoadPreparePrintEvents(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean enable, jthread thread) {
+ if (thread != nullptr) {
+ ClassLoadPreparePrinter::thread_name_filter_ =
+ ClassLoadPreparePrinter::GetThreadName(jvmti_env, env, thread);
+ } else {
+ ClassLoadPreparePrinter::thread_name_filter_ = "";
+ }
-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;
-}
-
class ClassLoadPrepareEquality {
public:
- static constexpr const char* kClassName = "LMain$ClassE;";
+ static constexpr const char* kClassName = "Lart/Test912$ClassE;";
static constexpr const char* kStorageFieldName = "STATIC";
static constexpr const char* kStorageFieldSig = "Ljava/lang/Object;";
static constexpr const char* kStorageWeakFieldName = "WEAK";
@@ -553,13 +498,13 @@ jobject ClassLoadPrepareEquality::local_stored_class_ = nullptr;
bool ClassLoadPrepareEquality::found_ = false;
bool ClassLoadPrepareEquality::compared_ = false;
-extern "C" JNIEXPORT void JNICALL Java_Main_setEqualityEventStorageClass(
+extern "C" JNIEXPORT void JNICALL Java_art_Test912_setEqualityEventStorageClass(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
ClassLoadPrepareEquality::storage_class_ =
reinterpret_cast<jclass>(env->NewGlobalRef(klass));
}
-extern "C" JNIEXPORT void JNICALL Java_Main_enableClassLoadPrepareEqualityEvents(
+extern "C" JNIEXPORT void JNICALL Java_art_Test912_enableClassLoadPrepareEqualityEvents(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) {
EnableEvents(env,
b,
diff --git a/test/912-classes/classes_art.cc b/test/912-classes/classes_art.cc
new file mode 100644
index 0000000000..de2e456a53
--- /dev/null
+++ b/test/912-classes/classes_art.cc
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include <mutex>
+#include <vector>
+
+#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
+
+#include "jni.h"
+#include "jvmti.h"
+
+// Test infrastructure
+#include "jni_helper.h"
+#include "jvmti_helper.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
+#include "test_env.h"
+
+namespace art {
+namespace Test912ArtClasses {
+
+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);
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
+ return;
+ }
+ ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+ JVMTI_EVENT_CLASS_PREPARE,
+ nullptr);
+ JvmtiErrorToException(env, jvmti_env, ret);
+ return;
+ }
+
+ jvmtiEventCallbacks callbacks;
+ memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
+ callbacks.ClassLoad = class_load;
+ callbacks.ClassPrepare = class_prepare;
+ jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
+ return;
+ }
+
+ ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+ JVMTI_EVENT_CLASS_LOAD,
+ nullptr);
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
+ return;
+ }
+ ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+ JVMTI_EVENT_CLASS_PREPARE,
+ nullptr);
+ JvmtiErrorToException(env, jvmti_env, ret);
+}
+
+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_art_Test912Art_enableClassLoadSeenEvents(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) {
+ EnableEvents(env, b, ClassLoadSeen::ClassLoadSeenCallback, nullptr);
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912Art_hadLoadEvent(
+ JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass ATTRIBUTE_UNUSED) {
+ return ClassLoadSeen::saw_event ? JNI_TRUE : JNI_FALSE;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912Art_isLoadedClass(
+ JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring class_name) {
+ ScopedUtfChars name(env, class_name);
+
+ jint class_count;
+ jclass* classes;
+ jvmtiError res = jvmti_env->GetLoadedClasses(&class_count, &classes);
+ if (JvmtiErrorToException(env, jvmti_env, res)) {
+ return JNI_FALSE;
+ }
+
+ bool found = false;
+ for (jint i = 0; !found && i < class_count; ++i) {
+ char* sig;
+ jvmtiError res2 = jvmti_env->GetClassSignature(classes[i], &sig, nullptr);
+ if (JvmtiErrorToException(env, jvmti_env, res2)) {
+ return JNI_FALSE;
+ }
+
+ found = strcmp(name.c_str(), sig) == 0;
+
+ CheckJvmtiError(jvmti_env, jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig)));
+ }
+
+ CheckJvmtiError(jvmti_env, jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes)));
+
+ return found;
+}
+
+// We use the implementations from runtime_state.cc.
+
+extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
+ jclass,
+ jclass cls,
+ jstring method_name);
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJit(JNIEnv*, jclass);
+
+extern "C" JNIEXPORT void JNICALL Java_art_Test912Art_ensureJitCompiled(
+ JNIEnv* env, jclass klass, jclass test_class, jstring name) {
+ Java_Main_ensureJitCompiled(env, klass, test_class, name);
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912Art_hasJit(JNIEnv* env, jclass klass) {
+ return Java_Main_hasJit(env, klass);
+}
+
+} // namespace Test912ArtClasses
+} // namespace art
diff --git a/test/912-classes/expected.txt b/test/912-classes/expected.txt
index 0f2920a0c2..9dcc5f9c90 100644
--- a/test/912-classes/expected.txt
+++ b/test/912-classes/expected.txt
@@ -6,14 +6,14 @@
11
[Ljava/util/List;, <E:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/Collection<TE;>;]
601
-[L$Proxy0;, null]
+[L$Proxy20;, null]
11
[I, null]
411
[[D, null]
411
int interface=false array=false modifiable=false
-$Proxy0 interface=false array=false modifiable=false
+$Proxy20 interface=false array=false modifiable=false
java.lang.Runnable interface=true array=false modifiable=false
java.lang.String interface=false array=false modifiable=false
java.util.ArrayList interface=false array=false modifiable=true
@@ -29,70 +29,65 @@ java.util.ArrayList interface=false array=false modifiable=true
int 100000
class [Ljava.lang.String; 10000
class java.lang.Object 111
-class Main$TestForNonInit 11
-class Main$TestForInitFail 1011
+class art.Test912$TestForNonInit 11
+class art.Test912$TestForInitFail 1011
int []
class [Ljava.lang.String; []
class java.lang.Object []
-interface Main$InfA []
-interface Main$InfB [interface Main$InfA]
-interface Main$InfC [interface Main$InfB]
-class Main$ClassA [interface Main$InfA]
-class Main$ClassB [interface Main$InfB]
-class Main$ClassC [interface Main$InfA, interface Main$InfC]
+interface art.Test912$InfA []
+interface art.Test912$InfB [interface art.Test912$InfA]
+interface art.Test912$InfC [interface art.Test912$InfB]
+class art.Test912$ClassA [interface art.Test912$InfA]
+class art.Test912$ClassB [interface art.Test912$InfB]
+class art.Test912$ClassC [interface art.Test912$InfA, interface art.Test912$InfC]
class java.lang.String null
class [Ljava.lang.String; null
-interface Main$InfA dalvik.system.PathClassLoader
-class $Proxy0 dalvik.system.PathClassLoader
+interface art.Test912$InfA dalvik.system.PathClassLoader
+class $Proxy20 dalvik.system.PathClassLoader
-boot <- src <- src-ex (A,B)
-912-classes-ex.jar+ -> 912-classes.jar+ ->
+boot <- (B) <- (A,C)
[class A, class B, class java.lang.Object]
-912-classes.jar+ ->
[class B, class java.lang.Object]
-boot <- src (B) <- src-ex (A, List)
-912-classes-ex.jar+ -> 912-classes.jar+ ->
+boot <- (B) <- (A, List)
[class A, class java.lang.Object, interface java.util.List]
-912-classes.jar+ ->
[class B, class java.lang.Object]
-boot <- src+src-ex (A,B)
-912-classes.jar+ ->
+boot <- 1+2 (A,B)
[class A, class B, class java.lang.Object]
[37, 0]
B, false
-Load: LB; on main
-Prepare: LB; on main (cur=main)
+Load: LB; on ClassEvents
+Prepare: LB; on ClassEvents (cur=ClassEvents)
B, true
-Load: LB; on main
-Prepare: LB; on main (cur=main)
+Load: LB; on ClassEvents
+Prepare: LB; on ClassEvents (cur=ClassEvents)
C, false
-Load: LA; on main
-Prepare: LA; on main (cur=main)
-Load: LC; on main
-Prepare: LC; on main (cur=main)
+Load: LA; on ClassEvents
+Prepare: LA; on ClassEvents (cur=ClassEvents)
+Load: LC; on ClassEvents
+Prepare: LC; on ClassEvents (cur=ClassEvents)
A, false
C, true
-Load: LA; on main
-Prepare: LA; on main (cur=main)
-Load: LC; on main
-Prepare: LC; on main (cur=main)
+Load: LA; on ClassEvents
+Prepare: LA; on ClassEvents (cur=ClassEvents)
+Load: LC; on ClassEvents
+Prepare: LC; on ClassEvents (cur=ClassEvents)
A, true
A, true
-Load: LA; on main
-Prepare: LA; on main (cur=main)
+Load: LA; on ClassEvents
+Prepare: LA; on ClassEvents (cur=ClassEvents)
C, true
-Load: LC; on main
-Prepare: LC; on main (cur=main)
+Load: LC; on ClassEvents
+Prepare: LC; on ClassEvents (cur=ClassEvents)
C, true
Load: LA; on TestRunner
Prepare: LA; on TestRunner (cur=TestRunner)
Load: LC; on TestRunner
Prepare: LC; on TestRunner (cur=TestRunner)
-Load: L$Proxy1; on main
-Prepare: L$Proxy1; on main (cur=main)
-Load: [LMain; on main
-Prepare: [LMain; on main (cur=main)
+Load: L$Proxy21; on ClassEvents
+Prepare: L$Proxy21; on ClassEvents (cur=ClassEvents)
+Load: [Lart/Test912; on ClassEvents
+Prepare: [Lart/Test912; on ClassEvents (cur=ClassEvents)
diff --git a/test/912-classes/src-ex/A.java b/test/912-classes/src-ex/A.java
deleted file mode 100644
index 2c43cfbd79..0000000000
--- a/test/912-classes/src-ex/A.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class A {
-}
diff --git a/test/912-classes/src-ex/C.java b/test/912-classes/src-ex/C.java
deleted file mode 100644
index 97f8021486..0000000000
--- a/test/912-classes/src-ex/C.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class C extends A {
-}
diff --git a/test/912-classes/src/B.java b/test/912-classes/src/B.java
deleted file mode 100644
index 52ce4dd58e..0000000000
--- a/test/912-classes/src/B.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class B {
-}
diff --git a/test/912-classes/src/Main.java b/test/912-classes/src/Main.java
index 6c8858ab65..f3ff2b0668 100644
--- a/test/912-classes/src/Main.java
+++ b/test/912-classes/src/Main.java
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+package art;
+
import java.lang.ref.Reference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
@@ -21,9 +23,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
-public class Main {
- public static void main(String[] args) throws Exception {
- art.Main.bindAgentJNIForClass(Main.class);
+public class Test912 {
+ public static void run() throws Exception {
+ art.Main.bindAgentJNIForClass(Test912.class);
doTest();
}
@@ -89,18 +91,19 @@ public class Main {
System.out.println();
- testClassEvents();
- }
-
- private static Class<?> proxyClass = null;
-
- private static Class<?> getProxyClass() throws Exception {
- if (proxyClass != null) {
- return proxyClass;
- }
-
- proxyClass = Proxy.getProxyClass(Main.class.getClassLoader(), new Class[] { Runnable.class });
- return proxyClass;
+ // Use a dedicated thread to have a well-defined current thread.
+ Thread classEventsThread = new Thread("ClassEvents") {
+ @Override
+ public void run() {
+ try {
+ testClassEvents();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+ classEventsThread.start();
+ classEventsThread.join();
}
private static void testClass(String className) throws Exception {
@@ -166,34 +169,34 @@ public class Main {
}
private static void testClassLoaderClasses() throws Exception {
- ClassLoader boot = ClassLoader.getSystemClassLoader().getParent();
- while (boot.getParent() != null) {
- boot = boot.getParent();
- }
-
System.out.println();
- System.out.println("boot <- src <- src-ex (A,B)");
- ClassLoader cl1 = create(create(boot, DEX1), DEX2);
+ System.out.println("boot <- (B) <- (A,C)");
+ ClassLoader cl1 = DexData.create2(DexData.create1());
Class.forName("B", false, cl1);
Class.forName("A", false, cl1);
printClassLoaderClasses(cl1);
System.out.println();
- System.out.println("boot <- src (B) <- src-ex (A, List)");
- ClassLoader cl2 = create(create(boot, DEX1), DEX2);
+ System.out.println("boot <- (B) <- (A, List)");
+ ClassLoader cl2 = DexData.create2(DexData.create1());
Class.forName("A", false, cl2);
Class.forName("java.util.List", false, cl2);
Class.forName("B", false, cl2.getParent());
printClassLoaderClasses(cl2);
System.out.println();
- System.out.println("boot <- src+src-ex (A,B)");
- ClassLoader cl3 = create(boot, DEX1, DEX2);
+ System.out.println("boot <- 1+2 (A,B)");
+ ClassLoader cl3 = DexData.create12();
Class.forName("B", false, cl3);
Class.forName("A", false, cl3);
printClassLoaderClasses(cl3);
// Check that the boot classloader dumps something non-empty.
+ ClassLoader boot = ClassLoader.getSystemClassLoader().getParent();
+ while (boot.getParent() != null) {
+ boot = boot.getParent();
+ }
+
Class<?>[] bootClasses = getClassLoaderClasses(boot);
if (bootClasses.length == 0) {
throw new RuntimeException("No classes initiated by boot classloader.");
@@ -236,9 +239,10 @@ public class Main {
@Override
public void run() {
try {
- ClassLoader cl6 = create(boot, DEX1, DEX2);
+ ClassLoader cl6 = DexData.create12();
System.out.println("C, true");
Class.forName("C", true, cl6);
+ printClassLoadMessages();
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -249,77 +253,60 @@ public class Main {
dummyThread.start();
dummyThread.join();
- ensureJitCompiled(Main.class, "testClassEvents");
-
- enableClassLoadPreparePrintEvents(true);
+ enableClassLoadPreparePrintEvents(true, Thread.currentThread());
- ClassLoader cl1 = create(boot, DEX1, DEX2);
+ ClassLoader cl1 = DexData.create12();
System.out.println("B, false");
Class.forName("B", false, cl1);
+ printClassLoadMessages();
- ClassLoader cl2 = create(boot, DEX1, DEX2);
+ ClassLoader cl2 = DexData.create12();
System.out.println("B, true");
Class.forName("B", true, cl2);
+ printClassLoadMessages();
- ClassLoader cl3 = create(boot, DEX1, DEX2);
+ ClassLoader cl3 = DexData.create12();
System.out.println("C, false");
Class.forName("C", false, cl3);
+ printClassLoadMessages();
System.out.println("A, false");
Class.forName("A", false, cl3);
+ printClassLoadMessages();
- ClassLoader cl4 = create(boot, DEX1, DEX2);
+ ClassLoader cl4 = DexData.create12();
System.out.println("C, true");
Class.forName("C", true, cl4);
+ printClassLoadMessages();
System.out.println("A, true");
Class.forName("A", true, cl4);
+ printClassLoadMessages();
- ClassLoader cl5 = create(boot, DEX1, DEX2);
+ ClassLoader cl5 = DexData.create12();
System.out.println("A, true");
Class.forName("A", true, cl5);
+ printClassLoadMessages();
System.out.println("C, true");
Class.forName("C", true, cl5);
+ printClassLoadMessages();
+
+ enableClassLoadPreparePrintEvents(false, null);
Thread t = new Thread(r, "TestRunner");
+ enableClassLoadPreparePrintEvents(true, t);
t.start();
t.join();
+ enableClassLoadPreparePrintEvents(false, null);
- // Check creation of arrays and proxies.
- Proxy.getProxyClass(Main.class.getClassLoader(), new Class[] { Comparable.class });
- Class.forName("[LMain;");
-
- 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();
- }
-
- testClassLoadPrepareEquality();
- }
-
- private static void testClassEventsJit() throws Exception {
- enableClassLoadSeenEvents(true);
+ enableClassLoadPreparePrintEvents(true, Thread.currentThread());
- testClassEventsJitImpl();
-
- enableClassLoadSeenEvents(false);
-
- if (!hadLoadEvent()) {
- throw new RuntimeException("Did not get expected load event.");
- }
- }
+ // Check creation of arrays and proxies.
+ Proxy.getProxyClass(Main.class.getClassLoader(), new Class[] { Comparable.class, I0.class });
+ Class.forName("[Lart.Test912;");
+ printClassLoadMessages();
- private static void testClassEventsJitImpl() throws Exception {
- ensureJitCompiled(Main.class, "testClassEventsJitImpl");
+ enableClassLoadPreparePrintEvents(false, null);
- if (ClassD.x != 1) {
- throw new RuntimeException("Unexpected value");
- }
+ testClassLoadPrepareEquality();
}
private static void testClassLoadPrepareEquality() throws Exception {
@@ -327,7 +314,7 @@ public class Main {
enableClassLoadPrepareEqualityEvents(true);
- Class.forName("Main$ClassE");
+ Class.forName("art.Test912$ClassE");
enableClassLoadPrepareEqualityEvents(false);
}
@@ -338,39 +325,17 @@ public class Main {
break;
}
- ClassLoader saved = cl;
- for (;;) {
- if (cl == null || !cl.getClass().getName().startsWith("dalvik.system")) {
- break;
- }
- String s = cl.toString();
- int index1 = s.indexOf("zip file");
- int index2 = s.indexOf(']', index1);
- if (index2 < 0) {
- throw new RuntimeException("Unexpected classloader " + s);
- }
- String zip_file = s.substring(index1, index2);
- int index3 = zip_file.indexOf('"');
- int index4 = zip_file.indexOf('"', index3 + 1);
- if (index4 < 0) {
- throw new RuntimeException("Unexpected classloader " + s);
- }
- String paths = zip_file.substring(index3 + 1, index4);
- String pathArray[] = paths.split(":");
- for (String path : pathArray) {
- int index5 = path.lastIndexOf('/');
- System.out.print(path.substring(index5 + 1));
- System.out.print('+');
- }
- System.out.print(" -> ");
- cl = cl.getParent();
- }
- System.out.println();
- Class<?> classes[] = getClassLoaderClasses(saved);
+ Class<?> classes[] = getClassLoaderClasses(cl);
Arrays.sort(classes, new ClassNameComparator());
System.out.println(Arrays.toString(classes));
- cl = saved.getParent();
+ cl = cl.getParent();
+ }
+ }
+
+ private static void printClassLoadMessages() {
+ for (String s : getClassLoadMessages()) {
+ System.out.println(s);
}
}
@@ -394,14 +359,8 @@ public class Main {
private static native int[] getClassVersion(Class<?> c);
- private static native void enableClassLoadPreparePrintEvents(boolean b);
-
- 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 native void enableClassLoadPreparePrintEvents(boolean b, Thread filter);
+ private static native String[] getClassLoadMessages();
private static native void setEqualityEventStorageClass(Class<?> c);
private static native void enableClassLoadPrepareEqualityEvents(boolean b);
@@ -428,10 +387,6 @@ public class Main {
public abstract static class ClassC implements InfA, InfC {
}
- public static class ClassD {
- static int x = 1;
- }
-
public static class ClassE {
public void foo() {
}
@@ -444,22 +399,56 @@ public class Main {
public static Reference<Object> WEAK = null;
}
- 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";
-
- private static ClassLoader create(ClassLoader parent, String... elements) throws Exception {
- // Note: We use a PathClassLoader, as we do not care about code performance. We only load
- // the classes, and they're empty.
- Class<?> pathClassLoaderClass = Class.forName("dalvik.system.PathClassLoader");
- Constructor<?> pathClassLoaderInit = pathClassLoaderClass.getConstructor(String.class,
- ClassLoader.class);
- String path = String.join(":", elements);
- return (ClassLoader) pathClassLoaderInit.newInstance(path, parent);
- }
-
private static class ClassNameComparator implements Comparator<Class<?>> {
public int compare(Class<?> c1, Class<?> c2) {
return c1.getName().compareTo(c2.getName());
}
}
+
+ // See run-test 910 for an explanation.
+
+ private static Class<?> proxyClass = null;
+
+ private static Class<?> getProxyClass() throws Exception {
+ if (proxyClass != null) {
+ return proxyClass;
+ }
+
+ for (int i = 1; i <= 21; i++) {
+ proxyClass = createProxyClass(i);
+ String name = proxyClass.getName();
+ if (name.equals("$Proxy20")) {
+ return proxyClass;
+ }
+ }
+ return proxyClass;
+ }
+
+ private static Class<?> createProxyClass(int i) throws Exception {
+ int count = Integer.bitCount(i);
+ Class<?>[] input = new Class<?>[count + 1];
+ input[0] = Runnable.class;
+ int inputIndex = 1;
+ int bitIndex = 0;
+ while (i != 0) {
+ if ((i & 1) != 0) {
+ input[inputIndex++] = Class.forName("art.Test912$I" + bitIndex);
+ }
+ i >>>= 1;
+ bitIndex++;
+ }
+ return Proxy.getProxyClass(Test912.class.getClassLoader(), input);
+ }
+
+ // Need this for the proxy naming.
+ public static interface I0 {
+ }
+ public static interface I1 {
+ }
+ public static interface I2 {
+ }
+ public static interface I3 {
+ }
+ public static interface I4 {
+ }
}
diff --git a/test/912-classes/src/art/DexData.java b/test/912-classes/src/art/DexData.java
new file mode 100644
index 0000000000..7d150322ca
--- /dev/null
+++ b/test/912-classes/src/art/DexData.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.nio.ByteBuffer;
+import java.util.Base64;
+
+import dalvik.system.InMemoryDexClassLoader;
+
+public class DexData {
+ public static ClassLoader getBootClassLoader() {
+ ClassLoader cl = DexData.class.getClassLoader();
+ while (cl.getParent() != null) {
+ cl = cl.getParent();
+ }
+ return cl;
+ }
+
+ public static ClassLoader create1() {
+ return create1(getBootClassLoader());
+ }
+ public static ClassLoader create1(ClassLoader parent) {
+ return create(parent, DEX_DATA_B);
+ }
+
+ public static ClassLoader create2() {
+ return create2(getBootClassLoader());
+ }
+ public static ClassLoader create2(ClassLoader parent) {
+ return create(parent, DEX_DATA_AC);
+ }
+
+ public static ClassLoader create12() {
+ return create12(getBootClassLoader());
+ }
+ public static ClassLoader create12(ClassLoader parent) {
+ return create(parent, DEX_DATA_AC, DEX_DATA_B);
+ }
+
+ private static ClassLoader create(ClassLoader parent, String... stringData) {
+ ByteBuffer byteBuffers[] = new ByteBuffer[stringData.length];
+ for (int i = 0; i < stringData.length; i++) {
+ byteBuffers[i] = ByteBuffer.wrap(Base64.getDecoder().decode(stringData[i]));
+ }
+ return new InMemoryDexClassLoader(byteBuffers, parent);
+ }
+
+ /*
+ * Derived from:
+ *
+ * public class A {
+ * }
+ *
+ * public class C extends A {
+ * }
+ *
+ */
+ private final static String DEX_DATA_AC =
+ "ZGV4CjAzNQD5KyH7WmGuqVEyL+2aKG1nyb27UJaCjFwQAgAAcAAAAHhWNBIAAAAAAAAAAIgBAAAH" +
+ "AAAAcAAAAAQAAACMAAAAAQAAAJwAAAAAAAAAAAAAAAMAAACoAAAAAgAAAMAAAAAQAQAAAAEAADAB" +
+ "AAA4AQAAQAEAAEgBAABNAQAAUgEAAGYBAAADAAAABAAAAAUAAAAGAAAABgAAAAMAAAAAAAAAAAAA" +
+ "AAAAAAABAAAAAAAAAAIAAAAAAAAAAAAAAAEAAAACAAAAAAAAAAEAAAAAAAAAcwEAAAAAAAABAAAA" +
+ "AQAAAAAAAAAAAAAAAgAAAAAAAAB9AQAAAAAAAAEAAQABAAAAaQEAAAQAAABwEAIAAAAOAAEAAQAB" +
+ "AAAAbgEAAAQAAABwEAAAAAAOAAY8aW5pdD4ABkEuamF2YQAGQy5qYXZhAANMQTsAA0xDOwASTGph" +
+ "dmEvbGFuZy9PYmplY3Q7AAFWABEABw4AEQAHDgAAAAEAAIGABIACAAABAAGBgASYAgALAAAAAAAA" +
+ "AAEAAAAAAAAAAQAAAAcAAABwAAAAAgAAAAQAAACMAAAAAwAAAAEAAACcAAAABQAAAAMAAACoAAAA" +
+ "BgAAAAIAAADAAAAAASAAAAIAAAAAAQAAAiAAAAcAAAAwAQAAAyAAAAIAAABpAQAAACAAAAIAAABz" +
+ "AQAAABAAAAEAAACIAQAA";
+
+ /*
+ * Derived from:
+ *
+ * public class B {
+ * }
+ *
+ */
+ private final static String DEX_DATA_B =
+ "ZGV4CjAzNQBgKV6iWFG4aOm5WEy8oGtDZjqsftBgwJ2oAQAAcAAAAHhWNBIAAAAAAAAAACABAAAF" +
+ "AAAAcAAAAAMAAACEAAAAAQAAAJAAAAAAAAAAAAAAAAIAAACcAAAAAQAAAKwAAADcAAAAzAAAAOQA" +
+ "AADsAAAA9AAAAPkAAAANAQAAAgAAAAMAAAAEAAAABAAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAAAA" +
+ "AAAAAAABAAAAAQAAAAAAAAABAAAAAAAAABUBAAAAAAAAAQABAAEAAAAQAQAABAAAAHAQAQAAAA4A" +
+ "Bjxpbml0PgAGQi5qYXZhAANMQjsAEkxqYXZhL2xhbmcvT2JqZWN0OwABVgARAAcOAAAAAQAAgYAE" +
+ "zAEACwAAAAAAAAABAAAAAAAAAAEAAAAFAAAAcAAAAAIAAAADAAAAhAAAAAMAAAABAAAAkAAAAAUA" +
+ "AAACAAAAnAAAAAYAAAABAAAArAAAAAEgAAABAAAAzAAAAAIgAAAFAAAA5AAAAAMgAAABAAAAEAEA" +
+ "AAAgAAABAAAAFQEAAAAQAAABAAAAIAEAAA==";
+}
diff --git a/test/912-classes/src/art/Test912Art.java b/test/912-classes/src/art/Test912Art.java
new file mode 100644
index 0000000000..e4384734d8
--- /dev/null
+++ b/test/912-classes/src/art/Test912Art.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.ref.Reference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+
+public class Test912Art {
+ public static void run() throws Exception {
+ art.Main.bindAgentJNIForClass(Test912Art.class);
+ doTest();
+ }
+
+ public static void doTest() throws Exception {
+ testClassEvents();
+ }
+
+ private static void testClassEvents() throws Exception {
+ // 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("art.Test912Art$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(Test912Art.class, "testClassEventsJitImpl");
+
+ if (ClassD.x != 1) {
+ throw new RuntimeException("Unexpected value");
+ }
+ }
+
+ 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();
+
+ public static class ClassD {
+ static int x = 1;
+ }
+}
diff --git a/test/Android.bp b/test/Android.bp
index c5d96da20c..095b754f1e 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -261,6 +261,7 @@ art_cc_defaults {
"908-gc-start-finish/gc_callbacks.cc",
"910-methods/methods.cc",
"911-get-stack-trace/stack_trace.cc",
+ "912-classes/classes.cc",
"913-heaps/heaps.cc",
"918-fields/fields.cc",
"920-objects/objects.cc",
@@ -295,7 +296,7 @@ art_cc_defaults {
// make this list smaller.
"901-hello-ti-agent/basics.cc",
"909-attach-agent/attach.cc",
- "912-classes/classes.cc",
+ "912-classes/classes_art.cc",
"936-search-onload/search_onload.cc",
"983-source-transform-verify/source_transform.cc",
],
diff --git a/test/Android.run-test-jvmti-java-library.mk b/test/Android.run-test-jvmti-java-library.mk
index dcb238cd9f..70ee693a60 100644
--- a/test/Android.run-test-jvmti-java-library.mk
+++ b/test/Android.run-test-jvmti-java-library.mk
@@ -45,6 +45,8 @@ LOCAL_SRC_FILES += \
911-get-stack-trace/src/art/Recurse.java \
911-get-stack-trace/src/art/SameThread.java \
911-get-stack-trace/src/art/ThreadListTraces.java \
+ 912-classes/src/art/Test912.java \
+ 912-classes/src/art/DexData.java \
913-heaps/src/art/Test913.java \
914-hello-obsolescence/src/art/Test914.java \
915-obsolete-2/src/art/Test915.java \
@@ -84,6 +86,7 @@ JVMTI_RUN_TEST_GENERATED_NUMBERS := \
908 \
910 \
911 \
+ 912 \
913 \
914 \
915 \