[global-handles] Refactor to allow for different node type

- Introduce NodeSpace that holds allocation related logic.
- Provide std compatible iterator for node iteration.

This allows for creating a different internal node type.

The change is just a refactoring without functional changes.

Bug: chromium:923361
Change-Id: I424f821d96b3a82f64024aedff6c289d3eec11a2
Reviewed-on: https://chromium-review.googlesource.com/c/1418192
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58931}
This commit is contained in:
Michael Lippautz 2019-01-18 16:58:20 +01:00 committed by Commit Bot
parent 9026d67171
commit 489d2a1888
2 changed files with 310 additions and 244 deletions

View File

@ -5,6 +5,7 @@
#include "src/global-handles.h" #include "src/global-handles.h"
#include "src/api-inl.h" #include "src/api-inl.h"
#include "src/base/compiler-specific.h"
#include "src/cancelable-task.h" #include "src/cancelable-task.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/objects/slots.h" #include "src/objects/slots.h"
@ -16,7 +17,223 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class GlobalHandles::Node { namespace {
constexpr size_t kBlockSize = 256;
} // namespace
template <class _NodeType>
class GlobalHandles::NodeBlock final {
public:
using BlockType = NodeBlock<_NodeType>;
using NodeType = _NodeType;
V8_INLINE static NodeBlock* From(NodeType* node);
NodeBlock(GlobalHandles* global_handles,
GlobalHandles::NodeSpace<NodeType>* space,
NodeBlock* next) V8_NOEXCEPT : next_(next),
global_handles_(global_handles),
space_(space) {}
NodeType* at(size_t index) { return &nodes_[index]; }
const NodeType* at(size_t index) const { return &nodes_[index]; }
GlobalHandles::NodeSpace<NodeType>* space() const { return space_; }
GlobalHandles* global_handles() const { return global_handles_; }
V8_INLINE bool IncreaseUsage();
V8_INLINE bool DecreaseUsage();
V8_INLINE void ListAdd(NodeBlock** top);
V8_INLINE void ListRemove(NodeBlock** top);
NodeBlock* next() const { return next_; }
NodeBlock* next_used() const { return next_used_; }
private:
NodeType nodes_[kBlockSize];
NodeBlock* const next_;
GlobalHandles* const global_handles_;
GlobalHandles::NodeSpace<NodeType>* const space_;
NodeBlock* next_used_ = nullptr;
NodeBlock* prev_used_ = nullptr;
uint32_t used_nodes_ = 0;
DISALLOW_COPY_AND_ASSIGN(NodeBlock);
};
template <class NodeType>
GlobalHandles::NodeBlock<NodeType>* GlobalHandles::NodeBlock<NodeType>::From(
NodeType* node) {
uintptr_t ptr =
reinterpret_cast<uintptr_t>(node) - sizeof(NodeType) * node->index();
BlockType* block = reinterpret_cast<BlockType*>(ptr);
DCHECK_EQ(node, block->at(node->index()));
return block;
}
template <class NodeType>
bool GlobalHandles::NodeBlock<NodeType>::IncreaseUsage() {
DCHECK_LT(used_nodes_, kBlockSize);
return used_nodes_++ == 0;
}
template <class NodeType>
void GlobalHandles::NodeBlock<NodeType>::ListAdd(BlockType** top) {
BlockType* old_top = *top;
*top = this;
next_used_ = old_top;
prev_used_ = nullptr;
if (old_top != nullptr) {
old_top->prev_used_ = this;
}
}
template <class NodeType>
bool GlobalHandles::NodeBlock<NodeType>::DecreaseUsage() {
DCHECK_GT(used_nodes_, 0);
return --used_nodes_ == 0;
}
template <class NodeType>
void GlobalHandles::NodeBlock<NodeType>::ListRemove(BlockType** top) {
if (next_used_ != nullptr) next_used_->prev_used_ = prev_used_;
if (prev_used_ != nullptr) prev_used_->next_used_ = next_used_;
if (this == *top) {
*top = next_used_;
}
}
template <class BlockType>
class GlobalHandles::NodeIterator final {
public:
using NodeType = typename BlockType::NodeType;
// Iterator traits.
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = NodeType*;
using reference = value_type;
using pointer = value_type*;
explicit NodeIterator(BlockType* block) V8_NOEXCEPT : block_(block) {}
NodeIterator(NodeIterator&& other) V8_NOEXCEPT : block_(other.block_),
index_(other.index_) {}
bool operator==(const NodeIterator& other) const {
return block_ == other.block_;
}
bool operator!=(const NodeIterator& other) const {
return block_ != other.block_;
}
NodeIterator& operator++() {
if (++index_ < kBlockSize) return *this;
index_ = 0;
block_ = block_->next_used();
return *this;
}
NodeType* operator*() { return block_->at(index_); }
NodeType* operator->() { return block_->at(index_); }
private:
BlockType* block_ = nullptr;
size_t index_ = 0;
DISALLOW_COPY_AND_ASSIGN(NodeIterator);
};
template <class NodeType>
class GlobalHandles::NodeSpace final {
public:
using BlockType = NodeBlock<NodeType>;
using iterator = NodeIterator<BlockType>;
static NodeSpace* From(NodeType* node);
static void Release(NodeType* node);
explicit NodeSpace(GlobalHandles* global_handles) V8_NOEXCEPT
: global_handles_(global_handles) {}
~NodeSpace();
V8_INLINE NodeType* Acquire(Object object);
iterator begin() { return iterator(first_used_block_); }
iterator end() { return iterator(nullptr); }
private:
void PutNodesOnFreeList(BlockType* block);
V8_INLINE void Free(NodeType* node);
GlobalHandles* const global_handles_;
BlockType* first_block_ = nullptr;
BlockType* first_used_block_ = nullptr;
NodeType* first_free_ = nullptr;
};
template <class NodeType>
GlobalHandles::NodeSpace<NodeType>::~NodeSpace() {
auto* block = first_block_;
while (block != nullptr) {
auto* tmp = block->next();
delete block;
block = tmp;
}
}
template <class NodeType>
NodeType* GlobalHandles::NodeSpace<NodeType>::Acquire(Object object) {
if (first_free_ == nullptr) {
first_block_ = new BlockType(global_handles_, this, first_block_);
PutNodesOnFreeList(first_block_);
}
DCHECK_NOT_NULL(first_free_);
NodeType* node = first_free_;
first_free_ = first_free_->next_free();
node->Acquire(object);
BlockType* block = BlockType::From(node);
if (block->IncreaseUsage()) {
block->ListAdd(&first_used_block_);
}
global_handles_->isolate()->counters()->global_handles()->Increment();
global_handles_->number_of_global_handles_++;
DCHECK(node->IsInUse());
return node;
}
template <class NodeType>
void GlobalHandles::NodeSpace<NodeType>::PutNodesOnFreeList(BlockType* block) {
for (int32_t i = kBlockSize - 1; i >= 0; --i) {
NodeType* node = block->at(i);
const uint8_t index = static_cast<uint8_t>(i);
DCHECK_EQ(i, index);
node->set_index(index);
node->Free(first_free_);
first_free_ = node;
}
}
template <class NodeType>
void GlobalHandles::NodeSpace<NodeType>::Release(NodeType* node) {
BlockType* block = BlockType::From(node);
block->space()->Free(node);
}
template <class NodeType>
void GlobalHandles::NodeSpace<NodeType>::Free(NodeType* node) {
node->Release(first_free_);
first_free_ = node;
BlockType* block = BlockType::From(node);
if (block->DecreaseUsage()) {
block->ListRemove(&first_used_block_);
}
global_handles_->isolate()->counters()->global_handles()->Decrement();
global_handles_->number_of_global_handles_--;
}
class GlobalHandles::Node final {
public: public:
// State transition diagram: // State transition diagram:
// FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE } // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
@ -47,43 +264,36 @@ class GlobalHandles::Node {
Internals::kNodeIsIndependentShift); Internals::kNodeIsIndependentShift);
STATIC_ASSERT(static_cast<int>(IsActive::kShift) == STATIC_ASSERT(static_cast<int>(IsActive::kShift) ==
Internals::kNodeIsActiveShift); Internals::kNodeIsActiveShift);
set_in_new_space_list(false);
} }
#ifdef ENABLE_HANDLE_ZAPPING #ifdef ENABLE_HANDLE_ZAPPING
~Node() { ~Node() {
// TODO(1428): if it's a weak handle we should have invoked its callback. ClearFields();
// Zap the values for eager trapping.
object_ = kGlobalHandleZapValue;
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
index_ = 0;
set_independent(false);
set_active(false);
set_in_new_space_list(false);
data_.next_free = nullptr; data_.next_free = nullptr;
weak_callback_ = nullptr; index_ = 0;
} }
#endif #endif
void Initialize(int index, Node** first_free) { void Free(Node* free_list) {
object_ = kGlobalHandleZapValue; ClearFields();
index_ = static_cast<uint8_t>(index);
DCHECK(static_cast<int>(index_) == index);
set_state(FREE); set_state(FREE);
set_in_new_space_list(false); data_.next_free = free_list;
data_.next_free = *first_free;
*first_free = this;
} }
void Acquire(Object object) { void Acquire(Object object) {
DCHECK(state() == FREE); DCHECK(!IsInUse());
CheckFieldsAreCleared();
object_ = object.ptr(); object_ = object.ptr();
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
set_independent(false);
set_active(false);
set_state(NORMAL); set_state(NORMAL);
data_.parameter = nullptr; data_.parameter = nullptr;
weak_callback_ = nullptr; DCHECK(IsInUse());
IncreaseBlockUses(); }
void Release(Node* free_list) {
DCHECK(IsInUse());
Free(free_list);
DCHECK(!IsInUse());
} }
void Zap() { void Zap() {
@ -92,18 +302,6 @@ class GlobalHandles::Node {
object_ = kGlobalHandleZapValue; object_ = kGlobalHandleZapValue;
} }
void Release() {
DCHECK(IsInUse());
set_state(FREE);
// Zap the values for eager trapping.
object_ = kGlobalHandleZapValue;
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
set_independent(false);
set_active(false);
weak_callback_ = nullptr;
DecreaseBlockUses();
}
// Object slot accessors. // Object slot accessors.
Object object() const { return Object(object_); } Object object() const { return Object(object_); }
FullObjectSlot location() { return FullObjectSlot(&object_); } FullObjectSlot location() { return FullObjectSlot(&object_); }
@ -114,7 +312,6 @@ class GlobalHandles::Node {
bool has_wrapper_class_id() const { bool has_wrapper_class_id() const {
return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
} }
uint16_t wrapper_class_id() const { return class_id_; } uint16_t wrapper_class_id() const { return class_id_; }
// State and flag accessors. // State and flag accessors.
@ -205,13 +402,9 @@ class GlobalHandles::Node {
// Accessors for next free node in the free list. // Accessors for next free node in the free list.
Node* next_free() { Node* next_free() {
DCHECK(state() == FREE); DCHECK_EQ(FREE, state());
return data_.next_free; return data_.next_free;
} }
void set_next_free(Node* value) {
DCHECK(state() == FREE);
data_.next_free = value;
}
void MakeWeak(void* parameter, void MakeWeak(void* parameter,
WeakCallbackInfo<void>::Callback phantom_callback, WeakCallbackInfo<void>::Callback phantom_callback,
@ -294,14 +487,14 @@ class GlobalHandles::Node {
DCHECK_NULL(weak_callback_); DCHECK_NULL(weak_callback_);
Address** handle = reinterpret_cast<Address**>(parameter()); Address** handle = reinterpret_cast<Address**>(parameter());
*handle = nullptr; *handle = nullptr;
Release(); NodeSpace<Node>::Release(this);
} }
bool PostGarbageCollectionProcessing(Isolate* isolate) { bool PostGarbageCollectionProcessing(Isolate* isolate) {
// Handles only weak handles (not phantom) that are dying. // Handles only weak handles (not phantom) that are dying.
if (state() != Node::PENDING) return false; if (state() != Node::PENDING) return false;
if (weak_callback_ == nullptr) { if (weak_callback_ == nullptr) {
Release(); NodeSpace<Node>::Release(this);
return false; return false;
} }
set_state(NEAR_DEATH); set_state(NEAR_DEATH);
@ -333,16 +526,34 @@ class GlobalHandles::Node {
inline GlobalHandles* GetGlobalHandles(); inline GlobalHandles* GetGlobalHandles();
uint8_t index() const { return index_; }
void set_index(uint8_t value) { index_ = value; }
private: private:
inline NodeBlock* FindBlock(); // Fields that are not used for managing node memory.
inline void IncreaseBlockUses(); void ClearFields() {
inline void DecreaseBlockUses(); // Zap the values for eager trapping.
object_ = kGlobalHandleZapValue;
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
set_independent(false);
set_active(false);
weak_callback_ = nullptr;
}
void CheckFieldsAreCleared() {
DCHECK_EQ(kGlobalHandleZapValue, object_);
DCHECK_EQ(v8::HeapProfiler::kPersistentHandleNoClassId, class_id_);
DCHECK(!is_independent());
DCHECK(!is_active());
DCHECK_EQ(nullptr, weak_callback_);
}
// Storage for object pointer. // Storage for object pointer.
// Placed first to avoid offset computation. //
// The stored data is equivalent to an Object. It is stored as a plain // Placed first to avoid offset computation. The stored data is equivalent to
// Address for convenience (smallest number of casts), and because it is a // an Object. It is stored as a plain Address for convenience (smallest number
// private implementation detail: the public interface provides type safety. // of casts), and because it is a private implementation detail: the public
// interface provides type safety.
Address object_; Address object_;
// Next word stores class_id, index, state, and independent. // Next word stores class_id, index, state, and independent.
@ -381,161 +592,21 @@ class GlobalHandles::Node {
DISALLOW_COPY_AND_ASSIGN(Node); DISALLOW_COPY_AND_ASSIGN(Node);
}; };
class GlobalHandles::NodeBlock {
public:
static const int kSize = 256;
explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next)
: next_(next),
used_nodes_(0),
next_used_(nullptr),
prev_used_(nullptr),
global_handles_(global_handles) {}
void PutNodesOnFreeList(Node** first_free) {
for (int i = kSize - 1; i >= 0; --i) {
nodes_[i].Initialize(i, first_free);
}
}
Node* node_at(int index) {
DCHECK(0 <= index && index < kSize);
return &nodes_[index];
}
void IncreaseUses() {
DCHECK_LT(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_ = nullptr;
if (old_first == nullptr) return;
old_first->prev_used_ = this;
}
}
void DecreaseUses() {
DCHECK_GT(used_nodes_, 0);
if (--used_nodes_ == 0) {
if (next_used_ != nullptr) next_used_->prev_used_ = prev_used_;
if (prev_used_ != nullptr) prev_used_->next_used_ = next_used_;
if (this == global_handles_->first_used_block_) {
global_handles_->first_used_block_ = next_used_;
}
}
}
GlobalHandles* global_handles() { return global_handles_; }
// Next block in the list of all blocks.
NodeBlock* next() const { return next_; }
// 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_; }
private:
Node nodes_[kSize];
NodeBlock* const next_;
int used_nodes_;
NodeBlock* next_used_;
NodeBlock* prev_used_;
GlobalHandles* global_handles_;
};
GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
return FindBlock()->global_handles(); return NodeBlock<Node>::From(this)->global_handles();
} }
GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
intptr_t ptr = reinterpret_cast<intptr_t>(this);
ptr = ptr - index_ * sizeof(Node);
NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
DCHECK(block->node_at(index_) == this);
return block;
}
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::Node::DecreaseBlockUses() {
NodeBlock* node_block = FindBlock();
GlobalHandles* global_handles = node_block->global_handles();
data_.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_--;
}
class GlobalHandles::NodeIterator {
public:
explicit NodeIterator(GlobalHandles* global_handles)
: block_(global_handles->first_used_block_),
index_(0) {}
bool done() const { return block_ == nullptr; }
Node* node() const {
DCHECK(!done());
return block_->node_at(index_);
}
void Advance() {
DCHECK(!done());
if (++index_ < NodeBlock::kSize) return;
index_ = 0;
block_ = block_->next_used();
}
private:
NodeBlock* block_;
int index_;
DISALLOW_COPY_AND_ASSIGN(NodeIterator);
};
GlobalHandles::GlobalHandles(Isolate* isolate) GlobalHandles::GlobalHandles(Isolate* isolate)
: isolate_(isolate), : isolate_(isolate),
first_block_(nullptr), regular_nodes_(new NodeSpace<GlobalHandles::Node>(this)),
first_used_block_(nullptr),
first_free_(nullptr),
number_of_global_handles_(0), number_of_global_handles_(0),
post_gc_processing_count_(0), post_gc_processing_count_(0),
number_of_phantom_handle_resets_(0) {} number_of_phantom_handle_resets_(0) {}
GlobalHandles::~GlobalHandles() { GlobalHandles::~GlobalHandles() { regular_nodes_.reset(nullptr); }
NodeBlock* block = first_block_;
while (block != nullptr) {
NodeBlock* tmp = block->next();
delete block;
block = tmp;
}
first_block_ = nullptr;
}
Handle<Object> GlobalHandles::Create(Object value) { Handle<Object> GlobalHandles::Create(Object value) {
if (first_free_ == nullptr) { GlobalHandles::Node* result = regular_nodes_->Acquire(value);
first_block_ = new NodeBlock(this, first_block_);
first_block_->PutNodesOnFreeList(&first_free_);
}
DCHECK_NOT_NULL(first_free_);
// Take the first node in the free list.
Node* result = first_free_;
first_free_ = result->next_free();
result->Acquire(value);
if (Heap::InNewSpace(value) && !result->is_in_new_space_list()) { if (Heap::InNewSpace(value) && !result->is_in_new_space_list()) {
new_space_nodes_.push_back(result); new_space_nodes_.push_back(result);
result->set_in_new_space_list(true); result->set_in_new_space_list(true);
@ -560,7 +631,9 @@ Handle<Object> GlobalHandles::CopyGlobal(Address* location) {
} }
void GlobalHandles::Destroy(Address* location) { void GlobalHandles::Destroy(Address* location) {
if (location != nullptr) Node::FromLocation(location)->Release(); if (location != nullptr) {
NodeSpace<Node>::Release(Node::FromLocation(location));
}
} }
typedef v8::WeakCallbackInfo<void>::Callback GenericCallback; typedef v8::WeakCallbackInfo<void>::Callback GenericCallback;
@ -595,8 +668,7 @@ bool GlobalHandles::IsWeak(Address* location) {
DISABLE_CFI_PERF DISABLE_CFI_PERF
void GlobalHandles::IterateWeakRootsForFinalizers(RootVisitor* v) { void GlobalHandles::IterateWeakRootsForFinalizers(RootVisitor* v) {
for (NodeIterator it(this); !it.done(); it.Advance()) { for (Node* node : *regular_nodes_) {
Node* node = it.node();
if (node->IsWeakRetainer() && node->state() == Node::PENDING) { if (node->IsWeakRetainer() && node->state() == Node::PENDING) {
DCHECK(!node->IsPhantomCallback()); DCHECK(!node->IsPhantomCallback());
DCHECK(!node->IsPhantomResetHandle()); DCHECK(!node->IsPhantomResetHandle());
@ -610,8 +682,7 @@ void GlobalHandles::IterateWeakRootsForFinalizers(RootVisitor* v) {
DISABLE_CFI_PERF DISABLE_CFI_PERF
void GlobalHandles::IterateWeakRootsForPhantomHandles( void GlobalHandles::IterateWeakRootsForPhantomHandles(
WeakSlotCallbackWithHeap should_reset_handle) { WeakSlotCallbackWithHeap should_reset_handle) {
for (NodeIterator it(this); !it.done(); it.Advance()) { for (Node* node : *regular_nodes_) {
Node* node = it.node();
if (node->IsWeakRetainer() && if (node->IsWeakRetainer() &&
should_reset_handle(isolate()->heap(), node->location())) { should_reset_handle(isolate()->heap(), node->location())) {
if (node->IsPhantomResetHandle()) { if (node->IsPhantomResetHandle()) {
@ -628,8 +699,7 @@ void GlobalHandles::IterateWeakRootsForPhantomHandles(
void GlobalHandles::IdentifyWeakHandles( void GlobalHandles::IdentifyWeakHandles(
WeakSlotCallbackWithHeap should_reset_handle) { WeakSlotCallbackWithHeap should_reset_handle) {
for (NodeIterator it(this); !it.done(); it.Advance()) { for (Node* node : *regular_nodes_) {
Node* node = it.node();
if (node->IsWeak() && if (node->IsWeak() &&
should_reset_handle(isolate()->heap(), node->location())) { should_reset_handle(isolate()->heap(), node->location())) {
if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) { if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) {
@ -792,20 +862,20 @@ int GlobalHandles::PostScavengeProcessing(
int GlobalHandles::PostMarkSweepProcessing( int GlobalHandles::PostMarkSweepProcessing(
const int initial_post_gc_processing_count) { const int initial_post_gc_processing_count) {
int freed_nodes = 0; int freed_nodes = 0;
for (NodeIterator it(this); !it.done(); it.Advance()) { for (Node* node : *regular_nodes_) {
if (!it.node()->IsRetainer()) { if (!node->IsRetainer()) {
// Free nodes do not have weak callbacks. Do not use them to compute // Free nodes do not have weak callbacks. Do not use them to compute
// the freed_nodes. // the freed_nodes.
continue; continue;
} }
it.node()->set_active(false); node->set_active(false);
if (it.node()->PostGarbageCollectionProcessing(isolate_)) { if (node->PostGarbageCollectionProcessing(isolate_)) {
if (initial_post_gc_processing_count != post_gc_processing_count_) { if (initial_post_gc_processing_count != post_gc_processing_count_) {
// See the comment above. // See the comment above.
return freed_nodes; return freed_nodes;
} }
} }
if (!it.node()->IsRetainer()) { if (!node->IsRetainer()) {
freed_nodes++; freed_nodes++;
} }
} }
@ -930,29 +1000,29 @@ int GlobalHandles::PostGarbageCollectionProcessing(
} }
void GlobalHandles::IterateStrongRoots(RootVisitor* v) { void GlobalHandles::IterateStrongRoots(RootVisitor* v) {
for (NodeIterator it(this); !it.done(); it.Advance()) { for (Node* node : *regular_nodes_) {
if (it.node()->IsStrongRetainer()) { if (node->IsStrongRetainer()) {
v->VisitRootPointer(Root::kGlobalHandles, it.node()->label(), v->VisitRootPointer(Root::kGlobalHandles, node->label(),
it.node()->location()); node->location());
} }
} }
} }
void GlobalHandles::IterateWeakRoots(RootVisitor* v) { void GlobalHandles::IterateWeakRoots(RootVisitor* v) {
for (NodeIterator it(this); !it.done(); it.Advance()) { for (Node* node : *regular_nodes_) {
if (it.node()->IsWeak()) { if (node->IsWeak()) {
v->VisitRootPointer(Root::kGlobalHandles, it.node()->label(), v->VisitRootPointer(Root::kGlobalHandles, node->label(),
it.node()->location()); node->location());
} }
} }
} }
DISABLE_CFI_PERF DISABLE_CFI_PERF
void GlobalHandles::IterateAllRoots(RootVisitor* v) { void GlobalHandles::IterateAllRoots(RootVisitor* v) {
for (NodeIterator it(this); !it.done(); it.Advance()) { for (Node* node : *regular_nodes_) {
if (it.node()->IsRetainer()) { if (node->IsRetainer()) {
v->VisitRootPointer(Root::kGlobalHandles, it.node()->label(), v->VisitRootPointer(Root::kGlobalHandles, node->label(),
it.node()->location()); node->location());
} }
} }
} }
@ -991,9 +1061,9 @@ void GlobalHandles::ApplyPersistentHandleVisitor(
DISABLE_CFI_PERF DISABLE_CFI_PERF
void GlobalHandles::IterateAllRootsWithClassIds( void GlobalHandles::IterateAllRootsWithClassIds(
v8::PersistentHandleVisitor* visitor) { v8::PersistentHandleVisitor* visitor) {
for (NodeIterator it(this); !it.done(); it.Advance()) { for (Node* node : *regular_nodes_) {
if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) { if (node->IsRetainer() && node->has_wrapper_class_id()) {
ApplyPersistentHandleVisitor(visitor, it.node()); ApplyPersistentHandleVisitor(visitor, node);
} }
} }
} }
@ -1026,15 +1096,15 @@ void GlobalHandles::RecordStats(HeapStats* stats) {
*stats->pending_global_handle_count = 0; *stats->pending_global_handle_count = 0;
*stats->near_death_global_handle_count = 0; *stats->near_death_global_handle_count = 0;
*stats->free_global_handle_count = 0; *stats->free_global_handle_count = 0;
for (NodeIterator it(this); !it.done(); it.Advance()) { for (Node* node : *regular_nodes_) {
*stats->global_handle_count += 1; *stats->global_handle_count += 1;
if (it.node()->state() == Node::WEAK) { if (node->state() == Node::WEAK) {
*stats->weak_global_handle_count += 1; *stats->weak_global_handle_count += 1;
} else if (it.node()->state() == Node::PENDING) { } else if (node->state() == Node::PENDING) {
*stats->pending_global_handle_count += 1; *stats->pending_global_handle_count += 1;
} else if (it.node()->state() == Node::NEAR_DEATH) { } else if (node->state() == Node::NEAR_DEATH) {
*stats->near_death_global_handle_count += 1; *stats->near_death_global_handle_count += 1;
} else if (it.node()->state() == Node::FREE) { } else if (node->state() == Node::FREE) {
*stats->free_global_handle_count += 1; *stats->free_global_handle_count += 1;
} }
} }
@ -1049,12 +1119,12 @@ void GlobalHandles::PrintStats() {
int near_death = 0; int near_death = 0;
int destroyed = 0; int destroyed = 0;
for (NodeIterator it(this); !it.done(); it.Advance()) { for (Node* node : *regular_nodes_) {
total++; total++;
if (it.node()->state() == Node::WEAK) weak++; if (node->state() == Node::WEAK) weak++;
if (it.node()->state() == Node::PENDING) pending++; if (node->state() == Node::PENDING) pending++;
if (it.node()->state() == Node::NEAR_DEATH) near_death++; if (node->state() == Node::NEAR_DEATH) near_death++;
if (it.node()->state() == Node::FREE) destroyed++; if (node->state() == Node::FREE) destroyed++;
} }
PrintF("Global Handle Statistics:\n"); PrintF("Global Handle Statistics:\n");
@ -1069,10 +1139,10 @@ void GlobalHandles::PrintStats() {
void GlobalHandles::Print() { void GlobalHandles::Print() {
PrintF("Global handles:\n"); PrintF("Global handles:\n");
for (NodeIterator it(this); !it.done(); it.Advance()) { for (Node* node : *regular_nodes_) {
PrintF(" handle %p to %p%s\n", it.node()->location().ToVoidPtr(), PrintF(" handle %p to %p%s\n", node->location().ToVoidPtr(),
reinterpret_cast<void*>(it.node()->object()->ptr()), reinterpret_cast<void*>(node->object()->ptr()),
it.node()->IsWeak() ? " (weak)" : ""); node->IsWeak() ? " (weak)" : "");
} }
} }

View File

@ -185,8 +185,12 @@ class GlobalHandles {
private: private:
// Internal node structures. // Internal node structures.
class Node; class Node;
template <class NodeType>
class NodeBlock; class NodeBlock;
template <class BlockType>
class NodeIterator; class NodeIterator;
template <class NodeType>
class NodeSpace;
class PendingPhantomCallback; class PendingPhantomCallback;
explicit GlobalHandles(Isolate* isolate); explicit GlobalHandles(Isolate* isolate);
@ -201,15 +205,7 @@ class GlobalHandles {
Isolate* isolate_; Isolate* isolate_;
// List of all allocated node blocks. std::unique_ptr<NodeSpace<Node>> regular_nodes_;
NodeBlock* first_block_;
// List of node blocks with used nodes.
NodeBlock* first_used_block_;
// Free list of nodes.
Node* first_free_;
// Contains all nodes holding new space objects. Note: when the list // Contains all nodes holding new space objects. Note: when the list
// is accessed, some of the objects may have been promoted already. // is accessed, some of the objects may have been promoted already.
std::vector<Node*> new_space_nodes_; std::vector<Node*> new_space_nodes_;