| Index: src/global-handles.cc
|
| diff --git a/src/global-handles.cc b/src/global-handles.cc
|
| index 0554c53bb5deca3d5458199a29793ced681fdb1b..25c6b4efda9dd9172f14df8d327828c417ab46ae 100644
|
| --- a/src/global-handles.cc
|
| +++ b/src/global-handles.cc
|
| @@ -264,38 +264,28 @@ class GlobalHandles::Node {
|
| if (weak_callback_ != NULL) {
|
| if (weakness_type() == NORMAL_WEAK) return;
|
|
|
| - v8::Isolate* api_isolate = reinterpret_cast<v8::Isolate*>(isolate);
|
| -
|
| DCHECK(weakness_type() == PHANTOM_WEAK ||
|
| weakness_type() == PHANTOM_WEAK_2_INTERNAL_FIELDS);
|
|
|
| - Object* internal_field0 = nullptr;
|
| - Object* internal_field1 = nullptr;
|
| - if (weakness_type() != PHANTOM_WEAK) {
|
| - if (object()->IsJSObject()) {
|
| - JSObject* jsobject = JSObject::cast(object());
|
| - int field_count = jsobject->GetInternalFieldCount();
|
| - if (field_count > 0) {
|
| - internal_field0 = jsobject->GetInternalField(0);
|
| - if (!internal_field0->IsSmi()) internal_field0 = nullptr;
|
| - }
|
| - if (field_count > 1) {
|
| - internal_field1 = jsobject->GetInternalField(1);
|
| - if (!internal_field1->IsSmi()) internal_field1 = nullptr;
|
| - }
|
| + void* internal_fields[v8::kInternalFieldsInWeakCallback] = {nullptr,
|
| + nullptr};
|
| + if (weakness_type() != PHANTOM_WEAK && object()->IsJSObject()) {
|
| + auto jsobject = JSObject::cast(object());
|
| + int field_count = jsobject->GetInternalFieldCount();
|
| + for (int i = 0; i < v8::kInternalFieldsInWeakCallback; ++i) {
|
| + if (field_count == i) break;
|
| + auto field = jsobject->GetInternalField(i);
|
| + if (field->IsSmi()) internal_fields[i] = field;
|
| }
|
| }
|
|
|
| - // Zap with harmless value.
|
| - *location() = Smi::FromInt(0);
|
| - typedef v8::WeakCallbackInfo<void> Data;
|
| -
|
| - Data data(api_isolate, parameter(), internal_field0, internal_field1);
|
| - Data::Callback callback =
|
| - reinterpret_cast<Data::Callback>(weak_callback_);
|
| + // Zap with something dangerous.
|
| + *location() = reinterpret_cast<Object*>(0x6057ca11);
|
|
|
| + typedef v8::WeakCallbackInfo<void> Data;
|
| + auto callback = reinterpret_cast<Data::Callback>(weak_callback_);
|
| pending_phantom_callbacks->Add(
|
| - PendingPhantomCallback(this, data, callback));
|
| + PendingPhantomCallback(this, callback, parameter(), internal_fields));
|
| DCHECK(IsInUse());
|
| set_state(NEAR_DEATH);
|
| }
|
| @@ -838,17 +828,50 @@ void GlobalHandles::UpdateListOfNewSpaceNodes() {
|
|
|
| int GlobalHandles::DispatchPendingPhantomCallbacks() {
|
| int freed_nodes = 0;
|
| + {
|
| + // The initial pass callbacks must simply clear the nodes.
|
| + for (auto i = pending_phantom_callbacks_.begin();
|
| + i != pending_phantom_callbacks_.end(); ++i) {
|
| + auto callback = i;
|
| + // Skip callbacks that have already been processed once.
|
| + if (callback->node() == nullptr) continue;
|
| + callback->Invoke(isolate());
|
| + freed_nodes++;
|
| + }
|
| + }
|
| + // The second pass empties the list.
|
| while (pending_phantom_callbacks_.length() != 0) {
|
| - PendingPhantomCallback callback = pending_phantom_callbacks_.RemoveLast();
|
| - DCHECK(callback.node()->IsInUse());
|
| - callback.invoke();
|
| - DCHECK(!callback.node()->IsInUse());
|
| - freed_nodes++;
|
| + auto callback = pending_phantom_callbacks_.RemoveLast();
|
| + DCHECK(callback.node() == nullptr);
|
| + // No second pass callback required.
|
| + if (callback.callback() == nullptr) continue;
|
| + // Fire second pass callback.
|
| + callback.Invoke(isolate());
|
| }
|
| return freed_nodes;
|
| }
|
|
|
|
|
| +void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate) {
|
| + Data::Callback* callback_addr = nullptr;
|
| + if (node_ != nullptr) {
|
| + // Initialize for first pass callback.
|
| + DCHECK(node_->state() == Node::NEAR_DEATH);
|
| + callback_addr = &callback_;
|
| + }
|
| + Data data(reinterpret_cast<v8::Isolate*>(isolate), parameter_,
|
| + internal_fields_, callback_addr);
|
| + Data::Callback callback = callback_;
|
| + callback_ = nullptr;
|
| + callback(data);
|
| + if (node_ != nullptr) {
|
| + // Transition to second pass state.
|
| + DCHECK(node_->state() == Node::FREE);
|
| + node_ = nullptr;
|
| + }
|
| +}
|
| +
|
| +
|
| 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
|
| @@ -879,14 +902,6 @@ int GlobalHandles::PostGarbageCollectionProcessing(GarbageCollector collector) {
|
| }
|
|
|
|
|
| -void GlobalHandles::PendingPhantomCallback::invoke() {
|
| - if (node_->state() == Node::FREE) return;
|
| - DCHECK(node_->state() == Node::NEAR_DEATH);
|
| - callback_(data_);
|
| - if (node_->state() != Node::FREE) node_->Release();
|
| -}
|
| -
|
| -
|
| void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
|
| for (NodeIterator it(this); !it.done(); it.Advance()) {
|
| if (it.node()->IsStrongRetainer()) {
|
|
|