Use ObjPtr for reflection.cc/h/inl
Changed Pretty helpers to use this to reduce usage of Decode. The
eventual goal is not have almost any calls to ObjPtr::Decode.
Moved ObjPtr out of mirror namespace for convenience. Added more
PoisonObjectPointers calls in class linker, thread suspension.
Bug: 31113334
Test: test-art-host
Change-Id: I44d08db5143d95ed1b65e2f00f9749ef5cf379f7
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index caabcde..d5b3090 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -70,6 +70,7 @@
mirror::StringDexCachePair::LookupString(declaring_class->GetDexCacheStrings(),
string_idx,
mirror::DexCache::kDexCacheStringCacheSize).Read();
+ Thread::PoisonObjectPointersIfDebug();
if (UNLIKELY(string == nullptr)) {
StackHandleScope<1> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
@@ -84,6 +85,7 @@
inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, ArtMethod* referrer) {
mirror::Class* resolved_type = referrer->GetDexCacheResolvedType(type_idx, image_pointer_size_);
+ Thread::PoisonObjectPointersIfDebug();
if (UNLIKELY(resolved_type == nullptr)) {
mirror::Class* declaring_class = referrer->GetDeclaringClass();
StackHandleScope<2> hs(Thread::Current());
@@ -101,6 +103,7 @@
mirror::Class* declaring_class = referrer->GetDeclaringClass();
mirror::DexCache* dex_cache_ptr = declaring_class->GetDexCache();
mirror::Class* resolved_type = dex_cache_ptr->GetResolvedType(type_idx);
+ Thread::PoisonObjectPointersIfDebug();
if (UNLIKELY(resolved_type == nullptr)) {
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(dex_cache_ptr));
@@ -148,6 +151,7 @@
ArtMethod* referrer,
InvokeType type) {
ArtMethod* resolved_method = GetResolvedMethod(method_idx, referrer);
+ Thread::PoisonObjectPointersIfDebug();
if (UNLIKELY(resolved_method == nullptr)) {
mirror::Class* declaring_class = referrer->GetDeclaringClass();
StackHandleScope<2> hs(self);
@@ -179,6 +183,7 @@
bool is_static) {
mirror::Class* declaring_class = referrer->GetDeclaringClass();
ArtField* resolved_field = GetResolvedField(field_idx, declaring_class);
+ Thread::PoisonObjectPointersIfDebug();
if (UNLIKELY(resolved_field == nullptr)) {
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ecaa4c2..eb38a8c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2167,6 +2167,7 @@
const char* descriptor,
mirror::Class* klass) {
DCHECK(klass != nullptr);
+ self->PoisonObjectPointers();
// For temporary classes we must wait for them to be retired.
if (init_done_ && klass->IsTemp()) {
@@ -2378,7 +2379,7 @@
DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
DCHECK(self != nullptr);
self->AssertNoPendingException();
- self->PoisonObjectPointers();
+ self->PoisonObjectPointers(); // For DefineClass, CreateArrayClass, etc...
if (descriptor[1] == '\0') {
// only the descriptors of primitive types should be 1 character long, also avoid class lookup
// for primitive classes that aren't backed by dex files.
@@ -7524,6 +7525,7 @@
Handle<mirror::DexCache> dex_cache) {
DCHECK(dex_cache.Get() != nullptr);
mirror::String* resolved = dex_cache->GetResolvedString(string_idx);
+ Thread::PoisonObjectPointersIfDebug();
if (resolved != nullptr) {
return resolved;
}
@@ -7566,6 +7568,7 @@
Handle<mirror::ClassLoader> class_loader) {
DCHECK(dex_cache.Get() != nullptr);
mirror::Class* resolved = dex_cache->GetResolvedType(type_idx);
+ Thread::PoisonObjectPointersIfDebug();
if (resolved == nullptr) {
Thread* self = Thread::Current();
const char* descriptor = dex_file.StringByTypeIdx(type_idx);
@@ -7604,6 +7607,7 @@
DCHECK(dex_cache.Get() != nullptr);
// Check for hit in the dex cache.
ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_);
+ Thread::PoisonObjectPointersIfDebug();
if (resolved != nullptr && !resolved->IsRuntimeMethod()) {
DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
if (kResolveMode == ClassLinker::kForceICCECheck) {
@@ -7807,6 +7811,7 @@
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader) {
ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_);
+ Thread::PoisonObjectPointersIfDebug();
if (resolved != nullptr && !resolved->IsRuntimeMethod()) {
DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
return resolved;
@@ -7839,6 +7844,7 @@
bool is_static) {
DCHECK(dex_cache.Get() != nullptr);
ArtField* resolved = dex_cache->GetResolvedField(field_idx, image_pointer_size_);
+ Thread::PoisonObjectPointersIfDebug();
if (resolved != nullptr) {
return resolved;
}
@@ -7881,6 +7887,7 @@
Handle<mirror::ClassLoader> class_loader) {
DCHECK(dex_cache.Get() != nullptr);
ArtField* resolved = dex_cache->GetResolvedField(field_idx, image_pointer_size_);
+ Thread::PoisonObjectPointersIfDebug();
if (resolved != nullptr) {
return resolved;
}
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index c6c87fd..c3cf53b 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -572,7 +572,7 @@
*annotation_ptr = annotation;
if (result_style == DexFile::kAllObjects && primitive_type != Primitive::kPrimVoid) {
- element_object = BoxPrimitive(primitive_type, annotation_value->value_);
+ element_object = BoxPrimitive(primitive_type, annotation_value->value_).Decode();
set_object = true;
}
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index fd9ffbd..bfa2b69 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -160,7 +160,7 @@
} else {
JValue jv;
jv.SetJ(args.at(i).j);
- mirror::Object* val = BoxPrimitive(Primitive::GetType(shorty[i + 1]), jv);
+ mirror::Object* val = BoxPrimitive(Primitive::GetType(shorty[i + 1]), jv).Decode();
if (val == nullptr) {
CHECK(soa.Self()->IsExceptionPending());
return zero;
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index b0ca18e..6d61c64 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -50,6 +50,7 @@
CHECK_EQ(self->GetState(), kRunnable);
self->AssertThreadSuspensionIsAllowable();
self->AssertNoPendingException();
+ self->PoisonObjectPointers();
}
// Need to check that we arent the large object allocator since the large object allocation code
// path this function. If we didn't check we would have an infinite loop.
diff --git a/runtime/handle.h b/runtime/handle.h
index d4c13d4..c41010a 100644
--- a/runtime/handle.h
+++ b/runtime/handle.h
@@ -23,6 +23,7 @@
#include "base/mutex.h"
#include "base/value_object.h"
#include "jni.h"
+#include "obj_ptr.h"
#include "stack_reference.h"
namespace art {
@@ -130,6 +131,14 @@
return old;
}
+ ALWAYS_INLINE T* Assign(ObjPtr<T> reference) REQUIRES_SHARED(Locks::mutator_lock_) {
+ StackReference<mirror::Object>* ref = Handle<T>::GetReference();
+ T* old = down_cast<T*>(ref->AsMirrorPtr());
+ ref->Assign(reference.Decode());
+ return old;
+ }
+
+
template<typename S>
explicit MutableHandle(const MutableHandle<S>& handle) REQUIRES_SHARED(Locks::mutator_lock_)
: Handle<T>(handle) {
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 0f5cbb2..ad7558c 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -31,6 +31,7 @@
#include "lock_word-inl.h"
#include "monitor.h"
#include "object_array-inl.h"
+#include "obj_ptr-inl.h"
#include "read_barrier-inl.h"
#include "reference.h"
#include "runtime.h"
@@ -281,7 +282,7 @@
}
template<VerifyObjectFlags kVerifyFlags>
-inline bool Object::InstanceOf(Class* klass) {
+inline bool Object::InstanceOf(ObjPtr<Class> klass) {
DCHECK(klass != nullptr);
DCHECK(GetClass<kVerifyNone>() != nullptr);
return klass->IsAssignableFrom(GetClass<kVerifyFlags>());
@@ -509,7 +510,7 @@
template GetObjectSize<kNewFlags, kReadBarrierOption>();
}
DCHECK_GE(result, sizeof(Object))
- << " class=" << PrettyTypeOf(GetClass<kNewFlags, kReadBarrierOption>());
+ << " class=" << PrettyClass(GetClass<kNewFlags, kReadBarrierOption>());
return result;
}
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 262cb57..10faf60 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -20,6 +20,7 @@
#include "base/casts.h"
#include "base/enums.h"
#include "globals.h"
+#include "obj_ptr.h"
#include "object_reference.h"
#include "offsets.h"
#include "verify_object.h"
@@ -120,7 +121,7 @@
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool VerifierInstanceOf(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- ALWAYS_INLINE bool InstanceOf(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
+ ALWAYS_INLINE bool InstanceOf(ObjPtr<Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index f4ecfb5..0f3447e 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -746,7 +746,7 @@
ObjPtr<mirror::Object, /*kPoison*/ true> null_ptr;
EXPECT_TRUE(null_ptr.IsNull());
EXPECT_TRUE(null_ptr.IsValid());
- EXPECT_TRUE(null_ptr.Get() == nullptr);
+ EXPECT_TRUE(null_ptr.Decode() == nullptr);
EXPECT_TRUE(null_ptr == nullptr);
EXPECT_TRUE(null_ptr == null_ptr);
EXPECT_FALSE(null_ptr != null_ptr);
@@ -758,13 +758,13 @@
ObjPtr<Class, /*kPoison*/ true> X(h_X.Get());
EXPECT_TRUE(!X.IsNull());
EXPECT_TRUE(X.IsValid());
- EXPECT_TRUE(X.Get() != nullptr);
- EXPECT_EQ(h_X.Get(), X.Get());
+ EXPECT_TRUE(X.Decode() != nullptr);
+ EXPECT_EQ(h_X.Get(), X.Decode());
// FindClass may cause thread suspension, it should invalidate X.
ObjPtr<Class, /*kPoison*/ true> Y(class_linker_->FindClass(soa.Self(), "LY;", class_loader));
EXPECT_TRUE(!Y.IsNull());
EXPECT_TRUE(Y.IsValid());
- EXPECT_TRUE(Y.Get() != nullptr);
+ EXPECT_TRUE(Y.Decode() != nullptr);
// Should IsNull be safe to call on null ObjPtr? I'll allow it for now.
EXPECT_TRUE(!X.IsNull());
@@ -773,7 +773,7 @@
X.Assign(h_X.Get());
EXPECT_TRUE(!X.IsNull());
EXPECT_TRUE(X.IsValid());
- EXPECT_EQ(h_X.Get(), X.Get());
+ EXPECT_EQ(h_X.Get(), X.Decode());
// Allow thread suspension to invalidate Y.
soa.Self()->AllowThreadSuspension();
@@ -784,7 +784,7 @@
ObjPtr<mirror::Object, /*kPoison*/ false> unpoisoned;
EXPECT_TRUE(unpoisoned.IsNull());
EXPECT_TRUE(unpoisoned.IsValid());
- EXPECT_TRUE(unpoisoned.Get() == nullptr);
+ EXPECT_TRUE(unpoisoned.Decode() == nullptr);
EXPECT_TRUE(unpoisoned == nullptr);
EXPECT_TRUE(unpoisoned == unpoisoned);
EXPECT_FALSE(unpoisoned != unpoisoned);
@@ -793,7 +793,7 @@
unpoisoned = h_X.Get();
EXPECT_FALSE(unpoisoned.IsNull());
EXPECT_TRUE(unpoisoned == h_X.Get());
- EXPECT_EQ(unpoisoned.Get(), h_X.Get());
+ EXPECT_EQ(unpoisoned.Decode(), h_X.Get());
}
} // namespace mirror
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index af9b68f..b6260e9 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -33,6 +33,7 @@
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/string-inl.h"
+#include "obj_ptr-inl.h"
#include "reflection.h"
#include "scoped_thread_state_change.h"
#include "scoped_fast_native_object_access.h"
@@ -669,7 +670,10 @@
caller.Assign(GetCallingClass(soa.Self(), 1));
}
if (UNLIKELY(caller.Get() != nullptr && !VerifyAccess(
- receiver.Get(), declaring_class, constructor->GetAccessFlags(), caller.Get()))) {
+ MakeObjPtr(receiver.Get()),
+ MakeObjPtr(declaring_class),
+ constructor->GetAccessFlags(),
+ MakeObjPtr(caller.Get())))) {
soa.Self()->ThrowNewExceptionF(
"Ljava/lang/IllegalAccessException;", "%s is not accessible from %s",
PrettyMethod(constructor).c_str(), PrettyClass(caller.Get()).c_str());
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index d001d0c..47c49d5 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -73,7 +73,7 @@
if (!m->IsAccessible() && !c->IsPublic()) {
// Go 2 frames back, this method is always called from newInstance0, which is called from
// Constructor.newInstance(Object... args).
- auto* caller = GetCallingClass(soa.Self(), 2);
+ ObjPtr<mirror::Class> caller = GetCallingClass(soa.Self(), 2);
// If caller is null, then we called from JNI, just avoid the check since JNI avoids most
// access checks anyways. TODO: Investigate if this the correct behavior.
if (caller != nullptr && !caller->CanAccess(c.Get())) {
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 412445f..dab510d 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -43,9 +43,13 @@
PrettyClass(field->GetDeclaringClass()).c_str()).c_str());
return false;
}
- mirror::Class* calling_class = nullptr;
- if (!VerifyAccess(self, obj, field->GetDeclaringClass(), field->GetAccessFlags(),
- &calling_class, 1)) {
+ ObjPtr<mirror::Class> calling_class;
+ if (!VerifyAccess(self,
+ MakeObjPtr(obj),
+ MakeObjPtr(field->GetDeclaringClass()),
+ field->GetAccessFlags(),
+ &calling_class,
+ 1)) {
ThrowIllegalAccessException(
StringPrintf("Class %s cannot access %s field %s of class %s",
calling_class == nullptr ? "null" : PrettyClass(calling_class).c_str(),
@@ -124,7 +128,7 @@
return true;
}
*class_or_rcvr = soa.Decode<mirror::Object*>(j_rcvr);
- if (!VerifyObjectIsClass(*class_or_rcvr, declaringClass)) {
+ if (!VerifyObjectIsClass(MakeObjPtr(*class_or_rcvr), MakeObjPtr(declaringClass))) {
DCHECK(soa.Self()->IsExceptionPending());
return false;
}
@@ -152,7 +156,7 @@
DCHECK(soa.Self()->IsExceptionPending());
return nullptr;
}
- return soa.AddLocalReference<jobject>(BoxPrimitive(field_type, value));
+ return soa.AddLocalReference<jobject>(BoxPrimitive(field_type, value).Decode());
}
template<Primitive::Type kPrimitiveType>
@@ -323,7 +327,10 @@
// Unbox the value, if necessary.
mirror::Object* boxed_value = soa.Decode<mirror::Object*>(javaValue);
JValue unboxed_value;
- if (!UnboxPrimitiveForField(boxed_value, field_type, f->GetArtField(), &unboxed_value)) {
+ if (!UnboxPrimitiveForField(MakeObjPtr(boxed_value),
+ MakeObjPtr(field_type),
+ f->GetArtField(),
+ &unboxed_value)) {
DCHECK(soa.Self()->IsExceptionPending());
return;
}
diff --git a/runtime/obj_ptr-inl.h b/runtime/obj_ptr-inl.h
new file mode 100644
index 0000000..3dfcf9e
--- /dev/null
+++ b/runtime/obj_ptr-inl.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_OBJ_PTR_INL_H_
+#define ART_RUNTIME_OBJ_PTR_INL_H_
+
+#include "obj_ptr.h"
+#include "thread-inl.h"
+
+namespace art {
+
+template<class MirrorType, bool kPoison>
+inline bool ObjPtr<MirrorType, kPoison>::IsValid() const {
+ if (!kPoison || IsNull()) {
+ return true;
+ }
+ return GetCookie() == TrimCookie(Thread::Current()->GetPoisonObjectCookie());
+}
+
+template<class MirrorType, bool kPoison>
+inline void ObjPtr<MirrorType, kPoison>::AssertValid() const {
+ if (kPoison) {
+ CHECK(IsValid()) << "Stale object pointer " << DecodeUnchecked() << " , expected cookie "
+ << TrimCookie(Thread::Current()->GetPoisonObjectCookie()) << " but got " << GetCookie();
+ }
+}
+
+template<class MirrorType, bool kPoison>
+inline uintptr_t ObjPtr<MirrorType, kPoison>::Encode(MirrorType* ptr) {
+ uintptr_t ref = reinterpret_cast<uintptr_t>(ptr);
+ if (kPoison && ref != 0) {
+ DCHECK_LE(ref, 0xFFFFFFFFU);
+ ref >>= kObjectAlignmentShift;
+ // Put cookie in high bits.
+ Thread* self = Thread::Current();
+ DCHECK(self != nullptr);
+ ref |= self->GetPoisonObjectCookie() << kCookieShift;
+ }
+ return ref;
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_OBJ_PTR_INL_H_
diff --git a/runtime/mirror/obj_ptr.h b/runtime/obj_ptr.h
similarity index 73%
rename from runtime/mirror/obj_ptr.h
rename to runtime/obj_ptr.h
index 10378e8..d4076be 100644
--- a/runtime/mirror/obj_ptr.h
+++ b/runtime/obj_ptr.h
@@ -14,23 +14,18 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_MIRROR_OBJ_PTR_H_
-#define ART_RUNTIME_MIRROR_OBJ_PTR_H_
+#ifndef ART_RUNTIME_OBJ_PTR_H_
+#define ART_RUNTIME_OBJ_PTR_H_
#include "base/mutex.h" // For Locks::mutator_lock_.
#include "globals.h"
#include "mirror/object_reference.h"
-#include "utils.h"
namespace art {
-namespace mirror {
-
-class Object;
// Value type representing a pointer to a mirror::Object of type MirrorType
// Pass kPoison as a template boolean for testing in non-debug builds.
-// Note that the functions are not 100% thread safe and may have spurious positive check passes in
-// these cases.
+// Since the cookie is thread based, it is not safe to share an ObjPtr between threads.
template<class MirrorType, bool kPoison = kIsDebugBuild>
class ObjPtr {
static constexpr size_t kCookieShift =
@@ -44,11 +39,13 @@
public:
ALWAYS_INLINE ObjPtr() REQUIRES_SHARED(Locks::mutator_lock_) : reference_(0u) {}
- ALWAYS_INLINE explicit ObjPtr(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_)
- : reference_(Encode(ptr)) {}
+ ALWAYS_INLINE ObjPtr(std::nullptr_t) REQUIRES_SHARED(Locks::mutator_lock_) : reference_(0u) {}
- ALWAYS_INLINE explicit ObjPtr(const ObjPtr& other) REQUIRES_SHARED(Locks::mutator_lock_)
- = default;
+ template <typename Type>
+ ALWAYS_INLINE ObjPtr(Type* ptr) REQUIRES_SHARED(Locks::mutator_lock_)
+ : reference_(Encode(static_cast<MirrorType*>(ptr))) {}
+
+ ALWAYS_INLINE ObjPtr(const ObjPtr& other) REQUIRES_SHARED(Locks::mutator_lock_) = default;
ALWAYS_INLINE ObjPtr& operator=(const ObjPtr& other) {
reference_ = other.reference_;
@@ -65,30 +62,23 @@
}
ALWAYS_INLINE MirrorType* operator->() const REQUIRES_SHARED(Locks::mutator_lock_) {
- return Get();
- }
-
- ALWAYS_INLINE MirrorType* Get() const REQUIRES_SHARED(Locks::mutator_lock_) {
return Decode();
}
+
ALWAYS_INLINE bool IsNull() const {
return reference_ == 0;
}
- ALWAYS_INLINE bool IsValid() const REQUIRES_SHARED(Locks::mutator_lock_) {
- if (!kPoison || IsNull()) {
- return true;
- }
- return GetCookie() == TrimCookie(Thread::Current()->GetPoisonObjectCookie());
+ // Decode makes sure that the object pointer is valid.
+ ALWAYS_INLINE MirrorType* Decode() const REQUIRES_SHARED(Locks::mutator_lock_) {
+ AssertValid();
+ return DecodeUnchecked();
}
- ALWAYS_INLINE void AssertValid() const REQUIRES_SHARED(Locks::mutator_lock_) {
- if (kPoison) {
- CHECK(IsValid()) << "Stale object pointer, expected cookie "
- << TrimCookie(Thread::Current()->GetPoisonObjectCookie()) << " but got " << GetCookie();
- }
- }
+ ALWAYS_INLINE bool IsValid() const REQUIRES_SHARED(Locks::mutator_lock_);
+
+ ALWAYS_INLINE void AssertValid() const REQUIRES_SHARED(Locks::mutator_lock_);
ALWAYS_INLINE bool operator==(const ObjPtr& ptr) const REQUIRES_SHARED(Locks::mutator_lock_) {
return Decode() == ptr.Decode();
@@ -124,22 +114,8 @@
return reference_ >> kCookieShift;
}
- ALWAYS_INLINE static uintptr_t Encode(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_) {
- uintptr_t ref = reinterpret_cast<uintptr_t>(ptr);
- if (kPoison && ref != 0) {
- DCHECK_LE(ref, 0xFFFFFFFFU);
- ref >>= kObjectAlignmentShift;
- // Put cookie in high bits.
- Thread* self = Thread::Current();
- DCHECK(self != nullptr);
- ref |= self->GetPoisonObjectCookie() << kCookieShift;
- }
- return ref;
- }
-
// Decode makes sure that the object pointer is valid.
- ALWAYS_INLINE MirrorType* Decode() const REQUIRES_SHARED(Locks::mutator_lock_) {
- AssertValid();
+ ALWAYS_INLINE MirrorType* DecodeUnchecked() const REQUIRES_SHARED(Locks::mutator_lock_) {
if (kPoison) {
return reinterpret_cast<MirrorType*>(
static_cast<uintptr_t>(static_cast<uint32_t>(reference_ << kObjectAlignmentShift)));
@@ -148,12 +124,16 @@
}
}
+ ALWAYS_INLINE static uintptr_t Encode(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_);
// The encoded reference and cookie.
uintptr_t reference_;
};
+template<class MirrorType, bool kPoison = kIsDebugBuild>
+static inline ObjPtr<MirrorType, kPoison> MakeObjPtr(MirrorType* ptr) {
+ return ObjPtr<MirrorType, kPoison>(ptr);
+}
-} // namespace mirror
} // namespace art
-#endif // ART_RUNTIME_MIRROR_OBJ_PTR_H_
+#endif // ART_RUNTIME_OBJ_PTR_H_
diff --git a/runtime/reflection-inl.h b/runtime/reflection-inl.h
index f54d4ca..d7db8a4 100644
--- a/runtime/reflection-inl.h
+++ b/runtime/reflection-inl.h
@@ -23,14 +23,17 @@
#include "common_throws.h"
#include "jvalue.h"
#include "mirror/object-inl.h"
+#include "obj_ptr-inl.h"
#include "primitive.h"
#include "utils.h"
namespace art {
inline bool ConvertPrimitiveValue(bool unbox_for_result,
- Primitive::Type srcType, Primitive::Type dstType,
- const JValue& src, JValue* dst) {
+ Primitive::Type srcType,
+ Primitive::Type dstType,
+ const JValue& src,
+ JValue* dst) {
DCHECK(srcType != Primitive::kPrimNot && dstType != Primitive::kPrimNot);
if (LIKELY(srcType == dstType)) {
dst->SetJ(src.GetJ());
@@ -100,11 +103,11 @@
return false;
}
-inline bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) {
+inline bool VerifyObjectIsClass(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c) {
if (UNLIKELY(o == nullptr)) {
ThrowNullPointerException("null receiver");
return false;
- } else if (UNLIKELY(!o->InstanceOf(c))) {
+ } else if (UNLIKELY(!o->InstanceOf(c.Decode()))) {
InvalidReceiverError(o, c);
return false;
}
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 30b10d8..7c0f2b5 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -72,8 +72,8 @@
num_bytes_ += 4;
}
- void Append(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
- Append(StackReference<mirror::Object>::FromMirrorPtr(obj).AsVRegValue());
+ void Append(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_) {
+ Append(StackReference<mirror::Object>::FromMirrorPtr(obj.Decode()).AsVRegValue());
}
void AppendWide(uint64_t value) {
@@ -95,7 +95,8 @@
}
void BuildArgArrayFromVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
- mirror::Object* receiver, va_list ap)
+ ObjPtr<mirror::Object> receiver,
+ va_list ap)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Set receiver if non-null (method is not static)
if (receiver != nullptr) {
@@ -131,7 +132,7 @@
}
void BuildArgArrayFromJValues(const ScopedObjectAccessAlreadyRunnable& soa,
- mirror::Object* receiver, jvalue* args)
+ ObjPtr<mirror::Object> receiver, jvalue* args)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Set receiver if non-null (method is not static)
if (receiver != nullptr) {
@@ -212,8 +213,9 @@
PrettyDescriptor(found_descriptor).c_str()).c_str());
}
- bool BuildArgArrayFromObjectArray(mirror::Object* receiver,
- mirror::ObjectArray<mirror::Object>* args, ArtMethod* m)
+ bool BuildArgArrayFromObjectArray(ObjPtr<mirror::Object> receiver,
+ ObjPtr<mirror::ObjectArray<mirror::Object>> args,
+ ArtMethod* m)
REQUIRES_SHARED(Locks::mutator_lock_) {
const DexFile::TypeList* classes = m->GetParameterTypeList();
// Set receiver if non-null (method is not static)
@@ -221,13 +223,13 @@
Append(receiver);
}
for (size_t i = 1, args_offset = 0; i < shorty_len_; ++i, ++args_offset) {
- mirror::Object* arg = args->Get(args_offset);
+ ObjPtr<mirror::Object> arg(args->Get(args_offset));
if (((shorty_[i] == 'L') && (arg != nullptr)) || ((arg == nullptr && shorty_[i] != 'L'))) {
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- mirror::Class* dst_class =
+ ObjPtr<mirror::Class> dst_class(
m->GetClassFromTypeIndex(classes->GetTypeItem(args_offset).type_idx_,
true /* resolve */,
- pointer_size);
+ pointer_size));
if (UNLIKELY(arg == nullptr || !arg->InstanceOf(dst_class))) {
ThrowIllegalArgumentException(
StringPrintf("method %s argument %zd has type %s, got %s",
@@ -240,15 +242,15 @@
}
#define DO_FIRST_ARG(match_descriptor, get_fn, append) { \
- if (LIKELY(arg != nullptr && arg->GetClass<>()->DescriptorEquals(match_descriptor))) { \
+ if (LIKELY(arg != nullptr && arg->GetClass()->DescriptorEquals(match_descriptor))) { \
ArtField* primitive_field = arg->GetClass()->GetInstanceField(0); \
- append(primitive_field-> get_fn(arg));
+ append(primitive_field-> get_fn(arg.Decode()));
#define DO_ARG(match_descriptor, get_fn, append) \
} else if (LIKELY(arg != nullptr && \
arg->GetClass<>()->DescriptorEquals(match_descriptor))) { \
ArtField* primitive_field = arg->GetClass()->GetInstanceField(0); \
- append(primitive_field-> get_fn(arg));
+ append(primitive_field-> get_fn(arg.Decode()));
#define DO_FAIL(expected) \
} else { \
@@ -362,9 +364,9 @@
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
for (uint32_t i = 0; i < num_params; i++) {
uint16_t type_idx = params->GetTypeItem(i).type_idx_;
- mirror::Class* param_type = m->GetClassFromTypeIndex(type_idx,
- true /* resolve*/,
- pointer_size);
+ ObjPtr<mirror::Class> param_type(m->GetClassFromTypeIndex(type_idx,
+ true /* resolve*/,
+ pointer_size));
if (param_type == nullptr) {
CHECK(self->IsExceptionPending());
LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
@@ -376,7 +378,7 @@
// TODO: There is a compaction bug here since GetClassFromTypeIdx can cause thread suspension,
// this is a hard to fix problem since the args can contain Object*, we need to save and
// restore them by using a visitor similar to the ones used in the trampoline entrypoints.
- mirror::Object* argument =
+ ObjPtr<mirror::Object> argument =
(reinterpret_cast<StackReference<mirror::Object>*>(&args[i + offset]))->AsMirrorPtr();
if (argument != nullptr && !argument->InstanceOf(param_type)) {
LOG(ERROR) << "JNI ERROR (app bug): attempt to pass an instance of "
@@ -423,7 +425,7 @@
}
}
-static ArtMethod* FindVirtualMethod(mirror::Object* receiver, ArtMethod* method)
+static ArtMethod* FindVirtualMethod(ObjPtr<mirror::Object> receiver, ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_) {
return receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(method, kRuntimePointerSize);
}
@@ -457,7 +459,7 @@
// Replace calls to String.<init> with equivalent StringFactory call.
method = WellKnownClasses::StringInitToStringFactory(method);
}
- mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
+ ObjPtr<mirror::Object> receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
uint32_t shorty_len = 0;
const char* shorty =
method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
@@ -488,7 +490,7 @@
// Replace calls to String.<init> with equivalent StringFactory call.
method = WellKnownClasses::StringInitToStringFactory(method);
}
- mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
+ ObjPtr<mirror::Object> receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
uint32_t shorty_len = 0;
const char* shorty =
method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
@@ -513,7 +515,7 @@
return JValue();
}
- mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
+ ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object*>(obj);
ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
if (is_string_init) {
@@ -545,7 +547,7 @@
return JValue();
}
- mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
+ ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object*>(obj);
ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
if (is_string_init) {
@@ -578,21 +580,21 @@
return nullptr;
}
- auto* executable = soa.Decode<mirror::Executable*>(javaMethod);
+ ObjPtr<mirror::Executable> executable = soa.Decode<mirror::Executable*>(javaMethod);
const bool accessible = executable->IsAccessible();
ArtMethod* m = executable->GetArtMethod();
- mirror::Class* declaring_class = m->GetDeclaringClass();
+ ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClass();
if (UNLIKELY(!declaring_class->IsInitialized())) {
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::Class> h_class(hs.NewHandle(declaring_class));
+ Handle<mirror::Class> h_class(hs.NewHandle(declaring_class.Decode()));
if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(soa.Self(), h_class, true, true)) {
return nullptr;
}
declaring_class = h_class.Get();
}
- mirror::Object* receiver = nullptr;
+ ObjPtr<mirror::Object> receiver;
if (!m->IsStatic()) {
// Replace calls to String.<init> with equivalent StringFactory call.
if (declaring_class->IsStringClass() && m->IsConstructor()) {
@@ -623,7 +625,7 @@
}
// If method is not set to be accessible, verify it can be accessed by the caller.
- mirror::Class* calling_class = nullptr;
+ ObjPtr<mirror::Class> calling_class;
if (!accessible && !VerifyAccess(soa.Self(),
receiver,
declaring_class,
@@ -674,10 +676,11 @@
}
// Box if necessary and return.
- return soa.AddLocalReference<jobject>(BoxPrimitive(Primitive::GetType(shorty[0]), result));
+ return soa.AddLocalReference<jobject>(
+ BoxPrimitive(Primitive::GetType(shorty[0]), result).Decode());
}
-mirror::Object* BoxPrimitive(Primitive::Type src_class, const JValue& value) {
+ObjPtr<mirror::Object> BoxPrimitive(Primitive::Type src_class, const JValue& value) {
if (src_class == Primitive::kPrimNot) {
return value.GetL();
}
@@ -750,8 +753,9 @@
return "result";
}
-static bool UnboxPrimitive(mirror::Object* o,
- mirror::Class* dst_class, ArtField* f,
+static bool UnboxPrimitive(ObjPtr<mirror::Object> o,
+ ObjPtr<mirror::Class> dst_class,
+ ArtField* f,
JValue* unboxed_value)
REQUIRES_SHARED(Locks::mutator_lock_) {
bool unbox_for_result = (f == nullptr);
@@ -769,7 +773,7 @@
}
return false;
}
- unboxed_value->SetL(o);
+ unboxed_value->SetL(o.Decode());
return true;
}
if (UNLIKELY(dst_class->GetPrimitiveType() == Primitive::kPrimVoid)) {
@@ -791,34 +795,34 @@
}
JValue boxed_value;
- mirror::Class* klass = o->GetClass();
- mirror::Class* src_class = nullptr;
+ ObjPtr<mirror::Class> klass = o->GetClass();
+ ObjPtr<mirror::Class> src_class = nullptr;
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
ArtField* primitive_field = &klass->GetIFieldsPtr()->At(0);
if (klass->DescriptorEquals("Ljava/lang/Boolean;")) {
src_class = class_linker->FindPrimitiveClass('Z');
- boxed_value.SetZ(primitive_field->GetBoolean(o));
+ boxed_value.SetZ(primitive_field->GetBoolean(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Byte;")) {
src_class = class_linker->FindPrimitiveClass('B');
- boxed_value.SetB(primitive_field->GetByte(o));
+ boxed_value.SetB(primitive_field->GetByte(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Character;")) {
src_class = class_linker->FindPrimitiveClass('C');
- boxed_value.SetC(primitive_field->GetChar(o));
+ boxed_value.SetC(primitive_field->GetChar(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Float;")) {
src_class = class_linker->FindPrimitiveClass('F');
- boxed_value.SetF(primitive_field->GetFloat(o));
+ boxed_value.SetF(primitive_field->GetFloat(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Double;")) {
src_class = class_linker->FindPrimitiveClass('D');
- boxed_value.SetD(primitive_field->GetDouble(o));
+ boxed_value.SetD(primitive_field->GetDouble(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Integer;")) {
src_class = class_linker->FindPrimitiveClass('I');
- boxed_value.SetI(primitive_field->GetInt(o));
+ boxed_value.SetI(primitive_field->GetInt(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Long;")) {
src_class = class_linker->FindPrimitiveClass('J');
- boxed_value.SetJ(primitive_field->GetLong(o));
+ boxed_value.SetJ(primitive_field->GetLong(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Short;")) {
src_class = class_linker->FindPrimitiveClass('S');
- boxed_value.SetS(primitive_field->GetShort(o));
+ boxed_value.SetS(primitive_field->GetShort(o.Decode()));
} else {
std::string temp;
ThrowIllegalArgumentException(
@@ -833,28 +837,36 @@
boxed_value, unboxed_value);
}
-bool UnboxPrimitiveForField(mirror::Object* o, mirror::Class* dst_class, ArtField* f,
+bool UnboxPrimitiveForField(ObjPtr<mirror::Object> o,
+ ObjPtr<mirror::Class> dst_class,
+ ArtField* f,
JValue* unboxed_value) {
DCHECK(f != nullptr);
return UnboxPrimitive(o, dst_class, f, unboxed_value);
}
-bool UnboxPrimitiveForResult(mirror::Object* o, mirror::Class* dst_class, JValue* unboxed_value) {
+bool UnboxPrimitiveForResult(ObjPtr<mirror::Object> o,
+ ObjPtr<mirror::Class> dst_class,
+ JValue* unboxed_value) {
return UnboxPrimitive(o, dst_class, nullptr, unboxed_value);
}
-mirror::Class* GetCallingClass(Thread* self, size_t num_frames) {
+ObjPtr<mirror::Class> GetCallingClass(Thread* self, size_t num_frames) {
NthCallerVisitor visitor(self, num_frames);
visitor.WalkStack();
return visitor.caller != nullptr ? visitor.caller->GetDeclaringClass() : nullptr;
}
-bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class,
- uint32_t access_flags, mirror::Class** calling_class, size_t num_frames) {
+bool VerifyAccess(Thread* self,
+ ObjPtr<mirror::Object> obj,
+ ObjPtr<mirror::Class> declaring_class,
+ uint32_t access_flags,
+ ObjPtr<mirror::Class>* calling_class,
+ size_t num_frames) {
if ((access_flags & kAccPublic) != 0) {
return true;
}
- auto* klass = GetCallingClass(self, num_frames);
+ ObjPtr<mirror::Class> klass = GetCallingClass(self, num_frames);
if (UNLIKELY(klass == nullptr)) {
// The caller is an attached native thread.
return false;
@@ -863,10 +875,10 @@
return VerifyAccess(obj, declaring_class, access_flags, klass);
}
-bool VerifyAccess(mirror::Object* obj,
- mirror::Class* declaring_class,
+bool VerifyAccess(ObjPtr<mirror::Object> obj,
+ ObjPtr<mirror::Class> declaring_class,
uint32_t access_flags,
- mirror::Class* calling_class) {
+ ObjPtr<mirror::Class> calling_class) {
if (calling_class == declaring_class) {
return true;
}
@@ -876,16 +888,16 @@
}
if ((access_flags & kAccProtected) != 0) {
if (obj != nullptr && !obj->InstanceOf(calling_class) &&
- !declaring_class->IsInSamePackage(calling_class)) {
+ !declaring_class->IsInSamePackage(calling_class.Decode())) {
return false;
- } else if (declaring_class->IsAssignableFrom(calling_class)) {
+ } else if (declaring_class->IsAssignableFrom(calling_class.Decode())) {
return true;
}
}
- return declaring_class->IsInSamePackage(calling_class);
+ return declaring_class->IsInSamePackage(calling_class.Decode());
}
-void InvalidReceiverError(mirror::Object* o, mirror::Class* c) {
+void InvalidReceiverError(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c) {
std::string expected_class_name(PrettyDescriptor(c));
std::string actual_class_name(PrettyTypeOf(o));
ThrowIllegalArgumentException(StringPrintf("Expected receiver of type %s, but got %s",
@@ -895,18 +907,18 @@
// This only works if there's one reference which points to the object in obj.
// Will need to be fixed if there's cases where it's not.
-void UpdateReference(Thread* self, jobject obj, mirror::Object* result) {
+void UpdateReference(Thread* self, jobject obj, ObjPtr<mirror::Object> result) {
IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
IndirectRefKind kind = GetIndirectRefKind(ref);
if (kind == kLocal) {
- self->GetJniEnv()->locals.Update(obj, result);
+ self->GetJniEnv()->locals.Update(obj, result.Decode());
} else if (kind == kHandleScopeOrInvalid) {
LOG(FATAL) << "Unsupported UpdateReference for kind kHandleScopeOrInvalid";
} else if (kind == kGlobal) {
- self->GetJniEnv()->vm->UpdateGlobal(self, ref, result);
+ self->GetJniEnv()->vm->UpdateGlobal(self, ref, result.Decode());
} else {
DCHECK_EQ(kind, kWeakGlobal);
- self->GetJniEnv()->vm->UpdateWeakGlobal(self, ref, result);
+ self->GetJniEnv()->vm->UpdateWeakGlobal(self, ref, result.Decode());
}
}
diff --git a/runtime/reflection.h b/runtime/reflection.h
index 208b533..6e5ef71 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -19,6 +19,7 @@
#include "base/mutex.h"
#include "jni.h"
+#include "obj_ptr.h"
#include "primitive.h"
namespace art {
@@ -32,62 +33,85 @@
class ScopedObjectAccessAlreadyRunnable;
class ShadowFrame;
-mirror::Object* BoxPrimitive(Primitive::Type src_class, const JValue& value)
+ObjPtr<mirror::Object> BoxPrimitive(Primitive::Type src_class, const JValue& value)
REQUIRES_SHARED(Locks::mutator_lock_);
-bool UnboxPrimitiveForField(mirror::Object* o, mirror::Class* dst_class, ArtField* f,
+
+bool UnboxPrimitiveForField(ObjPtr<mirror::Object> o,
+ ObjPtr<mirror::Class> dst_class,
+ ArtField* f,
JValue* unboxed_value)
REQUIRES_SHARED(Locks::mutator_lock_);
-bool UnboxPrimitiveForResult(mirror::Object* o, mirror::Class* dst_class, JValue* unboxed_value)
+
+bool UnboxPrimitiveForResult(ObjPtr<mirror::Object> o,
+ ObjPtr<mirror::Class> dst_class,
+ JValue* unboxed_value)
REQUIRES_SHARED(Locks::mutator_lock_);
ALWAYS_INLINE bool ConvertPrimitiveValue(bool unbox_for_result,
- Primitive::Type src_class, Primitive::Type dst_class,
- const JValue& src, JValue* dst)
+ Primitive::Type src_class,
+ Primitive::Type dst_class,
+ const JValue& src,
+ JValue* dst)
REQUIRES_SHARED(Locks::mutator_lock_);
-JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
+JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
+ jobject obj,
+ jmethodID mid,
va_list args)
REQUIRES_SHARED(Locks::mutator_lock_);
-JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
+JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
+ jobject obj,
+ jmethodID mid,
jvalue* args)
REQUIRES_SHARED(Locks::mutator_lock_);
JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
- jobject obj, jmethodID mid, jvalue* args)
+ jobject obj,
+ jmethodID mid,
+ jvalue* args)
REQUIRES_SHARED(Locks::mutator_lock_);
JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
- jobject obj, jmethodID mid, va_list args)
+ jobject obj,
+ jmethodID mid,
+ va_list args)
REQUIRES_SHARED(Locks::mutator_lock_);
// num_frames is number of frames we look up for access check.
-jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject method, jobject receiver,
- jobject args, size_t num_frames = 1)
+jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa,
+ jobject method,
+ jobject receiver,
+ jobject args,
+ size_t num_frames = 1)
REQUIRES_SHARED(Locks::mutator_lock_);
-ALWAYS_INLINE bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c)
+ALWAYS_INLINE bool VerifyObjectIsClass(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c)
REQUIRES_SHARED(Locks::mutator_lock_);
-bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class,
- uint32_t access_flags, mirror::Class** calling_class, size_t num_frames)
+bool VerifyAccess(Thread* self,
+ ObjPtr<mirror::Object> obj,
+ ObjPtr<mirror::Class> declaring_class,
+ uint32_t access_flags,
+ ObjPtr<mirror::Class>* calling_class,
+ size_t num_frames)
REQUIRES_SHARED(Locks::mutator_lock_);
// This version takes a known calling class.
-bool VerifyAccess(mirror::Object* obj,
- mirror::Class* declaring_class,
+bool VerifyAccess(ObjPtr<mirror::Object> obj,
+ ObjPtr<mirror::Class> declaring_class,
uint32_t access_flags,
- mirror::Class* calling_class)
+ ObjPtr<mirror::Class> calling_class)
REQUIRES_SHARED(Locks::mutator_lock_);
// Get the calling class by using a stack visitor, may return null for unattached native threads.
-mirror::Class* GetCallingClass(Thread* self, size_t num_frames)
+ObjPtr<mirror::Class> GetCallingClass(Thread* self, size_t num_frames)
REQUIRES_SHARED(Locks::mutator_lock_);
-void InvalidReceiverError(mirror::Object* o, mirror::Class* c)
+void InvalidReceiverError(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c)
REQUIRES_SHARED(Locks::mutator_lock_);
-void UpdateReference(Thread* self, jobject obj, mirror::Object* result)
+void UpdateReference(Thread* self, jobject obj, ObjPtr<mirror::Object> result)
REQUIRES_SHARED(Locks::mutator_lock_);
} // namespace art
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 298a974..bb6eb79 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -59,6 +59,8 @@
if (UNLIKELY(TestAllFlags())) {
CheckSuspend();
}
+ // Invalidate the current thread's object pointers (ObjPtr) to catch possible moving GC bugs due
+ // to missing handles.
PoisonObjectPointers();
}
@@ -173,6 +175,9 @@
inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) {
AssertThreadSuspensionIsAllowable();
+ if (kIsDebugBuild) {
+ PoisonObjectPointers();
+ }
DCHECK_EQ(this, Thread::Current());
// Change to non-runnable state, thereby appearing suspended to the system.
TransitionToSuspendedAndRunCheckpoints(new_state);
@@ -303,6 +308,12 @@
tlsPtr_.thread_local_alloc_stack_top = nullptr;
}
+inline void Thread::PoisonObjectPointersIfDebug() {
+ if (kIsDebugBuild) {
+ Thread::Current()->PoisonObjectPointers();
+ }
+}
+
} // namespace art
#endif // ART_RUNTIME_THREAD_INL_H_
diff --git a/runtime/thread.h b/runtime/thread.h
index fb6bde6..55f1489 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -475,6 +475,8 @@
++poison_object_cookie_;
}
+ ALWAYS_INLINE static void PoisonObjectPointersIfDebug();
+
ALWAYS_INLINE uintptr_t GetPoisonObjectCookie() const {
return poison_object_cookie_;
}
diff --git a/runtime/utils.cc b/runtime/utils.cc
index b52e2f2..0803ca7 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -37,6 +37,7 @@
#include "mirror/object_array-inl.h"
#include "mirror/string.h"
#include "oat_quick_method_header.h"
+#include "obj_ptr-inl.h"
#include "os.h"
#include "scoped_thread_state_change.h"
#include "utf-inl.h"
@@ -270,14 +271,14 @@
}
}
-std::string PrettyDescriptor(mirror::String* java_descriptor) {
+std::string PrettyStringDescriptor(ObjPtr<mirror::String> java_descriptor) {
if (java_descriptor == nullptr) {
return "null";
}
return PrettyDescriptor(java_descriptor->ToModifiedUtf8().c_str());
}
-std::string PrettyDescriptor(mirror::Class* klass) {
+std::string PrettyDescriptor(ObjPtr<mirror::Class> klass) {
if (klass == nullptr) {
return "null";
}
@@ -456,7 +457,7 @@
return result;
}
-std::string PrettyTypeOf(mirror::Object* obj) {
+std::string PrettyTypeOf(ObjPtr<mirror::Object> obj) {
if (obj == nullptr) {
return "null";
}
@@ -471,7 +472,7 @@
return result;
}
-std::string PrettyClass(mirror::Class* c) {
+std::string PrettyClass(ObjPtr<mirror::Class> c) {
if (c == nullptr) {
return "null";
}
@@ -482,7 +483,7 @@
return result;
}
-std::string PrettyClassAndClassLoader(mirror::Class* c) {
+std::string PrettyClassAndClassLoader(ObjPtr<mirror::Class> c) {
if (c == nullptr) {
return "null";
}
diff --git a/runtime/utils.h b/runtime/utils.h
index e65b947..ea9e8f7 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -33,6 +33,7 @@
#include "base/mutex.h"
#include "base/stringpiece.h"
#include "globals.h"
+#include "obj_ptr.h"
#include "primitive.h"
class BacktraceMap;
@@ -135,10 +136,10 @@
// Returns a human-readable equivalent of 'descriptor'. So "I" would be "int",
// "[[I" would be "int[][]", "[Ljava/lang/String;" would be
// "java.lang.String[]", and so forth.
-std::string PrettyDescriptor(mirror::String* descriptor)
+std::string PrettyStringDescriptor(ObjPtr<mirror::String> descriptor)
REQUIRES_SHARED(Locks::mutator_lock_);
std::string PrettyDescriptor(const char* descriptor);
-std::string PrettyDescriptor(mirror::Class* klass)
+std::string PrettyDescriptor(ObjPtr<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_);
std::string PrettyDescriptor(Primitive::Type type);
@@ -158,7 +159,7 @@
// So given an instance of java.lang.String, the output would
// be "java.lang.String". Given an array of int, the output would be "int[]".
// Given String.class, the output would be "java.lang.Class<java.lang.String>".
-std::string PrettyTypeOf(mirror::Object* obj)
+std::string PrettyTypeOf(ObjPtr<mirror::Object> obj)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns a human-readable form of the type at an index in the specified dex file.
@@ -167,11 +168,11 @@
// Returns a human-readable form of the name of the given class.
// Given String.class, the output would be "java.lang.Class<java.lang.String>".
-std::string PrettyClass(mirror::Class* c)
+std::string PrettyClass(ObjPtr<mirror::Class> c)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns a human-readable form of the name of the given class with its class loader.
-std::string PrettyClassAndClassLoader(mirror::Class* c)
+std::string PrettyClassAndClassLoader(ObjPtr<mirror::Class> c)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns a human-readable version of the Java part of the access flags, e.g., "private static "