OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/renderer/api_event_handler.h" | 5 #include "extensions/renderer/api_event_handler.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <map> | 8 #include <map> |
9 #include <memory> | 9 #include <memory> |
10 #include <vector> | 10 #include <vector> |
(...skipping 10 matching lines...) Expand all Loading... |
21 | 21 |
22 namespace extensions { | 22 namespace extensions { |
23 | 23 |
24 namespace { | 24 namespace { |
25 | 25 |
26 const char kExtensionAPIEventPerContextKey[] = "extension_api_events"; | 26 const char kExtensionAPIEventPerContextKey[] = "extension_api_events"; |
27 | 27 |
28 struct APIEventPerContextData : public base::SupportsUserData::Data { | 28 struct APIEventPerContextData : public base::SupportsUserData::Data { |
29 APIEventPerContextData(v8::Isolate* isolate) : isolate(isolate) {} | 29 APIEventPerContextData(v8::Isolate* isolate) : isolate(isolate) {} |
30 ~APIEventPerContextData() override { | 30 ~APIEventPerContextData() override { |
31 v8::HandleScope scope(isolate); | 31 DCHECK(emitters.empty()) |
32 // We explicitly clear the event data map here to remove all references to | 32 << "|emitters| should have been cleared by InvalidateContext()"; |
33 // v8 objects. This helps us avoid cycles in v8 where an event listener | 33 DCHECK(massagers.empty()) |
34 // could hold a reference to the event, which in turn holds the reference | 34 << "|massagers| should have been cleared by InvalidateContext()"; |
35 // to the listener. | |
36 for (const auto& pair : emitters) { | |
37 EventEmitter* emitter = nullptr; | |
38 gin::Converter<EventEmitter*>::FromV8( | |
39 isolate, pair.second.Get(isolate), &emitter); | |
40 CHECK(emitter); | |
41 emitter->listeners()->clear(); | |
42 } | |
43 } | 35 } |
44 | 36 |
45 // The associated v8::Isolate. Since this object is cleaned up at context | 37 // The associated v8::Isolate. Since this object is cleaned up at context |
46 // destruction, this should always be valid. | 38 // destruction, this should always be valid. |
47 v8::Isolate* isolate; | 39 v8::Isolate* isolate; |
48 | 40 |
49 // A map from event name -> event emitter. | 41 // A map from event name -> event emitter. |
50 std::map<std::string, v8::Global<v8::Object>> emitters; | 42 std::map<std::string, v8::Global<v8::Object>> emitters; |
51 | 43 |
52 // A map from event name -> argument massager. | 44 // A map from event name -> argument massager. |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 | 183 |
192 void APIEventHandler::RegisterArgumentMassager( | 184 void APIEventHandler::RegisterArgumentMassager( |
193 v8::Local<v8::Context> context, | 185 v8::Local<v8::Context> context, |
194 const std::string& event_name, | 186 const std::string& event_name, |
195 v8::Local<v8::Function> massager) { | 187 v8::Local<v8::Function> massager) { |
196 APIEventPerContextData* data = GetContextData(context, true); | 188 APIEventPerContextData* data = GetContextData(context, true); |
197 DCHECK(data->massagers.find(event_name) == data->massagers.end()); | 189 DCHECK(data->massagers.find(event_name) == data->massagers.end()); |
198 data->massagers[event_name].Reset(context->GetIsolate(), massager); | 190 data->massagers[event_name].Reset(context->GetIsolate(), massager); |
199 } | 191 } |
200 | 192 |
| 193 void APIEventHandler::InvalidateContext(v8::Local<v8::Context> context) { |
| 194 gin::PerContextData* per_context_data = gin::PerContextData::From(context); |
| 195 DCHECK(per_context_data); |
| 196 APIEventPerContextData* data = static_cast<APIEventPerContextData*>( |
| 197 per_context_data->GetUserData(kExtensionAPIEventPerContextKey)); |
| 198 if (!data) |
| 199 return; |
| 200 |
| 201 v8::Isolate* isolate = context->GetIsolate(); |
| 202 v8::HandleScope scope(isolate); |
| 203 // This loop *shouldn't* allow any self-modification (i.e., no listeners |
| 204 // should be added or removed as a result of the iteration). If that changes, |
| 205 // we'll need to cache the listeners elsewhere before iterating. |
| 206 for (const auto& pair : data->emitters) { |
| 207 EventEmitter* emitter = nullptr; |
| 208 gin::Converter<EventEmitter*>::FromV8(isolate, pair.second.Get(isolate), |
| 209 &emitter); |
| 210 CHECK(emitter); |
| 211 emitter->Invalidate(); |
| 212 // When the context is shut down, all listeners are removed. |
| 213 listeners_changed_.Run( |
| 214 pair.first, binding::EventListenersChanged::NO_LISTENERS, context); |
| 215 } |
| 216 |
| 217 data->emitters.clear(); |
| 218 data->massagers.clear(); |
| 219 |
| 220 // InvalidateContext() is called shortly (and, theoretically, synchronously) |
| 221 // before the PerContextData is deleted. We have a check that guarantees that |
| 222 // no new EventEmitters are created after the PerContextData is deleted, so |
| 223 // no new emitters should be created after this point. |
| 224 } |
| 225 |
201 size_t APIEventHandler::GetNumEventListenersForTesting( | 226 size_t APIEventHandler::GetNumEventListenersForTesting( |
202 const std::string& event_name, | 227 const std::string& event_name, |
203 v8::Local<v8::Context> context) { | 228 v8::Local<v8::Context> context) { |
204 APIEventPerContextData* data = GetContextData(context, false); | 229 APIEventPerContextData* data = GetContextData(context, false); |
205 DCHECK(data); | 230 DCHECK(data); |
206 | 231 |
207 auto iter = data->emitters.find(event_name); | 232 auto iter = data->emitters.find(event_name); |
208 DCHECK(iter != data->emitters.end()); | 233 DCHECK(iter != data->emitters.end()); |
209 EventEmitter* emitter = nullptr; | 234 EventEmitter* emitter = nullptr; |
210 gin::Converter<EventEmitter*>::FromV8( | 235 gin::Converter<EventEmitter*>::FromV8( |
211 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter); | 236 context->GetIsolate(), iter->second.Get(context->GetIsolate()), &emitter); |
212 CHECK(emitter); | 237 CHECK(emitter); |
213 return emitter->listeners()->size(); | 238 return emitter->listeners()->size(); |
214 } | 239 } |
215 | 240 |
216 } // namespace extensions | 241 } // namespace extensions |
OLD | NEW |