[vm] Remove quadratic time spent zapping scoped handles.

TEST=ci
Change-Id: I7faaf61ff33ae54795db4da1b253053abea0d5a9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/271581
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
This commit is contained in:
Ryan Macnak 2022-11-23 20:24:29 +00:00 committed by Commit Queue
parent 01fba618ed
commit ff8caf93b5
4 changed files with 41 additions and 36 deletions

View file

@ -90,11 +90,18 @@ HandleScope::~HandleScope() {
ASSERT(thread()->zone() != NULL);
VMHandles* handles = thread()->zone()->handles();
ASSERT(handles != NULL);
#if defined(DEBUG)
VMHandles::HandlesBlock* last = handles->scoped_blocks_;
#endif
handles->scoped_blocks_ = saved_handle_block_;
handles->scoped_blocks_->set_next_handle_slot(saved_handle_slot_);
#if defined(DEBUG)
handles->VerifyScopedHandleState();
handles->ZapFreeScopedHandles();
VMHandles::HandlesBlock* block = handles->scoped_blocks_;
for (;;) {
block->ZapFreeHandles();
if (block == last) break;
block = block->next_block();
}
ASSERT(thread()->top_handle_scope() == this);
thread()->set_top_handle_scope(link_);
#endif

View file

@ -218,14 +218,6 @@ class Handles {
// Allocates a new handle block and links it up.
void SetupNextZoneBlock();
#if defined(DEBUG)
// Verifies consistency of handle blocks after a scope is destroyed.
void VerifyScopedHandleState();
// Zaps the free scoped handles to an uninitialized value.
void ZapFreeScopedHandles();
#endif
HandlesBlock* zone_blocks_; // List of zone handles.
HandlesBlock first_scoped_block_; // First block of scoped handles.
HandlesBlock* scoped_blocks_; // List of scoped handles.

View file

@ -207,32 +207,6 @@ void Handles<kHandleSizeInWords, kHandlesPerChunk, kOffsetOfRawPtr>::
zone_blocks_ = new HandlesBlock(zone_blocks_);
}
#if defined(DEBUG)
template <int kHandleSizeInWords, int kHandlesPerChunk, int kOffsetOfRawPtr>
void Handles<kHandleSizeInWords, kHandlesPerChunk, kOffsetOfRawPtr>::
VerifyScopedHandleState() {
HandlesBlock* block = &first_scoped_block_;
const intptr_t end_index = (kHandleSizeInWords * kHandlesPerChunk);
do {
if (scoped_blocks_ == block && block->next_handle_slot() <= end_index) {
return;
}
block = block->next_block();
} while (block != NULL);
ASSERT(false);
}
template <int kHandleSizeInWords, int kHandlesPerChunk, int kOffsetOfRawPtr>
void Handles<kHandleSizeInWords, kHandlesPerChunk, kOffsetOfRawPtr>::
ZapFreeScopedHandles() {
HandlesBlock* block = scoped_blocks_;
while (block != NULL) {
block->ZapFreeHandles();
block = block->next_block();
}
}
#endif
template <int kHandleSizeInWords, int kHandlesPerChunk, int kOffsetOfRawPtr>
int Handles<kHandleSizeInWords, kHandlesPerChunk, kOffsetOfRawPtr>::
CountScopedHandles() const {

View file

@ -263,4 +263,36 @@ ISOLATE_UNIT_TEST_CASE(ZonesNotLimitedByCompressedHeap) {
}
#endif // defined(DART_COMPRESSED_POINTERS)
ISOLATE_UNIT_TEST_CASE(ZoneVerificationScaling) {
// This ought to complete in O(n), not O(n^2).
const intptr_t n = 1000000;
StackZone stack_zone(thread);
Zone* zone = stack_zone.GetZone();
{
HANDLESCOPE(thread);
for (intptr_t i = 0; i < n; i++) {
const Object& a = Object::Handle(zone);
DEBUG_ASSERT(!a.IsNotTemporaryScopedHandle());
USE(a);
const Object& b = Object::ZoneHandle(zone);
DEBUG_ASSERT(b.IsNotTemporaryScopedHandle());
USE(b);
}
// Leaves lots of HandleBlocks for recycling.
}
for (intptr_t i = 0; i < n; i++) {
HANDLESCOPE(thread);
const Object& a = Object::Handle(zone);
DEBUG_ASSERT(!a.IsNotTemporaryScopedHandle());
USE(a);
const Object& b = Object::ZoneHandle(zone);
DEBUG_ASSERT(b.IsNotTemporaryScopedHandle());
USE(b);
// Should not visit those recyclable blocks over and over again.
}
}
} // namespace dart