[snapshot] support attaching arbitrary v8::Data.

In collaboration with Qingyan Li <qingyan.liqy@alibaba-inc.com>.

R=jgruber@chromium.org, mlippautz@chromium.org

Bug: v8:7249
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: I87f62103ec5b31de274fa22ad275f1c1bcb3ed86
Reviewed-on: https://chromium-review.googlesource.com/846750
Commit-Queue: Yang Guo <yangguo@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50433}
This commit is contained in:
Yang Guo 2018-01-08 21:32:18 +01:00 committed by Commit Bot
parent 3f8d6f6074
commit 11e80a3509
18 changed files with 626 additions and 160 deletions

View File

@ -313,6 +313,7 @@ class Local {
friend class String; friend class String;
friend class Object; friend class Object;
friend class Context; friend class Context;
friend class Isolate;
friend class Private; friend class Private;
template<class F> friend class internal::CustomArguments; template<class F> friend class internal::CustomArguments;
friend Local<Primitive> Undefined(Isolate* isolate); friend Local<Primitive> Undefined(Isolate* isolate);
@ -5522,8 +5523,12 @@ class V8_EXPORT FunctionTemplate : public Template {
*/ */
bool HasInstance(Local<Value> object); bool HasInstance(Local<Value> object);
V8_INLINE static FunctionTemplate* Cast(Data* data);
private: private:
FunctionTemplate(); FunctionTemplate();
static void CheckCast(Data* that);
friend class Context; friend class Context;
friend class ObjectTemplate; friend class ObjectTemplate;
}; };
@ -5870,10 +5875,13 @@ class V8_EXPORT ObjectTemplate : public Template {
*/ */
void SetImmutableProto(); void SetImmutableProto();
V8_INLINE static ObjectTemplate* Cast(Data* data);
private: private:
ObjectTemplate(); ObjectTemplate();
static Local<ObjectTemplate> New(internal::Isolate* isolate, static Local<ObjectTemplate> New(internal::Isolate* isolate,
Local<FunctionTemplate> constructor); Local<FunctionTemplate> constructor);
static void CheckCast(Data* that);
friend class FunctionTemplate; friend class FunctionTemplate;
}; };
@ -7083,6 +7091,14 @@ class V8_EXPORT Isolate {
*/ */
V8_INLINE static uint32_t GetNumberOfDataSlots(); V8_INLINE static uint32_t GetNumberOfDataSlots();
/**
* Return data that was previously attached to the isolate snapshot via
* SnapshotCreator, and removes the reference to it.
* Repeated call with the same index returns an empty MaybeLocal.
*/
template <class T>
V8_INLINE MaybeLocal<T> GetDataFromSnapshotOnce(size_t index);
/** /**
* Get statistics about the heap memory usage. * Get statistics about the heap memory usage.
*/ */
@ -7725,6 +7741,7 @@ class V8_EXPORT Isolate {
template <class K, class V, class Traits> template <class K, class V, class Traits>
friend class PersistentValueMapBase; friend class PersistentValueMapBase;
internal::Object** GetDataFromSnapshotOnce(size_t index);
void ReportExternalAllocationLimitReached(); void ReportExternalAllocationLimitReached();
void CheckMemoryPressure(); void CheckMemoryPressure();
}; };
@ -8021,6 +8038,24 @@ class V8_EXPORT SnapshotCreator {
*/ */
size_t AddTemplate(Local<Template> template_obj); size_t AddTemplate(Local<Template> template_obj);
/**
* Attach arbitrary V8::Data to the context snapshot, which can be retrieved
* via Context::GetDataFromSnapshot after deserialization. This data does not
* survive when a new snapshot is created from an existing snapshot.
* \returns the index for retrieval.
*/
template <class T>
V8_INLINE size_t AddData(Local<Context> context, Local<T> object);
/**
* Attach arbitrary V8::Data to the isolate snapshot, which can be retrieved
* via Isolate::GetDataFromSnapshot after deserialization. This data does not
* survive when a new snapshot is created from an existing snapshot.
* \returns the index for retrieval.
*/
template <class T>
V8_INLINE size_t AddData(Local<T> object);
/** /**
* Created a snapshot data blob. * Created a snapshot data blob.
* This must not be called from within a handle scope. * This must not be called from within a handle scope.
@ -8036,6 +8071,9 @@ class V8_EXPORT SnapshotCreator {
void operator=(const SnapshotCreator&) = delete; void operator=(const SnapshotCreator&) = delete;
private: private:
size_t AddData(Local<Context> context, internal::Object* object);
size_t AddData(internal::Object* object);
void* data_; void* data_;
}; };
@ -8523,6 +8561,14 @@ class V8_EXPORT Context {
*/ */
void SetErrorMessageForCodeGenerationFromStrings(Local<String> message); void SetErrorMessageForCodeGenerationFromStrings(Local<String> message);
/**
* Return data that was previously attached to the context snapshot via
* SnapshotCreator, and removes the reference to it.
* Repeated call with the same index returns an empty MaybeLocal.
*/
template <class T>
V8_INLINE MaybeLocal<T> GetDataFromSnapshotOnce(size_t index);
/** /**
* Stack-allocated class which sets the execution context for all * Stack-allocated class which sets the execution context for all
* operations executed within a local scope. * operations executed within a local scope.
@ -8565,6 +8611,7 @@ class V8_EXPORT Context {
friend class Object; friend class Object;
friend class Function; friend class Function;
internal::Object** GetDataFromSnapshotOnce(size_t index);
Local<Value> SlowGetEmbedderData(int index); Local<Value> SlowGetEmbedderData(int index);
void* SlowGetAlignedPointerFromEmbedderData(int index); void* SlowGetAlignedPointerFromEmbedderData(int index);
}; };
@ -8942,6 +8989,29 @@ class Internals {
} }
}; };
// Only perform cast check for types derived from v8::Data since
// other types do not implement the Cast method.
template <bool PerformCheck>
struct CastCheck {
template <class T>
static void Perform(T* data);
};
template <>
template <class T>
void CastCheck<true>::Perform(T* data) {
T::Cast(data);
}
template <>
template <class T>
void CastCheck<false>::Perform(T* data) {}
template <class T>
V8_INLINE void PerformCastCheck(T* data) {
CastCheck<std::is_base_of<Data, T>::value>::Perform(data);
}
} // namespace internal } // namespace internal
@ -9405,6 +9475,19 @@ void Template::Set(Isolate* isolate, const char* name, Local<Data> value) {
value); value);
} }
FunctionTemplate* FunctionTemplate::Cast(Data* data) {
#ifdef V8_ENABLE_CHECKS
CheckCast(data);
#endif
return reinterpret_cast<FunctionTemplate*>(data);
}
ObjectTemplate* ObjectTemplate::Cast(Data* data) {
#ifdef V8_ENABLE_CHECKS
CheckCast(data);
#endif
return reinterpret_cast<ObjectTemplate*>(data);
}
Local<Value> Object::GetInternalField(int index) { Local<Value> Object::GetInternalField(int index) {
#ifndef V8_ENABLE_CHECKS #ifndef V8_ENABLE_CHECKS
@ -9983,6 +10066,12 @@ uint32_t Isolate::GetNumberOfDataSlots() {
return I::kNumIsolateDataSlots; return I::kNumIsolateDataSlots;
} }
template <class T>
MaybeLocal<T> Isolate::GetDataFromSnapshotOnce(size_t index) {
T* data = reinterpret_cast<T*>(GetDataFromSnapshotOnce(index));
if (data) internal::PerformCastCheck(data);
return Local<T>(data);
}
int64_t Isolate::AdjustAmountOfExternalAllocatedMemory( int64_t Isolate::AdjustAmountOfExternalAllocatedMemory(
int64_t change_in_bytes) { int64_t change_in_bytes) {
@ -10042,6 +10131,26 @@ void* Context::GetAlignedPointerFromEmbedderData(int index) {
#endif #endif
} }
template <class T>
MaybeLocal<T> Context::GetDataFromSnapshotOnce(size_t index) {
T* data = reinterpret_cast<T*>(GetDataFromSnapshotOnce(index));
if (data) internal::PerformCastCheck(data);
return Local<T>(data);
}
template <class T>
size_t SnapshotCreator::AddData(Local<Context> context, Local<T> object) {
T* object_ptr = *object;
internal::Object** p = reinterpret_cast<internal::Object**>(object_ptr);
return AddData(context, *p);
}
template <class T>
size_t SnapshotCreator::AddData(Local<T> object) {
T* object_ptr = *object;
internal::Object** p = reinterpret_cast<internal::Object**>(object_ptr);
return AddData(*p);
}
/** /**
* \example shell.cc * \example shell.cc

View File

@ -573,7 +573,6 @@ struct SnapshotCreatorData {
: isolate_(isolate), : isolate_(isolate),
default_context_(), default_context_(),
contexts_(isolate), contexts_(isolate),
templates_(isolate),
created_(false) {} created_(false) {}
static SnapshotCreatorData* cast(void* data) { static SnapshotCreatorData* cast(void* data) {
@ -585,7 +584,6 @@ struct SnapshotCreatorData {
Persistent<Context> default_context_; Persistent<Context> default_context_;
SerializeInternalFieldsCallback default_embedder_fields_serializer_; SerializeInternalFieldsCallback default_embedder_fields_serializer_;
PersistentValueVector<Context> contexts_; PersistentValueVector<Context> contexts_;
PersistentValueVector<Template> templates_;
std::vector<SerializeInternalFieldsCallback> embedder_fields_serializers_; std::vector<SerializeInternalFieldsCallback> embedder_fields_serializers_;
bool created_; bool created_;
}; };
@ -645,23 +643,81 @@ size_t SnapshotCreator::AddContext(Local<Context> context,
DCHECK(!data->created_); DCHECK(!data->created_);
Isolate* isolate = data->isolate_; Isolate* isolate = data->isolate_;
CHECK_EQ(isolate, context->GetIsolate()); CHECK_EQ(isolate, context->GetIsolate());
size_t index = static_cast<int>(data->contexts_.Size()); size_t index = data->contexts_.Size();
data->contexts_.Append(context); data->contexts_.Append(context);
data->embedder_fields_serializers_.push_back(callback); data->embedder_fields_serializers_.push_back(callback);
return index; return index;
} }
size_t SnapshotCreator::AddTemplate(Local<Template> template_obj) { size_t SnapshotCreator::AddTemplate(Local<Template> template_obj) {
DCHECK(!template_obj.IsEmpty()); return AddData(template_obj);
}
size_t SnapshotCreator::AddData(i::Object* object) {
DCHECK_NOT_NULL(object);
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
DCHECK(!data->created_); DCHECK(!data->created_);
DCHECK_EQ(reinterpret_cast<i::Isolate*>(data->isolate_), i::Isolate* isolate = reinterpret_cast<i::Isolate*>(data->isolate_);
Utils::OpenHandle(*template_obj)->GetIsolate()); i::HandleScope scope(isolate);
size_t index = static_cast<int>(data->templates_.Size()); i::Handle<i::Object> obj(object, isolate);
data->templates_.Append(template_obj); i::Handle<i::ArrayList> list;
if (!isolate->heap()->serialized_objects()->IsArrayList()) {
list = i::ArrayList::New(isolate, 1);
} else {
list = i::Handle<i::ArrayList>(
i::ArrayList::cast(isolate->heap()->serialized_objects()));
}
size_t index = static_cast<size_t>(list->Length());
list = i::ArrayList::Add(list, obj);
isolate->heap()->SetSerializedObjects(*list);
return index; return index;
} }
size_t SnapshotCreator::AddData(Local<Context> context, i::Object* object) {
DCHECK_NOT_NULL(object);
DCHECK(!SnapshotCreatorData::cast(data_)->created_);
i::Handle<i::Context> ctx = Utils::OpenHandle(*context);
i::Isolate* isolate = ctx->GetIsolate();
i::HandleScope scope(isolate);
i::Handle<i::Object> obj(object, isolate);
i::Handle<i::ArrayList> list;
if (!ctx->serialized_objects()->IsArrayList()) {
list = i::ArrayList::New(isolate, 1);
} else {
list =
i::Handle<i::ArrayList>(i::ArrayList::cast(ctx->serialized_objects()));
}
size_t index = static_cast<size_t>(list->Length());
list = i::ArrayList::Add(list, obj);
ctx->set_serialized_objects(*list);
return index;
}
namespace {
void ConvertSerializedObjectsToFixedArray(Local<Context> context) {
i::Handle<i::Context> ctx = Utils::OpenHandle(*context);
i::Isolate* isolate = ctx->GetIsolate();
if (!ctx->serialized_objects()->IsArrayList()) {
ctx->set_serialized_objects(isolate->heap()->empty_fixed_array());
} else {
i::Handle<i::ArrayList> list(i::ArrayList::cast(ctx->serialized_objects()));
i::Handle<i::FixedArray> elements = i::ArrayList::Elements(list);
ctx->set_serialized_objects(*elements);
}
}
void ConvertSerializedObjectsToFixedArray(i::Isolate* isolate) {
if (!isolate->heap()->serialized_objects()->IsArrayList()) {
isolate->heap()->SetSerializedObjects(isolate->heap()->empty_fixed_array());
} else {
i::Handle<i::ArrayList> list(
i::ArrayList::cast(isolate->heap()->serialized_objects()));
i::Handle<i::FixedArray> elements = i::ArrayList::Elements(list);
isolate->heap()->SetSerializedObjects(*elements);
}
}
} // anonymous namespace
StartupData SnapshotCreator::CreateBlob( StartupData SnapshotCreator::CreateBlob(
SnapshotCreator::FunctionCodeHandling function_code_handling) { SnapshotCreator::FunctionCodeHandling function_code_handling) {
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_); SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
@ -672,15 +728,16 @@ StartupData SnapshotCreator::CreateBlob(
int num_additional_contexts = static_cast<int>(data->contexts_.Size()); int num_additional_contexts = static_cast<int>(data->contexts_.Size());
{ {
int num_templates = static_cast<int>(data->templates_.Size());
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
i::Handle<i::FixedArray> templates = // Convert list of context-independent data to FixedArray.
isolate->factory()->NewFixedArray(num_templates, i::TENURED); ConvertSerializedObjectsToFixedArray(isolate);
for (int i = 0; i < num_templates; i++) {
templates->set(i, *v8::Utils::OpenHandle(*data->templates_.Get(i))); // Convert lists of context-dependent data to FixedArray.
ConvertSerializedObjectsToFixedArray(
data->default_context_.Get(data->isolate_));
for (int i = 0; i < num_additional_contexts; i++) {
ConvertSerializedObjectsToFixedArray(data->contexts_.Get(i));
} }
isolate->heap()->SetSerializedTemplates(*templates);
data->templates_.Clear();
// We need to store the global proxy size upfront in case we need the // We need to store the global proxy size upfront in case we need the
// bootstrapper to create a global proxy before we deserialize the context. // bootstrapper to create a global proxy before we deserialize the context.
@ -706,13 +763,13 @@ StartupData SnapshotCreator::CreateBlob(
i::DisallowHeapAllocation no_gc_from_here_on; i::DisallowHeapAllocation no_gc_from_here_on;
std::vector<i::Object*> contexts; int num_contexts = num_additional_contexts + 1;
contexts.reserve(num_additional_contexts); std::vector<i::Context*> contexts;
i::Object* default_context; contexts.reserve(num_contexts);
{ {
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
default_context = contexts.push_back(
*v8::Utils::OpenHandle(*data->default_context_.Get(data->isolate_)); *v8::Utils::OpenHandle(*data->default_context_.Get(data->isolate_)));
data->default_context_.Reset(); data->default_context_.Reset();
for (int i = 0; i < num_additional_contexts; i++) { for (int i = 0; i < num_additional_contexts; i++) {
i::Handle<i::Context> context = i::Handle<i::Context> context =
@ -722,6 +779,10 @@ StartupData SnapshotCreator::CreateBlob(
data->contexts_.Clear(); data->contexts_.Clear();
} }
// Check that values referenced by global/eternal handles are accounted for.
i::SerializedHandleChecker handle_checker(isolate, &contexts);
CHECK(handle_checker.CheckGlobalAndEternalHandles());
// Complete in-object slack tracking for all functions. // Complete in-object slack tracking for all functions.
i::HeapIterator heap_iterator(isolate->heap()); i::HeapIterator heap_iterator(isolate->heap());
while (i::HeapObject* current_obj = heap_iterator.next()) { while (i::HeapObject* current_obj = heap_iterator.next()) {
@ -735,26 +796,18 @@ StartupData SnapshotCreator::CreateBlob(
// Serialize each context with a new partial serializer. // Serialize each context with a new partial serializer.
std::vector<i::SnapshotData*> context_snapshots; std::vector<i::SnapshotData*> context_snapshots;
context_snapshots.reserve(num_additional_contexts + 1); context_snapshots.reserve(num_contexts);
// TODO(6593): generalize rehashing, and remove this flag. // TODO(6593): generalize rehashing, and remove this flag.
bool can_be_rehashed = true; bool can_be_rehashed = true;
{ for (int i = 0; i < num_contexts; i++) {
// The default context is created with a handler for embedder fields which bool is_default_context = i == 0;
// determines how they are handled if encountered during serialization.
i::PartialSerializer partial_serializer( i::PartialSerializer partial_serializer(
isolate, &startup_serializer, isolate, &startup_serializer,
data->default_embedder_fields_serializer_); is_default_context ? data->default_embedder_fields_serializer_
partial_serializer.Serialize(&default_context, false); : data->embedder_fields_serializers_[i - 1]);
can_be_rehashed = can_be_rehashed && partial_serializer.can_be_rehashed(); partial_serializer.Serialize(&contexts[i], !is_default_context);
context_snapshots.push_back(new i::SnapshotData(&partial_serializer));
}
for (int i = 0; i < num_additional_contexts; i++) {
i::PartialSerializer partial_serializer(
isolate, &startup_serializer, data->embedder_fields_serializers_[i]);
partial_serializer.Serialize(&contexts[i], true);
can_be_rehashed = can_be_rehashed && partial_serializer.can_be_rehashed(); can_be_rehashed = can_be_rehashed && partial_serializer.can_be_rehashed();
context_snapshots.push_back(new i::SnapshotData(&partial_serializer)); context_snapshots.push_back(new i::SnapshotData(&partial_serializer));
} }
@ -778,6 +831,7 @@ StartupData SnapshotCreator::CreateBlob(
delete context_snapshot; delete context_snapshot;
} }
data->created_ = true; data->created_ = true;
return result; return result;
} }
@ -1419,10 +1473,10 @@ Local<FunctionTemplate> FunctionTemplate::New(
MaybeLocal<FunctionTemplate> FunctionTemplate::FromSnapshot(Isolate* isolate, MaybeLocal<FunctionTemplate> FunctionTemplate::FromSnapshot(Isolate* isolate,
size_t index) { size_t index) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::FixedArray* templates = i_isolate->heap()->serialized_templates(); i::FixedArray* serialized_objects = i_isolate->heap()->serialized_objects();
int int_index = static_cast<int>(index); int int_index = static_cast<int>(index);
if (int_index < templates->length()) { if (int_index < serialized_objects->length()) {
i::Object* info = templates->get(int_index); i::Object* info = serialized_objects->get(int_index);
if (info->IsFunctionTemplateInfo()) { if (info->IsFunctionTemplateInfo()) {
return Utils::ToLocal(i::Handle<i::FunctionTemplateInfo>( return Utils::ToLocal(i::Handle<i::FunctionTemplateInfo>(
i::FunctionTemplateInfo::cast(info))); i::FunctionTemplateInfo::cast(info)));
@ -1632,10 +1686,10 @@ Local<ObjectTemplate> ObjectTemplate::New(
MaybeLocal<ObjectTemplate> ObjectTemplate::FromSnapshot(Isolate* isolate, MaybeLocal<ObjectTemplate> ObjectTemplate::FromSnapshot(Isolate* isolate,
size_t index) { size_t index) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::FixedArray* templates = i_isolate->heap()->serialized_templates(); i::FixedArray* serialized_objects = i_isolate->heap()->serialized_objects();
int int_index = static_cast<int>(index); int int_index = static_cast<int>(index);
if (int_index < templates->length()) { if (int_index < serialized_objects->length()) {
i::Object* info = templates->get(int_index); i::Object* info = serialized_objects->get(int_index);
if (info->IsObjectTemplateInfo()) { if (info->IsObjectTemplateInfo()) {
return Utils::ToLocal( return Utils::ToLocal(
i::Handle<i::ObjectTemplateInfo>(i::ObjectTemplateInfo::cast(info))); i::Handle<i::ObjectTemplateInfo>(i::ObjectTemplateInfo::cast(info)));
@ -6448,6 +6502,31 @@ void Context::SetErrorMessageForCodeGenerationFromStrings(Local<String> error) {
context->set_error_message_for_code_gen_from_strings(*error_handle); context->set_error_message_for_code_gen_from_strings(*error_handle);
} }
namespace {
i::Object** GetSerializedDataFromFixedArray(i::Isolate* isolate,
i::FixedArray* list, size_t index) {
if (index < static_cast<size_t>(list->length())) {
int int_index = static_cast<int>(index);
i::Object* object = list->get(int_index);
if (!object->IsTheHole(isolate)) {
list->set_the_hole(isolate, int_index);
// Shrink the list so that the last element is not the hole.
int last = list->length() - 1;
while (last >= 0 && list->is_the_hole(isolate, last)) last--;
list->Shrink(last + 1);
return i::Handle<i::Object>(object, isolate).location();
}
}
return nullptr;
}
} // anonymous namespace
i::Object** Context::GetDataFromSnapshotOnce(size_t index) {
auto context = Utils::OpenHandle(this);
i::Isolate* i_isolate = context->GetIsolate();
i::FixedArray* list = i::FixedArray::cast(context->serialized_objects());
return GetSerializedDataFromFixedArray(i_isolate, list, index);
}
MaybeLocal<v8::Object> ObjectTemplate::NewInstance(Local<Context> context) { MaybeLocal<v8::Object> ObjectTemplate::NewInstance(Local<Context> context) {
PREPARE_FOR_EXECUTION(context, ObjectTemplate, NewInstance, Object); PREPARE_FOR_EXECUTION(context, ObjectTemplate, NewInstance, Object);
@ -6465,6 +6544,17 @@ Local<v8::Object> ObjectTemplate::NewInstance() {
RETURN_TO_LOCAL_UNCHECKED(NewInstance(context), Object); RETURN_TO_LOCAL_UNCHECKED(NewInstance(context), Object);
} }
void v8::ObjectTemplate::CheckCast(Data* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
Utils::ApiCheck(obj->IsObjectTemplateInfo(), "v8::ObjectTemplate::Cast",
"Could not convert to object template");
}
void v8::FunctionTemplate::CheckCast(Data* that) {
i::Handle<i::Object> obj = Utils::OpenHandle(that);
Utils::ApiCheck(obj->IsFunctionTemplateInfo(), "v8::FunctionTemplate::Cast",
"Could not convert to function template");
}
MaybeLocal<v8::Function> FunctionTemplate::GetFunction(Local<Context> context) { MaybeLocal<v8::Function> FunctionTemplate::GetFunction(Local<Context> context) {
PREPARE_FOR_EXECUTION(context, FunctionTemplate, GetFunction, Function); PREPARE_FOR_EXECUTION(context, FunctionTemplate, GetFunction, Function);
@ -8414,6 +8504,11 @@ Isolate::SuppressMicrotaskExecutionScope::~SuppressMicrotaskExecutionScope() {
isolate_->handle_scope_implementer()->DecrementCallDepth(); isolate_->handle_scope_implementer()->DecrementCallDepth();
} }
i::Object** Isolate::GetDataFromSnapshotOnce(size_t index) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(this);
i::FixedArray* list = i_isolate->heap()->serialized_objects();
return GetSerializedDataFromFixedArray(i_isolate, list, index);
}
void Isolate::GetHeapStatistics(HeapStatistics* heap_statistics) { void Isolate::GetHeapStatistics(HeapStatistics* heap_statistics) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this); i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);

View File

@ -345,6 +345,7 @@ enum ContextLookupFlags {
V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \ V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \
V(SECURITY_TOKEN_INDEX, Object, security_token) \ V(SECURITY_TOKEN_INDEX, Object, security_token) \
V(SELF_WEAK_CELL_INDEX, WeakCell, self_weak_cell) \ V(SELF_WEAK_CELL_INDEX, WeakCell, self_weak_cell) \
V(SERIALIZED_OBJECTS, FixedArray, serialized_objects) \
V(SET_VALUE_ITERATOR_MAP_INDEX, Map, set_value_iterator_map) \ V(SET_VALUE_ITERATOR_MAP_INDEX, Map, set_value_iterator_map) \
V(SET_KEY_VALUE_ITERATOR_MAP_INDEX, Map, set_key_value_iterator_map) \ V(SET_KEY_VALUE_ITERATOR_MAP_INDEX, Map, set_key_value_iterator_map) \
V(SHARED_ARRAY_BUFFER_FUN_INDEX, JSFunction, shared_array_buffer_fun) \ V(SHARED_ARRAY_BUFFER_FUN_INDEX, JSFunction, shared_array_buffer_fun) \

View File

@ -995,6 +995,7 @@ Handle<Context> Factory::NewNativeContext() {
context->set_math_random_index(Smi::kZero); context->set_math_random_index(Smi::kZero);
Handle<WeakCell> weak_cell = NewWeakCell(context); Handle<WeakCell> weak_cell = NewWeakCell(context);
context->set_self_weak_cell(*weak_cell); context->set_self_weak_cell(*weak_cell);
context->set_serialized_objects(*empty_fixed_array());
DCHECK(context->IsNativeContext()); DCHECK(context->IsNativeContext());
return context; return context;
} }

View File

@ -94,14 +94,12 @@ void Heap::SetInterpreterEntryReturnPCOffset(int pc_offset) {
set_interpreter_entry_return_pc_offset(Smi::FromInt(pc_offset)); set_interpreter_entry_return_pc_offset(Smi::FromInt(pc_offset));
} }
void Heap::SetSerializedTemplates(FixedArray* templates) { void Heap::SetSerializedObjects(FixedArray* objects) {
DCHECK_EQ(empty_fixed_array(), serialized_templates());
DCHECK(isolate()->serializer_enabled()); DCHECK(isolate()->serializer_enabled());
set_serialized_templates(templates); set_serialized_objects(objects);
} }
void Heap::SetSerializedGlobalProxySizes(FixedArray* sizes) { void Heap::SetSerializedGlobalProxySizes(FixedArray* sizes) {
DCHECK_EQ(empty_fixed_array(), serialized_global_proxy_sizes());
DCHECK(isolate()->serializer_enabled()); DCHECK(isolate()->serializer_enabled());
set_serialized_global_proxy_sizes(sizes); set_serialized_global_proxy_sizes(sizes);
} }
@ -2658,7 +2656,7 @@ bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
case kFeedbackVectorsForProfilingToolsRootIndex: case kFeedbackVectorsForProfilingToolsRootIndex:
case kNoScriptSharedFunctionInfosRootIndex: case kNoScriptSharedFunctionInfosRootIndex:
case kWeakStackTraceListRootIndex: case kWeakStackTraceListRootIndex:
case kSerializedTemplatesRootIndex: case kSerializedObjectsRootIndex:
case kSerializedGlobalProxySizesRootIndex: case kSerializedGlobalProxySizesRootIndex:
case kPublicSymbolTableRootIndex: case kPublicSymbolTableRootIndex:
case kApiSymbolTableRootIndex: case kApiSymbolTableRootIndex:
@ -4984,6 +4982,9 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
// Iterate over global handles. // Iterate over global handles.
switch (mode) { switch (mode) {
case VISIT_FOR_SERIALIZATION: case VISIT_FOR_SERIALIZATION:
// Global handles are not iterated by the serializer. Values referenced by
// global handles need to be added manually.
break;
case VISIT_ONLY_STRONG: case VISIT_ONLY_STRONG:
isolate_->global_handles()->IterateStrongRoots(v); isolate_->global_handles()->IterateStrongRoots(v);
break; break;
@ -5003,12 +5004,15 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
} }
v->Synchronize(VisitorSynchronization::kGlobalHandles); v->Synchronize(VisitorSynchronization::kGlobalHandles);
// Iterate over eternal handles. // Iterate over eternal handles. Eternal handles are not iterated by the
// serializer. Values referenced by eternal handles need to be added manually.
if (mode != VISIT_FOR_SERIALIZATION) {
if (isMinorGC) { if (isMinorGC) {
isolate_->eternal_handles()->IterateNewSpaceRoots(v); isolate_->eternal_handles()->IterateNewSpaceRoots(v);
} else { } else {
isolate_->eternal_handles()->IterateAllRoots(v); isolate_->eternal_handles()->IterateAllRoots(v);
} }
}
v->Synchronize(VisitorSynchronization::kEternalHandles); v->Synchronize(VisitorSynchronization::kEternalHandles);
// Iterate over pointers being held by inactive threads. // Iterate over pointers being held by inactive threads.
@ -5024,11 +5028,9 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
// Iterate over the partial snapshot cache unless serializing. // Iterate over the partial snapshot cache unless serializing.
if (mode != VISIT_FOR_SERIALIZATION) { if (mode != VISIT_FOR_SERIALIZATION) {
SerializerDeserializer::Iterate(isolate_, v); SerializerDeserializer::Iterate(isolate_, v);
// We don't do a v->Synchronize call here because the serializer and the
// deserializer are deliberately out of sync here.
} }
// We don't do a v->Synchronize call here, because in debug mode that will
// output a flag to the snapshot. However at this point the serializer and
// deserializer are deliberately a little unsynchronized (see above) so the
// checking of the sync flag in the snapshot would fail.
} }

View File

@ -106,6 +106,7 @@ using v8::MemoryPressureLevel;
V(Map, script_context_table_map, ScriptContextTableMap) \ V(Map, script_context_table_map, ScriptContextTableMap) \
/* Maps */ \ /* Maps */ \
V(Map, descriptor_array_map, DescriptorArrayMap) \ V(Map, descriptor_array_map, DescriptorArrayMap) \
V(Map, array_list_map, ArrayListMap) \
V(Map, fixed_double_array_map, FixedDoubleArrayMap) \ V(Map, fixed_double_array_map, FixedDoubleArrayMap) \
V(Map, mutable_heap_number_map, MutableHeapNumberMap) \ V(Map, mutable_heap_number_map, MutableHeapNumberMap) \
V(Map, ordered_hash_map_map, OrderedHashMapMap) \ V(Map, ordered_hash_map_map, OrderedHashMapMap) \
@ -246,7 +247,7 @@ using v8::MemoryPressureLevel;
FeedbackVectorsForProfilingTools) \ FeedbackVectorsForProfilingTools) \
V(Object, weak_stack_trace_list, WeakStackTraceList) \ V(Object, weak_stack_trace_list, WeakStackTraceList) \
V(Object, noscript_shared_function_infos, NoScriptSharedFunctionInfos) \ V(Object, noscript_shared_function_infos, NoScriptSharedFunctionInfos) \
V(FixedArray, serialized_templates, SerializedTemplates) \ V(FixedArray, serialized_objects, SerializedObjects) \
V(FixedArray, serialized_global_proxy_sizes, SerializedGlobalProxySizes) \ V(FixedArray, serialized_global_proxy_sizes, SerializedGlobalProxySizes) \
V(TemplateList, message_listeners, MessageListeners) \ V(TemplateList, message_listeners, MessageListeners) \
/* DeserializeLazy handlers for lazy bytecode deserialization */ \ /* DeserializeLazy handlers for lazy bytecode deserialization */ \
@ -851,7 +852,7 @@ class Heap {
inline int NextScriptId(); inline int NextScriptId();
inline int GetNextTemplateSerialNumber(); inline int GetNextTemplateSerialNumber();
void SetSerializedTemplates(FixedArray* templates); void SetSerializedObjects(FixedArray* objects);
void SetSerializedGlobalProxySizes(FixedArray* sizes); void SetSerializedGlobalProxySizes(FixedArray* sizes);
// For post mortem debugging. // For post mortem debugging.

View File

@ -326,8 +326,8 @@ void ObjectStatsCollector::CollectGlobalStatistics() {
// Global FixedArrays. // Global FixedArrays.
RecordFixedArrayHelper(nullptr, heap_->weak_new_space_object_to_code_list(), RecordFixedArrayHelper(nullptr, heap_->weak_new_space_object_to_code_list(),
WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE, 0); WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE, 0);
RecordFixedArrayHelper(nullptr, heap_->serialized_templates(), RecordFixedArrayHelper(nullptr, heap_->serialized_objects(),
SERIALIZED_TEMPLATES_SUB_TYPE, 0); SERIALIZED_OBJECTS_SUB_TYPE, 0);
RecordFixedArrayHelper(nullptr, heap_->number_string_cache(), RecordFixedArrayHelper(nullptr, heap_->number_string_cache(),
NUMBER_STRING_CACHE_SUB_TYPE, 0); NUMBER_STRING_CACHE_SUB_TYPE, 0);
RecordFixedArrayHelper(nullptr, heap_->single_character_string_cache(), RecordFixedArrayHelper(nullptr, heap_->single_character_string_cache(),

View File

@ -306,6 +306,8 @@ bool Heap::CreateInitialMaps() {
ALLOCATE_VARSIZE_MAP(HASH_TABLE_TYPE, string_table) ALLOCATE_VARSIZE_MAP(HASH_TABLE_TYPE, string_table)
ALLOCATE_VARSIZE_MAP(HASH_TABLE_TYPE, weak_hash_table) ALLOCATE_VARSIZE_MAP(HASH_TABLE_TYPE, weak_hash_table)
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, array_list)
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, function_context) ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, function_context)
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, catch_context) ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, catch_context)
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, with_context) ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, with_context)
@ -557,9 +559,7 @@ void Heap::CreateInitialObjects() {
set_weak_object_to_code_table(*WeakHashTable::New(isolate(), 16, TENURED)); set_weak_object_to_code_table(*WeakHashTable::New(isolate(), 16, TENURED));
set_weak_new_space_object_to_code_list( set_weak_new_space_object_to_code_list(*ArrayList::New(isolate(), 16));
ArrayList::cast(*(factory->NewFixedArray(16, TENURED))));
weak_new_space_object_to_code_list()->SetLength(0);
set_feedback_vectors_for_profiling_tools(undefined_value()); set_feedback_vectors_for_profiling_tools(undefined_value());
@ -638,7 +638,7 @@ void Heap::CreateInitialObjects() {
cell->set_value(Smi::FromInt(Isolate::kProtectorValid)); cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
set_array_buffer_neutering_protector(*cell); set_array_buffer_neutering_protector(*cell);
set_serialized_templates(empty_fixed_array()); set_serialized_objects(empty_fixed_array());
set_serialized_global_proxy_sizes(empty_fixed_array()); set_serialized_global_proxy_sizes(empty_fixed_array());
set_weak_stack_trace_list(Smi::kZero); set_weak_stack_trace_list(Smi::kZero);

View File

@ -328,7 +328,10 @@ bool HeapObject::IsEnumCache() const { return IsTuple2(); }
bool HeapObject::IsFrameArray() const { return IsFixedArrayExact(); } bool HeapObject::IsFrameArray() const { return IsFixedArrayExact(); }
bool HeapObject::IsArrayList() const { return IsFixedArrayExact(); } bool HeapObject::IsArrayList() const {
return map() == GetHeap()->array_list_map() ||
this == GetHeap()->empty_fixed_array();
}
bool HeapObject::IsRegExpMatchInfo() const { return IsFixedArrayExact(); } bool HeapObject::IsRegExpMatchInfo() const { return IsFixedArrayExact(); }

View File

@ -10237,8 +10237,10 @@ Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
// static // static
Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) { Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
Handle<ArrayList> result = Handle<ArrayList>::cast( Handle<FixedArray> fixed_array =
isolate->factory()->NewFixedArray(size + kFirstIndex)); isolate->factory()->NewFixedArray(size + kFirstIndex);
fixed_array->set_map_no_write_barrier(isolate->heap()->array_list_map());
Handle<ArrayList> result = Handle<ArrayList>::cast(fixed_array);
result->SetLength(0); result->SetLength(0);
return result; return result;
} }
@ -10277,10 +10279,13 @@ Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array,
// static // static
Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) { Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
const bool empty = (array->length() == 0); const bool empty = (array->length() == 0);
auto ret = Handle<ArrayList>::cast( auto ret = EnsureSpaceInFixedArray(array, kFirstIndex + length);
EnsureSpaceInFixedArray(array, kFirstIndex + length)); if (empty) {
if (empty) ret->SetLength(0); ret->set_map_no_write_barrier(array->GetHeap()->array_list_map());
return ret;
Handle<ArrayList>::cast(ret)->SetLength(0);
}
return Handle<ArrayList>::cast(ret);
} }
Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures( Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(

View File

@ -45,7 +45,7 @@ namespace internal {
V(RETAINED_MAPS_SUB_TYPE) \ V(RETAINED_MAPS_SUB_TYPE) \
V(SCOPE_INFO_SUB_TYPE) \ V(SCOPE_INFO_SUB_TYPE) \
V(SCRIPT_LIST_SUB_TYPE) \ V(SCRIPT_LIST_SUB_TYPE) \
V(SERIALIZED_TEMPLATES_SUB_TYPE) \ V(SERIALIZED_OBJECTS_SUB_TYPE) \
V(SHARED_FUNCTION_INFOS_SUB_TYPE) \ V(SHARED_FUNCTION_INFOS_SUB_TYPE) \
V(SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE) \ V(SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE) \
V(SLOW_TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE) \ V(SLOW_TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE) \

View File

@ -17,7 +17,8 @@ PartialSerializer::PartialSerializer(
: Serializer(isolate), : Serializer(isolate),
startup_serializer_(startup_serializer), startup_serializer_(startup_serializer),
serialize_embedder_fields_(callback), serialize_embedder_fields_(callback),
can_be_rehashed_(true) { can_be_rehashed_(true),
context_(nullptr) {
InitializeCodeAddressMap(); InitializeCodeAddressMap();
} }
@ -25,24 +26,23 @@ PartialSerializer::~PartialSerializer() {
OutputStatistics("PartialSerializer"); OutputStatistics("PartialSerializer");
} }
void PartialSerializer::Serialize(Object** o, bool include_global_proxy) { void PartialSerializer::Serialize(Context** o, bool include_global_proxy) {
DCHECK((*o)->IsNativeContext()); context_ = *o;
DCHECK(context_->IsNativeContext());
Context* context = Context::cast(*o); reference_map()->AddAttachedReference(context_->global_proxy());
reference_map()->AddAttachedReference(context->global_proxy());
// The bootstrap snapshot has a code-stub context. When serializing the // The bootstrap snapshot has a code-stub context. When serializing the
// partial snapshot, it is chained into the weak context list on the isolate // partial snapshot, it is chained into the weak context list on the isolate
// and it's next context pointer may point to the code-stub context. Clear // and it's next context pointer may point to the code-stub context. Clear
// it before serializing, it will get re-added to the context list // it before serializing, it will get re-added to the context list
// explicitly when it's loaded. // explicitly when it's loaded.
context->set(Context::NEXT_CONTEXT_LINK, context_->set(Context::NEXT_CONTEXT_LINK,
isolate()->heap()->undefined_value()); isolate()->heap()->undefined_value());
DCHECK(!context->global_object()->IsUndefined(context->GetIsolate())); DCHECK(!context_->global_object()->IsUndefined(context_->GetIsolate()));
// Reset math random cache to get fresh random numbers. // Reset math random cache to get fresh random numbers.
context->set_math_random_index(Smi::kZero); context_->set_math_random_index(Smi::kZero);
context->set_math_random_cache(isolate()->heap()->undefined_value()); context_->set_math_random_cache(isolate()->heap()->undefined_value());
VisitRootPointer(Root::kPartialSnapshotCache, o); VisitRootPointer(Root::kPartialSnapshotCache, reinterpret_cast<Object**>(o));
SerializeDeferredObjects(); SerializeDeferredObjects();
SerializeEmbedderFields(); SerializeEmbedderFields();
Pad(); Pad();
@ -87,6 +87,8 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
DCHECK(!obj->IsInternalizedString()); DCHECK(!obj->IsInternalizedString());
// Function and object templates are not context specific. // Function and object templates are not context specific.
DCHECK(!obj->IsTemplateInfo()); DCHECK(!obj->IsTemplateInfo());
// We should not end up at another native context.
DCHECK_IMPLIES(obj != context_, !obj->IsNativeContext());
FlushSkip(skip); FlushSkip(skip);

View File

@ -21,7 +21,7 @@ class PartialSerializer : public Serializer<> {
~PartialSerializer() override; ~PartialSerializer() override;
// Serialize the objects reachable from a single object pointer. // Serialize the objects reachable from a single object pointer.
void Serialize(Object** o, bool include_global_proxy); void Serialize(Context** o, bool include_global_proxy);
bool can_be_rehashed() const { return can_be_rehashed_; } bool can_be_rehashed() const { return can_be_rehashed_; }
@ -41,6 +41,7 @@ class PartialSerializer : public Serializer<> {
// Indicates whether we only serialized hash tables that we can rehash. // Indicates whether we only serialized hash tables that we can rehash.
// TODO(yangguo): generalize rehashing, and remove this flag. // TODO(yangguo): generalize rehashing, and remove this flag.
bool can_be_rehashed_; bool can_be_rehashed_;
Context* context_;
DISALLOW_COPY_AND_ASSIGN(PartialSerializer); DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
}; };

View File

@ -122,8 +122,7 @@ void StartupSerializer::SerializeStrongReferences() {
CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse()); CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
// No active or weak handles. // No active or weak handles.
CHECK(isolate->handle_scope_implementer()->blocks()->empty()); CHECK(isolate->handle_scope_implementer()->blocks()->empty());
CHECK_EQ(0, isolate->global_handles()->global_handles_count());
CHECK_EQ(0, isolate->eternal_handles()->NumberOfHandles());
// Visit smi roots. // Visit smi roots.
// Clear the stack limits to make the snapshot reproducible. // Clear the stack limits to make the snapshot reproducible.
// Reset it again afterwards. // Reset it again afterwards.
@ -184,5 +183,36 @@ bool StartupSerializer::MustBeDeferred(HeapObject* object) {
return !object->IsMap(); return !object->IsMap();
} }
SerializedHandleChecker::SerializedHandleChecker(
Isolate* isolate, std::vector<Context*>* contexts)
: isolate_(isolate) {
AddToSet(isolate->heap()->serialized_objects());
for (auto const& context : *contexts) {
AddToSet(context->serialized_objects());
}
}
void SerializedHandleChecker::AddToSet(FixedArray* serialized) {
int length = serialized->length();
for (int i = 0; i < length; i++) serialized_.insert(serialized->get(i));
}
void SerializedHandleChecker::VisitRootPointers(Root root, Object** start,
Object** end) {
for (Object** p = start; p < end; p++) {
if (serialized_.find(*p) != serialized_.end()) continue;
PrintF("%s handle not serialized: ",
root == Root::kGlobalHandles ? "global" : "eternal");
(*p)->Print();
ok_ = false;
}
}
bool SerializedHandleChecker::CheckGlobalAndEternalHandles() {
isolate_->global_handles()->IterateAllRoots(this);
isolate_->eternal_handles()->IterateAllRoots(this);
return ok_;
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8

View File

@ -83,6 +83,20 @@ class StartupSerializer : public Serializer<> {
DISALLOW_COPY_AND_ASSIGN(StartupSerializer); DISALLOW_COPY_AND_ASSIGN(StartupSerializer);
}; };
class SerializedHandleChecker : public RootVisitor {
public:
SerializedHandleChecker(Isolate* isolate, std::vector<Context*>* contexts);
virtual void VisitRootPointers(Root root, Object** start, Object** end);
bool CheckGlobalAndEternalHandles();
private:
void AddToSet(FixedArray* serialized);
Isolate* isolate_;
std::unordered_set<Object*> serialized_;
bool ok_ = true;
};
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8

View File

@ -112,6 +112,7 @@
# Test that serialization with unknown external reference fails. # Test that serialization with unknown external reference fails.
'test-serialize/SnapshotCreatorUnknownExternalReferences': [FAIL], 'test-serialize/SnapshotCreatorUnknownExternalReferences': [FAIL],
'test-serialize/SnapshotCreatorUnknownHandles': [FAIL],
'test-serialize/SnapshotCreatorNoExternalReferencesCustomFail1': [FAIL], 'test-serialize/SnapshotCreatorNoExternalReferencesCustomFail1': [FAIL],
'test-serialize/SnapshotCreatorNoExternalReferencesCustomFail2': [FAIL], 'test-serialize/SnapshotCreatorNoExternalReferencesCustomFail2': [FAIL],

View File

@ -371,7 +371,7 @@ static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
} }
i::Object* raw_context = *v8::Utils::OpenPersistent(env); i::Context* raw_context = i::Context::cast(*v8::Utils::OpenPersistent(env));
env.Reset(); env.Reset();
@ -496,7 +496,7 @@ static void PartiallySerializeCustomContext(
v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); v8::Local<v8::Context>::New(v8_isolate, env)->Exit();
} }
i::Object* raw_context = *v8::Utils::OpenPersistent(env); i::Context* raw_context = i::Context::cast(*v8::Utils::OpenPersistent(env));
env.Reset(); env.Reset();
@ -2776,6 +2776,206 @@ TEST(SnapshotCreatorTemplates) {
delete[] blob.data; delete[] blob.data;
} }
TEST(SnapshotCreatorAddData) {
DisableAlwaysOpt();
v8::StartupData blob;
{
v8::SnapshotCreator creator;
v8::Isolate* isolate = creator.GetIsolate();
v8::Eternal<v8::Value> eternal_number;
v8::Persistent<v8::Value> persistent_number_1;
v8::Persistent<v8::Value> persistent_number_2;
v8::Persistent<v8::Context> persistent_context;
{
v8::HandleScope handle_scope(isolate);
eternal_number.Set(isolate, v8_num(2017));
persistent_number_1.Reset(isolate, v8_num(2018));
persistent_number_2.Reset(isolate, v8_num(2019));
v8::Local<v8::Context> context = v8::Context::New(isolate);
CHECK_EQ(0u, creator.AddData(context, persistent_number_2.Get(isolate)));
creator.SetDefaultContext(context);
context = v8::Context::New(isolate);
persistent_context.Reset(isolate, context);
v8::Context::Scope context_scope(context);
v8::Local<v8::Object> object = CompileRun("({ p: 12 })").As<v8::Object>();
v8::Local<v8::ObjectTemplate> object_template =
v8::ObjectTemplate::New(isolate);
object_template->SetInternalFieldCount(3);
CHECK_EQ(0u, creator.AddData(context, object));
CHECK_EQ(1u, creator.AddData(context, v8_str("context-dependent")));
CHECK_EQ(2u, creator.AddData(context, persistent_number_1.Get(isolate)));
CHECK_EQ(3u, creator.AddData(context, object_template));
CHECK_EQ(4u, creator.AddData(context, persistent_context.Get(isolate)));
creator.AddContext(context);
CHECK_EQ(0u, creator.AddData(v8_str("context-independent")));
CHECK_EQ(1u, creator.AddData(eternal_number.Get(isolate)));
CHECK_EQ(2u, creator.AddData(object_template));
CHECK_EQ(3u, creator.AddData(v8::FunctionTemplate::New(isolate)));
}
blob =
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
}
{
v8::Isolate::CreateParams params;
params.snapshot_blob = &blob;
params.array_buffer_allocator = CcTest::array_buffer_allocator();
// Test-appropriate equivalent of v8::Isolate::New.
v8::Isolate* isolate = TestIsolate::New(params);
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
// Check serialized data on the context.
v8::Local<v8::Object> object =
context->GetDataFromSnapshotOnce<v8::Object>(0).ToLocalChecked();
CHECK(context->GetDataFromSnapshotOnce<v8::Object>(0).IsEmpty());
CHECK_EQ(12, object->Get(context, v8_str("p"))
.ToLocalChecked()
->Int32Value(context)
.FromJust());
v8::Local<v8::String> string =
context->GetDataFromSnapshotOnce<v8::String>(1).ToLocalChecked();
CHECK(context->GetDataFromSnapshotOnce<v8::String>(1).IsEmpty());
CHECK(string->Equals(context, v8_str("context-dependent")).FromJust());
v8::Local<v8::Number> number =
context->GetDataFromSnapshotOnce<v8::Number>(2).ToLocalChecked();
CHECK(context->GetDataFromSnapshotOnce<v8::Number>(2).IsEmpty());
CHECK_EQ(2018, number->Int32Value(context).FromJust());
v8::Local<v8::ObjectTemplate> templ =
context->GetDataFromSnapshotOnce<v8::ObjectTemplate>(3)
.ToLocalChecked();
CHECK(context->GetDataFromSnapshotOnce<v8::ObjectTemplate>(3).IsEmpty());
CHECK_EQ(3, templ->InternalFieldCount());
v8::Local<v8::Context> serialized_context =
context->GetDataFromSnapshotOnce<v8::Context>(4).ToLocalChecked();
CHECK(context->GetDataFromSnapshotOnce<v8::Context>(4).IsEmpty());
CHECK_EQ(*v8::Utils::OpenHandle(*serialized_context),
*v8::Utils::OpenHandle(*context));
CHECK(context->GetDataFromSnapshotOnce<v8::Value>(5).IsEmpty());
// Check serialized data on the isolate.
string = isolate->GetDataFromSnapshotOnce<v8::String>(0).ToLocalChecked();
CHECK(context->GetDataFromSnapshotOnce<v8::String>(0).IsEmpty());
CHECK(string->Equals(context, v8_str("context-independent")).FromJust());
number = isolate->GetDataFromSnapshotOnce<v8::Number>(1).ToLocalChecked();
CHECK(isolate->GetDataFromSnapshotOnce<v8::Number>(1).IsEmpty());
CHECK_EQ(2017, number->Int32Value(context).FromJust());
templ = isolate->GetDataFromSnapshotOnce<v8::ObjectTemplate>(2)
.ToLocalChecked();
CHECK(isolate->GetDataFromSnapshotOnce<v8::ObjectTemplate>(2).IsEmpty());
CHECK_EQ(3, templ->InternalFieldCount());
isolate->GetDataFromSnapshotOnce<v8::FunctionTemplate>(3)
.ToLocalChecked();
CHECK(
isolate->GetDataFromSnapshotOnce<v8::FunctionTemplate>(3).IsEmpty());
CHECK(isolate->GetDataFromSnapshotOnce<v8::Value>(4).IsEmpty());
}
isolate->Dispose();
}
{
SnapshotCreator creator(nullptr, &blob);
v8::Isolate* isolate = creator.GetIsolate();
{
// Adding data to a snapshot replaces the list of existing data.
v8::HandleScope hscope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
creator.SetDefaultContext(context);
context = v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
v8::Local<v8::String> string =
context->GetDataFromSnapshotOnce<v8::String>(1).ToLocalChecked();
CHECK(context->GetDataFromSnapshotOnce<v8::String>(1).IsEmpty());
CHECK(string->Equals(context, v8_str("context-dependent")).FromJust());
v8::Local<v8::Number> number =
isolate->GetDataFromSnapshotOnce<v8::Number>(1).ToLocalChecked();
CHECK(isolate->GetDataFromSnapshotOnce<v8::Number>(1).IsEmpty());
CHECK_EQ(2017, number->Int32Value(context).FromJust());
CHECK_EQ(0u, creator.AddData(context, v8_num(2016)));
CHECK_EQ(0u, creator.AddContext(context));
CHECK_EQ(0u, creator.AddData(v8_str("stuff")));
}
delete[] blob.data;
blob =
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
}
{
v8::Isolate::CreateParams params;
params.snapshot_blob = &blob;
params.array_buffer_allocator = CcTest::array_buffer_allocator();
// Test-appropriate equivalent of v8::Isolate::New.
v8::Isolate* isolate = TestIsolate::New(params);
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
// Context where we did not re-add data no longer has data.
v8::Local<v8::Context> context = v8::Context::New(isolate);
CHECK(context->GetDataFromSnapshotOnce<v8::Object>(0).IsEmpty());
// Context where we re-added data has completely new ones.
context = v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
v8::Local<v8::Value> value =
context->GetDataFromSnapshotOnce<v8::Value>(0).ToLocalChecked();
CHECK_EQ(2016, value->Int32Value(context).FromJust());
CHECK(context->GetDataFromSnapshotOnce<v8::Value>(1).IsEmpty());
// Ditto for the isolate.
v8::Local<v8::String> string =
isolate->GetDataFromSnapshotOnce<v8::String>(0).ToLocalChecked();
CHECK(string->Equals(context, v8_str("stuff")).FromJust());
CHECK(context->GetDataFromSnapshotOnce<v8::String>(1).IsEmpty());
}
isolate->Dispose();
}
delete[] blob.data;
}
TEST(SnapshotCreatorUnknownHandles) {
DisableAlwaysOpt();
v8::StartupData blob;
{
v8::SnapshotCreator creator;
v8::Isolate* isolate = creator.GetIsolate();
v8::Eternal<v8::Value> eternal_number;
v8::Persistent<v8::Value> persistent_number;
{
v8::HandleScope handle_scope(isolate);
eternal_number.Set(isolate, v8_num(2017));
persistent_number.Reset(isolate, v8_num(2018));
v8::Local<v8::Context> context = v8::Context::New(isolate);
creator.SetDefaultContext(context);
}
blob =
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
}
delete[] blob.data;
}
TEST(SnapshotCreatorIncludeGlobalProxy) { TEST(SnapshotCreatorIncludeGlobalProxy) {
DisableAlwaysOpt(); DisableAlwaysOpt();
v8::StartupData blob; v8::StartupData blob;

View File

@ -206,79 +206,80 @@ KNOWN_MAPS = {
0x02e31: (171, "WithContextMap"), 0x02e31: (171, "WithContextMap"),
0x02e81: (171, "DebugEvaluateContextMap"), 0x02e81: (171, "DebugEvaluateContextMap"),
0x02ed1: (171, "ScriptContextTableMap"), 0x02ed1: (171, "ScriptContextTableMap"),
0x02f21: (148, "FixedDoubleArrayMap"), 0x02f21: (171, "ArrayListMap"),
0x02f71: (134, "MutableHeapNumberMap"), 0x02f71: (148, "FixedDoubleArrayMap"),
0x02fc1: (173, "OrderedHashMapMap"), 0x02fc1: (134, "MutableHeapNumberMap"),
0x03011: (173, "OrderedHashSetMap"), 0x03011: (173, "OrderedHashMapMap"),
0x03061: (173, "NameDictionaryMap"), 0x03061: (173, "OrderedHashSetMap"),
0x030b1: (173, "GlobalDictionaryMap"), 0x030b1: (173, "NameDictionaryMap"),
0x03101: (173, "NumberDictionaryMap"), 0x03101: (173, "GlobalDictionaryMap"),
0x03151: (173, "StringTableMap"), 0x03151: (173, "NumberDictionaryMap"),
0x031a1: (173, "WeakHashTableMap"), 0x031a1: (173, "StringTableMap"),
0x031f1: (171, "SloppyArgumentsElementsMap"), 0x031f1: (173, "WeakHashTableMap"),
0x03241: (182, "SmallOrderedHashMapMap"), 0x03241: (171, "SloppyArgumentsElementsMap"),
0x03291: (183, "SmallOrderedHashSetMap"), 0x03291: (182, "SmallOrderedHashMapMap"),
0x032e1: (176, "CodeDataContainerMap"), 0x032e1: (183, "SmallOrderedHashSetMap"),
0x03331: (1071, "JSMessageObjectMap"), 0x03331: (176, "CodeDataContainerMap"),
0x03381: (1057, "ExternalMap"), 0x03381: (1071, "JSMessageObjectMap"),
0x033d1: (137, "BytecodeArrayMap"), 0x033d1: (1057, "ExternalMap"),
0x03421: (171, "ModuleInfoMap"), 0x03421: (137, "BytecodeArrayMap"),
0x03471: (175, "NoClosuresCellMap"), 0x03471: (171, "ModuleInfoMap"),
0x034c1: (175, "OneClosureCellMap"), 0x034c1: (175, "NoClosuresCellMap"),
0x03511: (175, "ManyClosuresCellMap"), 0x03511: (175, "OneClosureCellMap"),
0x03561: (179, "PropertyArrayMap"), 0x03561: (175, "ManyClosuresCellMap"),
0x035b1: (130, "BigIntMap"), 0x035b1: (179, "PropertyArrayMap"),
0x03601: (106, "NativeSourceStringMap"), 0x03601: (130, "BigIntMap"),
0x03651: (64, "StringMap"), 0x03651: (106, "NativeSourceStringMap"),
0x036a1: (73, "ConsOneByteStringMap"), 0x036a1: (64, "StringMap"),
0x036f1: (65, "ConsStringMap"), 0x036f1: (73, "ConsOneByteStringMap"),
0x03741: (77, "ThinOneByteStringMap"), 0x03741: (65, "ConsStringMap"),
0x03791: (69, "ThinStringMap"), 0x03791: (77, "ThinOneByteStringMap"),
0x037e1: (67, "SlicedStringMap"), 0x037e1: (69, "ThinStringMap"),
0x03831: (75, "SlicedOneByteStringMap"), 0x03831: (67, "SlicedStringMap"),
0x03881: (66, "ExternalStringMap"), 0x03881: (75, "SlicedOneByteStringMap"),
0x038d1: (82, "ExternalStringWithOneByteDataMap"), 0x038d1: (66, "ExternalStringMap"),
0x03921: (74, "ExternalOneByteStringMap"), 0x03921: (82, "ExternalStringWithOneByteDataMap"),
0x03971: (98, "ShortExternalStringMap"), 0x03971: (74, "ExternalOneByteStringMap"),
0x039c1: (114, "ShortExternalStringWithOneByteDataMap"), 0x039c1: (98, "ShortExternalStringMap"),
0x03a11: (0, "InternalizedStringMap"), 0x03a11: (114, "ShortExternalStringWithOneByteDataMap"),
0x03a61: (2, "ExternalInternalizedStringMap"), 0x03a61: (0, "InternalizedStringMap"),
0x03ab1: (18, "ExternalInternalizedStringWithOneByteDataMap"), 0x03ab1: (2, "ExternalInternalizedStringMap"),
0x03b01: (10, "ExternalOneByteInternalizedStringMap"), 0x03b01: (18, "ExternalInternalizedStringWithOneByteDataMap"),
0x03b51: (34, "ShortExternalInternalizedStringMap"), 0x03b51: (10, "ExternalOneByteInternalizedStringMap"),
0x03ba1: (50, "ShortExternalInternalizedStringWithOneByteDataMap"), 0x03ba1: (34, "ShortExternalInternalizedStringMap"),
0x03bf1: (42, "ShortExternalOneByteInternalizedStringMap"), 0x03bf1: (50, "ShortExternalInternalizedStringWithOneByteDataMap"),
0x03c41: (106, "ShortExternalOneByteStringMap"), 0x03c41: (42, "ShortExternalOneByteInternalizedStringMap"),
0x03c91: (140, "FixedUint8ArrayMap"), 0x03c91: (106, "ShortExternalOneByteStringMap"),
0x03ce1: (139, "FixedInt8ArrayMap"), 0x03ce1: (140, "FixedUint8ArrayMap"),
0x03d31: (142, "FixedUint16ArrayMap"), 0x03d31: (139, "FixedInt8ArrayMap"),
0x03d81: (141, "FixedInt16ArrayMap"), 0x03d81: (142, "FixedUint16ArrayMap"),
0x03dd1: (144, "FixedUint32ArrayMap"), 0x03dd1: (141, "FixedInt16ArrayMap"),
0x03e21: (143, "FixedInt32ArrayMap"), 0x03e21: (144, "FixedUint32ArrayMap"),
0x03e71: (145, "FixedFloat32ArrayMap"), 0x03e71: (143, "FixedInt32ArrayMap"),
0x03ec1: (146, "FixedFloat64ArrayMap"), 0x03ec1: (145, "FixedFloat32ArrayMap"),
0x03f11: (147, "FixedUint8ClampedArrayMap"), 0x03f11: (146, "FixedFloat64ArrayMap"),
0x03f61: (169, "Tuple2Map"), 0x03f61: (147, "FixedUint8ClampedArrayMap"),
0x03fb1: (167, "ScriptMap"), 0x03fb1: (169, "Tuple2Map"),
0x04001: (160, "InterceptorInfoMap"), 0x04001: (167, "ScriptMap"),
0x04051: (151, "AccessorInfoMap"), 0x04051: (160, "InterceptorInfoMap"),
0x040a1: (150, "AccessCheckInfoMap"), 0x040a1: (151, "AccessorInfoMap"),
0x040f1: (152, "AccessorPairMap"), 0x040f1: (150, "AccessCheckInfoMap"),
0x04141: (153, "AliasedArgumentsEntryMap"), 0x04141: (152, "AccessorPairMap"),
0x04191: (154, "AllocationMementoMap"), 0x04191: (153, "AliasedArgumentsEntryMap"),
0x041e1: (155, "AllocationSiteMap"), 0x041e1: (154, "AllocationMementoMap"),
0x04231: (156, "AsyncGeneratorRequestMap"), 0x04231: (155, "AllocationSiteMap"),
0x04281: (157, "ContextExtensionMap"), 0x04281: (156, "AsyncGeneratorRequestMap"),
0x042d1: (158, "DebugInfoMap"), 0x042d1: (157, "ContextExtensionMap"),
0x04321: (159, "FunctionTemplateInfoMap"), 0x04321: (158, "DebugInfoMap"),
0x04371: (161, "ModuleInfoEntryMap"), 0x04371: (159, "FunctionTemplateInfoMap"),
0x043c1: (162, "ModuleMap"), 0x043c1: (161, "ModuleInfoEntryMap"),
0x04411: (163, "ObjectTemplateInfoMap"), 0x04411: (162, "ModuleMap"),
0x04461: (164, "PromiseReactionJobInfoMap"), 0x04461: (163, "ObjectTemplateInfoMap"),
0x044b1: (165, "PromiseResolveThenableJobInfoMap"), 0x044b1: (164, "PromiseReactionJobInfoMap"),
0x04501: (166, "PrototypeInfoMap"), 0x04501: (165, "PromiseResolveThenableJobInfoMap"),
0x04551: (168, "StackFrameInfoMap"), 0x04551: (166, "PrototypeInfoMap"),
0x045a1: (170, "Tuple3Map"), 0x045a1: (168, "StackFrameInfoMap"),
0x045f1: (170, "Tuple3Map"),
} }
# List of known V8 objects. # List of known V8 objects.