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 
21 namespace panda::ecmascript {
22 class LinearSpace : public Space {
23 public:
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 
GetAllocationTopAddress()33     const uintptr_t *GetAllocationTopAddress()
34     {
35         return allocator_.GetTopAddress();
36     }
GetAllocationEndAddress()37     const uintptr_t *GetAllocationEndAddress()
38     {
39         return allocator_.GetEndAddress();
40     }
GetOvershootSize() const41     size_t GetOvershootSize() const
42     {
43         return overShootSize_;
44     }
45     void InvokeAllocationInspector(Address object, size_t size, size_t alignedSize);
46 
RecordCurrentRegionAsHalfFresh()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 
IsFreshObjectInHalfFreshRegion(TaggedObject *object)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 
65 protected:
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 
78 class EdenSpace : public LinearSpace {
79 public:
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 
GetWaterLine() const93     uintptr_t GetWaterLine() const
94     {
95         return waterLine_;
96     }
GetTop() const97     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);
AllowTryEnable()105     void AllowTryEnable()
106     {
107         shouldTryEnable_ = true;
108     }
ShouldTryEnable()109     bool ShouldTryEnable()
110     {
111         if (shouldTryEnable_) {
112             shouldTryEnable_ = false;
113             return true;
114         }
115         return false;
116     }
117 
118 private:
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 
129 class SemiSpace : public LinearSpace {
130 public:
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 
GetWaterLine() const148     uintptr_t GetWaterLine() const
149     {
150         return waterLine_;
151     }
GetTop() const152     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 
162 private:
163     static constexpr int GROWING_FACTOR = 2;
164     Mutex lock_;
165     size_t minimumCapacity_;
166 };
167 
168 class SnapshotSpace : public LinearSpace {
169 public:
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 
GetHeapObjectSize() const175     size_t GetHeapObjectSize() const
176     {
177         return liveObjectSize_;
178     }
179 
IncreaseLiveObjectSize(size_t size)180     void IncreaseLiveObjectSize(size_t size)
181     {
182         liveObjectSize_ += size;
183     }
184 
185 private:
186     size_t liveObjectSize_ {0};
187 };
188 
189 class ReadOnlySpace : public LinearSpace {
190 public:
191     ReadOnlySpace(Heap *heap, size_t initialCapacity, size_t maximumCapacity,
192         MemSpaceType type = MemSpaceType::READ_ONLY_SPACE);
193     ~ReadOnlySpace() override = default;
SetReadOnly()194     void SetReadOnly()
195     {
196         auto cb = [](Region *region) {
197             region->SetReadOnlyAndMarked();
198         };
199         EnumerateRegions(cb);
200     }
201 
ClearReadOnly()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