1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ECMASCRIPT_MEM_LINEAR_SPACE_H
17#define ECMASCRIPT_MEM_LINEAR_SPACE_H
18
19#include "ecmascript/mem/space-inl.h"
20
21namespace panda::ecmascript {
22class LinearSpace : public Space {
23public:
24    LinearSpace(Heap *heap, MemSpaceType type, size_t initialCapacity, size_t maximumCapacity);
25    NO_COPY_SEMANTIC(LinearSpace);
26    NO_MOVE_SEMANTIC(LinearSpace);
27    uintptr_t Allocate(size_t size, bool isPromoted = false);
28    bool Expand(bool isPromoted);
29    void Stop();
30    void ResetAllocator();
31    void IterateOverObjects(const std::function<void(TaggedObject *object)> &objectVisitor) const;
32
33    const uintptr_t *GetAllocationTopAddress()
34    {
35        return allocator_.GetTopAddress();
36    }
37    const uintptr_t *GetAllocationEndAddress()
38    {
39        return allocator_.GetEndAddress();
40    }
41    size_t GetOvershootSize() const
42    {
43        return overShootSize_;
44    }
45    void InvokeAllocationInspector(Address object, size_t size, size_t alignedSize);
46
47    void RecordCurrentRegionAsHalfFresh()
48    {
49        Region *region = GetCurrentRegion();
50        ASSERT(region != nullptr);
51        ASSERT(!region->IsFreshRegion() && !region->IsHalfFreshRegion());
52        region->SetRegionTypeFlag(RegionTypeFlag::HALF_FRESH);
53        freshObjectWaterLine_ = allocator_.GetTop();
54        ASSERT(region->InRange(freshObjectWaterLine_));
55    }
56
57    bool IsFreshObjectInHalfFreshRegion(TaggedObject *object)
58    {
59        uintptr_t addr = ToUintPtr(object);
60        ASSERT(Region::ObjectAddressToRange(object)->IsHalfFreshRegion());
61        ASSERT(Region::ObjectAddressToRange(object)->InRange(addr));
62        return addr >= freshObjectWaterLine_;
63    }
64
65protected:
66    Heap *localHeap_;
67    JSThread *thread_ {nullptr};
68    BumpPointerAllocator allocator_;
69    size_t overShootSize_ {0};
70    size_t overShootSizeForConcurrentMark_ {0};
71    size_t allocateAfterLastGC_ {0};
72    size_t survivalObjectSize_ {0};
73    uintptr_t waterLine_ {0};
74    // This value is set in ConcurrentMark::InitializeMarking before post GC task, so do not need atomic store/load.
75    uintptr_t freshObjectWaterLine_ {0};
76};
77
78class EdenSpace : public LinearSpace {
79public:
80    EdenSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity);
81    ~EdenSpace() override;
82    NO_COPY_SEMANTIC(EdenSpace);
83    NO_MOVE_SEMANTIC(EdenSpace);
84
85    void Initialize() override;
86    void Restart();
87
88    uintptr_t AllocateSync(size_t size);
89    uintptr_t Allocate(size_t size);
90    bool Expand();
91    void SetOverShootSize(size_t size);
92
93    uintptr_t GetWaterLine() const
94    {
95        return waterLine_;
96    }
97    uintptr_t GetTop() const
98    {
99        return allocator_.GetTop();
100    }
101    size_t GetHeapObjectSize() const;
102    size_t GetSurvivalObjectSize() const;
103    size_t GetAllocatedSizeSinceGC(uintptr_t top = 0) const;
104    void ReclaimRegions(size_t cachedSize = 0);
105    void AllowTryEnable()
106    {
107        shouldTryEnable_ = true;
108    }
109    bool ShouldTryEnable()
110    {
111        if (shouldTryEnable_) {
112            shouldTryEnable_ = false;
113            return true;
114        }
115        return false;
116    }
117
118private:
119    Region *AllocRegion();
120
121    static constexpr int GROWING_FACTOR = 2;
122    bool isFull_ {true};
123    Mutex lock_;
124    MemMap memMap_;
125    std::deque<MemMap> freeRegions_;
126    bool shouldTryEnable_ {false};
127};
128
129class SemiSpace : public LinearSpace {
130public:
131    SemiSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity);
132    ~SemiSpace() override = default;
133    NO_COPY_SEMANTIC(SemiSpace);
134    NO_MOVE_SEMANTIC(SemiSpace);
135
136    void Initialize() override;
137    void Restart(size_t overShootSize = 0);
138    size_t CalculateNewOverShootSize();
139    bool CommittedSizeIsLarge();
140
141    uintptr_t AllocateSync(size_t size);
142
143    void SetOverShootSize(size_t size);
144    void AddOverShootSize(size_t size);
145    bool AdjustCapacity(size_t allocatedSizeSinceGC, JSThread *thread);
146    void SetWaterLine();
147
148    uintptr_t GetWaterLine() const
149    {
150        return waterLine_;
151    }
152    uintptr_t GetTop() const
153    {
154        return allocator_.GetTop();
155    }
156    size_t GetHeapObjectSize() const;
157    size_t GetSurvivalObjectSize() const;
158    size_t GetAllocatedSizeSinceGC(uintptr_t top = 0) const;
159
160    bool SwapRegion(Region *region, SemiSpace *fromSpace);
161
162private:
163    static constexpr int GROWING_FACTOR = 2;
164    Mutex lock_;
165    size_t minimumCapacity_;
166};
167
168class SnapshotSpace : public LinearSpace {
169public:
170    SnapshotSpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity);
171    ~SnapshotSpace() override = default;
172    NO_COPY_SEMANTIC(SnapshotSpace);
173    NO_MOVE_SEMANTIC(SnapshotSpace);
174
175    size_t GetHeapObjectSize() const
176    {
177        return liveObjectSize_;
178    }
179
180    void IncreaseLiveObjectSize(size_t size)
181    {
182        liveObjectSize_ += size;
183    }
184
185private:
186    size_t liveObjectSize_ {0};
187};
188
189class ReadOnlySpace : public LinearSpace {
190public:
191    ReadOnlySpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity,
192        MemSpaceType type = MemSpaceType::READ_ONLY_SPACE);
193    ~ReadOnlySpace() override = default;
194    void SetReadOnly()
195    {
196        auto cb = [](Region *region) {
197            region->SetReadOnlyAndMarked();
198        };
199        EnumerateRegions(cb);
200    }
201
202    void ClearReadOnly()
203    {
204        auto cb = [](Region *region) {
205            region->ClearReadOnly();
206        };
207        EnumerateRegions(cb);
208    }
209
210    NO_COPY_SEMANTIC(ReadOnlySpace);
211    NO_MOVE_SEMANTIC(ReadOnlySpace);
212};
213}  // namespace panda::ecmascript
214#endif  // ECMASCRIPT_MEM_LINEAR_SPACE_H
215