Commit 947138fe authored by Marja Hölttä's avatar Marja Hölttä Committed by V8 LUCI CQ

[web snapshots] Rewrite object discovery in the d8 snapshotter

In order to construct the optimal source code combination for functions
(and especially the positions inside the optimal source code for each
function), we need to know all functions upfront.

Rewrite the d8-based snapshotter so that it discovers all objects first
(+ assigns ids), then does the actual snapshotting.

Bug: v8:11525
Change-Id: I4f4e5589575ee9738e8a83aa6cda2c8164803b4c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3268915Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77794}
parent 7d591d2b
...@@ -219,6 +219,8 @@ bool WebSnapshotSerializer::TakeSnapshot(v8::Local<v8::Context> context, ...@@ -219,6 +219,8 @@ bool WebSnapshotSerializer::TakeSnapshot(v8::Local<v8::Context> context,
return false; return false;
} }
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
std::unique_ptr<Handle<JSObject>[]> export_objects(
new Handle<JSObject>[exports->Length()]);
for (int i = 0, length = exports->Length(); i < length; ++i) { for (int i = 0, length = exports->Length(); i < length; ++i) {
v8::Local<v8::String> str = v8::Local<v8::String> str =
exports->Get(v8_isolate, i)->ToString(context).ToLocalChecked(); exports->Get(v8_isolate, i)->ToString(context).ToLocalChecked();
...@@ -236,27 +238,48 @@ bool WebSnapshotSerializer::TakeSnapshot(v8::Local<v8::Context> context, ...@@ -236,27 +238,48 @@ bool WebSnapshotSerializer::TakeSnapshot(v8::Local<v8::Context> context,
return false; return false;
} }
auto object = Handle<JSObject>::cast(Utils::OpenHandle(*v8_object)); export_objects[i] = Handle<JSObject>::cast(Utils::OpenHandle(*v8_object));
SerializeExport(object, Handle<String>::cast(Utils::OpenHandle(*str))); Discovery(export_objects[i]);
} }
for (int i = 0, length = exports->Length(); i < length; ++i) {
v8::Local<v8::String> str =
exports->Get(v8_isolate, i)->ToString(context).ToLocalChecked();
SerializeExport(export_objects[i],
Handle<String>::cast(Utils::OpenHandle(*str)));
}
WriteSnapshot(data_out.buffer, data_out.buffer_size); WriteSnapshot(data_out.buffer, data_out.buffer_size);
return !has_error(); return !has_error();
} }
void WebSnapshotSerializer::SerializePendingItems() { void WebSnapshotSerializer::SerializePendingItems() {
while (!pending_objects_.empty() || !pending_arrays_.empty()) { for (int i = 0; i < contexts_->Length(); ++i) {
while (!pending_objects_.empty()) { Handle<Context> context =
const Handle<JSObject>& object = pending_objects_.front(); handle(Context::cast(contexts_->Get(i)), isolate_);
SerializePendingObject(object); SerializeContext(context);
pending_objects_.pop();
} }
for (int i = 0; i < functions_->Length(); ++i) {
while (!pending_arrays_.empty()) { Handle<JSFunction> function =
const Handle<JSArray>& array = pending_arrays_.front(); handle(JSFunction::cast(functions_->Get(i)), isolate_);
SerializePendingArray(array); SerializeFunction(function);
pending_arrays_.pop(); }
for (int i = 0; i < classes_->Length(); ++i) {
Handle<JSFunction> function =
handle(JSFunction::cast(classes_->Get(i)), isolate_);
SerializeClass(function);
}
for (int i = 0; i < arrays_->Length(); ++i) {
Handle<JSArray> array = handle(JSArray::cast(arrays_->Get(i)), isolate_);
SerializeArray(array);
} }
for (int i = 0; i < objects_->Length(); ++i) {
Handle<JSObject> object =
handle(JSObject::cast(objects_->Get(i)), isolate_);
SerializeObject(object);
} }
// Maps and strings get serialized when they're encountered; we don't need to
// serialize them explicitly.
} }
// Format (full snapshot): // Format (full snapshot):
...@@ -457,8 +480,7 @@ void WebSnapshotSerializer::SerializeFunctionInfo(ValueSerializer* serializer, ...@@ -457,8 +480,7 @@ void WebSnapshotSerializer::SerializeFunctionInfo(ValueSerializer* serializer,
serializer->WriteUint32(0); serializer->WriteUint32(0);
} else { } else {
DCHECK(context->IsFunctionContext() || context->IsBlockContext()); DCHECK(context->IsFunctionContext() || context->IsBlockContext());
uint32_t context_id = 0; uint32_t context_id = GetContextId(context);
SerializeContext(context, context_id);
serializer->WriteUint32(context_id + 1); serializer->WriteUint32(context_id + 1);
} }
...@@ -468,6 +490,167 @@ void WebSnapshotSerializer::SerializeFunctionInfo(ValueSerializer* serializer, ...@@ -468,6 +490,167 @@ void WebSnapshotSerializer::SerializeFunctionInfo(ValueSerializer* serializer,
FunctionKindToFunctionFlags(function->shared().kind())); FunctionKindToFunctionFlags(function->shared().kind()));
} }
void WebSnapshotSerializer::Discovery(Handle<Object> start_object) {
// The object discovery phase assigns IDs for objects / functions / classes /
// arrays and discovers outgoing references from them. This is needed so that
// e.g., we know all functions upfront and can construct the source code that
// covers them before serializing the functions.
// TODO(v8:11525): Serialize leaf objects first.
contexts_ = ArrayList::New(isolate_, 30);
functions_ = ArrayList::New(isolate_, 30);
classes_ = ArrayList::New(isolate_, 30);
arrays_ = ArrayList::New(isolate_, 30);
objects_ = ArrayList::New(isolate_, 30);
discovery_queue_.push(start_object);
while (!discovery_queue_.empty()) {
const Handle<Object>& object = discovery_queue_.front();
if (object->IsHeapObject()) {
switch (HeapObject::cast(*object).map().instance_type()) {
case JS_FUNCTION_TYPE:
DiscoverFunction(Handle<JSFunction>::cast(object));
break;
case JS_CLASS_CONSTRUCTOR_TYPE:
DiscoverClass(Handle<JSFunction>::cast(object));
break;
case JS_OBJECT_TYPE:
DiscoverObject(Handle<JSObject>::cast(object));
break;
case JS_ARRAY_TYPE:
DiscoverArray(Handle<JSArray>::cast(object));
break;
case ODDBALL_TYPE:
case HEAP_NUMBER_TYPE:
case JS_PRIMITIVE_WRAPPER_TYPE:
case JS_REG_EXP_TYPE:
// Can't contain references to other objects.
break;
default:
if (object->IsString()) {
// Can't contain references to other objects.
break;
} else {
Throw("Web snapshot: Unsupported object");
}
}
}
discovery_queue_.pop();
}
}
void WebSnapshotSerializer::DiscoverFunction(Handle<JSFunction> function) {
uint32_t id;
if (InsertIntoIndexMap(function_ids_, function, id)) {
return;
}
DCHECK_EQ(id, functions_->Length());
functions_ = ArrayList::Add(isolate_, functions_, function);
Handle<Context> context(function->context(), isolate_);
if (context->IsFunctionContext() || context->IsBlockContext()) {
DiscoverContext(context);
}
// TODO(v8:11525): Serialize .prototype.
// TODO(v8:11525): Support properties in functions.
}
void WebSnapshotSerializer::DiscoverClass(Handle<JSFunction> function) {
uint32_t id;
if (InsertIntoIndexMap(class_ids_, function, id)) {
return;
}
DCHECK_EQ(id, classes_->Length());
classes_ = ArrayList::Add(isolate_, classes_, function);
Handle<Context> context(function->context(), isolate_);
if (context->IsFunctionContext() || context->IsBlockContext()) {
DiscoverContext(context);
}
Handle<JSObject> prototype =
Handle<JSObject>::cast(handle(function->prototype(), isolate_));
discovery_queue_.push(prototype);
// TODO(v8:11525): Support properties in classes.
// TODO(v8:11525): Support class members.
}
void WebSnapshotSerializer::DiscoverContext(Handle<Context> context) {
// Ensure that parent contexts get a lower ID.
if (!context->previous().IsNativeContext() &&
!context->previous().IsScriptContext()) {
DiscoverContext(handle(context->previous(), isolate_));
}
uint32_t id;
if (InsertIntoIndexMap(context_ids_, context, id)) {
return;
}
DCHECK_EQ(id, contexts_->Length());
contexts_ = ArrayList::Add(isolate_, contexts_, context);
Handle<ScopeInfo> scope_info(context->scope_info(), isolate_);
int count = scope_info->ContextLocalCount();
for (int i = 0; i < count; ++i) {
// TODO(v8:11525): support parameters
// TODO(v8:11525): distinguish variable modes
Handle<Object> value(context->get(scope_info->ContextHeaderLength() + i),
isolate_);
discovery_queue_.push(value);
}
}
void WebSnapshotSerializer::DiscoverArray(Handle<JSArray> array) {
uint32_t id;
if (InsertIntoIndexMap(array_ids_, array, id)) {
return;
}
DCHECK_EQ(id, arrays_->Length());
arrays_ = ArrayList::Add(isolate_, arrays_, array);
auto elements_kind = array->GetElementsKind();
if (elements_kind != PACKED_SMI_ELEMENTS &&
elements_kind != PACKED_ELEMENTS) {
Throw("Web Snapshot: Unsupported array");
return;
}
// TODO(v8:11525): Support sparse arrays & arrays with holes.
uint32_t length = static_cast<uint32_t>(array->length().ToSmi().value());
Handle<FixedArray> elements =
handle(FixedArray::cast(array->elements()), isolate_);
for (uint32_t i = 0; i < length; ++i) {
discovery_queue_.push(handle(elements->get(i), isolate_));
}
}
void WebSnapshotSerializer::DiscoverObject(Handle<JSObject> object) {
uint32_t id;
if (InsertIntoIndexMap(object_ids_, object, id)) {
return;
}
DCHECK_EQ(id, objects_->Length());
objects_ = ArrayList::Add(isolate_, objects_, object);
Handle<Map> map(object->map(), isolate_);
for (InternalIndex i : map->IterateOwnDescriptors()) {
PropertyDetails details =
map->instance_descriptors(kRelaxedLoad).GetDetails(i);
FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
Handle<Object> value =
JSObject::FastPropertyAt(object, details.representation(), field_index);
discovery_queue_.push(value);
}
}
// Format (serialized function): // Format (serialized function):
// - 0 if there's no context, 1 + context id otherwise // - 0 if there's no context, 1 + context id otherwise
// - String id (source snippet) // - String id (source snippet)
...@@ -476,12 +659,7 @@ void WebSnapshotSerializer::SerializeFunctionInfo(ValueSerializer* serializer, ...@@ -476,12 +659,7 @@ void WebSnapshotSerializer::SerializeFunctionInfo(ValueSerializer* serializer,
// - Flags (see FunctionFlags) // - Flags (see FunctionFlags)
// TODO(v8:11525): Investigate whether the length is really needed. // TODO(v8:11525): Investigate whether the length is really needed.
// TODO(v8:11525): Serialize the formal parameter count. // TODO(v8:11525): Serialize the formal parameter count.
void WebSnapshotSerializer::SerializeFunction(Handle<JSFunction> function, void WebSnapshotSerializer::SerializeFunction(Handle<JSFunction> function) {
uint32_t& id) {
if (InsertIntoIndexMap(function_ids_, function, id)) {
return;
}
SerializeFunctionInfo(&function_serializer_, function); SerializeFunctionInfo(&function_serializer_, function);
// TODO(v8:11525): Serialize .prototype. // TODO(v8:11525): Serialize .prototype.
...@@ -497,18 +675,12 @@ void WebSnapshotSerializer::SerializeFunction(Handle<JSFunction> function, ...@@ -497,18 +675,12 @@ void WebSnapshotSerializer::SerializeFunction(Handle<JSFunction> function,
// - Length in the source snippet // - Length in the source snippet
// - Flags (see FunctionFlags) // - Flags (see FunctionFlags)
// - Object id (function prototype) // - Object id (function prototype)
void WebSnapshotSerializer::SerializeClass(Handle<JSFunction> function, void WebSnapshotSerializer::SerializeClass(Handle<JSFunction> function) {
uint32_t& id) {
if (InsertIntoIndexMap(class_ids_, function, id)) {
return;
}
SerializeFunctionInfo(&class_serializer_, function); SerializeFunctionInfo(&class_serializer_, function);
Handle<JSObject> prototype = Handle<JSObject> prototype =
Handle<JSObject>::cast(handle(function->prototype(), isolate_)); Handle<JSObject>::cast(handle(function->prototype(), isolate_));
uint32_t prototype_id; uint32_t prototype_id = GetObjectId(prototype);
SerializeObject(prototype, prototype_id);
class_serializer_.WriteUint32(prototype_id); class_serializer_.WriteUint32(prototype_id);
// TODO(v8:11525): Support properties in classes. // TODO(v8:11525): Support properties in classes.
...@@ -523,27 +695,13 @@ void WebSnapshotSerializer::SerializeClass(Handle<JSFunction> function, ...@@ -523,27 +695,13 @@ void WebSnapshotSerializer::SerializeClass(Handle<JSFunction> function,
// - For each variable: // - For each variable:
// - String id (name) // - String id (name)
// - Serialized value // - Serialized value
void WebSnapshotSerializer::SerializeContext(Handle<Context> context, void WebSnapshotSerializer::SerializeContext(Handle<Context> context) {
uint32_t& id) {
// Invariant: parent context is serialized first.
// Can't use InsertIntoIndexMap here, because it might reserve a lower id
// for the context than its parent.
int index_out = 0;
if (context_ids_.Lookup(context, &index_out)) {
id = static_cast<uint32_t>(index_out);
return;
}
uint32_t parent_context_id = 0; uint32_t parent_context_id = 0;
if (!context->previous().IsNativeContext() && if (!context->previous().IsNativeContext() &&
!context->previous().IsScriptContext()) { !context->previous().IsScriptContext()) {
SerializeContext(handle(context->previous(), isolate_), parent_context_id); parent_context_id = GetContextId(handle(context->previous(), isolate_)) + 1;
++parent_context_id;
} }
InsertIntoIndexMap(context_ids_, context, id);
// TODO(v8:11525): Use less space for encoding the context type. // TODO(v8:11525): Use less space for encoding the context type.
if (context->IsFunctionContext()) { if (context->IsFunctionContext()) {
context_serializer_.WriteUint32(ContextType::FUNCTION); context_serializer_.WriteUint32(ContextType::FUNCTION);
...@@ -571,34 +729,13 @@ void WebSnapshotSerializer::SerializeContext(Handle<Context> context, ...@@ -571,34 +729,13 @@ void WebSnapshotSerializer::SerializeContext(Handle<Context> context,
isolate_); isolate_);
WriteValue(value, context_serializer_); WriteValue(value, context_serializer_);
} }
// TODO(v8:11525): Support context referencing a context indirectly (e.g.,
// context -> array -> function -> context).
}
void WebSnapshotSerializer::SerializeObject(Handle<JSObject> object,
uint32_t& id) {
// TODO(v8:11525): Serialize the leaf objects first.
DCHECK(!object->IsJSFunction());
if (InsertIntoIndexMap(object_ids_, object, id)) {
return;
}
pending_objects_.push(object);
}
void WebSnapshotSerializer::SerializeArray(Handle<JSArray> array,
uint32_t& id) {
// TODO(v8:11525): Serialize the leaf objects first.
if (InsertIntoIndexMap(array_ids_, array, id)) {
return;
}
pending_arrays_.push(array);
} }
// Format (serialized object): // Format (serialized object):
// - Shape id // - Shape id
// - For each property: // - For each property:
// - Serialized value // - Serialized value
void WebSnapshotSerializer::SerializePendingObject(Handle<JSObject> object) { void WebSnapshotSerializer::SerializeObject(Handle<JSObject> object) {
Handle<Map> map(object->map(), isolate_); Handle<Map> map(object->map(), isolate_);
uint32_t map_id = 0; uint32_t map_id = 0;
SerializeMap(map, map_id); SerializeMap(map, map_id);
...@@ -624,7 +761,7 @@ void WebSnapshotSerializer::SerializePendingObject(Handle<JSObject> object) { ...@@ -624,7 +761,7 @@ void WebSnapshotSerializer::SerializePendingObject(Handle<JSObject> object) {
// - Length // - Length
// - For each element: // - For each element:
// - Serialized value // - Serialized value
void WebSnapshotSerializer::SerializePendingArray(Handle<JSArray> array) { void WebSnapshotSerializer::SerializeArray(Handle<JSArray> array) {
auto elements_kind = array->GetElementsKind(); auto elements_kind = array->GetElementsKind();
if (elements_kind != PACKED_SMI_ELEMENTS && if (elements_kind != PACKED_SMI_ELEMENTS &&
elements_kind != PACKED_ELEMENTS) { elements_kind != PACKED_ELEMENTS) {
...@@ -698,24 +835,20 @@ void WebSnapshotSerializer::WriteValue(Handle<Object> object, ...@@ -698,24 +835,20 @@ void WebSnapshotSerializer::WriteValue(Handle<Object> object,
serializer.WriteDouble(HeapNumber::cast(*object).value()); serializer.WriteDouble(HeapNumber::cast(*object).value());
break; break;
case JS_FUNCTION_TYPE: case JS_FUNCTION_TYPE:
SerializeFunction(Handle<JSFunction>::cast(object), id);
serializer.WriteUint32(ValueType::FUNCTION_ID); serializer.WriteUint32(ValueType::FUNCTION_ID);
serializer.WriteUint32(id); serializer.WriteUint32(GetFunctionId(Handle<JSFunction>::cast(object)));
break; break;
case JS_CLASS_CONSTRUCTOR_TYPE: case JS_CLASS_CONSTRUCTOR_TYPE:
SerializeClass(Handle<JSFunction>::cast(object), id);
serializer.WriteUint32(ValueType::CLASS_ID); serializer.WriteUint32(ValueType::CLASS_ID);
serializer.WriteUint32(id); serializer.WriteUint32(GetClassId(Handle<JSFunction>::cast(object)));
break; break;
case JS_OBJECT_TYPE: case JS_OBJECT_TYPE:
SerializeObject(Handle<JSObject>::cast(object), id);
serializer.WriteUint32(ValueType::OBJECT_ID); serializer.WriteUint32(ValueType::OBJECT_ID);
serializer.WriteUint32(id); serializer.WriteUint32(GetObjectId(Handle<JSObject>::cast(object)));
break; break;
case JS_ARRAY_TYPE: case JS_ARRAY_TYPE:
SerializeArray(Handle<JSArray>::cast(object), id);
serializer.WriteUint32(ValueType::ARRAY_ID); serializer.WriteUint32(ValueType::ARRAY_ID);
serializer.WriteUint32(id); serializer.WriteUint32(GetArrayId(Handle<JSArray>::cast(object)));
break; break;
case JS_REG_EXP_TYPE: { case JS_REG_EXP_TYPE: {
Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(object); Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(object);
...@@ -746,6 +879,46 @@ void WebSnapshotSerializer::WriteValue(Handle<Object> object, ...@@ -746,6 +879,46 @@ void WebSnapshotSerializer::WriteValue(Handle<Object> object,
// TODO(v8:11525): Support more types. // TODO(v8:11525): Support more types.
} }
uint32_t WebSnapshotSerializer::GetFunctionId(Handle<JSFunction> function) {
int id;
bool return_value = function_ids_.Lookup(function, &id);
DCHECK(return_value);
USE(return_value);
return static_cast<uint32_t>(id);
}
uint32_t WebSnapshotSerializer::GetClassId(Handle<JSFunction> function) {
int id;
bool return_value = class_ids_.Lookup(function, &id);
DCHECK(return_value);
USE(return_value);
return static_cast<uint32_t>(id);
}
uint32_t WebSnapshotSerializer::GetContextId(Handle<Context> context) {
int id;
bool return_value = context_ids_.Lookup(context, &id);
DCHECK(return_value);
USE(return_value);
return static_cast<uint32_t>(id);
}
uint32_t WebSnapshotSerializer::GetArrayId(Handle<JSArray> array) {
int id;
bool return_value = array_ids_.Lookup(array, &id);
DCHECK(return_value);
USE(return_value);
return static_cast<uint32_t>(id);
}
uint32_t WebSnapshotSerializer::GetObjectId(Handle<JSObject> object) {
int id;
bool return_value = object_ids_.Lookup(object, &id);
DCHECK(return_value);
USE(return_value);
return static_cast<uint32_t>(id);
}
WebSnapshotDeserializer::WebSnapshotDeserializer(v8::Isolate* isolate) WebSnapshotDeserializer::WebSnapshotDeserializer(v8::Isolate* isolate)
: WebSnapshotSerializerDeserializer( : WebSnapshotSerializerDeserializer(
reinterpret_cast<v8::internal::Isolate*>(isolate)) {} reinterpret_cast<v8::internal::Isolate*>(isolate)) {}
...@@ -1618,6 +1791,12 @@ void WebSnapshotDeserializer::AddDeferredReference(Handle<Object> container, ...@@ -1618,6 +1791,12 @@ void WebSnapshotDeserializer::AddDeferredReference(Handle<Object> container,
} }
void WebSnapshotDeserializer::ProcessDeferredReferences() { void WebSnapshotDeserializer::ProcessDeferredReferences() {
// Check for error now, since the FixedArrays below might not have been
// created if there was an error.
if (has_error()) {
return;
}
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
ArrayList raw_deferred_references = *deferred_references_; ArrayList raw_deferred_references = *deferred_references_;
FixedArray raw_functions = *functions_; FixedArray raw_functions = *functions_;
......
...@@ -155,6 +155,14 @@ class V8_EXPORT WebSnapshotSerializer ...@@ -155,6 +155,14 @@ class V8_EXPORT WebSnapshotSerializer
// Returns true if the object was already in the map, false if it was added. // Returns true if the object was already in the map, false if it was added.
bool InsertIntoIndexMap(ObjectCacheIndexMap& map, Handle<HeapObject> object, bool InsertIntoIndexMap(ObjectCacheIndexMap& map, Handle<HeapObject> object,
uint32_t& id); uint32_t& id);
void Discovery(Handle<Object> object);
void DiscoverFunction(Handle<JSFunction> function);
void DiscoverClass(Handle<JSFunction> function);
void DiscoverContext(Handle<Context> context);
void DiscoverArray(Handle<JSArray> array);
void DiscoverObject(Handle<JSObject> object);
void SerializeSource(ValueSerializer* serializer, void SerializeSource(ValueSerializer* serializer,
Handle<JSFunction> function); Handle<JSFunction> function);
void SerializeFunctionInfo(ValueSerializer* serializer, void SerializeFunctionInfo(ValueSerializer* serializer,
...@@ -162,16 +170,22 @@ class V8_EXPORT WebSnapshotSerializer ...@@ -162,16 +170,22 @@ class V8_EXPORT WebSnapshotSerializer
void SerializeString(Handle<String> string, uint32_t& id); void SerializeString(Handle<String> string, uint32_t& id);
void SerializeMap(Handle<Map> map, uint32_t& id); void SerializeMap(Handle<Map> map, uint32_t& id);
void SerializeFunction(Handle<JSFunction> function, uint32_t& id);
void SerializeClass(Handle<JSFunction> function, uint32_t& id); void SerializeFunction(Handle<JSFunction> function);
void SerializeContext(Handle<Context> context, uint32_t& id); void SerializeClass(Handle<JSFunction> function);
void SerializeArray(Handle<JSArray> array, uint32_t& id); void SerializeContext(Handle<Context> context);
void SerializePendingArray(Handle<JSArray> array); void SerializeArray(Handle<JSArray> array);
void SerializeObject(Handle<JSObject> object, uint32_t& id); void SerializeObject(Handle<JSObject> object);
void SerializePendingObject(Handle<JSObject> object);
void SerializeExport(Handle<JSObject> object, Handle<String> export_name); void SerializeExport(Handle<JSObject> object, Handle<String> export_name);
void WriteValue(Handle<Object> object, ValueSerializer& serializer); void WriteValue(Handle<Object> object, ValueSerializer& serializer);
uint32_t GetFunctionId(Handle<JSFunction> function);
uint32_t GetClassId(Handle<JSFunction> function);
uint32_t GetContextId(Handle<Context> context);
uint32_t GetArrayId(Handle<JSArray> array);
uint32_t GetObjectId(Handle<JSObject> object);
ValueSerializer string_serializer_; ValueSerializer string_serializer_;
ValueSerializer map_serializer_; ValueSerializer map_serializer_;
ValueSerializer context_serializer_; ValueSerializer context_serializer_;
...@@ -181,6 +195,14 @@ class V8_EXPORT WebSnapshotSerializer ...@@ -181,6 +195,14 @@ class V8_EXPORT WebSnapshotSerializer
ValueSerializer object_serializer_; ValueSerializer object_serializer_;
ValueSerializer export_serializer_; ValueSerializer export_serializer_;
// These are needed for being able to serialize items in order.
Handle<ArrayList> contexts_;
Handle<ArrayList> functions_;
Handle<ArrayList> classes_;
Handle<ArrayList> arrays_;
Handle<ArrayList> objects_;
// ObjectCacheIndexMap implements fast lookup item -> id.
ObjectCacheIndexMap string_ids_; ObjectCacheIndexMap string_ids_;
ObjectCacheIndexMap map_ids_; ObjectCacheIndexMap map_ids_;
ObjectCacheIndexMap context_ids_; ObjectCacheIndexMap context_ids_;
...@@ -190,8 +212,7 @@ class V8_EXPORT WebSnapshotSerializer ...@@ -190,8 +212,7 @@ class V8_EXPORT WebSnapshotSerializer
ObjectCacheIndexMap object_ids_; ObjectCacheIndexMap object_ids_;
uint32_t export_count_ = 0; uint32_t export_count_ = 0;
std::queue<Handle<JSObject>> pending_objects_; std::queue<Handle<Object>> discovery_queue_;
std::queue<Handle<JSArray>> pending_arrays_;
}; };
class V8_EXPORT WebSnapshotDeserializer class V8_EXPORT WebSnapshotDeserializer
......
...@@ -234,7 +234,7 @@ function takeAndUseWebSnapshot(createObjects, exports) { ...@@ -234,7 +234,7 @@ function takeAndUseWebSnapshot(createObjects, exports) {
assertEquals([5, 6, 7], foo.array); assertEquals([5, 6, 7], foo.array);
})(); })();
(function TestArray() { (function TestEmptyArray() {
function createObjects() { function createObjects() {
globalThis.foo = { globalThis.foo = {
array: [] array: []
...@@ -255,7 +255,6 @@ function takeAndUseWebSnapshot(createObjects, exports) { ...@@ -255,7 +255,6 @@ function takeAndUseWebSnapshot(createObjects, exports) {
assertEquals([[2, 3], [4, 5]], foo.array); assertEquals([[2, 3], [4, 5]], foo.array);
})(); })();
(function TestArrayContainingObject() { (function TestArrayContainingObject() {
function createObjects() { function createObjects() {
globalThis.foo = { globalThis.foo = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment