More code for the read barrier support.
Make it possible to disable the RB in Object::SizeOf() (and the
functions it calls transitively) which the collector will need to call
to get the size of an object when copying.
Add Object::AtomicSetReadBarrierPointer() for atomic write of a RB
pointer.
Bug: 12687968
Change-Id: Ibedd252860ac7ccd17e4e7d71b377a8892b48ff0
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index a6db387..fd4b5ff 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -34,9 +34,10 @@
namespace art {
namespace mirror {
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
inline Class* Object::GetClass() {
- return GetFieldObject<Class, kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, klass_), false);
+ return GetFieldObject<Class, kVerifyFlags, kDoReadBarrier>(
+ OFFSET_OF_OBJECT_MEMBER(Object, klass_), false);
}
template<VerifyObjectFlags kVerifyFlags>
@@ -104,18 +105,45 @@
#endif
}
-inline void Object::SetReadBarrierPointer(Object* rb_pointer) {
+inline void Object::SetReadBarrierPointer(Object* rb_ptr) {
#ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
DCHECK(kUseBakerOrBrooksReadBarrier);
// We don't mark the card as this occurs as part of object allocation. Not all objects have
// backing cards, such as large objects.
SetFieldObjectWithoutWriteBarrier<false, false, kVerifyNone>(
- OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_), rb_pointer, false);
+ OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_), rb_ptr, false);
#else
LOG(FATAL) << "Unreachable";
#endif
}
+inline bool Object::AtomicSetReadBarrierPointer(Object* expected_rb_ptr, Object* rb_ptr) {
+#ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
+ DCHECK(kUseBakerOrBrooksReadBarrier);
+ MemberOffset offset = OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_);
+ byte* raw_addr = reinterpret_cast<byte*>(this) + offset.SizeValue();
+ HeapReference<Object>* ref = reinterpret_cast<HeapReference<Object>*>(raw_addr);
+ HeapReference<Object> expected_ref(HeapReference<Object>::FromMirrorPtr(expected_rb_ptr));
+ HeapReference<Object> new_ref(HeapReference<Object>::FromMirrorPtr(rb_ptr));
+ uint32_t expected_val = expected_ref.reference_;
+ uint32_t new_val;
+ do {
+ uint32_t old_val = ref->reference_;
+ if (old_val != expected_val) {
+ // Lost the race.
+ return false;
+ }
+ new_val = new_ref.reference_;
+ } while (!__sync_bool_compare_and_swap(
+ reinterpret_cast<uint32_t*>(raw_addr), expected_val, new_val));
+ DCHECK_EQ(new_val, ref->reference_);
+ return true;
+#else
+ LOG(FATAL) << "Unreachable";
+ return false;
+#endif
+}
+
inline void Object::AssertReadBarrierPointer() const {
if (kUseBakerReadBarrier) {
Object* obj = const_cast<Object*>(this);
@@ -146,16 +174,17 @@
return klass->IsAssignableFrom(GetClass<kVerifyFlags>());
}
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
inline bool Object::IsClass() {
- Class* java_lang_Class = GetClass<kVerifyFlags>()->GetClass();
- return GetClass<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>() ==
+ Class* java_lang_Class =
+ GetClass<kVerifyFlags, kDoReadBarrier>()->template GetClass<kVerifyFlags, kDoReadBarrier>();
+ return GetClass<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis), kDoReadBarrier>() ==
java_lang_Class;
}
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
inline Class* Object::AsClass() {
- DCHECK(IsClass<kVerifyFlags>());
+ DCHECK((IsClass<kVerifyFlags, kDoReadBarrier>()));
return down_cast<Class*>(this);
}
@@ -172,14 +201,15 @@
return down_cast<ObjectArray<T>*>(this);
}
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
inline bool Object::IsArrayInstance() {
- return GetClass<kVerifyFlags>()->IsArrayClass();
+ return GetClass<kVerifyFlags, kDoReadBarrier>()->
+ template IsArrayClass<kVerifyFlags, kDoReadBarrier>();
}
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
inline bool Object::IsArtField() {
- return GetClass<kVerifyFlags>()->IsArtFieldClass();
+ return GetClass<kVerifyFlags, kDoReadBarrier>()->template IsArtFieldClass<kDoReadBarrier>();
}
template<VerifyObjectFlags kVerifyFlags>
@@ -188,9 +218,9 @@
return down_cast<ArtField*>(this);
}
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
inline bool Object::IsArtMethod() {
- return GetClass<kVerifyFlags>()->IsArtMethodClass();
+ return GetClass<kVerifyFlags, kDoReadBarrier>()->template IsArtMethodClass<kDoReadBarrier>();
}
template<VerifyObjectFlags kVerifyFlags>
@@ -210,9 +240,9 @@
return down_cast<Reference*>(this);
}
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
inline Array* Object::AsArray() {
- DCHECK(IsArrayInstance<kVerifyFlags>());
+ DCHECK((IsArrayInstance<kVerifyFlags, kDoReadBarrier>()));
return down_cast<Array*>(this);
}
@@ -338,20 +368,21 @@
return GetClass<kVerifyFlags>()->IsPhantomReferenceClass();
}
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
inline size_t Object::SizeOf() {
size_t result;
constexpr auto kNewFlags = static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis);
- if (IsArrayInstance<kVerifyFlags>()) {
- result = AsArray<kNewFlags>()->template SizeOf<kNewFlags>();
- } else if (IsClass<kNewFlags>()) {
- result = AsClass<kNewFlags>()->template SizeOf<kNewFlags>();
+ if (IsArrayInstance<kVerifyFlags, kDoReadBarrier>()) {
+ result = AsArray<kNewFlags, kDoReadBarrier>()->template SizeOf<kNewFlags, kDoReadBarrier>();
+ } else if (IsClass<kNewFlags, kDoReadBarrier>()) {
+ result = AsClass<kNewFlags, kDoReadBarrier>()->template SizeOf<kNewFlags, kDoReadBarrier>();
} else {
- result = GetClass<kNewFlags>()->GetObjectSize();
+ result = GetClass<kNewFlags, kDoReadBarrier>()->GetObjectSize();
}
- DCHECK_GE(result, sizeof(Object)) << " class=" << PrettyTypeOf(GetClass<kNewFlags>());
- DCHECK(!IsArtField<kNewFlags>() || result == sizeof(ArtField));
- DCHECK(!IsArtMethod<kNewFlags>() || result == sizeof(ArtMethod));
+ DCHECK_GE(result, sizeof(Object))
+ << " class=" << PrettyTypeOf(GetClass<kNewFlags, kDoReadBarrier>());
+ DCHECK(!(IsArtField<kNewFlags, kDoReadBarrier>()) || result == sizeof(ArtField));
+ DCHECK(!(IsArtMethod<kNewFlags, kDoReadBarrier>()) || result == sizeof(ArtMethod));
return result;
}