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_REGION_H 17 #define ECMASCRIPT_MEM_REGION_H 18 19 #include "ecmascript/mem/free_object_list.h" 20 #include "ecmascript/mem/mem.h" 21 #include "mem/gc/bitmap.h" 22 #include "native_area_allocator.h" 23 24 namespace panda { 25 using RangeBitmap = mem::MemBitmap<static_cast<size_t>(ecmascript::MemAlignment::MEM_ALIGN_OBJECT)>; 26 27 namespace ecmascript { 28 class Space; 29 class Heap; 30 class RememberedSet; 31 class WorkerHelper; 32 33 enum RegionFlags { 34 NEVER_EVACUATE = 1, 35 HAS_AGE_MARK = 1 << 1, 36 BELOW_AGE_MARK = 1 << 2, 37 IS_IN_YOUNG_GENERATION = 1 << 3, 38 IS_IN_SNAPSHOT_GENERATION = 1 << 4, 39 IS_HUGE_OBJECT = 1 << 5, 40 IS_IN_OLD_GENERATION = 1 << 6, 41 IS_IN_NON_MOVABLE_GENERATION = 1 << 7, 42 IS_IN_YOUNG_OR_OLD_GENERATION = IS_IN_YOUNG_GENERATION | IS_IN_OLD_GENERATION, 43 IS_IN_COLLECT_SET = 1 << 8, 44 IS_IN_NEW_TO_NEW_SET = 1 << 9, 45 IS_IN_YOUNG_OR_CSET_GENERATION = IS_IN_YOUNG_GENERATION | IS_IN_COLLECT_SET, 46 IS_INVALID = 1 << 10, 47 }; 48 49 #define REGION_OFFSET_LIST(V) \ 50 V(BITMAP, BitMap, markBitmap_, FLAG, sizeof(uint32_t), sizeof(uint64_t)) \ 51 V(OLDTONEWSET, OldToNewSet, oldToNewSet_, BITMAP, sizeof(uint32_t), sizeof(uint64_t)) 52 53 class Region { 54 public: Region(Space * space,Heap * heap,uintptr_t allocateBase,uintptr_t begin,uintptr_t end,NativeAreaAllocator * nativeAreaAllocator)55 Region(Space *space, Heap *heap, uintptr_t allocateBase, uintptr_t begin, 56 uintptr_t end, NativeAreaAllocator* nativeAreaAllocator) 57 : flags_(0), space_(space), heap_(heap), 58 allocateBase_(allocateBase), 59 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 60 begin_(begin), 61 end_(end), 62 highWaterMark_(end), 63 aliveObject_(0), 64 wasted_(0), 65 nativeAreaAllocator_(nativeAreaAllocator) 66 { 67 markBitmap_ = CreateMarkBitmap(); 68 } 69 ~Region() = default; 70 NO_COPY_SEMANTIC(Region); 71 NO_MOVE_SEMANTIC(Region); 72 Reset()73 void Reset() 74 { 75 flags_ = 0; 76 highWaterMark_ = end_; 77 if (memset_s(reinterpret_cast<void *>(begin_), GetSize(), 0, GetSize()) != EOK) { 78 UNREACHABLE(); 79 } 80 } 81 LinkNext(Region * next)82 void LinkNext(Region *next) 83 { 84 next_ = next; 85 } 86 GetNext()87 Region *GetNext() const 88 { 89 return next_; 90 } 91 LinkPrev(Region * prev)92 void LinkPrev(Region *prev) 93 { 94 prev_ = prev; 95 } 96 GetPrev()97 Region *GetPrev() const 98 { 99 return prev_; 100 } 101 GetBegin()102 uintptr_t GetBegin() const 103 { 104 return begin_; 105 } 106 GetEnd()107 uintptr_t GetEnd() const 108 { 109 return end_; 110 } 111 GetCapacity()112 size_t GetCapacity() const 113 { 114 return end_ - reinterpret_cast<uintptr_t>(this); 115 } 116 GetSize()117 size_t GetSize() const 118 { 119 return end_ - begin_; 120 } 121 122 inline void SetSpace(Space *space); 123 GetHeap()124 Heap *GetHeap() const 125 { 126 return heap_; 127 } 128 GetSpace()129 Space *GetSpace() const 130 { 131 return space_; 132 } 133 ResetFlag()134 void ResetFlag() 135 { 136 flags_ = 0; 137 } 138 SetFlag(RegionFlags flag)139 void SetFlag(RegionFlags flag) 140 { 141 flags_ |= flag; 142 } 143 ClearFlag(RegionFlags flag)144 void ClearFlag(RegionFlags flag) 145 { 146 // NOLINTNEXTLINE(hicpp-signed-bitwise) 147 flags_ &= ~flag; 148 } 149 IsFlagSet(RegionFlags flag)150 bool IsFlagSet(RegionFlags flag) const 151 { 152 return (flags_ & flag) != 0; 153 } 154 GetMarkBitmap()155 RangeBitmap *GetMarkBitmap() 156 { 157 return markBitmap_; 158 } 159 GetCrossRegionRememberedSet()160 RememberedSet *GetCrossRegionRememberedSet() 161 { 162 return crossRegionSet_; 163 } 164 GetOldToNewRememberedSet()165 RememberedSet *GetOldToNewRememberedSet() 166 { 167 return oldToNewSet_; 168 } 169 ObjectAddressToRange(TaggedObject * obj)170 static Region *ObjectAddressToRange(TaggedObject *obj) 171 { 172 return reinterpret_cast<Region *>(ToUintPtr(obj) & ~DEFAULT_REGION_MASK); 173 } 174 ObjectAddressToRange(uintptr_t objAddress)175 static Region *ObjectAddressToRange(uintptr_t objAddress) 176 { 177 return reinterpret_cast<Region *>(objAddress & ~DEFAULT_REGION_MASK); 178 } 179 InYoungGeneration()180 bool InYoungGeneration() const 181 { 182 return IsFlagSet(RegionFlags::IS_IN_YOUNG_GENERATION); 183 } 184 InOldGeneration()185 bool InOldGeneration() const 186 { 187 return IsFlagSet(RegionFlags::IS_IN_OLD_GENERATION); 188 } 189 InYoungAndOldGeneration()190 bool InYoungAndOldGeneration() const 191 { 192 return IsFlagSet(RegionFlags::IS_IN_YOUNG_OR_OLD_GENERATION); 193 } 194 InHugeObjectGeneration()195 bool InHugeObjectGeneration() const 196 { 197 return IsFlagSet(RegionFlags::IS_HUGE_OBJECT); 198 } 199 InYoungOrCSetGeneration()200 bool InYoungOrCSetGeneration() const 201 { 202 return IsFlagSet(RegionFlags::IS_IN_YOUNG_OR_CSET_GENERATION); 203 } 204 InNewToNewSet()205 bool InNewToNewSet() const 206 { 207 return IsFlagSet(RegionFlags::IS_IN_NEW_TO_NEW_SET); 208 } 209 InCollectSet()210 bool InCollectSet() const 211 { 212 return IsFlagSet(RegionFlags::IS_IN_COLLECT_SET); 213 } 214 HasAgeMark()215 bool HasAgeMark() const 216 { 217 return IsFlagSet(RegionFlags::HAS_AGE_MARK); 218 } 219 BelowAgeMark()220 bool BelowAgeMark() const 221 { 222 return IsFlagSet(RegionFlags::BELOW_AGE_MARK); 223 } 224 InRange(uintptr_t address)225 bool InRange(uintptr_t address) 226 { 227 return address >= begin_ && address <= end_; 228 } 229 CreateMarkBitmap()230 inline RangeBitmap *CreateMarkBitmap() 231 { 232 size_t heapSize = IsFlagSet(RegionFlags::IS_HUGE_OBJECT) ? LARGE_BITMAP_MIN_SIZE : GetCapacity(); 233 // Only one huge object is stored in a region. The BitmapSize of a huge region will always be 8 Bytes. 234 size_t bitmapSize = RangeBitmap::GetBitMapSizeInByte(heapSize); 235 ASSERT(nativeAreaAllocator_ != nullptr); 236 auto bitmapData = const_cast<NativeAreaAllocator *>(nativeAreaAllocator_)->Allocate(bitmapSize); 237 auto *ret = new RangeBitmap(this, heapSize, bitmapData); 238 ret->ClearAllBits(); 239 return ret; 240 } 241 inline RememberedSet *CreateRememberedSet(); 242 inline RememberedSet *GetOrCreateCrossRegionRememberedSet(); 243 inline RememberedSet *GetOrCreateOldToNewRememberedSet(); 244 inline void DeleteMarkBitmap(); 245 inline void DeleteCrossRegionRememberedSet(); 246 inline void DeleteOldToNewRememberedSet(); 247 inline void ClearMarkBitmap(); 248 inline void ClearCrossRegionRememberedSet(); 249 inline void InsertCrossRegionRememberedSet(uintptr_t addr); 250 inline void AtomicInsertCrossRegionRememberedSet(uintptr_t addr); 251 inline void InsertOldToNewRememberedSet(uintptr_t addr); 252 inline void AtomicInsertOldToNewRememberedSet(uintptr_t addr); 253 GetAllocateBase()254 uintptr_t GetAllocateBase() const 255 { 256 return allocateBase_; 257 } 258 259 size_t GetAllocatedBytes(uintptr_t top = 0) 260 { 261 ASSERT(top == 0 || InRange(top)); 262 return (top == 0) ? (highWaterMark_ - begin_) : (top - begin_); 263 } 264 SetHighWaterMark(uintptr_t mark)265 void SetHighWaterMark(uintptr_t mark) 266 { 267 ASSERT(InRange(mark)); 268 highWaterMark_ = mark; 269 } 270 SetCodeExecutableAndReadable()271 int SetCodeExecutableAndReadable() 272 { 273 // NOLINT(hicpp-signed-bitwise) 274 int res = mprotect(reinterpret_cast<void *>(allocateBase_), GetCapacity(), PROT_EXEC | PROT_READ | PROT_WRITE); 275 return res; 276 } 277 InitializeSet()278 void InitializeSet() 279 { 280 sets_ = Span<FreeObjectSet *>(new FreeObjectSet *[FreeObjectList::NumberOfSets()](), 281 FreeObjectList::NumberOfSets()); 282 } 283 RebuildSet()284 void RebuildSet() 285 { 286 EnumerateSets([](FreeObjectSet *set) { 287 if (set != nullptr) { 288 set->Rebuild(); 289 } 290 }); 291 } 292 DestroySet()293 void DestroySet() 294 { 295 for (auto set : sets_) { 296 delete set; 297 } 298 delete[] sets_.data(); 299 } 300 GetFreeObjectSet(SetType type)301 FreeObjectSet *GetFreeObjectSet(SetType type) 302 { 303 // Thread safe 304 if (sets_[type] == nullptr) { 305 sets_[type] = new FreeObjectSet(type); 306 } 307 return sets_[type]; 308 } 309 310 template<class Callback> EnumerateSets(Callback cb)311 void EnumerateSets(Callback cb) 312 { 313 for (auto set : sets_) { 314 cb(set); 315 } 316 } 317 318 inline bool IsMarking() const; 319 320 inline WorkerHelper *GetWorkList() const; 321 IncrementAliveObjectSafe(size_t size)322 void IncrementAliveObjectSafe(size_t size) 323 { 324 ASSERT(aliveObject_ + size <= GetSize()); 325 aliveObject_ += size; 326 } 327 IncrementAliveObject(size_t size)328 void IncrementAliveObject(size_t size) 329 { 330 ASSERT(aliveObject_ + size <= GetSize()); 331 aliveObject_.fetch_add(size, std::memory_order_relaxed); 332 } 333 ResetAliveObject()334 void ResetAliveObject() 335 { 336 aliveObject_ = 0; 337 } 338 AliveObject()339 size_t AliveObject() const 340 { 341 return aliveObject_; 342 } 343 MostObjectAlive()344 bool MostObjectAlive() const 345 { 346 return aliveObject_ > MOST_OBJECT_ALIVE_THRESHOLD_PERCENT * GetSize(); 347 } 348 ResetWasted()349 void ResetWasted() 350 { 351 wasted_ = 0; 352 } IncrementWasted(size_t size)353 void IncrementWasted(size_t size) 354 { 355 wasted_ += size; 356 } GetWastedSize()357 size_t GetWastedSize() 358 { 359 return wasted_; 360 } 361 362 static constexpr uint32_t GetOldToNewSetOffset(bool is32Bit = false) 363 { 364 return is32Bit ? REGION_OLDTONEWSET_OFFSET_32 : REGION_OLDTONEWSET_OFFSET_64; 365 } 366 367 static constexpr uint32_t GetBitMapOffset(bool is32Bit = false) 368 { 369 return is32Bit ? REGION_BITMAP_OFFSET_32 : REGION_BITMAP_OFFSET_64; 370 } 371 372 static constexpr uint32_t GetFlagOffset(bool is32Bit = false) 373 { 374 return is32Bit ? REGION_FLAG_OFFSET_32 : REGION_FLAG_OFFSET_64; 375 } 376 377 #define REGION_OFFSET_MACRO(name, camelName, memberName, lastName, lastSize32, lastSize64) \ 378 static constexpr uint32_t REGION_##name##_OFFSET_32 = REGION_##lastName##_OFFSET_32 + (lastSize32); \ 379 static constexpr uint32_t REGION_##name##_OFFSET_64 = REGION_##lastName##_OFFSET_64 + (lastSize64); 380 static constexpr uint32_t REGION_FLAG_OFFSET_32 = 0U; 381 static constexpr uint32_t REGION_FLAG_OFFSET_64 = 0U; REGION_OFFSET_LIST(REGION_OFFSET_MACRO)382 REGION_OFFSET_LIST(REGION_OFFSET_MACRO) 383 #undef REGION_OFFSET_MACRO 384 385 static constexpr bool CheckLayout() 386 { 387 #ifdef PANDA_TARGET_32 388 #define REGION_OFFSET_ASSET(name, camelName, memberName, lastName, lastSize32, lastSize64) \ 389 static_assert(MEMBER_OFFSET(Region, memberName) == (Get##camelName##Offset(true))); 390 REGION_OFFSET_LIST(REGION_OFFSET_ASSET) 391 static_assert(GetFlagOffset(true) == MEMBER_OFFSET(Region, flags_)); 392 #undef REGION_OFFSET_ASSET 393 #endif 394 #ifdef PANDA_TARGET_64 395 #define REGION_OFFSET_ASSET(name, camelName, memberName, lastName, lastSize32, lastSize64) \ 396 static_assert(MEMBER_OFFSET(Region, memberName) == (Get##camelName##Offset(false))); 397 REGION_OFFSET_LIST(REGION_OFFSET_ASSET) 398 static_assert(GetFlagOffset(false) == MEMBER_OFFSET(Region, flags_)); 399 #undef REGION_OFFSET_ASSET 400 #endif 401 return true; 402 } 403 private: 404 static constexpr double MOST_OBJECT_ALIVE_THRESHOLD_PERCENT = 0.8; 405 uintptr_t flags_; // Memory alignment, only low 32bits are used now 406 RangeBitmap *markBitmap_ {nullptr}; 407 RememberedSet *oldToNewSet_ {nullptr}; 408 Space *space_; 409 Heap *heap_; 410 411 uintptr_t allocateBase_; 412 uintptr_t begin_; 413 uintptr_t end_; 414 uintptr_t highWaterMark_; 415 std::atomic_size_t aliveObject_ {0}; 416 Region *next_ {nullptr}; 417 Region *prev_ {nullptr}; 418 419 RememberedSet *crossRegionSet_ {nullptr}; 420 Span<FreeObjectSet *> sets_; 421 size_t wasted_; 422 os::memory::Mutex lock_; 423 NativeAreaAllocator* nativeAreaAllocator_ {nullptr}; 424 friend class SnapShot; 425 }; 426 427 class BitmapHelper : public mem::Bitmap { 428 public: 429 static const size_t BITSPERWORD_64 = BITSPERBYTE * sizeof(uint64_t); 430 static const size_t BITSPERWORD_32 = BITSPERBYTE * sizeof(uint32_t); 431 static constexpr size_t LOG_BITSPERWORD_64 = panda::helpers::math::GetIntLog2( 432 static_cast<uint64_t>(BITSPERWORD_64)); 433 static constexpr size_t LOG_BITSPERWORD_32 = panda::helpers::math::GetIntLog2( 434 static_cast<uint64_t>(BITSPERWORD_32)); 435 NO_COPY_SEMANTIC(BitmapHelper); 436 NO_MOVE_SEMANTIC(BitmapHelper); 437 static constexpr uint32_t LogBitsPerWord(bool is32Bit = false) 438 { 439 return is32Bit ? LOG_BITSPERWORD_32 : LOG_BITSPERWORD_64; 440 } CheckLayout()441 static constexpr bool CheckLayout() 442 { 443 #ifdef PANDA_TARGET_32 444 static_assert(LogBitsPerWord(true) == mem::Bitmap::LOG_BITSPERWORD); 445 #else 446 static_assert(LogBitsPerWord(false) == mem::Bitmap::LOG_BITSPERWORD); 447 #endif 448 return true; 449 } 450 }; 451 static_assert(Region::CheckLayout()); 452 static_assert(BitmapHelper::CheckLayout()); 453 } // namespace ecmascript 454 } // namespace panda 455 456 #endif // ECMASCRIPT_MEM_REGION_H 457