diff --git a/common_components/common/mark_work_stack.h b/common_components/common/mark_work_stack.h index 37ee3cce842199544bb1786e4a0d1a45e72f9173..f7bebdb84e1b2af4913729e2c9cb7c53917f3f98 100755 --- a/common_components/common/mark_work_stack.h +++ b/common_components/common/mark_work_stack.h @@ -131,7 +131,7 @@ public: T back() { if (this->t_ == nullptr) { - return nullptr; + return T(); } return this->t_->back(); } diff --git a/common_components/heap/collector/trace_collector.cpp b/common_components/heap/collector/trace_collector.cpp index 6e6961a592a3191f3a0fad691be1598be879f105..cf8ab859f2a9f934a14cf6604f8b1ab1582aa0cb 100755 --- a/common_components/heap/collector/trace_collector.cpp +++ b/common_components/heap/collector/trace_collector.cpp @@ -459,7 +459,7 @@ bool TraceCollector::MarkSatbBuffer(WorkStack& workStack) void TraceCollector::MarkRememberSetImpl(BaseObject* object, WorkStack& workStack) { // in Young GC: maybe we can skip the object if it has no ref to young space - object->ForEachRefField([this, &workStack, &object](RefField<>& field) { + auto fieldHandler = [this, &workStack, &object](RefField<>& field) { BaseObject* targetObj = field.GetTargetObject(); if (Heap::IsHeapAddress(targetObj)) { RegionDesc* region = RegionDesc::GetRegionDescAt(reinterpret_cast(targetObj)); @@ -470,7 +470,8 @@ void TraceCollector::MarkRememberSetImpl(BaseObject* object, WorkStack& workStac DLOG(TRACE, "remember set trace obj: %p@%p, ref: %p", object, &field, targetObj); } } - }); + }; + object->ForEachRefField(fieldHandler, fieldHandler); } void TraceCollector::ConcurrentRemark(WorkStack& remarkStack, bool parallel) diff --git a/common_components/heap/collector/trace_collector.h b/common_components/heap/collector/trace_collector.h index 25a21c671a9d3857597147b5c5cacd2d8feeb6a6..8493c78237ccfeade31f777a333e4584f62ec385 100755 --- a/common_components/heap/collector/trace_collector.h +++ b/common_components/heap/collector/trace_collector.h @@ -121,7 +121,7 @@ public: using RootSet = MarkStack; using WorkStack = MarkStack; using WorkStackBuf = MarkStackBuffer; - using WeakStack = MarkStack*>; + using WeakStack = MarkStack*, size_t>>; void Init(const RuntimeParam& param) override; void Fini() override; diff --git a/common_components/heap/verification.cpp b/common_components/heap/verification.cpp index 086e5733f367076836c03a196be4beb5f903648c..7bc93e39db36f615735792e36664fae4ce113925 100755 --- a/common_components/heap/verification.cpp +++ b/common_components/heap/verification.cpp @@ -387,7 +387,7 @@ public: obj = markStack.back(); markStack.pop_back(); - obj->ForEachRefField(markFunc); + obj->ForEachRefField(markFunc, markFunc); } } diff --git a/common_components/heap/w_collector/w_collector.cpp b/common_components/heap/w_collector/w_collector.cpp index 648ba80a413d34e0d1aeefd4bd32b8b221e00b4d..7948cdde32b2b7705f1d03f0cdbf5da4f77a3d25 100755 --- a/common_components/heap/w_collector/w_collector.cpp +++ b/common_components/heap/w_collector/w_collector.cpp @@ -194,7 +194,7 @@ void WCollector::EnumRefFieldRoot(RefField<>& field, RootSet& rootSet) const } // note each ref-field will not be traced twice, so each old pointer the tracer meets must come from previous gc. -void WCollector::TraceRefField(BaseObject* obj, RefField<>& field, WorkStack& workStack, WeakStack& weakStack) const +void WCollector::TraceRefField(BaseObject* obj, RefField<>& field, WorkStack& workStack) const { RefField<> oldField(field); BaseObject* targetObj = oldField.GetTargetObject(); @@ -209,12 +209,6 @@ void WCollector::TraceRefField(BaseObject* obj, RefField<>& field, WorkStack& wo auto gcReason = Heap::GetHeap().GetGCReason(); auto targetRegion = RegionDesc::GetRegionDescAt(reinterpret_cast((void*)targetObj)); - if (gcReason != GC_REASON_YOUNG && oldField.IsWeak()) { - DLOG(TRACE, "trace: skip weak obj when full gc, object: %p@%p, targetObj: %p", obj, &field, targetObj); - weakStack.push_back(&field); - return; - } - if (gcReason == GC_REASON_YOUNG && targetRegion->IsInOldSpace()) { DLOG(TRACE, "trace: skip old object %p@%p, target object: %p<%p>(%zu)", obj, &field, targetObj, targetObj->GetTypeInfo(), targetObj->GetSize()); @@ -236,12 +230,37 @@ void WCollector::TraceRefField(BaseObject* obj, RefField<>& field, WorkStack& wo workStack.push_back(targetObj); } +// note each ref-field will not be traced twice, so each old pointer the tracer meets must come from previous gc. +void WCollector::TraceWeakRefField(BaseObject* obj, RefField<>& field, WorkStack& workStack, WeakStack& weakStack) const +{ + RefField<> oldField(field); + BaseObject* targetObj = oldField.GetTargetObject(); + + if (!Heap::IsTaggedObject(oldField.GetFieldValue())) { + return; + } + auto region = RegionDesc::GetRegionDescAt(reinterpret_cast((void*)targetObj)); + // field is tagged object, should be in heap + DCHECK_CC(Heap::IsHeapAddress(targetObj)); + + DLOG(TRACE, "trace: skip weak obj when full gc, object: %p@%p, targetObj: %p", obj, &field, targetObj); + weakStack.push_back(std::make_pair(&field, reinterpret_cast(&field) - reinterpret_cast(obj))); +} + void WCollector::TraceObjectRefFields(BaseObject* obj, WorkStack& workStack, WeakStack& weakStack) { - auto refFunc = [this, obj, &workStack, &weakStack] (RefField<>& field) { - TraceRefField(obj, field, workStack, weakStack); + auto refFunc = [this, obj, &workStack] (RefField<>& field) { + TraceRefField(obj, field, workStack); }; - obj->ForEachRefField(refFunc); + if (Heap::GetHeap().GetGCReason() == GC_REASON_YOUNG) { + // Handle WeakRef-s as general references in case of young collection + obj->ForEachRefField(refFunc, refFunc); + } else { + auto weakRefFunc = [this, obj, &workStack, &weakStack] (RefField<>& field) { + TraceWeakRefField(obj, field, workStack, weakStack); + }; + obj->ForEachRefField(refFunc, weakRefFunc); + } } #ifdef PANDA_JS_ETS_HYBRID_MODE @@ -312,7 +331,7 @@ 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); }; - obj->ForEachRefField(refFunc); + obj->ForEachRefField(refFunc, refFunc); } BaseObject* WCollector::ForwardUpdateRawRef(ObjectRef& root) @@ -778,22 +797,29 @@ void WCollector::ProcessWeakReferences() { OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::ProcessGlobalWeakStack", ""); while (!globalWeakStack_.empty()) { - RefField<>& field = reinterpret_cast&>(*globalWeakStack_.back()); + auto [fieldPointer, offset] = globalWeakStack_.back(); globalWeakStack_.pop_back(); + ASSERT_LOGF(offset % sizeof(RefField<>) == 0, "offset is not aligned"); + RefField<> &field = reinterpret_cast&>(*fieldPointer); RefField<> oldField(field); BaseObject* targetObj = oldField.GetTargetObject(); - if (Heap::GetHeap().GetGCReason() == GC_REASON_YOUNG) { - if (!Heap::IsHeapAddress(targetObj) || IsMarkedObject(targetObj) || - RegionSpace::IsNewObjectSinceTrace(targetObj) || !RegionSpace::IsYoungSpaceObject(targetObj)) { - continue; - } - } else { - if (!Heap::IsHeapAddress(targetObj) || IsMarkedObject(targetObj) || - RegionSpace::IsNewObjectSinceTrace(targetObj)) { - continue; - } - field.ClearRef(oldField.GetFieldValue()); + if (!Heap::IsHeapAddress(targetObj) || IsMarkedObject(targetObj) || + RegionSpace::IsNewObjectSinceTrace(targetObj)) { + continue; + } + + BaseObject* obj = reinterpret_cast(reinterpret_cast(&field) - offset); + auto regionType = RegionDesc::GetRegionDescAt(reinterpret_cast(obj))->GetRegionType(); + // the object might be trimed then forwarded, we need to make sure toField still points + // to the current object + if (regionType == RegionDesc::RegionType::FROM_REGION && obj->IsForwarded() && + obj->GetSizeForwarded() > offset) { + BaseObject *toObj = obj->GetForwardingPointer(); + RefField<> &toField = *reinterpret_cast*>(reinterpret_cast(toObj) + offset); + + toObj->ClearWeakRef(toField); } + obj->ClearWeakRef(field); } } } diff --git a/common_components/heap/w_collector/w_collector.h b/common_components/heap/w_collector/w_collector.h index 883e993076bf97130b901fec98913df38ff8ccb9..26d0c825abf9c87d8a5afc406e4bf6db6ab36e49 100755 --- a/common_components/heap/w_collector/w_collector.h +++ b/common_components/heap/w_collector/w_collector.h @@ -85,7 +85,6 @@ public: bool MarkObject(BaseObject* obj, size_t cellCount = 0) const override; void EnumRefFieldRoot(RefField<>& ref, RootSet& rootSet) const override; - void TraceRefField(BaseObject* obj, RefField<>& ref, WorkStack& workStack, WeakStack& weakStack) const; void TraceObjectRefFields(BaseObject* obj, WorkStack& workStack, WeakStack& weakStack) override; #ifdef PANDA_JS_ETS_HYBRID_MODE void TraceXRef(RefField<>& ref, WorkStack& workStack) const; @@ -203,6 +202,9 @@ private: void CollectGarbageWithXRef(); + void TraceRefField(BaseObject* obj, RefField<>& ref, WorkStack& workStack) const; + void TraceWeakRefField(BaseObject* obj, RefField<>& ref, WorkStack& workStack, WeakStack& weakStack) const; + CopyTable fwdTable_; GCMode gcMode_ = GCMode::CMC; diff --git a/ecmascript/mem/dynamic_object_operator.cpp b/ecmascript/mem/dynamic_object_operator.cpp index a1a33dc0dd593a03efd258502e51a7e341529284..0392f08c5f286ae143034790b00fc091dd364ae1 100644 --- a/ecmascript/mem/dynamic_object_operator.cpp +++ b/ecmascript/mem/dynamic_object_operator.cpp @@ -83,7 +83,11 @@ void RefFieldObjectVisitor::visit(ObjectSlot slot) if (!slot.GetTaggedValue().IsHeapObject()) { return; } - visitor_(reinterpret_cast&>(*(slot.GetRefFieldAddr()))); + if (slot.GetTaggedValue().IsWeak()) { + weakVisitor_(reinterpret_cast&>(*(slot.GetRefFieldAddr()))); + } else { + visitor_(reinterpret_cast&>(*(slot.GetRefFieldAddr()))); + } } } // namespace panda::ecmascript diff --git a/ecmascript/mem/dynamic_object_operator.h b/ecmascript/mem/dynamic_object_operator.h index 7a588da7f7c5e03f512564c8c043b4c144b48a0f..f76f8c3c9e4d80d68bc98a300bad101f6715097d 100644 --- a/ecmascript/mem/dynamic_object_operator.h +++ b/ecmascript/mem/dynamic_object_operator.h @@ -26,7 +26,9 @@ namespace panda::ecmascript { class RefFieldObjectVisitor final : public BaseObjectVisitor { public: - inline explicit RefFieldObjectVisitor(const common::RefFieldVisitor &visitor): visitor_(visitor) {}; + inline explicit RefFieldObjectVisitor(const common::RefFieldVisitor &visitor, + const common::RefFieldVisitor &weakVisitor) + : visitor_(visitor), weakVisitor_(weakVisitor) {}; ~RefFieldObjectVisitor() override = default; void VisitObjectRangeImpl(BaseObject *root, uintptr_t start, uintptr_t end, @@ -60,6 +62,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::RefFieldVisitor &visitor, + const common::RefFieldVisitor &weakVisitor) const override { auto freeObject = FreeObject::Cast(reinterpret_cast(object)); if (!freeObject->IsFreeObject()) { - RefFieldObjectVisitor refFieldObjectVisitor(visitor); + RefFieldObjectVisitor refFieldObjectVisitor(visitor, weakVisitor); refFieldObjectVisitor.VisitAllRefFields(TaggedObject::Cast(object)); } } + void ClearWeakRef(common::RefField<> &field) const override + { + field.CompareExchange(field.GetFieldValue(), JSTaggedValue::Undefined().GetRawData()); + } + void IterateXRef(const BaseObject *object, const common::RefFieldVisitor &visitor) const override; size_t GetSize(const BaseObject *object) const override