Land change to bail out from post garbage collection processing if
another post gc processing was trigger because of weak callbacks. Review URL: http://codereview.chromium.org/174141 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2737 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
88588df8c5
commit
fdf70d37fa
@ -144,8 +144,8 @@ class GlobalHandles::Node : public Malloced {
|
||||
// Returns the callback for this weak handle.
|
||||
WeakReferenceCallback callback() { return callback_; }
|
||||
|
||||
void PostGarbageCollectionProcessing() {
|
||||
if (state_ != Node::PENDING) return;
|
||||
bool PostGarbageCollectionProcessing() {
|
||||
if (state_ != Node::PENDING) return false;
|
||||
LOG(HandleEvent("GlobalHandle::Processing", handle().location()));
|
||||
void* par = parameter();
|
||||
state_ = NEAR_DEATH;
|
||||
@ -153,18 +153,19 @@ class GlobalHandles::Node : public Malloced {
|
||||
// The callback function is resolved as late as possible to preserve old
|
||||
// behavior.
|
||||
WeakReferenceCallback func = callback();
|
||||
if (func != NULL) {
|
||||
v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
|
||||
{
|
||||
// Forbid reuse of destroyed nodes as they might be already deallocated.
|
||||
// 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);
|
||||
// Leaving V8.
|
||||
VMState state(EXTERNAL);
|
||||
func(object, par);
|
||||
}
|
||||
if (func == NULL) return false;
|
||||
|
||||
v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
|
||||
{
|
||||
// Forbid reuse of destroyed nodes as they might be already deallocated.
|
||||
// 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);
|
||||
// Leaving V8.
|
||||
VMState state(EXTERNAL);
|
||||
func(object, par);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Place the handle address first to avoid offset computation.
|
||||
@ -275,15 +276,26 @@ void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
|
||||
}
|
||||
|
||||
|
||||
int post_gc_processing_count = 0;
|
||||
|
||||
void GlobalHandles::PostGarbageCollectionProcessing() {
|
||||
// Process weak global handle callbacks. This must be done after the
|
||||
// GC is completely done, because the callbacks may invoke arbitrary
|
||||
// API functions.
|
||||
// At the same time deallocate all DESTROYED nodes
|
||||
ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
|
||||
const int initial_post_gc_processing_count = ++post_gc_processing_count;
|
||||
Node** p = &head_;
|
||||
while (*p != NULL) {
|
||||
(*p)->PostGarbageCollectionProcessing();
|
||||
if ((*p)->PostGarbageCollectionProcessing()) {
|
||||
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).
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((*p)->state_ == Node::DESTROYED) {
|
||||
// Delete the link.
|
||||
Node* node = *p;
|
||||
|
@ -487,7 +487,10 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
|
||||
|
||||
void Heap::PostGarbageCollectionProcessing() {
|
||||
// Process weak handles post gc.
|
||||
GlobalHandles::PostGarbageCollectionProcessing();
|
||||
{
|
||||
DisableAssertNoAllocation allow_allocation;
|
||||
GlobalHandles::PostGarbageCollectionProcessing();
|
||||
}
|
||||
// Update flat string readers.
|
||||
FlatStringReader::PostGarbageCollectionProcessing();
|
||||
}
|
||||
|
20
src/heap.h
20
src/heap.h
@ -1388,6 +1388,20 @@ class AssertNoAllocation {
|
||||
bool old_state_;
|
||||
};
|
||||
|
||||
class DisableAssertNoAllocation {
|
||||
public:
|
||||
DisableAssertNoAllocation() {
|
||||
old_state_ = Heap::allow_allocation(true);
|
||||
}
|
||||
|
||||
~DisableAssertNoAllocation() {
|
||||
Heap::allow_allocation(old_state_);
|
||||
}
|
||||
|
||||
private:
|
||||
bool old_state_;
|
||||
};
|
||||
|
||||
#else // ndef DEBUG
|
||||
|
||||
class AssertNoAllocation {
|
||||
@ -1396,6 +1410,12 @@ class AssertNoAllocation {
|
||||
~AssertNoAllocation() { }
|
||||
};
|
||||
|
||||
class DisableAssertNoAllocation {
|
||||
public:
|
||||
DisableAssertNoAllocation() { }
|
||||
~DisableAssertNoAllocation() { }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
|
@ -6246,6 +6246,29 @@ THREADED_TEST(NewPersistentHandleFromWeakCallback) {
|
||||
}
|
||||
|
||||
|
||||
v8::Persistent<v8::Object> to_be_disposed;
|
||||
|
||||
void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
|
||||
to_be_disposed.Dispose();
|
||||
i::Heap::CollectAllGarbage();
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
|
||||
LocalContext context;
|
||||
|
||||
v8::Persistent<v8::Object> handle1, handle2;
|
||||
{
|
||||
v8::HandleScope scope;
|
||||
handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
|
||||
handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
|
||||
}
|
||||
handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
|
||||
to_be_disposed = handle2;
|
||||
i::Heap::CollectAllGarbage();
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(CheckForCrossContextObjectLiterals) {
|
||||
v8::V8::Initialize();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user