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 PANDA_RUNTIME_MEM_GC_BITMAP_H_ 17 #define PANDA_RUNTIME_MEM_GC_BITMAP_H_ 18 19 // clash with mingw 20 #ifndef PANDA_TARGET_WINDOWS 21 #include <securec.h> 22 #endif 23 #include <cstddef> 24 #include <cstdint> 25 #include <cstring> 26 27 #include "libpandabase/macros.h" 28 #include "libpandabase/mem/mem.h" 29 #include "libpandabase/utils/bit_utils.h" 30 #include "libpandabase/utils/math_helpers.h" 31 #include "libpandabase/utils/span.h" 32 33 namespace panda::mem { 34 35 /** 36 * Abstract base class. Constructor/destructor are protected. No virtual function to avoid dynamic polymorphism. 37 */ 38 class Bitmap { 39 public: 40 using BitmapWordType = uintptr_t; 41 Size()42 size_t Size() const 43 { 44 return bitsize_; 45 } 46 ClearAllBits()47 void ClearAllBits() 48 { 49 #ifndef PANDA_TARGET_WINDOWS 50 (void)memset_s(bitmap_.Data(), bitmap_.SizeBytes(), 0, bitmap_.SizeBytes()); 51 #endif 52 } 53 GetBitMap()54 Span<BitmapWordType> GetBitMap() 55 { 56 return bitmap_; 57 } 58 59 static const size_t BITSPERBYTE = 8; 60 static const size_t BITSPERWORD = BITSPERBYTE * sizeof(BitmapWordType); 61 static constexpr size_t LOG_BITSPERBYTE = panda::helpers::math::GetIntLog2(static_cast<uint64_t>(BITSPERBYTE)); 62 static constexpr size_t LOG_BITSPERWORD = panda::helpers::math::GetIntLog2(static_cast<uint64_t>(BITSPERWORD)); 63 64 protected: 65 /** 66 * \brief Set the bit indexed by bit_offset. 67 * @param bit_offset - index of the bit to set. 68 */ SetBit(size_t bit_offset)69 void SetBit(size_t bit_offset) 70 { 71 CheckBitOffset(bit_offset); 72 bitmap_[GetWordIdx(bit_offset)] |= GetBitMask(bit_offset); 73 } 74 75 /** 76 * \brief Clear the bit indexed by bit_offset. 77 * @param bit_offset - index of the bit to clear. 78 */ ClearBit(size_t bit_offset)79 void ClearBit(size_t bit_offset) 80 { 81 CheckBitOffset(bit_offset); 82 bitmap_[GetWordIdx(bit_offset)] &= ~GetBitMask(bit_offset); 83 } 84 85 /** 86 * \brief Test the bit indexed by bit_offset. 87 * @param bit_offset - index of the bit to test. 88 * @return Returns value of indexed bit. 89 */ TestBit(size_t bit_offset)90 bool TestBit(size_t bit_offset) const 91 { 92 CheckBitOffset(bit_offset); 93 return (bitmap_[GetWordIdx(bit_offset)] & GetBitMask(bit_offset)) != 0; 94 } 95 96 /** 97 * \brief Atomically set bit indexed by bit_offset. If the bit is not set, set it atomically. Otherwise, do nothing. 98 * @param bit_offset - index of the bit to set. 99 * @return Returns old value of the bit. 100 */ 101 bool AtomicTestAndSetBit(size_t bit_offset); 102 103 /** 104 * \brief Atomically clear bit corresponding to addr. If the bit is set, clear it atomically. Otherwise, do nothing. 105 * @param addr - addr must be aligned to BYTESPERCHUNK. 106 * @return Returns old value of the bit. 107 */ 108 bool AtomicTestAndClearBit(size_t bit_offset); 109 110 /** 111 * \brief Atomically test bit corresponding to addr. 112 * @param addr - addr must be aligned to BYTESPERCHUNK. 113 * @return Returns the value of the bit. 114 */ 115 bool AtomicTestBit(size_t bit_offset); 116 117 /** 118 * \brief Iterate over marked bits of bitmap sequentially. 119 * Finish iteration if the visitor returns false. 120 * @tparam VisitorType 121 * @param visitor - function pointer or functor. 122 */ 123 template <typename VisitorType> IterateOverSetBits(const VisitorType & visitor)124 void IterateOverSetBits(const VisitorType &visitor) 125 { 126 IterateOverSetBitsInRange(0, Size(), visitor); 127 } 128 129 /** 130 * \brief Iterate over all bits of bitmap sequentially. 131 * @tparam VisitorType 132 * @param visitor - function pointer or functor. 133 */ 134 template <typename VisitorType> IterateOverBits(const VisitorType & visitor)135 void IterateOverBits(const VisitorType &visitor) 136 { 137 IterateOverBitsInRange(0, Size(), visitor); 138 } 139 140 /** 141 * \brief Iterate over marked bits in range [begin, end) sequentially. 142 * Finish iteration if the visitor returns false. 143 * @tparam VisitorType 144 * @param begin - beginning index of the range, inclusive. 145 * @param end - end index of the range, exclusive. 146 * @param visitor - function pointer or functor. 147 */ 148 template <typename VisitorType> IterateOverSetBitsInRange(size_t begin,size_t end,const VisitorType & visitor)149 void IterateOverSetBitsInRange(size_t begin, size_t end, const VisitorType &visitor) 150 { 151 CheckBitRange(begin, end); 152 if (UNLIKELY(begin == end)) { 153 return; 154 } 155 156 // first word, clear bits before begin 157 auto bitmap_word = bitmap_[GetWordIdx(begin)]; 158 auto offset_within_word = GetBitIdxWithinWord(begin); 159 bitmap_word &= GetRangeBitMask(offset_within_word, BITSPERWORD); 160 auto offset_word_begin = GetWordIdx(begin) * BITSPERWORD; 161 const bool RIGHT_ALIGNED = (GetBitIdxWithinWord(end) == 0); 162 const auto OFFSET_LAST_WORD_BEGIN = GetWordIdx(end) * BITSPERWORD; 163 164 do { 165 if (offset_word_begin == OFFSET_LAST_WORD_BEGIN && !RIGHT_ALIGNED) { 166 // last partial word, clear bits after right boundary 167 auto mask = GetRangeBitMask(0, GetBitIdxWithinWord(end)); 168 bitmap_word &= mask; 169 } 170 // loop over bits of bitmap_word 171 while (offset_within_word < BITSPERWORD) { 172 if (bitmap_word == 0) { 173 break; 174 } 175 offset_within_word = Ctz(bitmap_word); 176 if (!visitor(offset_word_begin + offset_within_word)) { 177 return; 178 } 179 bitmap_word &= ~GetBitMask(offset_within_word); 180 } 181 182 offset_word_begin += BITSPERWORD; 183 if (offset_word_begin < end) { 184 bitmap_word = bitmap_[GetWordIdx(offset_word_begin)]; 185 offset_within_word = 0; 186 } 187 } while (offset_word_begin < end); 188 } 189 190 /** 191 * \brief Iterate over all bits in range [begin, end) sequentially. 192 * @tparam VisitorType 193 * @param begin - beginning index of the range, inclusive. 194 * @param end - end index of the range, exclusive. 195 * @param visitor - function pointer or functor. 196 */ 197 template <typename VisitorType> IterateOverBitsInRange(size_t begin,size_t end,const VisitorType & visitor)198 void IterateOverBitsInRange(size_t begin, size_t end, const VisitorType &visitor) 199 { 200 CheckBitRange(begin, end); 201 for (size_t i = begin; i < end; ++i) { 202 visitor(i); 203 } 204 } 205 206 /** 207 * \brief Clear all bits in range [begin, end). 208 * @param begin - beginning index of the range, inclusive. 209 * @param end - end index of the range, exclusive. 210 */ 211 void ClearBitsInRange(size_t begin, size_t end); 212 213 /** 214 * \brief Set all bits in range [begin, end). [begin, end) must be within a BitmapWord. 215 * @param begin - beginning index of the range, inclusive. 216 * @param end - end index of the range, exclusive. 217 */ SetRangeWithinWord(size_t begin,size_t end)218 void SetRangeWithinWord(size_t begin, size_t end) 219 { 220 if (LIKELY(begin != end)) { 221 ModifyRangeWithinWord<true>(begin, end); 222 } 223 } 224 225 /** 226 * \brief Clear all bits in range [begin, end). [begin, end) must be within a BitmapWord. 227 * @param begin - beginning index of the range, inclusive. 228 * @param end - end index of the range, exclusive. 229 */ ClearRangeWithinWord(size_t begin,size_t end)230 void ClearRangeWithinWord(size_t begin, size_t end) 231 { 232 if (LIKELY(begin != end)) { 233 ModifyRangeWithinWord<false>(begin, end); 234 } 235 } 236 237 /** 238 * \brief Set all BitmapWords in index range [begin, end). 239 * @param begin - beginning BitmapWord index of the range, inclusive. 240 * @param end - end BitmapWord index of the range, exclusive. 241 */ SetWords(size_t word_begin,size_t word_end)242 void SetWords([[maybe_unused]] size_t word_begin, [[maybe_unused]] size_t word_end) 243 { 244 ASSERT(word_begin <= word_end); 245 #ifndef PANDA_TARGET_WINDOWS 246 if (UNLIKELY(word_begin == word_end)) { 247 return; 248 } 249 (void)memset_s(&bitmap_[word_begin], (word_end - word_begin) * sizeof(BitmapWordType), 250 ~static_cast<unsigned char>(0), (word_end - word_begin) * sizeof(BitmapWordType)); 251 #endif 252 } 253 254 /** 255 * \brief Clear all BitmapWords in index range [begin, end). 256 * @param begin - beginning BitmapWord index of the range, inclusive. 257 * @param end - end BitmapWord index of the range, exclusive. 258 */ ClearWords(size_t word_begin,size_t word_end)259 void ClearWords([[maybe_unused]] size_t word_begin, [[maybe_unused]] size_t word_end) 260 { 261 ASSERT(word_begin <= word_end); 262 #ifndef PANDA_TARGET_WINDOWS 263 if (UNLIKELY(word_begin == word_end)) { 264 return; 265 } 266 (void)memset_s(&bitmap_[word_begin], (word_end - word_begin) * sizeof(BitmapWordType), 267 static_cast<unsigned char>(0), (word_end - word_begin) * sizeof(BitmapWordType)); 268 #endif 269 } 270 Bitmap(BitmapWordType * bitmap,size_t bitsize)271 explicit Bitmap(BitmapWordType *bitmap, size_t bitsize) 272 : bitmap_(bitmap, (AlignUp(bitsize, BITSPERWORD) >> LOG_BITSPERWORD)), bitsize_(bitsize) 273 { 274 } 275 ~Bitmap() = default; 276 // do we need special copy/move constructor? 277 NO_COPY_SEMANTIC(Bitmap); 278 NO_MOVE_SEMANTIC(Bitmap); 279 280 private: 281 Span<BitmapWordType> bitmap_; 282 size_t bitsize_ = 0; 283 284 /** 285 * \brief Compute word index from bit index. 286 * @param bit_offset - bit index. 287 * @return Returns BitmapWord Index of bit_offset. 288 */ GetWordIdx(size_t bit_offset)289 static size_t GetWordIdx(size_t bit_offset) 290 { 291 return bit_offset >> LOG_BITSPERWORD; 292 } 293 294 /** 295 * \brief Compute bit index within a BitmapWord from bit index. 296 * @param bit_offset - bit index. 297 * @return Returns bit index within a BitmapWord. 298 */ GetBitIdxWithinWord(size_t bit_offset)299 size_t GetBitIdxWithinWord(size_t bit_offset) const 300 { 301 CheckBitOffset(bit_offset); 302 constexpr auto BIT_INDEX_MASK = static_cast<size_t>((1UL << LOG_BITSPERWORD) - 1); 303 return bit_offset & BIT_INDEX_MASK; 304 } 305 306 /** 307 * \brief Compute bit mask from bit index. 308 * @param bit_offset - bit index. 309 * @return Returns bit mask of bit_offset. 310 */ GetBitMask(size_t bit_offset)311 BitmapWordType GetBitMask(size_t bit_offset) const 312 { 313 return 1UL << GetBitIdxWithinWord(bit_offset); 314 } 315 316 /** 317 * \brief Compute bit mask of range [begin_within_word, end_within_word). 318 * @param begin_within_word - beginning index within word, in range [0, BITSPERWORD). 319 * @param end_within_word - end index within word, in range [0, BITSPERWORD]. Make sure end_within_word is 320 * BITSPERWORD(instead of 0) if you want to cover from certain bit to last. [0, 0) is the only valid case when 321 * end_within_word is 0. 322 * @return Returns bit mask. 323 */ GetRangeBitMask(size_t begin_within_word,size_t end_within_word)324 BitmapWordType GetRangeBitMask(size_t begin_within_word, size_t end_within_word) const 325 { 326 ASSERT(begin_within_word < BITSPERWORD); 327 ASSERT(end_within_word <= BITSPERWORD); 328 ASSERT(begin_within_word <= end_within_word); 329 auto end_mask = 330 (end_within_word == BITSPERWORD) ? ~static_cast<BitmapWordType>(0) : GetBitMask(end_within_word) - 1; 331 return end_mask - (GetBitMask(begin_within_word) - 1); 332 } 333 334 /** 335 * \brief Check if bit_offset is valid. 336 */ CheckBitOffset(size_t bit_offset)337 void CheckBitOffset([[maybe_unused]] size_t bit_offset) const 338 { 339 ASSERT(bit_offset <= Size()); 340 } 341 342 /** 343 * \brief According to SET, set or clear range [begin, end) within a BitmapWord. 344 * @param begin - beginning global bit index. 345 * @param end - end global bit index. 346 */ 347 template <bool SET> ModifyRangeWithinWord(size_t begin,size_t end)348 ALWAYS_INLINE void ModifyRangeWithinWord(size_t begin, size_t end) 349 { 350 CheckBitRange(begin, end); 351 352 if (UNLIKELY(begin == end)) { 353 return; 354 } 355 356 BitmapWordType mask; 357 if (end % BITSPERWORD == 0) { 358 ASSERT(GetWordIdx(end) - GetWordIdx(begin) == 1); 359 mask = GetRangeBitMask(GetBitIdxWithinWord(begin), BITSPERWORD); 360 } else { 361 ASSERT(GetWordIdx(end) == GetWordIdx(begin)); 362 mask = GetRangeBitMask(GetBitIdxWithinWord(begin), GetBitIdxWithinWord(end)); 363 } 364 365 if (SET) { 366 bitmap_[GetWordIdx(begin)] |= mask; 367 } else { 368 bitmap_[GetWordIdx(begin)] &= ~mask; 369 } 370 } 371 372 /** 373 * \brief Check if bit range [begin, end) is valid. 374 */ CheckBitRange(size_t begin,size_t end)375 void CheckBitRange([[maybe_unused]] size_t begin, [[maybe_unused]] size_t end) const 376 { 377 ASSERT(begin < Size()); 378 ASSERT(end <= Size()); 379 ASSERT(begin <= end); 380 } 381 }; 382 383 /** 384 * Memory bitmap, binding a continuous range of memory to a bitmap. 385 * One bit represents BYTESPERCHUNK bytes of memory. 386 */ 387 template <size_t BYTESPERCHUNK = 1, typename pointer_type = object_pointer_type> 388 class MemBitmap : public Bitmap { 389 public: MemBitmap(void * mem_addr,size_t heap_size,void * bitmap_addr)390 explicit MemBitmap(void *mem_addr, size_t heap_size, void *bitmap_addr) 391 : Bitmap(static_cast<BitmapWordType *>(bitmap_addr), heap_size / BYTESPERCHUNK), 392 begin_addr_(ToPointerType(mem_addr)), 393 end_addr_(begin_addr_ + heap_size) 394 { 395 } 396 NO_COPY_SEMANTIC(MemBitmap); 397 NO_MOVE_SEMANTIC(MemBitmap); 398 399 /** 400 * \brief Reinitialize the MemBitmap for new memory range. 401 * The size of range will be the same as the initial 402 * because we reuse the same bitmap storage. 403 * @param mem_addr - start addr of the new range. 404 */ ReInitializeMemoryRange(void * mem_addr)405 void ReInitializeMemoryRange(void *mem_addr) 406 { 407 begin_addr_ = ToPointerType(mem_addr); 408 end_addr_ = begin_addr_ + MemSizeInBytes(); 409 Bitmap::ClearAllBits(); 410 } 411 GetBitMapSizeInByte(size_t heap_size)412 inline static constexpr size_t GetBitMapSizeInByte(size_t heap_size) 413 { 414 ASSERT(heap_size % BYTESPERCHUNK == 0); 415 size_t bit_size = heap_size / BYTESPERCHUNK; 416 return (AlignUp(bit_size, BITSPERWORD) >> Bitmap::LOG_BITSPERWORD) * sizeof(BitmapWordType); 417 } 418 419 ~MemBitmap() = default; 420 MemSizeInBytes()421 size_t MemSizeInBytes() const 422 { 423 return Size() * BYTESPERCHUNK; 424 } 425 GetHeapRange()426 inline std::pair<uintptr_t, uintptr_t> GetHeapRange() 427 { 428 return {begin_addr_, end_addr_}; 429 } 430 431 /** 432 * \brief Set bit corresponding to addr. 433 * @param addr - addr must be aligned to BYTESPERCHUNK. 434 */ Set(void * addr)435 void Set(void *addr) 436 { 437 CheckAddrValidity(addr); 438 SetBit(AddrToBitOffset(ToPointerType(addr))); 439 } 440 441 /** 442 * \brief Clear bit corresponding to addr. 443 * @param addr - addr must be aligned to BYTESPERCHUNK. 444 */ Clear(void * addr)445 void Clear(void *addr) 446 { 447 CheckAddrValidity(addr); 448 ClearBit(AddrToBitOffset(ToPointerType(addr))); 449 } 450 451 /** 452 * \brief Clear bits corresponding to addr range [begin, end). 453 */ ClearRange(void * begin,void * end)454 ALWAYS_INLINE void ClearRange(void *begin, void *end) 455 { 456 CheckHalfClosedHalfOpenAddressRange(begin, end); 457 ClearBitsInRange(AddrToBitOffset(ToPointerType(begin)), EndAddrToBitOffset(ToPointerType(end))); 458 } 459 460 /** 461 * \brief Test bit corresponding to addr. 462 * @param addr - addr must be aligned to BYTESPERCHUNK. 463 */ Test(const void * addr)464 bool Test(const void *addr) const 465 { 466 CheckAddrValidity(addr); 467 return TestBit(AddrToBitOffset(ToPointerType(addr))); 468 } 469 470 /** 471 * \brief Test bit corresponding to addr if addr is valid. 472 * @return value of indexed bit if addr is valid. If addr is invalid then false 473 */ TestIfAddrValid(const void * addr)474 bool TestIfAddrValid(const void *addr) const 475 { 476 if (IsAddrValid(addr)) { 477 return TestBit(AddrToBitOffset(ToPointerType(addr))); 478 } 479 return false; 480 } 481 482 /** 483 * \brief Atomically set bit corresponding to addr. If the bit is not set, set it atomically. Otherwise, do nothing. 484 * @param addr - addr must be aligned to BYTESPERCHUNK. 485 * @return Returns old value of the bit. 486 */ AtomicTestAndSet(void * addr)487 bool AtomicTestAndSet(void *addr) 488 { 489 CheckAddrValidity(addr); 490 return AtomicTestAndSetBit(AddrToBitOffset(ToPointerType(addr))); 491 } 492 493 /** 494 * \brief Atomically clear bit corresponding to addr. If the bit is set, clear it atomically. Otherwise, do nothing. 495 * @param addr - addr must be aligned to BYTESPERCHUNK. 496 * @return Returns old value of the bit. 497 */ AtomicTestAndClear(void * addr)498 bool AtomicTestAndClear(void *addr) 499 { 500 CheckAddrValidity(addr); 501 return AtomicTestAndClearBit(AddrToBitOffset(ToPointerType(addr))); 502 } 503 504 /** 505 * \brief Atomically test bit corresponding to addr. 506 * @param addr - addr must be aligned to BYTESPERCHUNK. 507 * @return Returns the value of the bit. 508 */ AtomicTest(void * addr)509 bool AtomicTest(void *addr) 510 { 511 CheckAddrValidity(addr); 512 return AtomicTestBit(AddrToBitOffset(ToPointerType(addr))); 513 } 514 515 /** 516 * \brief Find first marked chunk. 517 */ FindFirstMarkedChunks()518 void *FindFirstMarkedChunks() 519 { 520 void *first_marked = nullptr; 521 IterateOverSetBits([&first_marked, this](size_t bit_offset) { 522 first_marked = BitOffsetToAddr(bit_offset); 523 return false; 524 }); 525 return first_marked; 526 } 527 528 /** 529 * \brief Iterate over marked chunks of memory sequentially. 530 */ 531 template <typename MemVisitor> IterateOverMarkedChunks(const MemVisitor & visitor)532 void IterateOverMarkedChunks(const MemVisitor &visitor) 533 { 534 IterateOverSetBits([&visitor, this](size_t bit_offset) { 535 visitor(BitOffsetToAddr(bit_offset)); 536 return true; 537 }); 538 } 539 540 /** 541 * \brief Iterate over all chunks of memory sequentially. 542 */ 543 template <typename MemVisitor> IterateOverChunks(const MemVisitor & visitor)544 void IterateOverChunks(const MemVisitor &visitor) 545 { 546 IterateOverBits([&visitor, this](size_t bit_offset) { visitor(BitOffsetToAddr(bit_offset)); }); 547 } 548 549 /** 550 * \brief Iterate over marked chunks of memory in range [begin, end) sequentially. 551 */ 552 template <typename MemVisitor> IterateOverMarkedChunkInRange(void * begin,void * end,const MemVisitor & visitor)553 void IterateOverMarkedChunkInRange(void *begin, void *end, const MemVisitor &visitor) 554 { 555 CheckHalfClosedHalfOpenAddressRange(begin, end); 556 IterateOverSetBitsInRange(AddrToBitOffset(ToPointerType(begin)), EndAddrToBitOffset(ToPointerType(end)), 557 [&visitor, this](size_t bit_offset) { 558 visitor(BitOffsetToAddr(bit_offset)); 559 return true; 560 }); 561 } 562 563 /** 564 * \brief Iterate over all chunks of memory in range [begin, end) sequentially. 565 */ 566 template <typename MemVisitor> IterateOverChunkInRange(void * begin,void * end,const MemVisitor & visitor)567 void IterateOverChunkInRange(void *begin, void *end, const MemVisitor &visitor) 568 { 569 CheckHalfClosedHalfOpenAddressRange(begin, end); 570 IterateOverBitsInRange(AddrToBitOffset(ToPointerType(begin)), EndAddrToBitOffset(ToPointerType(end)), 571 [&visitor, this](size_t bit_offset) { visitor(BitOffsetToAddr(bit_offset)); }); 572 } 573 IsAddrInRange(const void * addr)574 bool IsAddrInRange(const void *addr) const 575 { 576 return addr >= ToVoidPtr(begin_addr_) && addr < ToVoidPtr(end_addr_); 577 } 578 579 template <class T> ToPointerType(T * val)580 static constexpr pointer_type ToPointerType(T *val) 581 { 582 return static_cast<pointer_type>(ToUintPtr(val)); 583 } 584 585 private: 586 /** 587 * \brief Compute bit offset from addr. 588 */ AddrToBitOffset(pointer_type addr)589 size_t AddrToBitOffset(pointer_type addr) const 590 { 591 return (addr - begin_addr_) / BYTESPERCHUNK; 592 } 593 EndAddrToBitOffset(pointer_type addr)594 size_t EndAddrToBitOffset(pointer_type addr) const 595 { 596 return (AlignUp(addr, BYTESPERCHUNK) - begin_addr_) / BYTESPERCHUNK; 597 } 598 599 /** 600 * \brief Compute address from bit offset. 601 */ BitOffsetToAddr(size_t bit_offset)602 void *BitOffsetToAddr(size_t bit_offset) const 603 { 604 return ToVoidPtr(begin_addr_ + bit_offset * BYTESPERCHUNK); 605 } 606 607 /** 608 * \brief Check if addr is valid. 609 */ CheckAddrValidity(const void * addr)610 void CheckAddrValidity([[maybe_unused]] const void *addr) const 611 { 612 ASSERT(IsAddrInRange(addr)); 613 ASSERT((ToPointerType(addr) - begin_addr_) % BYTESPERCHUNK == 0); 614 } 615 616 /** 617 * \brief Check if addr is valid with returned value. 618 * @return true if addr is valid 619 */ IsAddrValid(const void * addr)620 bool IsAddrValid(const void *addr) const 621 { 622 return IsAddrInRange(addr) && (ToPointerType(addr) - begin_addr_) % BYTESPERCHUNK == 0; 623 } 624 625 /** 626 * \brief Check if [begin, end) is a valid address range. 627 */ CheckHalfClosedHalfOpenAddressRange(void * begin,void * end)628 void CheckHalfClosedHalfOpenAddressRange([[maybe_unused]] void *begin, [[maybe_unused]] void *end) const 629 { 630 CheckAddrValidity(begin); 631 ASSERT(ToPointerType(end) >= begin_addr_); 632 ASSERT(ToPointerType(end) <= end_addr_); 633 ASSERT(ToPointerType(begin) <= ToPointerType(end)); 634 } 635 636 pointer_type begin_addr_ {0}; 637 pointer_type end_addr_ {0}; 638 }; 639 640 using MarkBitmap = MemBitmap<DEFAULT_ALIGNMENT_IN_BYTES>; 641 642 } // namespace panda::mem 643 644 #endif // PANDA_RUNTIME_MEM_GC_BITMAP_H_ 645