[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:
parent
3f8d6f6074
commit
11e80a3509
109
include/v8.h
109
include/v8.h
@ -313,6 +313,7 @@ class Local {
|
||||
friend class String;
|
||||
friend class Object;
|
||||
friend class Context;
|
||||
friend class Isolate;
|
||||
friend class Private;
|
||||
template<class F> friend class internal::CustomArguments;
|
||||
friend Local<Primitive> Undefined(Isolate* isolate);
|
||||
@ -5522,8 +5523,12 @@ class V8_EXPORT FunctionTemplate : public Template {
|
||||
*/
|
||||
bool HasInstance(Local<Value> object);
|
||||
|
||||
V8_INLINE static FunctionTemplate* Cast(Data* data);
|
||||
|
||||
private:
|
||||
FunctionTemplate();
|
||||
|
||||
static void CheckCast(Data* that);
|
||||
friend class Context;
|
||||
friend class ObjectTemplate;
|
||||
};
|
||||
@ -5870,10 +5875,13 @@ class V8_EXPORT ObjectTemplate : public Template {
|
||||
*/
|
||||
void SetImmutableProto();
|
||||
|
||||
V8_INLINE static ObjectTemplate* Cast(Data* data);
|
||||
|
||||
private:
|
||||
ObjectTemplate();
|
||||
static Local<ObjectTemplate> New(internal::Isolate* isolate,
|
||||
Local<FunctionTemplate> constructor);
|
||||
static void CheckCast(Data* that);
|
||||
friend class FunctionTemplate;
|
||||
};
|
||||
|
||||
@ -7083,6 +7091,14 @@ class V8_EXPORT Isolate {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@ -7725,6 +7741,7 @@ class V8_EXPORT Isolate {
|
||||
template <class K, class V, class Traits>
|
||||
friend class PersistentValueMapBase;
|
||||
|
||||
internal::Object** GetDataFromSnapshotOnce(size_t index);
|
||||
void ReportExternalAllocationLimitReached();
|
||||
void CheckMemoryPressure();
|
||||
};
|
||||
@ -8021,6 +8038,24 @@ class V8_EXPORT SnapshotCreator {
|
||||
*/
|
||||
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.
|
||||
* This must not be called from within a handle scope.
|
||||
@ -8036,6 +8071,9 @@ class V8_EXPORT SnapshotCreator {
|
||||
void operator=(const SnapshotCreator&) = delete;
|
||||
|
||||
private:
|
||||
size_t AddData(Local<Context> context, internal::Object* object);
|
||||
size_t AddData(internal::Object* object);
|
||||
|
||||
void* data_;
|
||||
};
|
||||
|
||||
@ -8523,6 +8561,14 @@ class V8_EXPORT Context {
|
||||
*/
|
||||
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
|
||||
* operations executed within a local scope.
|
||||
@ -8565,6 +8611,7 @@ class V8_EXPORT Context {
|
||||
friend class Object;
|
||||
friend class Function;
|
||||
|
||||
internal::Object** GetDataFromSnapshotOnce(size_t index);
|
||||
Local<Value> SlowGetEmbedderData(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
|
||||
|
||||
|
||||
@ -9405,6 +9475,19 @@ void Template::Set(Isolate* isolate, const char* name, Local<Data> 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) {
|
||||
#ifndef V8_ENABLE_CHECKS
|
||||
@ -9983,6 +10066,12 @@ uint32_t Isolate::GetNumberOfDataSlots() {
|
||||
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 change_in_bytes) {
|
||||
@ -10042,6 +10131,26 @@ void* Context::GetAlignedPointerFromEmbedderData(int index) {
|
||||
#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
|
||||
|
175
src/api.cc
175
src/api.cc
@ -573,7 +573,6 @@ struct SnapshotCreatorData {
|
||||
: isolate_(isolate),
|
||||
default_context_(),
|
||||
contexts_(isolate),
|
||||
templates_(isolate),
|
||||
created_(false) {}
|
||||
|
||||
static SnapshotCreatorData* cast(void* data) {
|
||||
@ -585,7 +584,6 @@ struct SnapshotCreatorData {
|
||||
Persistent<Context> default_context_;
|
||||
SerializeInternalFieldsCallback default_embedder_fields_serializer_;
|
||||
PersistentValueVector<Context> contexts_;
|
||||
PersistentValueVector<Template> templates_;
|
||||
std::vector<SerializeInternalFieldsCallback> embedder_fields_serializers_;
|
||||
bool created_;
|
||||
};
|
||||
@ -645,23 +643,81 @@ size_t SnapshotCreator::AddContext(Local<Context> context,
|
||||
DCHECK(!data->created_);
|
||||
Isolate* isolate = data->isolate_;
|
||||
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->embedder_fields_serializers_.push_back(callback);
|
||||
return index;
|
||||
}
|
||||
|
||||
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_);
|
||||
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);
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(data->isolate_);
|
||||
i::HandleScope scope(isolate);
|
||||
i::Handle<i::Object> obj(object, isolate);
|
||||
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;
|
||||
}
|
||||
|
||||
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(
|
||||
SnapshotCreator::FunctionCodeHandling function_code_handling) {
|
||||
SnapshotCreatorData* data = SnapshotCreatorData::cast(data_);
|
||||
@ -672,15 +728,16 @@ StartupData SnapshotCreator::CreateBlob(
|
||||
int num_additional_contexts = static_cast<int>(data->contexts_.Size());
|
||||
|
||||
{
|
||||
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)));
|
||||
// Convert list of context-independent data to FixedArray.
|
||||
ConvertSerializedObjectsToFixedArray(isolate);
|
||||
|
||||
// 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
|
||||
// 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;
|
||||
|
||||
std::vector<i::Object*> contexts;
|
||||
contexts.reserve(num_additional_contexts);
|
||||
i::Object* default_context;
|
||||
int num_contexts = num_additional_contexts + 1;
|
||||
std::vector<i::Context*> contexts;
|
||||
contexts.reserve(num_contexts);
|
||||
{
|
||||
i::HandleScope scope(isolate);
|
||||
default_context =
|
||||
*v8::Utils::OpenHandle(*data->default_context_.Get(data->isolate_));
|
||||
contexts.push_back(
|
||||
*v8::Utils::OpenHandle(*data->default_context_.Get(data->isolate_)));
|
||||
data->default_context_.Reset();
|
||||
for (int i = 0; i < num_additional_contexts; i++) {
|
||||
i::Handle<i::Context> context =
|
||||
@ -722,6 +779,10 @@ StartupData SnapshotCreator::CreateBlob(
|
||||
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.
|
||||
i::HeapIterator heap_iterator(isolate->heap());
|
||||
while (i::HeapObject* current_obj = heap_iterator.next()) {
|
||||
@ -735,26 +796,18 @@ StartupData SnapshotCreator::CreateBlob(
|
||||
|
||||
// Serialize each context with a new partial serializer.
|
||||
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.
|
||||
bool can_be_rehashed = true;
|
||||
|
||||
{
|
||||
// The default context is created with a handler for embedder fields which
|
||||
// determines how they are handled if encountered during serialization.
|
||||
for (int i = 0; i < num_contexts; i++) {
|
||||
bool is_default_context = i == 0;
|
||||
i::PartialSerializer partial_serializer(
|
||||
isolate, &startup_serializer,
|
||||
data->default_embedder_fields_serializer_);
|
||||
partial_serializer.Serialize(&default_context, false);
|
||||
can_be_rehashed = can_be_rehashed && partial_serializer.can_be_rehashed();
|
||||
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);
|
||||
is_default_context ? data->default_embedder_fields_serializer_
|
||||
: data->embedder_fields_serializers_[i - 1]);
|
||||
partial_serializer.Serialize(&contexts[i], !is_default_context);
|
||||
can_be_rehashed = can_be_rehashed && partial_serializer.can_be_rehashed();
|
||||
context_snapshots.push_back(new i::SnapshotData(&partial_serializer));
|
||||
}
|
||||
@ -778,6 +831,7 @@ StartupData SnapshotCreator::CreateBlob(
|
||||
delete context_snapshot;
|
||||
}
|
||||
data->created_ = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1419,10 +1473,10 @@ Local<FunctionTemplate> FunctionTemplate::New(
|
||||
MaybeLocal<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();
|
||||
i::FixedArray* serialized_objects = i_isolate->heap()->serialized_objects();
|
||||
int int_index = static_cast<int>(index);
|
||||
if (int_index < templates->length()) {
|
||||
i::Object* info = templates->get(int_index);
|
||||
if (int_index < serialized_objects->length()) {
|
||||
i::Object* info = serialized_objects->get(int_index);
|
||||
if (info->IsFunctionTemplateInfo()) {
|
||||
return Utils::ToLocal(i::Handle<i::FunctionTemplateInfo>(
|
||||
i::FunctionTemplateInfo::cast(info)));
|
||||
@ -1632,10 +1686,10 @@ Local<ObjectTemplate> ObjectTemplate::New(
|
||||
MaybeLocal<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();
|
||||
i::FixedArray* serialized_objects = i_isolate->heap()->serialized_objects();
|
||||
int int_index = static_cast<int>(index);
|
||||
if (int_index < templates->length()) {
|
||||
i::Object* info = templates->get(int_index);
|
||||
if (int_index < serialized_objects->length()) {
|
||||
i::Object* info = serialized_objects->get(int_index);
|
||||
if (info->IsObjectTemplateInfo()) {
|
||||
return Utils::ToLocal(
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
PREPARE_FOR_EXECUTION(context, ObjectTemplate, NewInstance, Object);
|
||||
@ -6465,6 +6544,17 @@ Local<v8::Object> ObjectTemplate::NewInstance() {
|
||||
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) {
|
||||
PREPARE_FOR_EXECUTION(context, FunctionTemplate, GetFunction, Function);
|
||||
@ -8414,6 +8504,11 @@ Isolate::SuppressMicrotaskExecutionScope::~SuppressMicrotaskExecutionScope() {
|
||||
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) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
|
@ -345,6 +345,7 @@ enum ContextLookupFlags {
|
||||
V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \
|
||||
V(SECURITY_TOKEN_INDEX, Object, security_token) \
|
||||
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_KEY_VALUE_ITERATOR_MAP_INDEX, Map, set_key_value_iterator_map) \
|
||||
V(SHARED_ARRAY_BUFFER_FUN_INDEX, JSFunction, shared_array_buffer_fun) \
|
||||
|
@ -995,6 +995,7 @@ Handle<Context> Factory::NewNativeContext() {
|
||||
context->set_math_random_index(Smi::kZero);
|
||||
Handle<WeakCell> weak_cell = NewWeakCell(context);
|
||||
context->set_self_weak_cell(*weak_cell);
|
||||
context->set_serialized_objects(*empty_fixed_array());
|
||||
DCHECK(context->IsNativeContext());
|
||||
return context;
|
||||
}
|
||||
|
@ -94,14 +94,12 @@ void Heap::SetInterpreterEntryReturnPCOffset(int pc_offset) {
|
||||
set_interpreter_entry_return_pc_offset(Smi::FromInt(pc_offset));
|
||||
}
|
||||
|
||||
void Heap::SetSerializedTemplates(FixedArray* templates) {
|
||||
DCHECK_EQ(empty_fixed_array(), serialized_templates());
|
||||
void Heap::SetSerializedObjects(FixedArray* objects) {
|
||||
DCHECK(isolate()->serializer_enabled());
|
||||
set_serialized_templates(templates);
|
||||
set_serialized_objects(objects);
|
||||
}
|
||||
|
||||
void Heap::SetSerializedGlobalProxySizes(FixedArray* sizes) {
|
||||
DCHECK_EQ(empty_fixed_array(), serialized_global_proxy_sizes());
|
||||
DCHECK(isolate()->serializer_enabled());
|
||||
set_serialized_global_proxy_sizes(sizes);
|
||||
}
|
||||
@ -2658,7 +2656,7 @@ bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
|
||||
case kFeedbackVectorsForProfilingToolsRootIndex:
|
||||
case kNoScriptSharedFunctionInfosRootIndex:
|
||||
case kWeakStackTraceListRootIndex:
|
||||
case kSerializedTemplatesRootIndex:
|
||||
case kSerializedObjectsRootIndex:
|
||||
case kSerializedGlobalProxySizesRootIndex:
|
||||
case kPublicSymbolTableRootIndex:
|
||||
case kApiSymbolTableRootIndex:
|
||||
@ -4984,6 +4982,9 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
|
||||
// Iterate over global handles.
|
||||
switch (mode) {
|
||||
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:
|
||||
isolate_->global_handles()->IterateStrongRoots(v);
|
||||
break;
|
||||
@ -5003,11 +5004,14 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
|
||||
}
|
||||
v->Synchronize(VisitorSynchronization::kGlobalHandles);
|
||||
|
||||
// Iterate over eternal handles.
|
||||
if (isMinorGC) {
|
||||
isolate_->eternal_handles()->IterateNewSpaceRoots(v);
|
||||
} else {
|
||||
isolate_->eternal_handles()->IterateAllRoots(v);
|
||||
// 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) {
|
||||
isolate_->eternal_handles()->IterateNewSpaceRoots(v);
|
||||
} else {
|
||||
isolate_->eternal_handles()->IterateAllRoots(v);
|
||||
}
|
||||
}
|
||||
v->Synchronize(VisitorSynchronization::kEternalHandles);
|
||||
|
||||
@ -5024,11 +5028,9 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
|
||||
// Iterate over the partial snapshot cache unless serializing.
|
||||
if (mode != VISIT_FOR_SERIALIZATION) {
|
||||
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.
|
||||
}
|
||||
|
||||
|
||||
|
@ -106,6 +106,7 @@ using v8::MemoryPressureLevel;
|
||||
V(Map, script_context_table_map, ScriptContextTableMap) \
|
||||
/* Maps */ \
|
||||
V(Map, descriptor_array_map, DescriptorArrayMap) \
|
||||
V(Map, array_list_map, ArrayListMap) \
|
||||
V(Map, fixed_double_array_map, FixedDoubleArrayMap) \
|
||||
V(Map, mutable_heap_number_map, MutableHeapNumberMap) \
|
||||
V(Map, ordered_hash_map_map, OrderedHashMapMap) \
|
||||
@ -246,7 +247,7 @@ using v8::MemoryPressureLevel;
|
||||
FeedbackVectorsForProfilingTools) \
|
||||
V(Object, weak_stack_trace_list, WeakStackTraceList) \
|
||||
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(TemplateList, message_listeners, MessageListeners) \
|
||||
/* DeserializeLazy handlers for lazy bytecode deserialization */ \
|
||||
@ -851,7 +852,7 @@ class Heap {
|
||||
inline int NextScriptId();
|
||||
inline int GetNextTemplateSerialNumber();
|
||||
|
||||
void SetSerializedTemplates(FixedArray* templates);
|
||||
void SetSerializedObjects(FixedArray* objects);
|
||||
void SetSerializedGlobalProxySizes(FixedArray* sizes);
|
||||
|
||||
// For post mortem debugging.
|
||||
|
@ -326,8 +326,8 @@ void ObjectStatsCollector::CollectGlobalStatistics() {
|
||||
// Global FixedArrays.
|
||||
RecordFixedArrayHelper(nullptr, heap_->weak_new_space_object_to_code_list(),
|
||||
WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE, 0);
|
||||
RecordFixedArrayHelper(nullptr, heap_->serialized_templates(),
|
||||
SERIALIZED_TEMPLATES_SUB_TYPE, 0);
|
||||
RecordFixedArrayHelper(nullptr, heap_->serialized_objects(),
|
||||
SERIALIZED_OBJECTS_SUB_TYPE, 0);
|
||||
RecordFixedArrayHelper(nullptr, heap_->number_string_cache(),
|
||||
NUMBER_STRING_CACHE_SUB_TYPE, 0);
|
||||
RecordFixedArrayHelper(nullptr, heap_->single_character_string_cache(),
|
||||
|
@ -306,6 +306,8 @@ bool Heap::CreateInitialMaps() {
|
||||
ALLOCATE_VARSIZE_MAP(HASH_TABLE_TYPE, string_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, catch_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_new_space_object_to_code_list(
|
||||
ArrayList::cast(*(factory->NewFixedArray(16, TENURED))));
|
||||
weak_new_space_object_to_code_list()->SetLength(0);
|
||||
set_weak_new_space_object_to_code_list(*ArrayList::New(isolate(), 16));
|
||||
|
||||
set_feedback_vectors_for_profiling_tools(undefined_value());
|
||||
|
||||
@ -638,7 +638,7 @@ void Heap::CreateInitialObjects() {
|
||||
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
|
||||
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_weak_stack_trace_list(Smi::kZero);
|
||||
|
@ -328,7 +328,10 @@ bool HeapObject::IsEnumCache() const { return IsTuple2(); }
|
||||
|
||||
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(); }
|
||||
|
||||
|
@ -10237,8 +10237,10 @@ Handle<ArrayList> ArrayList::Add(Handle<ArrayList> array, Handle<Object> obj1,
|
||||
|
||||
// static
|
||||
Handle<ArrayList> ArrayList::New(Isolate* isolate, int size) {
|
||||
Handle<ArrayList> result = Handle<ArrayList>::cast(
|
||||
isolate->factory()->NewFixedArray(size + kFirstIndex));
|
||||
Handle<FixedArray> fixed_array =
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
@ -10277,10 +10279,13 @@ Handle<FixedArray> EnsureSpaceInFixedArray(Handle<FixedArray> array,
|
||||
// static
|
||||
Handle<ArrayList> ArrayList::EnsureSpace(Handle<ArrayList> array, int length) {
|
||||
const bool empty = (array->length() == 0);
|
||||
auto ret = Handle<ArrayList>::cast(
|
||||
EnsureSpaceInFixedArray(array, kFirstIndex + length));
|
||||
if (empty) ret->SetLength(0);
|
||||
return ret;
|
||||
auto ret = EnsureSpaceInFixedArray(array, kFirstIndex + length);
|
||||
if (empty) {
|
||||
ret->set_map_no_write_barrier(array->GetHeap()->array_list_map());
|
||||
|
||||
Handle<ArrayList>::cast(ret)->SetLength(0);
|
||||
}
|
||||
return Handle<ArrayList>::cast(ret);
|
||||
}
|
||||
|
||||
Handle<RegExpMatchInfo> RegExpMatchInfo::ReserveCaptures(
|
||||
|
@ -45,7 +45,7 @@ namespace internal {
|
||||
V(RETAINED_MAPS_SUB_TYPE) \
|
||||
V(SCOPE_INFO_SUB_TYPE) \
|
||||
V(SCRIPT_LIST_SUB_TYPE) \
|
||||
V(SERIALIZED_TEMPLATES_SUB_TYPE) \
|
||||
V(SERIALIZED_OBJECTS_SUB_TYPE) \
|
||||
V(SHARED_FUNCTION_INFOS_SUB_TYPE) \
|
||||
V(SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE) \
|
||||
V(SLOW_TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE) \
|
||||
|
@ -17,7 +17,8 @@ PartialSerializer::PartialSerializer(
|
||||
: Serializer(isolate),
|
||||
startup_serializer_(startup_serializer),
|
||||
serialize_embedder_fields_(callback),
|
||||
can_be_rehashed_(true) {
|
||||
can_be_rehashed_(true),
|
||||
context_(nullptr) {
|
||||
InitializeCodeAddressMap();
|
||||
}
|
||||
|
||||
@ -25,24 +26,23 @@ PartialSerializer::~PartialSerializer() {
|
||||
OutputStatistics("PartialSerializer");
|
||||
}
|
||||
|
||||
void PartialSerializer::Serialize(Object** o, bool include_global_proxy) {
|
||||
DCHECK((*o)->IsNativeContext());
|
||||
|
||||
Context* context = Context::cast(*o);
|
||||
reference_map()->AddAttachedReference(context->global_proxy());
|
||||
void PartialSerializer::Serialize(Context** o, bool include_global_proxy) {
|
||||
context_ = *o;
|
||||
DCHECK(context_->IsNativeContext());
|
||||
reference_map()->AddAttachedReference(context_->global_proxy());
|
||||
// The bootstrap snapshot has a code-stub context. When serializing the
|
||||
// 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
|
||||
// it before serializing, it will get re-added to the context list
|
||||
// explicitly when it's loaded.
|
||||
context->set(Context::NEXT_CONTEXT_LINK,
|
||||
isolate()->heap()->undefined_value());
|
||||
DCHECK(!context->global_object()->IsUndefined(context->GetIsolate()));
|
||||
context_->set(Context::NEXT_CONTEXT_LINK,
|
||||
isolate()->heap()->undefined_value());
|
||||
DCHECK(!context_->global_object()->IsUndefined(context_->GetIsolate()));
|
||||
// Reset math random cache to get fresh random numbers.
|
||||
context->set_math_random_index(Smi::kZero);
|
||||
context->set_math_random_cache(isolate()->heap()->undefined_value());
|
||||
context_->set_math_random_index(Smi::kZero);
|
||||
context_->set_math_random_cache(isolate()->heap()->undefined_value());
|
||||
|
||||
VisitRootPointer(Root::kPartialSnapshotCache, o);
|
||||
VisitRootPointer(Root::kPartialSnapshotCache, reinterpret_cast<Object**>(o));
|
||||
SerializeDeferredObjects();
|
||||
SerializeEmbedderFields();
|
||||
Pad();
|
||||
@ -87,6 +87,8 @@ void PartialSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
|
||||
DCHECK(!obj->IsInternalizedString());
|
||||
// Function and object templates are not context specific.
|
||||
DCHECK(!obj->IsTemplateInfo());
|
||||
// We should not end up at another native context.
|
||||
DCHECK_IMPLIES(obj != context_, !obj->IsNativeContext());
|
||||
|
||||
FlushSkip(skip);
|
||||
|
||||
|
@ -21,7 +21,7 @@ class PartialSerializer : public Serializer<> {
|
||||
~PartialSerializer() override;
|
||||
|
||||
// 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_; }
|
||||
|
||||
@ -41,6 +41,7 @@ class PartialSerializer : public Serializer<> {
|
||||
// Indicates whether we only serialized hash tables that we can rehash.
|
||||
// TODO(yangguo): generalize rehashing, and remove this flag.
|
||||
bool can_be_rehashed_;
|
||||
Context* context_;
|
||||
DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
|
||||
};
|
||||
|
||||
|
@ -122,8 +122,7 @@ void StartupSerializer::SerializeStrongReferences() {
|
||||
CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
|
||||
// No active or weak handles.
|
||||
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.
|
||||
// Clear the stack limits to make the snapshot reproducible.
|
||||
// Reset it again afterwards.
|
||||
@ -184,5 +183,36 @@ bool StartupSerializer::MustBeDeferred(HeapObject* object) {
|
||||
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 v8
|
||||
|
@ -83,6 +83,20 @@ class StartupSerializer : public Serializer<> {
|
||||
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 v8
|
||||
|
||||
|
@ -112,6 +112,7 @@
|
||||
|
||||
# Test that serialization with unknown external reference fails.
|
||||
'test-serialize/SnapshotCreatorUnknownExternalReferences': [FAIL],
|
||||
'test-serialize/SnapshotCreatorUnknownHandles': [FAIL],
|
||||
'test-serialize/SnapshotCreatorNoExternalReferencesCustomFail1': [FAIL],
|
||||
'test-serialize/SnapshotCreatorNoExternalReferencesCustomFail2': [FAIL],
|
||||
|
||||
|
@ -371,7 +371,7 @@ static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
|
||||
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();
|
||||
|
||||
@ -496,7 +496,7 @@ static void PartiallySerializeCustomContext(
|
||||
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();
|
||||
|
||||
@ -2776,6 +2776,206 @@ TEST(SnapshotCreatorTemplates) {
|
||||
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) {
|
||||
DisableAlwaysOpt();
|
||||
v8::StartupData blob;
|
||||
|
@ -206,79 +206,80 @@ KNOWN_MAPS = {
|
||||
0x02e31: (171, "WithContextMap"),
|
||||
0x02e81: (171, "DebugEvaluateContextMap"),
|
||||
0x02ed1: (171, "ScriptContextTableMap"),
|
||||
0x02f21: (148, "FixedDoubleArrayMap"),
|
||||
0x02f71: (134, "MutableHeapNumberMap"),
|
||||
0x02fc1: (173, "OrderedHashMapMap"),
|
||||
0x03011: (173, "OrderedHashSetMap"),
|
||||
0x03061: (173, "NameDictionaryMap"),
|
||||
0x030b1: (173, "GlobalDictionaryMap"),
|
||||
0x03101: (173, "NumberDictionaryMap"),
|
||||
0x03151: (173, "StringTableMap"),
|
||||
0x031a1: (173, "WeakHashTableMap"),
|
||||
0x031f1: (171, "SloppyArgumentsElementsMap"),
|
||||
0x03241: (182, "SmallOrderedHashMapMap"),
|
||||
0x03291: (183, "SmallOrderedHashSetMap"),
|
||||
0x032e1: (176, "CodeDataContainerMap"),
|
||||
0x03331: (1071, "JSMessageObjectMap"),
|
||||
0x03381: (1057, "ExternalMap"),
|
||||
0x033d1: (137, "BytecodeArrayMap"),
|
||||
0x03421: (171, "ModuleInfoMap"),
|
||||
0x03471: (175, "NoClosuresCellMap"),
|
||||
0x034c1: (175, "OneClosureCellMap"),
|
||||
0x03511: (175, "ManyClosuresCellMap"),
|
||||
0x03561: (179, "PropertyArrayMap"),
|
||||
0x035b1: (130, "BigIntMap"),
|
||||
0x03601: (106, "NativeSourceStringMap"),
|
||||
0x03651: (64, "StringMap"),
|
||||
0x036a1: (73, "ConsOneByteStringMap"),
|
||||
0x036f1: (65, "ConsStringMap"),
|
||||
0x03741: (77, "ThinOneByteStringMap"),
|
||||
0x03791: (69, "ThinStringMap"),
|
||||
0x037e1: (67, "SlicedStringMap"),
|
||||
0x03831: (75, "SlicedOneByteStringMap"),
|
||||
0x03881: (66, "ExternalStringMap"),
|
||||
0x038d1: (82, "ExternalStringWithOneByteDataMap"),
|
||||
0x03921: (74, "ExternalOneByteStringMap"),
|
||||
0x03971: (98, "ShortExternalStringMap"),
|
||||
0x039c1: (114, "ShortExternalStringWithOneByteDataMap"),
|
||||
0x03a11: (0, "InternalizedStringMap"),
|
||||
0x03a61: (2, "ExternalInternalizedStringMap"),
|
||||
0x03ab1: (18, "ExternalInternalizedStringWithOneByteDataMap"),
|
||||
0x03b01: (10, "ExternalOneByteInternalizedStringMap"),
|
||||
0x03b51: (34, "ShortExternalInternalizedStringMap"),
|
||||
0x03ba1: (50, "ShortExternalInternalizedStringWithOneByteDataMap"),
|
||||
0x03bf1: (42, "ShortExternalOneByteInternalizedStringMap"),
|
||||
0x03c41: (106, "ShortExternalOneByteStringMap"),
|
||||
0x03c91: (140, "FixedUint8ArrayMap"),
|
||||
0x03ce1: (139, "FixedInt8ArrayMap"),
|
||||
0x03d31: (142, "FixedUint16ArrayMap"),
|
||||
0x03d81: (141, "FixedInt16ArrayMap"),
|
||||
0x03dd1: (144, "FixedUint32ArrayMap"),
|
||||
0x03e21: (143, "FixedInt32ArrayMap"),
|
||||
0x03e71: (145, "FixedFloat32ArrayMap"),
|
||||
0x03ec1: (146, "FixedFloat64ArrayMap"),
|
||||
0x03f11: (147, "FixedUint8ClampedArrayMap"),
|
||||
0x03f61: (169, "Tuple2Map"),
|
||||
0x03fb1: (167, "ScriptMap"),
|
||||
0x04001: (160, "InterceptorInfoMap"),
|
||||
0x04051: (151, "AccessorInfoMap"),
|
||||
0x040a1: (150, "AccessCheckInfoMap"),
|
||||
0x040f1: (152, "AccessorPairMap"),
|
||||
0x04141: (153, "AliasedArgumentsEntryMap"),
|
||||
0x04191: (154, "AllocationMementoMap"),
|
||||
0x041e1: (155, "AllocationSiteMap"),
|
||||
0x04231: (156, "AsyncGeneratorRequestMap"),
|
||||
0x04281: (157, "ContextExtensionMap"),
|
||||
0x042d1: (158, "DebugInfoMap"),
|
||||
0x04321: (159, "FunctionTemplateInfoMap"),
|
||||
0x04371: (161, "ModuleInfoEntryMap"),
|
||||
0x043c1: (162, "ModuleMap"),
|
||||
0x04411: (163, "ObjectTemplateInfoMap"),
|
||||
0x04461: (164, "PromiseReactionJobInfoMap"),
|
||||
0x044b1: (165, "PromiseResolveThenableJobInfoMap"),
|
||||
0x04501: (166, "PrototypeInfoMap"),
|
||||
0x04551: (168, "StackFrameInfoMap"),
|
||||
0x045a1: (170, "Tuple3Map"),
|
||||
0x02f21: (171, "ArrayListMap"),
|
||||
0x02f71: (148, "FixedDoubleArrayMap"),
|
||||
0x02fc1: (134, "MutableHeapNumberMap"),
|
||||
0x03011: (173, "OrderedHashMapMap"),
|
||||
0x03061: (173, "OrderedHashSetMap"),
|
||||
0x030b1: (173, "NameDictionaryMap"),
|
||||
0x03101: (173, "GlobalDictionaryMap"),
|
||||
0x03151: (173, "NumberDictionaryMap"),
|
||||
0x031a1: (173, "StringTableMap"),
|
||||
0x031f1: (173, "WeakHashTableMap"),
|
||||
0x03241: (171, "SloppyArgumentsElementsMap"),
|
||||
0x03291: (182, "SmallOrderedHashMapMap"),
|
||||
0x032e1: (183, "SmallOrderedHashSetMap"),
|
||||
0x03331: (176, "CodeDataContainerMap"),
|
||||
0x03381: (1071, "JSMessageObjectMap"),
|
||||
0x033d1: (1057, "ExternalMap"),
|
||||
0x03421: (137, "BytecodeArrayMap"),
|
||||
0x03471: (171, "ModuleInfoMap"),
|
||||
0x034c1: (175, "NoClosuresCellMap"),
|
||||
0x03511: (175, "OneClosureCellMap"),
|
||||
0x03561: (175, "ManyClosuresCellMap"),
|
||||
0x035b1: (179, "PropertyArrayMap"),
|
||||
0x03601: (130, "BigIntMap"),
|
||||
0x03651: (106, "NativeSourceStringMap"),
|
||||
0x036a1: (64, "StringMap"),
|
||||
0x036f1: (73, "ConsOneByteStringMap"),
|
||||
0x03741: (65, "ConsStringMap"),
|
||||
0x03791: (77, "ThinOneByteStringMap"),
|
||||
0x037e1: (69, "ThinStringMap"),
|
||||
0x03831: (67, "SlicedStringMap"),
|
||||
0x03881: (75, "SlicedOneByteStringMap"),
|
||||
0x038d1: (66, "ExternalStringMap"),
|
||||
0x03921: (82, "ExternalStringWithOneByteDataMap"),
|
||||
0x03971: (74, "ExternalOneByteStringMap"),
|
||||
0x039c1: (98, "ShortExternalStringMap"),
|
||||
0x03a11: (114, "ShortExternalStringWithOneByteDataMap"),
|
||||
0x03a61: (0, "InternalizedStringMap"),
|
||||
0x03ab1: (2, "ExternalInternalizedStringMap"),
|
||||
0x03b01: (18, "ExternalInternalizedStringWithOneByteDataMap"),
|
||||
0x03b51: (10, "ExternalOneByteInternalizedStringMap"),
|
||||
0x03ba1: (34, "ShortExternalInternalizedStringMap"),
|
||||
0x03bf1: (50, "ShortExternalInternalizedStringWithOneByteDataMap"),
|
||||
0x03c41: (42, "ShortExternalOneByteInternalizedStringMap"),
|
||||
0x03c91: (106, "ShortExternalOneByteStringMap"),
|
||||
0x03ce1: (140, "FixedUint8ArrayMap"),
|
||||
0x03d31: (139, "FixedInt8ArrayMap"),
|
||||
0x03d81: (142, "FixedUint16ArrayMap"),
|
||||
0x03dd1: (141, "FixedInt16ArrayMap"),
|
||||
0x03e21: (144, "FixedUint32ArrayMap"),
|
||||
0x03e71: (143, "FixedInt32ArrayMap"),
|
||||
0x03ec1: (145, "FixedFloat32ArrayMap"),
|
||||
0x03f11: (146, "FixedFloat64ArrayMap"),
|
||||
0x03f61: (147, "FixedUint8ClampedArrayMap"),
|
||||
0x03fb1: (169, "Tuple2Map"),
|
||||
0x04001: (167, "ScriptMap"),
|
||||
0x04051: (160, "InterceptorInfoMap"),
|
||||
0x040a1: (151, "AccessorInfoMap"),
|
||||
0x040f1: (150, "AccessCheckInfoMap"),
|
||||
0x04141: (152, "AccessorPairMap"),
|
||||
0x04191: (153, "AliasedArgumentsEntryMap"),
|
||||
0x041e1: (154, "AllocationMementoMap"),
|
||||
0x04231: (155, "AllocationSiteMap"),
|
||||
0x04281: (156, "AsyncGeneratorRequestMap"),
|
||||
0x042d1: (157, "ContextExtensionMap"),
|
||||
0x04321: (158, "DebugInfoMap"),
|
||||
0x04371: (159, "FunctionTemplateInfoMap"),
|
||||
0x043c1: (161, "ModuleInfoEntryMap"),
|
||||
0x04411: (162, "ModuleMap"),
|
||||
0x04461: (163, "ObjectTemplateInfoMap"),
|
||||
0x044b1: (164, "PromiseReactionJobInfoMap"),
|
||||
0x04501: (165, "PromiseResolveThenableJobInfoMap"),
|
||||
0x04551: (166, "PrototypeInfoMap"),
|
||||
0x045a1: (168, "StackFrameInfoMap"),
|
||||
0x045f1: (170, "Tuple3Map"),
|
||||
}
|
||||
|
||||
# List of known V8 objects.
|
||||
|
Loading…
Reference in New Issue
Block a user