Chromium Code Reviews| Index: extensions/renderer/api_event_handler.cc |
| diff --git a/extensions/renderer/api_event_handler.cc b/extensions/renderer/api_event_handler.cc |
| index 2391607e67ab5955be1ae634c9df4379cd6c6252..52979cdad6b1008ae29eac1e3e64aa5905a1dc89 100644 |
| --- a/extensions/renderer/api_event_handler.cc |
| +++ b/extensions/renderer/api_event_handler.cc |
| @@ -28,18 +28,8 @@ const char kExtensionAPIEventPerContextKey[] = "extension_api_events"; |
| struct APIEventPerContextData : public base::SupportsUserData::Data { |
| APIEventPerContextData(v8::Isolate* isolate) : isolate(isolate) {} |
| ~APIEventPerContextData() override { |
| - v8::HandleScope scope(isolate); |
| - // We explicitly clear the event data map here to remove all references to |
| - // v8 objects. This helps us avoid cycles in v8 where an event listener |
| - // could hold a reference to the event, which in turn holds the reference |
| - // to the listener. |
| - for (const auto& pair : event_data) { |
| - EventEmitter* emitter = nullptr; |
| - gin::Converter<EventEmitter*>::FromV8( |
| - isolate, pair.second.Get(isolate), &emitter); |
| - CHECK(emitter); |
| - emitter->listeners()->clear(); |
| - } |
| + DCHECK(event_data.empty()) |
| + << "|event_data| should have been cleared by InvalidateContext()"; |
| } |
| // The associated v8::Isolate. Since this object is cleaned up at context |
| @@ -127,6 +117,35 @@ void APIEventHandler::FireEventInContext(const std::string& event_name, |
| emitter->Fire(context, &v8_args); |
| } |
| +void APIEventHandler::InvalidateContext(v8::Local<v8::Context> context) { |
| + gin::PerContextData* per_context_data = gin::PerContextData::From(context); |
| + DCHECK(per_context_data); |
| + APIEventPerContextData* data = static_cast<APIEventPerContextData*>( |
| + per_context_data->GetUserData(kExtensionAPIEventPerContextKey)); |
| + if (!data) |
| + return; |
| + |
| + v8::Isolate* isolate = context->GetIsolate(); |
| + v8::HandleScope scope(isolate); |
| + for (const auto& pair : data->event_data) { |
| + EventEmitter* emitter = nullptr; |
| + gin::Converter<EventEmitter*>::FromV8(isolate, pair.second.Get(isolate), |
| + &emitter); |
| + CHECK(emitter); |
| + emitter->Invalidate(); |
| + // When the context is shut down, all listeners are removed. |
| + listeners_changed_.Run( |
| + pair.first, binding::EventListenersChanged::NO_LISTENERS, context); |
| + } |
| + |
| + data->event_data.clear(); |
|
lazyboy
2017/03/03 22:14:19
FYI: If there's a chance that |data->event_data| c
Devlin
2017/03/06 19:11:06
It shouldn't be possible, but I've added a comment
|
| + |
| + // InvalidateContext() is called shortly (and, theoretically, synchronously) |
| + // before the PerContextData is deleted. We have a check that guarantees that |
| + // no new EventEmitters are created after the PerContextData is deleted, so |
| + // no new emitters should be created after this point. |
| +} |
| + |
| size_t APIEventHandler::GetNumEventListenersForTesting( |
| const std::string& event_name, |
| v8::Local<v8::Context> context) { |