| Index: src/global-handles.cc
|
| diff --git a/src/global-handles.cc b/src/global-handles.cc
|
| index 88ebe31647dc954fa21f0f5deca99dbf2ccc819b..78db4e260124f06e6a7849171ebff0547b0cc3ba 100644
|
| --- a/src/global-handles.cc
|
| +++ b/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.
|
| @@ -93,13 +95,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 +112,6 @@ class GlobalHandles::Node {
|
| set_state(NORMAL);
|
| parameter_or_next_free_.parameter = NULL;
|
| weak_reference_callback_ = NULL;
|
| - IncreaseBlockUses();
|
| }
|
|
|
| void Release() {
|
| @@ -125,7 +125,7 @@ class GlobalHandles::Node {
|
| set_partially_dependent(false);
|
| weak_reference_callback_ = NULL;
|
| #endif
|
| - DecreaseBlockUses();
|
| + ReleaseFromBlock();
|
| }
|
|
|
| // Object slot accessors.
|
| @@ -204,10 +204,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 +272,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 +310,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());
|
| +}
|
| +
|
| +
|
| +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
|
|
|
| - 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) {
|
| +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::SortBlocks(bool shouldPrune) {
|
| +#ifdef DEBUG
|
| + VerifyBlockInvariants();
|
| +#endif
|
| + BlockList::SortBlocks(this, shouldPrune);
|
| +#ifdef DEBUG
|
| + VerifyBlockInvariants();
|
| +#endif
|
| +}
|
| +
|
| +
|
| +GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
|
| + return FindBlock()->global_handles();
|
| }
|
|
|
|
|
| -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_++;
|
| +GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
|
| + return NodeBlock::From(this, index_);
|
| }
|
|
|
|
|
| -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_--;
|
| +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 +897,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 +945,8 @@ bool GlobalHandles::PostGarbageCollectionProcessing(
|
| }
|
| }
|
| new_space_nodes_.Rewind(last);
|
| + bool shouldPruneBlocks = collector != SCAVENGER;
|
| + SortBlocks(shouldPruneBlocks);
|
| return next_gc_likely_to_collect_more;
|
| }
|
|
|
| @@ -765,48 +1014,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);
|
| }
|
|
|
|
|