diff --git a/src/global-handles.cc b/src/global-handles.cc index 54a7ccb00f..e519d7077f 100644 --- a/src/global-handles.cc +++ b/src/global-handles.cc @@ -165,6 +165,9 @@ class GlobalHandles::Node : public Malloced { // It's fine though to reuse nodes that were destroyed in weak callback // as those cannot be deallocated until we are back from the callback. set_first_free(NULL); + if (first_deallocated()) { + first_deallocated()->set_next(head()); + } // Leaving V8. VMState state(EXTERNAL); func(object, par); @@ -270,6 +273,7 @@ Handle GlobalHandles::Create(Object* value) { // Next try deallocated list result = first_deallocated(); set_first_deallocated(result->next_free()); + ASSERT(result->next() == head()); set_head(result); } else { // Allocate a new node. diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 475cdf8b0d..17a2b9a3f1 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -6226,6 +6226,31 @@ THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) { i::Heap::CollectAllGarbage(false); } +void DisposingCallback(v8::Persistent handle, void*) { + handle.Dispose(); +} + +void HandleCreatingCallback(v8::Persistent handle, void*) { + v8::HandleScope scope; + v8::Persistent::New(v8::Object::New()); +} + + +THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) { + LocalContext context; + + v8::Persistent handle1, handle2, handle3; + { + v8::HandleScope scope; + handle3 = v8::Persistent::New(v8::Object::New()); + handle2 = v8::Persistent::New(v8::Object::New()); + handle1 = v8::Persistent::New(v8::Object::New()); + } + handle2.MakeWeak(NULL, DisposingCallback); + handle3.MakeWeak(NULL, HandleCreatingCallback); + i::Heap::CollectAllGarbage(false); +} + THREADED_TEST(CheckForCrossContextObjectLiterals) { v8::V8::Initialize();