diff --git a/common_components/heap/collector/trace_collector.cpp b/common_components/heap/collector/trace_collector.cpp index 68b8aa29879d7dfa6bd0990b53ab32e99552d431..985a3d77d1ccca6497051cb318ce9bbb716fe561 100755 --- a/common_components/heap/collector/trace_collector.cpp +++ b/common_components/heap/collector/trace_collector.cpp @@ -498,8 +498,8 @@ bool TraceCollector::MarkSatbBuffer(WorkStack& workStack) void TraceCollector::MarkRememberSetImpl(BaseObject* object, WorkStack& workStack) { - object->ForEachRefField([this, &workStack, &object](RefField<>& field) { - BaseObject* targetObj = field.GetTargetObject(); + object->ForEachRefField([this, &workStack, &object](RefField<>& field, RefField<>& snapshotField) { + BaseObject* targetObj = snapshotField.GetTargetObject(); if (Heap::IsHeapAddress(targetObj)) { RegionDesc* region = RegionDesc::GetAliveRegionDescAt(reinterpret_cast(targetObj)); if (region->IsInYoungSpace() && diff --git a/common_components/heap/collector/trace_collector.h b/common_components/heap/collector/trace_collector.h index 3f41128961cc611cf55ae837e6a0dcf7feb0ee77..f9beeb0c578e37a52406d5e89e02945d6f576b96 100755 --- a/common_components/heap/collector/trace_collector.h +++ b/common_components/heap/collector/trace_collector.h @@ -201,7 +201,7 @@ public: const auto &GetClosure() const { return closure_; } private: - common::RefFieldVisitor visitor_; + common::RefFieldWithSnapshotVisitor visitor_; std::shared_ptr closure_; }; virtual TraceRefFieldVisitor CreateTraceObjectRefFieldsVisitor(WorkStack *workStack, WeakStack *weakStack) = 0; diff --git a/common_components/heap/verification.cpp b/common_components/heap/verification.cpp index 38f4c4a97c7688c8ee30a45d610c650a34cfd853..b8b420b01a97f76c456ef751ddeb7544c26a1117 100755 --- a/common_components/heap/verification.cpp +++ b/common_components/heap/verification.cpp @@ -396,8 +396,10 @@ public: while (!markStack.empty()) { obj = markStack.back(); markStack.pop_back(); - - obj->ForEachRefField(markFunc); + auto func = [&markFunc](RefField<>& field, RefField<>& snapshotField) { + markFunc(field); + }; + obj->ForEachRefField(func); } } diff --git a/common_components/heap/w_collector/w_collector.cpp b/common_components/heap/w_collector/w_collector.cpp index ba7fbfe2695bd90a632344ce3266d26cc8b52c3c..b1e1eb8086d815e54e4ea306f747f683a716c399 100755 --- a/common_components/heap/w_collector/w_collector.cpp +++ b/common_components/heap/w_collector/w_collector.cpp @@ -141,21 +141,20 @@ bool WCollector::TryUntagRefField(BaseObject* obj, RefField<>& field, BaseObject static void TraceRefField(BaseObject *obj, BaseObject *targetObj, RefField<> &field, WorkStack &workStack, RegionDesc *targetRegion); -// note each ref-field will not be traced twice, so each old pointer the tracer meets must come from previous gc. -static void TraceRefField(BaseObject *obj, RefField<> &field, WorkStack &workStack, +// note each ref-field will not be traced twice, so each old pointer the tracer +// meets must come from previous gc. oldFieldValue remains immutable to external +// writes, but fieldValue is mutable and reflects real-time changes +static void TraceRefField(BaseObject *obj, RefField<> &field, + RefField<> &snapshotField, WorkStack &workStack, WeakStack &weakStack, const GCReason gcReason) { - RefField<> oldField(field); - BaseObject* targetObj = oldField.GetTargetObject(); + BaseObject* targetObj = snapshotField.GetTargetObject(); - if (!Heap::IsTaggedObject(oldField.GetFieldValue())) { - return; - } // field is tagged object, should be in heap DCHECK_CC(Heap::IsHeapAddress(targetObj)); auto targetRegion = RegionDesc::GetAliveRegionDescAt(reinterpret_cast((void*)targetObj)); - if (gcReason != GC_REASON_YOUNG && oldField.IsWeak()) { + if (gcReason != GC_REASON_YOUNG && snapshotField.IsWeak()) { DLOG(TRACE, "trace: skip weak obj when full gc, object: %p@%p, targetObj: %p", obj, &field, targetObj); // weak ref is cleared after roots pre-forward, so there might be a to-version weak ref which also need to be // cleared, offset recorded here will help us find it @@ -198,14 +197,18 @@ TraceCollector::TraceRefFieldVisitor WCollector::CreateTraceObjectRefFieldsVisit TraceRefFieldVisitor visitor; if (gcReason_ == GCReason::GC_REASON_YOUNG) { - visitor.SetVisitor([obj = visitor.GetClosure(), workStack, weakStack](RefField<> &field) { + visitor.SetVisitor([obj = visitor.GetClosure(), workStack, weakStack]( + RefField<> &field, RefField<> &snapshotField) { const GCReason gcReason = GCReason::GC_REASON_YOUNG; - TraceRefField(*obj, field, *workStack, *weakStack, gcReason); + TraceRefField(*obj, field, snapshotField, *workStack, *weakStack, + gcReason); }); } else { - visitor.SetVisitor([obj = visitor.GetClosure(), workStack, weakStack](RefField<> &field) { + visitor.SetVisitor([obj = visitor.GetClosure(), workStack, weakStack]( + RefField<> &field, RefField<> &snapshotField) { const GCReason gcReason = GCReason::GC_REASON_HEU; - TraceRefField(*obj, field, *workStack, *weakStack, gcReason); + TraceRefField(*obj, field, snapshotField, *workStack, *weakStack, + gcReason); }); } return visitor; @@ -217,44 +220,53 @@ void WCollector::TraceObjectRefFields(BaseObject *obj, TraceRefFieldVisitor *dat obj->ForEachRefField(data->GetRefFieldVisitor()); } -void WCollector::FixRefField(BaseObject* obj, RefField<>& field) const +// snapshotFieldValue remains immutable to external writes, but fieldValue is mutable +// and reflects real-time changes +void WCollector::FixRefField(BaseObject *obj, RefField<> &field, + RefField<> &snapshotField) const { - RefField<> oldField(field); - BaseObject* targetObj = oldField.GetTargetObject(); - if (!Heap::IsTaggedObject(oldField.GetFieldValue())) { - return; - } + BaseObject* targetObj = snapshotField.GetTargetObject(); // target object could be null or non-heap for some static variable. if (!Heap::IsHeapAddress(targetObj)) { return; } - BaseObject* latest = FindToVersion(targetObj); - - // update remember set - BaseObject* toObj = latest == nullptr ? targetObj : latest; - RegionDesc* objRegion = RegionDesc::GetAliveRegionDescAt(reinterpret_cast((void*)obj)); - RegionDesc* refRegion = RegionDesc::GetAliveRegionDescAt(reinterpret_cast((void*)toObj)); - if (!objRegion->IsInRecentSpace() && refRegion->IsInRecentSpace()) { - if (objRegion->MarkRSetCardTable(obj)) { - DLOG(TRACE, "fix phase update point-out remember set of region %p, obj %p, ref: %p<%p>", - objRegion, obj, toObj, toObj->GetTypeInfo()); + RegionDesc::InlinedRegionMetaData *refRegion = RegionDesc::InlinedRegionMetaData::GetInlinedRegionMetaData( + reinterpret_cast(targetObj)); + bool isFrom = refRegion->IsFromRegion(); + bool isInRcent = refRegion->IsInRecentSpace(); + if (isInRcent) { + RegionDesc::InlinedRegionMetaData *objRegion = RegionDesc::InlinedRegionMetaData::GetInlinedRegionMetaData( + reinterpret_cast(obj)); + if (!objRegion->IsInRecentSpace() && + objRegion->MarkRSetCardTable(obj)) { + DLOG(TRACE, + "fix phase update point-out remember set of region %p, obj " + "%p, ref: <%p>", + objRegion, obj, targetObj->GetTypeInfo()); } + return; + } else if (!isFrom) { + return; } + + BaseObject* latest = FindToVersion(targetObj); + // update remember set if (latest == nullptr) { return; } - CHECK_CC(latest->IsValidObject()); - RefField<> newField(latest, oldField.IsWeak()); - if (field.CompareExchange(oldField.GetFieldValue(), newField.GetFieldValue())) { + RefField<> newField(latest, snapshotField.IsWeak()); + if (field.CompareExchange(snapshotField.GetFieldValue(), newField.GetFieldValue())) { DLOG(FIX, "fix obj %p+%zu ref@%p: %#zx => %p<%p>(%zu)", obj, obj->GetSize(), &field, - oldField.GetFieldValue(), latest, latest->GetTypeInfo(), latest->GetSize()); + snapshotField.GetFieldValue(), latest, latest->GetTypeInfo(), latest->GetSize()); } } void WCollector::FixObjectRefFields(BaseObject* obj) const { DLOG(FIX, "fix obj %p<%p>(%zu)", obj, obj->GetTypeInfo(), obj->GetSize()); - auto refFunc = [this, obj](RefField<>& field) { FixRefField(obj, field); }; + auto refFunc = [this, obj](RefField<> &field, RefField<> &snapshotField) { + FixRefField(obj, field, snapshotField); + }; obj->ForEachRefField(refFunc); } diff --git a/common_components/heap/w_collector/w_collector.h b/common_components/heap/w_collector/w_collector.h index c2727f87756ad2c61a905187406105a476fc2ccd..1ed5c62ccff2139bbcd06cd7050c0b3da2a7bcc9 100755 --- a/common_components/heap/w_collector/w_collector.h +++ b/common_components/heap/w_collector/w_collector.h @@ -88,7 +88,7 @@ public: void TraceObjectRefFields(BaseObject *obj, TraceRefFieldVisitor *data) override; void FixObjectRefFields(BaseObject* obj) const override; - void FixRefField(BaseObject* obj, RefField<>& field) const; + void FixRefField(BaseObject* obj, RefField<>& field, RefField<>& snapshotField) const; BaseObject* ForwardObject(BaseObject* fromVersion) override; diff --git a/ecmascript/mem/dynamic_object_operator.cpp b/ecmascript/mem/dynamic_object_operator.cpp index e1f0f1add294093a654ed406ac09a9812965893c..81c3518b4a8c6c91a9948dfee7ce8ea0553d8e0b 100644 --- a/ecmascript/mem/dynamic_object_operator.cpp +++ b/ecmascript/mem/dynamic_object_operator.cpp @@ -46,7 +46,13 @@ void RefFieldObjectVisitor::VisitObjectRangeImpl(BaseObject *root, uintptr_t sta void RefFieldObjectVisitor::VisitObjectHClassImpl(BaseObject *hclass) { JSTaggedValue clz(reinterpret_cast(hclass)); - visitor_(reinterpret_cast&>(clz)); + auto refFiled = reinterpret_cast &>(clz); + common::RefField<> snapshotField(refFiled); + + // The first Field points to an object, while the second Field actually + // points to a local variable. The first one accesses the latest field value + // and allows modification, whereas the second retrieves a snapshot. + visitor_(reinterpret_cast &>(clz), snapshotField); } void RefFieldObjectVisitor::VisitAllRefFields(TaggedObject *obj) @@ -59,10 +65,18 @@ void RefFieldObjectVisitor::VisitAllRefFields(TaggedObject *obj) void RefFieldObjectVisitor::visit(ObjectSlot slot) { - if (!slot.GetTaggedValue().IsHeapObject()) { + auto refFiled = + reinterpret_cast &>(*(slot.GetRefFieldAddr())); + common::RefField<> snapshotField(refFiled); + auto taggedValue = JSTaggedValue(snapshotField.GetFieldValue()); + if (!taggedValue.IsHeapObject()) { return; } - visitor_(reinterpret_cast&>(*(slot.GetRefFieldAddr()))); + // The first Field points to an object, while the second Field actually + // points to a local variable. The first one accesses the latest field value + // and allows modification, whereas the second retrieves a snapshot. + visitor_(reinterpret_cast &>(*(slot.GetRefFieldAddr())), + snapshotField); } } // namespace panda::ecmascript diff --git a/ecmascript/mem/dynamic_object_operator.h b/ecmascript/mem/dynamic_object_operator.h index 3f79e3f422b1b95f245978fa0456d20ba22a7a89..747b84b36fb803123a42796506dd2b889579ca42 100644 --- a/ecmascript/mem/dynamic_object_operator.h +++ b/ecmascript/mem/dynamic_object_operator.h @@ -21,12 +21,13 @@ #include "ecmascript/free_object.h" #include "ecmascript/js_hclass-inl.h" #include "ecmascript/mem/tagged_object.h" +#include "heap/heap_visitor.h" #include "libpandabase/macros.h" namespace panda::ecmascript { class RefFieldObjectVisitor final : public BaseObjectVisitor { public: - inline explicit RefFieldObjectVisitor(const common::RefFieldVisitor &visitor): visitor_(visitor) {}; + inline explicit RefFieldObjectVisitor(const common::RefFieldWithSnapshotVisitor &visitor): visitor_(visitor) {}; ~RefFieldObjectVisitor() override = default; void VisitObjectRangeImpl(BaseObject *root, uintptr_t start, uintptr_t end, @@ -79,7 +80,7 @@ class RefFieldObjectVisitor final : public BaseObjectVisitorGetClass()->IsHClass(); } - void ForEachRefField(const BaseObject *object, const common::RefFieldVisitor &visitor) const override + void ForEachRefField(const BaseObject *object, const common::RefFieldWithSnapshotVisitor &visitor) const override { auto freeObject = FreeObject::Cast(reinterpret_cast(object)); if (!freeObject->IsFreeObject()) {