Upgrade to 3.29
Update V8 to 3.29.88.17 and update makefiles to support building on
all the relevant platforms.
Bug: 17370214
Change-Id: Ia3407c157fd8d72a93e23d8318ccaf6ecf77fa4e
diff --git a/src/global-handles.cc b/src/global-handles.cc
index 9c0ad45..282ca2d 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -1,43 +1,26 @@
// Copyright 2009 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
-#include "v8.h"
+#include "src/v8.h"
-#include "api.h"
-#include "global-handles.h"
+#include "src/api.h"
+#include "src/global-handles.h"
-#include "vm-state-inl.h"
+#include "src/vm-state-inl.h"
namespace v8 {
namespace internal {
ObjectGroup::~ObjectGroup() {
- if (info_ != NULL) info_->Dispose();
+ if (info != NULL) info->Dispose();
+ delete[] objects;
+}
+
+
+ImplicitRefGroup::~ImplicitRefGroup() {
+ delete[] children;
}
@@ -46,7 +29,7 @@
// State transition diagram:
// FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
enum State {
- FREE,
+ FREE = 0,
NORMAL, // Normal global handle.
WEAK, // Flagged as weak but not yet finalized.
PENDING, // Has been recognized as only reachable by weak handles.
@@ -55,58 +38,70 @@
// Maps handle location (slot) to the containing node.
static Node* FromLocation(Object** location) {
- ASSERT(OFFSET_OF(Node, object_) == 0);
+ DCHECK(OFFSET_OF(Node, object_) == 0);
return reinterpret_cast<Node*>(location);
}
- Node() {}
+ Node() {
+ DCHECK(OFFSET_OF(Node, class_id_) == Internals::kNodeClassIdOffset);
+ DCHECK(OFFSET_OF(Node, flags_) == Internals::kNodeFlagsOffset);
+ 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);
+ STATIC_ASSERT(static_cast<int>(IsPartiallyDependent::kShift) ==
+ Internals::kNodeIsPartiallyDependentShift);
+ }
-#ifdef DEBUG
+#ifdef ENABLE_HANDLE_ZAPPING
~Node() {
// TODO(1428): if it's a weak handle we should have invoked its callback.
// Zap the values for eager trapping.
- object_ = NULL;
+ object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
index_ = 0;
- independent_ = false;
- in_new_space_list_ = false;
+ set_independent(false);
+ set_partially_dependent(false);
+ set_in_new_space_list(false);
parameter_or_next_free_.next_free = NULL;
- callback_ = NULL;
+ weak_callback_ = NULL;
}
#endif
void Initialize(int index, Node** first_free) {
index_ = static_cast<uint8_t>(index);
- ASSERT(static_cast<int>(index_) == index);
- state_ = FREE;
- in_new_space_list_ = false;
+ DCHECK(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;
}
- void Acquire(Object* object, GlobalHandles* global_handles) {
- ASSERT(state_ == FREE);
+ void Acquire(Object* object) {
+ DCHECK(state() == FREE);
object_ = object;
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
- independent_ = false;
- state_ = NORMAL;
+ set_independent(false);
+ set_partially_dependent(false);
+ set_state(NORMAL);
parameter_or_next_free_.parameter = NULL;
- callback_ = NULL;
- IncreaseBlockUses(global_handles);
+ weak_callback_ = NULL;
+ IncreaseBlockUses();
}
- void Release(GlobalHandles* global_handles) {
- ASSERT(state_ != FREE);
- if (IsWeakRetainer()) {
- global_handles->number_of_weak_handles_--;
- if (object_->IsJSGlobalObject()) {
- global_handles->number_of_global_object_weak_handles_--;
- }
- }
- state_ = FREE;
- parameter_or_next_free_.next_free = global_handles->first_free_;
- global_handles->first_free_ = this;
- DecreaseBlockUses(global_handles);
+ void Release() {
+ DCHECK(state() != FREE);
+ set_state(FREE);
+ // Zap the values for eager trapping.
+ object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
+ class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
+ set_independent(false);
+ set_partially_dependent(false);
+ weak_callback_ = NULL;
+ DecreaseBlockUses();
}
// Object slot accessors.
@@ -118,130 +113,154 @@
bool has_wrapper_class_id() const {
return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
}
+
uint16_t wrapper_class_id() const { return class_id_; }
- void set_wrapper_class_id(uint16_t class_id) {
- class_id_ = class_id;
+
+ // State and flag accessors.
+
+ State state() const {
+ return NodeState::decode(flags_);
+ }
+ void set_state(State state) {
+ flags_ = NodeState::update(flags_, state);
}
- // State accessors.
+ bool is_independent() {
+ return IsIndependent::decode(flags_);
+ }
+ void set_independent(bool v) {
+ flags_ = IsIndependent::update(flags_, v);
+ }
- State state() const { return state_; }
+ bool is_partially_dependent() {
+ return IsPartiallyDependent::decode(flags_);
+ }
+ void set_partially_dependent(bool v) {
+ flags_ = IsPartiallyDependent::update(flags_, v);
+ }
+
+ bool is_in_new_space_list() {
+ return IsInNewSpaceList::decode(flags_);
+ }
+ void set_in_new_space_list(bool v) {
+ flags_ = IsInNewSpaceList::update(flags_, v);
+ }
bool IsNearDeath() const {
// Check for PENDING to ensure correct answer when processing callbacks.
- return state_ == PENDING || state_ == NEAR_DEATH;
+ return state() == PENDING || state() == NEAR_DEATH;
}
- bool IsWeak() const { return state_ == WEAK; }
+ bool IsWeak() const { return state() == WEAK; }
- bool IsRetainer() const { return state_ != FREE; }
+ bool IsRetainer() const { return state() != FREE; }
- bool IsStrongRetainer() const { return state_ == NORMAL; }
+ bool IsStrongRetainer() const { return state() == NORMAL; }
bool IsWeakRetainer() const {
- return state_ == WEAK || state_ == PENDING || state_ == NEAR_DEATH;
+ return state() == WEAK || state() == PENDING || state() == NEAR_DEATH;
}
void MarkPending() {
- ASSERT(state_ == WEAK);
- state_ = PENDING;
+ DCHECK(state() == WEAK);
+ set_state(PENDING);
}
// Independent flag accessors.
void MarkIndependent() {
- ASSERT(state_ != FREE);
- independent_ = true;
+ DCHECK(state() != FREE);
+ set_independent(true);
}
- bool is_independent() const { return independent_; }
- // In-new-space-list flag accessors.
- void set_in_new_space_list(bool v) { in_new_space_list_ = v; }
- bool is_in_new_space_list() const { return in_new_space_list_; }
+ void MarkPartiallyDependent() {
+ DCHECK(state() != FREE);
+ if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) {
+ set_partially_dependent(true);
+ }
+ }
+ void clear_partially_dependent() { set_partially_dependent(false); }
// Callback accessor.
- WeakReferenceCallback callback() { return callback_; }
+ // TODO(svenpanne) Re-enable or nuke later.
+ // WeakReferenceCallback callback() { return callback_; }
// Callback parameter accessors.
void set_parameter(void* parameter) {
- ASSERT(state_ != FREE);
+ DCHECK(state() != FREE);
parameter_or_next_free_.parameter = parameter;
}
void* parameter() const {
- ASSERT(state_ != FREE);
+ DCHECK(state() != FREE);
return parameter_or_next_free_.parameter;
}
// Accessors for next free node in the free list.
Node* next_free() {
- ASSERT(state_ == FREE);
+ DCHECK(state() == FREE);
return parameter_or_next_free_.next_free;
}
void set_next_free(Node* value) {
- ASSERT(state_ == FREE);
+ DCHECK(state() == FREE);
parameter_or_next_free_.next_free = value;
}
- void MakeWeak(GlobalHandles* global_handles,
- void* parameter,
- WeakReferenceCallback callback) {
- ASSERT(state_ != FREE);
- if (!IsWeakRetainer()) {
- global_handles->number_of_weak_handles_++;
- if (object_->IsJSGlobalObject()) {
- global_handles->number_of_global_object_weak_handles_++;
- }
- }
- state_ = WEAK;
+ void MakeWeak(void* parameter, WeakCallback weak_callback) {
+ DCHECK(weak_callback != NULL);
+ DCHECK(state() != FREE);
+ CHECK(object_ != NULL);
+ set_state(WEAK);
set_parameter(parameter);
- callback_ = callback;
+ weak_callback_ = weak_callback;
}
- void ClearWeakness(GlobalHandles* global_handles) {
- ASSERT(state_ != FREE);
- if (IsWeakRetainer()) {
- global_handles->number_of_weak_handles_--;
- if (object_->IsJSGlobalObject()) {
- global_handles->number_of_global_object_weak_handles_--;
- }
- }
- state_ = NORMAL;
+ void* ClearWeakness() {
+ DCHECK(state() != FREE);
+ void* p = parameter();
+ set_state(NORMAL);
set_parameter(NULL);
+ return p;
}
- bool PostGarbageCollectionProcessing(Isolate* isolate,
- GlobalHandles* global_handles) {
- if (state_ != Node::PENDING) return false;
- WeakReferenceCallback func = callback();
- if (func == NULL) {
- Release(global_handles);
+ bool PostGarbageCollectionProcessing(Isolate* isolate) {
+ if (state() != Node::PENDING) return false;
+ if (weak_callback_ == NULL) {
+ Release();
return false;
}
void* par = parameter();
- state_ = NEAR_DEATH;
+ set_state(NEAR_DEATH);
set_parameter(NULL);
- v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
+ Object** object = location();
{
// Check that we are not passing a finalized external string to
// the callback.
- ASSERT(!object_->IsExternalAsciiString() ||
- ExternalAsciiString::cast(object_)->resource() != NULL);
- ASSERT(!object_->IsExternalTwoByteString() ||
+ DCHECK(!object_->IsExternalOneByteString() ||
+ ExternalOneByteString::cast(object_)->resource() != NULL);
+ DCHECK(!object_->IsExternalTwoByteString() ||
ExternalTwoByteString::cast(object_)->resource() != NULL);
// Leaving V8.
- VMState state(isolate, EXTERNAL);
- func(object, par);
+ VMState<EXTERNAL> state(isolate);
+ HandleScope handle_scope(isolate);
+ Handle<Object> handle(*object, isolate);
+ v8::WeakCallbackData<v8::Value, void> data(
+ reinterpret_cast<v8::Isolate*>(isolate),
+ v8::Utils::ToLocal(handle),
+ par);
+ weak_callback_(data);
}
// Absence of explicit cleanup or revival of weak handle
// in most of the cases would lead to memory leak.
- ASSERT(state_ != NEAR_DEATH);
+ CHECK(state() != NEAR_DEATH);
return true;
}
+ inline GlobalHandles* GetGlobalHandles();
+
private:
inline NodeBlock* FindBlock();
- inline void IncreaseBlockUses(GlobalHandles* global_handles);
- inline void DecreaseBlockUses(GlobalHandles* global_handles);
+ inline void IncreaseBlockUses();
+ inline void DecreaseBlockUses();
// Storage for object pointer.
// Placed first to avoid offset computation.
@@ -256,14 +275,17 @@
// Index in the containing handle block.
uint8_t index_;
- // Need one more bit for MSVC as it treats enums as signed.
- State state_ : 4;
+ // This stores three flags (independent, partially_dependent and
+ // in_new_space_list) and a State.
+ class NodeState: public BitField<State, 0, 4> {};
+ class IsIndependent: public BitField<bool, 4, 1> {};
+ class IsPartiallyDependent: public BitField<bool, 5, 1> {};
+ class IsInNewSpaceList: public BitField<bool, 6, 1> {};
- bool independent_ : 1;
- bool in_new_space_list_ : 1;
+ uint8_t flags_;
- // Handle specific callback.
- WeakReferenceCallback callback_;
+ // Handle specific callback - might be a weak reference in disguise.
+ WeakCallback weak_callback_;
// Provided data for callback. In FREE state, this is used for
// the free list link.
@@ -280,8 +302,12 @@
public:
static const int kSize = 256;
- explicit NodeBlock(NodeBlock* next)
- : next_(next), used_nodes_(0), next_used_(NULL), prev_used_(NULL) {}
+ 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) {
for (int i = kSize - 1; i >= 0; --i) {
@@ -290,15 +316,15 @@
}
Node* node_at(int index) {
- ASSERT(0 <= index && index < kSize);
+ DCHECK(0 <= index && index < kSize);
return &nodes_[index];
}
- void IncreaseUses(GlobalHandles* global_handles) {
- ASSERT(used_nodes_ < kSize);
+ void IncreaseUses() {
+ DCHECK(used_nodes_ < kSize);
if (used_nodes_++ == 0) {
- NodeBlock* old_first = global_handles->first_used_block_;
- global_handles->first_used_block_ = this;
+ 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;
@@ -306,17 +332,19 @@
}
}
- void DecreaseUses(GlobalHandles* global_handles) {
- ASSERT(used_nodes_ > 0);
+ void DecreaseUses() {
+ DCHECK(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_;
+ 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_; }
@@ -330,25 +358,41 @@
int used_nodes_;
NodeBlock* next_used_;
NodeBlock* prev_used_;
+ GlobalHandles* global_handles_;
};
+GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
+ return FindBlock()->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);
- ASSERT(block->node_at(index_) == this);
+ DCHECK(block->node_at(index_) == this);
return block;
}
-void GlobalHandles::Node::IncreaseBlockUses(GlobalHandles* global_handles) {
- FindBlock()->IncreaseUses(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_++;
}
-void GlobalHandles::Node::DecreaseBlockUses(GlobalHandles* global_handles) {
- FindBlock()->DecreaseUses(global_handles);
+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_--;
}
@@ -361,12 +405,12 @@
bool done() const { return block_ == NULL; }
Node* node() const {
- ASSERT(!done());
+ DCHECK(!done());
return block_->node_at(index_);
}
void Advance() {
- ASSERT(!done());
+ DCHECK(!done());
if (++index_ < NodeBlock::kSize) return;
index_ = 0;
block_ = block_->next_used();
@@ -382,13 +426,12 @@
GlobalHandles::GlobalHandles(Isolate* isolate)
: isolate_(isolate),
- number_of_weak_handles_(0),
- number_of_global_object_weak_handles_(0),
number_of_global_handles_(0),
first_block_(NULL),
first_used_block_(NULL),
first_free_(NULL),
- post_gc_processing_count_(0) {}
+ post_gc_processing_count_(0),
+ object_group_connections_(kObjectGroupConnectionsCapacity) {}
GlobalHandles::~GlobalHandles() {
@@ -403,17 +446,15 @@
Handle<Object> GlobalHandles::Create(Object* value) {
- isolate_->counters()->global_handles()->Increment();
- number_of_global_handles_++;
if (first_free_ == NULL) {
- first_block_ = new NodeBlock(first_block_);
+ first_block_ = new NodeBlock(this, first_block_);
first_block_->PutNodesOnFreeList(&first_free_);
}
- ASSERT(first_free_ != NULL);
+ DCHECK(first_free_ != NULL);
// Take the first node in the free list.
Node* result = first_free_;
first_free_ = result->next_free();
- result->Acquire(value, this);
+ result->Acquire(value);
if (isolate_->heap()->InNewSpace(value) &&
!result->is_in_new_space_list()) {
new_space_nodes_.Add(result);
@@ -423,23 +464,26 @@
}
+Handle<Object> GlobalHandles::CopyGlobal(Object** location) {
+ DCHECK(location != NULL);
+ return Node::FromLocation(location)->GetGlobalHandles()->Create(*location);
+}
+
+
void GlobalHandles::Destroy(Object** location) {
- isolate_->counters()->global_handles()->Decrement();
- number_of_global_handles_--;
- if (location == NULL) return;
- Node::FromLocation(location)->Release(this);
+ if (location != NULL) Node::FromLocation(location)->Release();
}
-void GlobalHandles::MakeWeak(Object** location, void* parameter,
- WeakReferenceCallback callback) {
- ASSERT(callback != NULL);
- Node::FromLocation(location)->MakeWeak(this, parameter, callback);
+void GlobalHandles::MakeWeak(Object** location,
+ void* parameter,
+ WeakCallback weak_callback) {
+ Node::FromLocation(location)->MakeWeak(parameter, weak_callback);
}
-void GlobalHandles::ClearWeakness(Object** location) {
- Node::FromLocation(location)->ClearWeakness(this);
+void* GlobalHandles::ClearWeakness(Object** location) {
+ return Node::FromLocation(location)->ClearWeakness();
}
@@ -448,6 +492,16 @@
}
+void GlobalHandles::MarkPartiallyDependent(Object** location) {
+ Node::FromLocation(location)->MarkPartiallyDependent();
+}
+
+
+bool GlobalHandles::IsIndependent(Object** location) {
+ return Node::FromLocation(location)->is_independent();
+}
+
+
bool GlobalHandles::IsNearDeath(Object** location) {
return Node::FromLocation(location)->IsNearDeath();
}
@@ -458,11 +512,6 @@
}
-void GlobalHandles::SetWrapperClassId(Object** location, uint16_t class_id) {
- Node::FromLocation(location)->set_wrapper_class_id(class_id);
-}
-
-
void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
for (NodeIterator it(this); !it.done(); it.Advance()) {
if (it.node()->IsWeakRetainer()) v->VisitPointer(it.node()->location());
@@ -470,16 +519,6 @@
}
-void GlobalHandles::IterateWeakRoots(WeakReferenceGuest f,
- WeakReferenceCallback callback) {
- for (NodeIterator it(this); !it.done(); it.Advance()) {
- if (it.node()->IsWeak() && it.node()->callback() == callback) {
- f(it.node()->object(), it.node()->parameter());
- }
- }
-}
-
-
void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
for (NodeIterator it(this); !it.done(); it.Advance()) {
if (it.node()->IsWeak() && f(it.node()->location())) {
@@ -493,8 +532,9 @@
for (int i = 0; i < new_space_nodes_.length(); ++i) {
Node* node = new_space_nodes_[i];
if (node->IsStrongRetainer() ||
- (node->IsWeakRetainer() && !node->is_independent())) {
- v->VisitPointer(node->location());
+ (node->IsWeakRetainer() && !node->is_independent() &&
+ !node->is_partially_dependent())) {
+ v->VisitPointer(node->location());
}
}
}
@@ -504,9 +544,9 @@
WeakSlotCallbackWithHeap f) {
for (int i = 0; i < new_space_nodes_.length(); ++i) {
Node* node = new_space_nodes_[i];
- ASSERT(node->is_in_new_space_list());
- if (node->is_independent() && node->IsWeak() &&
- f(isolate_->heap(), node->location())) {
+ DCHECK(node->is_in_new_space_list());
+ if ((node->is_independent() || node->is_partially_dependent()) &&
+ node->IsWeak() && f(isolate_->heap(), node->location())) {
node->MarkPending();
}
}
@@ -516,53 +556,114 @@
void GlobalHandles::IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v) {
for (int i = 0; i < new_space_nodes_.length(); ++i) {
Node* node = new_space_nodes_[i];
- ASSERT(node->is_in_new_space_list());
- if (node->is_independent() && node->IsWeakRetainer()) {
+ DCHECK(node->is_in_new_space_list());
+ if ((node->is_independent() || node->is_partially_dependent()) &&
+ node->IsWeakRetainer()) {
v->VisitPointer(node->location());
}
}
}
-bool GlobalHandles::PostGarbageCollectionProcessing(
+bool GlobalHandles::IterateObjectGroups(ObjectVisitor* v,
+ WeakSlotCallbackWithHeap can_skip) {
+ ComputeObjectGroupsAndImplicitReferences();
+ int last = 0;
+ bool any_group_was_visited = false;
+ for (int i = 0; i < object_groups_.length(); i++) {
+ ObjectGroup* entry = object_groups_.at(i);
+ DCHECK(entry != NULL);
+
+ Object*** objects = entry->objects;
+ bool group_should_be_visited = false;
+ for (size_t j = 0; j < entry->length; j++) {
+ Object* object = *objects[j];
+ if (object->IsHeapObject()) {
+ if (!can_skip(isolate_->heap(), &object)) {
+ group_should_be_visited = true;
+ break;
+ }
+ }
+ }
+
+ if (!group_should_be_visited) {
+ object_groups_[last++] = entry;
+ continue;
+ }
+
+ // An object in the group requires visiting, so iterate over all
+ // objects in the group.
+ for (size_t j = 0; j < entry->length; ++j) {
+ Object* object = *objects[j];
+ if (object->IsHeapObject()) {
+ v->VisitPointer(&object);
+ any_group_was_visited = true;
+ }
+ }
+
+ // Once the entire group has been iterated over, set the object
+ // group to NULL so it won't be processed again.
+ delete entry;
+ object_groups_.at(i) = NULL;
+ }
+ object_groups_.Rewind(last);
+ return any_group_was_visited;
+}
+
+
+int GlobalHandles::PostGarbageCollectionProcessing(
GarbageCollector collector) {
// Process weak global handle callbacks. This must be done after the
// GC is completely done, because the callbacks may invoke arbitrary
// API functions.
- ASSERT(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
+ DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
const int initial_post_gc_processing_count = ++post_gc_processing_count_;
- bool next_gc_likely_to_collect_more = false;
+ int freed_nodes = 0;
if (collector == SCAVENGER) {
for (int i = 0; i < new_space_nodes_.length(); ++i) {
Node* node = new_space_nodes_[i];
- ASSERT(node->is_in_new_space_list());
+ DCHECK(node->is_in_new_space_list());
+ if (!node->IsRetainer()) {
+ // Free nodes do not have weak callbacks. Do not use them to compute
+ // the freed_nodes.
+ continue;
+ }
// Skip dependent handles. Their weak callbacks might expect to be
// called between two global garbage collection callbacks which
// are not called for minor collections.
- if (!node->is_independent()) continue;
- if (node->PostGarbageCollectionProcessing(isolate_, this)) {
+ if (!node->is_independent() && !node->is_partially_dependent()) {
+ continue;
+ }
+ node->clear_partially_dependent();
+ if (node->PostGarbageCollectionProcessing(isolate_)) {
if (initial_post_gc_processing_count != post_gc_processing_count_) {
// Weak callback triggered another GC and another round of
// PostGarbageCollection processing. The current node might
// have been deleted in that round, so we need to bail out (or
// restart the processing).
- return next_gc_likely_to_collect_more;
+ return freed_nodes;
}
}
if (!node->IsRetainer()) {
- next_gc_likely_to_collect_more = true;
+ freed_nodes++;
}
}
} else {
for (NodeIterator it(this); !it.done(); it.Advance()) {
- if (it.node()->PostGarbageCollectionProcessing(isolate_, this)) {
+ if (!it.node()->IsRetainer()) {
+ // Free nodes do not have weak callbacks. Do not use them to compute
+ // the freed_nodes.
+ continue;
+ }
+ 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;
+ return freed_nodes;
}
}
if (!it.node()->IsRetainer()) {
- next_gc_likely_to_collect_more = true;
+ freed_nodes++;
}
}
}
@@ -570,15 +671,22 @@
int last = 0;
for (int i = 0; i < new_space_nodes_.length(); ++i) {
Node* node = new_space_nodes_[i];
- ASSERT(node->is_in_new_space_list());
- if (node->IsRetainer() && isolate_->heap()->InNewSpace(node->object())) {
- new_space_nodes_[last++] = node;
+ DCHECK(node->is_in_new_space_list());
+ if (node->IsRetainer()) {
+ if (isolate_->heap()->InNewSpace(node->object())) {
+ new_space_nodes_[last++] = node;
+ isolate_->heap()->IncrementNodesCopiedInNewSpace();
+ } else {
+ node->set_in_new_space_list(false);
+ isolate_->heap()->IncrementNodesPromoted();
+ }
} else {
node->set_in_new_space_list(false);
+ isolate_->heap()->IncrementNodesDiedInNewSpace();
}
}
new_space_nodes_.Rewind(last);
- return next_gc_likely_to_collect_more;
+ return freed_nodes;
}
@@ -602,7 +710,7 @@
void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
for (NodeIterator it(this); !it.done(); it.Advance()) {
- if (it.node()->has_wrapper_class_id() && it.node()->IsRetainer()) {
+ if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) {
v->VisitEmbedderReference(it.node()->location(),
it.node()->wrapper_class_id());
}
@@ -610,6 +718,40 @@
}
+void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v) {
+ for (int i = 0; i < new_space_nodes_.length(); ++i) {
+ Node* node = new_space_nodes_[i];
+ if (node->IsRetainer() && node->has_wrapper_class_id()) {
+ v->VisitEmbedderReference(node->location(),
+ node->wrapper_class_id());
+ }
+ }
+}
+
+
+int GlobalHandles::NumberOfWeakHandles() {
+ int count = 0;
+ for (NodeIterator it(this); !it.done(); it.Advance()) {
+ if (it.node()->IsWeakRetainer()) {
+ count++;
+ }
+ }
+ return count;
+}
+
+
+int GlobalHandles::NumberOfGlobalObjectWeakHandles() {
+ int count = 0;
+ for (NodeIterator it(this); !it.done(); it.Advance()) {
+ if (it.node()->IsWeakRetainer() &&
+ it.node()->object()->IsJSGlobalObject()) {
+ count++;
+ }
+ }
+ return count;
+}
+
+
void GlobalHandles::RecordStats(HeapStats* stats) {
*stats->global_handle_count = 0;
*stats->weak_global_handle_count = 0;
@@ -656,6 +798,7 @@
PrintF(" # total = %d\n", total);
}
+
void GlobalHandles::Print() {
PrintF("Global handles:\n");
for (NodeIterator it(this); !it.done(); it.Advance()) {
@@ -675,44 +818,65 @@
v8::RetainedObjectInfo* info) {
#ifdef DEBUG
for (size_t i = 0; i < length; ++i) {
- ASSERT(!Node::FromLocation(handles[i])->is_independent());
+ DCHECK(!Node::FromLocation(handles[i])->is_independent());
}
#endif
if (length == 0) {
if (info != NULL) info->Dispose();
return;
}
- object_groups_.Add(ObjectGroup::New(handles, length, info));
+ ObjectGroup* group = new ObjectGroup(length);
+ for (size_t i = 0; i < length; ++i)
+ group->objects[i] = handles[i];
+ group->info = info;
+ object_groups_.Add(group);
}
-void GlobalHandles::AddImplicitReferences(HeapObject** parent,
- Object*** children,
- size_t length) {
-#ifdef DEBUG
- ASSERT(!Node::FromLocation(BitCast<Object**>(parent))->is_independent());
- for (size_t i = 0; i < length; ++i) {
- ASSERT(!Node::FromLocation(children[i])->is_independent());
- }
-#endif
- if (length == 0) return;
- implicit_ref_groups_.Add(ImplicitRefGroup::New(parent, children, length));
+void GlobalHandles::SetObjectGroupId(Object** handle,
+ UniqueId id) {
+ object_group_connections_.Add(ObjectGroupConnection(id, handle));
+}
+
+
+void GlobalHandles::SetRetainedObjectInfo(UniqueId id,
+ RetainedObjectInfo* info) {
+ retainer_infos_.Add(ObjectGroupRetainerInfo(id, info));
+}
+
+
+void GlobalHandles::SetReferenceFromGroup(UniqueId id, Object** child) {
+ DCHECK(!Node::FromLocation(child)->is_independent());
+ implicit_ref_connections_.Add(ObjectGroupConnection(id, child));
+}
+
+
+void GlobalHandles::SetReference(HeapObject** parent, Object** child) {
+ DCHECK(!Node::FromLocation(child)->is_independent());
+ ImplicitRefGroup* group = new ImplicitRefGroup(parent, 1);
+ group->children[0] = child;
+ implicit_ref_groups_.Add(group);
}
void GlobalHandles::RemoveObjectGroups() {
- for (int i = 0; i < object_groups_.length(); i++) {
- object_groups_.at(i)->Dispose();
- }
+ for (int i = 0; i < object_groups_.length(); i++)
+ delete object_groups_.at(i);
object_groups_.Clear();
+ for (int i = 0; i < retainer_infos_.length(); ++i)
+ retainer_infos_[i].info->Dispose();
+ retainer_infos_.Clear();
+ object_group_connections_.Clear();
+ object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
}
void GlobalHandles::RemoveImplicitRefGroups() {
for (int i = 0; i < implicit_ref_groups_.length(); i++) {
- implicit_ref_groups_.at(i)->Dispose();
+ delete implicit_ref_groups_.at(i);
}
implicit_ref_groups_.Clear();
+ implicit_ref_connections_.Clear();
}
@@ -721,4 +885,172 @@
}
+void GlobalHandles::ComputeObjectGroupsAndImplicitReferences() {
+ if (object_group_connections_.length() == 0) {
+ for (int i = 0; i < retainer_infos_.length(); ++i)
+ retainer_infos_[i].info->Dispose();
+ retainer_infos_.Clear();
+ implicit_ref_connections_.Clear();
+ return;
+ }
+
+ object_group_connections_.Sort();
+ retainer_infos_.Sort();
+ implicit_ref_connections_.Sort();
+
+ int info_index = 0; // For iterating retainer_infos_.
+ UniqueId current_group_id(0);
+ int current_group_start = 0;
+
+ int current_implicit_refs_start = 0;
+ int current_implicit_refs_end = 0;
+ for (int i = 0; i <= object_group_connections_.length(); ++i) {
+ if (i == 0)
+ current_group_id = object_group_connections_[i].id;
+ if (i == object_group_connections_.length() ||
+ current_group_id != object_group_connections_[i].id) {
+ // Group detected: objects in indices [current_group_start, i[.
+
+ // Find out which implicit references are related to this group. (We want
+ // to ignore object groups which only have 1 object, but that object is
+ // needed as a representative object for the implicit refrerence group.)
+ while (current_implicit_refs_start < implicit_ref_connections_.length() &&
+ implicit_ref_connections_[current_implicit_refs_start].id <
+ current_group_id)
+ ++current_implicit_refs_start;
+ current_implicit_refs_end = current_implicit_refs_start;
+ while (current_implicit_refs_end < implicit_ref_connections_.length() &&
+ implicit_ref_connections_[current_implicit_refs_end].id ==
+ current_group_id)
+ ++current_implicit_refs_end;
+
+ if (current_implicit_refs_end > current_implicit_refs_start) {
+ // Find a representative object for the implicit references.
+ HeapObject** representative = NULL;
+ for (int j = current_group_start; j < i; ++j) {
+ Object** object = object_group_connections_[j].object;
+ if ((*object)->IsHeapObject()) {
+ representative = reinterpret_cast<HeapObject**>(object);
+ break;
+ }
+ }
+ if (representative) {
+ ImplicitRefGroup* group = new ImplicitRefGroup(
+ representative,
+ current_implicit_refs_end - current_implicit_refs_start);
+ for (int j = current_implicit_refs_start;
+ j < current_implicit_refs_end;
+ ++j) {
+ group->children[j - current_implicit_refs_start] =
+ implicit_ref_connections_[j].object;
+ }
+ implicit_ref_groups_.Add(group);
+ }
+ current_implicit_refs_start = current_implicit_refs_end;
+ }
+
+ // Find a RetainedObjectInfo for the group.
+ RetainedObjectInfo* info = NULL;
+ while (info_index < retainer_infos_.length() &&
+ retainer_infos_[info_index].id < current_group_id) {
+ retainer_infos_[info_index].info->Dispose();
+ ++info_index;
+ }
+ if (info_index < retainer_infos_.length() &&
+ retainer_infos_[info_index].id == current_group_id) {
+ // This object group has an associated ObjectGroupRetainerInfo.
+ info = retainer_infos_[info_index].info;
+ ++info_index;
+ }
+
+ // Ignore groups which only contain one object.
+ if (i > current_group_start + 1) {
+ ObjectGroup* group = new ObjectGroup(i - current_group_start);
+ for (int j = current_group_start; j < i; ++j) {
+ group->objects[j - current_group_start] =
+ object_group_connections_[j].object;
+ }
+ group->info = info;
+ object_groups_.Add(group);
+ } else if (info) {
+ info->Dispose();
+ }
+
+ if (i < object_group_connections_.length()) {
+ current_group_id = object_group_connections_[i].id;
+ current_group_start = i;
+ }
+ }
+ }
+ object_group_connections_.Clear();
+ object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
+ retainer_infos_.Clear();
+ implicit_ref_connections_.Clear();
+}
+
+
+EternalHandles::EternalHandles() : size_(0) {
+ for (unsigned i = 0; i < arraysize(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++) {
+ DCHECK(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);
+}
+
+
+void EternalHandles::Create(Isolate* isolate, Object* object, int* index) {
+ DCHECK_EQ(kInvalidIndex, *index);
+ if (object == NULL) return;
+ DCHECK_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);
+ }
+ DCHECK_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]);
+ blocks_[block][offset] = object;
+ if (isolate->heap()->InNewSpace(object)) {
+ new_space_indices_.Add(size_);
+ }
+ *index = size_++;
+}
+
+
} } // namespace v8::internal