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

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

Issue 2841443005: [Bindings] Create and use V8 context snapshots (Closed)
Patch Set: Work for some comments 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
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "bindings/core/v8/V8SnapshotCreator.h"
6
7 #include <cstring>
8
9 #include "bindings/core/v8/GeneratedCodeHelper.h"
10 #include "bindings/core/v8/V8Document.h"
11 #include "bindings/core/v8/V8HTMLDocument.h"
12 #include "bindings/core/v8/V8Initializer.h"
13 #include "bindings/core/v8/V8Node.h"
14 #include "bindings/core/v8/V8Window.h"
15 #include "platform/bindings/DOMWrapperWorld.h"
16 #include "platform/bindings/V8ObjectConstructor.h"
17 #include "platform/bindings/V8PerIsolateData.h"
18 #include "platform/bindings/V8PrivateProperty.h"
19 #include "v8/include/v8.h"
20
21 namespace blink {
22
23 namespace {
24
25 // This value must be accessed only on the main thread, and is
26 // true when the process (not a renderer) is to take a snapshot.
27 bool g_taking_snapshot = false;
haraken 2017/05/20 19:10:02 Shall we move this flag to gin/isolate_holder.h? T
peria 2017/05/30 08:25:44 Acknowledged.
28
29 intptr_t* g_snapshot_reference_table = nullptr;
30
31 // NOTE(peria): This method is almost a copy of
32 // V8PerContext::ConstructorForTypeSlowCase().
33 // TODO(peria): Merge with it.
34 v8::Local<v8::Function> ConstructPlainType(v8::Isolate* isolate,
35 const DOMWrapperWorld& world,
36 v8::Local<v8::Context> context,
37 const WrapperTypeInfo* type) {
38 v8::Context::Scope scope(context);
39 // We shouldn't reach this point for the types that are implemented in v8 such
40 // as typed arrays and hence don't have domTemplateFunction.
41 DCHECK(type->dom_template_function);
42 v8::Local<v8::FunctionTemplate> interface_template =
43 type->domTemplate(isolate, world);
44 // Getting the function might fail if we're running out of stack or memory.
45 v8::Local<v8::Function> interface_object;
46 if (!interface_template->GetFunction(context).ToLocal(&interface_object))
47 return v8::Local<v8::Function>();
48
49 if (type->parent_class) {
50 v8::Local<v8::Object> prototype_template =
51 ConstructPlainType(isolate, world, context, type->parent_class);
52 CHECK(interface_object->SetPrototype(context, prototype_template)
53 .ToChecked());
54 }
55
56 v8::Local<v8::Value> prototype_value;
57 CHECK(interface_object->Get(context, V8AtomicString(isolate, "prototype"))
58 .ToLocal(&prototype_value));
59 CHECK(prototype_value->IsObject());
60 v8::Local<v8::Object> prototype_object = prototype_value.As<v8::Object>();
61 if (prototype_object->InternalFieldCount() ==
62 kV8PrototypeInternalFieldcount &&
63 type->wrapper_type_prototype ==
64 WrapperTypeInfo::kWrapperTypeObjectPrototype) {
65 prototype_object->SetAlignedPointerInInternalField(
66 kV8PrototypeTypeIndex, const_cast<WrapperTypeInfo*>(type));
67 }
68 type->PreparePrototypeAndInterfaceObject(
69 context, world, prototype_object, interface_object, interface_template);
70
71 return interface_object;
72 }
73
74 // NOTE(peria): This method is almost a copy of
75 // V8PerContext::CreateWrapperFromCacheSlowCase().
76 // TODO(peria): Merge with it.
77 v8::Local<v8::Object> CreatePlainWrapper(v8::Isolate* isolate,
78 const DOMWrapperWorld& world,
79 v8::Local<v8::Context> context,
80 const WrapperTypeInfo* type) {
81 CHECK(V8HTMLDocument::wrapperTypeInfo.Equals(type));
82
83 v8::Context::Scope scope(context);
84 v8::Local<v8::Function> interface_object =
85 ConstructPlainType(isolate, world, context, type);
86 CHECK(!interface_object.IsEmpty());
87 v8::Local<v8::Object> instance_template;
88 CHECK(V8ObjectConstructor::NewInstance(isolate, interface_object)
89 .ToLocal(&instance_template));
90 v8::Local<v8::Object> wrapper = instance_template->Clone();
91 wrapper->SetAlignedPointerInInternalField(kV8DOMWrapperTypeIndex,
92 const_cast<WrapperTypeInfo*>(type));
93 return wrapper;
94 }
95
96 int GetSnapshotIndexForWorld(const DOMWrapperWorld& world) {
97 return world.IsMainWorld() ? 0 : 1;
98 }
99
100 constexpr const WrapperTypeInfo* kSnapshotWrapperTypes[] = {
101 &V8EventTarget::wrapperTypeInfo, &V8Window::wrapperTypeInfo,
102 &V8Node::wrapperTypeInfo, &V8Document::wrapperTypeInfo,
103 &V8HTMLDocument::wrapperTypeInfo,
104 };
105
106 enum class InternalFieldType : uint8_t {
107 kNone,
108 kNodeType,
109 kDocumentType,
110 kHTMLDocumentType,
111 kHTMLDocumentObject,
112 };
113
114 const WrapperTypeInfo* FieldTypeToWrapperTypeInfo(InternalFieldType type) {
115 switch (type) {
116 case InternalFieldType::kNodeType:
117 return &V8Node::wrapperTypeInfo;
118 case InternalFieldType::kDocumentType:
119 return &V8Document::wrapperTypeInfo;
120 case InternalFieldType::kHTMLDocumentType:
121 return &V8HTMLDocument::wrapperTypeInfo;
122 case InternalFieldType::kHTMLDocumentObject:
123 return &V8HTMLDocument::wrapperTypeInfo;
124 case InternalFieldType::kNone:
125 NOTREACHED();
126 break;
127 }
128 NOTREACHED();
129 return nullptr;
130 }
131
132 } // namespace
133
134 void V8SnapshotCreator::TakeSnapshotForWorld(v8::SnapshotCreator* creator,
135 const DOMWrapperWorld& world) {
136 CHECK(TakingSnapshot());
137 v8::Isolate* isolate = creator->GetIsolate();
138 CHECK_EQ(isolate, v8::Isolate::GetCurrent());
139
140 // Function templates
141 v8::HandleScope handleScope(isolate);
142 Vector<v8::Local<v8::FunctionTemplate>> interface_templates;
143 for (const WrapperTypeInfo* wrapper_type_info : kSnapshotWrapperTypes) {
144 v8::Local<v8::FunctionTemplate> interface_template =
145 wrapper_type_info->domTemplate(isolate, world);
146 CHECK(!interface_template.IsEmpty());
147 interface_templates.push_back(interface_template);
148 }
149
150 // FIXME: Confirm interface_tempaltes[1] is a template of V8Window.
151 v8::Local<v8::ObjectTemplate> window_template =
152 interface_templates[1]->InstanceTemplate();
153 CHECK(!window_template.IsEmpty());
154
155 v8::Local<v8::Context> context;
156 {
157 V8PerIsolateData::UseCounterDisabledScope use_counter_disabled(
158 V8PerIsolateData::From(isolate));
159 context = v8::Context::New(isolate, nullptr, window_template);
160 }
161 CHECK(!context.IsEmpty());
162
163 if (world.IsMainWorld()) {
164 context->Enter();
165 v8::Context::Scope scope(context);
166 v8::Local<v8::Object> document_wrapper = CreatePlainWrapper(
167 isolate, world, context, &V8HTMLDocument::wrapperTypeInfo);
168 int indices[] = {kV8DOMWrapperObjectIndex, kV8DOMWrapperTypeIndex};
169 void* values[] = {nullptr, const_cast<WrapperTypeInfo*>(
170 &V8HTMLDocument::wrapperTypeInfo)};
171 document_wrapper->SetAlignedPointerInInternalFields(
172 WTF_ARRAY_LENGTH(indices), indices, values);
173
174 // Update the cached accessor for window.document.
175 CHECK(V8PrivateProperty::GetWindowDocumentCachedAccessor(isolate).Set(
176 context->Global(), document_wrapper));
177 context->Exit();
178 }
179
180 for (auto& interface_template : interface_templates) {
181 creator->AddTemplate(interface_template);
182 }
183 creator->AddContext(context, SerializeInternalField);
184
185 V8PerIsolateData::From(isolate)->ClearPersistents();
186
187 // Snapshot is taken on the main thread, but it can be used on other threads.
188 // So we remove a message handler for the main thread.
189 isolate->RemoveMessageListeners(V8Initializer::MessageHandlerInMainThread);
190 }
191
192 v8::StartupData V8SnapshotCreator::TakeSnapshot(v8::SnapshotCreator* creator) {
193 v8::Isolate* isolate = creator->GetIsolate();
194 CHECK_EQ(isolate, v8::Isolate::GetCurrent());
195
196 // Disable all runtime enabled featuers
197 RuntimeEnabledFeatures::setStableFeaturesEnabled(false);
198 RuntimeEnabledFeatures::setExperimentalFeaturesEnabled(false);
199 RuntimeEnabledFeatures::setTestFeaturesEnabled(false);
200
201 {
202 v8::HandleScope handleScope(isolate);
203 creator->SetDefaultContext(v8::Context::New(isolate));
204
205 TakeSnapshotForWorld(creator, DOMWrapperWorld::MainWorld());
206 // For non main worlds, we can use any type to create a context.
207 TakeSnapshotForWorld(creator,
208 *DOMWrapperWorld::Create(
209 isolate, DOMWrapperWorld::WorldType::kTesting));
210 }
211
212 return creator->CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
213 }
214
215 void V8SnapshotCreator::EnsureInterfaceTemplates(v8::Isolate* isolate,
216 const DOMWrapperWorld& world) {
217 if (V8PerIsolateData::From(isolate)->GetV8ContextMode() !=
218 gin::IsolateHolder::kUseSnapshot) {
219 return;
220 }
221
222 // TODO(peria): Skip this method if all templates are already created.
223 for (const WrapperTypeInfo* wrapper_type_info : kSnapshotWrapperTypes) {
224 v8::Local<v8::FunctionTemplate> interface =
225 wrapper_type_info->domTemplate(isolate, world);
226 CHECK(!interface.IsEmpty());
227 }
228 }
229
230 v8::Local<v8::FunctionTemplate> V8SnapshotCreator::CreateInterfaceTemplate(
231 v8::Isolate* isolate,
232 const DOMWrapperWorld& world,
233 WrapperTypeInfo* wrapper_type_info) {
234 if (V8PerIsolateData::From(isolate)->GetV8ContextMode() !=
235 gin::IsolateHolder::kUseSnapshot) {
236 return v8::Local<v8::FunctionTemplate>();
237 }
238
239 const int index_offset =
240 world.IsMainWorld() ? 0 : WTF_ARRAY_LENGTH(kSnapshotWrapperTypes);
241
242 // Snapshotted templates are expected to be used just to get
243 // wrapper_type_info.
244 for (size_t i = 0; i < WTF_ARRAY_LENGTH(kSnapshotWrapperTypes); ++i) {
245 if (kSnapshotWrapperTypes[i]->Equals(wrapper_type_info)) {
246 return v8::FunctionTemplate::FromSnapshot(isolate, index_offset + i)
247 .ToLocalChecked();
248 }
249 }
250 return v8::Local<v8::FunctionTemplate>();
251 }
252
253 v8::SnapshotCreator* V8SnapshotCreator::GetSnapshotCreator() {
254 CHECK(TakingSnapshot());
255 return V8PerIsolateData::From(V8PerIsolateData::MainThreadIsolate())
256 ->GetSnapshotCreator();
257 }
258
259 bool V8SnapshotCreator::TakingSnapshot() {
260 // CHECK(IsMainThread());
261 return g_taking_snapshot;
262 }
263
264 void V8SnapshotCreator::SetTakingSnapshot(bool value) {
265 // CHECK(IsMainThread());
266 g_taking_snapshot = value;
267 }
268
269 v8::StartupData V8SnapshotCreator::SerializeInternalField(
270 v8::Local<v8::Object> holder,
271 int index,
272 void* /*data*/) {
273 InternalFieldType field_type = InternalFieldType::kNone;
274 const WrapperTypeInfo* wrapper_type = ToWrapperTypeInfo(holder);
275 if (kV8DOMWrapperObjectIndex == index) {
276 if (blink::V8HTMLDocument::wrapperTypeInfo.Equals(wrapper_type)) {
277 field_type = InternalFieldType::kHTMLDocumentObject;
278 }
279 } else if (kV8DOMWrapperTypeIndex == index) {
280 if (blink::V8HTMLDocument::wrapperTypeInfo.Equals(wrapper_type)) {
281 field_type = InternalFieldType::kHTMLDocumentType;
282 } else if (blink::V8Document::wrapperTypeInfo.Equals(wrapper_type)) {
283 field_type = InternalFieldType::kDocumentType;
284 } else if (blink::V8Node::wrapperTypeInfo.Equals(wrapper_type)) {
285 field_type = InternalFieldType::kNodeType;
286 }
287 }
288
289 // To confirm covering all patterns to be serialized.
290 CHECK_NE(field_type, InternalFieldType::kNone);
291
292 int size = sizeof(InternalFieldType);
293 char* data = new char[size];
294 std::memcpy(data, &field_type, size);
295
296 return {data, size};
297 }
298
299 void V8SnapshotCreator::DeserializeInternalField(v8::Local<v8::Object> wrapper,
300 int index,
301 v8::StartupData payload,
302 void* ptr) {
303 CHECK_EQ(payload.raw_size, static_cast<int>(sizeof(InternalFieldType)));
304 InternalFieldType type =
305 *reinterpret_cast<const InternalFieldType*>(payload.data);
306
307 const WrapperTypeInfo* wrapper_type_info = FieldTypeToWrapperTypeInfo(type);
308 switch (type) {
309 case InternalFieldType::kNodeType:
310 case InternalFieldType::kDocumentType:
311 case InternalFieldType::kHTMLDocumentType: {
312 CHECK_EQ(index, kV8DOMWrapperTypeIndex);
313 wrapper->SetAlignedPointerInInternalField(
314 index, const_cast<WrapperTypeInfo*>(wrapper_type_info));
315 wrapper_type_info->WrapperCreated();
316 return;
317 }
318 case InternalFieldType::kHTMLDocumentObject: {
319 CHECK_EQ(index, kV8DOMWrapperObjectIndex);
320 v8::Isolate* isolate = v8::Isolate::GetCurrent();
321 DataForDeserializer* data = static_cast<DataForDeserializer*>(ptr);
322 ScriptWrappable* document = data->document;
323
324 // Make reference from wrapper to document
325 wrapper->SetAlignedPointerInInternalField(index, document);
326 // Make reference from document to wrapper
327 CHECK(document->SetWrapper(isolate, wrapper_type_info, wrapper));
328 return;
329 }
330 case InternalFieldType::kNone:
331 NOTREACHED();
332 return;
333 }
334
335 NOTREACHED();
336 }
337
338 v8::Local<v8::Context> V8SnapshotCreator::CreateContext(
339 v8::Isolate* isolate,
340 const DOMWrapperWorld& world,
341 v8::ExtensionConfiguration* extension_configuration,
342 v8::Local<v8::Object> global_proxy,
343 Document* document) {
344 if (V8PerIsolateData::From(isolate)->GetV8ContextMode() !=
345 gin::IsolateHolder::kUseSnapshot) {
346 return v8::Local<v8::Context>();
347 }
348 if (world.IsMainWorld() && !(document && document->IsHTMLDocument())) {
349 return v8::Local<v8::Context>();
350 }
351
352 v8::Local<v8::Context> context;
353 const int index = GetSnapshotIndexForWorld(world);
354 DataForDeserializer data{document};
355 CHECK(v8::Context::FromSnapshot(isolate, index,
356 v8::DeserializeInternalFieldsCallback(
357 &DeserializeInternalField, &data),
358 extension_configuration, global_proxy)
359 .ToLocal(&context));
360
361 return context;
362 }
363
364 void V8SnapshotCreator::InstallRuntimeEnabledFeaturesOnDocument(
365 ScriptState* script_state,
366 v8::Local<v8::Object> wrapper) {
367 v8::Isolate* isolate = script_state->GetIsolate();
368 if (V8PerIsolateData::From(isolate)->GetV8ContextMode() !=
369 gin::IsolateHolder::kUseSnapshot) {
370 return;
371 }
372
373 v8::Local<v8::Context> context = script_state->GetContext();
374 DOMWrapperWorld& world = script_state->World();
375
376 v8::Local<v8::Object> htmldocument_prototype =
377 wrapper->GetPrototype().As<v8::Object>();
378 v8::Local<v8::Function> htmldocument_interface =
379 V8HTMLDocument::domTemplate(isolate, world)->GetFunction();
380 V8HTMLDocument::installRuntimeEnabledFeatures(
381 isolate, world, wrapper, htmldocument_prototype, htmldocument_interface);
382
383 v8::Local<v8::Object> document_prototype =
384 htmldocument_prototype->GetPrototype().As<v8::Object>();
385 v8::Local<v8::Function> document_interface =
386 V8Document::domTemplate(isolate, world)->GetFunction();
387 V8Document::installRuntimeEnabledFeatures(
388 isolate, world, wrapper, document_prototype, document_interface);
389
390 V8Document::preparePrototypeAndInterfaceObject(
391 context, world, document_prototype, document_interface,
392 v8::Local<v8::FunctionTemplate>());
393 }
394
395 void V8SnapshotCreator::InstallRuntimeEnabledFeaturesOnGlobal(
396 ScriptState* script_state,
397 v8::Local<v8::Object> global) {
398 v8::Isolate* isolate = script_state->GetIsolate();
399 if (V8PerIsolateData::From(isolate)->GetV8ContextMode() !=
400 gin::IsolateHolder::kUseSnapshot) {
401 return;
402 }
403
404 DOMWrapperWorld& world = script_state->World();
405
406 v8::Local<v8::Object> window_prototype =
407 global->GetPrototype().As<v8::Object>();
408 v8::Local<v8::Function> window_interface =
409 V8Window::domTemplate(isolate, world)->GetFunction();
410 V8Window::installV8WindowRuntimeEnabledFunction(
411 isolate, world, global, window_prototype, window_interface);
412 }
413
414 void V8SnapshotCreator::SetReferenceTable(intptr_t* table) {
415 g_snapshot_reference_table = table;
416 }
417
418 intptr_t* V8SnapshotCreator::GetReferenceTable() {
419 return g_snapshot_reference_table;
420 }
421
422 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698