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)
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_->GetEcmaVM(), 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 ExpandCompressFromOld(size);
103 result = localSpace_->Allocate(size, true);
104 }
105 ASSERT(result != 0);
106 return result;
107 }
108
ExpandYoung()109 bool TlabAllocator::ExpandYoung()
110 {
111 uintptr_t buffer = heap_->AllocateYoungSync(MIN_BUFFER_SIZE);
112 if (buffer == 0) {
113 if (youngAllocator_.Available() != 0) {
114 FreeObject::FillFreeObject(heap_->GetEcmaVM(), youngAllocator_.GetTop(), youngAllocator_.Available());
115 }
116 return false;
117 }
118 uintptr_t end = buffer + MIN_BUFFER_SIZE;
119
120 if (buffer == youngAllocator_.GetEnd()) {
121 buffer = youngAllocator_.GetTop();
122 } else {
123 if (youngAllocator_.Available() != 0) {
124 FreeObject::FillFreeObject(heap_->GetEcmaVM(), youngAllocator_.GetTop(), youngAllocator_.Available());
125 }
126 }
127 youngAllocator_.Reset(buffer, end);
128 return true;
129 }
130
ExpandCompressFromOld(size_t size)131 bool TlabAllocator::ExpandCompressFromOld(size_t size)
132 {
133 auto region = heap_->GetOldSpace()->TryToGetExclusiveRegion(size);
134 if (region != nullptr) {
135 localSpace_->AddRegionToList(region);
136 return true;
137 }
138 return false;
139 }
140 } // namespace panda::ecmascript
141 #endif // ECMASCRIPT_MEM_TLAB_ALLOCATOR_INL_H
142