Chromium Code Reviews| Index: third_party/WebKit/Source/bindings/core/v8/V8SnapshotUtil.cpp |
| diff --git a/third_party/WebKit/Source/bindings/core/v8/V8SnapshotUtil.cpp b/third_party/WebKit/Source/bindings/core/v8/V8SnapshotUtil.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..7be4228905ef5083414b17cf15c3aa2a499f0de9 |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/bindings/core/v8/V8SnapshotUtil.cpp |
| @@ -0,0 +1,498 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "bindings/core/v8/V8SnapshotUtil.h" |
| + |
| +#include <cstring> |
| + |
| +#include "bindings/core/v8/GeneratedCodeHelper.h" |
| +#include "bindings/core/v8/V8Document.h" |
| +#include "bindings/core/v8/V8EventTarget.h" |
| +#include "bindings/core/v8/V8HTMLDocument.h" |
| +#include "bindings/core/v8/V8Initializer.h" |
| +#include "bindings/core/v8/V8Node.h" |
| +#include "bindings/core/v8/V8Window.h" |
| +#include "platform/bindings/DOMWrapperWorld.h" |
| +#include "platform/bindings/V8ObjectConstructor.h" |
| +#include "platform/bindings/V8PerIsolateData.h" |
| +#include "platform/bindings/V8PrivateProperty.h" |
| +#include "v8/include/v8.h" |
| + |
| +namespace blink { |
| + |
| +namespace { |
| + |
| +intptr_t* g_snapshot_reference_table = nullptr; |
| + |
| +// TODO(peria): This method is almost a copy of |
| +// V8PerContext::ConstructorForTypeSlowCase(), so merge with it. |
| +v8::Local<v8::Function> ConstructPlainType(v8::Isolate* isolate, |
| + const DOMWrapperWorld& world, |
| + v8::Local<v8::Context> context, |
| + const WrapperTypeInfo* type) { |
| + v8::Context::Scope scope(context); |
| + // We shouldn't reach this point for the types that are implemented in v8 such |
| + // as typed arrays and hence don't have domTemplateFunction. |
| + DCHECK(type->dom_template_function); |
| + v8::Local<v8::FunctionTemplate> interface_template = |
| + type->domTemplate(isolate, world); |
| + // Getting the function might fail if we're running out of stack or memory. |
| + v8::Local<v8::Function> interface_object; |
| + if (!interface_template->GetFunction(context).ToLocal(&interface_object)) |
|
Yuki
2017/06/23 15:20:45
s/ToLocal/ToLocalChecked/
peria
2017/06/27 09:52:37
Done.
|
| + return v8::Local<v8::Function>(); |
| + |
| + if (type->parent_class) { |
| + v8::Local<v8::Object> prototype_template = |
| + ConstructPlainType(isolate, world, context, type->parent_class); |
| + CHECK(interface_object->SetPrototype(context, prototype_template) |
| + .ToChecked()); |
| + } |
| + |
| + v8::Local<v8::Value> prototype_value; |
| + CHECK(interface_object->Get(context, V8AtomicString(isolate, "prototype")) |
| + .ToLocal(&prototype_value)); |
|
Yuki
2017/06/23 15:20:44
s/CHECK(...ToLocal(...))/ToLocalChecked()/
peria
2017/06/27 09:52:37
Done.
|
| + CHECK(prototype_value->IsObject()); |
| + v8::Local<v8::Object> prototype_object = prototype_value.As<v8::Object>(); |
| + if (prototype_object->InternalFieldCount() == |
| + kV8PrototypeInternalFieldcount && |
| + type->wrapper_type_prototype == |
| + WrapperTypeInfo::kWrapperTypeObjectPrototype) { |
| + prototype_object->SetAlignedPointerInInternalField( |
| + kV8PrototypeTypeIndex, const_cast<WrapperTypeInfo*>(type)); |
| + } |
| + type->PreparePrototypeAndInterfaceObject( |
| + context, world, prototype_object, interface_object, interface_template); |
| + |
| + return interface_object; |
| +} |
| + |
| +// TODO(peria): This method is almost a copy of |
| +// V8PerContext::CreateWrapperFromCacheSlowCase(), so merge with it. |
| +v8::Local<v8::Object> CreatePlainWrapper(v8::Isolate* isolate, |
| + const DOMWrapperWorld& world, |
| + v8::Local<v8::Context> context, |
| + const WrapperTypeInfo* type) { |
| + CHECK(V8HTMLDocument::wrapperTypeInfo.Equals(type)); |
| + |
| + v8::Context::Scope scope(context); |
| + v8::Local<v8::Function> interface_object = |
| + ConstructPlainType(isolate, world, context, type); |
| + CHECK(!interface_object.IsEmpty()); |
| + v8::Local<v8::Object> instance_template; |
| + CHECK(V8ObjectConstructor::NewInstance(isolate, interface_object) |
| + .ToLocal(&instance_template)); |
|
Yuki
2017/06/23 15:20:44
s/CHECK(...ToLocal(...))/ToLocalChecked()/
peria
2017/06/27 09:52:37
Done.
|
| + v8::Local<v8::Object> wrapper = instance_template->Clone(); |
| + wrapper->SetAlignedPointerInInternalField(kV8DOMWrapperTypeIndex, |
| + const_cast<WrapperTypeInfo*>(type)); |
| + return wrapper; |
| +} |
| + |
| +constexpr int kWorldIdForNonMainWorld = |
| + DOMWrapperWorld::WorldId::kIsolatedWorldIdLimit - 1; |
| + |
| +int GetSnapshotIndexForWorld(const DOMWrapperWorld& world) { |
| + return world.IsMainWorld() ? 0 : 1; |
| +} |
| + |
| +constexpr const WrapperTypeInfo* kSnapshotWrapperTypes[] = { |
| + &V8Window::wrapperTypeInfo, &V8HTMLDocument::wrapperTypeInfo, |
| + &V8EventTarget::wrapperTypeInfo, &V8Node::wrapperTypeInfo, |
| + &V8Document::wrapperTypeInfo, |
| +}; |
| + |
| +enum class InternalFieldType : uint8_t { |
| + kNone, |
| + kNodeType, |
| + kDocumentType, |
| + kHTMLDocumentType, |
| + kHTMLDocumentObject, |
| +}; |
| + |
| +const WrapperTypeInfo* FieldTypeToWrapperTypeInfo(InternalFieldType type) { |
| + switch (type) { |
| + case InternalFieldType::kNone: |
| + NOTREACHED(); |
| + break; |
| + case InternalFieldType::kNodeType: |
| + return &V8Node::wrapperTypeInfo; |
| + case InternalFieldType::kDocumentType: |
| + return &V8Document::wrapperTypeInfo; |
| + case InternalFieldType::kHTMLDocumentType: |
| + return &V8HTMLDocument::wrapperTypeInfo; |
| + case InternalFieldType::kHTMLDocumentObject: |
| + return &V8HTMLDocument::wrapperTypeInfo; |
| + } |
| + NOTREACHED(); |
| + return nullptr; |
| +} |
| + |
| +struct DataForDeserializer { |
| + STACK_ALLOCATED(); |
| + Member<Document> document; |
| +}; |
| + |
| +int CountExternalReferenceEntries() { |
| + if (!g_snapshot_reference_table) |
| + return 0; |
| + |
| + int count = 0; |
| + for (intptr_t* p = g_snapshot_reference_table; *p; ++p) |
| + ++count; |
| + return count; |
| +} |
| + |
| +} // namespace |
| + |
| +v8::StartupData V8SnapshotUtil::TakeSnapshot() { |
| + DCHECK_EQ(V8PerIsolateData::From(V8PerIsolateData::MainThreadIsolate()) |
| + ->GetV8ContextMode(), |
| + V8PerIsolateData::V8ContextMode::kTakeSnapshot); |
| + |
| + v8::SnapshotCreator* creator = |
| + V8PerIsolateData::From(V8PerIsolateData::MainThreadIsolate()) |
| + ->GetSnapshotCreator(); |
| + v8::Isolate* isolate = creator->GetIsolate(); |
| + CHECK_EQ(isolate, v8::Isolate::GetCurrent()); |
| + |
| + VLOG(1) << "External reference table has " << CountExternalReferenceEntries() |
| + << " entries."; |
| + |
| + // Disable all runtime enabled featuers |
| + RuntimeEnabledFeatures::SetStableFeaturesEnabled(false); |
| + RuntimeEnabledFeatures::SetExperimentalFeaturesEnabled(false); |
| + RuntimeEnabledFeatures::SetTestFeaturesEnabled(false); |
| + |
| + { |
| + v8::HandleScope handleScope(isolate); |
| + creator->SetDefaultContext(v8::Context::New(isolate)); |
| + |
| + TakeSnapshotForWorld(creator, DOMWrapperWorld::MainWorld()); |
| + // For non main worlds, we can use any type to create a context. |
| + TakeSnapshotForWorld(creator, *DOMWrapperWorld::EnsureIsolatedWorld( |
| + isolate, kWorldIdForNonMainWorld)); |
| + } |
| + |
| + // Snapshot is taken on the main thread, but it can be used on other threads. |
| + // So we remove a message handler for the main thread. |
| + isolate->RemoveMessageListeners(V8Initializer::MessageHandlerInMainThread); |
| + |
| + return creator->CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear); |
| +} |
| + |
| +void V8SnapshotUtil::TakeSnapshotForWorld(v8::SnapshotCreator* creator, |
|
Yuki
2017/06/23 15:20:45
Be consistent with the declaration order in the he
peria
2017/06/27 09:52:37
Done.
|
| + const DOMWrapperWorld& world) { |
| + v8::Isolate* isolate = creator->GetIsolate(); |
| + CHECK_EQ(isolate, v8::Isolate::GetCurrent()); |
| + |
| + // Function templates |
| + v8::HandleScope handleScope(isolate); |
| + Vector<v8::Local<v8::FunctionTemplate>> interface_templates; |
|
Yuki
2017/06/23 15:20:45
It's not allowed to put v8::Local on heap. Vector
peria
2017/06/27 09:52:37
Done.
|
| + for (const WrapperTypeInfo* wrapper_type_info : kSnapshotWrapperTypes) { |
| + v8::Local<v8::FunctionTemplate> interface_template = |
| + wrapper_type_info->domTemplate(isolate, world); |
| + CHECK(!interface_template.IsEmpty()); |
| + interface_templates.push_back(interface_template); |
| + } |
| + |
| + // TODO(peria): Confirm interface_tempaltes[0] is a template of V8Window. |
| + v8::Local<v8::ObjectTemplate> window_template = |
| + interface_templates[0]->InstanceTemplate(); |
| + CHECK(!window_template.IsEmpty()); |
| + |
| + v8::Local<v8::Context> context; |
| + { |
| + V8PerIsolateData::UseCounterDisabledScope use_counter_disabled( |
| + V8PerIsolateData::From(isolate)); |
| + context = v8::Context::New(isolate, nullptr, window_template); |
| + } |
| + CHECK(!context.IsEmpty()); |
| + |
| + if (world.IsMainWorld()) { |
| + v8::Context::Scope scope(context); |
| + v8::Local<v8::Object> document_wrapper = CreatePlainWrapper( |
| + isolate, world, context, &V8HTMLDocument::wrapperTypeInfo); |
| + int indices[] = {kV8DOMWrapperObjectIndex, kV8DOMWrapperTypeIndex}; |
| + void* values[] = {nullptr, const_cast<WrapperTypeInfo*>( |
| + &V8HTMLDocument::wrapperTypeInfo)}; |
| + document_wrapper->SetAlignedPointerInInternalFields( |
| + WTF_ARRAY_LENGTH(indices), indices, values); |
| + |
| + // Update the cached accessor for window.document. |
| + CHECK(V8PrivateProperty::GetWindowDocumentCachedAccessor(isolate).Set( |
|
Yuki
2017/06/23 15:20:44
Probably, this should be gone.
You're now setting
peria
2017/06/27 09:52:37
Hmm. This code is required here to keep the HTMLDo
|
| + context->Global(), document_wrapper)); |
| + } |
| + |
| + for (auto& interface_template : interface_templates) { |
| + creator->AddTemplate(interface_template); |
| + } |
| + creator->AddContext(context, SerializeInternalField); |
| + |
| + V8PerIsolateData::From(isolate)->ClearPersistentsForV8Snapshot(); |
| +} |
| + |
| +void V8SnapshotUtil::EnsureInterfaceTemplates(v8::Isolate* isolate) { |
| + if (V8PerIsolateData::From(isolate)->GetV8ContextMode() != |
| + V8PerIsolateData::V8ContextMode::kUseSnapshot) { |
| + return; |
| + } |
| + |
| + EnsureInterfaceTemplatesForWorld(isolate, DOMWrapperWorld::MainWorld()); |
| + EnsureInterfaceTemplatesForWorld( |
| + isolate, |
| + *DOMWrapperWorld::EnsureIsolatedWorld(isolate, kWorldIdForNonMainWorld)); |
| +} |
| + |
| +void V8SnapshotUtil::EnsureInterfaceTemplatesForWorld( |
| + v8::Isolate* isolate, |
| + const DOMWrapperWorld& world) { |
| + V8PerIsolateData* data = V8PerIsolateData::From(isolate); |
| + for (const WrapperTypeInfo* wrapper_type_info : kSnapshotWrapperTypes) { |
| + v8::Local<v8::FunctionTemplate> interface = |
| + InterfaceTemplateFromSnapshot(isolate, world, wrapper_type_info); |
| + CHECK(!interface.IsEmpty()); |
| + data->SetInterfaceTemplate(world, wrapper_type_info, interface); |
| + } |
| +} |
| + |
| +v8::Local<v8::FunctionTemplate> V8SnapshotUtil::InterfaceTemplateFromSnapshot( |
|
Yuki
2017/06/23 15:20:44
InterfaceTemplateFromSnapshot is only used in Ensu
peria
2017/06/27 09:52:37
Done.
|
| + v8::Isolate* isolate, |
| + const DOMWrapperWorld& world, |
| + const WrapperTypeInfo* wrapper_type_info) { |
| + const int index_offset = |
| + world.IsMainWorld() ? 0 : WTF_ARRAY_LENGTH(kSnapshotWrapperTypes); |
| + |
| + if (V8Window::wrapperTypeInfo.Equals(wrapper_type_info)) { |
| + v8::Local<v8::FunctionTemplate> interface_template = |
| + v8::FunctionTemplate::FromSnapshot(isolate, index_offset + 0) |
| + .ToLocalChecked(); |
| + V8Window::installV8WindowRuntimeEnabledOnTemplateFunction( |
|
Yuki
2017/06/23 15:20:44
s/installV8Window.../InstallV8Window.../
Does thi
peria
2017/06/27 09:52:37
For V8Window, we call it via static function point
|
| + isolate, world, interface_template); |
| + return interface_template; |
| + } |
| + if (V8HTMLDocument::wrapperTypeInfo.Equals(wrapper_type_info)) { |
| + v8::Local<v8::FunctionTemplate> interface_template = |
| + v8::FunctionTemplate::FromSnapshot(isolate, index_offset + 1) |
| + .ToLocalChecked(); |
| + V8HTMLDocument::InstallRuntimeEnabledFeaturesOnTemplate(isolate, world, |
| + interface_template); |
| + return interface_template; |
| + } |
| + if (V8EventTarget::wrapperTypeInfo.Equals(wrapper_type_info)) { |
| + v8::Local<v8::FunctionTemplate> interface_template = |
| + v8::FunctionTemplate::FromSnapshot(isolate, index_offset + 2) |
| + .ToLocalChecked(); |
| + V8EventTarget::InstallRuntimeEnabledFeaturesOnTemplate(isolate, world, |
| + interface_template); |
| + return interface_template; |
| + } |
| + if (V8Node::wrapperTypeInfo.Equals(wrapper_type_info)) { |
| + v8::Local<v8::FunctionTemplate> interface_template = |
| + v8::FunctionTemplate::FromSnapshot(isolate, index_offset + 3) |
| + .ToLocalChecked(); |
| + V8Node::InstallRuntimeEnabledFeaturesOnTemplate(isolate, world, |
| + interface_template); |
| + return interface_template; |
| + } |
| + if (V8Document::wrapperTypeInfo.Equals(wrapper_type_info)) { |
| + v8::Local<v8::FunctionTemplate> interface_template = |
| + v8::FunctionTemplate::FromSnapshot(isolate, index_offset + 4) |
| + .ToLocalChecked(); |
| + V8Document::InstallRuntimeEnabledFeaturesOnTemplate(isolate, world, |
| + interface_template); |
| + return interface_template; |
| + } |
| + |
| + NOTREACHED(); |
| + return v8::Local<v8::FunctionTemplate>(); |
| +} |
| + |
| +v8::StartupData V8SnapshotUtil::SerializeInternalField( |
| + v8::Local<v8::Object> holder, |
| + int index, |
| + void*) { |
| + InternalFieldType field_type = InternalFieldType::kNone; |
| + const WrapperTypeInfo* wrapper_type = ToWrapperTypeInfo(holder); |
| + if (kV8DOMWrapperObjectIndex == index) { |
| + if (blink::V8HTMLDocument::wrapperTypeInfo.Equals(wrapper_type)) { |
| + field_type = InternalFieldType::kHTMLDocumentObject; |
| + } |
| + } else if (kV8DOMWrapperTypeIndex == index) { |
| + if (blink::V8HTMLDocument::wrapperTypeInfo.Equals(wrapper_type)) { |
| + field_type = InternalFieldType::kHTMLDocumentType; |
| + } else if (blink::V8Document::wrapperTypeInfo.Equals(wrapper_type)) { |
| + field_type = InternalFieldType::kDocumentType; |
| + } else if (blink::V8Node::wrapperTypeInfo.Equals(wrapper_type)) { |
| + field_type = InternalFieldType::kNodeType; |
| + } |
| + } |
| + CHECK_NE(field_type, InternalFieldType::kNone); |
| + |
| + int size = sizeof(InternalFieldType); |
| + char* data = new char[size]; |
| + std::memcpy(data, &field_type, size); |
| + |
| + return {data, size}; |
| +} |
| + |
| +void V8SnapshotUtil::DeserializeInternalField(v8::Local<v8::Object> holder, |
|
Yuki
2017/06/23 15:20:44
s/holder/object/
This is not relevant to a holder
peria
2017/06/27 09:52:37
Done.
|
| + int index, |
| + v8::StartupData payload, |
| + void* ptr) { |
| + // DeserializeInternalField() expects to be called in the main world |
| + // with |document| being HTMLDocument. |
| + CHECK_EQ(payload.raw_size, static_cast<int>(sizeof(InternalFieldType))); |
| + InternalFieldType type = |
| + *reinterpret_cast<const InternalFieldType*>(payload.data); |
| + |
| + const WrapperTypeInfo* wrapper_type_info = FieldTypeToWrapperTypeInfo(type); |
| + switch (type) { |
| + case InternalFieldType::kNodeType: |
| + case InternalFieldType::kDocumentType: |
| + case InternalFieldType::kHTMLDocumentType: { |
| + CHECK_EQ(index, kV8DOMWrapperTypeIndex); |
| + holder->SetAlignedPointerInInternalField( |
| + index, const_cast<WrapperTypeInfo*>(wrapper_type_info)); |
| + return; |
| + } |
| + case InternalFieldType::kHTMLDocumentObject: { |
| + CHECK_EQ(index, kV8DOMWrapperObjectIndex); |
| + v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| + DataForDeserializer* data = static_cast<DataForDeserializer*>(ptr); |
| + ScriptWrappable* document = data->document; |
| + DCHECK(document); |
| + |
| + // Make reference from wrapper to document |
| + holder->SetAlignedPointerInInternalField(index, document); |
| + // Make reference from document to wrapper |
| + CHECK(document->SetWrapper(isolate, wrapper_type_info, holder)); |
| + WrapperTypeInfo::WrapperCreated(); |
| + return; |
| + } |
| + case InternalFieldType::kNone: |
| + NOTREACHED(); |
| + return; |
| + } |
| + |
| + NOTREACHED(); |
| +} |
| + |
| +v8::Local<v8::Context> V8SnapshotUtil::CreateContext( |
| + v8::Isolate* isolate, |
| + const DOMWrapperWorld& world, |
| + v8::ExtensionConfiguration* extension_configuration, |
| + v8::Local<v8::Object> global_proxy, |
| + Document* document) { |
| + if (V8PerIsolateData::From(isolate)->GetV8ContextMode() != |
| + V8PerIsolateData::V8ContextMode::kUseSnapshot) { |
| + return v8::Local<v8::Context>(); |
| + } |
| + // For main world frames, we don't support the case that |document| is not |
| + // an instance of HTMLDocument, e.g. XMLDocument. |
| + if (world.IsMainWorld() && !(document && document->IsHTMLDocument())) { |
| + return v8::Local<v8::Context>(); |
| + } |
| + const int index = GetSnapshotIndexForWorld(world); |
| + DataForDeserializer data{document}; |
| + v8::DeserializeInternalFieldsCallback callback = |
| + v8::DeserializeInternalFieldsCallback(&DeserializeInternalField, &data); |
| + v8::Local<v8::Context> context = |
| + v8::Context::FromSnapshot(isolate, index, callback, |
| + extension_configuration, global_proxy) |
| + .ToLocalChecked(); |
| + CHECK(!context.IsEmpty()); |
| + DVLOG(1) << "A context is created from snapshot"; |
| + |
| + return context; |
| +} |
| + |
| +void V8SnapshotUtil::SetupContext(v8::Local<v8::Context> context, |
| + Document* document) { |
| + ScriptState* script_state = ScriptState::From(context); |
| + v8::Isolate* isolate = script_state->GetIsolate(); |
| + if (V8PerIsolateData::From(isolate)->GetV8ContextMode() != |
| + V8PerIsolateData::V8ContextMode::kUseSnapshot) { |
| + return; |
| + } |
| + |
| + v8::Local<v8::String> prototype_str = V8AtomicString(isolate, "prototype"); |
| + DOMWrapperWorld& world = script_state->World(); |
| + V8PerContextData* data = script_state->PerContextData(); |
| + |
| + v8::Local<v8::Object> global_proxy = context->Global(); |
| + v8::Local<v8::Object> window_wrapper = |
| + global_proxy->GetPrototype().As<v8::Object>(); |
| + { |
| + const WrapperTypeInfo* type = &V8EventTarget::wrapperTypeInfo; |
| + v8::Local<v8::Function> constructor = data->ConstructorForType(type); |
|
Yuki
2017/06/23 15:20:44
nit: s/constructor/interface/
We're not intereste
peria
2017/06/27 09:52:37
Done.
|
| + v8::Local<v8::Object> prototype = constructor->Get(context, prototype_str) |
| + .ToLocalChecked() |
| + .As<v8::Object>(); |
| + V8EventTarget::InstallRuntimeEnabledFeatures(isolate, world, window_wrapper, |
| + prototype, constructor); |
| + } |
| + { |
| + const WrapperTypeInfo* type = &V8Window::wrapperTypeInfo; |
| + v8::Local<v8::Function> constructor = data->ConstructorForType(type); |
| + v8::Local<v8::Object> prototype = constructor->Get(context, prototype_str) |
| + .ToLocalChecked() |
| + .As<v8::Object>(); |
| + V8Window::installV8WindowRuntimeEnabledFunction( |
| + isolate, world, window_wrapper, prototype, constructor); |
| + } |
| + |
| + // In case we create a context for the main world from snapshot, we also have |
| + // to work for HTMLDocument wrapper and its prototype chain. |
| + if (world.IsMainWorld() && document && document->IsHTMLDocument()) { |
|
Yuki
2017/06/23 15:20:44
This condition must appear at the very beginning o
peria
2017/06/27 09:52:37
Done.
|
| + CHECK(document->ContainsWrapper()); |
| + v8::Local<v8::Object> document_wrapper = |
| + document->MainWorldWrapper(isolate); |
| + |
| + { |
| + // Prototype object and interface object of EventTarget were set up with |
| + // Window wrapper. |
| + V8EventTarget::InstallRuntimeEnabledFeatures( |
| + isolate, world, document_wrapper, v8::Local<v8::Object>(), |
| + v8::Local<v8::Function>()); |
| + } |
| + { |
| + const WrapperTypeInfo* type = &V8Node::wrapperTypeInfo; |
| + v8::Local<v8::Function> constructor = data->ConstructorForType(type); |
| + v8::Local<v8::Object> prototype = constructor->Get(context, prototype_str) |
| + .ToLocalChecked() |
| + .As<v8::Object>(); |
| + V8Node::InstallRuntimeEnabledFeatures(isolate, world, document_wrapper, |
| + prototype, constructor); |
| + } |
| + { |
| + const WrapperTypeInfo* type = &V8Document::wrapperTypeInfo; |
| + v8::Local<v8::Function> constructor = data->ConstructorForType(type); |
| + v8::Local<v8::Object> prototype = constructor->Get(context, prototype_str) |
| + .ToLocalChecked() |
| + .As<v8::Object>(); |
| + V8Document::InstallRuntimeEnabledFeatures( |
| + isolate, world, document_wrapper, prototype, constructor); |
| + } |
| + { |
| + const WrapperTypeInfo* type = &V8HTMLDocument::wrapperTypeInfo; |
| + v8::Local<v8::Function> constructor = data->ConstructorForType(type); |
| + v8::Local<v8::Object> prototype = constructor->Get(context, prototype_str) |
| + .ToLocalChecked() |
| + .As<v8::Object>(); |
| + V8HTMLDocument::InstallRuntimeEnabledFeatures( |
| + isolate, world, document_wrapper, prototype, constructor); |
| + } |
| + } |
| +} |
| + |
| +void V8SnapshotUtil::SetReferenceTable(intptr_t* table) { |
| + DCHECK(!g_snapshot_reference_table); |
| + g_snapshot_reference_table = table; |
| +} |
| + |
| +intptr_t* V8SnapshotUtil::GetReferenceTable() { |
| + DCHECK(g_snapshot_reference_table); |
| + return g_snapshot_reference_table; |
| +} |
| + |
| +} // namespace blink |