diff options
-rw-r--r-- | runtime/class_linker.cc | 2 | ||||
-rw-r--r-- | runtime/class_linker.h | 7 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils.cc | 2 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils.h | 2 | ||||
-rw-r--r-- | runtime/mirror/art_field.cc | 3 | ||||
-rw-r--r-- | runtime/mirror/art_field.h | 5 | ||||
-rw-r--r-- | runtime/mirror/art_method.cc | 3 | ||||
-rw-r--r-- | runtime/mirror/art_method.h | 5 | ||||
-rw-r--r-- | runtime/native/scoped_fast_native_object_access.h | 4 | ||||
-rw-r--r-- | runtime/reflection.cc | 26 | ||||
-rw-r--r-- | runtime/reflection.h | 14 | ||||
-rw-r--r-- | runtime/scoped_thread_state_change.h | 130 | ||||
-rw-r--r-- | runtime/thread.cc | 20 | ||||
-rw-r--r-- | runtime/thread.h | 16 |
14 files changed, 141 insertions, 98 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 3c620def4e..382aba3113 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -2802,7 +2802,7 @@ static void CheckProxyConstructor(mirror::ArtMethod* constructor); static void CheckProxyMethod(mirror::ArtMethod* method, Handle<mirror::ArtMethod>& prototype); -mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccess& soa, jstring name, +mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, jstring name, jobjectArray interfaces, jobject loader, jobjectArray methods, jobjectArray throws) { Thread* self = soa.Self(); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 22fd668ad2..38c437b406 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -46,7 +46,7 @@ namespace mirror { class InternTable; template<class T> class ObjectLock; -class ScopedObjectAccess; +class ScopedObjectAccessAlreadyRunnable; template<class T> class Handle; typedef bool (ClassVisitor)(mirror::Class* c, void* arg); @@ -326,8 +326,9 @@ class ClassLinker { void ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, mirror::ArtMethod* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - mirror::Class* CreateProxyClass(ScopedObjectAccess& soa, jstring name, jobjectArray interfaces, - jobject loader, jobjectArray methods, jobjectArray throws) + mirror::Class* CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, jstring name, + jobjectArray interfaces, jobject loader, jobjectArray methods, + jobjectArray throws) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); std::string GetDescriptorForProxy(mirror::Class* proxy_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index c81706fcb2..39b2ec2dae 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -139,7 +139,7 @@ void ThrowStackOverflowError(Thread* self) { self->ResetDefaultStackEnd(!explicit_overflow_check); // Return to default stack size. } -JValue InvokeProxyInvocationHandler(ScopedObjectAccessUnchecked& soa, const char* shorty, +JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, const char* shorty, jobject rcvr_jobj, jobject interface_method_jobj, std::vector<jvalue>& args) { DCHECK(soa.Env()->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy)); diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index bfcb58f274..f1795a5a63 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -699,7 +699,7 @@ static inline void CheckSuspend(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mut } } -JValue InvokeProxyInvocationHandler(ScopedObjectAccessUnchecked& soa, const char* shorty, +JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, const char* shorty, jobject rcvr_jobj, jobject interface_art_method_jobj, std::vector<jvalue>& args) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc index 86c5c3fe3b..b3b1b71e5b 100644 --- a/runtime/mirror/art_field.cc +++ b/runtime/mirror/art_field.cc @@ -32,7 +32,8 @@ namespace mirror { // TODO: Get global references for these Class* ArtField::java_lang_reflect_ArtField_ = NULL; -ArtField* ArtField::FromReflectedField(const ScopedObjectAccess& soa, jobject jlr_field) { +ArtField* ArtField::FromReflectedField(const ScopedObjectAccessAlreadyRunnable& soa, + jobject jlr_field) { mirror::ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_reflect_Field_artField); mirror::ArtField* field = f->GetObject(soa.Decode<mirror::Object*>(jlr_field))->AsArtField(); DCHECK(field != nullptr); diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h index 029bd5ae92..36e62c2094 100644 --- a/runtime/mirror/art_field.h +++ b/runtime/mirror/art_field.h @@ -27,14 +27,15 @@ namespace art { struct ArtFieldOffsets; -class ScopedObjectAccess; +class ScopedObjectAccessAlreadyRunnable; namespace mirror { // C++ mirror of java.lang.reflect.ArtField class MANAGED ArtField : public Object { public: - static ArtField* FromReflectedField(const ScopedObjectAccess& soa, jobject jlr_field) + static ArtField* FromReflectedField(const ScopedObjectAccessAlreadyRunnable& soa, + jobject jlr_field) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); Class* GetDeclaringClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc index 495ae2d552..6af4cdb2cb 100644 --- a/runtime/mirror/art_method.cc +++ b/runtime/mirror/art_method.cc @@ -48,7 +48,8 @@ extern "C" void art_quick_invoke_static_stub(ArtMethod*, uint32_t*, uint32_t, Th // TODO: get global references for these Class* ArtMethod::java_lang_reflect_ArtMethod_ = NULL; -ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccess& soa, jobject jlr_method) { +ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa, + jobject jlr_method) { mirror::ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod); mirror::ArtMethod* method = f->GetObject(soa.Decode<mirror::Object*>(jlr_method))->AsArtMethod(); diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h index 3950a980d5..bd9d5ab248 100644 --- a/runtime/mirror/art_method.h +++ b/runtime/mirror/art_method.h @@ -32,7 +32,7 @@ struct ConstructorMethodOffsets; union JValue; struct MethodClassOffsets; class MethodHelper; -class ScopedObjectAccess; +class ScopedObjectAccessAlreadyRunnable; class StringPiece; class ShadowFrame; @@ -46,7 +46,8 @@ typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper& mh, // C++ mirror of java.lang.reflect.Method and java.lang.reflect.Constructor class MANAGED ArtMethod : public Object { public: - static ArtMethod* FromReflectedMethod(const ScopedObjectAccess& soa, jobject jlr_method) + static ArtMethod* FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa, + jobject jlr_method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); Class* GetDeclaringClass() ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/native/scoped_fast_native_object_access.h b/runtime/native/scoped_fast_native_object_access.h index 744ac05dc6..822aefa43c 100644 --- a/runtime/native/scoped_fast_native_object_access.h +++ b/runtime/native/scoped_fast_native_object_access.h @@ -24,12 +24,12 @@ namespace art { // Variant of ScopedObjectAccess that does no runnable transitions. Should only be used by "fast" // JNI methods. -class ScopedFastNativeObjectAccess : public ScopedObjectAccess { +class ScopedFastNativeObjectAccess : public ScopedObjectAccessAlreadyRunnable { public: explicit ScopedFastNativeObjectAccess(JNIEnv* env) LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE - : ScopedObjectAccess(env) { + : ScopedObjectAccessAlreadyRunnable(env) { Locks::mutator_lock_->AssertSharedHeld(Self()); DCHECK((*Self()->GetManagedStack()->GetTopQuickFrame())->IsFastNative()); // Don't work with raw objects in non-runnable states. diff --git a/runtime/reflection.cc b/runtime/reflection.cc index cbd66a6a51..dc42723bc3 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -100,7 +100,8 @@ class ArgArray { AppendWide(jv.j); } - void BuildArgArrayFromVarArgs(const ScopedObjectAccess& soa, mirror::Object* receiver, va_list ap) + void BuildArgArrayFromVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, + mirror::Object* receiver, va_list ap) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // Set receiver if non-null (method is not static) if (receiver != nullptr) { @@ -135,8 +136,8 @@ class ArgArray { } } - void BuildArgArrayFromJValues(const ScopedObjectAccessUnchecked& soa, mirror::Object* receiver, - jvalue* args) + void BuildArgArrayFromJValues(const ScopedObjectAccessAlreadyRunnable& soa, + mirror::Object* receiver, jvalue* args) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // Set receiver if non-null (method is not static) if (receiver != nullptr) { @@ -217,7 +218,8 @@ class ArgArray { PrettyDescriptor(found_descriptor.as_string()).c_str()).c_str()); } - bool BuildArgArrayFromObjectArray(const ScopedObjectAccess& soa, mirror::Object* receiver, + bool BuildArgArrayFromObjectArray(const ScopedObjectAccessAlreadyRunnable& soa, + mirror::Object* receiver, mirror::ObjectArray<mirror::Object>* args, MethodHelper& mh) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile::TypeList* classes = mh.GetParameterTypeList(); @@ -396,8 +398,9 @@ static mirror::ArtMethod* FindVirtualMethod(mirror::Object* receiver, } -static void InvokeWithArgArray(const ScopedObjectAccessUnchecked& soa, mirror::ArtMethod* method, - ArgArray* arg_array, JValue* result, const char* shorty) +static void InvokeWithArgArray(const ScopedObjectAccessAlreadyRunnable& soa, + mirror::ArtMethod* method, ArgArray* arg_array, JValue* result, + const char* shorty) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { uint32_t* args = arg_array->GetArray(); if (UNLIKELY(soa.Env()->check_jni)) { @@ -406,7 +409,8 @@ static void InvokeWithArgArray(const ScopedObjectAccessUnchecked& soa, mirror::A method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, shorty); } -JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj, jmethodID mid, va_list args) +JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid, + va_list args) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtMethod* method = soa.DecodeMethod(mid); mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj); @@ -418,7 +422,7 @@ JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj, jmethodID m return result; } -JValue InvokeWithJValues(const ScopedObjectAccessUnchecked& soa, mirror::Object* receiver, +JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, mirror::Object* receiver, jmethodID mid, jvalue* args) { mirror::ArtMethod* method = soa.DecodeMethod(mid); MethodHelper mh(method); @@ -429,7 +433,7 @@ JValue InvokeWithJValues(const ScopedObjectAccessUnchecked& soa, mirror::Object* return result; } -JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccess& soa, +JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, mirror::Object* receiver, jmethodID mid, jvalue* args) { mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid)); MethodHelper mh(method); @@ -440,7 +444,7 @@ JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccess& soa, return result; } -JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccess& soa, +JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid, va_list args) { mirror::Object* receiver = soa.Decode<mirror::Object*>(obj); mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid)); @@ -460,7 +464,7 @@ void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg mh.GetShorty()); } -jobject InvokeMethod(const ScopedObjectAccess& soa, jobject javaMethod, +jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaMethod, jobject javaReceiver, jobject javaArgs, bool accessible) { mirror::ArtMethod* m = mirror::ArtMethod::FromReflectedMethod(soa, javaMethod); diff --git a/runtime/reflection.h b/runtime/reflection.h index d9a722825a..2c54c067fd 100644 --- a/runtime/reflection.h +++ b/runtime/reflection.h @@ -29,8 +29,7 @@ namespace mirror { } // namespace mirror union JValue; class MethodHelper; -class ScopedObjectAccess; -class ScopedObjectAccessUnchecked; +class ScopedObjectAccessAlreadyRunnable; class ShadowFrame; class ThrowLocation; @@ -48,18 +47,19 @@ bool ConvertPrimitiveValue(const ThrowLocation* throw_location, bool unbox_for_r const JValue& src, JValue* dst) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); -JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj, jmethodID mid, va_list args) +JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid, + va_list args) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); -JValue InvokeWithJValues(const ScopedObjectAccessUnchecked& soa, mirror::Object* receiver, +JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, mirror::Object* receiver, jmethodID mid, jvalue* args) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); -JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccess& soa, +JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, mirror::Object* receiver, jmethodID mid, jvalue* args) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); -JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccess& soa, +JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid, va_list args) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -67,7 +67,7 @@ void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg MethodHelper& mh, JValue* result) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); -jobject InvokeMethod(const ScopedObjectAccess& soa, jobject method, jobject receiver, +jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject method, jobject receiver, jobject args, bool accessible) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h index dbd961f942..d56495e4f9 100644 --- a/runtime/scoped_thread_state_change.h +++ b/runtime/scoped_thread_state_change.h @@ -93,50 +93,15 @@ class ScopedThreadStateChange { ThreadState old_thread_state_; const bool expected_has_no_thread_; + friend class ScopedObjectAccessUnchecked; DISALLOW_COPY_AND_ASSIGN(ScopedThreadStateChange); }; -// Entry/exit processing for transitions from Native to Runnable (ie within JNI functions). -// -// This class performs the necessary thread state switching to and from Runnable and lets us -// amortize the cost of working out the current thread. Additionally it lets us check (and repair) -// apps that are using a JNIEnv on the wrong thread. The class also decodes and encodes Objects -// into jobjects via methods of this class. Performing this here enforces the Runnable thread state -// for use of Object, thereby inhibiting the Object being modified by GC whilst native or VM code -// is also manipulating the Object. -// -// The destructor transitions back to the previous thread state, typically Native. In this state -// GC and thread suspension may occur. -// -// For annotalysis the subclass ScopedObjectAccess (below) makes it explicit that a shared of -// the mutator_lock_ will be acquired on construction. -class ScopedObjectAccessUnchecked : public ScopedThreadStateChange { +// Assumes we are already runnable. +class ScopedObjectAccessAlreadyRunnable { public: - explicit ScopedObjectAccessUnchecked(JNIEnv* env) - LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) ALWAYS_INLINE - : ScopedThreadStateChange(ThreadForEnv(env), kRunnable), - env_(down_cast<JNIEnvExt*>(env)), vm_(env_->vm) { - self_->VerifyStack(); - Locks::mutator_lock_->AssertSharedHeld(self_); - } - - explicit ScopedObjectAccessUnchecked(Thread* self) - LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) - : ScopedThreadStateChange(self, kRunnable), - env_(down_cast<JNIEnvExt*>(self->GetJniEnv())), - vm_(env_ != NULL ? env_->vm : NULL) { - self_->VerifyStack(); - Locks::mutator_lock_->AssertSharedHeld(self_); - } - - // Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't - // change into Runnable or acquire a share on the mutator_lock_. - explicit ScopedObjectAccessUnchecked(JavaVM* vm) - : ScopedThreadStateChange(), env_(NULL), vm_(down_cast<JavaVMExt*>(vm)) {} - - // Here purely to force inlining. - ~ScopedObjectAccessUnchecked() ALWAYS_INLINE { - Locks::mutator_lock_->AssertSharedHeld(self_); + Thread* Self() const { + return self_; } JNIEnvExt* Env() const { @@ -159,13 +124,11 @@ class ScopedObjectAccessUnchecked : public ScopedThreadStateChange { template<typename T> T AddLocalReference(mirror::Object* obj) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Locks::mutator_lock_->AssertSharedHeld(Self()); - DCHECK_EQ(thread_state_, kRunnable); // Don't work with raw objects in non-runnable states. + DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. if (obj == NULL) { return NULL; } - DCHECK_NE((reinterpret_cast<uintptr_t>(obj) & 0xffff0000), 0xebad0000); - return Env()->AddLocalReference<T>(obj); } @@ -173,14 +136,14 @@ class ScopedObjectAccessUnchecked : public ScopedThreadStateChange { T Decode(jobject obj) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Locks::mutator_lock_->AssertSharedHeld(Self()); - DCHECK_EQ(thread_state_, kRunnable); // Don't work with raw objects in non-runnable states. + DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. return down_cast<T>(Self()->DecodeJObject(obj)); } mirror::ArtField* DecodeField(jfieldID fid) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Locks::mutator_lock_->AssertSharedHeld(Self()); - DCHECK_EQ(thread_state_, kRunnable); // Don't work with raw objects in non-runnable states. + DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. CHECK(!kMovingFields); return reinterpret_cast<mirror::ArtField*>(fid); } @@ -188,7 +151,7 @@ class ScopedObjectAccessUnchecked : public ScopedThreadStateChange { jfieldID EncodeField(mirror::ArtField* field) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Locks::mutator_lock_->AssertSharedHeld(Self()); - DCHECK_EQ(thread_state_, kRunnable); // Don't work with raw objects in non-runnable states. + DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. CHECK(!kMovingFields); return reinterpret_cast<jfieldID>(field); } @@ -196,7 +159,7 @@ class ScopedObjectAccessUnchecked : public ScopedThreadStateChange { mirror::ArtMethod* DecodeMethod(jmethodID mid) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Locks::mutator_lock_->AssertSharedHeld(Self()); - DCHECK_EQ(thread_state_, kRunnable); // Don't work with raw objects in non-runnable states. + DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. CHECK(!kMovingMethods); return reinterpret_cast<mirror::ArtMethod*>(mid); } @@ -204,16 +167,83 @@ class ScopedObjectAccessUnchecked : public ScopedThreadStateChange { jmethodID EncodeMethod(mirror::ArtMethod* method) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Locks::mutator_lock_->AssertSharedHeld(Self()); - DCHECK_EQ(thread_state_, kRunnable); // Don't work with raw objects in non-runnable states. + DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. CHECK(!kMovingMethods); return reinterpret_cast<jmethodID>(method); } - private: + bool IsRunnable() const { + return self_->GetState() == kRunnable; + } + + protected: + explicit ScopedObjectAccessAlreadyRunnable(JNIEnv* env) + LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) ALWAYS_INLINE + : self_(ThreadForEnv(env)), env_(down_cast<JNIEnvExt*>(env)), vm_(env_->vm) { + } + + explicit ScopedObjectAccessAlreadyRunnable(Thread* self) + LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) ALWAYS_INLINE + : self_(self), env_(down_cast<JNIEnvExt*>(self->GetJniEnv())), + vm_(env_ != nullptr ? env_->vm : nullptr) { + } + + // Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't + // change into Runnable or acquire a share on the mutator_lock_. + explicit ScopedObjectAccessAlreadyRunnable(JavaVM* vm) + : self_(nullptr), env_(nullptr), vm_(down_cast<JavaVMExt*>(vm)) {} + + // Here purely to force inlining. + ~ScopedObjectAccessAlreadyRunnable() ALWAYS_INLINE { + } + + // Self thread, can be null. + Thread* const self_; // The full JNIEnv. JNIEnvExt* const env_; // The full JavaVM. JavaVMExt* const vm_; +}; + +// Entry/exit processing for transitions from Native to Runnable (ie within JNI functions). +// +// This class performs the necessary thread state switching to and from Runnable and lets us +// amortize the cost of working out the current thread. Additionally it lets us check (and repair) +// apps that are using a JNIEnv on the wrong thread. The class also decodes and encodes Objects +// into jobjects via methods of this class. Performing this here enforces the Runnable thread state +// for use of Object, thereby inhibiting the Object being modified by GC whilst native or VM code +// is also manipulating the Object. +// +// The destructor transitions back to the previous thread state, typically Native. In this state +// GC and thread suspension may occur. +// +// For annotalysis the subclass ScopedObjectAccess (below) makes it explicit that a shared of +// the mutator_lock_ will be acquired on construction. +class ScopedObjectAccessUnchecked : public ScopedObjectAccessAlreadyRunnable { + public: + explicit ScopedObjectAccessUnchecked(JNIEnv* env) + LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) ALWAYS_INLINE + : ScopedObjectAccessAlreadyRunnable(env), tsc_(Self(), kRunnable) { + Self()->VerifyStack(); + Locks::mutator_lock_->AssertSharedHeld(Self()); + } + + explicit ScopedObjectAccessUnchecked(Thread* self) + LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) ALWAYS_INLINE + : ScopedObjectAccessAlreadyRunnable(self), tsc_(self, kRunnable) { + Self()->VerifyStack(); + Locks::mutator_lock_->AssertSharedHeld(Self()); + } + + // Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't + // change into Runnable or acquire a share on the mutator_lock_. + explicit ScopedObjectAccessUnchecked(JavaVM* vm) ALWAYS_INLINE + : ScopedObjectAccessAlreadyRunnable(vm), tsc_() {} + + private: + // The scoped thread state change makes sure that we are runnable and restores the thread state + // in the destructor. + const ScopedThreadStateChange tsc_; DISALLOW_COPY_AND_ASSIGN(ScopedObjectAccessUnchecked); }; @@ -229,7 +259,7 @@ class ScopedObjectAccess : public ScopedObjectAccessUnchecked { explicit ScopedObjectAccess(Thread* self) LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) - SHARED_LOCK_FUNCTION(Locks::mutator_lock_) + SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE : ScopedObjectAccessUnchecked(self) { } diff --git a/runtime/thread.cc b/runtime/thread.cc index 488961eec5..8c057e3f59 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -171,7 +171,7 @@ void* Thread::CreateCallback(void* arg) { return nullptr; } -Thread* Thread::FromManagedThread(const ScopedObjectAccessUnchecked& soa, +Thread* Thread::FromManagedThread(const ScopedObjectAccessAlreadyRunnable& soa, mirror::Object* thread_peer) { mirror::ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer); Thread* result = reinterpret_cast<Thread*>(static_cast<uintptr_t>(f->GetLong(thread_peer))); @@ -186,7 +186,8 @@ Thread* Thread::FromManagedThread(const ScopedObjectAccessUnchecked& soa, return result; } -Thread* Thread::FromManagedThread(const ScopedObjectAccessUnchecked& soa, jobject java_thread) { +Thread* Thread::FromManagedThread(const ScopedObjectAccessAlreadyRunnable& soa, + jobject java_thread) { return FromManagedThread(soa, soa.Decode<mirror::Object*>(java_thread)); } @@ -556,7 +557,7 @@ void Thread::Dump(std::ostream& os) const { DumpStack(os); } -mirror::String* Thread::GetThreadName(const ScopedObjectAccessUnchecked& soa) const { +mirror::String* Thread::GetThreadName(const ScopedObjectAccessAlreadyRunnable& soa) const { mirror::ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_name); return (tlsPtr_.opeer != nullptr) ? reinterpret_cast<mirror::String*>(f->GetObject(tlsPtr_.opeer)) : nullptr; } @@ -1432,7 +1433,7 @@ class BuildInternalStackTraceVisitor : public StackVisitor { }; template<bool kTransactionActive> -jobject Thread::CreateInternalStackTrace(const ScopedObjectAccessUnchecked& soa) const { +jobject Thread::CreateInternalStackTrace(const ScopedObjectAccessAlreadyRunnable& soa) const { // Compute depth of stack CountStackDepthVisitor count_visitor(const_cast<Thread*>(this)); count_visitor.WalkStack(); @@ -1455,11 +1456,14 @@ jobject Thread::CreateInternalStackTrace(const ScopedObjectAccessUnchecked& soa) } return soa.AddLocalReference<jobjectArray>(trace); } -template jobject Thread::CreateInternalStackTrace<false>(const ScopedObjectAccessUnchecked& soa) const; -template jobject Thread::CreateInternalStackTrace<true>(const ScopedObjectAccessUnchecked& soa) const; +template jobject Thread::CreateInternalStackTrace<false>( + const ScopedObjectAccessAlreadyRunnable& soa) const; +template jobject Thread::CreateInternalStackTrace<true>( + const ScopedObjectAccessAlreadyRunnable& soa) const; -jobjectArray Thread::InternalStackTraceToStackTraceElementArray(const ScopedObjectAccess& soa, - jobject internal, jobjectArray output_array, int* stack_depth) { +jobjectArray Thread::InternalStackTraceToStackTraceElementArray( + const ScopedObjectAccessAlreadyRunnable& soa, jobject internal, jobjectArray output_array, + int* stack_depth) { // Decode the internal stack trace into the depth, method trace and PC trace int32_t depth = soa.Decode<mirror::ObjectArray<mirror::Object>*>(internal)->GetLength() - 1; diff --git a/runtime/thread.h b/runtime/thread.h index f7aef429f4..20830c2971 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -72,8 +72,7 @@ class JavaVMExt; struct JNIEnvExt; class Monitor; class Runtime; -class ScopedObjectAccess; -class ScopedObjectAccessUnchecked; +class ScopedObjectAccessAlreadyRunnable; class ShadowFrame; struct SingleStepControl; class Thread; @@ -140,12 +139,12 @@ class Thread { static Thread* Current(); - static Thread* FromManagedThread(const ScopedObjectAccessUnchecked& ts, + static Thread* FromManagedThread(const ScopedObjectAccessAlreadyRunnable& ts, mirror::Object* thread_peer) EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_lock_) LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - static Thread* FromManagedThread(const ScopedObjectAccessUnchecked& ts, jobject thread) + static Thread* FromManagedThread(const ScopedObjectAccessAlreadyRunnable& ts, jobject thread) EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_lock_) LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -276,7 +275,7 @@ class Thread { } // Returns the java.lang.Thread's name, or NULL if this Thread* doesn't have a peer. - mirror::String* GetThreadName(const ScopedObjectAccessUnchecked& ts) const + mirror::String* GetThreadName(const ScopedObjectAccessAlreadyRunnable& ts) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Sets 'name' to the java.lang.Thread's name. This requires no transition to managed code, @@ -458,15 +457,16 @@ class Thread { // Create the internal representation of a stack trace, that is more time // and space efficient to compute than the StackTraceElement[]. template<bool kTransactionActive> - jobject CreateInternalStackTrace(const ScopedObjectAccessUnchecked& soa) const + jobject CreateInternalStackTrace(const ScopedObjectAccessAlreadyRunnable& soa) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Convert an internal stack trace representation (returned by CreateInternalStackTrace) to a // StackTraceElement[]. If output_array is NULL, a new array is created, otherwise as many // frames as will fit are written into the given array. If stack_depth is non-NULL, it's updated // with the number of valid frames in the returned array. - static jobjectArray InternalStackTraceToStackTraceElementArray(const ScopedObjectAccess& soa, - jobject internal, jobjectArray output_array = nullptr, int* stack_depth = nullptr) + static jobjectArray InternalStackTraceToStackTraceElementArray( + const ScopedObjectAccessAlreadyRunnable& soa, jobject internal, + jobjectArray output_array = nullptr, int* stack_depth = nullptr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void VisitRoots(RootCallback* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |