* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_MEM_SHARED_HEAP_SHARED_GC_VISITOR_INL_H
#define ECMASCRIPT_MEM_SHARED_HEAP_SHARED_GC_VISITOR_INL_H
#include "ecmascript/mem/shared_heap/shared_gc_visitor.h"
#include "ecmascript/mem/region-inl.h"
#include "ecmascript/mem/work_manager-inl.h"
namespace panda::ecmascript {
SharedGCMarkRootVisitor::SharedGCMarkRootVisitor(SharedGCWorkNodeHolder *sWorkNodeHolder)
: sWorkNodeHolder_(sWorkNodeHolder)
{
}
void SharedGCMarkRootVisitor::VisitRoot([[maybe_unused]] Root type, ObjectSlot slot)
{
JSTaggedValue value(slot.GetTaggedType());
if (value.IsHeapObject()) {
ASSERT(!value.IsWeak());
MarkObject(value.GetTaggedObject());
}
}
void SharedGCMarkRootVisitor::VisitRangeRoot([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end)
{
for (ObjectSlot slot = start; slot < end; slot++) {
JSTaggedValue value(slot.GetTaggedType());
if (value.IsHeapObject()) {
ASSERT(!value.IsWeak());
MarkObject(value.GetTaggedObject());
}
}
}
void SharedGCMarkRootVisitor::VisitBaseAndDerivedRoot([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base,
[[maybe_unused]] ObjectSlot derived,
[[maybe_unused]] uintptr_t baseOldObject)
{
}
void SharedGCMarkRootVisitor::MarkObject(TaggedObject *object)
{
Region *objectRegion = Region::ObjectAddressToRange(object);
if (!objectRegion->InSharedSweepableSpace()) {
return;
}
if (objectRegion->AtomicMark(object)) {
sWorkNodeHolder_->Push(object);
}
}
SharedGCMarkObjectVisitor::SharedGCMarkObjectVisitor(SharedGCWorkNodeHolder *sWorkNodeHolder)
: sWorkNodeHolder_(sWorkNodeHolder)
{
}
void SharedGCMarkObjectVisitor::VisitObjectRangeImpl(BaseObject *root, uintptr_t startAddr, uintptr_t endAddr,
VisitObjectArea area)
{
Region *rootRegion = Region::ObjectAddressToRange(root);
ObjectSlot start(startAddr);
ObjectSlot end(endAddr);
if (UNLIKELY(area == VisitObjectArea::IN_OBJECT)) {
JSHClass *hclass = TaggedObject::Cast(root)->SynchronizedGetClass();
ASSERT(!hclass->IsAllTaggedProp());
int index = 0;
LayoutInfo *layout = LayoutInfo::UncheckCast(hclass->GetLayout(THREAD_ARG_PLACEHOLDER).GetTaggedObject());
ObjectSlot realEnd = start;
realEnd += layout->GetPropertiesCapacity();
end = end > realEnd ? realEnd : end;
for (ObjectSlot slot = start; slot < end; slot++) {
PropertyAttributes attr = layout->GetAttr(THREAD_ARG_PLACEHOLDER, index++);
if (attr.IsTaggedRep()) {
HandleSlot(slot, rootRegion);
}
}
return;
}
for (ObjectSlot slot = start; slot < end; slot++) {
HandleSlot(slot, rootRegion);
}
}
void SharedGCMarkObjectVisitor::VisitObjectHClassImpl(BaseObject *hclass)
{
ASSERT(TaggedObject::Cast(hclass)->GetClass()->IsHClass());
Region *hclassRegion = Region::ObjectAddressToRange(hclass);
if (hclassRegion->InSharedSweepableSpace()) {
ASSERT(hclassRegion->InSharedNonMovableSpace());
MarkAndPush(TaggedObject::Cast(hclass), hclassRegion);
}
}
void SharedGCMarkObjectVisitor::HandleSlot(ObjectSlot slot, Region *rootRegion)
{
JSTaggedValue value(slot.GetTaggedType());
if (!value.IsHeapObject()) {
return;
}
Region *objectRegion = Region::ObjectAddressToRange(value.GetRawHeapObject());
ASSERT(objectRegion->InSharedHeap());
if (!objectRegion->InSharedSweepableSpace()) {
return;
}
if (!value.IsWeakForHeapObject()) {
TaggedObject *object = value.GetTaggedObject();
MarkAndPush(object, objectRegion);
if (objectRegion->InSharedOldSpace() && (rootRegion != objectRegion)) {
rootRegion->AtomicInsertCrossRegionRSet(slot.SlotAddress());
}
} else {
RecordWeakReference(reinterpret_cast<JSTaggedType*>(slot.SlotAddress()));
}
}
void SharedGCMarkObjectVisitor::MarkAndPush(TaggedObject *object, Region *objectRegion)
{
if (objectRegion->AtomicMark(object)) {
sWorkNodeHolder_->Push(object);
}
}
void SharedGCMarkObjectVisitor::RecordWeakReference(JSTaggedType *weak)
{
sWorkNodeHolder_->PushWeakReference(weak);
}
template <SharedMarkType markType>
SharedGCMarkLocalToShareRSetVisitor<markType>::SharedGCMarkLocalToShareRSetVisitor(
SharedGCWorkNodeHolder *sWorkNodeHolder) : sWorkNodeHolder_(sWorkNodeHolder)
{
}
template <SharedMarkType markType>
bool SharedGCMarkLocalToShareRSetVisitor<markType>::operator()(void *mem) const
{
ObjectSlot slot(ToUintPtr(mem));
JSTaggedValue value(slot.GetTaggedType());
if (value.IsInSharedSweepableSpace()) {
if constexpr (markType == SharedMarkType::CONCURRENT_MARK_INITIAL_MARK) {
MarkObject(value.GetHeapObject());
} else {
static_assert(markType == SharedMarkType::NOT_CONCURRENT_MARK);
if (value.IsWeakForHeapObject()) {
RecordWeakReference(reinterpret_cast<JSTaggedType *>(mem));
} else {
MarkObject(value.GetTaggedObject());
}
}
return true;
}
return false;
}
template <SharedMarkType markType>
void SharedGCMarkLocalToShareRSetVisitor<markType>::MarkObject(TaggedObject *object) const
{
Region *objectRegion = Region::ObjectAddressToRange(object);
ASSERT(objectRegion->InSharedHeap());
if (!objectRegion->InSharedReadOnlySpace() && objectRegion->AtomicMark(object)) {
ASSERT(objectRegion->InSharedSweepableSpace());
sWorkNodeHolder_->Push(object);
}
}
template <SharedMarkType markType>
void SharedGCMarkLocalToShareRSetVisitor<markType>::RecordWeakReference(JSTaggedType *weak) const
{
sWorkNodeHolder_->PushWeakReference(weak);
}
}
#endif