14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2024 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_JIT_FORT_MEMDESC_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_MEM_JIT_FORT_MEMDESC_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include <deque>
204514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value.h"
214514f5e3Sopenharmony_ci#include "ecmascript/base/asan_interface.h"
224514f5e3Sopenharmony_ci#include "ecmascript/platform/mutex.h"
234514f5e3Sopenharmony_ci
244514f5e3Sopenharmony_cinamespace panda::ecmascript {
254514f5e3Sopenharmony_ci
264514f5e3Sopenharmony_ci// Before Jit Fort, FreeList allocator uses FreeObject to link
274514f5e3Sopenharmony_ci// together free memory blocks in heap regions where each
284514f5e3Sopenharmony_ci// free memory block is a FreeObject with size of the block and
294514f5e3Sopenharmony_ci// a pointer to the next free block in the heap region. Its usage
304514f5e3Sopenharmony_ci// requires a mutable heap region and does not work with Jit Fort space
314514f5e3Sopenharmony_ci// which is immutbale execept for access by CodeSigner.
324514f5e3Sopenharmony_ci//
334514f5e3Sopenharmony_ci// When JIT Fort is enabled, FreeObject usage is replaced by MemDesc
344514f5e3Sopenharmony_ci// which serves same purpose as FreeObjects, but is stored outside of
354514f5e3Sopenharmony_ci// JitFort memory space.
364514f5e3Sopenharmony_ci//
374514f5e3Sopenharmony_ci// To reuse FreeList allocator code for JitFort, related classes
384514f5e3Sopenharmony_ci// (allocator/FreeObjectList/FreeObjectSet, etc) had to be changed into
394514f5e3Sopenharmony_ci// template classes to support both FreeObject and MemDesc targets,
404514f5e3Sopenharmony_ci// and MemDesc has to support same methods as FreeObject, and use the
414514f5e3Sopenharmony_ci// same null pointer value forlink pointer that FreeObject uses, i.e.
424514f5e3Sopenharmony_ci// NULL_POINTER with a value of 0x5 instead of 0.
434514f5e3Sopenharmony_ci//
444514f5e3Sopenharmony_ci#define INVALID_OBJPTR ((uintptr_t) JSTaggedValue::NULL_POINTER)
454514f5e3Sopenharmony_ci
464514f5e3Sopenharmony_ciclass MemDesc {
474514f5e3Sopenharmony_cipublic:
484514f5e3Sopenharmony_ci    MemDesc() = default;
494514f5e3Sopenharmony_ci    ~MemDesc() = default;
504514f5e3Sopenharmony_ci
514514f5e3Sopenharmony_ci    static MemDesc *Cast(uintptr_t object)
524514f5e3Sopenharmony_ci    {
534514f5e3Sopenharmony_ci        return reinterpret_cast<MemDesc *>(object);
544514f5e3Sopenharmony_ci    }
554514f5e3Sopenharmony_ci
564514f5e3Sopenharmony_ci    inline uintptr_t GetBegin() const
574514f5e3Sopenharmony_ci    {
584514f5e3Sopenharmony_ci        return mem_;
594514f5e3Sopenharmony_ci    }
604514f5e3Sopenharmony_ci
614514f5e3Sopenharmony_ci    inline uintptr_t GetEnd() const
624514f5e3Sopenharmony_ci    {
634514f5e3Sopenharmony_ci        return mem_ + size_;
644514f5e3Sopenharmony_ci    }
654514f5e3Sopenharmony_ci
664514f5e3Sopenharmony_ci    inline void SetMem(uintptr_t mem)
674514f5e3Sopenharmony_ci    {
684514f5e3Sopenharmony_ci        mem_ = mem;
694514f5e3Sopenharmony_ci    }
704514f5e3Sopenharmony_ci
714514f5e3Sopenharmony_ci    inline void SetSize(size_t size)
724514f5e3Sopenharmony_ci    {
734514f5e3Sopenharmony_ci        size_ = size;
744514f5e3Sopenharmony_ci    }
754514f5e3Sopenharmony_ci
764514f5e3Sopenharmony_ci    inline void SetNext(MemDesc *desc)
774514f5e3Sopenharmony_ci    {
784514f5e3Sopenharmony_ci        next_ = desc;
794514f5e3Sopenharmony_ci    }
804514f5e3Sopenharmony_ci
814514f5e3Sopenharmony_ci    inline MemDesc *GetNext()
824514f5e3Sopenharmony_ci    {
834514f5e3Sopenharmony_ci        return next_;
844514f5e3Sopenharmony_ci    }
854514f5e3Sopenharmony_ci
864514f5e3Sopenharmony_ci    inline uint32_t Available() const
874514f5e3Sopenharmony_ci    {
884514f5e3Sopenharmony_ci        return size_;
894514f5e3Sopenharmony_ci    }
904514f5e3Sopenharmony_ci
914514f5e3Sopenharmony_ci    inline bool IsFreeObject() const
924514f5e3Sopenharmony_ci    {
934514f5e3Sopenharmony_ci        return true; // for compatibility with FreeObject
944514f5e3Sopenharmony_ci    }
954514f5e3Sopenharmony_ci
964514f5e3Sopenharmony_ci    inline void SetAvailable(uint32_t size)
974514f5e3Sopenharmony_ci    {
984514f5e3Sopenharmony_ci        size_ = size;
994514f5e3Sopenharmony_ci    }
1004514f5e3Sopenharmony_ci
1014514f5e3Sopenharmony_ci    inline void AsanPoisonFreeObject() const
1024514f5e3Sopenharmony_ci    {
1034514f5e3Sopenharmony_ci        ASAN_POISON_MEMORY_REGION((const volatile void *)mem_, size_);
1044514f5e3Sopenharmony_ci    }
1054514f5e3Sopenharmony_ci
1064514f5e3Sopenharmony_ci    inline void AsanUnPoisonFreeObject() const
1074514f5e3Sopenharmony_ci    {
1084514f5e3Sopenharmony_ci        ASAN_UNPOISON_MEMORY_REGION((const volatile void *)mem_, size_);
1094514f5e3Sopenharmony_ci    }
1104514f5e3Sopenharmony_ci
1114514f5e3Sopenharmony_ci    inline void SetInstalled(bool installed)
1124514f5e3Sopenharmony_ci    {
1134514f5e3Sopenharmony_ci        installed_.store(installed, std::memory_order_release);
1144514f5e3Sopenharmony_ci    }
1154514f5e3Sopenharmony_ci
1164514f5e3Sopenharmony_ci    inline bool IsInstalled()
1174514f5e3Sopenharmony_ci    {
1184514f5e3Sopenharmony_ci        return installed_.load(std::memory_order_acquire);
1194514f5e3Sopenharmony_ci    }
1204514f5e3Sopenharmony_ci
1214514f5e3Sopenharmony_ciprivate:
1224514f5e3Sopenharmony_ci    uintptr_t mem_ {0};
1234514f5e3Sopenharmony_ci    size_t size_ {0};
1244514f5e3Sopenharmony_ci    std::atomic<bool> installed_ {false};
1254514f5e3Sopenharmony_ci    MemDesc *next_ {MemDesc::Cast(INVALID_OBJPTR)};
1264514f5e3Sopenharmony_ci};
1274514f5e3Sopenharmony_ci
1284514f5e3Sopenharmony_ciclass MemDescPool {
1294514f5e3Sopenharmony_cipublic:
1304514f5e3Sopenharmony_ci    MemDescPool(uintptr_t fortBegin, size_t fortSize);
1314514f5e3Sopenharmony_ci    ~MemDescPool();
1324514f5e3Sopenharmony_ci
1334514f5e3Sopenharmony_ci    static inline bool IsEmpty(MemDesc* list)
1344514f5e3Sopenharmony_ci    {
1354514f5e3Sopenharmony_ci        return (list == nullptr || list == MemDesc::Cast(INVALID_OBJPTR));
1364514f5e3Sopenharmony_ci    }
1374514f5e3Sopenharmony_ci
1384514f5e3Sopenharmony_ci    inline MemDesc *GetDescFromPool()
1394514f5e3Sopenharmony_ci    {
1404514f5e3Sopenharmony_ci        LockHolder lock(lock_);
1414514f5e3Sopenharmony_ci        return GetDesc();
1424514f5e3Sopenharmony_ci    }
1434514f5e3Sopenharmony_ci
1444514f5e3Sopenharmony_ci    inline void ReturnDescToPool(MemDesc *desc)
1454514f5e3Sopenharmony_ci    {
1464514f5e3Sopenharmony_ci        LockHolder lock(lock_);
1474514f5e3Sopenharmony_ci        Add(desc);
1484514f5e3Sopenharmony_ci        returned_++;
1494514f5e3Sopenharmony_ci    }
1504514f5e3Sopenharmony_ci
1514514f5e3Sopenharmony_ci    inline uintptr_t JitFortBegin()
1524514f5e3Sopenharmony_ci    {
1534514f5e3Sopenharmony_ci        return fortBegin_;
1544514f5e3Sopenharmony_ci    }
1554514f5e3Sopenharmony_ci
1564514f5e3Sopenharmony_ci    inline size_t JitFortSize()
1574514f5e3Sopenharmony_ci    {
1584514f5e3Sopenharmony_ci        return fortSize_;
1594514f5e3Sopenharmony_ci    }
1604514f5e3Sopenharmony_ci
1614514f5e3Sopenharmony_ciprivate:
1624514f5e3Sopenharmony_ci    MemDesc *GetDesc();
1634514f5e3Sopenharmony_ci    void Add(MemDesc *);
1644514f5e3Sopenharmony_ci    void Expand();
1654514f5e3Sopenharmony_ci
1664514f5e3Sopenharmony_ci    static constexpr size_t MEMDESCS_PER_BLOCK = 100;
1674514f5e3Sopenharmony_ci    MemDesc *freeList_ {nullptr};
1684514f5e3Sopenharmony_ci    std::deque<void *> memDescBlocks_;
1694514f5e3Sopenharmony_ci    size_t allocated_ {0};
1704514f5e3Sopenharmony_ci    size_t returned_ {0};
1714514f5e3Sopenharmony_ci    size_t highwater_ {0};
1724514f5e3Sopenharmony_ci    Mutex lock_;
1734514f5e3Sopenharmony_ci
1744514f5e3Sopenharmony_ci    uintptr_t fortBegin_;
1754514f5e3Sopenharmony_ci    size_t fortSize_;
1764514f5e3Sopenharmony_ci};
1774514f5e3Sopenharmony_ci
1784514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
1794514f5e3Sopenharmony_ci
1804514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_MEM_JIT_FORT_MEMDESC_H
181