14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_MEM_PARALLEL_MARKER_INL_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_MEM_PARALLEL_MARKER_INL_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include "ecmascript/mem/parallel_marker.h"
204514f5e3Sopenharmony_ci
214514f5e3Sopenharmony_ci#include "ecmascript/js_hclass-inl.h"
224514f5e3Sopenharmony_ci#include "ecmascript/mem/gc_bitset.h"
234514f5e3Sopenharmony_ci#include "ecmascript/mem/heap.h"
244514f5e3Sopenharmony_ci#include "ecmascript/mem/region-inl.h"
254514f5e3Sopenharmony_ci#include "ecmascript/mem/tlab_allocator-inl.h"
264514f5e3Sopenharmony_ci
274514f5e3Sopenharmony_cinamespace panda::ecmascript {
284514f5e3Sopenharmony_ci
294514f5e3Sopenharmony_citemplate <typename Callback>
304514f5e3Sopenharmony_ciARK_INLINE bool NonMovableMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end,
314514f5e3Sopenharmony_ci                                                 bool needBarrier, Callback callback)
324514f5e3Sopenharmony_ci{
334514f5e3Sopenharmony_ci    auto hclass = root->SynchronizedGetClass();
344514f5e3Sopenharmony_ci    Region *rootRegion = Region::ObjectAddressToRange(root);
354514f5e3Sopenharmony_ci    int index = 0;
364514f5e3Sopenharmony_ci    auto layout = LayoutInfo::UncheckCast(hclass->GetLayout().GetTaggedObject());
374514f5e3Sopenharmony_ci    ObjectSlot realEnd = start;
384514f5e3Sopenharmony_ci    realEnd += layout->GetPropertiesCapacity();
394514f5e3Sopenharmony_ci    end = end > realEnd ? realEnd : end;
404514f5e3Sopenharmony_ci    for (ObjectSlot slot = start; slot < end; slot++) {
414514f5e3Sopenharmony_ci        auto attr = layout->GetAttr(index++);
424514f5e3Sopenharmony_ci        if (attr.IsTaggedRep()) {
434514f5e3Sopenharmony_ci            callback(slot, rootRegion, needBarrier);
444514f5e3Sopenharmony_ci        }
454514f5e3Sopenharmony_ci    }
464514f5e3Sopenharmony_ci    return true;
474514f5e3Sopenharmony_ci}
484514f5e3Sopenharmony_ci
494514f5e3Sopenharmony_ciinline void NonMovableMarker::MarkValue(uint32_t threadId, ObjectSlot &slot, Region *rootRegion, bool needBarrier)
504514f5e3Sopenharmony_ci{
514514f5e3Sopenharmony_ci    JSTaggedValue value(slot.GetTaggedType());
524514f5e3Sopenharmony_ci    if (value.IsHeapObject()) {
534514f5e3Sopenharmony_ci        ASSERT(!value.IsHole()); // check that value is not zero
544514f5e3Sopenharmony_ci        TaggedObject *obj = nullptr;
554514f5e3Sopenharmony_ci        if (!value.IsWeakForHeapObject()) {
564514f5e3Sopenharmony_ci            obj = value.GetTaggedObject();
574514f5e3Sopenharmony_ci            Region *objRegion = Region::ObjectAddressToRange(obj);
584514f5e3Sopenharmony_ci            if (objRegion->IsFreshRegion()) {
594514f5e3Sopenharmony_ci                // Object in fresh region should only mark from JS Thread in barrier, or MarkObject in MarkRoots.
604514f5e3Sopenharmony_ci                ASSERT(objRegion->InYoungSpace());
614514f5e3Sopenharmony_ci                return;
624514f5e3Sopenharmony_ci            }
634514f5e3Sopenharmony_ci            MarkObject(threadId, obj);
644514f5e3Sopenharmony_ci        } else {
654514f5e3Sopenharmony_ci            RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()), rootRegion);
664514f5e3Sopenharmony_ci            obj = value.GetWeakReferentUnChecked();
674514f5e3Sopenharmony_ci        }
684514f5e3Sopenharmony_ci        if (needBarrier) {
694514f5e3Sopenharmony_ci            Region *valueRegion = Region::ObjectAddressToRange(obj);
704514f5e3Sopenharmony_ci            if (valueRegion->InCollectSet()) {
714514f5e3Sopenharmony_ci                rootRegion->AtomicInsertCrossRegionRSet(slot.SlotAddress());
724514f5e3Sopenharmony_ci            }
734514f5e3Sopenharmony_ci        }
744514f5e3Sopenharmony_ci    }
754514f5e3Sopenharmony_ci}
764514f5e3Sopenharmony_ci
774514f5e3Sopenharmony_ciinline void NonMovableMarker::MarkObject(uint32_t threadId, TaggedObject *object)
784514f5e3Sopenharmony_ci{
794514f5e3Sopenharmony_ci    Region *objectRegion = Region::ObjectAddressToRange(object);
804514f5e3Sopenharmony_ci
814514f5e3Sopenharmony_ci    if (objectRegion->InSharedHeap()) {
824514f5e3Sopenharmony_ci        return;
834514f5e3Sopenharmony_ci    }
844514f5e3Sopenharmony_ci
854514f5e3Sopenharmony_ci    if (heap_->IsYoungMark() && objectRegion->InGeneralOldSpace()) {
864514f5e3Sopenharmony_ci        return;
874514f5e3Sopenharmony_ci    }
884514f5e3Sopenharmony_ci
894514f5e3Sopenharmony_ci    if (heap_->IsEdenMark() && !objectRegion->InEdenSpace()) {
904514f5e3Sopenharmony_ci        return;
914514f5e3Sopenharmony_ci    }
924514f5e3Sopenharmony_ci
934514f5e3Sopenharmony_ci    if (objectRegion->IsFreshRegion()) {
944514f5e3Sopenharmony_ci        // This should only happen in MarkRoot from js thread.
954514f5e3Sopenharmony_ci        ASSERT(JSThread::GetCurrent() != nullptr);
964514f5e3Sopenharmony_ci        ASSERT(objectRegion->InYoungSpace());
974514f5e3Sopenharmony_ci        objectRegion->NonAtomicMark(object);
984514f5e3Sopenharmony_ci    } else if (objectRegion->AtomicMark(object)) {
994514f5e3Sopenharmony_ci        workManager_->Push(threadId, object);
1004514f5e3Sopenharmony_ci    }
1014514f5e3Sopenharmony_ci}
1024514f5e3Sopenharmony_ci
1034514f5e3Sopenharmony_ciinline void NonMovableMarker::HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot)
1044514f5e3Sopenharmony_ci{
1054514f5e3Sopenharmony_ci    JSTaggedValue value(slot.GetTaggedType());
1064514f5e3Sopenharmony_ci    if (value.IsHeapObject()) {
1074514f5e3Sopenharmony_ci        MarkObject(threadId, value.GetTaggedObject());
1084514f5e3Sopenharmony_ci    }
1094514f5e3Sopenharmony_ci}
1104514f5e3Sopenharmony_ci
1114514f5e3Sopenharmony_ciinline void NonMovableMarker::HandleRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start,
1124514f5e3Sopenharmony_ci    ObjectSlot end)
1134514f5e3Sopenharmony_ci{
1144514f5e3Sopenharmony_ci    for (ObjectSlot slot = start; slot < end; slot++) {
1154514f5e3Sopenharmony_ci        JSTaggedValue value(slot.GetTaggedType());
1164514f5e3Sopenharmony_ci        if (value.IsHeapObject()) {
1174514f5e3Sopenharmony_ci            if (value.IsWeakForHeapObject()) {
1184514f5e3Sopenharmony_ci                LOG_ECMA_MEM(FATAL) << "Weak Reference in NonMovableMarker roots";
1194514f5e3Sopenharmony_ci            }
1204514f5e3Sopenharmony_ci            MarkObject(threadId, value.GetTaggedObject());
1214514f5e3Sopenharmony_ci        }
1224514f5e3Sopenharmony_ci    }
1234514f5e3Sopenharmony_ci}
1244514f5e3Sopenharmony_ci
1254514f5e3Sopenharmony_ciinline void NonMovableMarker::HandleDerivedRoots([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base,
1264514f5e3Sopenharmony_ci                                                 [[maybe_unused]] ObjectSlot derived,
1274514f5e3Sopenharmony_ci                                                 [[maybe_unused]] uintptr_t baseOldObject)
1284514f5e3Sopenharmony_ci{
1294514f5e3Sopenharmony_ci    // It is only used to update the derived value. The mark of partial GC does not need to update slot
1304514f5e3Sopenharmony_ci}
1314514f5e3Sopenharmony_ci
1324514f5e3Sopenharmony_ciinline void NonMovableMarker::HandleNewToEdenRSet(uint32_t threadId, Region *region)
1334514f5e3Sopenharmony_ci{
1344514f5e3Sopenharmony_ci    ASSERT(region->InYoungSpace());
1354514f5e3Sopenharmony_ci    region->IterateAllNewToEdenBits([this, threadId, region](void *mem) -> bool {
1364514f5e3Sopenharmony_ci        ObjectSlot slot(ToUintPtr(mem));
1374514f5e3Sopenharmony_ci        JSTaggedValue value(slot.GetTaggedType());
1384514f5e3Sopenharmony_ci        if (value.IsHeapObject()) {
1394514f5e3Sopenharmony_ci            if (value.IsWeakForHeapObject()) {
1404514f5e3Sopenharmony_ci                RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(mem), region);
1414514f5e3Sopenharmony_ci            } else {
1424514f5e3Sopenharmony_ci                MarkObject(threadId, value.GetTaggedObject());
1434514f5e3Sopenharmony_ci            }
1444514f5e3Sopenharmony_ci        }
1454514f5e3Sopenharmony_ci        return true;
1464514f5e3Sopenharmony_ci    });
1474514f5e3Sopenharmony_ci}
1484514f5e3Sopenharmony_ci
1494514f5e3Sopenharmony_ciinline void NonMovableMarker::HandleOldToNewRSet(uint32_t threadId, Region *region)
1504514f5e3Sopenharmony_ci{
1514514f5e3Sopenharmony_ci    bool isEdenMark = heap_->IsEdenMark();
1524514f5e3Sopenharmony_ci    region->IterateAllOldToNewBits([this, threadId, &region, isEdenMark](void *mem) -> bool {
1534514f5e3Sopenharmony_ci        ObjectSlot slot(ToUintPtr(mem));
1544514f5e3Sopenharmony_ci        JSTaggedValue value(slot.GetTaggedType());
1554514f5e3Sopenharmony_ci        if (!value.IsHeapObject()) {
1564514f5e3Sopenharmony_ci            return true;
1574514f5e3Sopenharmony_ci        }
1584514f5e3Sopenharmony_ci        if (value.IsWeakForHeapObject()) {
1594514f5e3Sopenharmony_ci            RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(mem), region);
1604514f5e3Sopenharmony_ci        } else {
1614514f5e3Sopenharmony_ci            auto object = value.GetTaggedObject();
1624514f5e3Sopenharmony_ci            Region *objectRegion = Region::ObjectAddressToRange(object);
1634514f5e3Sopenharmony_ci            if (isEdenMark) {
1644514f5e3Sopenharmony_ci                if (objectRegion->InEdenSpace()) {
1654514f5e3Sopenharmony_ci                    MarkObject(threadId, value.GetTaggedObject());
1664514f5e3Sopenharmony_ci                }
1674514f5e3Sopenharmony_ci            } else {
1684514f5e3Sopenharmony_ci                MarkObject(threadId, value.GetTaggedObject());
1694514f5e3Sopenharmony_ci            }
1704514f5e3Sopenharmony_ci        }
1714514f5e3Sopenharmony_ci        return true;
1724514f5e3Sopenharmony_ci    });
1734514f5e3Sopenharmony_ci}
1744514f5e3Sopenharmony_ci
1754514f5e3Sopenharmony_ciinline void NonMovableMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref, Region *objectRegion)
1764514f5e3Sopenharmony_ci{
1774514f5e3Sopenharmony_ci    auto value = JSTaggedValue(*ref);
1784514f5e3Sopenharmony_ci    Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedWeakRef());
1794514f5e3Sopenharmony_ci    if (heap_->IsEdenMark()) {
1804514f5e3Sopenharmony_ci        // only record object may be sweep, but no object will be sweep in EdenGC
1814514f5e3Sopenharmony_ci        return;
1824514f5e3Sopenharmony_ci    }
1834514f5e3Sopenharmony_ci    if (!objectRegion->InGeneralNewSpaceOrCSet() && !valueRegion->InGeneralNewSpaceOrCSet()) {
1844514f5e3Sopenharmony_ci        workManager_->PushWeakReference(threadId, ref);
1854514f5e3Sopenharmony_ci    }
1864514f5e3Sopenharmony_ci}
1874514f5e3Sopenharmony_ci
1884514f5e3Sopenharmony_citemplate <typename Callback>
1894514f5e3Sopenharmony_ciARK_INLINE bool MovableMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback)
1904514f5e3Sopenharmony_ci{
1914514f5e3Sopenharmony_ci    auto hclass = root->GetClass();
1924514f5e3Sopenharmony_ci    int index = 0;
1934514f5e3Sopenharmony_ci    TaggedObject *dst = hclass->GetLayout().GetTaggedObject();
1944514f5e3Sopenharmony_ci    auto layout = LayoutInfo::UncheckCast(dst);
1954514f5e3Sopenharmony_ci    ObjectSlot realEnd = start;
1964514f5e3Sopenharmony_ci    realEnd += layout->GetPropertiesCapacity();
1974514f5e3Sopenharmony_ci    end = end > realEnd ? realEnd : end;
1984514f5e3Sopenharmony_ci    for (ObjectSlot slot = start; slot < end; slot++) {
1994514f5e3Sopenharmony_ci        auto attr = layout->GetAttr(index++);
2004514f5e3Sopenharmony_ci        if (attr.IsTaggedRep()) {
2014514f5e3Sopenharmony_ci            callback(slot, root);
2024514f5e3Sopenharmony_ci        }
2034514f5e3Sopenharmony_ci    }
2044514f5e3Sopenharmony_ci    return true;
2054514f5e3Sopenharmony_ci}
2064514f5e3Sopenharmony_ci
2074514f5e3Sopenharmony_ciinline void MovableMarker::HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot)
2084514f5e3Sopenharmony_ci{
2094514f5e3Sopenharmony_ci    JSTaggedValue value(slot.GetTaggedType());
2104514f5e3Sopenharmony_ci    if (value.IsHeapObject()) {
2114514f5e3Sopenharmony_ci        MarkObject(threadId, value.GetTaggedObject(), slot);
2124514f5e3Sopenharmony_ci    }
2134514f5e3Sopenharmony_ci}
2144514f5e3Sopenharmony_ci
2154514f5e3Sopenharmony_ciinline void MovableMarker::HandleRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start,
2164514f5e3Sopenharmony_ci    ObjectSlot end)
2174514f5e3Sopenharmony_ci{
2184514f5e3Sopenharmony_ci    for (ObjectSlot slot = start; slot < end; slot++) {
2194514f5e3Sopenharmony_ci        JSTaggedValue value(slot.GetTaggedType());
2204514f5e3Sopenharmony_ci        if (value.IsHeapObject()) {
2214514f5e3Sopenharmony_ci            if (value.IsWeakForHeapObject()) {
2224514f5e3Sopenharmony_ci                Region *objectRegion = Region::ObjectAddressToRange(start.SlotAddress());
2234514f5e3Sopenharmony_ci                RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()), objectRegion);
2244514f5e3Sopenharmony_ci            } else {
2254514f5e3Sopenharmony_ci                MarkObject(threadId, value.GetTaggedObject(), slot);
2264514f5e3Sopenharmony_ci            }
2274514f5e3Sopenharmony_ci        }
2284514f5e3Sopenharmony_ci    }
2294514f5e3Sopenharmony_ci}
2304514f5e3Sopenharmony_ci
2314514f5e3Sopenharmony_ciinline void MovableMarker::HandleDerivedRoots([[maybe_unused]] Root type, ObjectSlot base,
2324514f5e3Sopenharmony_ci                                              ObjectSlot derived, uintptr_t baseOldObject)
2334514f5e3Sopenharmony_ci{
2344514f5e3Sopenharmony_ci    if (JSTaggedValue(base.GetTaggedType()).IsHeapObject()) {
2354514f5e3Sopenharmony_ci        derived.Update(base.GetTaggedType() + derived.GetTaggedType() - baseOldObject);
2364514f5e3Sopenharmony_ci    }
2374514f5e3Sopenharmony_ci}
2384514f5e3Sopenharmony_ci
2394514f5e3Sopenharmony_ciinline void MovableMarker::HandleNewToEdenRSet(uint32_t threadId, Region *region)
2404514f5e3Sopenharmony_ci{
2414514f5e3Sopenharmony_ci    region->IterateAllNewToEdenBits([this, threadId, &region](void *mem) -> bool {
2424514f5e3Sopenharmony_ci        ObjectSlot slot(ToUintPtr(mem));
2434514f5e3Sopenharmony_ci        JSTaggedValue value(slot.GetTaggedType());
2444514f5e3Sopenharmony_ci        if (value.IsHeapObject()) {
2454514f5e3Sopenharmony_ci            if (value.IsWeakForHeapObject()) {
2464514f5e3Sopenharmony_ci                RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(mem), region);
2474514f5e3Sopenharmony_ci                return true;
2484514f5e3Sopenharmony_ci            }
2494514f5e3Sopenharmony_ci            auto slotStatus = MarkObject(threadId, value.GetTaggedObject(), slot);
2504514f5e3Sopenharmony_ci            if (slotStatus == SlotStatus::CLEAR_SLOT) {
2514514f5e3Sopenharmony_ci                return false;
2524514f5e3Sopenharmony_ci            }
2534514f5e3Sopenharmony_ci        }
2544514f5e3Sopenharmony_ci        return true;
2554514f5e3Sopenharmony_ci    });
2564514f5e3Sopenharmony_ci}
2574514f5e3Sopenharmony_ci
2584514f5e3Sopenharmony_ciinline void MovableMarker::HandleOldToNewRSet(uint32_t threadId, Region *region)
2594514f5e3Sopenharmony_ci{
2604514f5e3Sopenharmony_ci    region->IterateAllOldToNewBits([this, threadId, &region](void *mem) -> bool {
2614514f5e3Sopenharmony_ci        ObjectSlot slot(ToUintPtr(mem));
2624514f5e3Sopenharmony_ci        JSTaggedValue value(slot.GetTaggedType());
2634514f5e3Sopenharmony_ci        if (value.IsHeapObject()) {
2644514f5e3Sopenharmony_ci            if (value.IsWeakForHeapObject()) {
2654514f5e3Sopenharmony_ci                RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(mem), region);
2664514f5e3Sopenharmony_ci                return true;
2674514f5e3Sopenharmony_ci            }
2684514f5e3Sopenharmony_ci            auto slotStatus = MarkObject(threadId, value.GetTaggedObject(), slot);
2694514f5e3Sopenharmony_ci            if (slotStatus == SlotStatus::CLEAR_SLOT) {
2704514f5e3Sopenharmony_ci                return false;
2714514f5e3Sopenharmony_ci            }
2724514f5e3Sopenharmony_ci        }
2734514f5e3Sopenharmony_ci        return true;
2744514f5e3Sopenharmony_ci    });
2754514f5e3Sopenharmony_ci}
2764514f5e3Sopenharmony_ci
2774514f5e3Sopenharmony_ciinline uintptr_t MovableMarker::AllocateDstSpace(uint32_t threadId, size_t size, bool &shouldPromote)
2784514f5e3Sopenharmony_ci{
2794514f5e3Sopenharmony_ci    uintptr_t forwardAddress = 0;
2804514f5e3Sopenharmony_ci    if (shouldPromote) {
2814514f5e3Sopenharmony_ci        forwardAddress = workManager_->GetTlabAllocator(threadId)->Allocate(size, COMPRESS_SPACE);
2824514f5e3Sopenharmony_ci        if (UNLIKELY(forwardAddress == 0)) {
2834514f5e3Sopenharmony_ci            LOG_ECMA_MEM(FATAL) << "EvacuateObject alloc failed: "
2844514f5e3Sopenharmony_ci                                << " size: " << size;
2854514f5e3Sopenharmony_ci            UNREACHABLE();
2864514f5e3Sopenharmony_ci        }
2874514f5e3Sopenharmony_ci    } else {
2884514f5e3Sopenharmony_ci        forwardAddress = workManager_->GetTlabAllocator(threadId)->Allocate(size, SEMI_SPACE);
2894514f5e3Sopenharmony_ci        if (UNLIKELY(forwardAddress == 0)) {
2904514f5e3Sopenharmony_ci            forwardAddress = workManager_->GetTlabAllocator(threadId)->Allocate(size, COMPRESS_SPACE);
2914514f5e3Sopenharmony_ci            if (UNLIKELY(forwardAddress == 0)) {
2924514f5e3Sopenharmony_ci                LOG_ECMA_MEM(FATAL) << "EvacuateObject alloc failed: "
2934514f5e3Sopenharmony_ci                                    << " size: " << size;
2944514f5e3Sopenharmony_ci                UNREACHABLE();
2954514f5e3Sopenharmony_ci            }
2964514f5e3Sopenharmony_ci            shouldPromote = true;
2974514f5e3Sopenharmony_ci        }
2984514f5e3Sopenharmony_ci    }
2994514f5e3Sopenharmony_ci    return forwardAddress;
3004514f5e3Sopenharmony_ci}
3014514f5e3Sopenharmony_ci
3024514f5e3Sopenharmony_ciinline void MovableMarker::UpdateForwardAddressIfSuccess(uint32_t threadId, TaggedObject *object, JSHClass *klass,
3034514f5e3Sopenharmony_ci    uintptr_t toAddress, size_t size, ObjectSlot slot, bool isPromoted)
3044514f5e3Sopenharmony_ci{
3054514f5e3Sopenharmony_ci    workManager_->IncreaseAliveSize(threadId, size);
3064514f5e3Sopenharmony_ci    if (isPromoted) {
3074514f5e3Sopenharmony_ci        workManager_->IncreasePromotedSize(threadId, size);
3084514f5e3Sopenharmony_ci    }
3094514f5e3Sopenharmony_ci
3104514f5e3Sopenharmony_ci    heap_->OnMoveEvent(reinterpret_cast<intptr_t>(object), reinterpret_cast<TaggedObject *>(toAddress), size);
3114514f5e3Sopenharmony_ci    if (klass->HasReferenceField()) {
3124514f5e3Sopenharmony_ci        workManager_->Push(threadId, reinterpret_cast<TaggedObject *>(toAddress));
3134514f5e3Sopenharmony_ci    }
3144514f5e3Sopenharmony_ci    slot.Update(reinterpret_cast<TaggedObject *>(toAddress));
3154514f5e3Sopenharmony_ci}
3164514f5e3Sopenharmony_ci
3174514f5e3Sopenharmony_ciinline bool MovableMarker::UpdateForwardAddressIfFailed(TaggedObject *object, uintptr_t toAddress, size_t size,
3184514f5e3Sopenharmony_ci    ObjectSlot slot)
3194514f5e3Sopenharmony_ci{
3204514f5e3Sopenharmony_ci    FreeObject::FillFreeObject(heap_, toAddress, size);
3214514f5e3Sopenharmony_ci    TaggedObject *dst = MarkWord(object).ToForwardingAddress();
3224514f5e3Sopenharmony_ci    slot.Update(dst);
3234514f5e3Sopenharmony_ci    return Region::ObjectAddressToRange(dst)->InYoungSpace();
3244514f5e3Sopenharmony_ci}
3254514f5e3Sopenharmony_ci
3264514f5e3Sopenharmony_ciinline void MovableMarker::RawCopyObject(uintptr_t fromAddress, uintptr_t toAddress, size_t size,
3274514f5e3Sopenharmony_ci    const MarkWord &markWord)
3284514f5e3Sopenharmony_ci{
3294514f5e3Sopenharmony_ci    if (memcpy_s(ToVoidPtr(toAddress + HEAD_SIZE), size - HEAD_SIZE, ToVoidPtr(fromAddress + HEAD_SIZE),
3304514f5e3Sopenharmony_ci        size - HEAD_SIZE) != EOK) {
3314514f5e3Sopenharmony_ci        LOG_FULL(FATAL) << "memcpy_s failed";
3324514f5e3Sopenharmony_ci    }
3334514f5e3Sopenharmony_ci    *reinterpret_cast<MarkWordType *>(toAddress) = markWord.GetValue();
3344514f5e3Sopenharmony_ci}
3354514f5e3Sopenharmony_ci
3364514f5e3Sopenharmony_civoid MovableMarker::UpdateLocalToShareRSet(TaggedObject *object, JSHClass *cls)
3374514f5e3Sopenharmony_ci{
3384514f5e3Sopenharmony_ci    Region *region = Region::ObjectAddressToRange(object);
3394514f5e3Sopenharmony_ci    ASSERT(!region->InSharedHeap());
3404514f5e3Sopenharmony_ci    auto callbackWithCSet = [this, region](TaggedObject *root, ObjectSlot start, ObjectSlot end, VisitObjectArea area) {
3414514f5e3Sopenharmony_ci        if (area == VisitObjectArea::IN_OBJECT) {
3424514f5e3Sopenharmony_ci            if (VisitBodyInObj(root, start, end,
3434514f5e3Sopenharmony_ci                               [&](ObjectSlot slot, [[maybe_unused]]TaggedObject *root) {
3444514f5e3Sopenharmony_ci                                   SetLocalToShareRSet(slot, region);
3454514f5e3Sopenharmony_ci                               })) {
3464514f5e3Sopenharmony_ci                return;
3474514f5e3Sopenharmony_ci            };
3484514f5e3Sopenharmony_ci        }
3494514f5e3Sopenharmony_ci        for (ObjectSlot slot = start; slot < end; slot++) {
3504514f5e3Sopenharmony_ci            SetLocalToShareRSet(slot, region);
3514514f5e3Sopenharmony_ci        }
3524514f5e3Sopenharmony_ci    };
3534514f5e3Sopenharmony_ci    ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(object, cls, callbackWithCSet);
3544514f5e3Sopenharmony_ci}
3554514f5e3Sopenharmony_ci
3564514f5e3Sopenharmony_civoid MovableMarker::SetLocalToShareRSet(ObjectSlot slot, Region *region)
3574514f5e3Sopenharmony_ci{
3584514f5e3Sopenharmony_ci    ASSERT(!region->InSharedHeap());
3594514f5e3Sopenharmony_ci    JSTaggedType value = slot.GetTaggedType();
3604514f5e3Sopenharmony_ci    if (!JSTaggedValue(value).IsHeapObject()) {
3614514f5e3Sopenharmony_ci        return;
3624514f5e3Sopenharmony_ci    }
3634514f5e3Sopenharmony_ci    Region *valueRegion = Region::ObjectAddressToRange(value);
3644514f5e3Sopenharmony_ci    if (valueRegion->InSharedSweepableSpace()) {
3654514f5e3Sopenharmony_ci        region->AtomicInsertLocalToShareRSet(slot.SlotAddress());
3664514f5e3Sopenharmony_ci    }
3674514f5e3Sopenharmony_ci}
3684514f5e3Sopenharmony_ci
3694514f5e3Sopenharmony_ciinline void SemiGCMarker::MarkValue(uint32_t threadId, TaggedObject *root, ObjectSlot slot)
3704514f5e3Sopenharmony_ci{
3714514f5e3Sopenharmony_ci    JSTaggedValue value(slot.GetTaggedType());
3724514f5e3Sopenharmony_ci    if (value.IsHeapObject()) {
3734514f5e3Sopenharmony_ci        Region *rootRegion = Region::ObjectAddressToRange(root);
3744514f5e3Sopenharmony_ci        if (value.IsWeakForHeapObject()) {
3754514f5e3Sopenharmony_ci            RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()), rootRegion);
3764514f5e3Sopenharmony_ci            return;
3774514f5e3Sopenharmony_ci        }
3784514f5e3Sopenharmony_ci        auto slotStatus = MarkObject(threadId, value.GetTaggedObject(), slot);
3794514f5e3Sopenharmony_ci        if (rootRegion->InGeneralOldSpace() && slotStatus == SlotStatus::KEEP_SLOT) {
3804514f5e3Sopenharmony_ci            SlotNeedUpdate waitUpdate(reinterpret_cast<TaggedObject *>(root), slot);
3814514f5e3Sopenharmony_ci            workManager_->PushSlotNeedUpdate(threadId, waitUpdate);
3824514f5e3Sopenharmony_ci        }
3834514f5e3Sopenharmony_ci    }
3844514f5e3Sopenharmony_ci}
3854514f5e3Sopenharmony_ci
3864514f5e3Sopenharmony_ciinline SlotStatus SemiGCMarker::MarkObject(uint32_t threadId, TaggedObject *object, ObjectSlot slot)
3874514f5e3Sopenharmony_ci{
3884514f5e3Sopenharmony_ci    Region *objectRegion = Region::ObjectAddressToRange(object);
3894514f5e3Sopenharmony_ci    if (objectRegion->InGeneralOldSpace()) {
3904514f5e3Sopenharmony_ci        return SlotStatus::CLEAR_SLOT;
3914514f5e3Sopenharmony_ci    }
3924514f5e3Sopenharmony_ci
3934514f5e3Sopenharmony_ci    MarkWord markWord(object);
3944514f5e3Sopenharmony_ci    if (markWord.IsForwardingAddress()) {
3954514f5e3Sopenharmony_ci        TaggedObject *dst = markWord.ToForwardingAddress();
3964514f5e3Sopenharmony_ci        slot.Update(dst);
3974514f5e3Sopenharmony_ci        Region *valueRegion = Region::ObjectAddressToRange(dst);
3984514f5e3Sopenharmony_ci        return valueRegion->InYoungSpace() ? SlotStatus::KEEP_SLOT : SlotStatus::CLEAR_SLOT;
3994514f5e3Sopenharmony_ci    }
4004514f5e3Sopenharmony_ci    return EvacuateObject(threadId, object, markWord, slot);
4014514f5e3Sopenharmony_ci}
4024514f5e3Sopenharmony_ci
4034514f5e3Sopenharmony_ciinline SlotStatus SemiGCMarker::EvacuateObject(uint32_t threadId, TaggedObject *object, const MarkWord &markWord,
4044514f5e3Sopenharmony_ci    ObjectSlot slot)
4054514f5e3Sopenharmony_ci{
4064514f5e3Sopenharmony_ci    JSHClass *klass = markWord.GetJSHClass();
4074514f5e3Sopenharmony_ci    size_t size = klass->SizeFromJSHClass(object);
4084514f5e3Sopenharmony_ci    bool isPromoted = ShouldBePromoted(object);
4094514f5e3Sopenharmony_ci
4104514f5e3Sopenharmony_ci    uintptr_t forwardAddress = AllocateDstSpace(threadId, size, isPromoted);
4114514f5e3Sopenharmony_ci    RawCopyObject(ToUintPtr(object), forwardAddress, size, markWord);
4124514f5e3Sopenharmony_ci
4134514f5e3Sopenharmony_ci    auto oldValue = markWord.GetValue();
4144514f5e3Sopenharmony_ci    auto result = Barriers::AtomicSetPrimitive(object, 0, oldValue,
4154514f5e3Sopenharmony_ci                                               MarkWord::FromForwardingAddress(forwardAddress));
4164514f5e3Sopenharmony_ci    if (result == oldValue) {
4174514f5e3Sopenharmony_ci        UpdateForwardAddressIfSuccess(threadId, object, klass, forwardAddress, size, slot, isPromoted);
4184514f5e3Sopenharmony_ci        return isPromoted ? SlotStatus::CLEAR_SLOT : SlotStatus::KEEP_SLOT;
4194514f5e3Sopenharmony_ci    }
4204514f5e3Sopenharmony_ci    bool keepSlot = UpdateForwardAddressIfFailed(object, forwardAddress, size, slot);
4214514f5e3Sopenharmony_ci    return keepSlot ? SlotStatus::KEEP_SLOT : SlotStatus::CLEAR_SLOT;
4224514f5e3Sopenharmony_ci}
4234514f5e3Sopenharmony_ci
4244514f5e3Sopenharmony_ciinline bool SemiGCMarker::ShouldBePromoted(TaggedObject *object)
4254514f5e3Sopenharmony_ci{
4264514f5e3Sopenharmony_ci    Region *region = Region::ObjectAddressToRange(object);
4274514f5e3Sopenharmony_ci    return (region->BelowAgeMark() || (region->HasAgeMark() && ToUintPtr(object) < waterLine_));
4284514f5e3Sopenharmony_ci}
4294514f5e3Sopenharmony_ci
4304514f5e3Sopenharmony_ciinline void SemiGCMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref,
4314514f5e3Sopenharmony_ci                                              [[maybe_unused]] Region *objectRegion)
4324514f5e3Sopenharmony_ci{
4334514f5e3Sopenharmony_ci    auto value = JSTaggedValue(*ref);
4344514f5e3Sopenharmony_ci    Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedWeakRef());
4354514f5e3Sopenharmony_ci    if (valueRegion->InYoungSpace()) {
4364514f5e3Sopenharmony_ci        workManager_->PushWeakReference(threadId, ref);
4374514f5e3Sopenharmony_ci    }
4384514f5e3Sopenharmony_ci}
4394514f5e3Sopenharmony_ci
4404514f5e3Sopenharmony_ciinline void CompressGCMarker::MarkValue(uint32_t threadId, ObjectSlot slot)
4414514f5e3Sopenharmony_ci{
4424514f5e3Sopenharmony_ci    JSTaggedValue value(slot.GetTaggedType());
4434514f5e3Sopenharmony_ci    if (value.IsHeapObject()) {
4444514f5e3Sopenharmony_ci        if (value.IsWeakForHeapObject()) {
4454514f5e3Sopenharmony_ci            // It is unnecessary to use region pointer in compressGCMarker.
4464514f5e3Sopenharmony_ci            RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()));
4474514f5e3Sopenharmony_ci            return;
4484514f5e3Sopenharmony_ci        }
4494514f5e3Sopenharmony_ci        MarkObject(threadId, value.GetTaggedObject(), slot);
4504514f5e3Sopenharmony_ci    }
4514514f5e3Sopenharmony_ci}
4524514f5e3Sopenharmony_ci
4534514f5e3Sopenharmony_ciinline SlotStatus CompressGCMarker::MarkObject(uint32_t threadId, TaggedObject *object, ObjectSlot slot)
4544514f5e3Sopenharmony_ci{
4554514f5e3Sopenharmony_ci    Region *objectRegion = Region::ObjectAddressToRange(object);
4564514f5e3Sopenharmony_ci    if (!NeedEvacuate(objectRegion)) {
4574514f5e3Sopenharmony_ci        if (!objectRegion->InSharedHeap() && objectRegion->AtomicMark(object)) {
4584514f5e3Sopenharmony_ci            workManager_->Push(threadId, object);
4594514f5e3Sopenharmony_ci            auto hclass = object->GetClass();
4604514f5e3Sopenharmony_ci            auto size = hclass->SizeFromJSHClass(object);
4614514f5e3Sopenharmony_ci            objectRegion->IncreaseAliveObject(size);
4624514f5e3Sopenharmony_ci        }
4634514f5e3Sopenharmony_ci        return SlotStatus::CLEAR_SLOT;
4644514f5e3Sopenharmony_ci    }
4654514f5e3Sopenharmony_ci
4664514f5e3Sopenharmony_ci    MarkWord markWord(object);
4674514f5e3Sopenharmony_ci    if (markWord.IsForwardingAddress()) {
4684514f5e3Sopenharmony_ci        TaggedObject *dst = markWord.ToForwardingAddress();
4694514f5e3Sopenharmony_ci        slot.Update(dst);
4704514f5e3Sopenharmony_ci        return SlotStatus::CLEAR_SLOT;
4714514f5e3Sopenharmony_ci    }
4724514f5e3Sopenharmony_ci    return EvacuateObject(threadId, object, markWord, slot);
4734514f5e3Sopenharmony_ci}
4744514f5e3Sopenharmony_ci
4754514f5e3Sopenharmony_ciinline uintptr_t CompressGCMarker::AllocateReadOnlySpace(size_t size)
4764514f5e3Sopenharmony_ci{
4774514f5e3Sopenharmony_ci    LockHolder lock(mutex_);
4784514f5e3Sopenharmony_ci    uintptr_t forwardAddress = heap_->GetReadOnlySpace()->Allocate(size);
4794514f5e3Sopenharmony_ci    if (UNLIKELY(forwardAddress == 0)) {
4804514f5e3Sopenharmony_ci        LOG_ECMA_MEM(FATAL) << "Evacuate Read only Object: alloc failed: "
4814514f5e3Sopenharmony_ci                            << " size: " << size;
4824514f5e3Sopenharmony_ci        UNREACHABLE();
4834514f5e3Sopenharmony_ci    }
4844514f5e3Sopenharmony_ci    return forwardAddress;
4854514f5e3Sopenharmony_ci}
4864514f5e3Sopenharmony_ci
4874514f5e3Sopenharmony_ciinline uintptr_t CompressGCMarker::AllocateAppSpawnSpace(size_t size)
4884514f5e3Sopenharmony_ci{
4894514f5e3Sopenharmony_ci    LockHolder lock(mutex_);
4904514f5e3Sopenharmony_ci    uintptr_t forwardAddress = heap_->GetAppSpawnSpace()->Allocate(size);
4914514f5e3Sopenharmony_ci    if (UNLIKELY(forwardAddress == 0)) {
4924514f5e3Sopenharmony_ci        LOG_ECMA_MEM(FATAL) << "Evacuate AppSpawn Object: alloc failed: "
4934514f5e3Sopenharmony_ci                            << " size: " << size;
4944514f5e3Sopenharmony_ci        UNREACHABLE();
4954514f5e3Sopenharmony_ci    }
4964514f5e3Sopenharmony_ci    return forwardAddress;
4974514f5e3Sopenharmony_ci}
4984514f5e3Sopenharmony_ci
4994514f5e3Sopenharmony_ciinline SlotStatus CompressGCMarker::EvacuateObject(uint32_t threadId, TaggedObject *object, const MarkWord &markWord,
5004514f5e3Sopenharmony_ci    ObjectSlot slot)
5014514f5e3Sopenharmony_ci{
5024514f5e3Sopenharmony_ci    JSHClass *klass = markWord.GetJSHClass();
5034514f5e3Sopenharmony_ci    size_t size = klass->SizeFromJSHClass(object);
5044514f5e3Sopenharmony_ci    uintptr_t forwardAddress = AllocateForwardAddress(threadId, size, klass, object);
5054514f5e3Sopenharmony_ci    RawCopyObject(ToUintPtr(object), forwardAddress, size, markWord);
5064514f5e3Sopenharmony_ci
5074514f5e3Sopenharmony_ci    auto oldValue = markWord.GetValue();
5084514f5e3Sopenharmony_ci    auto result = Barriers::AtomicSetPrimitive(object, 0, oldValue,
5094514f5e3Sopenharmony_ci                                               MarkWord::FromForwardingAddress(forwardAddress));
5104514f5e3Sopenharmony_ci    if (result == oldValue) {
5114514f5e3Sopenharmony_ci        UpdateForwardAddressIfSuccess(threadId, object, klass, forwardAddress, size, slot);
5124514f5e3Sopenharmony_ci        Region *region = Region::ObjectAddressToRange(object);
5134514f5e3Sopenharmony_ci        if (region->HasLocalToShareRememberedSet()) {
5144514f5e3Sopenharmony_ci            UpdateLocalToShareRSet(reinterpret_cast<TaggedObject *>(forwardAddress), klass);
5154514f5e3Sopenharmony_ci        }
5164514f5e3Sopenharmony_ci        if (isAppSpawn_ && klass->IsString()) {
5174514f5e3Sopenharmony_ci            // calculate and set hashcode for read-only ecmastring in advance
5184514f5e3Sopenharmony_ci            EcmaStringAccessor(reinterpret_cast<TaggedObject *>(forwardAddress)).GetHashcode();
5194514f5e3Sopenharmony_ci        }
5204514f5e3Sopenharmony_ci        return SlotStatus::CLEAR_SLOT;
5214514f5e3Sopenharmony_ci    }
5224514f5e3Sopenharmony_ci    UpdateForwardAddressIfFailed(object, forwardAddress, size, slot);
5234514f5e3Sopenharmony_ci    return SlotStatus::CLEAR_SLOT;
5244514f5e3Sopenharmony_ci}
5254514f5e3Sopenharmony_ci
5264514f5e3Sopenharmony_ciinline void CompressGCMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref,
5274514f5e3Sopenharmony_ci                                                  [[maybe_unused]] Region *objectRegion)
5284514f5e3Sopenharmony_ci{
5294514f5e3Sopenharmony_ci    workManager_->PushWeakReference(threadId, ref);
5304514f5e3Sopenharmony_ci}
5314514f5e3Sopenharmony_ci
5324514f5e3Sopenharmony_ciinline bool CompressGCMarker::NeedEvacuate(Region *region)
5334514f5e3Sopenharmony_ci{
5344514f5e3Sopenharmony_ci    if (isAppSpawn_) {
5354514f5e3Sopenharmony_ci        return !region->InHugeObjectSpace()  && !region->InReadOnlySpace() && !region->InNonMovableSpace() &&
5364514f5e3Sopenharmony_ci               !region->InSharedHeap();
5374514f5e3Sopenharmony_ci    }
5384514f5e3Sopenharmony_ci    return region->InYoungOrOldSpace();
5394514f5e3Sopenharmony_ci}
5404514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
5414514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_MEM_PARALLEL_MARKER_INL_H
542