diff options
author | 2022-11-18 10:55:05 +0000 | |
---|---|---|
committer | 2022-11-21 14:25:03 +0000 | |
commit | f7bd1fa21250302ef885ffef3b1e096d53b0845c (patch) | |
tree | cf2deeb39a4f19550c9190f958171dadd932b950 | |
parent | f356dcd48faaab0bb78fe085b9d429ff4cdd6d59 (diff) |
Change well known thread methods to `ArtMethod*`.
Also rename `java_lang_ThreadGroup_removeThread` to
`java_lang_ThreadGroup_threadTerminated` in line with
the actual method it references.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Change-Id: Iaf2644d006f44759a47587c82db2dcdba0bfa67e
-rw-r--r-- | adbconnection/adbconnection.cc | 40 | ||||
-rw-r--r-- | openjdkjvmti/ti_redefine.cc | 2 | ||||
-rw-r--r-- | openjdkjvmti/ti_stack.cc | 5 | ||||
-rw-r--r-- | openjdkjvmti/ti_thread.cc | 72 | ||||
-rw-r--r-- | openjdkjvmti/ti_threadgroup.cc | 30 | ||||
-rw-r--r-- | runtime/art_method-inl.h | 42 | ||||
-rw-r--r-- | runtime/art_method.h | 21 | ||||
-rw-r--r-- | runtime/class_linker.cc | 3 | ||||
-rw-r--r-- | runtime/hidden_api.cc | 4 | ||||
-rw-r--r-- | runtime/interpreter/unstarted_runtime.cc | 10 | ||||
-rw-r--r-- | runtime/jni/jni_internal.cc | 5 | ||||
-rw-r--r-- | runtime/native/jdk_internal_misc_Unsafe.cc | 8 | ||||
-rw-r--r-- | runtime/native/sun_misc_Unsafe.cc | 8 | ||||
-rw-r--r-- | runtime/runtime.cc | 22 | ||||
-rw-r--r-- | runtime/runtime_callbacks_test.cc | 56 | ||||
-rw-r--r-- | runtime/thread.cc | 187 | ||||
-rw-r--r-- | runtime/thread.h | 20 | ||||
-rw-r--r-- | runtime/well_known_classes.cc | 85 | ||||
-rw-r--r-- | runtime/well_known_classes.h | 12 | ||||
-rw-r--r-- | test/913-heaps/expected-stdout.txt | 8 |
20 files changed, 361 insertions, 279 deletions
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc index de6f6fcff7..e1980bd604 100644 --- a/adbconnection/adbconnection.cc +++ b/adbconnection/adbconnection.cc @@ -33,6 +33,7 @@ #include "debugger.h" #include "jni/java_vm_ext.h" #include "jni/jni_env_ext.h" +#include "mirror/class-alloc-inl.h" #include "mirror/throwable.h" #include "nativehelper/scoped_local_ref.h" #include "runtime-inl.h" @@ -181,24 +182,33 @@ AdbConnectionState::~AdbConnectionState() { } } -static jobject CreateAdbConnectionThread(art::ScopedObjectAccess& soa) +static art::ObjPtr<art::mirror::Object> CreateAdbConnectionThread(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_) { - JNIEnv* env = soa.Self()->GetJniEnv(); - ScopedLocalRef<jstring> thr_name(env, env->NewStringUTF(kAdbConnectionThreadName)); + art::StackHandleScope<2u> hs(self); + art::Handle<art::mirror::String> thr_name = + hs.NewHandle(art::mirror::String::AllocFromModifiedUtf8(self, kAdbConnectionThreadName)); + if (thr_name == nullptr) { + DCHECK(self->IsExceptionPending()); + return nullptr; + } + art::ObjPtr<art::mirror::Class> thread_class = + art::WellKnownClasses::java_lang_Thread_init->GetDeclaringClass(); + art::Handle<art::mirror::Object> thread = hs.NewHandle(thread_class->AllocObject(self)); + if (thread == nullptr) { + DCHECK(self->IsExceptionPending()); + return nullptr; + } art::ArtField* system_thread_group_field = art::WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup; + DCHECK(system_thread_group_field->GetDeclaringClass()->IsInitialized()); // Avoid using `ArtField::GetObject` as it requires linking against `libdexfile` for // `operator<<(std::ostream&, Primitive::Type)`. art::ObjPtr<art::mirror::Object> system_thread_group = system_thread_group_field->GetDeclaringClass()->GetFieldObject<art::mirror::Object>( system_thread_group_field->GetOffset()); - ScopedLocalRef<jobject> thr_group(env, soa.AddLocalReference<jobject>(system_thread_group)); - return env->NewObject(art::WellKnownClasses::java_lang_Thread, - art::WellKnownClasses::java_lang_Thread_init, - thr_group.get(), - thr_name.get(), - /*Priority=*/ 0, - /*Daemon=*/ true); + art::WellKnownClasses::java_lang_Thread_init->InvokeInstance<'V', 'L', 'L', 'I', 'Z'>( + self, thread.Get(), system_thread_group, thr_name.Get(), /*priority=*/ 0, /*daemon=*/ 1u); + return self->IsExceptionPending() ? nullptr : thread.Get(); } struct CallbackData { @@ -278,10 +288,14 @@ void AdbConnectionState::StartDebuggerThreads() { } runtime->StartThreadBirth(); } - ScopedLocalRef<jobject> thr(soa.Env(), CreateAdbConnectionThread(soa)); + jobject thr = soa.Env()->GetVm()->AddGlobalRef(self, CreateAdbConnectionThread(soa.Self())); + if (thr == nullptr) { + LOG(ERROR) << "Failed to create debugger thread!"; + return; + } // Note: Using pthreads instead of std::thread to not abort when the thread cannot be // created (exception support required). - std::unique_ptr<CallbackData> data(new CallbackData { this, soa.Env()->NewGlobalRef(thr.get()) }); + std::unique_ptr<CallbackData> data(new CallbackData { this, thr }); started_debugger_threads_ = true; gPthread.emplace(); int pthread_create_result = pthread_create(&gPthread.value(), @@ -293,7 +307,7 @@ void AdbConnectionState::StartDebuggerThreads() { started_debugger_threads_ = false; // If the create succeeded the other thread will call EndThreadBirth. art::Runtime* runtime = art::Runtime::Current(); - soa.Env()->DeleteGlobalRef(data->thr_); + soa.Env()->DeleteGlobalRef(thr); LOG(ERROR) << "Failed to create thread for adb-jdwp connection manager!"; art::MutexLock mu(art::Thread::Current(), *art::Locks::runtime_shutdown_lock_); runtime->EndThreadBirth(); diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index c1f6d6319e..a8c4495689 100644 --- a/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc @@ -457,7 +457,7 @@ jvmtiError Redefiner::GetClassRedefinitionError(art::Handle<art::mirror::Class> // Check Thread specifically since it's not a root but too many things reach into it with Unsafe // too allow structural redefinition. if (klass->IsAssignableFrom( - self->DecodeJObject(art::WellKnownClasses::java_lang_Thread)->AsClass())) { + art::WellKnownClasses::java_lang_Thread_init->GetDeclaringClass())) { *error_msg = "java.lang.Thread has fields accessed using sun.misc.unsafe directly. It is not " "safe to structurally redefine it."; diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc index 38257f1d6a..74dae8e9f7 100644 --- a/openjdkjvmti/ti_stack.cc +++ b/openjdkjvmti/ti_stack.cc @@ -578,10 +578,11 @@ jvmtiError StackUtil::GetThreadListStackTraces(jvmtiEnv* env, if (thread_list[i] == nullptr) { return ERR(INVALID_THREAD); } - if (!soa.Env()->IsInstanceOf(thread_list[i], art::WellKnownClasses::java_lang_Thread)) { + art::ObjPtr<art::mirror::Object> thread = soa.Decode<art::mirror::Object>(thread_list[i]); + if (!thread->InstanceOf(art::WellKnownClasses::java_lang_Thread_init->GetDeclaringClass())) { return ERR(INVALID_THREAD); } - data.handles.push_back(hs.NewHandle(soa.Decode<art::mirror::Object>(thread_list[i]))); + data.handles.push_back(hs.NewHandle(thread)); } RunCheckpointAndWait(&data, static_cast<size_t>(max_frame_count)); diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc index a138c69945..5c0c3854a4 100644 --- a/openjdkjvmti/ti_thread.cc +++ b/openjdkjvmti/ti_thread.cc @@ -193,7 +193,7 @@ void ThreadUtil::CacheData() { art::Thread* self = art::Thread::Current(); art::ScopedObjectAccess soa(self); art::ObjPtr<art::mirror::Class> thread_class = - soa.Decode<art::mirror::Class>(art::WellKnownClasses::java_lang_Thread); + art::WellKnownClasses::java_lang_Thread_init->GetDeclaringClass(); CHECK(thread_class != nullptr); context_class_loader_ = thread_class->FindDeclaredInstanceField("contextClassLoader", "Ljava/lang/ClassLoader;"); @@ -236,7 +236,9 @@ bool ThreadUtil::GetNativeThread(jthread thread, if (thread == nullptr) { *thr = art::Thread::Current(); return true; - } else if (!soa.Env()->IsInstanceOf(thread, art::WellKnownClasses::java_lang_Thread)) { + } + art::ObjPtr<art::mirror::Object> othread = soa.Decode<art::mirror::Object>(thread); + if (!othread->InstanceOf(art::WellKnownClasses::java_lang_Thread_init->GetDeclaringClass())) { *err = ERR(INVALID_THREAD); return false; } else { @@ -618,7 +620,7 @@ jvmtiError ThreadUtil::GetThreadState(jvmtiEnv* env ATTRIBUTE_UNUSED, // Need to read the Java "started" field to know whether this is starting or terminated. art::Handle<art::mirror::Object> peer(hs.NewHandle(soa.Decode<art::mirror::Object>(thread))); art::ObjPtr<art::mirror::Class> thread_klass = - soa.Decode<art::mirror::Class>(art::WellKnownClasses::java_lang_Thread); + art::WellKnownClasses::java_lang_Thread_init->GetDeclaringClass(); if (!thread_klass->IsAssignableFrom(peer->GetClass())) { return ERR(INVALID_THREAD); } @@ -815,39 +817,44 @@ jvmtiError ThreadUtil::RunAgentThread(jvmtiEnv* jvmti_env, if (priority < JVMTI_THREAD_MIN_PRIORITY || priority > JVMTI_THREAD_MAX_PRIORITY) { return ERR(INVALID_PRIORITY); } - JNIEnv* env = art::Thread::Current()->GetJniEnv(); - if (thread == nullptr || !env->IsInstanceOf(thread, art::WellKnownClasses::java_lang_Thread)) { + if (thread == nullptr) { return ERR(INVALID_THREAD); } - if (proc == nullptr) { - return ERR(NULL_POINTER); - } - + art::Runtime* runtime = art::Runtime::Current(); + art::Thread* self = art::Thread::Current(); + std::unique_ptr<AgentData> data; { - art::Runtime* runtime = art::Runtime::Current(); - art::MutexLock mu(art::Thread::Current(), *art::Locks::runtime_shutdown_lock_); - if (runtime->IsShuttingDownLocked()) { - // The runtime is shutting down so we cannot create new threads. - // TODO It's not fully clear from the spec what we should do here. We aren't yet in - // JVMTI_PHASE_DEAD so we cannot return ERR(WRONG_PHASE) but creating new threads is now - // impossible. Existing agents don't seem to generally do anything with this return value so - // it doesn't matter too much. We could do something like sending a fake ThreadStart event - // even though code is never actually run. - return ERR(INTERNAL); + art::ScopedObjectAccess soa(self); + art::ObjPtr<art::mirror::Object> othread = soa.Decode<art::mirror::Object>(thread); + if (!othread->InstanceOf(art::WellKnownClasses::java_lang_Thread_init->GetDeclaringClass())) { + return ERR(INVALID_THREAD); + } + if (proc == nullptr) { + return ERR(NULL_POINTER); } - runtime->StartThreadBirth(); - } - std::unique_ptr<AgentData> data(new AgentData); - data->arg = arg; - data->proc = proc; - // We need a global ref for Java objects, as local refs will be invalid. - data->thread = env->NewGlobalRef(thread); - data->java_vm = art::Runtime::Current()->GetJavaVM(); - data->jvmti_env = jvmti_env; - data->priority = priority; - { - art::ScopedObjectAccess soa(env); + { + art::MutexLock mu(soa.Self(), *art::Locks::runtime_shutdown_lock_); + if (runtime->IsShuttingDownLocked()) { + // The runtime is shutting down so we cannot create new threads. + // TODO It's not fully clear from the spec what we should do here. We aren't yet in + // JVMTI_PHASE_DEAD so we cannot return ERR(WRONG_PHASE) but creating new threads is now + // impossible. Existing agents don't seem to generally do anything with this return value so + // it doesn't matter too much. We could do something like sending a fake ThreadStart event + // even though code is never actually run. + return ERR(INTERNAL); + } + runtime->StartThreadBirth(); + } + + data.reset(new AgentData); + data->arg = arg; + data->proc = proc; + // We need a global ref for Java objects, as local refs will be invalid. + data->thread = runtime->GetJavaVM()->AddGlobalRef(soa.Self(), othread); + data->java_vm = runtime->GetJavaVM(); + data->jvmti_env = jvmti_env; + data->priority = priority; art::ObjPtr<art::mirror::Object> name = art::WellKnownClasses::java_lang_Thread_name->GetObject( soa.Decode<art::mirror::Object>(thread)); @@ -865,8 +872,7 @@ jvmtiError ThreadUtil::RunAgentThread(jvmtiEnv* jvmti_env, reinterpret_cast<void*>(data.get())); if (pthread_create_result != 0) { // If the create succeeded the other thread will call EndThreadBirth. - art::Runtime* runtime = art::Runtime::Current(); - art::MutexLock mu(art::Thread::Current(), *art::Locks::runtime_shutdown_lock_); + art::MutexLock mu(self, *art::Locks::runtime_shutdown_lock_); runtime->EndThreadBirth(); return ERR(INTERNAL); } diff --git a/openjdkjvmti/ti_threadgroup.cc b/openjdkjvmti/ti_threadgroup.cc index e7d91effa7..979e3d1653 100644 --- a/openjdkjvmti/ti_threadgroup.cc +++ b/openjdkjvmti/ti_threadgroup.cc @@ -95,21 +95,21 @@ jvmtiError ThreadGroupUtil::GetThreadGroupInfo(jvmtiEnv* env, } art::ScopedObjectAccess soa(art::Thread::Current()); - if (soa.Env()->IsInstanceOf(group, art::WellKnownClasses::java_lang_ThreadGroup) == JNI_FALSE) { + art::StackHandleScope<2> hs(soa.Self()); + art::Handle<art::mirror::Class> tg_class = + hs.NewHandle(art::WellKnownClasses::java_lang_ThreadGroup_add->GetDeclaringClass()); + art::Handle<art::mirror::Object> thread_group = + hs.NewHandle(soa.Decode<art::mirror::Object>(group)); + if (!thread_group->InstanceOf(tg_class.Get())) { return ERR(INVALID_THREAD_GROUP); } - art::StackHandleScope<2> hs(soa.Self()); - art::Handle<art::mirror::Class> tg_class( - hs.NewHandle(soa.Decode<art::mirror::Class>(art::WellKnownClasses::java_lang_ThreadGroup))); - art::Handle<art::mirror::Object> obj(hs.NewHandle(soa.Decode<art::mirror::Object>(group))); - // Do the name first. It's the only thing that can fail. { art::ArtField* name_field = art::WellKnownClasses::java_lang_ThreadGroup_name; CHECK(name_field != nullptr); art::ObjPtr<art::mirror::String> name_obj = - art::ObjPtr<art::mirror::String>::DownCast(name_field->GetObject(obj.Get())); + art::ObjPtr<art::mirror::String>::DownCast(name_field->GetObject(thread_group.Get())); std::string tmp_str; const char* tmp_cstr; if (name_obj == nullptr) { @@ -130,7 +130,7 @@ jvmtiError ThreadGroupUtil::GetThreadGroupInfo(jvmtiEnv* env, { art::ArtField* parent_field = art::WellKnownClasses::java_lang_ThreadGroup_parent; CHECK(parent_field != nullptr); - art::ObjPtr<art::mirror::Object> parent_group = parent_field->GetObject(obj.Get()); + art::ObjPtr<art::mirror::Object> parent_group = parent_field->GetObject(thread_group.Get()); info_ptr->parent = parent_group == nullptr ? nullptr : soa.AddLocalReference<jthreadGroup>(parent_group); @@ -140,14 +140,14 @@ jvmtiError ThreadGroupUtil::GetThreadGroupInfo(jvmtiEnv* env, { art::ArtField* prio_field = tg_class->FindDeclaredInstanceField("maxPriority", "I"); CHECK(prio_field != nullptr); - info_ptr->max_priority = static_cast<jint>(prio_field->GetInt(obj.Get())); + info_ptr->max_priority = static_cast<jint>(prio_field->GetInt(thread_group.Get())); } // Daemon. { art::ArtField* daemon_field = tg_class->FindDeclaredInstanceField("daemon", "Z"); CHECK(daemon_field != nullptr); - info_ptr->is_daemon = daemon_field->GetBoolean(obj.Get()) == 0 ? JNI_FALSE : JNI_TRUE; + info_ptr->is_daemon = daemon_field->GetBoolean(thread_group.Get()) == 0 ? JNI_FALSE : JNI_TRUE; } return ERR(NONE); @@ -221,14 +221,14 @@ jvmtiError ThreadGroupUtil::GetThreadGroupChildren(jvmtiEnv* env, } art::ScopedObjectAccess soa(art::Thread::Current()); - - if (!soa.Env()->IsInstanceOf(group, art::WellKnownClasses::java_lang_ThreadGroup)) { + art::StackHandleScope<1> hs(soa.Self()); + art::Handle<art::mirror::Object> thread_group = + hs.NewHandle(soa.Decode<art::mirror::Object>(group)); + if (!thread_group->InstanceOf( + art::WellKnownClasses::java_lang_ThreadGroup_add->GetDeclaringClass())) { return ERR(INVALID_THREAD_GROUP); } - art::StackHandleScope<1> hs(soa.Self()); - art::Handle<art::mirror::Object> thread_group = hs.NewHandle( - soa.Decode<art::mirror::Object>(group)); art::ObjectLock<art::mirror::Object> thread_group_lock(soa.Self(), thread_group); diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index d105d9e41d..c3aa5c914a 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -192,6 +192,7 @@ typename detail::ShortyTraits<ReturnType>::Type ArtMethod::InvokeInstance(Thread* self, ObjPtr<mirror::Object> receiver, typename detail::ShortyTraits<ArgType>::Type... args) { + DCHECK(!GetDeclaringClass()->IsInterface()); DCHECK(!IsStatic()); JValue result; constexpr auto shorty = detail::MaterializeShorty<ReturnType, ArgType...>(); @@ -200,6 +201,47 @@ ArtMethod::InvokeInstance(Thread* self, return detail::ShortyTraits<ReturnType>::Get(result); } +template <char ReturnType, char... ArgType> +typename detail::ShortyTraits<ReturnType>::Type +ArtMethod::InvokeFinal(Thread* self, + ObjPtr<mirror::Object> receiver, + typename detail::ShortyTraits<ArgType>::Type... args) { + DCHECK(!GetDeclaringClass()->IsInterface()); + DCHECK(!IsStatic()); + DCHECK(IsFinal()); + DCHECK(receiver != nullptr); + return InvokeInstance<ReturnType, ArgType...>(self, receiver, args...); +} + +template <char ReturnType, char... ArgType> +typename detail::ShortyTraits<ReturnType>::Type +ArtMethod::InvokeVirtual(Thread* self, + ObjPtr<mirror::Object> receiver, + typename detail::ShortyTraits<ArgType>::Type... args) { + DCHECK(!GetDeclaringClass()->IsInterface()); + DCHECK(!IsStatic()); + DCHECK(!IsFinal()); + DCHECK(receiver != nullptr); + ArtMethod* target_method = + receiver->GetClass()->FindVirtualMethodForVirtual(this, kRuntimePointerSize); + DCHECK(target_method != nullptr); + return target_method->InvokeInstance<ReturnType, ArgType...>(self, receiver, args...); +} + +template <char ReturnType, char... ArgType> +typename detail::ShortyTraits<ReturnType>::Type +ArtMethod::InvokeInterface(Thread* self, + ObjPtr<mirror::Object> receiver, + typename detail::ShortyTraits<ArgType>::Type... args) { + DCHECK(GetDeclaringClass()->IsInterface()); + DCHECK(!IsStatic()); + DCHECK(receiver != nullptr); + ArtMethod* target_method = + receiver->GetClass()->FindVirtualMethodForInterface(this, kRuntimePointerSize); + DCHECK(target_method != nullptr); + return target_method->InvokeInstance<ReturnType, ArgType...>(self, receiver, args...); +} + template <ReadBarrierOption kReadBarrierOption> inline ObjPtr<mirror::Class> ArtMethod::GetDeclaringClassUnchecked() { GcRootSource gc_root_source(this); diff --git a/runtime/art_method.h b/runtime/art_method.h index 16350e746d..1065429b17 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -677,6 +677,27 @@ class ArtMethod final { typename detail::ShortyTraits<ArgType>::Type... args) REQUIRES_SHARED(Locks::mutator_lock_); + template <char ReturnType, char... ArgType> + typename detail::ShortyTraits<ReturnType>::Type + InvokeFinal(Thread* self, + ObjPtr<mirror::Object> receiver, + typename detail::ShortyTraits<ArgType>::Type... args) + REQUIRES_SHARED(Locks::mutator_lock_); + + template <char ReturnType, char... ArgType> + typename detail::ShortyTraits<ReturnType>::Type + InvokeVirtual(Thread* self, + ObjPtr<mirror::Object> receiver, + typename detail::ShortyTraits<ArgType>::Type... args) + REQUIRES_SHARED(Locks::mutator_lock_); + + template <char ReturnType, char... ArgType> + typename detail::ShortyTraits<ReturnType>::Type + InvokeInterface(Thread* self, + ObjPtr<mirror::Object> receiver, + typename detail::ShortyTraits<ArgType>::Type... args) + REQUIRES_SHARED(Locks::mutator_lock_); + const void* GetEntryPointFromQuickCompiledCode() const { return GetEntryPointFromQuickCompiledCodePtrSize(kRuntimePointerSize); } diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index f76fe2a86b..919383f1ca 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1141,6 +1141,9 @@ void ClassLinker::RunRootClinits(Thread* self) { WellKnownClasses::java_lang_Integer_valueOf, WellKnownClasses::java_lang_Long_valueOf, WellKnownClasses::java_lang_Short_valueOf, + // Ensure `Thread` and `ThreadGroup` classes are initialized (avoid check at runtime). + WellKnownClasses::java_lang_Thread_init, + WellKnownClasses::java_lang_ThreadGroup_add, // Ensure `DirectByteBuffer` class is initialized (avoid check at runtime). WellKnownClasses::java_nio_DirectByteBuffer_init, // Ensure reflection annotation classes are initialized (avoid check at runtime). diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc index ba317c872d..315eb898cb 100644 --- a/runtime/hidden_api.cc +++ b/runtime/hidden_api.cc @@ -432,9 +432,7 @@ void MemberSignature::NotifyHiddenApiListener(AccessMethod access_method) { CHECK(signature_str != nullptr); // Call through to Consumer.accept(String memberSignature); - ArtMethod* accept_method = consumer_object->GetClass()->FindVirtualMethodForInterface( - WellKnownClasses::java_util_function_Consumer_accept, kRuntimePointerSize); - accept_method->InvokeInstance<'V', 'L'>( + WellKnownClasses::java_util_function_Consumer_accept->InvokeInterface<'V', 'L'>( soa.Self(), consumer_object.Get(), signature_str.Get()); } } diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 5678732c9b..c1cae6f124 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -1112,18 +1112,14 @@ void UnstartedRuntime::UnstartedThreadCurrentThread( // thread as unstarted to the ThreadGroup. A faked-up main thread peer is good enough for // these purposes. Runtime::Current()->InitThreadGroups(self); - jobject main_peer = - self->CreateCompileTimePeer(self->GetJniEnv(), - "main", - false, - Runtime::Current()->GetMainThreadGroup()); + ObjPtr<mirror::Object> main_peer = self->CreateCompileTimePeer( + "main", /*as_daemon=*/ false, Runtime::Current()->GetMainThreadGroup()); if (main_peer == nullptr) { AbortTransactionOrFail(self, "Failed allocating peer"); return; } - result->SetL(self->DecodeJObject(main_peer)); - self->GetJniEnv()->DeleteLocalRef(main_peer); + result->SetL(main_peer); } else { AbortTransactionOrFail(self, "Thread.currentThread() does not support %s", diff --git a/runtime/jni/jni_internal.cc b/runtime/jni/jni_internal.cc index 4d0b7aa0cb..6f1ef24ed4 100644 --- a/runtime/jni/jni_internal.cc +++ b/runtime/jni/jni_internal.cc @@ -2827,9 +2827,8 @@ class JNI { // // NB GetDirectBufferAddress() does not need to call Buffer.isDirect() since it is only // able return a valid address if the Buffer address field is not-null. - ArtMethod* is_direct_method = buffer->GetClass()->FindVirtualMethodForVirtual( - WellKnownClasses::java_nio_Buffer_isDirect, kRuntimePointerSize); - uint8_t direct = is_direct_method->InvokeInstance<'Z'>(soa.Self(), buffer.Get()); + uint8_t direct = WellKnownClasses::java_nio_Buffer_isDirect->InvokeVirtual<'Z'>( + soa.Self(), buffer.Get()); if (direct == 0u) { return -1; } diff --git a/runtime/native/jdk_internal_misc_Unsafe.cc b/runtime/native/jdk_internal_misc_Unsafe.cc index 7ab915209b..fa84f0e687 100644 --- a/runtime/native/jdk_internal_misc_Unsafe.cc +++ b/runtime/native/jdk_internal_misc_Unsafe.cc @@ -474,12 +474,14 @@ static void Unsafe_park(JNIEnv* env, jobject, jboolean isAbsolute, jlong time) { static void Unsafe_unpark(JNIEnv* env, jobject, jobject jthread) { art::ScopedFastNativeObjectAccess soa(env); - if (jthread == nullptr || !env->IsInstanceOf(jthread, WellKnownClasses::java_lang_Thread)) { + ObjPtr<mirror::Object> mirror_thread = soa.Decode<mirror::Object>(jthread); + if (mirror_thread == nullptr || + !mirror_thread->InstanceOf(WellKnownClasses::java_lang_Thread_init->GetDeclaringClass())) { ThrowIllegalArgumentException("Argument to unpark() was not a Thread"); return; } art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_); - art::Thread* thread = art::Thread::FromManagedThread(soa, jthread); + art::Thread* thread = art::Thread::FromManagedThread(soa, mirror_thread); if (thread != nullptr) { thread->Unpark(); } else { @@ -489,7 +491,7 @@ static void Unsafe_unpark(JNIEnv* env, jobject, jobject jthread) { // already terminated. ArtField* unparked = WellKnownClasses::java_lang_Thread_unparkedBeforeStart; // JNI must use non transactional mode. - unparked->SetBoolean<false>(soa.Decode<mirror::Object>(jthread), JNI_TRUE); + unparked->SetBoolean<false>(mirror_thread, JNI_TRUE); } } diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc index da28489c49..52407db292 100644 --- a/runtime/native/sun_misc_Unsafe.cc +++ b/runtime/native/sun_misc_Unsafe.cc @@ -521,12 +521,14 @@ static void Unsafe_park(JNIEnv* env, jobject, jboolean isAbsolute, jlong time) { static void Unsafe_unpark(JNIEnv* env, jobject, jobject jthread) { art::ScopedFastNativeObjectAccess soa(env); - if (jthread == nullptr || !env->IsInstanceOf(jthread, WellKnownClasses::java_lang_Thread)) { + ObjPtr<mirror::Object> mirror_thread = soa.Decode<mirror::Object>(jthread); + if (mirror_thread == nullptr || + !mirror_thread->InstanceOf(WellKnownClasses::java_lang_Thread_init->GetDeclaringClass())) { ThrowIllegalArgumentException("Argument to unpark() was not a Thread"); return; } art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_); - art::Thread* thread = art::Thread::FromManagedThread(soa, jthread); + art::Thread* thread = art::Thread::FromManagedThread(soa, mirror_thread); if (thread != nullptr) { thread->Unpark(); } else { @@ -536,7 +538,7 @@ static void Unsafe_unpark(JNIEnv* env, jobject, jobject jthread) { // already terminated. ArtField* unparked = WellKnownClasses::java_lang_Thread_unparkedBeforeStart; // JNI must use non transactional mode. - unparked->SetBoolean<false>(soa.Decode<mirror::Object>(jthread), JNI_TRUE); + unparked->SetBoolean<false>(mirror_thread, JNI_TRUE); } } diff --git a/runtime/runtime.cc b/runtime/runtime.cc index eaeda04256..51a2c977cd 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -891,7 +891,7 @@ static jobject CreateSystemClassLoader(Runtime* runtime) { soa.Self()->SetClassLoaderOverride(g_system_class_loader); ObjPtr<mirror::Class> thread_class = - WellKnownClasses::ToClass(WellKnownClasses::java_lang_Thread); + WellKnownClasses::java_lang_Thread_init->GetDeclaringClass(); ArtField* contextClassLoader = thread_class->FindDeclaredInstanceField("contextClassLoader", "Ljava/lang/ClassLoader;"); CHECK(contextClassLoader != nullptr); @@ -2226,12 +2226,26 @@ void Runtime::InitThreadGroups(Thread* self) { ScopedObjectAccess soa(self); ArtField* main_thread_group_field = WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup; ArtField* system_thread_group_field = WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup; - ObjPtr<mirror::Class> thread_group_class = main_thread_group_field->GetDeclaringClass(); + // Note: This is running before `ClassLinker::RunRootClinits()`, so we cannot rely on + // `ThreadGroup` and `Thread` being initialized. + // TODO: Clean up initialization order after all well-known methods are converted to `ArtMethod*` + // (and therefore the `WellKnownClasses::Init()` shall not initialize any classes). + StackHandleScope<2u> hs(self); + Handle<mirror::Class> thread_group_class = + hs.NewHandle(main_thread_group_field->GetDeclaringClass()); + bool initialized = GetClassLinker()->EnsureInitialized( + self, thread_group_class, /*can_init_fields=*/ true, /*can_init_parents=*/ true); + CHECK(initialized); + Handle<mirror::Class> thread_class = + hs.NewHandle(WellKnownClasses::java_lang_Thread_init->GetDeclaringClass()); + initialized = GetClassLinker()->EnsureInitialized( + self, thread_class, /*can_init_fields=*/ true, /*can_init_parents=*/ true); + CHECK(initialized); main_thread_group_ = - soa.Vm()->AddGlobalRef(self, main_thread_group_field->GetObject(thread_group_class)); + soa.Vm()->AddGlobalRef(self, main_thread_group_field->GetObject(thread_group_class.Get())); CHECK_IMPLIES(main_thread_group_ == nullptr, IsAotCompiler()); system_thread_group_ = - soa.Vm()->AddGlobalRef(self, system_thread_group_field->GetObject(thread_group_class)); + soa.Vm()->AddGlobalRef(self, system_thread_group_field->GetObject(thread_group_class.Get())); CHECK_IMPLIES(system_thread_group_ == nullptr, IsAotCompiler()); } diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc index 302d57e74b..c38bd6156e 100644 --- a/runtime/runtime_callbacks_test.cc +++ b/runtime/runtime_callbacks_test.cc @@ -35,7 +35,7 @@ #include "dex/class_reference.h" #include "handle.h" #include "handle_scope-inl.h" -#include "mirror/class-inl.h" +#include "mirror/class-alloc-inl.h" #include "mirror/class_loader.h" #include "monitor-inl.h" #include "nativehelper/scoped_local_ref.h" @@ -164,40 +164,40 @@ TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackJava) cb_.state = CallbackState::kBase; // Ignore main thread attach. - { - ScopedObjectAccess soa(self); - MakeExecutable(WellKnownClasses::ToClass(WellKnownClasses::java_lang_Thread)); - } - - JNIEnv* env = self->GetJniEnv(); + ScopedObjectAccess soa(self); + MakeExecutable(WellKnownClasses::java_lang_Thread_init->GetDeclaringClass()); - ScopedLocalRef<jobject> thread_name(env, - env->NewStringUTF("ThreadLifecycleCallback test thread")); - ASSERT_TRUE(thread_name.get() != nullptr); + StackHandleScope<2u> hs(self); + Handle<mirror::String> thread_name = hs.NewHandle( + mirror::String::AllocFromModifiedUtf8(self, "ThreadLifecycleCallback test thread")); + ASSERT_TRUE(thread_name != nullptr); - ScopedLocalRef<jobject> thread(env, env->AllocObject(WellKnownClasses::java_lang_Thread)); - ASSERT_TRUE(thread.get() != nullptr); + DCHECK(WellKnownClasses::java_lang_Thread_init->GetDeclaringClass()->IsInitialized()); + Handle<mirror::Object> thread = hs.NewHandle( + WellKnownClasses::java_lang_Thread_init->GetDeclaringClass()->AllocObject(self)); + ASSERT_TRUE(thread != nullptr); - env->CallNonvirtualVoidMethod(thread.get(), - WellKnownClasses::java_lang_Thread, - WellKnownClasses::java_lang_Thread_init, - runtime_->GetMainThreadGroup(), - thread_name.get(), - kMinThreadPriority, - JNI_FALSE); - ASSERT_FALSE(env->ExceptionCheck()); + WellKnownClasses::java_lang_Thread_init->InvokeInstance<'V', 'L', 'L', 'I', 'Z'>( + self, + thread.Get(), + soa.Decode<mirror::Object>(runtime_->GetMainThreadGroup()), + thread_name.Get(), + kMinThreadPriority, + /*daemon=*/ 0u); + ASSERT_FALSE(self->IsExceptionPending()); - jmethodID start_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "start", "()V"); - ASSERT_TRUE(start_id != nullptr); + ArtMethod* start_method = + thread->GetClass()->FindClassMethod("start", "()V", kRuntimePointerSize); + ASSERT_TRUE(start_method != nullptr); - env->CallVoidMethod(thread.get(), start_id); - ASSERT_FALSE(env->ExceptionCheck()); + start_method->InvokeVirtual<'V'>(self, thread.Get()); + ASSERT_FALSE(self->IsExceptionPending()); - jmethodID join_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "join", "()V"); - ASSERT_TRUE(join_id != nullptr); + ArtMethod* join_method = thread->GetClass()->FindClassMethod("join", "()V", kRuntimePointerSize); + ASSERT_TRUE(join_method != nullptr); - env->CallVoidMethod(thread.get(), join_id); - ASSERT_FALSE(env->ExceptionCheck()); + join_method->InvokeFinal<'V'>(self, thread.Get()); + ASSERT_FALSE(self->IsExceptionPending()); EXPECT_EQ(cb_.state, CallbackState::kDied); } diff --git a/runtime/thread.cc b/runtime/thread.cc index 80f1ff5331..19c2ce8d17 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -667,9 +667,7 @@ void* Thread::CreateCallback(void* arg) { } // Invoke the 'run' method of our java.lang.Thread. ObjPtr<mirror::Object> receiver = self->tlsPtr_.opeer; - jmethodID mid = WellKnownClasses::java_lang_Thread_run; - ScopedLocalRef<jobject> ref(soa.Env(), soa.AddLocalReference<jobject>(receiver)); - InvokeVirtualOrInterfaceWithJValues(soa, ref.get(), mid, nullptr); + WellKnownClasses::java_lang_Thread_run->InvokeVirtual<'V'>(self, receiver); } // Detach and delete self. Runtime::Current()->GetThreadList()->Unregister(self, /* should_run_callbacks= */ true); @@ -1125,43 +1123,40 @@ Thread* Thread::Attach(const char* thread_name, bool as_daemon, jobject thread_p void Thread::CreatePeer(const char* name, bool as_daemon, jobject thread_group) { Runtime* runtime = Runtime::Current(); CHECK(runtime->IsStarted()); - JNIEnv* env = tlsPtr_.jni_env; + Thread* self = this; + DCHECK_EQ(self, Thread::Current()); - if (thread_group == nullptr) { - thread_group = runtime->GetMainThreadGroup(); - } - ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF(name)); + ScopedObjectAccess soa(self); + StackHandleScope<4u> hs(self); + DCHECK(WellKnownClasses::java_lang_ThreadGroup_add->GetDeclaringClass()->IsInitialized()); + Handle<mirror::Object> thr_group = hs.NewHandle(soa.Decode<mirror::Object>( + thread_group != nullptr ? thread_group : runtime->GetMainThreadGroup())); + Handle<mirror::String> thread_name = hs.NewHandle( + name != nullptr ? mirror::String::AllocFromModifiedUtf8(self, name) : nullptr); // Add missing null check in case of OOM b/18297817 - if (name != nullptr && thread_name.get() == nullptr) { - CHECK(IsExceptionPending()); + if (name != nullptr && UNLIKELY(thread_name == nullptr)) { + CHECK(self->IsExceptionPending()); return; } jint thread_priority = GetNativePriority(); jboolean thread_is_daemon = as_daemon; - ScopedLocalRef<jobject> peer(env, env->AllocObject(WellKnownClasses::java_lang_Thread)); - if (peer.get() == nullptr) { + DCHECK(WellKnownClasses::java_lang_Thread_init->GetDeclaringClass()->IsInitialized()); + Handle<mirror::Object> peer = hs.NewHandle( + WellKnownClasses::java_lang_Thread_init->GetDeclaringClass()->AllocObject(self)); + if (UNLIKELY(peer == nullptr)) { CHECK(IsExceptionPending()); return; } - { - ScopedObjectAccess soa(this); - tlsPtr_.opeer = soa.Decode<mirror::Object>(peer.get()).Ptr(); - } - env->CallNonvirtualVoidMethod(peer.get(), - WellKnownClasses::java_lang_Thread, - WellKnownClasses::java_lang_Thread_init, - thread_group, thread_name.get(), thread_priority, thread_is_daemon); - if (IsExceptionPending()) { + tlsPtr_.opeer = peer.Get(); + WellKnownClasses::java_lang_Thread_init->InvokeInstance<'V', 'L', 'L', 'I', 'Z'>( + self, peer.Get(), thr_group.Get(), thread_name.Get(), thread_priority, thread_is_daemon); + if (self->IsExceptionPending()) { return; } - Thread* self = this; - DCHECK_EQ(self, Thread::Current()); - ScopedObjectAccess soa(self); - SetNativePeer</*kSupportTransaction=*/ false>(soa.Decode<mirror::Object>(peer.get()), self); + SetNativePeer</*kSupportTransaction=*/ false>(peer.Get(), self); - StackHandleScope<1> hs(self); MutableHandle<mirror::String> peer_thread_name(hs.NewHandle(GetThreadName())); if (peer_thread_name == nullptr) { // The Thread constructor should have set the Thread.name to a @@ -1169,18 +1164,16 @@ void Thread::CreatePeer(const char* name, bool as_daemon, jobject thread_group) // available (in the compiler, in tests), we manually assign the // fields the constructor should have set. if (runtime->IsActiveTransaction()) { - InitPeer<true>(soa, - tlsPtr_.opeer, + InitPeer<true>(tlsPtr_.opeer, thread_is_daemon, - thread_group, - thread_name.get(), + thr_group.Get(), + thread_name.Get(), thread_priority); } else { - InitPeer<false>(soa, - tlsPtr_.opeer, + InitPeer<false>(tlsPtr_.opeer, thread_is_daemon, - thread_group, - thread_name.get(), + thr_group.Get(), + thread_name.Get(), thread_priority); } peer_thread_name.Assign(GetThreadName()); @@ -1191,27 +1184,33 @@ void Thread::CreatePeer(const char* name, bool as_daemon, jobject thread_group) } } -jobject Thread::CreateCompileTimePeer(JNIEnv* env, - const char* name, - bool as_daemon, - jobject thread_group) { +ObjPtr<mirror::Object> Thread::CreateCompileTimePeer(const char* name, + bool as_daemon, + jobject thread_group) { Runtime* runtime = Runtime::Current(); CHECK(!runtime->IsStarted()); + Thread* self = this; + DCHECK_EQ(self, Thread::Current()); - if (thread_group == nullptr) { - thread_group = runtime->GetMainThreadGroup(); - } - ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF(name)); + ScopedObjectAccessUnchecked soa(self); + StackHandleScope<3u> hs(self); + DCHECK(WellKnownClasses::java_lang_ThreadGroup_add->GetDeclaringClass()->IsInitialized()); + Handle<mirror::Object> thr_group = hs.NewHandle(soa.Decode<mirror::Object>( + thread_group != nullptr ? thread_group : runtime->GetMainThreadGroup())); + Handle<mirror::String> thread_name = hs.NewHandle( + name != nullptr ? mirror::String::AllocFromModifiedUtf8(self, name) : nullptr); // Add missing null check in case of OOM b/18297817 - if (name != nullptr && thread_name.get() == nullptr) { - CHECK(Thread::Current()->IsExceptionPending()); + if (name != nullptr && UNLIKELY(thread_name == nullptr)) { + CHECK(self->IsExceptionPending()); return nullptr; } jint thread_priority = kNormThreadPriority; // Always normalize to NORM priority. jboolean thread_is_daemon = as_daemon; - ScopedLocalRef<jobject> peer(env, env->AllocObject(WellKnownClasses::java_lang_Thread)); - if (peer.get() == nullptr) { + DCHECK(WellKnownClasses::java_lang_Thread_init->GetDeclaringClass()->IsInitialized()); + Handle<mirror::Object> peer = hs.NewHandle( + WellKnownClasses::java_lang_Thread_init->GetDeclaringClass()->AllocObject(self)); + if (peer == nullptr) { CHECK(Thread::Current()->IsExceptionPending()); return nullptr; } @@ -1222,39 +1221,32 @@ jobject Thread::CreateCompileTimePeer(JNIEnv* env, // non-null value. However, because we can run without code // available (in the compiler, in tests), we manually assign the // fields the constructor should have set. - ScopedObjectAccessUnchecked soa(Thread::Current()); if (runtime->IsActiveTransaction()) { - InitPeer<true>(soa, - soa.Decode<mirror::Object>(peer.get()), + InitPeer<true>(peer.Get(), thread_is_daemon, - thread_group, - thread_name.get(), + thr_group.Get(), + thread_name.Get(), thread_priority); } else { - InitPeer<false>(soa, - soa.Decode<mirror::Object>(peer.get()), + InitPeer<false>(peer.Get(), thread_is_daemon, - thread_group, - thread_name.get(), + thr_group.Get(), + thread_name.Get(), thread_priority); } - return peer.release(); + return peer.Get(); } template<bool kTransactionActive> -void Thread::InitPeer(ScopedObjectAccessAlreadyRunnable& soa, - ObjPtr<mirror::Object> peer, +void Thread::InitPeer(ObjPtr<mirror::Object> peer, jboolean thread_is_daemon, - jobject thread_group, - jobject thread_name, + ObjPtr<mirror::Object> thread_group, + ObjPtr<mirror::String> thread_name, jint thread_priority) { - WellKnownClasses::java_lang_Thread_daemon-> - SetBoolean<kTransactionActive>(peer, thread_is_daemon); - WellKnownClasses::java_lang_Thread_group-> - SetObject<kTransactionActive>(peer, soa.Decode<mirror::Object>(thread_group)); - WellKnownClasses::java_lang_Thread_name-> - SetObject<kTransactionActive>(peer, soa.Decode<mirror::Object>(thread_name)); + WellKnownClasses::java_lang_Thread_daemon->SetBoolean<kTransactionActive>(peer, thread_is_daemon); + WellKnownClasses::java_lang_Thread_group->SetObject<kTransactionActive>(peer, thread_group); + WellKnownClasses::java_lang_Thread_name->SetObject<kTransactionActive>(peer, thread_name); WellKnownClasses::java_lang_Thread_priority->SetInt<kTransactionActive>(peer, thread_priority); } @@ -2434,25 +2426,19 @@ void Thread::Shutdown() { } void Thread::NotifyThreadGroup(ScopedObjectAccessAlreadyRunnable& soa, jobject thread_group) { - ScopedLocalRef<jobject> thread_jobject( - soa.Env(), soa.Env()->AddLocalReference<jobject>(Thread::Current()->GetPeer())); - ScopedLocalRef<jobject> thread_group_jobject_scoped( - soa.Env(), nullptr); - jobject thread_group_jobject = thread_group; + ObjPtr<mirror::Object> thread_object = soa.Self()->GetPeer(); + ObjPtr<mirror::Object> thread_group_object = soa.Decode<mirror::Object>(thread_group); if (thread_group == nullptr || kIsDebugBuild) { // There is always a group set. Retrieve it. - thread_group_jobject_scoped.reset(soa.AddLocalReference<jobject>( - WellKnownClasses::java_lang_Thread_group->GetObject( - soa.Decode<mirror::Object>(thread_jobject.get())))); - thread_group_jobject = thread_group_jobject_scoped.get(); + thread_group_object = WellKnownClasses::java_lang_Thread_group->GetObject(thread_object); if (kIsDebugBuild && thread_group != nullptr) { - CHECK(soa.Env()->IsSameObject(thread_group, thread_group_jobject)); + CHECK(thread_group_object == soa.Decode<mirror::Object>(thread_group)); } } - soa.Env()->CallNonvirtualVoidMethod(thread_group_jobject, - WellKnownClasses::java_lang_ThreadGroup, - WellKnownClasses::java_lang_ThreadGroup_add, - thread_jobject.get()); + // TODO: Why are we calling the non-final method `ThreadGroup.add(Thread)` directly + // instead of using the virtual dispatch? (Preserved from old code.) + WellKnownClasses::java_lang_ThreadGroup_add->InvokeInstance<'V', 'L'>( + soa.Self(), thread_group_object, thread_object); } Thread::Thread(bool daemon) @@ -2577,8 +2563,8 @@ void Thread::Destroy(bool should_run_callbacks) { if (tlsPtr_.opeer != nullptr) { ScopedObjectAccess soa(self); // We may need to call user-supplied managed code, do this before final clean-up. - HandleUncaughtExceptions(soa); - RemoveFromThreadGroup(soa); + HandleUncaughtExceptions(); + RemoveFromThreadGroup(); Runtime* runtime = Runtime::Current(); if (runtime != nullptr && should_run_callbacks) { runtime->GetRuntimeCallbacks()->ThreadDeath(self); @@ -2657,38 +2643,35 @@ Thread::~Thread() { TearDownAlternateSignalStack(); } -void Thread::HandleUncaughtExceptions(ScopedObjectAccessAlreadyRunnable& soa) { - if (!IsExceptionPending()) { +void Thread::HandleUncaughtExceptions() { + Thread* self = this; + DCHECK_EQ(self, Thread::Current()); + if (!self->IsExceptionPending()) { return; } - ScopedLocalRef<jobject> peer(tlsPtr_.jni_env, soa.AddLocalReference<jobject>(tlsPtr_.opeer)); - ScopedThreadStateChange tsc(this, ThreadState::kNative); // Get and clear the exception. - ScopedLocalRef<jthrowable> exception(tlsPtr_.jni_env, tlsPtr_.jni_env->ExceptionOccurred()); - tlsPtr_.jni_env->ExceptionClear(); + ObjPtr<mirror::Object> exception = self->GetException(); + self->ClearException(); // Call the Thread instance's dispatchUncaughtException(Throwable) - tlsPtr_.jni_env->CallVoidMethod(peer.get(), - WellKnownClasses::java_lang_Thread_dispatchUncaughtException, - exception.get()); + WellKnownClasses::java_lang_Thread_dispatchUncaughtException->InvokeFinal<'V', 'L'>( + self, tlsPtr_.opeer, exception); // If the dispatchUncaughtException threw, clear that exception too. - tlsPtr_.jni_env->ExceptionClear(); + self->ClearException(); } -void Thread::RemoveFromThreadGroup(ScopedObjectAccessAlreadyRunnable& soa) { - // this.group.removeThread(this); +void Thread::RemoveFromThreadGroup() { + Thread* self = this; + DCHECK_EQ(self, Thread::Current()); + // this.group.threadTerminated(this); // group can be null if we're in the compiler or a test. - ObjPtr<mirror::Object> ogroup = + ObjPtr<mirror::Object> group = WellKnownClasses::java_lang_Thread_group->GetObject(tlsPtr_.opeer); - if (ogroup != nullptr) { - ScopedLocalRef<jobject> group(soa.Env(), soa.AddLocalReference<jobject>(ogroup)); - ScopedLocalRef<jobject> peer(soa.Env(), soa.AddLocalReference<jobject>(tlsPtr_.opeer)); - ScopedThreadStateChange tsc(soa.Self(), ThreadState::kNative); - tlsPtr_.jni_env->CallVoidMethod(group.get(), - WellKnownClasses::java_lang_ThreadGroup_removeThread, - peer.get()); + if (group != nullptr) { + WellKnownClasses::java_lang_ThreadGroup_threadTerminated->InvokeVirtual<'V', 'L'>( + self, group, tlsPtr_.opeer); } } diff --git a/runtime/thread.h b/runtime/thread.h index 2a6e148fa0..0b108ad771 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -1403,10 +1403,9 @@ class Thread { // Set to the read barrier marking entrypoints to be non-null. void SetReadBarrierEntrypoints(); - static jobject CreateCompileTimePeer(JNIEnv* env, - const char* name, - bool as_daemon, - jobject thread_group) + ObjPtr<mirror::Object> CreateCompileTimePeer(const char* name, + bool as_daemon, + jobject thread_group) REQUIRES_SHARED(Locks::mutator_lock_); ALWAYS_INLINE InterpreterCache* GetInterpreterCache() { @@ -1486,11 +1485,10 @@ class Thread { void CreatePeer(const char* name, bool as_daemon, jobject thread_group); template<bool kTransactionActive> - static void InitPeer(ScopedObjectAccessAlreadyRunnable& soa, - ObjPtr<mirror::Object> peer, + static void InitPeer(ObjPtr<mirror::Object> peer, jboolean thread_is_daemon, - jobject thread_group, - jobject thread_name, + ObjPtr<mirror::Object> thread_group, + ObjPtr<mirror::String> thread_name, jint thread_priority) REQUIRES_SHARED(Locks::mutator_lock_); @@ -1556,10 +1554,8 @@ class Thread { static NO_INLINE void* CreateCallbackWithUffdGc(void* arg); static void* CreateCallback(void* arg); - void HandleUncaughtExceptions(ScopedObjectAccessAlreadyRunnable& soa) - REQUIRES_SHARED(Locks::mutator_lock_); - void RemoveFromThreadGroup(ScopedObjectAccessAlreadyRunnable& soa) - REQUIRES_SHARED(Locks::mutator_lock_); + void HandleUncaughtExceptions() REQUIRES_SHARED(Locks::mutator_lock_); + void RemoveFromThreadGroup() REQUIRES_SHARED(Locks::mutator_lock_); // Initialize a thread. // diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index f7d4c8ab2c..9f1b8e70c8 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -76,8 +76,6 @@ jclass WellKnownClasses::java_lang_StackOverflowError; jclass WellKnownClasses::java_lang_String; jclass WellKnownClasses::java_lang_StringFactory; jclass WellKnownClasses::java_lang_System; -jclass WellKnownClasses::java_lang_Thread; -jclass WellKnownClasses::java_lang_ThreadGroup; jclass WellKnownClasses::java_lang_Throwable; jclass WellKnownClasses::java_lang_Void; jclass WellKnownClasses::libcore_reflect_AnnotationMember__array; @@ -111,11 +109,11 @@ jmethodID WellKnownClasses::java_lang_reflect_Proxy_invoke; jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad; ArtMethod* WellKnownClasses::java_lang_Short_valueOf; jmethodID WellKnownClasses::java_lang_String_charAt; -jmethodID WellKnownClasses::java_lang_Thread_dispatchUncaughtException; -jmethodID WellKnownClasses::java_lang_Thread_init; -jmethodID WellKnownClasses::java_lang_Thread_run; -jmethodID WellKnownClasses::java_lang_ThreadGroup_add; -jmethodID WellKnownClasses::java_lang_ThreadGroup_removeThread; +ArtMethod* WellKnownClasses::java_lang_Thread_dispatchUncaughtException; +ArtMethod* WellKnownClasses::java_lang_Thread_init; +ArtMethod* WellKnownClasses::java_lang_Thread_run; +ArtMethod* WellKnownClasses::java_lang_ThreadGroup_add; +ArtMethod* WellKnownClasses::java_lang_ThreadGroup_threadTerminated; ArtMethod* WellKnownClasses::java_nio_Buffer_isDirect; ArtMethod* WellKnownClasses::java_nio_DirectByteBuffer_init; ArtMethod* WellKnownClasses::java_util_function_Consumer_accept; @@ -392,8 +390,6 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_String = CacheClass(env, "java/lang/String"); java_lang_StringFactory = CacheClass(env, "java/lang/StringFactory"); java_lang_System = CacheClass(env, "java/lang/System"); - java_lang_Thread = CacheClass(env, "java/lang/Thread"); - java_lang_ThreadGroup = CacheClass(env, "java/lang/ThreadGroup"); java_lang_Throwable = CacheClass(env, "java/lang/Throwable"); java_lang_Void = CacheClass(env, "java/lang/Void"); libcore_reflect_AnnotationMember__array = CacheClass(env, "[Llibcore/reflect/AnnotationMember;"); @@ -445,17 +441,16 @@ void WellKnownClasses::InitFieldsAndMethodsOnly(JNIEnv* env) { java_lang_reflect_InvocationTargetException_init = CacheMethod(env, java_lang_reflect_InvocationTargetException, false, "<init>", "(Ljava/lang/Throwable;)V"); java_lang_reflect_Parameter_init = CacheMethod(env, java_lang_reflect_Parameter, false, "<init>", "(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V"); java_lang_String_charAt = CacheMethod(env, java_lang_String, false, "charAt", "(I)C"); - java_lang_Thread_dispatchUncaughtException = CacheMethod(env, java_lang_Thread, false, "dispatchUncaughtException", "(Ljava/lang/Throwable;)V"); - java_lang_Thread_init = CacheMethod(env, java_lang_Thread, false, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V"); - java_lang_Thread_run = CacheMethod(env, java_lang_Thread, false, "run", "()V"); - java_lang_ThreadGroup_add = CacheMethod(env, java_lang_ThreadGroup, false, "add", "(Ljava/lang/Thread;)V"); - java_lang_ThreadGroup_removeThread = CacheMethod(env, java_lang_ThreadGroup, false, "threadTerminated", "(Ljava/lang/Thread;)V"); - StackHandleScope<12u> hs(self); + StackHandleScope<14u> hs(self); Handle<mirror::Class> d_s_vmr = hs.NewHandle(FindSystemClass(class_linker, self, "Ldalvik/system/VMRuntime;")); Handle<mirror::Class> j_i_fd = hs.NewHandle(FindSystemClass(class_linker, self, "Ljava/io/FileDescriptor;")); + Handle<mirror::Class> j_l_Thread = + hs.NewHandle(FindSystemClass(class_linker, self, "Ljava/lang/Thread;")); + Handle<mirror::Class> j_l_tg = + hs.NewHandle(FindSystemClass(class_linker, self, "Ljava/lang/ThreadGroup;")); Handle<mirror::Class> j_n_b = hs.NewHandle(FindSystemClass(class_linker, self, "Ljava/nio/Buffer;")); Handle<mirror::Class> j_n_bb = @@ -494,6 +489,29 @@ void WellKnownClasses::InitFieldsAndMethodsOnly(JNIEnv* env) { java_lang_Float_floatToRawIntBits = CacheMethod(j_l_Float, /*is_static=*/ true, "floatToRawIntBits", "(F)I", pointer_size); + java_lang_Thread_dispatchUncaughtException = CacheMethod( + j_l_Thread.Get(), + /*is_static=*/ false, + "dispatchUncaughtException", + "(Ljava/lang/Throwable;)V", + pointer_size); + java_lang_Thread_init = CacheMethod( + j_l_Thread.Get(), + /*is_static=*/ false, + "<init>", + "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V", + pointer_size); + java_lang_Thread_run = CacheMethod( + j_l_Thread.Get(), /*is_static=*/ false, "run", "()V", pointer_size); + java_lang_ThreadGroup_add = CacheMethod( + j_l_tg.Get(), /*is_static=*/ false, "add", "(Ljava/lang/Thread;)V", pointer_size); + java_lang_ThreadGroup_threadTerminated = CacheMethod( + j_l_tg.Get(), + /*is_static=*/ false, + "threadTerminated", + "(Ljava/lang/Thread;)V", + pointer_size); + java_nio_Buffer_isDirect = CacheMethod(j_n_b.Get(), /*is_static=*/ false, "isDirect", "()Z", pointer_size); java_nio_DirectByteBuffer_init = @@ -556,35 +574,34 @@ void WellKnownClasses::InitFieldsAndMethodsOnly(JNIEnv* env) { java_lang_ClassLoader_parent = CacheField( j_l_cl, /*is_static=*/ false, "parent", "Ljava/lang/ClassLoader;"); - ObjPtr<mirror::Class> j_l_Thread = soa.Decode<mirror::Class>(java_lang_Thread); java_lang_Thread_parkBlocker = - CacheField(j_l_Thread, /*is_static=*/ false, "parkBlocker", "Ljava/lang/Object;"); - java_lang_Thread_daemon = CacheField(j_l_Thread, /*is_static=*/ false, "daemon", "Z"); + CacheField(j_l_Thread.Get(), /*is_static=*/ false, "parkBlocker", "Ljava/lang/Object;"); + java_lang_Thread_daemon = CacheField(j_l_Thread.Get(), /*is_static=*/ false, "daemon", "Z"); java_lang_Thread_group = - CacheField(j_l_Thread, /*is_static=*/ false, "group", "Ljava/lang/ThreadGroup;"); + CacheField(j_l_Thread.Get(), /*is_static=*/ false, "group", "Ljava/lang/ThreadGroup;"); java_lang_Thread_lock = - CacheField(j_l_Thread, /*is_static=*/ false, "lock", "Ljava/lang/Object;"); + CacheField(j_l_Thread.Get(), /*is_static=*/ false, "lock", "Ljava/lang/Object;"); java_lang_Thread_name = - CacheField(j_l_Thread, /*is_static=*/ false, "name", "Ljava/lang/String;"); - java_lang_Thread_priority = CacheField(j_l_Thread, /*is_static=*/ false, "priority", "I"); - java_lang_Thread_nativePeer = CacheField(j_l_Thread, /*is_static=*/ false, "nativePeer", "J"); + CacheField(j_l_Thread.Get(), /*is_static=*/ false, "name", "Ljava/lang/String;"); + java_lang_Thread_priority = CacheField(j_l_Thread.Get(), /*is_static=*/ false, "priority", "I"); + java_lang_Thread_nativePeer = + CacheField(j_l_Thread.Get(), /*is_static=*/ false, "nativePeer", "J"); java_lang_Thread_systemDaemon = - CacheField(j_l_Thread, /*is_static=*/ false, "systemDaemon", "Z"); + CacheField(j_l_Thread.Get(), /*is_static=*/ false, "systemDaemon", "Z"); java_lang_Thread_unparkedBeforeStart = - CacheField(j_l_Thread, /*is_static=*/ false, "unparkedBeforeStart", "Z"); + CacheField(j_l_Thread.Get(), /*is_static=*/ false, "unparkedBeforeStart", "Z"); - ObjPtr<mirror::Class> j_l_tg = soa.Decode<mirror::Class>(java_lang_ThreadGroup); java_lang_ThreadGroup_groups = - CacheField(j_l_tg, /*is_static=*/ false, "groups", "[Ljava/lang/ThreadGroup;"); - java_lang_ThreadGroup_ngroups = CacheField(j_l_tg, /*is_static=*/ false, "ngroups", "I"); + CacheField(j_l_tg.Get(), /*is_static=*/ false, "groups", "[Ljava/lang/ThreadGroup;"); + java_lang_ThreadGroup_ngroups = CacheField(j_l_tg.Get(), /*is_static=*/ false, "ngroups", "I"); java_lang_ThreadGroup_mainThreadGroup = - CacheField(j_l_tg, /*is_static=*/ true, "mainThreadGroup", "Ljava/lang/ThreadGroup;"); + CacheField(j_l_tg.Get(), /*is_static=*/ true, "mainThreadGroup", "Ljava/lang/ThreadGroup;"); java_lang_ThreadGroup_name = - CacheField(j_l_tg, /*is_static=*/ false, "name", "Ljava/lang/String;"); + CacheField(j_l_tg.Get(), /*is_static=*/ false, "name", "Ljava/lang/String;"); java_lang_ThreadGroup_parent = - CacheField(j_l_tg, /*is_static=*/ false, "parent", "Ljava/lang/ThreadGroup;"); + CacheField(j_l_tg.Get(), /*is_static=*/ false, "parent", "Ljava/lang/ThreadGroup;"); java_lang_ThreadGroup_systemThreadGroup = - CacheField(j_l_tg, /*is_static=*/ true, "systemThreadGroup", "Ljava/lang/ThreadGroup;"); + CacheField(j_l_tg.Get(), /*is_static=*/ true, "systemThreadGroup", "Ljava/lang/ThreadGroup;"); ObjPtr<mirror::Class> j_l_Throwable = soa.Decode<mirror::Class>(java_lang_Throwable); java_lang_Throwable_cause = CacheField( @@ -686,8 +703,6 @@ void WellKnownClasses::Clear() { java_lang_String = nullptr; java_lang_StringFactory = nullptr; java_lang_System = nullptr; - java_lang_Thread = nullptr; - java_lang_ThreadGroup = nullptr; java_lang_Throwable = nullptr; java_lang_Void = nullptr; libcore_reflect_AnnotationMember__array = nullptr; @@ -725,7 +740,7 @@ void WellKnownClasses::Clear() { java_lang_Thread_init = nullptr; java_lang_Thread_run = nullptr; java_lang_ThreadGroup_add = nullptr; - java_lang_ThreadGroup_removeThread = nullptr; + java_lang_ThreadGroup_threadTerminated = nullptr; java_nio_Buffer_isDirect = nullptr; java_nio_DirectByteBuffer_init = nullptr; libcore_reflect_AnnotationFactory_createAnnotation = nullptr; diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index 14962a85c7..0a58766708 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -87,8 +87,6 @@ struct WellKnownClasses { static jclass java_lang_String; static jclass java_lang_StringFactory; static jclass java_lang_System; - static jclass java_lang_Thread; - static jclass java_lang_ThreadGroup; static jclass java_lang_Throwable; static jclass java_lang_Void; static jclass libcore_reflect_AnnotationMember__array; @@ -122,11 +120,11 @@ struct WellKnownClasses { static jmethodID java_lang_Runtime_nativeLoad; static ArtMethod* java_lang_Short_valueOf; static jmethodID java_lang_String_charAt; - static jmethodID java_lang_Thread_dispatchUncaughtException; - static jmethodID java_lang_Thread_init; - static jmethodID java_lang_Thread_run; - static jmethodID java_lang_ThreadGroup_add; - static jmethodID java_lang_ThreadGroup_removeThread; + static ArtMethod* java_lang_Thread_dispatchUncaughtException; + static ArtMethod* java_lang_Thread_init; + static ArtMethod* java_lang_Thread_run; + static ArtMethod* java_lang_ThreadGroup_add; + static ArtMethod* java_lang_ThreadGroup_threadTerminated; static ArtMethod* java_nio_Buffer_isDirect; static ArtMethod* java_nio_DirectByteBuffer_init; static ArtMethod* java_util_function_Consumer_accept; diff --git a/test/913-heaps/expected-stdout.txt b/test/913-heaps/expected-stdout.txt index 5f882b1e24..e7a372aa10 100644 --- a/test/913-heaps/expected-stdout.txt +++ b/test/913-heaps/expected-stdout.txt @@ -1,6 +1,5 @@ --- true true -root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=120, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=120, length=-1] root@root --(thread)--> 3000@0 [size=120, length=-1] @@ -44,7 +43,6 @@ root@root --(thread)--> 3000@0 [size=120, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] -root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=120, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] @@ -97,7 +95,6 @@ root@root --(thread)--> 3000@0 [size=120, length=-1] --- 3@1001 --(class)--> 1001@0 [size=123456780016, length=-1] --- -root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=120, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=120, length=-1] root@root --(thread)--> 3000@0 [size=120, length=-1] @@ -109,7 +106,6 @@ root@root --(thread)--> 3000@0 [size=120, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] -root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=120, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] @@ -195,7 +191,6 @@ root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot --- --- ---- untagged objects -root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=120, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=120, length=-1] root@root --(thread)--> 3000@0 [size=120, length=-1] @@ -239,7 +234,6 @@ root@root --(thread)--> 3000@0 [size=120, length=-1] --- root@root --(jni-global)--> 1@1000 [size=16, length=-1] root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1] -root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=120, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1] @@ -285,7 +279,6 @@ root@root --(thread)--> 3000@0 [size=120, length=-1] 6@1000 --(class)--> 1000@0 [size=123456780055, length=-1] --- ---- tagged classes -root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=120, length=-1] root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=120, length=-1] root@root --(thread)--> 3000@0 [size=120, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123456780060, length=-1] @@ -312,7 +305,6 @@ root@root --(thread)--> 3000@0 [size=120, length=-1] 5@1002 --(field@8)--> 500@0 [size=20, length=2] 6@1000 --(class)--> 1000@0 [size=123456780060, length=-1] --- -root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=120, length=-1] root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=120, length=-1] root@root --(thread)--> 3000@0 [size=120, length=-1] 1001@0 --(superclass)--> 1000@0 [size=123456780065, length=-1] |