1 /*
2  * Copyright (c) 2021 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_TLAB_ALLOCATOR_INL_H
17 #define ECMASCRIPT_MEM_TLAB_ALLOCATOR_INL_H
18 
19 #include "ecmascript/mem/tlab_allocator.h"
20 
21 #include "ecmascript/free_object.h"
22 #include "ecmascript/mem/full_gc.h"
23 #include "ecmascript/mem/heap-inl.h"
24 
25 namespace panda::ecmascript {
26 static constexpr size_t MIN_BUFFER_SIZE = 31_KB;
27 static constexpr size_t SMALL_OBJECT_SIZE = 8_KB;
28 
TlabAllocator(Heap *heap)29 TlabAllocator::TlabAllocator(Heap *heap)
30     : heap_(heap), enableExpandYoung_(true), enableStealOldRegion_(true)
31 {
32     size_t maxOldSpaceCapacity = heap->GetOldSpace()->GetMaximumCapacity();
33     localSpace_ = new LocalSpace(heap, maxOldSpaceCapacity, maxOldSpaceCapacity);
34     youngAllocator_.Reset();
35 }
36 
Finalize()37 inline void TlabAllocator::Finalize()
38 {
39     if (youngAllocator_.Available() != 0) {
40         FreeObject::FillFreeObject(heap_, youngAllocator_.GetTop(), youngAllocator_.Available());
41         youngAllocator_.Reset();
42     }
43 
44     heap_->MergeToOldSpaceSync(localSpace_);
45 }
46 
Allocate(size_t size, MemSpaceType space)47 uintptr_t TlabAllocator::Allocate(size_t size, MemSpaceType space)
48 {
49     uintptr_t result = 0;
50     switch (space) {
51         case SEMI_SPACE:
52             result = AllocateInYoungSpace(size);
53             break;
54         case OLD_SPACE:
55             result = AllocateInOldSpace(size);
56             break;
57         case COMPRESS_SPACE:
58             result = AllocateInCompressSpace(size);
59             break;
60         default:
61             LOG_ECMA(FATAL) << "this branch is unreachable";
62             UNREACHABLE();
63     }
64     return result;
65 }
66 
AllocateInYoungSpace(size_t size)67 uintptr_t TlabAllocator::AllocateInYoungSpace(size_t size)
68 {
69     ASSERT(AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) == size);
70     if (UNLIKELY(size > SMALL_OBJECT_SIZE)) {
71         uintptr_t address = heap_->AllocateYoungSync(size);
72         return address;
73     }
74     uintptr_t result = youngAllocator_.Allocate(size);
75     if (result != 0) {
76         return result;
77     }
78     if (!enableExpandYoung_ || !ExpandYoung()) {
79         enableExpandYoung_ = false;
80         return 0;
81     }
82     return youngAllocator_.Allocate(size);
83 }
84 
AllocateInCompressSpace(size_t size)85 uintptr_t TlabAllocator::AllocateInCompressSpace(size_t size)
86 {
87     ASSERT(AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) == size);
88     size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
89     uintptr_t result = localSpace_->Allocate(size, true);
90     ASSERT(result != 0);
91     return result;
92 }
93 
AllocateInOldSpace(size_t size)94 uintptr_t TlabAllocator::AllocateInOldSpace(size_t size)
95 {
96     ASSERT(AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) == size);
97     size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
98     // 1. Allocate from freelist in compress allocator
99     uintptr_t result = localSpace_->Allocate(size, false);
100     if (result == 0) {
101         // 2. Expand region from old space
102         if (enableStealOldRegion_) {
103             enableStealOldRegion_ = ExpandCompressFromOld(size);
104         }
105         result = localSpace_->Allocate(size, true);
106     }
107     ASSERT(result != 0);
108     return result;
109 }
110 
ExpandYoung()111 bool TlabAllocator::ExpandYoung()
112 {
113     uintptr_t buffer = heap_->AllocateYoungSync(MIN_BUFFER_SIZE);
114     if (buffer == 0) {
115         if (youngAllocator_.Available() != 0) {
116             FreeObject::FillFreeObject(heap_, youngAllocator_.GetTop(), youngAllocator_.Available());
117         }
118         return false;
119     }
120     uintptr_t end = buffer + MIN_BUFFER_SIZE;
121 
122     if (buffer == youngAllocator_.GetEnd()) {
123         buffer = youngAllocator_.GetTop();
124     } else {
125         if (youngAllocator_.Available() != 0) {
126             FreeObject::FillFreeObject(heap_, youngAllocator_.GetTop(), youngAllocator_.Available());
127         }
128     }
129     youngAllocator_.Reset(buffer, end);
130     return true;
131 }
132 
ExpandCompressFromOld(size_t size)133 bool TlabAllocator::ExpandCompressFromOld(size_t size)
134 {
135     auto region = heap_->GetOldSpace()->TryToGetExclusiveRegion(size);
136     if (region != nullptr) {
137         localSpace_->AddRegionToList(region);
138         return true;
139     }
140     return false;
141 }
142 
SharedTlabAllocator(SharedHeap *sHeap)143 SharedTlabAllocator::SharedTlabAllocator(SharedHeap *sHeap)
144     : sHeap_(sHeap)
145 {
146     size_t maxOldSpaceCapacity = sHeap->GetOldSpace()->GetMaximumCapacity();
147     sLocalSpace_ = new SharedLocalSpace(sHeap, maxOldSpaceCapacity, maxOldSpaceCapacity);
148 }
149 
Finalize()150 inline void SharedTlabAllocator::Finalize()
151 {
152     sHeap_->MergeToOldSpaceSync(sLocalSpace_);
153 }
154 
Allocate(size_t size, MemSpaceType space)155 uintptr_t SharedTlabAllocator::Allocate(size_t size, MemSpaceType space)
156 {
157     uintptr_t result = 0;
158     switch (space) {
159         case SHARED_COMPRESS_SPACE:
160             result = AllocateInCompressSpace(size);
161             break;
162         default:
163             LOG_ECMA(FATAL) << "this branch is unreachable";
164             UNREACHABLE();
165     }
166     return result;
167 }
168 
AllocateInCompressSpace(size_t size)169 uintptr_t SharedTlabAllocator::AllocateInCompressSpace(size_t size)
170 {
171     ASSERT(AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) == size);
172     size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
173     uintptr_t result = sLocalSpace_->Allocate(size, true);
174     ASSERT(result != 0);
175     return result;
176 }
177 
178 }  // namespace panda::ecmascript
179 #endif  // ECMASCRIPT_MEM_TLAB_ALLOCATOR_INL_H
180