diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2013-08-10 16:27:43 +0200 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2013-08-10 16:27:43 +0200 |
commit | f69be329f0d78f19e71ac9e75d6e4ee816e13c97 (patch) | |
tree | 022e53d1aff74dbe50f3984c154461bf6c19efb0 /deps/v8/src/global-handles.cc | |
parent | 39aa894035f9e3b58e04ce1a2b598e496e1f6bd6 (diff) | |
download | node-new-f69be329f0d78f19e71ac9e75d6e4ee816e13c97.tar.gz |
v8: upgrade v8 to 3.20.14.1
Diffstat (limited to 'deps/v8/src/global-handles.cc')
-rw-r--r-- | deps/v8/src/global-handles.cc | 594 |
1 files changed, 445 insertions, 149 deletions
diff --git a/deps/v8/src/global-handles.cc b/deps/v8/src/global-handles.cc index 88ebe31647..2eae474510 100644 --- a/deps/v8/src/global-handles.cc +++ b/deps/v8/src/global-handles.cc @@ -56,7 +56,9 @@ class GlobalHandles::Node { NORMAL, // Normal global handle. WEAK, // Flagged as weak but not yet finalized. PENDING, // Has been recognized as only reachable by weak handles. - NEAR_DEATH // Callback has informed the handle is near death. + NEAR_DEATH, // Callback has informed the handle is near death. + + NUMBER_OF_STATES }; // Maps handle location (slot) to the containing node. @@ -71,6 +73,7 @@ class GlobalHandles::Node { STATIC_ASSERT(static_cast<int>(NodeState::kMask) == Internals::kNodeStateMask); STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue); + STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue); STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue); STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) == Internals::kNodeIsIndependentShift); @@ -93,13 +96,12 @@ class GlobalHandles::Node { } #endif - void Initialize(int index, Node** first_free) { + void Initialize(int index, Node* first_free) { index_ = static_cast<uint8_t>(index); ASSERT(static_cast<int>(index_) == index); set_state(FREE); set_in_new_space_list(false); - parameter_or_next_free_.next_free = *first_free; - *first_free = this; + parameter_or_next_free_.next_free = first_free; } void Acquire(Object* object) { @@ -111,7 +113,6 @@ class GlobalHandles::Node { set_state(NORMAL); parameter_or_next_free_.parameter = NULL; weak_reference_callback_ = NULL; - IncreaseBlockUses(); } void Release() { @@ -125,7 +126,7 @@ class GlobalHandles::Node { set_partially_dependent(false); weak_reference_callback_ = NULL; #endif - DecreaseBlockUses(); + ReleaseFromBlock(); } // Object slot accessors. @@ -204,10 +205,6 @@ class GlobalHandles::Node { } void clear_partially_dependent() { set_partially_dependent(false); } - // Callback accessor. - // TODO(svenpanne) Re-enable or nuke later. - // WeakReferenceCallback callback() { return callback_; } - // Callback parameter accessors. void set_parameter(void* parameter) { ASSERT(state() != FREE); @@ -276,8 +273,7 @@ class GlobalHandles::Node { private: inline NodeBlock* FindBlock(); inline GlobalHandles* GetGlobalHandles(); - inline void IncreaseBlockUses(); - inline void DecreaseBlockUses(); + inline void ReleaseFromBlock(); // Storage for object pointer. // Placed first to avoid offset computation. @@ -315,163 +311,404 @@ class GlobalHandles::Node { }; -class GlobalHandles::NodeBlock { +class GlobalHandles::BlockListIterator { public: - static const int kSize = 256; + explicit inline BlockListIterator(BlockList* anchor) + : anchor_(anchor), current_(anchor->next()) { + ASSERT(anchor->IsAnchor()); + } + inline BlockList* block() const { + ASSERT(!done()); + return current_; + } + inline bool done() const { + ASSERT_EQ(anchor_ == current_, current_->IsAnchor()); + return anchor_ == current_; + } + inline void Advance() { + ASSERT(!done()); + current_ = current_->next(); + } + + private: + BlockList* const anchor_; + BlockList* current_; + DISALLOW_COPY_AND_ASSIGN(BlockListIterator); +}; + + +GlobalHandles::BlockList::BlockList() + : prev_block_(this), + next_block_(this), + first_free_(NULL), + used_nodes_(0) {} + + +void GlobalHandles::BlockList::InsertAsNext(BlockList* const block) { + ASSERT(block != this); + ASSERT(!block->IsAnchor()); + ASSERT(block->IsDetached()); + block->prev_block_ = this; + block->next_block_ = next_block_; + next_block_->prev_block_ = block; + next_block_ = block; + ASSERT(!IsDetached()); + ASSERT(!block->IsDetached()); +} + + +void GlobalHandles::BlockList::Detach() { + ASSERT(!IsAnchor()); + ASSERT(!IsDetached()); + prev_block_->next_block_ = next_block_; + next_block_->prev_block_ = prev_block_; + prev_block_ = this; + next_block_ = this; + ASSERT(IsDetached()); +} - explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next) - : next_(next), - used_nodes_(0), - next_used_(NULL), - prev_used_(NULL), - global_handles_(global_handles) {} - void PutNodesOnFreeList(Node** first_free) { +bool GlobalHandles::BlockList::HasAtLeastLength(int length) { + ASSERT(IsAnchor()); + ASSERT(length > 0); + for (BlockListIterator it(this); !it.done(); it.Advance()) { + if (--length <= 0) return true; + } + return false; +} + + +#ifdef DEBUG +int GlobalHandles::BlockList::LengthOfFreeList() { + int count = 0; + Node* node = first_free_; + while (node != NULL) { + count++; + node = node->next_free(); + } + return count; +} +#endif + + +int GlobalHandles::BlockList::CompareBlocks(const void* a, const void* b) { + const BlockList* block_a = + *reinterpret_cast<const BlockList**>(reinterpret_cast<uintptr_t>(a)); + const BlockList* block_b = + *reinterpret_cast<const BlockList**>(reinterpret_cast<uintptr_t>(b)); + if (block_a->used_nodes() > block_b->used_nodes()) return -1; + if (block_a->used_nodes() == block_b->used_nodes()) return 0; + return 1; +} + + +class GlobalHandles::NodeBlock : public BlockList { + public: + static const int kSize = 256; + + explicit NodeBlock(GlobalHandles* global_handles) + : global_handles_(global_handles) { + // Initialize nodes + Node* first_free = first_free_; for (int i = kSize - 1; i >= 0; --i) { nodes_[i].Initialize(i, first_free); + first_free = &nodes_[i]; } + first_free_ = first_free; + ASSERT(!IsAnchor()); + // Link into global_handles + ASSERT(global_handles->non_full_blocks_.IsDetached()); + global_handles->non_full_blocks_.InsertAsHead(this); + global_handles->number_of_blocks_++; } - Node* node_at(int index) { - ASSERT(0 <= index && index < kSize); - return &nodes_[index]; - } - - void IncreaseUses() { + Node* Acquire(Object* o) { ASSERT(used_nodes_ < kSize); - if (used_nodes_++ == 0) { - NodeBlock* old_first = global_handles_->first_used_block_; - global_handles_->first_used_block_ = this; - next_used_ = old_first; - prev_used_ = NULL; - if (old_first == NULL) return; - old_first->prev_used_ = this; + ASSERT(first_free_ != NULL); + ASSERT(global_handles_->non_full_blocks_.next() == this); + // Remove from free list + Node* node = first_free_; + first_free_ = node->next_free(); + // Increment counters + global_handles_->isolate()->counters()->global_handles()->Increment(); + global_handles_->number_of_global_handles_++; + // Initialize node with value + node->Acquire(o); + bool now_full = ++used_nodes_ == kSize; + ASSERT_EQ(now_full, first_free_ == NULL); + if (now_full) { + // Move block to tail of non_full_blocks_ + Detach(); + global_handles_->full_blocks_.InsertAsTail(this); } + return node; } - void DecreaseUses() { + void Release(Node* node) { ASSERT(used_nodes_ > 0); - if (--used_nodes_ == 0) { - if (next_used_ != NULL) next_used_->prev_used_ = prev_used_; - if (prev_used_ != NULL) prev_used_->next_used_ = next_used_; - if (this == global_handles_->first_used_block_) { - global_handles_->first_used_block_ = next_used_; - } + // Add to free list + node->set_next_free(first_free_); + first_free_ = node; + // Decrement counters + global_handles_->isolate()->counters()->global_handles()->Decrement(); + global_handles_->number_of_global_handles_--; + bool was_full = used_nodes_-- == kSize; + ASSERT_EQ(was_full, first_free_->next_free() == NULL); + if (was_full) { + // Move this block to head of non_full_blocks_ + Detach(); + global_handles_->non_full_blocks_.InsertAsHead(this); } } + Node* node_at(int index) { + ASSERT(0 <= index && index < kSize); + return &nodes_[index]; + } + GlobalHandles* global_handles() { return global_handles_; } - // Next block in the list of all blocks. - NodeBlock* next() const { return next_; } + static NodeBlock* Cast(BlockList* block_list) { + ASSERT(!block_list->IsAnchor()); + return static_cast<NodeBlock*>(block_list); + } - // Next/previous block in the list of blocks with used nodes. - NodeBlock* next_used() const { return next_used_; } - NodeBlock* prev_used() const { return prev_used_; } + static NodeBlock* From(Node* node, uint8_t index) { + uintptr_t ptr = reinterpret_cast<uintptr_t>(node - index); + ptr -= OFFSET_OF(NodeBlock, nodes_); + NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); + ASSERT(block->node_at(index) == node); + return block; + } private: Node nodes_[kSize]; - NodeBlock* const next_; - int used_nodes_; - NodeBlock* next_used_; - NodeBlock* prev_used_; GlobalHandles* global_handles_; }; -GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { - return FindBlock()->global_handles(); +void GlobalHandles::BlockList::SortBlocks(GlobalHandles* global_handles, + bool prune) { + // Always sort at least 2 blocks + if (!global_handles->non_full_blocks_.HasAtLeastLength(2)) return; + // build a vector that could contain the upper bound of the block count + int number_of_blocks = global_handles->block_count(); + // Build array of blocks and update number_of_blocks to actual count + ScopedVector<BlockList*> blocks(number_of_blocks); + { + int i = 0; + BlockList* anchor = &global_handles->non_full_blocks_; + for (BlockListIterator it(anchor); !it.done(); it.Advance()) { + blocks[i++] = it.block(); + } + number_of_blocks = i; + } + // Nothing to do. + if (number_of_blocks <= 1) return; + // Sort blocks + qsort(blocks.start(), number_of_blocks, sizeof(blocks[0]), CompareBlocks); + // Prune empties + if (prune) { + static const double kUnusedPercentage = 0.30; + static const double kUsedPercentage = 1.30; + int total_slots = global_handles->number_of_blocks_ * NodeBlock::kSize; + const int total_used = global_handles->number_of_global_handles_; + const int target_unused = static_cast<int>(Max( + total_used * kUsedPercentage, + total_slots * kUnusedPercentage)); + // Reverse through empty blocks. Note: always leave one block free. + int blocks_deleted = 0; + for (int i = number_of_blocks - 1; i > 0 && blocks[i]->IsUnused(); i--) { + // Not worth deleting + if (total_slots - total_used < target_unused) break; + blocks[i]->Detach(); + delete blocks[i]; + blocks_deleted++; + total_slots -= NodeBlock::kSize; + } + global_handles->number_of_blocks_ -= blocks_deleted; + number_of_blocks -= blocks_deleted; + } + // Relink all blocks + for (int i = 0; i < number_of_blocks; i++) { + blocks[i]->Detach(); + global_handles->non_full_blocks_.InsertAsTail(blocks[i]); + } +#ifdef DEBUG + // Check sorting + BlockList* anchor = &global_handles->non_full_blocks_; + int last_size = NodeBlock::kSize; + for (BlockListIterator it(anchor); !it.done(); it.Advance()) { + ASSERT(it.block()->used_nodes() <= last_size); + last_size = it.block()->used_nodes(); + } +#endif } -GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { - intptr_t ptr = reinterpret_cast<intptr_t>(this); - ptr = ptr - index_ * sizeof(Node); - NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); - ASSERT(block->node_at(index_) == this); - return block; +#ifdef DEBUG +void GlobalHandles::VerifyBlockInvariants() { + int number_of_blocks = 0; + int number_of_handles = 0; + for (int i = 0; i < kAllAnchorsSize; i++) { + for (BlockListIterator it(all_anchors_[i]); !it.done(); it.Advance()) { + BlockList* block = it.block(); + number_of_blocks++; + int used_nodes = block->used_nodes(); + number_of_handles += used_nodes; + int unused_nodes = block->LengthOfFreeList(); + ASSERT_EQ(used_nodes + unused_nodes, NodeBlock::kSize); + if (all_anchors_[i] == &full_blocks_) { + ASSERT_EQ(NodeBlock::kSize, used_nodes); + } else { + ASSERT_NE(NodeBlock::kSize, used_nodes); + } + } + } + ASSERT_EQ(number_of_handles, number_of_global_handles_); + ASSERT_EQ(number_of_blocks, number_of_blocks_); } +#endif -void GlobalHandles::Node::IncreaseBlockUses() { - NodeBlock* node_block = FindBlock(); - node_block->IncreaseUses(); - GlobalHandles* global_handles = node_block->global_handles(); - global_handles->isolate()->counters()->global_handles()->Increment(); - global_handles->number_of_global_handles_++; +void GlobalHandles::SortBlocks(bool shouldPrune) { +#ifdef DEBUG + VerifyBlockInvariants(); +#endif + BlockList::SortBlocks(this, shouldPrune); +#ifdef DEBUG + VerifyBlockInvariants(); +#endif } -void GlobalHandles::Node::DecreaseBlockUses() { - NodeBlock* node_block = FindBlock(); - GlobalHandles* global_handles = node_block->global_handles(); - parameter_or_next_free_.next_free = global_handles->first_free_; - global_handles->first_free_ = this; - node_block->DecreaseUses(); - global_handles->isolate()->counters()->global_handles()->Decrement(); - global_handles->number_of_global_handles_--; +GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { + return FindBlock()->global_handles(); +} + + +GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { + return NodeBlock::From(this, index_); +} + + +void GlobalHandles::Node::ReleaseFromBlock() { + FindBlock()->Release(this); } class GlobalHandles::NodeIterator { public: explicit NodeIterator(GlobalHandles* global_handles) - : block_(global_handles->first_used_block_), - index_(0) {} + : all_anchors_(global_handles->all_anchors_), + block_(all_anchors_[0]), + anchor_index_(0), + node_index_(0) { + AdvanceBlock(); + } - bool done() const { return block_ == NULL; } + bool done() const { + return anchor_index_ == kAllAnchorsSize; + } Node* node() const { ASSERT(!done()); - return block_->node_at(index_); + return NodeBlock::Cast(block_)->node_at(node_index_); } void Advance() { ASSERT(!done()); - if (++index_ < NodeBlock::kSize) return; - index_ = 0; - block_ = block_->next_used(); + if (++node_index_ < NodeBlock::kSize) return; + node_index_ = 0; + AdvanceBlock(); } + typedef int CountArray[Node::NUMBER_OF_STATES]; + static int CollectStats(GlobalHandles* global_handles, CountArray counts); + private: - NodeBlock* block_; - int index_; + void AdvanceBlock() { + ASSERT(!done()); + while (true) { + block_ = block_->next(); + // block is valid + if (block_ != all_anchors_[anchor_index_]) { + ASSERT(!done()); + ASSERT(!block_->IsAnchor()); + // skip empty blocks + if (block_->IsUnused()) continue; + return; + } + // jump lists + anchor_index_++; + if (anchor_index_ == kAllAnchorsSize) break; + block_ = all_anchors_[anchor_index_]; + } + ASSERT(done()); + } + + BlockList* const * const all_anchors_; + BlockList* block_; + int anchor_index_; + int node_index_; DISALLOW_COPY_AND_ASSIGN(NodeIterator); }; +int GlobalHandles::NodeIterator::CollectStats(GlobalHandles* global_handles, + CountArray counts) { + static const int kSize = Node::NUMBER_OF_STATES; + for (int i = 0; i < kSize; i++) { + counts[i] = 0; + } + int total = 0; + for (NodeIterator it(global_handles); !it.done(); it.Advance()) { + total++; + Node::State state = it.node()->state(); + ASSERT(state >= 0 && state < kSize); + counts[state]++; + } + // NodeIterator skips empty blocks + int skipped = global_handles->number_of_blocks_ * NodeBlock::kSize - total; + total += skipped; + counts[Node::FREE] += total; + return total; +} + + GlobalHandles::GlobalHandles(Isolate* isolate) : isolate_(isolate), + number_of_blocks_(0), number_of_global_handles_(0), - first_block_(NULL), - first_used_block_(NULL), - first_free_(NULL), post_gc_processing_count_(0), - object_group_connections_(kObjectGroupConnectionsCapacity) {} + object_group_connections_(kObjectGroupConnectionsCapacity) { + all_anchors_[0] = &full_blocks_; + all_anchors_[1] = &non_full_blocks_; +} GlobalHandles::~GlobalHandles() { - NodeBlock* block = first_block_; - while (block != NULL) { - NodeBlock* tmp = block->next(); - delete block; - block = tmp; + for (int i = 0; i < kAllAnchorsSize; i++) { + BlockList* block = all_anchors_[i]->next(); + while (block != all_anchors_[i]) { + BlockList* tmp = block->next(); + block->Detach(); + delete NodeBlock::Cast(block); + block = tmp; + } } - first_block_ = NULL; } Handle<Object> GlobalHandles::Create(Object* value) { - if (first_free_ == NULL) { - first_block_ = new NodeBlock(this, first_block_); - first_block_->PutNodesOnFreeList(&first_free_); - } - ASSERT(first_free_ != NULL); - // Take the first node in the free list. - Node* result = first_free_; - first_free_ = result->next_free(); - result->Acquire(value); + if (non_full_blocks_.IsDetached()) { + new NodeBlock(this); + ASSERT(!non_full_blocks_.IsDetached()); + } + ASSERT(non_full_blocks_.IsAnchor()); + ASSERT(!non_full_blocks_.next()->IsAnchor()); + Node* result = NodeBlock::Cast(non_full_blocks_.next())->Acquire(value); if (isolate_->heap()->InNewSpace(value) && !result->is_in_new_space_list()) { new_space_nodes_.Add(result); @@ -661,21 +898,32 @@ bool GlobalHandles::PostGarbageCollectionProcessing( } } } else { - for (NodeIterator it(this); !it.done(); it.Advance()) { - if (!it.node()->IsRetainer()) { - // Free nodes do not have weak callbacks. Do not use them to compute - // the next_gc_likely_to_collect_more. - continue; + // Must cache all blocks, as NodeIterator can't survive mutation. + List<NodeBlock*> blocks(number_of_blocks_); + for (int i = 0; i < kAllAnchorsSize; i++) { + for (BlockListIterator it(all_anchors_[i]); !it.done(); it.Advance()) { + blocks.Add(NodeBlock::Cast(it.block())); } - it.node()->clear_partially_dependent(); - if (it.node()->PostGarbageCollectionProcessing(isolate_)) { - if (initial_post_gc_processing_count != post_gc_processing_count_) { - // See the comment above. - return next_gc_likely_to_collect_more; + } + for (int block_index = 0; block_index < blocks.length(); block_index++) { + NodeBlock* block = blocks[block_index]; + for (int node_index = 0; node_index < NodeBlock::kSize; node_index++) { + Node* node = block->node_at(node_index); + if (!node->IsRetainer()) { + // Free nodes do not have weak callbacks. Do not use them to compute + // the next_gc_likely_to_collect_more. + continue; + } + node->clear_partially_dependent(); + if (node->PostGarbageCollectionProcessing(isolate_)) { + if (initial_post_gc_processing_count != post_gc_processing_count_) { + // See the comment above. + return next_gc_likely_to_collect_more; + } + } + if (!node->IsRetainer()) { + next_gc_likely_to_collect_more = true; } - } - if (!it.node()->IsRetainer()) { - next_gc_likely_to_collect_more = true; } } } @@ -698,6 +946,8 @@ bool GlobalHandles::PostGarbageCollectionProcessing( } } new_space_nodes_.Rewind(last); + bool shouldPruneBlocks = collector != SCAVENGER; + SortBlocks(shouldPruneBlocks); return next_gc_likely_to_collect_more; } @@ -765,48 +1015,30 @@ int GlobalHandles::NumberOfGlobalObjectWeakHandles() { void GlobalHandles::RecordStats(HeapStats* stats) { - *stats->global_handle_count = 0; - *stats->weak_global_handle_count = 0; - *stats->pending_global_handle_count = 0; - *stats->near_death_global_handle_count = 0; - *stats->free_global_handle_count = 0; - for (NodeIterator it(this); !it.done(); it.Advance()) { - *stats->global_handle_count += 1; - if (it.node()->state() == Node::WEAK) { - *stats->weak_global_handle_count += 1; - } else if (it.node()->state() == Node::PENDING) { - *stats->pending_global_handle_count += 1; - } else if (it.node()->state() == Node::NEAR_DEATH) { - *stats->near_death_global_handle_count += 1; - } else if (it.node()->state() == Node::FREE) { - *stats->free_global_handle_count += 1; - } - } + NodeIterator::CountArray counts; + int total = NodeIterator::CollectStats(this, counts); + *stats->global_handle_count = total; + *stats->weak_global_handle_count = counts[Node::WEAK]; + *stats->pending_global_handle_count = counts[Node::PENDING]; + *stats->near_death_global_handle_count = counts[Node::NEAR_DEATH]; + *stats->free_global_handle_count = counts[Node::FREE]; } + #ifdef DEBUG void GlobalHandles::PrintStats() { - int total = 0; - int weak = 0; - int pending = 0; - int near_death = 0; - int destroyed = 0; - - for (NodeIterator it(this); !it.done(); it.Advance()) { - total++; - if (it.node()->state() == Node::WEAK) weak++; - if (it.node()->state() == Node::PENDING) pending++; - if (it.node()->state() == Node::NEAR_DEATH) near_death++; - if (it.node()->state() == Node::FREE) destroyed++; - } - + NodeIterator::CountArray counts; + int total = NodeIterator::CollectStats(this, counts); + size_t total_consumed = sizeof(NodeBlock) * number_of_blocks_; PrintF("Global Handle Statistics:\n"); - PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total); - PrintF(" # weak = %d\n", weak); - PrintF(" # pending = %d\n", pending); - PrintF(" # near_death = %d\n", near_death); - PrintF(" # free = %d\n", destroyed); + PrintF(" allocated blocks = %d\n", number_of_blocks_); + PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", total_consumed); + PrintF(" # normal = %d\n", counts[Node::NORMAL]); + PrintF(" # weak = %d\n", counts[Node::WEAK]); + PrintF(" # pending = %d\n", counts[Node::PENDING]); + PrintF(" # near_death = %d\n", counts[Node::NEAR_DEATH]); + PrintF(" # free = %d\n", counts[Node::FREE]); PrintF(" # total = %d\n", total); } @@ -1018,4 +1250,68 @@ void GlobalHandles::ComputeObjectGroupsAndImplicitReferences() { } +EternalHandles::EternalHandles() : size_(0) { + STATIC_ASSERT(v8::kUninitializedEternalIndex == kInvalidIndex); + for (unsigned i = 0; i < ARRAY_SIZE(singleton_handles_); i++) { + singleton_handles_[i] = kInvalidIndex; + } +} + + +EternalHandles::~EternalHandles() { + for (int i = 0; i < blocks_.length(); i++) delete[] blocks_[i]; +} + + +void EternalHandles::IterateAllRoots(ObjectVisitor* visitor) { + int limit = size_; + for (int i = 0; i < blocks_.length(); i++) { + ASSERT(limit > 0); + Object** block = blocks_[i]; + visitor->VisitPointers(block, block + Min(limit, kSize)); + limit -= kSize; + } +} + + +void EternalHandles::IterateNewSpaceRoots(ObjectVisitor* visitor) { + for (int i = 0; i < new_space_indices_.length(); i++) { + visitor->VisitPointer(GetLocation(new_space_indices_[i])); + } +} + + +void EternalHandles::PostGarbageCollectionProcessing(Heap* heap) { + int last = 0; + for (int i = 0; i < new_space_indices_.length(); i++) { + int index = new_space_indices_[i]; + if (heap->InNewSpace(*GetLocation(index))) { + new_space_indices_[last++] = index; + } + } + new_space_indices_.Rewind(last); +} + + +int EternalHandles::Create(Isolate* isolate, Object* object) { + if (object == NULL) return kInvalidIndex; + ASSERT_NE(isolate->heap()->the_hole_value(), object); + int block = size_ >> kShift; + int offset = size_ & kMask; + // need to resize + if (offset == 0) { + Object** next_block = new Object*[kSize]; + Object* the_hole = isolate->heap()->the_hole_value(); + MemsetPointer(next_block, the_hole, kSize); + blocks_.Add(next_block); + } + ASSERT_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]); + blocks_[block][offset] = object; + if (isolate->heap()->InNewSpace(object)) { + new_space_indices_.Add(size_); + } + return size_++; +} + + } } // namespace v8::internal |