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..1be6b097f28f0c58b37ff9b4bd7009949d61aeca |
--- /dev/null |
+++ b/third_party/WebKit/Source/bindings/core/v8/V8SnapshotUtil.cpp |
@@ -0,0 +1,510 @@ |
+// 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)) |
+ 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)); |
+ 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)); |
+ 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, |
Yuki
2017/06/20 14:20:11
nit: one entry per line rather than manual spacing
peria
2017/06/21 07:19:16
clang-format does it.
|
+ &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; |
+ |
+ // To ignore the terminate entry '0'. |
Yuki
2017/06/20 14:20:11
It seems that you're not counting the null termina
peria
2017/06/21 07:19:16
Done.
|
+ int count = -1; |
+ 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()); |
+ |
+ LOG(INFO) << "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, |
+ 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; |
+ 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); |
+ } |
+ |
+ // FIXME: Confirm interface_tempaltes[0] is a template of V8Window. |
Yuki
2017/06/20 14:20:11
s/FIXME/TODO(peria)/
peria
2017/06/21 07:19:16
Done.
|
+ 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( |
+ 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) { |
+ for (const WrapperTypeInfo* wrapper_type_info : kSnapshotWrapperTypes) { |
+ v8::Local<v8::FunctionTemplate> interface = |
+ wrapper_type_info->domTemplate(isolate, world); |
+ CHECK(!interface.IsEmpty()); |
+ } |
+} |
+ |
+v8::Local<v8::FunctionTemplate> V8SnapshotUtil::InterfaceTemplateFromSnapshot( |
+ v8::Isolate* isolate, |
+ const DOMWrapperWorld& world, |
+ WrapperTypeInfo* wrapper_type_info) { |
+ if (V8PerIsolateData::From(isolate)->GetV8ContextMode() != |
+ V8PerIsolateData::V8ContextMode::kUseSnapshot) { |
+ return v8::Local<v8::FunctionTemplate>(); |
+ } |
+ |
+ const int index_offset = |
+ world.IsMainWorld() ? 0 : WTF_ARRAY_LENGTH(kSnapshotWrapperTypes); |
+ |
+ // Snapshotted templates are expected to be used just to get |
+ // wrapper_type_info. |
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(kSnapshotWrapperTypes); ++i) { |
+ if (kSnapshotWrapperTypes[i]->Equals(wrapper_type_info)) { |
+ return v8::FunctionTemplate::FromSnapshot(isolate, index_offset + i) |
+ .ToLocalChecked(); |
+ } |
+ } |
+ 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, |
+ 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, a HTMLDocument object is required to be |
+ // deserialized. |
+ 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()); |
+ |
+ if (world.IsMainWorld()) { |
+ v8::Context::Scope scope(context); |
+ v8::Local<v8::Object> wrapper = document->MainWorldWrapper(isolate); |
+ CHECK(!wrapper.IsEmpty()); |
+ v8::Local<v8::Object> empty_prototype; |
+ v8::Local<v8::Function> empty_interface; |
+ |
+ V8HTMLDocument::InstallRuntimeEnabledFeatures( |
+ isolate, world, wrapper, empty_prototype, empty_interface); |
+ V8Document::InstallRuntimeEnabledFeatures(isolate, world, wrapper, |
+ empty_prototype, empty_interface); |
+ V8Node::InstallRuntimeEnabledFeatures(isolate, world, wrapper, |
+ empty_prototype, empty_interface); |
+ V8EventTarget::InstallRuntimeEnabledFeatures( |
+ isolate, world, wrapper, empty_prototype, empty_interface); |
+ } |
+ return context; |
+} |
+ |
+void V8SnapshotUtil::SetupContext(v8::Local<v8::Context> context) { |
+ ScriptState* script_state = ScriptState::From(context); |
+ v8::Isolate* isolate = script_state->GetIsolate(); |
+ if (V8PerIsolateData::From(isolate)->GetV8ContextMode() != |
+ V8PerIsolateData::V8ContextMode::kUseSnapshot) { |
+ return; |
+ } |
+ |
+ DOMWrapperWorld& world = script_state->World(); |
+ V8PerContextData* data = script_state->PerContextData(); |
+ |
+ v8::Local<v8::Object> empty_prototype; |
+ v8::Local<v8::Function> empty_interface; |
+ // Set up Window wrapper. |
+ { |
+ v8::Local<v8::Object> global_proxy = context->Global(); |
+ v8::Local<v8::Object> wrapper = |
+ global_proxy->GetPrototype().As<v8::Object>(); |
+ V8Window::installV8WindowRuntimeEnabledFunction( |
+ isolate, world, wrapper, empty_prototype, empty_interface); |
+ V8EventTarget::InstallRuntimeEnabledFeatures( |
+ isolate, world, wrapper, empty_prototype, empty_interface); |
+ } |
+ |
+ // Setup V8PerContextData::constructor_map_ and wrapper_boilerplate_. |
+ { |
+ const WrapperTypeInfo* type = &V8EventTarget::wrapperTypeInfo; |
+ v8::Local<v8::Function> constructor = data->ConstructorForType(type); |
+ v8::Local<v8::Object> prototype = |
+ constructor->Get(context, V8AtomicString(isolate, "prototype")) |
+ .ToLocalChecked() |
+ .As<v8::Object>(); |
+ v8::Local<v8::Object> wrapper = data->CreateWrapperFromCache(type); |
+ V8EventTarget::InstallRuntimeEnabledFeatures(isolate, world, wrapper, |
+ prototype, constructor); |
+ data->constructor_map_.Set(type, constructor); |
+ data->wrapper_boilerplates_.Set(type, wrapper); |
+ } |
+ { |
+ const WrapperTypeInfo* type = &V8Window::wrapperTypeInfo; |
+ v8::Local<v8::Function> constructor = data->ConstructorForType(type); |
+ v8::Local<v8::Object> prototype = |
+ constructor->Get(context, V8AtomicString(isolate, "prototype")) |
+ .ToLocalChecked() |
+ .As<v8::Object>(); |
+ v8::Local<v8::Object> wrapper = data->CreateWrapperFromCache(type); |
+ V8Window::installV8WindowRuntimeEnabledFunction(isolate, world, wrapper, |
+ prototype, constructor); |
+ V8EventTarget::InstallRuntimeEnabledFeatures( |
+ isolate, world, wrapper, empty_prototype, empty_interface); |
+ data->constructor_map_.Set(type, constructor); |
+ data->wrapper_boilerplates_.Set(type, wrapper); |
+ } |
+ { |
+ const WrapperTypeInfo* type = &V8Node::wrapperTypeInfo; |
+ v8::Local<v8::Function> constructor = data->ConstructorForType(type); |
+ v8::Local<v8::Object> prototype = |
+ constructor->Get(context, V8AtomicString(isolate, "prototype")) |
+ .ToLocalChecked() |
+ .As<v8::Object>(); |
+ v8::Local<v8::Object> wrapper = data->CreateWrapperFromCache(type); |
+ V8Node::InstallRuntimeEnabledFeatures(isolate, world, wrapper, prototype, |
+ constructor); |
+ V8EventTarget::InstallRuntimeEnabledFeatures( |
+ isolate, world, wrapper, empty_prototype, empty_interface); |
+ data->constructor_map_.Set(type, constructor); |
+ data->wrapper_boilerplates_.Set(type, wrapper); |
+ } |
+ { |
+ const WrapperTypeInfo* type = &V8Document::wrapperTypeInfo; |
+ v8::Local<v8::Function> constructor = data->ConstructorForType(type); |
+ v8::Local<v8::Object> prototype = |
+ constructor->Get(context, V8AtomicString(isolate, "prototype")) |
+ .ToLocalChecked() |
+ .As<v8::Object>(); |
+ v8::Local<v8::Object> wrapper = data->CreateWrapperFromCache(type); |
+ V8Document::InstallRuntimeEnabledFeatures(isolate, world, wrapper, |
+ prototype, constructor); |
+ V8Node::InstallRuntimeEnabledFeatures(isolate, world, wrapper, |
+ empty_prototype, empty_interface); |
+ V8EventTarget::InstallRuntimeEnabledFeatures( |
+ isolate, world, wrapper, empty_prototype, empty_interface); |
+ data->constructor_map_.Set(type, constructor); |
+ data->wrapper_boilerplates_.Set(type, wrapper); |
+ } |
+ { |
+ const WrapperTypeInfo* type = &V8HTMLDocument::wrapperTypeInfo; |
+ v8::Local<v8::Function> constructor = data->ConstructorForType(type); |
+ v8::Local<v8::Object> prototype = |
+ constructor->Get(context, V8AtomicString(isolate, "prototype")) |
+ .ToLocalChecked() |
+ .As<v8::Object>(); |
+ v8::Local<v8::Object> wrapper = data->CreateWrapperFromCache(type); |
+ V8HTMLDocument::InstallRuntimeEnabledFeatures(isolate, world, wrapper, |
+ prototype, constructor); |
+ V8Document::InstallRuntimeEnabledFeatures(isolate, world, wrapper, |
+ empty_prototype, empty_interface); |
+ V8Node::InstallRuntimeEnabledFeatures(isolate, world, wrapper, |
+ empty_prototype, empty_interface); |
+ V8EventTarget::InstallRuntimeEnabledFeatures( |
+ isolate, world, wrapper, empty_prototype, empty_interface); |
+ data->constructor_map_.Set(type, constructor); |
+ data->wrapper_boilerplates_.Set(type, wrapper); |
+ } |
+} |
+ |
+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 |