Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp

Issue 2828643002: Make customElements.define faster
Patch Set: Try to make Android builder happy. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "bindings/core/v8/ScriptCustomElementDefinition.h" 5 #include "bindings/core/v8/ScriptCustomElementDefinition.h"
6 6
7 #include "bindings/core/v8/ScriptState.h" 7 #include "bindings/core/v8/ScriptState.h"
8 #include "bindings/core/v8/V8Binding.h" 8 #include "bindings/core/v8/V8Binding.h"
9 #include "bindings/core/v8/V8BindingMacros.h" 9 #include "bindings/core/v8/V8BindingMacros.h"
10 #include "bindings/core/v8/V8CustomElementRegistry.h" 10 #include "bindings/core/v8/V8CustomElementRegistry.h"
11 #include "bindings/core/v8/V8Element.h" 11 #include "bindings/core/v8/V8Element.h"
12 #include "bindings/core/v8/V8ErrorHandler.h" 12 #include "bindings/core/v8/V8ErrorHandler.h"
13 #include "bindings/core/v8/V8PrivateProperty.h" 13 #include "bindings/core/v8/V8PrivateProperty.h"
14 #include "bindings/core/v8/V8ScriptRunner.h" 14 #include "bindings/core/v8/V8ScriptRunner.h"
15 #include "bindings/core/v8/V8ThrowException.h" 15 #include "bindings/core/v8/V8ThrowException.h"
16 #include "core/dom/ExceptionCode.h" 16 #include "core/dom/ExceptionCode.h"
17 #include "core/dom/ExecutionContext.h" 17 #include "core/dom/ExecutionContext.h"
18 #include "core/dom/custom/CustomElement.h" 18 #include "core/dom/custom/CustomElement.h"
19 #include "core/events/ErrorEvent.h" 19 #include "core/events/ErrorEvent.h"
20 #include "core/html/HTMLElement.h" 20 #include "core/html/HTMLElement.h"
21 #include "core/html/imports/HTMLImportsController.h" 21 #include "core/html/imports/HTMLImportsController.h"
22 #include "platform/wtf/Allocator.h" 22 #include "platform/wtf/Allocator.h"
23 #include "v8.h" 23 #include "v8.h"
24 24
25 namespace blink { 25 namespace blink {
26 26
27 // Retrieves the custom elements constructor -> name map, creating it
28 // if necessary.
29 static v8::Local<v8::Map> EnsureCustomElementRegistryMap(
30 ScriptState* script_state,
31 CustomElementRegistry* registry) {
32 CHECK(script_state->World().IsMainWorld());
33 v8::Isolate* isolate = script_state->GetIsolate();
34
35 V8PrivateProperty::Symbol symbol =
36 V8PrivateProperty::GetCustomElementRegistryMap(isolate);
37 v8::Local<v8::Object> wrapper = ToV8(registry, script_state).As<v8::Object>();
38 v8::Local<v8::Value> map = symbol.GetOrUndefined(wrapper);
39 if (map->IsUndefined()) {
40 map = v8::Map::New(isolate);
41 symbol.Set(wrapper, map);
42 }
43 return map.As<v8::Map>();
44 }
45
46 ScriptCustomElementDefinition* ScriptCustomElementDefinition::ForConstructor( 27 ScriptCustomElementDefinition* ScriptCustomElementDefinition::ForConstructor(
47 ScriptState* script_state, 28 ScriptState* script_state,
48 CustomElementRegistry* registry, 29 CustomElementRegistry* registry,
49 const v8::Local<v8::Value>& constructor) { 30 const v8::Local<v8::Value>& constructor) {
50 v8::Local<v8::Map> map = 31 if (!constructor->IsObject())
51 EnsureCustomElementRegistryMap(script_state, registry);
52 v8::Local<v8::Value> name_value =
53 map->Get(script_state->GetContext(), constructor).ToLocalChecked();
54 if (!name_value->IsString())
55 return nullptr; 32 return nullptr;
56 AtomicString name = ToCoreAtomicString(name_value.As<v8::String>()); 33 auto private_id =
34 script_state->PerContextData()->GetPrivateCustomElementDefinitionId();
35 v8::Local<v8::Value> id_value;
36 if (!V8Call(constructor.As<v8::Object>()->GetPrivate(
37 script_state->GetContext(), private_id),
38 id_value))
39 return nullptr;
40 if (!id_value->IsUint32())
41 return nullptr;
42 uint32_t id = id_value.As<v8::Uint32>()->Value();
57 43
58 // This downcast is safe because only 44 // This downcast is safe because only
59 // ScriptCustomElementDefinitions have a name associated with a V8 45 // ScriptCustomElementDefinitions have a name associated with a V8
60 // constructor in the map; see 46 // constructor in the map; see
61 // ScriptCustomElementDefinition::create. This relies on three 47 // ScriptCustomElementDefinition::create. This relies on three
62 // things: 48 // things:
63 // 49 //
64 // 1. Only ScriptCustomElementDefinition adds entries to the map. 50 // 1. Only ScriptCustomElementDefinition adds entries to the map.
65 // Audit the use of private properties in general and how the 51 // Audit the use of private properties in general and how the
66 // map is handled--it should never be leaked to script. 52 // map is handled--it should never be leaked to script.
67 // 53 //
68 // 2. CustomElementRegistry does not overwrite definitions with a 54 // 2. CustomElementRegistry does not overwrite definitions with a
69 // given name--see the CHECK in CustomElementRegistry::define 55 // given name--see the CHECK in CustomElementRegistry::define
70 // --and adds ScriptCustomElementDefinitions to the map without 56 // --and adds ScriptCustomElementDefinitions to the map without
71 // fail. 57 // fail.
72 // 58 //
73 // 3. The relationship between the CustomElementRegistry and its 59 // 3. The relationship between the CustomElementRegistry and its
74 // map is never mixed up; this is guaranteed by the bindings 60 // map is never mixed up; this is guaranteed by the bindings
75 // system which provides a stable wrapper, and the map hangs 61 // system which provides a stable wrapper, and the map hangs
76 // off the wrapper. 62 // off the wrapper.
77 // 63 //
78 // At a meta-level, this downcast is safe because there is 64 // At a meta-level, this downcast is safe because there is
79 // currently only one implementation of CustomElementDefinition in 65 // currently only one implementation of CustomElementDefinition in
80 // product code and that is ScriptCustomElementDefinition. But 66 // product code and that is ScriptCustomElementDefinition. But
81 // that may change in the future. 67 // that may change in the future.
82 CustomElementDefinition* definition = registry->DefinitionForName(name); 68 CustomElementDefinition* definition = registry->DefinitionForId(id);
83 CHECK(definition); 69 CHECK(definition);
84 return static_cast<ScriptCustomElementDefinition*>(definition); 70 ScriptCustomElementDefinition* scriptDefinition =
71 static_cast<ScriptCustomElementDefinition*>(definition);
72 // v8::Object::GetPrivate notes that private properties may be
73 // inherited in future, so check that the definition's constructor
74 // is exactly the passed object.
75 return scriptDefinition->constructor_.Get() == constructor ? scriptDefinition
76 : nullptr;
85 } 77 }
86 78
87 using SymbolGetter = V8PrivateProperty::Symbol (*)(v8::Isolate*); 79 using SymbolGetter = V8PrivateProperty::Symbol (*)(v8::Isolate*);
88 80
89 template <typename T> 81 template <typename T>
90 static void KeepAlive(v8::Local<v8::Object>& object, 82 static void KeepAlive(v8::Local<v8::Object>& object,
91 SymbolGetter symbol_getter, 83 SymbolGetter symbol_getter,
92 const v8::Local<T>& value, 84 const v8::Local<T>& value,
93 ScopedPersistent<T>& persistent, 85 ScopedPersistent<T>& persistent,
94 ScriptState* script_state) { 86 ScriptState* script_state) {
95 if (value.IsEmpty()) 87 if (value.IsEmpty())
96 return; 88 return;
97 89
98 v8::Isolate* isolate = script_state->GetIsolate(); 90 v8::Isolate* isolate = script_state->GetIsolate();
99 symbol_getter(isolate).Set(object, value); 91 symbol_getter(isolate).Set(object, value);
100 persistent.Set(isolate, value); 92 persistent.Set(isolate, value);
101 persistent.SetPhantom(); 93 persistent.SetPhantom();
102 } 94 }
103 95
104 ScriptCustomElementDefinition* ScriptCustomElementDefinition::Create( 96 ScriptCustomElementDefinition* ScriptCustomElementDefinition::Create(
105 ScriptState* script_state, 97 ScriptState* script_state,
106 CustomElementRegistry* registry, 98 CustomElementRegistry* registry,
107 const CustomElementDescriptor& descriptor, 99 const CustomElementDescriptor& descriptor,
100 CustomElementDefinition::Id id,
108 const v8::Local<v8::Object>& constructor, 101 const v8::Local<v8::Object>& constructor,
109 const v8::Local<v8::Function>& connected_callback, 102 const v8::Local<v8::Function>& connected_callback,
110 const v8::Local<v8::Function>& disconnected_callback, 103 const v8::Local<v8::Function>& disconnected_callback,
111 const v8::Local<v8::Function>& adopted_callback, 104 const v8::Local<v8::Function>& adopted_callback,
112 const v8::Local<v8::Function>& attribute_changed_callback, 105 const v8::Local<v8::Function>& attribute_changed_callback,
113 const HashSet<AtomicString>& observed_attributes) { 106 const HashSet<AtomicString>& observed_attributes) {
114 ScriptCustomElementDefinition* definition = new ScriptCustomElementDefinition( 107 auto private_id =
108 script_state->PerContextData()->GetPrivateCustomElementDefinitionId();
109 CHECK(constructor
110 ->SetPrivate(
111 script_state->GetContext(), private_id,
112 v8::Integer::NewFromUnsigned(script_state->GetIsolate(), id))
113 .ToChecked());
114 return new ScriptCustomElementDefinition(
115 script_state, descriptor, constructor, connected_callback, 115 script_state, descriptor, constructor, connected_callback,
116 disconnected_callback, adopted_callback, attribute_changed_callback, 116 disconnected_callback, adopted_callback, attribute_changed_callback,
117 observed_attributes); 117 observed_attributes);
118
119 // Add a constructor -> name mapping to the registry.
120 v8::Local<v8::Value> name_value =
121 V8String(script_state->GetIsolate(), descriptor.GetName());
122 v8::Local<v8::Map> map =
123 EnsureCustomElementRegistryMap(script_state, registry);
124 map->Set(script_state->GetContext(), constructor, name_value)
125 .ToLocalChecked();
126 definition->constructor_.SetPhantom();
127
128 // We add the callbacks here to keep them alive. We use the name as
129 // the key because it is unique per-registry.
130 v8::Local<v8::Object> object = v8::Object::New(script_state->GetIsolate());
131 KeepAlive(object, V8PrivateProperty::GetCustomElementConnectedCallback,
132 connected_callback, definition->connected_callback_, script_state);
133 KeepAlive(object, V8PrivateProperty::GetCustomElementDisconnectedCallback,
134 disconnected_callback, definition->disconnected_callback_,
135 script_state);
136 KeepAlive(object, V8PrivateProperty::GetCustomElementAdoptedCallback,
137 adopted_callback, definition->adopted_callback_, script_state);
138 KeepAlive(object, V8PrivateProperty::GetCustomElementAttributeChangedCallback,
139 attribute_changed_callback, definition->attribute_changed_callback_,
140 script_state);
141 map->Set(script_state->GetContext(), name_value, object).ToLocalChecked();
142
143 return definition;
144 } 118 }
145 119
146 ScriptCustomElementDefinition::ScriptCustomElementDefinition( 120 ScriptCustomElementDefinition::ScriptCustomElementDefinition(
147 ScriptState* script_state, 121 ScriptState* script_state,
148 const CustomElementDescriptor& descriptor, 122 const CustomElementDescriptor& descriptor,
149 const v8::Local<v8::Object>& constructor, 123 const v8::Local<v8::Object>& constructor,
150 const v8::Local<v8::Function>& connected_callback, 124 const v8::Local<v8::Function>& connected_callback,
151 const v8::Local<v8::Function>& disconnected_callback, 125 const v8::Local<v8::Function>& disconnected_callback,
152 const v8::Local<v8::Function>& adopted_callback, 126 const v8::Local<v8::Function>& adopted_callback,
153 const v8::Local<v8::Function>& attribute_changed_callback, 127 const v8::Local<v8::Function>& attribute_changed_callback,
154 const HashSet<AtomicString>& observed_attributes) 128 const HashSet<AtomicString>& observed_attributes)
155 : CustomElementDefinition(descriptor, observed_attributes), 129 : CustomElementDefinition(descriptor, observed_attributes),
156 script_state_(script_state), 130 script_state_(script_state),
157 constructor_(script_state->GetIsolate(), constructor) {} 131 constructor_(script_state->GetIsolate(), this, constructor),
132 connected_callback_(this),
133 disconnected_callback_(this),
134 adopted_callback_(this),
135 attribute_changed_callback_(this) {
136 v8::Isolate* isolate = script_state->GetIsolate();
137 if (!connected_callback.IsEmpty())
138 connected_callback_.Set(isolate, connected_callback);
139 if (!disconnected_callback.IsEmpty())
140 disconnected_callback_.Set(isolate, disconnected_callback);
141 if (!adopted_callback.IsEmpty())
142 adopted_callback_.Set(isolate, adopted_callback);
143 if (!attribute_changed_callback.IsEmpty())
144 attribute_changed_callback_.Set(isolate, attribute_changed_callback);
145 }
158 146
159 static void DispatchErrorEvent(v8::Isolate* isolate, 147 static void DispatchErrorEvent(v8::Isolate* isolate,
160 v8::Local<v8::Value> exception, 148 v8::Local<v8::Value> exception,
161 v8::Local<v8::Object> constructor) { 149 v8::Local<v8::Object> constructor) {
162 v8::TryCatch try_catch(isolate); 150 v8::TryCatch try_catch(isolate);
163 try_catch.SetVerbose(true); 151 try_catch.SetVerbose(true);
164 V8ScriptRunner::ThrowException( 152 V8ScriptRunner::ThrowException(
165 isolate, exception, constructor.As<v8::Function>()->GetScriptOrigin()); 153 isolate, exception, constructor.As<v8::Function>()->GetScriptOrigin());
166 } 154 }
167 155
156 DEFINE_TRACE_WRAPPERS(ScriptCustomElementDefinition) {
157 visitor->TraceWrappers(constructor_);
158 visitor->TraceWrappers(connected_callback_);
Michael Lippautz 2017/04/19 08:49:12 Continued from the declaration: visitor->TraceW
159 visitor->TraceWrappers(disconnected_callback_);
160 visitor->TraceWrappers(adopted_callback_);
161 visitor->TraceWrappers(attribute_changed_callback_);
162 }
163
168 HTMLElement* ScriptCustomElementDefinition::HandleCreateElementSyncException( 164 HTMLElement* ScriptCustomElementDefinition::HandleCreateElementSyncException(
169 Document& document, 165 Document& document,
170 const QualifiedName& tag_name, 166 const QualifiedName& tag_name,
171 v8::Isolate* isolate, 167 v8::Isolate* isolate,
172 ExceptionState& exception_state) { 168 ExceptionState& exception_state) {
173 DCHECK(exception_state.HadException()); 169 DCHECK(exception_state.HadException());
174 // 6.1."If any of these subsubsteps threw an exception".1 170 // 6.1."If any of these subsubsteps threw an exception".1
175 // Report the exception. 171 // Report the exception.
176 DispatchErrorEvent(isolate, exception_state.GetException(), Constructor()); 172 DispatchErrorEvent(isolate, exception_state.GetException(), Constructor());
177 exception_state.ClearException(); 173 exception_state.ClearException();
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 if (!V8Call(V8ScriptRunner::CallAsConstructor(isolate, Constructor(), 273 if (!V8Call(V8ScriptRunner::CallAsConstructor(isolate, Constructor(),
278 execution_context, 0, nullptr), 274 execution_context, 0, nullptr),
279 result)) { 275 result)) {
280 return nullptr; 276 return nullptr;
281 } 277 }
282 return V8Element::toImplWithTypeCheck(isolate, result); 278 return V8Element::toImplWithTypeCheck(isolate, result);
283 } 279 }
284 280
285 v8::Local<v8::Object> ScriptCustomElementDefinition::Constructor() const { 281 v8::Local<v8::Object> ScriptCustomElementDefinition::Constructor() const {
286 DCHECK(!constructor_.IsEmpty()); 282 DCHECK(!constructor_.IsEmpty());
287 return constructor_.NewLocal(script_state_->GetIsolate()); 283 return constructor_.NewLocal(script_state_->GetIsolate()).As<v8::Object>();
Michael Lippautz 2017/04/19 08:49:12 This cast is not needed then. (And all below.)
288 } 284 }
289 285
290 // CustomElementDefinition 286 // CustomElementDefinition
291 ScriptValue ScriptCustomElementDefinition::GetConstructorForScript() { 287 ScriptValue ScriptCustomElementDefinition::GetConstructorForScript() {
292 return ScriptValue(script_state_.Get(), Constructor()); 288 return ScriptValue(script_state_.Get(), Constructor());
293 } 289 }
294 290
295 bool ScriptCustomElementDefinition::HasConnectedCallback() const { 291 bool ScriptCustomElementDefinition::HasConnectedCallback() const {
296 return !connected_callback_.IsEmpty(); 292 return !connected_callback_.IsEmpty();
297 } 293 }
(...skipping 26 matching lines...) Expand all
324 ToV8(element, script_state_->GetContext()->Global(), isolate); 320 ToV8(element, script_state_->GetContext()->Global(), isolate);
325 V8ScriptRunner::CallFunction(callback, execution_context, element_handle, 321 V8ScriptRunner::CallFunction(callback, execution_context, element_handle,
326 argc, argv, isolate); 322 argc, argv, isolate);
327 } 323 }
328 324
329 void ScriptCustomElementDefinition::RunConnectedCallback(Element* element) { 325 void ScriptCustomElementDefinition::RunConnectedCallback(Element* element) {
330 if (!script_state_->ContextIsValid()) 326 if (!script_state_->ContextIsValid())
331 return; 327 return;
332 ScriptState::Scope scope(script_state_.Get()); 328 ScriptState::Scope scope(script_state_.Get());
333 v8::Isolate* isolate = script_state_->GetIsolate(); 329 v8::Isolate* isolate = script_state_->GetIsolate();
334 RunCallback(connected_callback_.NewLocal(isolate), element); 330 RunCallback(connected_callback_.NewLocal(isolate).As<v8::Function>(),
331 element);
335 } 332 }
336 333
337 void ScriptCustomElementDefinition::RunDisconnectedCallback(Element* element) { 334 void ScriptCustomElementDefinition::RunDisconnectedCallback(Element* element) {
338 if (!script_state_->ContextIsValid()) 335 if (!script_state_->ContextIsValid())
339 return; 336 return;
340 ScriptState::Scope scope(script_state_.Get()); 337 ScriptState::Scope scope(script_state_.Get());
341 v8::Isolate* isolate = script_state_->GetIsolate(); 338 v8::Isolate* isolate = script_state_->GetIsolate();
342 RunCallback(disconnected_callback_.NewLocal(isolate), element); 339 RunCallback(disconnected_callback_.NewLocal(isolate).As<v8::Function>(),
340 element);
343 } 341 }
344 342
345 void ScriptCustomElementDefinition::RunAdoptedCallback(Element* element, 343 void ScriptCustomElementDefinition::RunAdoptedCallback(Element* element,
346 Document* old_owner, 344 Document* old_owner,
347 Document* new_owner) { 345 Document* new_owner) {
348 if (!script_state_->ContextIsValid()) 346 if (!script_state_->ContextIsValid())
349 return; 347 return;
350 ScriptState::Scope scope(script_state_.Get()); 348 ScriptState::Scope scope(script_state_.Get());
351 v8::Isolate* isolate = script_state_->GetIsolate(); 349 v8::Isolate* isolate = script_state_->GetIsolate();
352 v8::Local<v8::Value> argv[] = { 350 v8::Local<v8::Value> argv[] = {
353 ToV8(old_owner, script_state_->GetContext()->Global(), isolate), 351 ToV8(old_owner, script_state_->GetContext()->Global(), isolate),
354 ToV8(new_owner, script_state_->GetContext()->Global(), isolate)}; 352 ToV8(new_owner, script_state_->GetContext()->Global(), isolate)};
355 RunCallback(adopted_callback_.NewLocal(isolate), element, 353 RunCallback(adopted_callback_.NewLocal(isolate).As<v8::Function>(), element,
356 WTF_ARRAY_LENGTH(argv), argv); 354 WTF_ARRAY_LENGTH(argv), argv);
357 } 355 }
358 356
359 void ScriptCustomElementDefinition::RunAttributeChangedCallback( 357 void ScriptCustomElementDefinition::RunAttributeChangedCallback(
360 Element* element, 358 Element* element,
361 const QualifiedName& name, 359 const QualifiedName& name,
362 const AtomicString& old_value, 360 const AtomicString& old_value,
363 const AtomicString& new_value) { 361 const AtomicString& new_value) {
364 if (!script_state_->ContextIsValid()) 362 if (!script_state_->ContextIsValid())
365 return; 363 return;
366 ScriptState::Scope scope(script_state_.Get()); 364 ScriptState::Scope scope(script_state_.Get());
367 v8::Isolate* isolate = script_state_->GetIsolate(); 365 v8::Isolate* isolate = script_state_->GetIsolate();
368 v8::Local<v8::Value> argv[] = { 366 v8::Local<v8::Value> argv[] = {
369 V8String(isolate, name.LocalName()), V8StringOrNull(isolate, old_value), 367 V8String(isolate, name.LocalName()), V8StringOrNull(isolate, old_value),
370 V8StringOrNull(isolate, new_value), 368 V8StringOrNull(isolate, new_value),
371 V8StringOrNull(isolate, name.NamespaceURI()), 369 V8StringOrNull(isolate, name.NamespaceURI()),
372 }; 370 };
373 RunCallback(attribute_changed_callback_.NewLocal(isolate), element, 371 RunCallback(attribute_changed_callback_.NewLocal(isolate).As<v8::Function>(),
374 WTF_ARRAY_LENGTH(argv), argv); 372 element, WTF_ARRAY_LENGTH(argv), argv);
375 } 373 }
376 374
377 } // namespace blink 375 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698