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 25namespace panda::ecmascript { 26static constexpr size_t MIN_BUFFER_SIZE = 31_KB; 27static constexpr size_t SMALL_OBJECT_SIZE = 8_KB; 28 29TlabAllocator::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 37inline 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 47uintptr_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 67uintptr_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 85uintptr_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 94uintptr_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 111bool 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 133bool 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 143SharedTlabAllocator::SharedTlabAllocator(SharedHeap *sHeap) 144 : sHeap_(sHeap) 145{ 146 size_t maxOldSpaceCapacity = sHeap->GetOldSpace()->GetMaximumCapacity(); 147 sLocalSpace_ = new SharedLocalSpace(sHeap, maxOldSpaceCapacity, maxOldSpaceCapacity); 148} 149 150inline void SharedTlabAllocator::Finalize() 151{ 152 sHeap_->MergeToOldSpaceSync(sLocalSpace_); 153} 154 155uintptr_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 169uintptr_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