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, ®ion, 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, ®ion](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, ®ion](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