Revision: 7521
Author: [email protected]
Date: Wed Apr 6 12:17:54 2011
Log: Make object groups and implicit references a bit more lightweight.
We can only call malloc/free once per group and we can avoid scanning
through a list of NULLs if we keep unprocessed groups in the beginning.
I also changed the internal representation of implicit references to
hold a handle to the parent (instead of a direct pointer). The
prologue callback must not trigger a GC, but it's better to be safe.
Review URL: http://codereview.chromium.org/6800003
http://code.google.com/p/v8/source/detail?r=7521
Modified:
/branches/bleeding_edge/src/api.cc
/branches/bleeding_edge/src/global-handles.cc
/branches/bleeding_edge/src/global-handles.h
/branches/bleeding_edge/src/mark-compact.cc
/branches/bleeding_edge/src/profile-generator.cc
/branches/bleeding_edge/src/v8utils.h
/branches/bleeding_edge/test/cctest/test-mark-compact.cc
=======================================
--- /branches/bleeding_edge/src/api.cc Fri Apr 1 05:17:20 2011
+++ /branches/bleeding_edge/src/api.cc Wed Apr 6 12:17:54 2011
@@ -4473,7 +4473,7 @@
if (IsDeadCheck(isolate, "v8::V8::AddImplicitReferences()")) return;
STATIC_ASSERT(sizeof(Persistent<Value>) == sizeof(i::Object**));
isolate->global_handles()->AddImplicitReferences(
- *Utils::OpenHandle(*parent),
+
i::Handle<i::HeapObject>::cast(Utils::OpenHandle(*parent)).location(),
reinterpret_cast<i::Object***>(children), length);
}
=======================================
--- /branches/bleeding_edge/src/global-handles.cc Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/global-handles.cc Wed Apr 6 12:17:54 2011
@@ -558,28 +558,25 @@
void GlobalHandles::AddObjectGroup(Object*** handles,
size_t length,
v8::RetainedObjectInfo* info) {
- ObjectGroup* new_entry = new ObjectGroup(length, info);
- for (size_t i = 0; i < length; ++i) {
- new_entry->objects_.Add(handles[i]);
- }
- object_groups_.Add(new_entry);
+ if (length == 0) {
+ if (info != NULL) info->Dispose();
+ return;
+ }
+ object_groups_.Add(ObjectGroup::New(handles, length, info));
}
-void GlobalHandles::AddImplicitReferences(HeapObject* parent,
+void GlobalHandles::AddImplicitReferences(HeapObject** parent,
Object*** children,
size_t length) {
- ImplicitRefGroup* new_entry = new ImplicitRefGroup(parent, length);
- for (size_t i = 0; i < length; ++i) {
- new_entry->children_.Add(children[i]);
- }
- implicit_ref_groups_.Add(new_entry);
+ if (length == 0) return;
+ implicit_ref_groups_.Add(ImplicitRefGroup::New(parent, children,
length));
}
void GlobalHandles::RemoveObjectGroups() {
for (int i = 0; i < object_groups_.length(); i++) {
- delete object_groups_.at(i);
+ object_groups_.at(i)->Dispose();
}
object_groups_.Clear();
}
@@ -587,7 +584,7 @@
void GlobalHandles::RemoveImplicitRefGroups() {
for (int i = 0; i < implicit_ref_groups_.length(); i++) {
- delete implicit_ref_groups_.at(i);
+ implicit_ref_groups_.at(i)->Dispose();
}
implicit_ref_groups_.Clear();
}
=======================================
--- /branches/bleeding_edge/src/global-handles.h Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/global-handles.h Wed Apr 6 12:17:54 2011
@@ -42,37 +42,66 @@
// An object group is treated like a single JS object: if one of object in
// the group is alive, all objects in the same group are considered alive.
// An object group is used to simulate object relationship in a DOM tree.
-class ObjectGroup : public Malloced {
+class ObjectGroup {
public:
- ObjectGroup() : objects_(4) {}
- ObjectGroup(size_t capacity, v8::RetainedObjectInfo* info)
- : objects_(static_cast<int>(capacity)),
- info_(info) { }
- ~ObjectGroup();
-
- List<Object**> objects_;
+ static ObjectGroup* New(Object*** handles,
+ size_t length,
+ v8::RetainedObjectInfo* info) {
+ ASSERT(length > 0);
+ ObjectGroup* group = reinterpret_cast<ObjectGroup*>(
+ malloc(OFFSET_OF(ObjectGroup, objects_[length])));
+ group->length_ = length;
+ group->info_ = info;
+ CopyWords(group->objects_, handles, length);
+ return group;
+ }
+
+ void Dispose() {
+ free(this);
+ }
+
+ size_t length_;
v8::RetainedObjectInfo* info_;
+ Object** objects_[1]; // Variable sized array.
private:
- DISALLOW_COPY_AND_ASSIGN(ObjectGroup);
+ void* operator new(size_t size);
+ void operator delete(void* p);
+ ~ObjectGroup();
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ObjectGroup);
};
// An implicit references group consists of two parts: a parent object and
// a list of children objects. If the parent is alive, all the children
// are alive too.
-class ImplicitRefGroup : public Malloced {
+class ImplicitRefGroup {
public:
- ImplicitRefGroup() : children_(4) {}
- ImplicitRefGroup(HeapObject* parent, size_t capacity)
- : parent_(parent),
- children_(static_cast<int>(capacity)) { }
-
- HeapObject* parent_;
- List<Object**> children_;
+ static ImplicitRefGroup* New(HeapObject** parent,
+ Object*** children,
+ size_t length) {
+ ASSERT(length > 0);
+ ImplicitRefGroup* group = reinterpret_cast<ImplicitRefGroup*>(
+ malloc(OFFSET_OF(ImplicitRefGroup, children_[length])));
+ group->parent_ = parent;
+ group->length_ = length;
+ CopyWords(group->children_, children, length);
+ return group;
+ }
+
+ void Dispose() {
+ free(this);
+ }
+
+ HeapObject** parent_;
+ size_t length_;
+ Object** children_[1]; // Variable sized array.
private:
- DISALLOW_COPY_AND_ASSIGN(ImplicitRefGroup);
+ void* operator new(size_t size);
+ void operator delete(void* p);
+ ~ImplicitRefGroup();
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ImplicitRefGroup);
};
@@ -154,7 +183,7 @@
// Add an implicit references' group.
// Should be only used in GC callback function before a collection.
// All groups are destroyed after a mark-compact collection.
- void AddImplicitReferences(HeapObject* parent,
+ void AddImplicitReferences(HeapObject** parent,
Object*** children,
size_t length);
=======================================
--- /branches/bleeding_edge/src/mark-compact.cc Tue Apr 5 02:01:47 2011
+++ /branches/bleeding_edge/src/mark-compact.cc Wed Apr 6 12:17:54 2011
@@ -1217,13 +1217,14 @@
List<ObjectGroup*>* object_groups =
heap()->isolate()->global_handles()->object_groups();
+ int last = 0;
for (int i = 0; i < object_groups->length(); i++) {
ObjectGroup* entry = object_groups->at(i);
- if (entry == NULL) continue;
-
- List<Object**>& objects = entry->objects_;
+ ASSERT(entry != NULL);
+
+ Object*** objects = entry->objects_;
bool group_marked = false;
- for (int j = 0; j < objects.length(); j++) {
+ for (size_t j = 0; j < entry->length_; j++) {
Object* object = *objects[j];
if (object->IsHeapObject() && HeapObject::cast(object)->IsMarked()) {
group_marked = true;
@@ -1231,21 +1232,24 @@
}
}
- if (!group_marked) continue;
-
- // An object in the group is marked, so mark as gray all white heap
- // objects in the group.
- for (int j = 0; j < objects.length(); ++j) {
+ if (!group_marked) {
+ (*object_groups)[last++] = entry;
+ continue;
+ }
+
+ // An object in the group is marked, so mark all heap objects in
+ // the group.
+ for (size_t j = 0; j < entry->length_; ++j) {
if ((*objects[j])->IsHeapObject()) {
MarkObject(HeapObject::cast(*objects[j]));
}
}
- // Once the entire group has been colored gray, set the object group
- // to NULL so it won't be processed again.
- delete entry;
- object_groups->at(i) = NULL;
- }
+ // Once the entire group has been marked, dispose it because it's
+ // not needed anymore.
+ entry->Dispose();
+ }
+ object_groups->Rewind(last);
}
@@ -1253,26 +1257,29 @@
List<ImplicitRefGroup*>* ref_groups =
heap()->isolate()->global_handles()->implicit_ref_groups();
+ int last = 0;
for (int i = 0; i < ref_groups->length(); i++) {
ImplicitRefGroup* entry = ref_groups->at(i);
- if (entry == NULL) continue;
-
- if (!entry->parent_->IsMarked()) continue;
-
- List<Object**>& children = entry->children_;
- // A parent object is marked, so mark as gray all child white heap
- // objects.
- for (int j = 0; j < children.length(); ++j) {
+ ASSERT(entry != NULL);
+
+ if (!(*entry->parent_)->IsMarked()) {
+ (*ref_groups)[last++] = entry;
+ continue;
+ }
+
+ Object*** children = entry->children_;
+ // A parent object is marked, so mark all child heap objects.
+ for (size_t j = 0; j < entry->length_; ++j) {
if ((*children[j])->IsHeapObject()) {
MarkObject(HeapObject::cast(*children[j]));
}
}
- // Once the entire group has been colored gray, set the group
- // to NULL so it won't be processed again.
- delete entry;
- ref_groups->at(i) = NULL;
- }
+ // Once the entire group has been marked, dispose it because it's
+ // not needed anymore.
+ entry->Dispose();
+ }
+ ref_groups->Rewind(last);
}
=======================================
--- /branches/bleeding_edge/src/profile-generator.cc Wed Mar 30 07:04:50
2011
+++ /branches/bleeding_edge/src/profile-generator.cc Wed Apr 6 12:17:54
2011
@@ -2295,7 +2295,7 @@
ObjectGroup* group = groups->at(i);
if (group->info_ == NULL) continue;
List<HeapObject*>* list = GetListMaybeDisposeInfo(group->info_);
- for (int j = 0; j < group->objects_.length(); ++j) {
+ for (size_t j = 0; j < group->length_; ++j) {
HeapObject* obj = HeapObject::cast(*group->objects_[j]);
list->Add(obj);
in_groups_.Insert(obj);
=======================================
--- /branches/bleeding_edge/src/v8utils.h Wed Mar 30 07:04:26 2011
+++ /branches/bleeding_edge/src/v8utils.h Wed Apr 6 12:17:54 2011
@@ -120,7 +120,9 @@
// Memory
// Copies data from |src| to |dst|. The data spans MUST not overlap.
-inline void CopyWords(Object** dst, Object** src, int num_words) {
+template <typename T>
+inline void CopyWords(T* dst, T* src, int num_words) {
+ STATIC_ASSERT(sizeof(T) == kPointerSize);
ASSERT(Min(dst, src) + num_words <= Max(dst, src));
ASSERT(num_words > 0);
=======================================
--- /branches/bleeding_edge/test/cctest/test-mark-compact.cc Fri Mar 18
13:35:07 2011
+++ /branches/bleeding_edge/test/cctest/test-mark-compact.cc Wed Apr 6
12:17:54 2011
@@ -299,8 +299,8 @@
}
TEST(ObjectGroups) {
- GlobalHandles* global_handles = Isolate::Current()->global_handles();
InitializeVM();
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
NumberOfWeakCalls = 0;
v8::HandleScope handle_scope;
@@ -308,9 +308,9 @@
Handle<Object> g1s1 =
global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
Handle<Object> g1s2 =
- global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
+
global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
Handle<Object> g1c1 =
- global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
+
global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
global_handles->MakeWeak(g1s1.location(),
reinterpret_cast<void*>(1234),
&WeakPointerCallback);
@@ -349,11 +349,11 @@
Object** g2_objects[] = { g2s1.location(), g2s2.location() };
Object** g2_children[] = { g2c1.location() };
global_handles->AddObjectGroup(g1_objects, 2, NULL);
- global_handles->AddImplicitReferences(HeapObject::cast(*g1s1),
- g1_children, 1);
+ global_handles->AddImplicitReferences(
+ Handle<HeapObject>::cast(g1s1).location(), g1_children, 1);
global_handles->AddObjectGroup(g2_objects, 2, NULL);
- global_handles->AddImplicitReferences(HeapObject::cast(*g2s2),
- g2_children, 1);
+ global_handles->AddImplicitReferences(
+ Handle<HeapObject>::cast(g2s2).location(), g2_children, 1);
}
// Do a full GC
HEAP->CollectGarbage(OLD_POINTER_SPACE);
@@ -377,11 +377,11 @@
Object** g2_objects[] = { g2s1.location(), g2s2.location() };
Object** g2_children[] = { g2c1.location() };
global_handles->AddObjectGroup(g1_objects, 2, NULL);
- global_handles->AddImplicitReferences(HeapObject::cast(*g1s1),
- g1_children, 1);
+ global_handles->AddImplicitReferences(
+ Handle<HeapObject>::cast(g1s1).location(), g1_children, 1);
global_handles->AddObjectGroup(g2_objects, 2, NULL);
- global_handles->AddImplicitReferences(HeapObject::cast(*g2s2),
- g2_children, 1);
+ global_handles->AddImplicitReferences(
+ Handle<HeapObject>::cast(g2s2).location(), g2_children, 1);
}
HEAP->CollectGarbage(OLD_POINTER_SPACE);
@@ -400,3 +400,45 @@
HEAP->CollectGarbage(OLD_POINTER_SPACE);
CHECK_EQ(7, NumberOfWeakCalls);
}
+
+
+class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
+ public:
+ TestRetainedObjectInfo() : has_been_disposed_(false) {}
+
+ bool has_been_disposed() { return has_been_disposed_; }
+
+ virtual void Dispose() {
+ ASSERT(!has_been_disposed_);
+ has_been_disposed_ = true;
+ }
+
+ virtual bool IsEquivalent(v8::RetainedObjectInfo* other) {
+ return other == this;
+ }
+
+ virtual intptr_t GetHash() { return 0; }
+
+ virtual const char* GetLabel() { return "whatever"; }
+
+ private:
+ bool has_been_disposed_;
+};
+
+
+TEST(EmptyObjectGroups) {
+ InitializeVM();
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
+
+ v8::HandleScope handle_scope;
+
+ Handle<Object> object =
+
global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
+
+ TestRetainedObjectInfo info;
+ global_handles->AddObjectGroup(NULL, 0, &info);
+ ASSERT(info.has_been_disposed());
+
+ global_handles->AddImplicitReferences(
+ Handle<HeapObject>::cast(object).location(), NULL, 0);
+}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev