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