class CopyReferenceFieldsWithReadBarrierVisitor { public: explicit CopyReferenceFieldsWithReadBarrierVisitor(ObjPtr<Object> dest_obj)
: dest_obj_(dest_obj) {}
voidoperator()(ObjPtr<Object> obj, MemberOffset offset, bool/* is_static */) const
ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) { // GetFieldObject() contains a RB.
ObjPtr<Object> ref = obj->GetFieldObject<Object>(offset); // 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);
}
// Unused since we don't copy class native roots. void VisitRootIfNonNull(
[[maybe_unused]] mirror::CompressedReference<mirror::Object>* root) const {} void VisitRoot([[maybe_unused]] mirror::CompressedReference<mirror::Object>* root) const {}
private: const ObjPtr<Object> dest_obj_;
};
void Object::CopyRawObjectData(uint8_t* dst_bytes,
ObjPtr<mirror::Object> src,
size_t num_bytes) { // Copy instance data. Don't assume memcpy copies by words (b/32012820). const size_t offset = sizeof(Object);
uint8_t* src_bytes = reinterpret_cast<uint8_t*>(src.Ptr()) + offset;
dst_bytes += offset;
DCHECK_ALIGNED(src_bytes, sizeof(uintptr_t));
DCHECK_ALIGNED(dst_bytes, sizeof(uintptr_t)); // Use word sized copies to begin. while (num_bytes >= sizeof(uintptr_t)) { reinterpret_cast<Atomic<uintptr_t>*>(dst_bytes)->store( reinterpret_cast<Atomic<uintptr_t>*>(src_bytes)->load(std::memory_order_relaxed),
std::memory_order_relaxed);
src_bytes += sizeof(uintptr_t);
dst_bytes += sizeof(uintptr_t);
num_bytes -= sizeof(uintptr_t);
} // Copy possible 32 bit word. if (sizeof(uintptr_t) != sizeof(uint32_t) && num_bytes >= sizeof(uint32_t)) { reinterpret_cast<Atomic<uint32_t>*>(dst_bytes)->store( reinterpret_cast<Atomic<uint32_t>*>(src_bytes)->load(std::memory_order_relaxed),
std::memory_order_relaxed);
src_bytes += sizeof(uint32_t);
dst_bytes += sizeof(uint32_t);
num_bytes -= sizeof(uint32_t);
} // Copy remaining bytes, avoid going past the end of num_bytes since there may be a redzone // there. while (num_bytes > 0) { reinterpret_cast<Atomic<uint8_t>*>(dst_bytes)->store( reinterpret_cast<Atomic<uint8_t>*>(src_bytes)->load(std::memory_order_relaxed),
std::memory_order_relaxed);
src_bytes += sizeof(uint8_t);
dst_bytes += sizeof(uint8_t);
num_bytes -= sizeof(uint8_t);
}
}
ObjPtr<Object> Object::CopyObject(ObjPtr<mirror::Object> dest,
ObjPtr<mirror::Object> src,
size_t num_bytes) { // Copy everything but the header.
CopyRawObjectData(reinterpret_cast<uint8_t*>(dest.Ptr()), src, num_bytes - sizeof(Object));
if (gUseReadBarrier) { // We need a RB here. After copying the whole object above, copy references fields one by one // again with a RB to make sure there are no from space refs. TODO: Optimize this later?
CopyReferenceFieldsWithReadBarrierVisitor visitor(dest);
src->VisitReferences(visitor, visitor);
} // Perform write barriers on copied object references.
ObjPtr<Class> c = src->GetClass(); if (c->IsArrayClass()) { if (!c->GetComponentType()->IsPrimitive()) {
ObjPtr<ObjectArray<Object>> array = dest->AsObjectArray<Object>();
WriteBarrier::ForArrayWrite(dest, 0, array->GetLength());
}
} else {
WriteBarrier::ForEveryFieldWrite(dest);
} return dest;
}
// An allocation pre-fence visitor that copies the object. class CopyObjectVisitor { public:
CopyObjectVisitor(Handle<Object>* orig, size_t num_bytes)
: orig_(orig), num_bytes_(num_bytes) {}
template <bool kAllowInflation>
int32_t Object::IdentityHashCodeHelper() {
ObjPtr<Object> current_this = this; // The this pointer may get invalidated by thread suspension. while (true) {
LockWord lw = current_this->GetLockWord(false); 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 // loop iteration.
LockWord hash_word = LockWord::FromHashCode(GenerateIdentityHashCode(), lw.GCState());
DCHECK_EQ(hash_word.GetState(), LockWord::kHashCode); // Use a strong CAS to prevent spurious failures since these can make the boot image // non-deterministic. if (current_this->CasLockWord(lw, hash_word, CASMode::kStrong, std::memory_order_relaxed)) { return hash_word.GetHashCode();
} break;
} case LockWord::kThinLocked: { if (!kAllowInflation) { return0;
} // Inflate the thin lock to a monitor and stick the hash code inside of the monitor. May // fail spuriously.
Thread* self = Thread::Current();
StackHandleScope<1> hs(self);
Handle<mirror::Object> h_this(hs.NewHandle(current_this));
Monitor::InflateThinLocked(self, h_this, lw, GenerateIdentityHashCode()); // A GC may have occurred when we switched to kBlocked.
current_this = h_this.Get(); break;
} case LockWord::kFatLocked: { // Already inflated, return the hash stored in the monitor.
Monitor* monitor = lw.FatLockMonitor();
DCHECK(monitor != nullptr); return monitor->GetHashCode();
} case LockWord::kHashCode: { return lw.GetHashCode();
} default: {
LOG(FATAL) << "Invalid state during hashcode " << lw.GetState();
UNREACHABLE();
}
}
}
}
void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, ObjPtr<Object> new_value) {
ObjPtr<Class> c = GetClass();
Runtime* runtime = Runtime::Current(); if (runtime->GetClassLinker() == nullptr || !runtime->IsStarted() ||
!runtime->GetHeap()->IsObjectValidationEnabled() || !c->IsResolved()) { return;
} for (ObjPtr<Class> cur = c; cur != nullptr; cur = cur->GetSuperClass()) { for (ArtField& field : cur->GetFields()) { if (!field.IsStatic() && field.GetOffset().Int32Value() == field_offset.Int32Value()) {
CHECK_NE(field.GetTypeAsPrimitiveType(), Primitive::kPrimNot); // TODO: resolve the field type for moving GC.
ObjPtr<mirror::Class> field_type =
kMovingCollector ? field.LookupResolvedType() : field.ResolveType(); if (field_type != nullptr) {
CHECK(field_type->IsAssignableFrom(new_value->GetClass()));
} return;
}
}
} if (c->IsArrayClass()) { // Bounds and assign-ability done in the array setter. return;
} if (IsClass()) { for (ArtField& field : AsClass()->GetFields()) { if (field.IsStatic() && field.GetOffset().Int32Value() == field_offset.Int32Value()) {
CHECK_NE(field.GetTypeAsPrimitiveType(), Primitive::kPrimNot); // TODO: resolve the field type for moving GC.
ObjPtr<mirror::Class> field_type =
kMovingCollector ? field.LookupResolvedType() : field.ResolveType(); if (field_type != nullptr) {
CHECK(field_type->IsAssignableFrom(new_value->GetClass()));
} return;
}
}
}
LOG(FATAL) << "Failed to find field for assignment to " << reinterpret_cast<void*>(this)
<< " of type " << c->PrettyDescriptor() << " at offset " << field_offset;
UNREACHABLE();
}
std::string Object::PrettyTypeOf() { // From-space version is the same as the to-space version since the dex file never changes. // Avoiding the read barrier here is important to prevent recursive AssertToSpaceInvariant // issues.
ObjPtr<mirror::Class> klass = GetClass<kDefaultVerifyFlags, kWithoutReadBarrier>(); if (klass == nullptr) { return"(raw)";
}
std::string temp;
std::string result(PrettyDescriptor(klass->GetDescriptor(&temp))); if (klass->IsClassClass()) {
result += "<" + PrettyDescriptor(AsClass()->GetDescriptor(&temp)) + ">";
} return result;
}
} // namespace mirror
} // namespace art
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.9Bemerkung:
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.