| 441 | } |
| 442 | |
| 443 | void HashStringAllocator::free(Header* _header) { |
| 444 | Header* header = _header; |
| 445 | |
| 446 | do { |
| 447 | Header* continued = nullptr; |
| 448 | if (header->isContinued()) { |
| 449 | continued = header->nextContinued(); |
| 450 | header->clearContinued(); |
| 451 | } |
| 452 | if (header->size() > kMaxAlloc && !pool_.isInCurrentRange(header) && |
| 453 | allocationsFromPool_.find(header) != allocationsFromPool_.end()) { |
| 454 | freeToPool(header, header->size() + sizeof(Header)); |
| 455 | // In `freeToPool()`, it accounts for sizeof(Header). |
| 456 | cumulativeBytes_ += sizeof(Header); |
| 457 | } else { |
| 458 | BOLT_CHECK(!header->isFree()); |
| 459 | freeBytes_ += header->size() + sizeof(Header); |
| 460 | cumulativeBytes_ -= header->size(); |
| 461 | Header* next = header->next(); |
| 462 | if (next) { |
| 463 | BOLT_CHECK(!next->isPreviousFree()); |
| 464 | if (next->isFree()) { |
| 465 | --numFree_; |
| 466 | removeFromFreeList(next); |
| 467 | header->setSize(header->size() + next->size() + sizeof(Header)); |
| 468 | next = reinterpret_cast<Header*>(header->end()); |
| 469 | BOLT_CHECK(next->isArenaEnd() || !next->isFree()); |
| 470 | } |
| 471 | } |
| 472 | if (header->isPreviousFree()) { |
| 473 | auto previousFree = getPreviousFree(header); |
| 474 | removeFromFreeList(previousFree); |
| 475 | previousFree->setSize( |
| 476 | previousFree->size() + header->size() + sizeof(Header)); |
| 477 | |
| 478 | header = previousFree; |
| 479 | } else { |
| 480 | ++numFree_; |
| 481 | } |
| 482 | auto freedSize = header->size(); |
| 483 | auto freeIndex = freeListIndex(freedSize); |
| 484 | bits::setBit(freeNonEmpty_, freeIndex); |
| 485 | free_[freeIndex].insert( |
| 486 | reinterpret_cast<CompactDoubleList*>(header->begin())); |
| 487 | markAsFree(header); |
| 488 | } |
| 489 | header = continued; |
| 490 | } while (header); |
| 491 | } |
| 492 | |
| 493 | // static |
| 494 | int64_t HashStringAllocator::offset( |
no test coverage detected