summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 \