// 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 RUNTIME_VM_HANDLES_IMPL_H_ #define RUNTIME_VM_HANDLES_IMPL_H_ #include "vm/handle_visitor.h" #include "vm/thread.h" #include "vm/visitor.h" namespace dart { template void Handles:: VisitObjectPointers(ObjectPointerVisitor* visitor) { // Visit all zone handles. HandlesBlock* block = zone_blocks_; while (block != nullptr) { 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 != nullptr); UNREACHABLE(); } template void Handles::Visit( HandleVisitor* visitor) { // Visit all zone handles. HandlesBlock* block = zone_blocks_; while (block != nullptr) { 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 != nullptr); } template void Handles::Reset() { // Delete all the extra zone handle blocks allocated and reinit the first // zone block. if (zone_blocks_ != nullptr) { 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 Zone and // allocate a handle in that scope. The function assumes that a // current handle scope exists. It asserts for this appropriately. template uword Handles:: AllocateHandle(Zone* zone) { #if defined(DEBUG) Thread* thread = Thread::Current(); ASSERT(thread->MayAllocateHandles()); #endif // DEBUG Handles* handles = zone->handles(); ASSERT(handles != nullptr); return handles->AllocateScopedHandle(); } // The function assumes that 'zone' is the current zone and asserts for // this appropriately. template uword Handles:: AllocateZoneHandle(Zone* zone) { #if defined(DEBUG) Thread* thread = Thread::Current(); ASSERT(zone->ContainsNestedZone(thread->zone())); ASSERT(thread->MayAllocateHandles()); #endif // DEBUG Handles* handles = zone->handles(); ASSERT(handles != nullptr); uword address = handles->AllocateHandleInZone(); return address; } #if defined(DEBUG) // Figure out the current zone using the current Thread and // check if the specified handle has been allocated in this zone. template bool Handles:: IsZoneHandle(uword handle) { // TODO(5411412): Accessing the current thread is a performance problem, // consider passing it down as a parameter. Thread* thread = Thread::Current(); ASSERT(thread != nullptr); ASSERT(thread->zone() != nullptr); Handles* handles = thread->zone()->handles(); ASSERT(handles != nullptr); return handles->IsValidZoneHandle(handle); } #endif 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_ = nullptr; // 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 != nullptr) { HandlesBlock* block = blocks; blocks = blocks->next_block(); delete block; } } template void Handles:: SetupNextScopeBlock() { if (FLAG_trace_handles) { OS::PrintErr("*** Handle Counts for (0x%" Px "):Zone = %d,Scoped = %d\n", reinterpret_cast(this), CountZoneHandles(), CountScopedHandles()); } if (scoped_blocks_->next_block() == nullptr) { HandlesBlock* block = new HandlesBlock(nullptr); scoped_blocks_->set_next_block(block); } 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 != nullptr) { 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 != nullptr) { if (iterator->IsValidHandle(handle)) { return true; } iterator = iterator->next_block(); } return false; } template void Handles:: SetupNextZoneBlock() { if (FLAG_trace_handles) { OS::PrintErr("*** Handle Counts for (0x%" Px "):Zone = %d,Scoped = %d\n", reinterpret_cast(this), CountZoneHandles(), CountScopedHandles()); } zone_blocks_ = new HandlesBlock(zone_blocks_); } 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 != nullptr); UNREACHABLE(); return 0; } template int Handles:: CountZoneHandles() const { int count = 0; const HandlesBlock* block = zone_blocks_; while (block != nullptr) { 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_ = nullptr; #if defined(DEBUG) ZapFreeHandles(); #endif } template void Handles:: HandlesBlock::VisitObjectPointers(ObjectPointerVisitor* visitor) { ASSERT(visitor != nullptr); 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 != nullptr); 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 // RUNTIME_VM_HANDLES_IMPL_H_