summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/class_linker.cc2
-rw-r--r--runtime/class_linker.h7
-rw-r--r--runtime/entrypoints/entrypoint_utils.cc2
-rw-r--r--runtime/entrypoints/entrypoint_utils.h2
-rw-r--r--runtime/mirror/art_field.cc3
-rw-r--r--runtime/mirror/art_field.h5
-rw-r--r--runtime/mirror/art_method.cc3
-rw-r--r--runtime/mirror/art_method.h5
-rw-r--r--runtime/native/scoped_fast_native_object_access.h4
-rw-r--r--runtime/reflection.cc26
-rw-r--r--runtime/reflection.h14
-rw-r--r--runtime/scoped_thread_state_change.h130
-rw-r--r--runtime/thread.cc20
-rw-r--r--runtime/thread.h16
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_);