namespace art {
namespace mirror {
+class CopyReferenceFieldsWithReadBarrierVisitor {
+ public:
+ explicit CopyReferenceFieldsWithReadBarrierVisitor(Object* dest_obj)
+ : dest_obj_(dest_obj) {}
+
+ void operator()(Object* obj, MemberOffset offset, bool /* is_static */) const
+ ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // GetFieldObject() contains a RB.
+ Object* ref = obj->GetFieldObject<Object>(offset, false);
+ // No WB here as a large object space does not have a card table
+ // coverage. Instead, cards will be marked separately.
+ dest_obj_->SetFieldObjectWithoutWriteBarrier<false, false>(offset, ref, false);
+ }
+
+ void operator()(mirror::Class* klass, mirror::Reference* ref) const
+ ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Copy java.lang.ref.Reference.referent which isn't visited in
+ // Object::VisitReferences().
+ DCHECK(klass->IsReferenceClass());
+ this->operator()(ref, mirror::Reference::ReferentOffset(), false);
+ }
+
+ private:
+ Object* const dest_obj_;
+};
+
static Object* CopyObject(Thread* self, mirror::Object* dest, mirror::Object* src, size_t num_bytes)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// Copy instance data. We assume memcpy copies by words.
byte* dst_bytes = reinterpret_cast<byte*>(dest);
size_t offset = sizeof(Object);
memcpy(dst_bytes + offset, src_bytes + offset, num_bytes - offset);
+ if (kUseBakerOrBrooksReadBarrier) {
+ // We need a RB here. After the memcpy that covers the whole
+ // object above, copy references fields one by one again with a
+ // RB. TODO: Optimize this later?
+ CopyReferenceFieldsWithReadBarrierVisitor visitor(dest);
+ src->VisitReferences<true>(visitor, visitor);
+ }
gc::Heap* heap = Runtime::Current()->GetHeap();
// Perform write barriers on copied object references.
Class* c = src->GetClass();
CHECK_EQ(sizeof(HeapReference<T>), sizeof(uint32_t));
IntArray* dstAsIntArray = reinterpret_cast<IntArray*>(this);
IntArray* srcAsIntArray = reinterpret_cast<IntArray*>(src);
- dstAsIntArray->Memmove(dst_pos, srcAsIntArray, src_pos, count);
+ if (kUseBakerOrBrooksReadBarrier) {
+ // TODO: Optimize this later?
+ const bool copy_forward = (src != this) || (dst_pos < src_pos) || (dst_pos - src_pos >= count);
+ if (copy_forward) {
+ // Forward copy.
+ for (int i = 0; i < count; ++i) {
+ // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB.
+ Object* obj = src->GetWithoutChecks(src_pos + i);
+ SetWithoutChecks<false>(dst_pos + i, obj);
+ }
+ } else {
+ // Backward copy.
+ for (int i = count - 1; i >= 0; --i) {
+ // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB.
+ Object* obj = src->GetWithoutChecks(src_pos + i);
+ SetWithoutChecks<false>(dst_pos + i, obj);
+ }
+ }
+ } else {
+ dstAsIntArray->Memmove(dst_pos, srcAsIntArray, src_pos, count);
+ }
Runtime::Current()->GetHeap()->WriteBarrierArray(this, dst_pos, count);
if (kIsDebugBuild) {
for (int i = 0; i < count; ++i) {
CHECK_EQ(sizeof(HeapReference<T>), sizeof(uint32_t));
IntArray* dstAsIntArray = reinterpret_cast<IntArray*>(this);
IntArray* srcAsIntArray = reinterpret_cast<IntArray*>(src);
- dstAsIntArray->Memcpy(dst_pos, srcAsIntArray, src_pos, count);
+ if (kUseBakerOrBrooksReadBarrier) {
+ // TODO: Optimize this later?
+ for (int i = 0; i < count; ++i) {
+ // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB.
+ T* obj = src->GetWithoutChecks(src_pos + i);
+ SetWithoutChecks<false>(dst_pos + i, obj);
+ }
+ } else {
+ dstAsIntArray->Memcpy(dst_pos, srcAsIntArray, src_pos, count);
+ }
Runtime::Current()->GetHeap()->WriteBarrierArray(this, dst_pos, count);
if (kIsDebugBuild) {
for (int i = 0; i < count; ++i) {
int i = 0;
for (; i < count; ++i) {
// The follow get operations force the objects to be verified.
+ // We need a RB here. ObjectArray::GetWithoutChecks() contains a RB.
o = src->GetWithoutChecks(src_pos + i);
if (o == nullptr) {
// Null is always assignable.