// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef VM_HANDLES_IMPL_H_ #define VM_HANDLES_IMPL_H_ #include "vm/heap.h" #include "vm/visitor.h" namespace dart { DECLARE_DEBUG_FLAG(bool, trace_handles); template void Handles::VisitObjectPointers( ObjectPointerVisitor* visitor) { // Visit all zone handles. HandlesBlock* block = zone_blocks_; while (block != NULL) { block->VisitObjectPointers(visitor); block = block->next_block(); } // Visit all scoped handles. VisitScopedHandles(visitor); } template void Handles::VisitScopedHandles( ObjectPointerVisitor* visitor) { HandlesBlock* block = &first_scoped_block_; do { block->VisitObjectPointers(visitor); if (block == scoped_blocks_) { return; } block = block->next_block(); } while (block != NULL); UNREACHABLE(); } template void Handles::Visit(HandleVisitor* visitor) { // Visit all zone handles. HandlesBlock* block = zone_blocks_; while (block != NULL) { block->Visit(visitor); block = block->next_block(); } // Visit all scoped handles. block = &first_scoped_block_; do { block->Visit(visitor); block = block->next_block(); } while (block != NULL); } template void Handles::Reset() { // Delete all the extra zone handle blocks allocated and reinit the first // zone block. if (zone_blocks_ != NULL) { DeleteHandleBlocks(zone_blocks_->next_block()); zone_blocks_->ReInit(); } // Delete all the extra scoped handle blocks allocated and reinit the first // scoped block. DeleteHandleBlocks(first_scoped_block_.next_block()); first_scoped_block_.ReInit(); scoped_blocks_ = &first_scoped_block_; } // Figure out the current handle scope using the current Isolate and // allocate a handle in that scope. The function assumes that a // current Isolate, current zone and current handle scope exist. It // asserts for this appropriately. template uword Handles::AllocateHandle(Isolate* isolate) { ASSERT(isolate != NULL); ASSERT(isolate->current_zone() != NULL); ASSERT(isolate->top_handle_scope() != NULL); ASSERT(isolate->no_handle_scope_depth() == 0); Handles* handles = isolate->current_zone()->handles(); ASSERT(handles != NULL); return handles->AllocateScopedHandle(); } // Figure out the current zone using the current Isolate and // allocate a handle in that zone. The function assumes that a // current Isolate and current zone exist. It asserts for // this appropriately. template uword Handles::AllocateZoneHandle(Isolate* isolate) { ASSERT(isolate != NULL); ASSERT(isolate->current_zone() != NULL); ASSERT(isolate->no_handle_scope_depth() == 0); Handles* handles = isolate->current_zone()->handles(); ASSERT(handles != NULL); uword address = handles->AllocateHandleInZone(); return address; } // Figure out the current zone using the current Isolate and // check if the specified handle has been allocated in this zone. template bool Handles::IsZoneHandle(uword handle) { // TODO(5411412): Accessing the current isolate is a performance problem, // consider passing it down as a parameter. Isolate* isolate = Isolate::Current(); ASSERT(isolate != NULL); ASSERT(isolate->current_zone() != NULL); Handles* handles = isolate->current_zone()->handles(); ASSERT(handles != NULL); return handles->IsValidZoneHandle(handle); } template void Handles::DeleteAll() { // Delete all the zone allocated handle blocks. // GCTrace does not need to trace this call to DeleteHandleBlocks, // since the individual zone deletions will be caught // by instrumentation in the BaseZone destructor. DeleteHandleBlocks(zone_blocks_); zone_blocks_ = NULL; // Delete all the scoped handle blocks. scoped_blocks_ = first_scoped_block_.next_block(); DeleteHandleBlocks(scoped_blocks_); first_scoped_block_.ReInit(); scoped_blocks_ = &first_scoped_block_; } template void Handles::DeleteHandleBlocks( HandlesBlock* blocks) { while (blocks != NULL) { HandlesBlock* block = blocks; blocks = blocks->next_block(); delete block; } } template void Handles::SetupNextScopeBlock() { #if defined(DEBUG) if (FLAG_trace_handles) { OS::PrintErr("*** Handle Counts for (0x%" Px "):Zone = %d,Scoped = %d\n", reinterpret_cast(this), CountZoneHandles(), CountScopedHandles()); } #endif if (scoped_blocks_->next_block() == NULL) { scoped_blocks_->set_next_block(new HandlesBlock(NULL)); } scoped_blocks_ = scoped_blocks_->next_block(); scoped_blocks_->set_next_handle_slot(0); #if defined(DEBUG) scoped_blocks_->ZapFreeHandles(); #endif } // Validation of the handle involves iterating through all the // handle blocks to check if the handle is valid, please // use this only in ASSERT code for verification purposes. template bool Handles::IsValidScopedHandle(uword handle) const { const HandlesBlock* iterator = &first_scoped_block_; while (iterator != NULL) { if (iterator->IsValidHandle(handle)) { return true; } iterator = iterator->next_block(); } return false; } template bool Handles::IsValidZoneHandle(uword handle) const { const HandlesBlock* iterator = zone_blocks_; while (iterator != NULL) { if (iterator->IsValidHandle(handle)) { return true; } iterator = iterator->next_block(); } return false; } template void Handles::SetupNextZoneBlock() { #if defined(DEBUG) if (FLAG_trace_handles) { OS::PrintErr("*** Handle Counts for (0x%" Px "):Zone = %d,Scoped = %d\n", reinterpret_cast(this), CountZoneHandles(), CountScopedHandles()); } #endif zone_blocks_ = new HandlesBlock(zone_blocks_); ASSERT(zone_blocks_ != NULL); } #if defined(DEBUG) template void Handles::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 void Handles::ZapFreeScopedHandles() { HandlesBlock* block = scoped_blocks_; while (block != NULL) { block->ZapFreeHandles(); block = block->next_block(); } } #endif template int Handles::CountScopedHandles() const { int count = 0; const HandlesBlock* block = &first_scoped_block_; do { count += block->HandleCount(); if (block == scoped_blocks_) { return count; } block = block->next_block(); } while (block != NULL); UNREACHABLE(); return 0; } template int Handles::CountZoneHandles() const { int count = 0; const HandlesBlock* block = zone_blocks_; while (block != NULL) { count += block->HandleCount(); block = block->next_block(); } return count; } template Handles::HandlesBlock::~HandlesBlock() { #if defined(DEBUG) ReInit(); #endif } template void Handles::HandlesBlock::ReInit() { next_handle_slot_ = 0; next_block_ = NULL; #if defined(DEBUG) ZapFreeHandles(); #endif } template void Handles::HandlesBlock::VisitObjectPointers( ObjectPointerVisitor* visitor) { ASSERT(visitor != NULL); for (intptr_t i = 0; i < next_handle_slot_; i += kHandleSizeInWords) { visitor->VisitPointer( reinterpret_cast(&data_[i + kOffsetOfRawPtr/kWordSize])); } } template void Handles::HandlesBlock::Visit(HandleVisitor* visitor) { ASSERT(visitor != NULL); for (intptr_t i = 0; i < next_handle_slot_; i += kHandleSizeInWords) { visitor->VisitHandle(reinterpret_cast(&data_[i])); } } #if defined(DEBUG) template void Handles::HandlesBlock::ZapFreeHandles() { // Reinitialize the handle area to some uninitialized value. for (intptr_t i = next_handle_slot_; i < (kHandleSizeInWords * kHandlesPerChunk); i++) { data_[i] = kZapUninitializedWord; } } #endif template int Handles::HandlesBlock::HandleCount() const { return (next_handle_slot_ / kHandleSizeInWords); } } // namespace dart #endif // VM_HANDLES_IMPL_H_