diff options
Diffstat (limited to 'runtime/mirror/object.cc')
-rw-r--r-- | runtime/mirror/object.cc | 64 |
1 files changed, 41 insertions, 23 deletions
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc index 87d02c9469..385ef5ff89 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -39,38 +39,48 @@ namespace art { namespace mirror { -Object* Object::Clone(Thread* self) { - mirror::Class* c = GetClass(); - DCHECK(!c->IsClassClass()); - // Object::SizeOf gets the right size even if we're an array. - // Using c->AllocObject() here would be wrong. - size_t num_bytes = SizeOf(); - gc::Heap* heap = Runtime::Current()->GetHeap(); - SirtRef<mirror::Object> sirt_this(self, this); - Object* copy = heap->AllocObject(self, c, num_bytes); - if (UNLIKELY(copy == nullptr)) { - return nullptr; - } +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. // TODO: expose and use move32. - byte* src_bytes = reinterpret_cast<byte*>(sirt_this.get()); - byte* dst_bytes = reinterpret_cast<byte*>(copy); + byte* src_bytes = reinterpret_cast<byte*>(src); + byte* dst_bytes = reinterpret_cast<byte*>(dest); size_t offset = sizeof(Object); memcpy(dst_bytes + offset, src_bytes + offset, num_bytes - offset); + gc::Heap* heap = Runtime::Current()->GetHeap(); // Perform write barriers on copied object references. - c = copy->GetClass(); // Re-read Class in case it moved. + Class* c = src->GetClass(); if (c->IsArrayClass()) { if (!c->GetComponentType()->IsPrimitive()) { - const ObjectArray<Object>* array = copy->AsObjectArray<Object>(); - heap->WriteBarrierArray(copy, 0, array->GetLength()); + const ObjectArray<Object>* array = dest->AsObjectArray<Object>(); + heap->WriteBarrierArray(dest, 0, array->GetLength()); } } else { - heap->WriteBarrierEveryFieldOf(copy); + heap->WriteBarrierEveryFieldOf(dest); } if (c->IsFinalizable()) { - SirtRef<mirror::Object> sirt_copy(self, copy); - heap->AddFinalizerReference(self, copy); - return sirt_copy.get(); + SirtRef<Object> sirt_dest(self, dest); + heap->AddFinalizerReference(self, dest); + return sirt_dest.get(); + } + return dest; +} + +Object* Object::Clone(Thread* self) { + CHECK(!IsClass()) << "Can't clone classes."; + // Object::SizeOf gets the right size even if we're an array. Using c->AllocObject() here would + // be wrong. + gc::Heap* heap = Runtime::Current()->GetHeap(); + size_t num_bytes = SizeOf(); + SirtRef<Object> this_object(self, this); + Object* copy; + if (heap->IsMovableObject(this)) { + copy = heap->AllocObject(self, GetClass(), num_bytes); + } else { + copy = heap->AllocNonMovableObject(self, GetClass(), num_bytes); + } + if (LIKELY(copy != nullptr)) { + return CopyObject(self, copy, this_object.get(), num_bytes); } return copy; } @@ -87,8 +97,9 @@ int32_t Object::GenerateIdentityHashCode() { } int32_t Object::IdentityHashCode() const { + mirror::Object* current_this = const_cast<mirror::Object*>(this); while (true) { - LockWord lw = GetLockWord(); + LockWord lw = current_this->GetLockWord(); switch (lw.GetState()) { case LockWord::kUnlocked: { // Try to compare and swap in a new hash, if we succeed we will return the hash on the next @@ -103,7 +114,10 @@ int32_t Object::IdentityHashCode() const { case LockWord::kThinLocked: { // Inflate the thin lock to a monitor and stick the hash code inside of the monitor. Thread* self = Thread::Current(); - Monitor::InflateThinLocked(self, const_cast<Object*>(this), lw, GenerateIdentityHashCode()); + SirtRef<mirror::Object> sirt_this(self, current_this); + Monitor::InflateThinLocked(self, sirt_this, lw, GenerateIdentityHashCode()); + // A GC may have occurred when we switched to kBlocked. + current_this = sirt_this.get(); break; } case LockWord::kFatLocked: { @@ -115,6 +129,10 @@ int32_t Object::IdentityHashCode() const { case LockWord::kHashCode: { return lw.GetHashCode(); } + default: { + LOG(FATAL) << "Invalid state during hashcode " << lw.GetState(); + break; + } } } LOG(FATAL) << "Unreachable"; |