Introduce one way dependencies into object grouping.
Those are necessary to properly manage relationship between objects in cases when they don't form proper tree structure. Review URL: http://codereview.chromium.org/6686053 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7202 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
e181bd2b6f
commit
a7bb1d5278
11
include/v8.h
11
include/v8.h
@ -2717,6 +2717,17 @@ class V8EXPORT V8 {
|
||||
size_t length,
|
||||
RetainedObjectInfo* info = NULL);
|
||||
|
||||
/**
|
||||
* Allows the host application to declare implicit references between
|
||||
* the objects: if |parent| is alive, all |children| are alive too.
|
||||
* After each garbage collection, all implicit references
|
||||
* are removed. It is intended to be used in the before-garbage-collection
|
||||
* callback function.
|
||||
*/
|
||||
static void AddImplicitReferences(Persistent<Object> parent,
|
||||
Persistent<Value>* children,
|
||||
size_t length);
|
||||
|
||||
/**
|
||||
* Initializes from snapshot if possible. Otherwise, attempts to
|
||||
* initialize from scratch. This function is called implicitly if
|
||||
|
13
src/api.cc
13
src/api.cc
@ -4126,11 +4126,22 @@ void V8::AddObjectGroup(Persistent<Value>* objects,
|
||||
RetainedObjectInfo* info) {
|
||||
if (IsDeadCheck("v8::V8::AddObjectGroup()")) return;
|
||||
STATIC_ASSERT(sizeof(Persistent<Value>) == sizeof(i::Object**));
|
||||
i::GlobalHandles::AddGroup(
|
||||
i::GlobalHandles::AddObjectGroup(
|
||||
reinterpret_cast<i::Object***>(objects), length, info);
|
||||
}
|
||||
|
||||
|
||||
void V8::AddImplicitReferences(Persistent<Object> parent,
|
||||
Persistent<Value>* children,
|
||||
size_t length) {
|
||||
if (IsDeadCheck("v8::V8::AddImplicitReferences()")) return;
|
||||
STATIC_ASSERT(sizeof(Persistent<Value>) == sizeof(i::Object**));
|
||||
i::GlobalHandles::AddImplicitReferences(
|
||||
*Utils::OpenHandle(*parent),
|
||||
reinterpret_cast<i::Object***>(children), length);
|
||||
}
|
||||
|
||||
|
||||
int V8::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
|
||||
if (IsDeadCheck("v8::V8::AdjustAmountOfExternalAllocatedMemory()")) return 0;
|
||||
return i::Heap::AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
|
||||
|
@ -541,16 +541,36 @@ List<ObjectGroup*>* GlobalHandles::ObjectGroups() {
|
||||
return &groups;
|
||||
}
|
||||
|
||||
void GlobalHandles::AddGroup(Object*** handles,
|
||||
size_t length,
|
||||
v8::RetainedObjectInfo* info) {
|
||||
|
||||
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)
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
new_entry->objects_.Add(handles[i]);
|
||||
}
|
||||
ObjectGroups()->Add(new_entry);
|
||||
}
|
||||
|
||||
|
||||
List<ImplicitRefGroup*>* GlobalHandles::ImplicitRefGroups() {
|
||||
// Lazily initialize the list to avoid startup time static constructors.
|
||||
static List<ImplicitRefGroup*> groups(4);
|
||||
return &groups;
|
||||
}
|
||||
|
||||
|
||||
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]);
|
||||
}
|
||||
ImplicitRefGroups()->Add(new_entry);
|
||||
}
|
||||
|
||||
|
||||
void GlobalHandles::RemoveObjectGroups() {
|
||||
List<ObjectGroup*>* object_groups = ObjectGroups();
|
||||
for (int i = 0; i< object_groups->length(); i++) {
|
||||
@ -559,4 +579,14 @@ void GlobalHandles::RemoveObjectGroups() {
|
||||
object_groups->Clear();
|
||||
}
|
||||
|
||||
|
||||
void GlobalHandles::RemoveImplicitRefGroups() {
|
||||
List<ImplicitRefGroup*>* ref_groups = ImplicitRefGroups();
|
||||
for (int i = 0; i< ref_groups->length(); i++) {
|
||||
delete ref_groups->at(i);
|
||||
}
|
||||
ref_groups->Clear();
|
||||
}
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -39,9 +39,6 @@ namespace internal {
|
||||
// At GC the destroyed global handles are removed from the free list
|
||||
// and deallocated.
|
||||
|
||||
// Callback function on handling weak global handles.
|
||||
// typedef bool (*WeakSlotCallback)(Object** pointer);
|
||||
|
||||
// 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.
|
||||
@ -61,6 +58,24 @@ class ObjectGroup : public Malloced {
|
||||
};
|
||||
|
||||
|
||||
// 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 {
|
||||
public:
|
||||
ImplicitRefGroup() : children_(4) {}
|
||||
ImplicitRefGroup(HeapObject* parent, size_t capacity)
|
||||
: parent_(parent),
|
||||
children_(static_cast<int>(capacity)) { }
|
||||
|
||||
HeapObject* parent_;
|
||||
List<Object**> children_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(ImplicitRefGroup);
|
||||
};
|
||||
|
||||
|
||||
typedef void (*WeakReferenceGuest)(Object* object, void* parameter);
|
||||
|
||||
class GlobalHandles : public AllStatic {
|
||||
@ -128,17 +143,28 @@ class GlobalHandles : public AllStatic {
|
||||
static void IdentifyWeakHandles(WeakSlotCallback f);
|
||||
|
||||
// Add an object group.
|
||||
// Should only used in GC callback function before a collection.
|
||||
// Should be only used in GC callback function before a collection.
|
||||
// All groups are destroyed after a mark-compact collection.
|
||||
static void AddGroup(Object*** handles,
|
||||
size_t length,
|
||||
v8::RetainedObjectInfo* info);
|
||||
static void AddObjectGroup(Object*** handles,
|
||||
size_t length,
|
||||
v8::RetainedObjectInfo* info);
|
||||
|
||||
// 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.
|
||||
static void AddImplicitReferences(HeapObject* parent,
|
||||
Object*** children,
|
||||
size_t length);
|
||||
|
||||
// Returns the object groups.
|
||||
static List<ObjectGroup*>* ObjectGroups();
|
||||
|
||||
// Returns the implicit references' groups.
|
||||
static List<ImplicitRefGroup*>* ImplicitRefGroups();
|
||||
|
||||
// Remove bags, this should only happen after GC.
|
||||
static void RemoveObjectGroups();
|
||||
static void RemoveImplicitRefGroups();
|
||||
|
||||
// Tear down the global handle structure.
|
||||
static void TearDown();
|
||||
|
@ -1190,14 +1190,41 @@ void MarkCompactCollector::MarkObjectGroups() {
|
||||
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 object_groups->at(i);
|
||||
delete entry;
|
||||
object_groups->at(i) = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::MarkImplicitRefGroups() {
|
||||
List<ImplicitRefGroup*>* ref_groups = GlobalHandles::ImplicitRefGroups();
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Mark all objects reachable from the objects on the marking stack.
|
||||
// Before: the marking stack contains zero or more heap object pointers.
|
||||
// After: the marking stack is empty, and all objects reachable from the
|
||||
@ -1276,11 +1303,12 @@ void MarkCompactCollector::ProcessMarkingStack() {
|
||||
}
|
||||
|
||||
|
||||
void MarkCompactCollector::ProcessObjectGroups() {
|
||||
void MarkCompactCollector::ProcessExternalMarking() {
|
||||
bool work_to_do = true;
|
||||
ASSERT(marking_stack.is_empty());
|
||||
while (work_to_do) {
|
||||
MarkObjectGroups();
|
||||
MarkImplicitRefGroups();
|
||||
work_to_do = !marking_stack.is_empty();
|
||||
ProcessMarkingStack();
|
||||
}
|
||||
@ -1311,10 +1339,9 @@ void MarkCompactCollector::MarkLiveObjects() {
|
||||
MarkRoots(&root_visitor);
|
||||
|
||||
// The objects reachable from the roots are marked, yet unreachable
|
||||
// objects are unmarked. Mark objects reachable from object groups
|
||||
// containing at least one marked object, and continue until no new
|
||||
// objects are reachable from the object groups.
|
||||
ProcessObjectGroups();
|
||||
// objects are unmarked. Mark objects reachable due to host
|
||||
// application specific logic.
|
||||
ProcessExternalMarking();
|
||||
|
||||
// The objects reachable from the roots or object groups are marked,
|
||||
// yet unreachable objects are unmarked. Mark objects reachable
|
||||
@ -1330,9 +1357,9 @@ void MarkCompactCollector::MarkLiveObjects() {
|
||||
EmptyMarkingStack();
|
||||
}
|
||||
|
||||
// Repeat the object groups to mark unmarked groups reachable from the
|
||||
// weak roots.
|
||||
ProcessObjectGroups();
|
||||
// Repeat host application specific marking to mark unmarked objects
|
||||
// reachable from the weak roots.
|
||||
ProcessExternalMarking();
|
||||
|
||||
// Prune the symbol table removing all symbols only pointed to by the
|
||||
// symbol table. Cannot use symbol_table() here because the symbol
|
||||
@ -1350,6 +1377,7 @@ void MarkCompactCollector::MarkLiveObjects() {
|
||||
|
||||
// Remove object groups after marking phase.
|
||||
GlobalHandles::RemoveObjectGroups();
|
||||
GlobalHandles::RemoveImplicitRefGroups();
|
||||
|
||||
// Flush code from collected candidates.
|
||||
FlushCode::ProcessCandidates();
|
||||
|
@ -220,10 +220,13 @@ class MarkCompactCollector: public AllStatic {
|
||||
// group marked.
|
||||
static void MarkObjectGroups();
|
||||
|
||||
// Mark all objects in an object group with at least one marked
|
||||
// object, then all objects reachable from marked objects in object
|
||||
// groups, and repeat.
|
||||
static void ProcessObjectGroups();
|
||||
// Mark objects in implicit references groups if their parent object
|
||||
// is marked.
|
||||
static void MarkImplicitRefGroups();
|
||||
|
||||
// Mark all objects which are reachable due to host application
|
||||
// logic like object groups or implicit references' groups.
|
||||
static void ProcessExternalMarking();
|
||||
|
||||
// Mark objects reachable (transitively) from objects in the marking stack
|
||||
// or overflowed in the heap.
|
||||
|
@ -50,15 +50,19 @@ static bool IsNaN(double x) {
|
||||
#endif
|
||||
}
|
||||
|
||||
using ::v8::ObjectTemplate;
|
||||
using ::v8::Value;
|
||||
using ::v8::Context;
|
||||
using ::v8::Local;
|
||||
using ::v8::String;
|
||||
using ::v8::Script;
|
||||
using ::v8::Function;
|
||||
using ::v8::AccessorInfo;
|
||||
using ::v8::Context;
|
||||
using ::v8::Extension;
|
||||
using ::v8::Function;
|
||||
using ::v8::HandleScope;
|
||||
using ::v8::Local;
|
||||
using ::v8::Object;
|
||||
using ::v8::ObjectTemplate;
|
||||
using ::v8::Persistent;
|
||||
using ::v8::Script;
|
||||
using ::v8::String;
|
||||
using ::v8::Value;
|
||||
using ::v8::V8;
|
||||
|
||||
namespace i = ::i;
|
||||
|
||||
@ -1789,6 +1793,180 @@ THREADED_TEST(GlobalHandle) {
|
||||
}
|
||||
|
||||
|
||||
static int NumberOfWeakCalls = 0;
|
||||
static void WeakPointerCallback(Persistent<Value> handle, void* id) {
|
||||
CHECK_EQ(reinterpret_cast<void*>(1234), id);
|
||||
NumberOfWeakCalls++;
|
||||
handle.Dispose();
|
||||
}
|
||||
|
||||
THREADED_TEST(ApiObjectGroups) {
|
||||
HandleScope scope;
|
||||
LocalContext env;
|
||||
|
||||
NumberOfWeakCalls = 0;
|
||||
|
||||
Persistent<Object> g1s1;
|
||||
Persistent<Object> g1s2;
|
||||
Persistent<Object> g1c1;
|
||||
Persistent<Object> g2s1;
|
||||
Persistent<Object> g2s2;
|
||||
Persistent<Object> g2c1;
|
||||
|
||||
{
|
||||
HandleScope scope;
|
||||
g1s1 = Persistent<Object>::New(Object::New());
|
||||
g1s2 = Persistent<Object>::New(Object::New());
|
||||
g1c1 = Persistent<Object>::New(Object::New());
|
||||
g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
|
||||
g2s1 = Persistent<Object>::New(Object::New());
|
||||
g2s2 = Persistent<Object>::New(Object::New());
|
||||
g2c1 = Persistent<Object>::New(Object::New());
|
||||
g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
}
|
||||
|
||||
Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
|
||||
|
||||
// Connect group 1 and 2, make a cycle.
|
||||
CHECK(g1s2->Set(0, g2s2));
|
||||
CHECK(g2s1->Set(0, g1s1));
|
||||
|
||||
{
|
||||
Persistent<Value> g1_objects[] = { g1s1, g1s2 };
|
||||
Persistent<Value> g1_children[] = { g1c1 };
|
||||
Persistent<Value> g2_objects[] = { g2s1, g2s2 };
|
||||
Persistent<Value> g2_children[] = { g2c1 };
|
||||
V8::AddObjectGroup(g1_objects, 2);
|
||||
V8::AddImplicitReferences(g1s1, g1_children, 1);
|
||||
V8::AddObjectGroup(g2_objects, 2);
|
||||
V8::AddImplicitReferences(g2s2, g2_children, 1);
|
||||
}
|
||||
// Do a full GC
|
||||
i::Heap::CollectGarbage(i::OLD_POINTER_SPACE);
|
||||
|
||||
// All object should be alive.
|
||||
CHECK_EQ(0, NumberOfWeakCalls);
|
||||
|
||||
// Weaken the root.
|
||||
root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
// But make children strong roots---all the objects (except for children)
|
||||
// should be collectable now.
|
||||
g1c1.ClearWeak();
|
||||
g2c1.ClearWeak();
|
||||
|
||||
// Groups are deleted, rebuild groups.
|
||||
{
|
||||
Persistent<Value> g1_objects[] = { g1s1, g1s2 };
|
||||
Persistent<Value> g1_children[] = { g1c1 };
|
||||
Persistent<Value> g2_objects[] = { g2s1, g2s2 };
|
||||
Persistent<Value> g2_children[] = { g2c1 };
|
||||
V8::AddObjectGroup(g1_objects, 2);
|
||||
V8::AddImplicitReferences(g1s1, g1_children, 1);
|
||||
V8::AddObjectGroup(g2_objects, 2);
|
||||
V8::AddImplicitReferences(g2s2, g2_children, 1);
|
||||
}
|
||||
|
||||
i::Heap::CollectGarbage(i::OLD_POINTER_SPACE);
|
||||
|
||||
// All objects should be gone. 5 global handles in total.
|
||||
CHECK_EQ(5, NumberOfWeakCalls);
|
||||
|
||||
// And now make children weak again and collect them.
|
||||
g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
|
||||
i::Heap::CollectGarbage(i::OLD_POINTER_SPACE);
|
||||
CHECK_EQ(7, NumberOfWeakCalls);
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(ApiObjectGroupsCycle) {
|
||||
HandleScope scope;
|
||||
LocalContext env;
|
||||
|
||||
NumberOfWeakCalls = 0;
|
||||
|
||||
Persistent<Object> g1s1;
|
||||
Persistent<Object> g1s2;
|
||||
Persistent<Object> g2s1;
|
||||
Persistent<Object> g2s2;
|
||||
Persistent<Object> g3s1;
|
||||
Persistent<Object> g3s2;
|
||||
|
||||
{
|
||||
HandleScope scope;
|
||||
g1s1 = Persistent<Object>::New(Object::New());
|
||||
g1s2 = Persistent<Object>::New(Object::New());
|
||||
g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
|
||||
g2s1 = Persistent<Object>::New(Object::New());
|
||||
g2s2 = Persistent<Object>::New(Object::New());
|
||||
g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
|
||||
g3s1 = Persistent<Object>::New(Object::New());
|
||||
g3s2 = Persistent<Object>::New(Object::New());
|
||||
g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
}
|
||||
|
||||
Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root.
|
||||
|
||||
// Connect groups. We're building the following cycle:
|
||||
// G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
|
||||
// groups.
|
||||
{
|
||||
Persistent<Value> g1_objects[] = { g1s1, g1s2 };
|
||||
Persistent<Value> g1_children[] = { g2s1 };
|
||||
Persistent<Value> g2_objects[] = { g2s1, g2s2 };
|
||||
Persistent<Value> g2_children[] = { g3s1 };
|
||||
Persistent<Value> g3_objects[] = { g3s1, g3s2 };
|
||||
Persistent<Value> g3_children[] = { g1s1 };
|
||||
V8::AddObjectGroup(g1_objects, 2);
|
||||
V8::AddImplicitReferences(g1s1, g1_children, 1);
|
||||
V8::AddObjectGroup(g2_objects, 2);
|
||||
V8::AddImplicitReferences(g2s1, g2_children, 1);
|
||||
V8::AddObjectGroup(g3_objects, 2);
|
||||
V8::AddImplicitReferences(g3s1, g3_children, 1);
|
||||
}
|
||||
// Do a full GC
|
||||
i::Heap::CollectGarbage(i::OLD_POINTER_SPACE);
|
||||
|
||||
// All object should be alive.
|
||||
CHECK_EQ(0, NumberOfWeakCalls);
|
||||
|
||||
// Weaken the root.
|
||||
root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback);
|
||||
|
||||
// Groups are deleted, rebuild groups.
|
||||
{
|
||||
Persistent<Value> g1_objects[] = { g1s1, g1s2 };
|
||||
Persistent<Value> g1_children[] = { g2s1 };
|
||||
Persistent<Value> g2_objects[] = { g2s1, g2s2 };
|
||||
Persistent<Value> g2_children[] = { g3s1 };
|
||||
Persistent<Value> g3_objects[] = { g3s1, g3s2 };
|
||||
Persistent<Value> g3_children[] = { g1s1 };
|
||||
V8::AddObjectGroup(g1_objects, 2);
|
||||
V8::AddImplicitReferences(g1s1, g1_children, 1);
|
||||
V8::AddObjectGroup(g2_objects, 2);
|
||||
V8::AddImplicitReferences(g2s1, g2_children, 1);
|
||||
V8::AddObjectGroup(g3_objects, 2);
|
||||
V8::AddImplicitReferences(g3s1, g3_children, 1);
|
||||
}
|
||||
|
||||
i::Heap::CollectGarbage(i::OLD_POINTER_SPACE);
|
||||
|
||||
// All objects should be gone. 7 global handles in total.
|
||||
CHECK_EQ(7, NumberOfWeakCalls);
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(ScriptException) {
|
||||
v8::HandleScope scope;
|
||||
LocalContext env;
|
||||
|
@ -298,6 +298,7 @@ TEST(GCCallback) {
|
||||
|
||||
static int NumberOfWeakCalls = 0;
|
||||
static void WeakPointerCallback(v8::Persistent<v8::Value> handle, void* id) {
|
||||
ASSERT(id == reinterpret_cast<void*>(1234));
|
||||
NumberOfWeakCalls++;
|
||||
handle.Dispose();
|
||||
}
|
||||
@ -312,23 +313,33 @@ TEST(ObjectGroups) {
|
||||
GlobalHandles::Create(Heap::AllocateFixedArray(1)->ToObjectChecked());
|
||||
Handle<Object> g1s2 =
|
||||
GlobalHandles::Create(Heap::AllocateFixedArray(1)->ToObjectChecked());
|
||||
Handle<Object> g1c1 =
|
||||
GlobalHandles::Create(Heap::AllocateFixedArray(1)->ToObjectChecked());
|
||||
GlobalHandles::MakeWeak(g1s1.location(),
|
||||
reinterpret_cast<void*>(1234),
|
||||
&WeakPointerCallback);
|
||||
GlobalHandles::MakeWeak(g1s2.location(),
|
||||
reinterpret_cast<void*>(1234),
|
||||
&WeakPointerCallback);
|
||||
GlobalHandles::MakeWeak(g1c1.location(),
|
||||
reinterpret_cast<void*>(1234),
|
||||
&WeakPointerCallback);
|
||||
|
||||
Handle<Object> g2s1 =
|
||||
GlobalHandles::Create(Heap::AllocateFixedArray(1)->ToObjectChecked());
|
||||
Handle<Object> g2s2 =
|
||||
GlobalHandles::Create(Heap::AllocateFixedArray(1)->ToObjectChecked());
|
||||
Handle<Object> g2c1 =
|
||||
GlobalHandles::Create(Heap::AllocateFixedArray(1)->ToObjectChecked());
|
||||
GlobalHandles::MakeWeak(g2s1.location(),
|
||||
reinterpret_cast<void*>(1234),
|
||||
&WeakPointerCallback);
|
||||
GlobalHandles::MakeWeak(g2s2.location(),
|
||||
reinterpret_cast<void*>(1234),
|
||||
&WeakPointerCallback);
|
||||
GlobalHandles::MakeWeak(g2c1.location(),
|
||||
reinterpret_cast<void*>(1234),
|
||||
&WeakPointerCallback);
|
||||
|
||||
Handle<Object> root = GlobalHandles::Create(*g1s1); // make a root.
|
||||
|
||||
@ -338,9 +349,15 @@ TEST(ObjectGroups) {
|
||||
|
||||
{
|
||||
Object** g1_objects[] = { g1s1.location(), g1s2.location() };
|
||||
Object** g1_children[] = { g1c1.location() };
|
||||
Object** g2_objects[] = { g2s1.location(), g2s2.location() };
|
||||
GlobalHandles::AddGroup(g1_objects, 2, NULL);
|
||||
GlobalHandles::AddGroup(g2_objects, 2, NULL);
|
||||
Object** g2_children[] = { g2c1.location() };
|
||||
GlobalHandles::AddObjectGroup(g1_objects, 2, NULL);
|
||||
GlobalHandles::AddImplicitReferences(HeapObject::cast(*g1s1),
|
||||
g1_children, 1);
|
||||
GlobalHandles::AddObjectGroup(g2_objects, 2, NULL);
|
||||
GlobalHandles::AddImplicitReferences(HeapObject::cast(*g2s2),
|
||||
g2_children, 1);
|
||||
}
|
||||
// Do a full GC
|
||||
Heap::CollectGarbage(OLD_POINTER_SPACE);
|
||||
@ -352,17 +369,38 @@ TEST(ObjectGroups) {
|
||||
GlobalHandles::MakeWeak(root.location(),
|
||||
reinterpret_cast<void*>(1234),
|
||||
&WeakPointerCallback);
|
||||
// But make children strong roots---all the objects (except for children)
|
||||
// should be collectable now.
|
||||
GlobalHandles::ClearWeakness(g1c1.location());
|
||||
GlobalHandles::ClearWeakness(g2c1.location());
|
||||
|
||||
// Groups are deleted, rebuild groups.
|
||||
{
|
||||
Object** g1_objects[] = { g1s1.location(), g1s2.location() };
|
||||
Object** g1_children[] = { g1c1.location() };
|
||||
Object** g2_objects[] = { g2s1.location(), g2s2.location() };
|
||||
GlobalHandles::AddGroup(g1_objects, 2, NULL);
|
||||
GlobalHandles::AddGroup(g2_objects, 2, NULL);
|
||||
Object** g2_children[] = { g2c1.location() };
|
||||
GlobalHandles::AddObjectGroup(g1_objects, 2, NULL);
|
||||
GlobalHandles::AddImplicitReferences(HeapObject::cast(*g1s1),
|
||||
g1_children, 1);
|
||||
GlobalHandles::AddObjectGroup(g2_objects, 2, NULL);
|
||||
GlobalHandles::AddImplicitReferences(HeapObject::cast(*g2s2),
|
||||
g2_children, 1);
|
||||
}
|
||||
|
||||
Heap::CollectGarbage(OLD_POINTER_SPACE);
|
||||
|
||||
// All objects should be gone. 5 global handles in total.
|
||||
CHECK_EQ(5, NumberOfWeakCalls);
|
||||
|
||||
// And now make children weak again and collect them.
|
||||
GlobalHandles::MakeWeak(g1c1.location(),
|
||||
reinterpret_cast<void*>(1234),
|
||||
&WeakPointerCallback);
|
||||
GlobalHandles::MakeWeak(g2c1.location(),
|
||||
reinterpret_cast<void*>(1234),
|
||||
&WeakPointerCallback);
|
||||
|
||||
Heap::CollectGarbage(OLD_POINTER_SPACE);
|
||||
CHECK_EQ(7, NumberOfWeakCalls);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user