14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021-2022 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_SPACE_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_MEM_SPACE_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include "ecmascript/mem/allocation_inspector.h"
204514f5e3Sopenharmony_ci#include "ecmascript/mem/allocator.h"
214514f5e3Sopenharmony_ci#include "ecmascript/mem/c_containers.h"
224514f5e3Sopenharmony_ci#include "ecmascript/mem/ecma_list.h"
234514f5e3Sopenharmony_ci#include "ecmascript/mem/heap_region_allocator.h"
244514f5e3Sopenharmony_ci#include "ecmascript/mem/mem.h"
254514f5e3Sopenharmony_ci#include "ecmascript/mem/region.h"
264514f5e3Sopenharmony_ci
274514f5e3Sopenharmony_ci#include "securec.h"
284514f5e3Sopenharmony_ci
294514f5e3Sopenharmony_cinamespace panda::ecmascript {
304514f5e3Sopenharmony_cienum MemSpaceType {
314514f5e3Sopenharmony_ci    OLD_SPACE = 0,
324514f5e3Sopenharmony_ci    NON_MOVABLE,
334514f5e3Sopenharmony_ci    MACHINE_CODE_SPACE,
344514f5e3Sopenharmony_ci    HUGE_OBJECT_SPACE,
354514f5e3Sopenharmony_ci    EDEN_SPACE,
364514f5e3Sopenharmony_ci    SEMI_SPACE,
374514f5e3Sopenharmony_ci    SNAPSHOT_SPACE,
384514f5e3Sopenharmony_ci    COMPRESS_SPACE,
394514f5e3Sopenharmony_ci    LOCAL_SPACE,
404514f5e3Sopenharmony_ci    READ_ONLY_SPACE,
414514f5e3Sopenharmony_ci    APPSPAWN_SPACE,
424514f5e3Sopenharmony_ci    HUGE_MACHINE_CODE_SPACE,
434514f5e3Sopenharmony_ci    SHARED_OLD_SPACE,
444514f5e3Sopenharmony_ci    SHARED_NON_MOVABLE,
454514f5e3Sopenharmony_ci    SHARED_READ_ONLY_SPACE,
464514f5e3Sopenharmony_ci    SHARED_HUGE_OBJECT_SPACE,
474514f5e3Sopenharmony_ci    SHARED_LOCAL_SPACE,
484514f5e3Sopenharmony_ci    SHARED_COMPRESS_SPACE,
494514f5e3Sopenharmony_ci    SHARED_APPSPAWN_SPACE,
504514f5e3Sopenharmony_ci    SPACE_TYPE_LAST,  // Count of different types
514514f5e3Sopenharmony_ci
524514f5e3Sopenharmony_ci    SHARED_BEGIN = SHARED_OLD_SPACE,
534514f5e3Sopenharmony_ci    SHARED_END = SHARED_HUGE_OBJECT_SPACE,
544514f5e3Sopenharmony_ci    // Free region means memory maybe always in use and can not be evacuated
554514f5e3Sopenharmony_ci    FREE_LIST_NUM = MACHINE_CODE_SPACE - OLD_SPACE + 1,
564514f5e3Sopenharmony_ci    SHARED_SWEEPING_SPACE_BEGIN = SHARED_OLD_SPACE,
574514f5e3Sopenharmony_ci    SHARED_SWEEPING_SPACE_END = SHARED_NON_MOVABLE,
584514f5e3Sopenharmony_ci    SHARED_SWEEPING_SPACE_NUM = SHARED_SWEEPING_SPACE_END - SHARED_SWEEPING_SPACE_BEGIN + 1,
594514f5e3Sopenharmony_ci};
604514f5e3Sopenharmony_ci
614514f5e3Sopenharmony_cienum class MemSpaceKind {
624514f5e3Sopenharmony_ci    LOCAL = 0,
634514f5e3Sopenharmony_ci    SHARED = 1
644514f5e3Sopenharmony_ci};
654514f5e3Sopenharmony_ci
664514f5e3Sopenharmony_cienum class AllocateEventType {
674514f5e3Sopenharmony_ci    NORMAL,
684514f5e3Sopenharmony_ci    DESERIALIZE,
694514f5e3Sopenharmony_ci};
704514f5e3Sopenharmony_ci
714514f5e3Sopenharmony_cistatic inline bool IsSMemSpace(MemSpaceType type)
724514f5e3Sopenharmony_ci{
734514f5e3Sopenharmony_ci    return (type >= MemSpaceType::SHARED_BEGIN) && (type <= MemSpaceType::SHARED_END);
744514f5e3Sopenharmony_ci}
754514f5e3Sopenharmony_ci
764514f5e3Sopenharmony_cistatic inline std::string ToSpaceTypeName(MemSpaceType type)
774514f5e3Sopenharmony_ci{
784514f5e3Sopenharmony_ci    switch (type) {
794514f5e3Sopenharmony_ci        case OLD_SPACE:
804514f5e3Sopenharmony_ci            return "old space";
814514f5e3Sopenharmony_ci        case NON_MOVABLE:
824514f5e3Sopenharmony_ci            return "non movable space";
834514f5e3Sopenharmony_ci        case MACHINE_CODE_SPACE:
844514f5e3Sopenharmony_ci            return "machine code space";
854514f5e3Sopenharmony_ci        case HUGE_OBJECT_SPACE:
864514f5e3Sopenharmony_ci            return "huge object space";
874514f5e3Sopenharmony_ci        case EDEN_SPACE:
884514f5e3Sopenharmony_ci            return "eden space";
894514f5e3Sopenharmony_ci        case SEMI_SPACE:
904514f5e3Sopenharmony_ci            return "semi space";
914514f5e3Sopenharmony_ci        case SNAPSHOT_SPACE:
924514f5e3Sopenharmony_ci            return "snapshot space";
934514f5e3Sopenharmony_ci        case COMPRESS_SPACE:
944514f5e3Sopenharmony_ci            return "compress space";
954514f5e3Sopenharmony_ci        case LOCAL_SPACE:
964514f5e3Sopenharmony_ci            return "local space";
974514f5e3Sopenharmony_ci        case READ_ONLY_SPACE:
984514f5e3Sopenharmony_ci            return "read only space";
994514f5e3Sopenharmony_ci        case APPSPAWN_SPACE:
1004514f5e3Sopenharmony_ci            return "appspawn space";
1014514f5e3Sopenharmony_ci        case HUGE_MACHINE_CODE_SPACE:
1024514f5e3Sopenharmony_ci            return "huge machine code space";
1034514f5e3Sopenharmony_ci        case SHARED_NON_MOVABLE:
1044514f5e3Sopenharmony_ci            return "shared non movable space";
1054514f5e3Sopenharmony_ci        case SHARED_OLD_SPACE:
1064514f5e3Sopenharmony_ci            return "shared old space";
1074514f5e3Sopenharmony_ci        case SHARED_READ_ONLY_SPACE:
1084514f5e3Sopenharmony_ci            return "shared read only space";
1094514f5e3Sopenharmony_ci        case SHARED_HUGE_OBJECT_SPACE:
1104514f5e3Sopenharmony_ci            return "shared huge object space";
1114514f5e3Sopenharmony_ci        case SHARED_COMPRESS_SPACE:
1124514f5e3Sopenharmony_ci            return "compress space";
1134514f5e3Sopenharmony_ci        case SHARED_LOCAL_SPACE:
1144514f5e3Sopenharmony_ci            return "shared local space";
1154514f5e3Sopenharmony_ci        case SHARED_APPSPAWN_SPACE:
1164514f5e3Sopenharmony_ci            return "shared appspawn space";
1174514f5e3Sopenharmony_ci        default:
1184514f5e3Sopenharmony_ci            return "unknown space";
1194514f5e3Sopenharmony_ci    }
1204514f5e3Sopenharmony_ci}
1214514f5e3Sopenharmony_ci
1224514f5e3Sopenharmony_ciclass Space {
1234514f5e3Sopenharmony_cipublic:
1244514f5e3Sopenharmony_ci    Space(BaseHeap* heap, HeapRegionAllocator *regionAllocator, MemSpaceType spaceType, size_t initialCapacity,
1254514f5e3Sopenharmony_ci          size_t maximumCapacity);
1264514f5e3Sopenharmony_ci    virtual ~Space() = default;
1274514f5e3Sopenharmony_ci    NO_COPY_SEMANTIC(Space);
1284514f5e3Sopenharmony_ci    NO_MOVE_SEMANTIC(Space);
1294514f5e3Sopenharmony_ci
1304514f5e3Sopenharmony_ci    size_t GetMaximumCapacity() const
1314514f5e3Sopenharmony_ci    {
1324514f5e3Sopenharmony_ci        return maximumCapacity_;
1334514f5e3Sopenharmony_ci    }
1344514f5e3Sopenharmony_ci
1354514f5e3Sopenharmony_ci    void SetMaximumCapacity(size_t maximumCapacity)
1364514f5e3Sopenharmony_ci    {
1374514f5e3Sopenharmony_ci        maximumCapacity_ = maximumCapacity;
1384514f5e3Sopenharmony_ci    }
1394514f5e3Sopenharmony_ci
1404514f5e3Sopenharmony_ci    size_t GetOverShootMaximumCapacity() const
1414514f5e3Sopenharmony_ci    {
1424514f5e3Sopenharmony_ci        return maximumCapacity_ + outOfMemoryOvershootSize_;
1434514f5e3Sopenharmony_ci    }
1444514f5e3Sopenharmony_ci
1454514f5e3Sopenharmony_ci    size_t GetInitialCapacity() const
1464514f5e3Sopenharmony_ci    {
1474514f5e3Sopenharmony_ci        return initialCapacity_;
1484514f5e3Sopenharmony_ci    }
1494514f5e3Sopenharmony_ci
1504514f5e3Sopenharmony_ci    void SetInitialCapacity(size_t initialCapacity)
1514514f5e3Sopenharmony_ci    {
1524514f5e3Sopenharmony_ci        initialCapacity_ = initialCapacity;
1534514f5e3Sopenharmony_ci    }
1544514f5e3Sopenharmony_ci
1554514f5e3Sopenharmony_ci    size_t GetCommittedSize() const
1564514f5e3Sopenharmony_ci    {
1574514f5e3Sopenharmony_ci        return committedSize_;
1584514f5e3Sopenharmony_ci    }
1594514f5e3Sopenharmony_ci
1604514f5e3Sopenharmony_ci    void IncreaseCommitted(size_t bytes)
1614514f5e3Sopenharmony_ci    {
1624514f5e3Sopenharmony_ci        committedSize_ += bytes;
1634514f5e3Sopenharmony_ci    }
1644514f5e3Sopenharmony_ci
1654514f5e3Sopenharmony_ci    void DecreaseCommitted(size_t bytes)
1664514f5e3Sopenharmony_ci    {
1674514f5e3Sopenharmony_ci        committedSize_ -= bytes;
1684514f5e3Sopenharmony_ci    }
1694514f5e3Sopenharmony_ci
1704514f5e3Sopenharmony_ci    void IncreaseObjectSize(size_t bytes)
1714514f5e3Sopenharmony_ci    {
1724514f5e3Sopenharmony_ci        objectSize_ += bytes;
1734514f5e3Sopenharmony_ci    }
1744514f5e3Sopenharmony_ci
1754514f5e3Sopenharmony_ci    void DecreaseObjectSize(size_t bytes)
1764514f5e3Sopenharmony_ci    {
1774514f5e3Sopenharmony_ci        objectSize_ -= bytes;
1784514f5e3Sopenharmony_ci    }
1794514f5e3Sopenharmony_ci
1804514f5e3Sopenharmony_ci    size_t GetObjectSize()
1814514f5e3Sopenharmony_ci    {
1824514f5e3Sopenharmony_ci        return objectSize_;
1834514f5e3Sopenharmony_ci    }
1844514f5e3Sopenharmony_ci
1854514f5e3Sopenharmony_ci    size_t GetOutOfMemoryOvershootSize() const
1864514f5e3Sopenharmony_ci    {
1874514f5e3Sopenharmony_ci        return outOfMemoryOvershootSize_;
1884514f5e3Sopenharmony_ci    }
1894514f5e3Sopenharmony_ci
1904514f5e3Sopenharmony_ci    void IncreaseOutOfMemoryOvershootSize(size_t size)
1914514f5e3Sopenharmony_ci    {
1924514f5e3Sopenharmony_ci        outOfMemoryOvershootSize_ += size;
1934514f5e3Sopenharmony_ci    }
1944514f5e3Sopenharmony_ci
1954514f5e3Sopenharmony_ci    void DecreaseOutOfMemoryOvershootSize(size_t size)
1964514f5e3Sopenharmony_ci    {
1974514f5e3Sopenharmony_ci        ASSERT(outOfMemoryOvershootSize_ >= size);
1984514f5e3Sopenharmony_ci        outOfMemoryOvershootSize_ -= size;
1994514f5e3Sopenharmony_ci    }
2004514f5e3Sopenharmony_ci
2014514f5e3Sopenharmony_ci    MemSpaceType GetSpaceType() const
2024514f5e3Sopenharmony_ci    {
2034514f5e3Sopenharmony_ci        return spaceType_;
2044514f5e3Sopenharmony_ci    }
2054514f5e3Sopenharmony_ci
2064514f5e3Sopenharmony_ci    inline RegionSpaceFlag GetRegionFlag() const;
2074514f5e3Sopenharmony_ci
2084514f5e3Sopenharmony_ci    uintptr_t GetAllocateAreaBegin() const
2094514f5e3Sopenharmony_ci    {
2104514f5e3Sopenharmony_ci        return regionList_.GetLast()->GetBegin();
2114514f5e3Sopenharmony_ci    }
2124514f5e3Sopenharmony_ci
2134514f5e3Sopenharmony_ci    uintptr_t GetAllocateAreaEnd() const
2144514f5e3Sopenharmony_ci    {
2154514f5e3Sopenharmony_ci        return regionList_.GetLast()->GetEnd();
2164514f5e3Sopenharmony_ci    }
2174514f5e3Sopenharmony_ci
2184514f5e3Sopenharmony_ci    Region *GetCurrentRegion() const
2194514f5e3Sopenharmony_ci    {
2204514f5e3Sopenharmony_ci        return regionList_.GetLast();
2214514f5e3Sopenharmony_ci    }
2224514f5e3Sopenharmony_ci
2234514f5e3Sopenharmony_ci    Region *GetFirstRegion() const
2244514f5e3Sopenharmony_ci    {
2254514f5e3Sopenharmony_ci        return regionList_.GetFirst();
2264514f5e3Sopenharmony_ci    }
2274514f5e3Sopenharmony_ci
2284514f5e3Sopenharmony_ci    uint32_t GetRegionCount()
2294514f5e3Sopenharmony_ci    {
2304514f5e3Sopenharmony_ci        return regionList_.GetLength();
2314514f5e3Sopenharmony_ci    }
2324514f5e3Sopenharmony_ci
2334514f5e3Sopenharmony_ci    EcmaList<Region> &GetRegionList()
2344514f5e3Sopenharmony_ci    {
2354514f5e3Sopenharmony_ci        return regionList_;
2364514f5e3Sopenharmony_ci    }
2374514f5e3Sopenharmony_ci
2384514f5e3Sopenharmony_ci    const EcmaList<Region> &GetRegionList() const
2394514f5e3Sopenharmony_ci    {
2404514f5e3Sopenharmony_ci        return regionList_;
2414514f5e3Sopenharmony_ci    }
2424514f5e3Sopenharmony_ci
2434514f5e3Sopenharmony_ci    void SetRecordRegion()
2444514f5e3Sopenharmony_ci    {
2454514f5e3Sopenharmony_ci        recordRegion_ = GetCurrentRegion();
2464514f5e3Sopenharmony_ci    }
2474514f5e3Sopenharmony_ci
2484514f5e3Sopenharmony_ci    bool IsOOMDumpSpace()
2494514f5e3Sopenharmony_ci    {
2504514f5e3Sopenharmony_ci        return spaceType_ == SEMI_SPACE || spaceType_ == OLD_SPACE || spaceType_ == NON_MOVABLE ||
2514514f5e3Sopenharmony_ci            spaceType_ == HUGE_OBJECT_SPACE;
2524514f5e3Sopenharmony_ci    }
2534514f5e3Sopenharmony_ci
2544514f5e3Sopenharmony_ci    // methods for allocation inspector
2554514f5e3Sopenharmony_ci    void AddAllocationInspector(AllocationInspector* inspector);
2564514f5e3Sopenharmony_ci    void ClearAllocationInspector();
2574514f5e3Sopenharmony_ci    void SwapAllocationCounter(Space *space);
2584514f5e3Sopenharmony_ci
2594514f5e3Sopenharmony_ci    template <class Callback>
2604514f5e3Sopenharmony_ci    inline void EnumerateRegions(const Callback &cb, Region *region = nullptr) const;
2614514f5e3Sopenharmony_ci    template <class Callback>
2624514f5e3Sopenharmony_ci    inline void EnumerateRegionsWithRecord(const Callback &cb) const;
2634514f5e3Sopenharmony_ci
2644514f5e3Sopenharmony_ci    inline void AddRegion(Region *region);
2654514f5e3Sopenharmony_ci    inline void RemoveRegion(Region *region);
2664514f5e3Sopenharmony_ci
2674514f5e3Sopenharmony_ci    virtual void Initialize() {};
2684514f5e3Sopenharmony_ci    void Destroy();
2694514f5e3Sopenharmony_ci
2704514f5e3Sopenharmony_ci    void ReclaimRegions(size_t cachedSize = 0);
2714514f5e3Sopenharmony_ci
2724514f5e3Sopenharmony_ciprotected:
2734514f5e3Sopenharmony_ci    void ClearAndFreeRegion(Region *region, size_t cachedSize = 0);
2744514f5e3Sopenharmony_ci
2754514f5e3Sopenharmony_ci    BaseHeap *heap_ {nullptr};
2764514f5e3Sopenharmony_ci    HeapRegionAllocator *heapRegionAllocator_ {nullptr};
2774514f5e3Sopenharmony_ci    EcmaList<Region> regionList_ {};
2784514f5e3Sopenharmony_ci    MemSpaceType spaceType_ {};
2794514f5e3Sopenharmony_ci    size_t initialCapacity_ {0};
2804514f5e3Sopenharmony_ci    size_t maximumCapacity_ {0};
2814514f5e3Sopenharmony_ci    size_t committedSize_ {0};
2824514f5e3Sopenharmony_ci    size_t objectSize_ {0};
2834514f5e3Sopenharmony_ci    size_t outOfMemoryOvershootSize_ {0};
2844514f5e3Sopenharmony_ci    Region *recordRegion_ {nullptr};
2854514f5e3Sopenharmony_ci    AllocationCounter allocationCounter_;
2864514f5e3Sopenharmony_ci};
2874514f5e3Sopenharmony_ci
2884514f5e3Sopenharmony_ciclass HugeObjectSpace : public Space {
2894514f5e3Sopenharmony_cipublic:
2904514f5e3Sopenharmony_ci    HugeObjectSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity,
2914514f5e3Sopenharmony_ci                    size_t maximumCapacity);
2924514f5e3Sopenharmony_ci    HugeObjectSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity,
2934514f5e3Sopenharmony_ci                    size_t maximumCapacity, MemSpaceType spaceType);
2944514f5e3Sopenharmony_ci    ~HugeObjectSpace() override = default;
2954514f5e3Sopenharmony_ci    NO_COPY_SEMANTIC(HugeObjectSpace);
2964514f5e3Sopenharmony_ci    NO_MOVE_SEMANTIC(HugeObjectSpace);
2974514f5e3Sopenharmony_ci    // Sometimes it is unsafe to checkSafePoint here, e.g. in deserialize, if do checkSafePoint JSThread may be
2984514f5e3Sopenharmony_ci    // suspended and then do SharedGC, which will free some regions in SharedHeap that are allocated at the beginning
2994514f5e3Sopenharmony_ci    // of deserializing for further object allocating, but no object has been allocated on at this moment.
3004514f5e3Sopenharmony_ci    uintptr_t Allocate(size_t objectSize, JSThread *thread, AllocateEventType allocType = AllocateEventType::NORMAL);
3014514f5e3Sopenharmony_ci    void Sweep();
3024514f5e3Sopenharmony_ci    size_t GetHeapObjectSize() const;
3034514f5e3Sopenharmony_ci    void IterateOverObjects(const std::function<void(TaggedObject *object)> &objectVisitor) const;
3044514f5e3Sopenharmony_ci
3054514f5e3Sopenharmony_ci    void ReclaimHugeRegion();
3064514f5e3Sopenharmony_ci
3074514f5e3Sopenharmony_ci    void InvokeAllocationInspector(Address object, size_t objectSize);
3084514f5e3Sopenharmony_ci
3094514f5e3Sopenharmony_ciprotected:
3104514f5e3Sopenharmony_ci    static constexpr size_t HUGE_OBJECT_BITSET_SIZE = 16;
3114514f5e3Sopenharmony_ciprivate:
3124514f5e3Sopenharmony_ci    EcmaList<Region> hugeNeedFreeList_ {};
3134514f5e3Sopenharmony_ci};
3144514f5e3Sopenharmony_ci
3154514f5e3Sopenharmony_ciclass HugeMachineCodeSpace : public HugeObjectSpace {
3164514f5e3Sopenharmony_cipublic:
3174514f5e3Sopenharmony_ci    HugeMachineCodeSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity,
3184514f5e3Sopenharmony_ci                         size_t maximumCapacity);
3194514f5e3Sopenharmony_ci    uintptr_t GetMachineCodeObject(uintptr_t pc) const;
3204514f5e3Sopenharmony_ci    uintptr_t Allocate(size_t objectSize, JSThread *thread, void *desc,
3214514f5e3Sopenharmony_ci        AllocateEventType allocType = AllocateEventType::NORMAL);
3224514f5e3Sopenharmony_ci    uintptr_t Allocate(size_t objectSize, JSThread *thread);
3234514f5e3Sopenharmony_ci    Region *PUBLIC_API AllocateFort(size_t objectSize, JSThread *thread, void *desc);
3244514f5e3Sopenharmony_ci};
3254514f5e3Sopenharmony_ci
3264514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
3274514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_MEM_SPACE_H
328