diff options
| -rw-r--r-- | test/912-classes/classes.cc | 219 | ||||
| -rw-r--r-- | test/912-classes/classes_art.cc | 146 | ||||
| -rw-r--r-- | test/912-classes/expected.txt | 75 | ||||
| -rw-r--r-- | test/912-classes/src-ex/A.java | 18 | ||||
| -rw-r--r-- | test/912-classes/src-ex/C.java | 18 | ||||
| -rw-r--r-- | test/912-classes/src/B.java | 18 | ||||
| -rw-r--r-- | test/912-classes/src/Main.java | 239 | ||||
| -rw-r--r-- | test/912-classes/src/art/DexData.java | 100 | ||||
| -rw-r--r-- | test/912-classes/src/art/Test912Art.java | 78 | ||||
| -rw-r--r-- | test/Android.bp | 3 | ||||
| -rw-r--r-- | test/Android.run-test-jvmti-java-library.mk | 3 |
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 \ |