[snapshot] support including templates in the snapshot.
R=jochen@chromium.org, verwaest@chromium.org BUG=chromium:617892 Review-Url: https://codereview.chromium.org/2076083002 Cr-Commit-Position: refs/heads/master@{#37122}
This commit is contained in:
parent
6773ee2508
commit
c5ae5bb16b
12
include/v8.h
12
include/v8.h
@ -4487,6 +4487,9 @@ class V8_EXPORT FunctionTemplate : public Template {
|
||||
Local<Value> data = Local<Value>(),
|
||||
Local<Signature> signature = Local<Signature>(), int length = 0);
|
||||
|
||||
/** Get a template included in the snapshot by index. */
|
||||
static Local<FunctionTemplate> FromSnapshot(Isolate* isolate, size_t index);
|
||||
|
||||
/**
|
||||
* Creates a function template with a fast handler. If a fast handler is set,
|
||||
* the callback cannot be null.
|
||||
@ -4662,6 +4665,9 @@ class V8_EXPORT ObjectTemplate : public Template {
|
||||
Local<FunctionTemplate> constructor = Local<FunctionTemplate>());
|
||||
static V8_DEPRECATED("Use isolate version", Local<ObjectTemplate> New());
|
||||
|
||||
/** Get a template included in the snapshot by index. */
|
||||
static Local<ObjectTemplate> FromSnapshot(Isolate* isolate, size_t index);
|
||||
|
||||
/** Creates a new instance of this template.*/
|
||||
V8_DEPRECATE_SOON("Use maybe version", Local<Object> NewInstance());
|
||||
V8_WARN_UNUSED_RESULT MaybeLocal<Object> NewInstance(Local<Context> context);
|
||||
@ -6810,6 +6816,12 @@ class SnapshotCreator {
|
||||
*/
|
||||
size_t AddContext(Local<Context> context);
|
||||
|
||||
/**
|
||||
* Add a template to be included in the snapshot blob.
|
||||
* \returns the index of the template in the snapshot blob.
|
||||
*/
|
||||
size_t AddTemplate(Local<Template> template_obj);
|
||||
|
||||
/**
|
||||
* Created a snapshot data blob.
|
||||
* This must not be called from within a handle scope.
|
||||
|
58
src/api.cc
58
src/api.cc
@ -386,7 +386,10 @@ bool RunExtraCode(Isolate* isolate, Local<Context> context,
|
||||
|
||||
struct SnapshotCreatorData {
|
||||
explicit SnapshotCreatorData(Isolate* isolate)
|
||||
: isolate_(isolate), contexts_(isolate), created_(false) {}
|
||||
: isolate_(isolate),
|
||||
contexts_(isolate),
|
||||
templates_(isolate),
|
||||
created_(false) {}
|
||||
|
||||
static SnapshotCreatorData* cast(void* data) {
|
||||
return reinterpret_cast<SnapshotCreatorData*>(data);
|
||||
@ -395,6 +398,7 @@ struct SnapshotCreatorData {
|
||||
ArrayBufferAllocator allocator_;
|
||||
Isolate* isolate_;
|
||||
PersistentValueVector<Context> contexts_;
|
||||
PersistentValueVector<Template> templates_;
|
||||
bool created_;
|
||||
};
|
||||
|
||||
@ -442,12 +446,35 @@ size_t SnapshotCreator::AddContext(Local<Context> context) {
|
||||
return index;
|
||||
}
|
||||
|
||||
size_t SnapshotCreator::AddTemplate(Local<Template> template_obj) {
|
||||
DCHECK(!template_obj.IsEmpty());
|
||||
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
|
||||
DCHECK(!data->created_);
|
||||
DCHECK_EQ(reinterpret_cast<i::Isolate*>(data->isolate_),
|
||||
Utils::OpenHandle(*template_obj)->GetIsolate());
|
||||
size_t index = static_cast<int>(data->templates_.Size());
|
||||
data->templates_.Append(template_obj);
|
||||
return index;
|
||||
}
|
||||
|
||||
StartupData SnapshotCreator::CreateBlob(
|
||||
SnapshotCreator::FunctionCodeHandling function_code_handling) {
|
||||
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(data->isolate_);
|
||||
DCHECK(!data->created_);
|
||||
|
||||
{
|
||||
int num_templates = static_cast<int>(data->templates_.Size());
|
||||
i::HandleScope scope(isolate);
|
||||
i::Handle<i::FixedArray> templates =
|
||||
isolate->factory()->NewFixedArray(num_templates, i::TENURED);
|
||||
for (int i = 0; i < num_templates; i++) {
|
||||
templates->set(i, *v8::Utils::OpenHandle(*data->templates_.Get(i)));
|
||||
}
|
||||
isolate->heap()->SetSerializedTemplates(*templates);
|
||||
data->templates_.Clear();
|
||||
}
|
||||
|
||||
// If we don't do this then we end up with a stray root pointing at the
|
||||
// context even after we have disposed of the context.
|
||||
isolate->heap()->CollectAllAvailableGarbage("mksnapshot");
|
||||
@ -1173,6 +1200,20 @@ Local<FunctionTemplate> FunctionTemplate::New(Isolate* isolate,
|
||||
length, false);
|
||||
}
|
||||
|
||||
Local<FunctionTemplate> FunctionTemplate::FromSnapshot(Isolate* isolate,
|
||||
size_t index) {
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
i::FixedArray* templates = i_isolate->heap()->serialized_templates();
|
||||
int int_index = static_cast<int>(index);
|
||||
if (int_index < templates->length()) {
|
||||
i::Object* info = i_isolate->heap()->serialized_templates()->get(int_index);
|
||||
if (info->IsFunctionTemplateInfo()) {
|
||||
return Utils::ToLocal(i::Handle<i::FunctionTemplateInfo>(
|
||||
i::FunctionTemplateInfo::cast(info)));
|
||||
}
|
||||
}
|
||||
return Local<FunctionTemplate>();
|
||||
}
|
||||
|
||||
Local<FunctionTemplate> FunctionTemplate::NewWithFastHandler(
|
||||
Isolate* isolate, FunctionCallback callback,
|
||||
@ -1384,6 +1425,21 @@ Local<ObjectTemplate> ObjectTemplate::New(
|
||||
return ObjectTemplateNew(isolate, constructor, false);
|
||||
}
|
||||
|
||||
Local<ObjectTemplate> ObjectTemplate::FromSnapshot(Isolate* isolate,
|
||||
size_t index) {
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
i::FixedArray* templates = i_isolate->heap()->serialized_templates();
|
||||
int int_index = static_cast<int>(index);
|
||||
if (int_index < templates->length()) {
|
||||
i::Object* info = i_isolate->heap()->serialized_templates()->get(int_index);
|
||||
if (info->IsObjectTemplateInfo()) {
|
||||
return Utils::ToLocal(
|
||||
i::Handle<i::ObjectTemplateInfo>(i::ObjectTemplateInfo::cast(info)));
|
||||
}
|
||||
}
|
||||
return Local<ObjectTemplate>();
|
||||
}
|
||||
|
||||
// Ensure that the object template has a constructor. If no
|
||||
// constructor is available we create one.
|
||||
static i::Handle<i::FunctionTemplateInfo> EnsureConstructor(
|
||||
|
@ -732,6 +732,11 @@ int Heap::GetNextTemplateSerialNumber() {
|
||||
return next_serial_number;
|
||||
}
|
||||
|
||||
void Heap::SetSerializedTemplates(FixedArray* templates) {
|
||||
DCHECK_EQ(empty_fixed_array(), serialized_templates());
|
||||
set_serialized_templates(templates);
|
||||
}
|
||||
|
||||
AlwaysAllocateScope::AlwaysAllocateScope(Isolate* isolate)
|
||||
: heap_(isolate->heap()) {
|
||||
heap_->always_allocate_scope_count_.Increment(1);
|
||||
|
@ -2897,6 +2897,8 @@ void Heap::CreateInitialObjects() {
|
||||
handle(Smi::FromInt(Isolate::kArrayProtectorValid), isolate()));
|
||||
set_species_protector(*species_cell);
|
||||
|
||||
set_serialized_templates(empty_fixed_array());
|
||||
|
||||
set_weak_stack_trace_list(Smi::FromInt(0));
|
||||
|
||||
set_noscript_shared_function_infos(Smi::FromInt(0));
|
||||
@ -2934,6 +2936,7 @@ bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
|
||||
case kRetainedMapsRootIndex:
|
||||
case kNoScriptSharedFunctionInfosRootIndex:
|
||||
case kWeakStackTraceListRootIndex:
|
||||
case kSerializedTemplatesRootIndex:
|
||||
// Smi values
|
||||
#define SMI_ENTRY(type, name, Name) case k##Name##RootIndex:
|
||||
SMI_ROOT_LIST(SMI_ENTRY)
|
||||
|
@ -197,7 +197,8 @@ using v8::MemoryPressureLevel;
|
||||
V(Map, bytecode_array_map, BytecodeArrayMap) \
|
||||
V(WeakCell, empty_weak_cell, EmptyWeakCell) \
|
||||
V(PropertyCell, has_instance_protector, HasInstanceProtector) \
|
||||
V(Cell, species_protector, SpeciesProtector)
|
||||
V(Cell, species_protector, SpeciesProtector) \
|
||||
V(FixedArray, serialized_templates, SerializedTemplates)
|
||||
|
||||
// Entries in this list are limited to Smis and are not visited during GC.
|
||||
#define SMI_ROOT_LIST(V) \
|
||||
@ -807,6 +808,8 @@ class Heap {
|
||||
inline void SetInterpreterEntryReturnPCOffset(int pc_offset);
|
||||
inline int GetNextTemplateSerialNumber();
|
||||
|
||||
inline void SetSerializedTemplates(FixedArray* templates);
|
||||
|
||||
// For post mortem debugging.
|
||||
void RememberUnmappedPage(Address page, bool compacted);
|
||||
|
||||
|
@ -74,6 +74,8 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
|
||||
// All the internalized strings that the partial snapshot needs should be
|
||||
// either in the root table or in the partial snapshot cache.
|
||||
DCHECK(!obj->IsInternalizedString());
|
||||
// Function and object templates are not context specific.
|
||||
DCHECK(!obj->IsTemplateInfo());
|
||||
|
||||
if (SerializeKnownObject(obj, how_to_code, where_to_point, skip)) return;
|
||||
|
||||
|
@ -2031,7 +2031,7 @@ TEST(SnapshotCreatorExternalReferences) {
|
||||
delete[] blob.data;
|
||||
}
|
||||
|
||||
TEST(SnapshotCreatorGlobalTemplate) {
|
||||
TEST(SnapshotCreatorTemplates) {
|
||||
DisableTurbofan();
|
||||
v8::StartupData blob;
|
||||
{
|
||||
@ -2042,13 +2042,16 @@ TEST(SnapshotCreatorGlobalTemplate) {
|
||||
v8::ExtensionConfiguration* no_extension = nullptr;
|
||||
v8::Local<v8::ObjectTemplate> global_template =
|
||||
v8::ObjectTemplate::New(isolate);
|
||||
global_template->Set(
|
||||
v8_str("f"), v8::FunctionTemplate::New(isolate, SerializedCallback));
|
||||
v8::Local<v8::FunctionTemplate> callback =
|
||||
v8::FunctionTemplate::New(isolate, SerializedCallback);
|
||||
global_template->Set(v8_str("f"), callback);
|
||||
v8::Local<v8::Context> context =
|
||||
v8::Context::New(isolate, no_extension, global_template);
|
||||
v8::Context::Scope context_scope(context);
|
||||
ExpectInt32("f()", 42);
|
||||
CHECK_EQ(0, creator.AddContext(context));
|
||||
CHECK_EQ(0, creator.AddTemplate(callback));
|
||||
CHECK_EQ(1, creator.AddTemplate(global_template));
|
||||
}
|
||||
blob =
|
||||
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
@ -2073,6 +2076,28 @@ TEST(SnapshotCreatorGlobalTemplate) {
|
||||
v8::Context::New(isolate, no_extension, no_template, no_object, 0);
|
||||
v8::Context::Scope context_scope(context);
|
||||
ExpectInt32("f()", 42);
|
||||
|
||||
// Retrieve the snapshotted object template.
|
||||
v8::Local<v8::ObjectTemplate> obj_template =
|
||||
v8::ObjectTemplate::FromSnapshot(isolate, 1);
|
||||
CHECK(!obj_template.IsEmpty());
|
||||
v8::Local<v8::Object> object =
|
||||
obj_template->NewInstance(context).ToLocalChecked();
|
||||
CHECK(context->Global()->Set(context, v8_str("o"), object).FromJust());
|
||||
ExpectInt32("o.f()", 42);
|
||||
// Check that it instantiates to the same prototype.
|
||||
ExpectTrue("o.f.prototype === f.prototype");
|
||||
|
||||
// Retrieve the snapshotted function template.
|
||||
v8::Local<v8::FunctionTemplate> fun_template =
|
||||
v8::FunctionTemplate::FromSnapshot(isolate, 0);
|
||||
CHECK(!fun_template.IsEmpty());
|
||||
v8::Local<v8::Function> fun =
|
||||
fun_template->GetFunction(context).ToLocalChecked();
|
||||
CHECK(context->Global()->Set(context, v8_str("g"), fun).FromJust());
|
||||
ExpectInt32("g()", 42);
|
||||
// Check that it instantiates to the same prototype.
|
||||
ExpectTrue("g.prototype === f.prototype");
|
||||
}
|
||||
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user