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

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

Issue 2828643002: Make customElements.define faster
Patch Set: Remove some unneeded casts. Created 3 years, 7 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/V8BindingForCore.h" 8 #include "bindings/core/v8/V8BindingForCore.h"
9 #include "bindings/core/v8/V8BindingMacros.h" 9 #include "bindings/core/v8/V8BindingMacros.h"
10 #include "bindings/core/v8/V8CustomElementRegistry.h"
11 #include "bindings/core/v8/V8Element.h" 10 #include "bindings/core/v8/V8Element.h"
12 #include "bindings/core/v8/V8ErrorHandler.h"
13 #include "bindings/core/v8/V8PrivateProperty.h"
14 #include "bindings/core/v8/V8ScriptRunner.h" 11 #include "bindings/core/v8/V8ScriptRunner.h"
15 #include "bindings/core/v8/V8ThrowDOMException.h" 12 #include "bindings/core/v8/V8ThrowDOMException.h"
16 #include "core/dom/ExceptionCode.h" 13 #include "core/dom/ExceptionCode.h"
17 #include "core/dom/ExecutionContext.h" 14 #include "core/dom/ExecutionContext.h"
18 #include "core/dom/custom/CustomElement.h" 15 #include "core/dom/custom/CustomElement.h"
16 #include "core/dom/custom/CustomElementRegistry.h"
19 #include "core/events/ErrorEvent.h" 17 #include "core/events/ErrorEvent.h"
20 #include "core/html/HTMLElement.h" 18 #include "core/html/HTMLElement.h"
21 #include "core/html/imports/HTMLImportsController.h" 19 #include "core/html/imports/HTMLImportsController.h"
22 #include "platform/wtf/Allocator.h" 20 #include "platform/wtf/Allocator.h"
23 #include "v8.h" 21 #include "v8.h"
24 22
25 namespace blink { 23 namespace blink {
26 24
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( 25 ScriptCustomElementDefinition* ScriptCustomElementDefinition::ForConstructor(
47 ScriptState* script_state, 26 ScriptState* script_state,
48 CustomElementRegistry* registry, 27 CustomElementRegistry* registry,
49 const v8::Local<v8::Value>& constructor) { 28 const v8::Local<v8::Value>& constructor) {
50 v8::Local<v8::Map> map = 29 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; 30 return nullptr;
56 AtomicString name = ToCoreAtomicString(name_value.As<v8::String>()); 31 auto private_id =
32 script_state->PerContextData()->GetPrivateCustomElementDefinitionId();
33 v8::Local<v8::Value> id_value;
34 if (!constructor.As<v8::Object>()
35 ->GetPrivate(script_state->GetContext(), private_id)
36 .ToLocal(&id_value))
37 return nullptr;
38 if (!id_value->IsUint32())
39 return nullptr;
40 uint32_t id = id_value.As<v8::Uint32>()->Value();
57 41
58 // This downcast is safe because only 42 // This downcast is safe because only ScriptCustomElementDefinitions
59 // ScriptCustomElementDefinitions have a name associated with a V8 43 // have a ID associated with a V8 constructor; see
60 // constructor in the map; see
61 // ScriptCustomElementDefinition::create. This relies on three 44 // ScriptCustomElementDefinition::create. This relies on three
62 // things: 45 // things:
63 // 46 //
64 // 1. Only ScriptCustomElementDefinition adds entries to the map. 47 // 1. Only ScriptCustomElementDefinition sets the private property
65 // Audit the use of private properties in general and how the 48 // on a constructor.
66 // map is handled--it should never be leaked to script.
67 // 49 //
68 // 2. CustomElementRegistry does not overwrite definitions with a 50 // 2. CustomElementRegistry adds ScriptCustomElementDefinitions
69 // given name--see the CHECK in CustomElementRegistry::define 51 // assigned an ID to the list of definitions without fail.
70 // --and adds ScriptCustomElementDefinitions to the map without
71 // fail.
72 // 52 //
73 // 3. The relationship between the CustomElementRegistry and its 53 // 3. The relationship between the CustomElementRegistry and its
74 // map is never mixed up; this is guaranteed by the bindings 54 // private property is never mixed up; this is guaranteed by the
75 // system which provides a stable wrapper, and the map hangs 55 // bindings system because the registry is associated with its
76 // off the wrapper. 56 // context.
77 // 57 //
78 // At a meta-level, this downcast is safe because there is 58 // At a meta-level, this downcast is safe because there is
79 // currently only one implementation of CustomElementDefinition in 59 // currently only one implementation of CustomElementDefinition in
80 // product code and that is ScriptCustomElementDefinition. But 60 // product code and that is ScriptCustomElementDefinition. But
81 // that may change in the future. 61 // that may change in the future.
82 CustomElementDefinition* definition = registry->DefinitionForName(name); 62 CustomElementDefinition* definition = registry->DefinitionForId(id);
83 CHECK(definition); 63 CHECK(definition);
84 return static_cast<ScriptCustomElementDefinition*>(definition); 64 ScriptCustomElementDefinition* scriptDefinition =
85 } 65 static_cast<ScriptCustomElementDefinition*>(definition);
86 66 // v8::Object::GetPrivate notes that private properties may be
87 using SymbolGetter = V8PrivateProperty::Symbol (*)(v8::Isolate*); 67 // inherited in future, so check that the definition's constructor
88 68 // is exactly the passed object.
89 template <typename T> 69 return scriptDefinition->constructor_.Get() == constructor ? scriptDefinition
90 static void KeepAlive(v8::Local<v8::Object>& object, 70 : nullptr;
91 SymbolGetter symbol_getter,
92 const v8::Local<T>& value,
93 ScopedPersistent<T>& persistent,
94 ScriptState* script_state) {
95 if (value.IsEmpty())
96 return;
97
98 v8::Isolate* isolate = script_state->GetIsolate();
99 symbol_getter(isolate).Set(object, value);
100 persistent.Set(isolate, value);
101 persistent.SetPhantom();
102 } 71 }
103 72
104 ScriptCustomElementDefinition* ScriptCustomElementDefinition::Create( 73 ScriptCustomElementDefinition* ScriptCustomElementDefinition::Create(
105 ScriptState* script_state, 74 ScriptState* script_state,
106 CustomElementRegistry* registry, 75 CustomElementRegistry* registry,
107 const CustomElementDescriptor& descriptor, 76 const CustomElementDescriptor& descriptor,
77 CustomElementDefinition::Id id,
108 const v8::Local<v8::Object>& constructor, 78 const v8::Local<v8::Object>& constructor,
109 const v8::Local<v8::Function>& connected_callback, 79 const v8::Local<v8::Function>& connected_callback,
110 const v8::Local<v8::Function>& disconnected_callback, 80 const v8::Local<v8::Function>& disconnected_callback,
111 const v8::Local<v8::Function>& adopted_callback, 81 const v8::Local<v8::Function>& adopted_callback,
112 const v8::Local<v8::Function>& attribute_changed_callback, 82 const v8::Local<v8::Function>& attribute_changed_callback,
113 const HashSet<AtomicString>& observed_attributes) { 83 HashSet<AtomicString>&& observed_attributes) {
114 ScriptCustomElementDefinition* definition = new ScriptCustomElementDefinition( 84 auto private_id =
85 script_state->PerContextData()->GetPrivateCustomElementDefinitionId();
86 CHECK(constructor
87 ->SetPrivate(
88 script_state->GetContext(), private_id,
89 v8::Integer::NewFromUnsigned(script_state->GetIsolate(), id))
90 .ToChecked());
91 return new ScriptCustomElementDefinition(
115 script_state, descriptor, constructor, connected_callback, 92 script_state, descriptor, constructor, connected_callback,
116 disconnected_callback, adopted_callback, attribute_changed_callback, 93 disconnected_callback, adopted_callback, attribute_changed_callback,
117 observed_attributes); 94 std::move(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 } 95 }
145 96
146 ScriptCustomElementDefinition::ScriptCustomElementDefinition( 97 ScriptCustomElementDefinition::ScriptCustomElementDefinition(
147 ScriptState* script_state, 98 ScriptState* script_state,
148 const CustomElementDescriptor& descriptor, 99 const CustomElementDescriptor& descriptor,
149 const v8::Local<v8::Object>& constructor, 100 const v8::Local<v8::Object>& constructor,
150 const v8::Local<v8::Function>& connected_callback, 101 const v8::Local<v8::Function>& connected_callback,
151 const v8::Local<v8::Function>& disconnected_callback, 102 const v8::Local<v8::Function>& disconnected_callback,
152 const v8::Local<v8::Function>& adopted_callback, 103 const v8::Local<v8::Function>& adopted_callback,
153 const v8::Local<v8::Function>& attribute_changed_callback, 104 const v8::Local<v8::Function>& attribute_changed_callback,
154 const HashSet<AtomicString>& observed_attributes) 105 HashSet<AtomicString>&& observed_attributes)
155 : CustomElementDefinition(descriptor, observed_attributes), 106 : CustomElementDefinition(descriptor, std::move(observed_attributes)),
156 script_state_(script_state), 107 script_state_(script_state),
157 constructor_(script_state->GetIsolate(), constructor) {} 108 constructor_(script_state->GetIsolate(), this, constructor),
109 connected_callback_(this),
110 disconnected_callback_(this),
111 adopted_callback_(this),
112 attribute_changed_callback_(this) {
113 v8::Isolate* isolate = script_state->GetIsolate();
114 if (!connected_callback.IsEmpty())
115 connected_callback_.Set(isolate, connected_callback);
116 if (!disconnected_callback.IsEmpty())
117 disconnected_callback_.Set(isolate, disconnected_callback);
118 if (!adopted_callback.IsEmpty())
119 adopted_callback_.Set(isolate, adopted_callback);
120 if (!attribute_changed_callback.IsEmpty())
121 attribute_changed_callback_.Set(isolate, attribute_changed_callback);
122 }
158 123
159 static void DispatchErrorEvent(v8::Isolate* isolate, 124 static void DispatchErrorEvent(v8::Isolate* isolate,
160 v8::Local<v8::Value> exception, 125 v8::Local<v8::Value> exception,
161 v8::Local<v8::Object> constructor) { 126 v8::Local<v8::Object> constructor) {
162 v8::TryCatch try_catch(isolate); 127 v8::TryCatch try_catch(isolate);
163 try_catch.SetVerbose(true); 128 try_catch.SetVerbose(true);
164 V8ScriptRunner::ThrowException( 129 V8ScriptRunner::ThrowException(
165 isolate, exception, constructor.As<v8::Function>()->GetScriptOrigin()); 130 isolate, exception, constructor.As<v8::Function>()->GetScriptOrigin());
166 } 131 }
167 132
133 DEFINE_TRACE_WRAPPERS(ScriptCustomElementDefinition) {
134 visitor->TraceWrappers(constructor_.Cast<v8::Value>());
haraken 2017/04/28 08:49:30 Won't visitor->TraceWrappers(constructor_) work?
135 visitor->TraceWrappers(connected_callback_.Cast<v8::Value>());
136 visitor->TraceWrappers(disconnected_callback_.Cast<v8::Value>());
137 visitor->TraceWrappers(adopted_callback_.Cast<v8::Value>());
138 visitor->TraceWrappers(attribute_changed_callback_.Cast<v8::Value>());
139 }
140
168 HTMLElement* ScriptCustomElementDefinition::HandleCreateElementSyncException( 141 HTMLElement* ScriptCustomElementDefinition::HandleCreateElementSyncException(
169 Document& document, 142 Document& document,
170 const QualifiedName& tag_name, 143 const QualifiedName& tag_name,
171 v8::Isolate* isolate, 144 v8::Isolate* isolate,
172 ExceptionState& exception_state) { 145 ExceptionState& exception_state) {
173 DCHECK(exception_state.HadException()); 146 DCHECK(exception_state.HadException());
174 // 6.1."If any of these subsubsteps threw an exception".1 147 // 6.1."If any of these subsubsteps threw an exception".1
175 // Report the exception. 148 // Report the exception.
176 DispatchErrorEvent(isolate, exception_state.GetException(), Constructor()); 149 DispatchErrorEvent(isolate, exception_state.GetException(), Constructor());
177 exception_state.ClearException(); 150 exception_state.ClearException();
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 v8::Local<v8::Value> argv[] = { 341 v8::Local<v8::Value> argv[] = {
369 V8String(isolate, name.LocalName()), V8StringOrNull(isolate, old_value), 342 V8String(isolate, name.LocalName()), V8StringOrNull(isolate, old_value),
370 V8StringOrNull(isolate, new_value), 343 V8StringOrNull(isolate, new_value),
371 V8StringOrNull(isolate, name.NamespaceURI()), 344 V8StringOrNull(isolate, name.NamespaceURI()),
372 }; 345 };
373 RunCallback(attribute_changed_callback_.NewLocal(isolate), element, 346 RunCallback(attribute_changed_callback_.NewLocal(isolate), element,
374 WTF_ARRAY_LENGTH(argv), argv); 347 WTF_ARRAY_LENGTH(argv), argv);
375 } 348 }
376 349
377 } // namespace blink 350 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698