Commit 16fa2f28 authored by jameslahm's avatar jameslahm Committed by V8 LUCI CQ

[web snapshot] Support properties in function

This CL adds the serialization and deserialization
for properties in function. And we only support fast
properties in property array now.

Bug: v8:11525
Change-Id: If0bb3fee400ca957009d046ed74b92d8192c2514
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3650675
Commit-Queue: 王澳 <wangao.james@bytedance.com>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80858}
parent cbdc545d
...@@ -590,17 +590,18 @@ void WebSnapshotSerializer::SerializeMap(Handle<Map> map) { ...@@ -590,17 +590,18 @@ void WebSnapshotSerializer::SerializeMap(Handle<Map> map) {
keys.reserve(map->NumberOfOwnDescriptors()); keys.reserve(map->NumberOfOwnDescriptors());
attributes.reserve(map->NumberOfOwnDescriptors()); attributes.reserve(map->NumberOfOwnDescriptors());
for (InternalIndex i : map->IterateOwnDescriptors()) { for (InternalIndex i : map->IterateOwnDescriptors()) {
Handle<Name> key(map->instance_descriptors(kRelaxedLoad).GetKey(i),
isolate_);
keys.push_back(key);
PropertyDetails details = PropertyDetails details =
map->instance_descriptors(kRelaxedLoad).GetDetails(i); map->instance_descriptors(kRelaxedLoad).GetDetails(i);
// If there are non-field properties in a map that doesn't allow them, i.e.,
// a non-function map, DiscoverMap has already thrown.
if (details.location() != PropertyLocation::kField) { if (details.location() != PropertyLocation::kField) {
Throw("Properties which are not fields not supported"); continue;
return;
} }
Handle<Name> key(map->instance_descriptors(kRelaxedLoad).GetKey(i),
isolate_);
keys.push_back(key);
if (first_custom_index >= 0 || details.IsReadOnly() || if (first_custom_index >= 0 || details.IsReadOnly() ||
!details.IsConfigurable() || details.IsDontEnum()) { !details.IsConfigurable() || details.IsDontEnum()) {
if (first_custom_index == -1) first_custom_index = i.as_int(); if (first_custom_index == -1) first_custom_index = i.as_int();
...@@ -692,6 +693,29 @@ void WebSnapshotSerializer::ConstructSource() { ...@@ -692,6 +693,29 @@ void WebSnapshotSerializer::ConstructSource() {
DCHECK(!in_place); DCHECK(!in_place);
} }
void WebSnapshotSerializer::SerializeFunctionProperties(
Handle<JSFunction> function) {
Handle<Map> map(function->map(), isolate_);
if (function->map() ==
isolate_->context().get(function->shared().function_map_index())) {
function_serializer_.WriteUint32(0);
return;
} else {
function_serializer_.WriteUint32(GetMapId(function->map()) + 1);
}
for (InternalIndex i : map->IterateOwnDescriptors()) {
PropertyDetails details =
map->instance_descriptors(kRelaxedLoad).GetDetails(i);
if (details.location() == PropertyLocation::kDescriptor) {
continue;
}
FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
Handle<Object> value = JSObject::FastPropertyAt(
isolate_, function, details.representation(), field_index);
WriteValue(value, function_serializer_);
}
}
void WebSnapshotSerializer::SerializeFunctionInfo(Handle<JSFunction> function, void WebSnapshotSerializer::SerializeFunctionInfo(Handle<JSFunction> function,
ValueSerializer& serializer) { ValueSerializer& serializer) {
if (!function->shared().HasSourceCode()) { if (!function->shared().HasSourceCode()) {
...@@ -735,7 +759,6 @@ void WebSnapshotSerializer::SerializeFunctionInfo(Handle<JSFunction> function, ...@@ -735,7 +759,6 @@ void WebSnapshotSerializer::SerializeFunctionInfo(Handle<JSFunction> function,
} else { } else {
serializer.WriteUint32(0); serializer.WriteUint32(0);
} }
WriteValue(handle(function->map().prototype(), isolate_), serializer);
} }
void WebSnapshotSerializer::ShallowDiscoverExternals(FixedArray externals) { void WebSnapshotSerializer::ShallowDiscoverExternals(FixedArray externals) {
...@@ -836,7 +859,19 @@ void WebSnapshotSerializer::Discover(Handle<HeapObject> start_object) { ...@@ -836,7 +859,19 @@ void WebSnapshotSerializer::Discover(Handle<HeapObject> start_object) {
} }
} }
void WebSnapshotSerializer::DiscoverMap(Handle<Map> map) { void WebSnapshotSerializer::DiscoverPropertyKey(Handle<Name> key) {
if (key->IsString()) {
DiscoverString(Handle<String>::cast(key), AllowInPlace::Yes);
} else if (key->IsSymbol()) {
DiscoverSymbol(Handle<Symbol>::cast(key));
} else {
Throw("Property key is not a String / Symbol");
return;
}
}
void WebSnapshotSerializer::DiscoverMap(Handle<Map> map,
bool allow_property_in_descriptor) {
// Dictionary map object names get discovered in DiscoverObject. // Dictionary map object names get discovered in DiscoverObject.
if (map->is_dictionary_map()) { if (map->is_dictionary_map()) {
return; return;
...@@ -849,16 +884,19 @@ void WebSnapshotSerializer::DiscoverMap(Handle<Map> map) { ...@@ -849,16 +884,19 @@ void WebSnapshotSerializer::DiscoverMap(Handle<Map> map) {
DCHECK_EQ(id, maps_->Length()); DCHECK_EQ(id, maps_->Length());
maps_ = ArrayList::Add(isolate_, maps_, map); maps_ = ArrayList::Add(isolate_, maps_, map);
for (InternalIndex i : map->IterateOwnDescriptors()) { for (InternalIndex i : map->IterateOwnDescriptors()) {
Handle<Name> key(map->instance_descriptors(kRelaxedLoad).GetKey(i), PropertyDetails details =
isolate_); map->instance_descriptors(kRelaxedLoad).GetDetails(i);
if (key->IsString()) { if (details.location() != PropertyLocation::kField) {
DiscoverString(Handle<String>::cast(key), AllowInPlace::Yes); if (!allow_property_in_descriptor) {
} else if (key->IsSymbol()) { Throw("Properties which are not fields not supported");
DiscoverSymbol(Handle<Symbol>::cast(key));
} else {
Throw("Map key is not a String / Symbol");
return; return;
} else {
continue;
}
} }
Handle<Name> key(map->instance_descriptors(kRelaxedLoad).GetKey(i),
isolate_);
DiscoverPropertyKey(key);
} }
} }
...@@ -900,8 +938,37 @@ void WebSnapshotSerializer::DiscoverFunction(Handle<JSFunction> function) { ...@@ -900,8 +938,37 @@ void WebSnapshotSerializer::DiscoverFunction(Handle<JSFunction> function) {
DCHECK_EQ(id, functions_->Length()); DCHECK_EQ(id, functions_->Length());
functions_ = ArrayList::Add(isolate_, functions_, function); functions_ = ArrayList::Add(isolate_, functions_, function);
JSObject::MigrateSlowToFast(function, 0, "Web snapshot");
// TODO(v8:11525): Support functions with so many properties that they can't
// be in fast mode.
if (!function->HasFastProperties()) {
Throw("Unsupported function with dictionary map");
return;
}
DiscoverContextAndPrototype(function); DiscoverContextAndPrototype(function);
// TODO(v8:11525): Support properties in functions. if (function->map() !=
isolate_->context().get(function->shared().function_map_index())) {
Handle<Map> map(function->map(), isolate_);
// We only serialize properties which are fields in function. And properties
// which are descriptors will be setup in CreateJSFunction.
DiscoverMap(map, true);
discovery_queue_.push(handle(map->prototype(), isolate_));
// Discover property values.
for (InternalIndex i : map->IterateOwnDescriptors()) {
PropertyDetails details =
map->instance_descriptors(kRelaxedLoad).GetDetails(i);
if (details.location() == PropertyLocation::kDescriptor) {
continue;
}
FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
Handle<Object> value = JSObject::FastPropertyAt(
isolate_, function, details.representation(), field_index);
if (!value->IsHeapObject()) continue;
discovery_queue_.push(Handle<HeapObject>::cast(value));
}
}
DiscoverSource(function); DiscoverSource(function);
} }
...@@ -1095,14 +1162,7 @@ void WebSnapshotSerializer::DiscoverObjectPropertiesWithDictionaryMap(T dict) { ...@@ -1095,14 +1162,7 @@ void WebSnapshotSerializer::DiscoverObjectPropertiesWithDictionaryMap(T dict) {
// Ignore deleted entries. // Ignore deleted entries.
continue; continue;
} }
if (key->IsString()) { DiscoverPropertyKey(Handle<Name>::cast(key));
DiscoverString(Handle<String>::cast(key), AllowInPlace::Yes);
} else if (key->IsSymbol()) {
DiscoverSymbol(Handle<Symbol>::cast(key));
} else {
Throw("Object property is not a String / Symbol");
return;
}
Handle<Object> value = handle(dict->ValueAt(index), isolate_); Handle<Object> value = handle(dict->ValueAt(index), isolate_);
if (!value->IsHeapObject()) { if (!value->IsHeapObject()) {
continue; continue;
...@@ -1126,8 +1186,12 @@ void WebSnapshotSerializer::DiscoverObject(Handle<JSObject> object) { ...@@ -1126,8 +1186,12 @@ void WebSnapshotSerializer::DiscoverObject(Handle<JSObject> object) {
DCHECK_EQ(id, objects_->Length()); DCHECK_EQ(id, objects_->Length());
objects_ = ArrayList::Add(isolate_, objects_, object); objects_ = ArrayList::Add(isolate_, objects_, object);
// TODO(v8:11525): Support objects with so many properties that they can't be // TODO(v8:11525): After we allow "non-map" objects which are small
// in fast mode. // enough to have a fast map, we should remove this. Although we support
// objects with dictionary map now, we still check the property count is
// bigger than kMaxNumberOfDescriptors when deserializing dictionary map and
// then removing this will break deserializing prototype objects having a
// dictionary map with few properties.
JSObject::MigrateSlowToFast(object, 0, "Web snapshot"); JSObject::MigrateSlowToFast(object, 0, "Web snapshot");
Handle<Map> map(object->map(), isolate_); Handle<Map> map(object->map(), isolate_);
...@@ -1216,12 +1280,16 @@ void WebSnapshotSerializer::DiscoverSymbol(Handle<Symbol> symbol) { ...@@ -1216,12 +1280,16 @@ void WebSnapshotSerializer::DiscoverSymbol(Handle<Symbol> symbol) {
// - Length in the source snippet // - Length in the source snippet
// - Formal parameter count // - Formal parameter count
// - Flags (see FunctionFlags) // - Flags (see FunctionFlags)
// - 0 if there's no function prototype, 1 + object id for the function // - 0 if there's no map, 1 + map id otherwise
// prototype otherwise // - For each function property
// - Serialized value
// - Function prototype
// TODO(v8:11525): Investigate whether the length is really needed. // TODO(v8:11525): Investigate whether the length is really needed.
void WebSnapshotSerializer::SerializeFunction(Handle<JSFunction> function) { void WebSnapshotSerializer::SerializeFunction(Handle<JSFunction> function) {
SerializeFunctionInfo(function, function_serializer_); SerializeFunctionInfo(function, function_serializer_);
// TODO(v8:11525): Support properties in functions. SerializeFunctionProperties(function);
WriteValue(handle(function->map().prototype(), isolate_),
function_serializer_);
} }
// Format (serialized class): // Format (serialized class):
...@@ -1234,6 +1302,7 @@ void WebSnapshotSerializer::SerializeFunction(Handle<JSFunction> function) { ...@@ -1234,6 +1302,7 @@ void WebSnapshotSerializer::SerializeFunction(Handle<JSFunction> function) {
// - 1 + object id for the function prototype // - 1 + object id for the function prototype
void WebSnapshotSerializer::SerializeClass(Handle<JSFunction> function) { void WebSnapshotSerializer::SerializeClass(Handle<JSFunction> function) {
SerializeFunctionInfo(function, class_serializer_); SerializeFunctionInfo(function, class_serializer_);
WriteValue(handle(function->map().prototype(), isolate_), class_serializer_);
// TODO(v8:11525): Support properties in classes. // TODO(v8:11525): Support properties in classes.
// TODO(v8:11525): Support class members. // TODO(v8:11525): Support class members.
} }
...@@ -1320,9 +1389,9 @@ void WebSnapshotSerializer::SerializeObjectPropertiesWithDictionaryMap(T dict) { ...@@ -1320,9 +1389,9 @@ void WebSnapshotSerializer::SerializeObjectPropertiesWithDictionaryMap(T dict) {
WriteValue(handle(dict->ValueAt(index), isolate_), object_serializer_); WriteValue(handle(dict->ValueAt(index), isolate_), object_serializer_);
if (first_custom_index >= 0) { if (first_custom_index >= 0) {
if (index.as_int() < first_custom_index) { if (index.as_int() < first_custom_index) {
map_serializer_.WriteUint32(default_flags); object_serializer_.WriteUint32(default_flags);
} else { } else {
map_serializer_.WriteUint32( object_serializer_.WriteUint32(
attributes[index.as_int() - first_custom_index]); attributes[index.as_int() - first_custom_index]);
} }
} }
...@@ -2457,6 +2526,54 @@ void WebSnapshotDeserializer::DeserializeFunctions() { ...@@ -2457,6 +2526,54 @@ void WebSnapshotDeserializer::DeserializeFunctions() {
functions_.set(current_function_count_, *function); functions_.set(current_function_count_, *function);
ReadFunctionPrototype(function); ReadFunctionPrototype(function);
uint32_t map_id;
if (!deserializer_->ReadUint32(&map_id) || map_id >= map_count_ + 1) {
Throw("Malformed function");
return;
}
if (map_id > 0) {
map_id--; // Subtract 1 to get the real map_id.
Handle<Map> map(Map::cast(maps_.get(map_id)), isolate_);
int no_properties = map->NumberOfOwnDescriptors();
Handle<DescriptorArray> descriptors =
handle(map->instance_descriptors(kRelaxedLoad), isolate_);
Handle<PropertyArray> property_array =
DeserializePropertyArray(descriptors, no_properties);
// This function map was already deserialized completely and can be
// directly used.
auto iter = deserialized_function_maps_.find(map_id);
if (iter != deserialized_function_maps_.end()) {
function->set_map(*iter->second, kReleaseStore);
function->set_raw_properties_or_hash(*property_array);
} else {
// TODO(v8:11525): In-object properties.
Handle<Map> function_map = Map::Copy(
isolate_, handle(function->map(), isolate_), "Web Snapshot");
Map::EnsureDescriptorSlack(isolate_, function_map,
descriptors->number_of_descriptors());
{
for (InternalIndex i : map->IterateOwnDescriptors()) {
Descriptor d = Descriptor::DataField(
isolate_, handle(descriptors->GetKey(i), isolate_),
descriptors->GetDetails(i).field_index(),
descriptors->GetDetails(i).attributes(),
descriptors->GetDetails(i).representation());
function_map->instance_descriptors().Append(&d);
if (d.GetKey()->IsInterestingSymbol()) {
function_map->set_may_have_interesting_symbols(true);
}
}
function_map->SetNumberOfOwnDescriptors(
function_map->NumberOfOwnDescriptors() +
descriptors->number_of_descriptors());
function->set_map(*function_map, kReleaseStore);
function->set_raw_properties_or_hash(*property_array);
}
deserialized_function_maps_.insert(
std::make_pair(map_id, function_map));
}
}
DeserializeObjectPrototypeForFunction(function); DeserializeObjectPrototypeForFunction(function);
} }
} }
...@@ -2531,13 +2648,33 @@ void WebSnapshotDeserializer::DeserializeObjectPrototype(Handle<Map> map) { ...@@ -2531,13 +2648,33 @@ void WebSnapshotDeserializer::DeserializeObjectPrototype(Handle<Map> map) {
} }
} }
bool WebSnapshotDeserializer::IsInitialFunctionPrototype(Object prototype) {
return prototype == isolate_->context().function_prototype() ||
// Asyncfunction prototype.
prototype == isolate_->context()
.async_function_constructor()
.instance_prototype() ||
// GeneratorFunction prototype.
prototype == JSFunction::cast(isolate_->context()
.generator_function_map()
.constructor_or_back_pointer())
.instance_prototype() ||
// AsyncGeneratorFunction prototype
prototype == JSFunction::cast(isolate_->context()
.async_generator_function_map()
.constructor_or_back_pointer())
.instance_prototype();
}
void WebSnapshotDeserializer::DeserializeObjectPrototypeForFunction( void WebSnapshotDeserializer::DeserializeObjectPrototypeForFunction(
Handle<JSFunction> function) { Handle<JSFunction> function) {
Handle<Map> map(function->map(), isolate_); Handle<Map> map(function->map(), isolate_);
// Copy the map so that we don't end up modifying the canonical maps. // If the function prototype is not the initial function prototype, then the
// map must not be the canonical maps because we already copy the map when
// deserializaing the map for the function. And so we don't need to copy the
// map.
// TODO(v8:11525): Ensure we create the same map tree as for non-websnapshot // TODO(v8:11525): Ensure we create the same map tree as for non-websnapshot
// functions + add a test. // functions + add a test.
map = Map::Copy(isolate_, map, "Web Snapshot");
auto result = ReadValue(map, 0, InternalizeStrings::kNo); auto result = ReadValue(map, 0, InternalizeStrings::kNo);
Object prototype = std::get<0>(result); Object prototype = std::get<0>(result);
bool was_deferred = std::get<1>(result); bool was_deferred = std::get<1>(result);
...@@ -2546,16 +2683,13 @@ void WebSnapshotDeserializer::DeserializeObjectPrototypeForFunction( ...@@ -2546,16 +2683,13 @@ void WebSnapshotDeserializer::DeserializeObjectPrototypeForFunction(
// TODO(v8:11525): if the object order is relaxed, it's possible to have a // TODO(v8:11525): if the object order is relaxed, it's possible to have a
// deferred reference to Function.prototype, and we'll need to recognize and // deferred reference to Function.prototype, and we'll need to recognize and
// handle that case. // handle that case.
if (prototype == isolate_->context().function_prototype()) { if (IsInitialFunctionPrototype(prototype)) {
DCHECK_EQ(function->map().prototype(), DCHECK(IsInitialFunctionPrototype(function->map().prototype()));
isolate_->context().function_prototype());
// TODO(v8:11525): Avoid map creation (above) in this case.
return; return;
} }
if (!was_deferred) { if (!was_deferred) {
SetPrototype(map, handle(prototype, isolate_)); SetPrototype(map, handle(prototype, isolate_));
} }
function->set_map(*map, kReleaseStore);
} }
Handle<Map> Handle<Map>
...@@ -2647,6 +2781,32 @@ bool WebSnapshotDeserializer::ReadMapType() { ...@@ -2647,6 +2781,32 @@ bool WebSnapshotDeserializer::ReadMapType() {
} }
} }
Handle<PropertyArray> WebSnapshotDeserializer::DeserializePropertyArray(
Handle<DescriptorArray> descriptors, int no_properties) {
Handle<PropertyArray> property_array =
factory()->NewPropertyArray(no_properties);
for (int i = 0; i < no_properties; ++i) {
Object value = std::get<0>(ReadValue(property_array, i));
DisallowGarbageCollection no_gc;
// Read the representation from the map.
DescriptorArray raw_descriptors = *descriptors;
PropertyDetails details = raw_descriptors.GetDetails(InternalIndex(i));
CHECK_EQ(details.location(), PropertyLocation::kField);
CHECK_EQ(PropertyKind::kData, details.kind());
Representation r = details.representation();
if (r.IsNone()) {
// Switch over to wanted_representation.
details = details.CopyWithRepresentation(Representation::Tagged());
raw_descriptors.SetDetails(InternalIndex(i), details);
} else if (!r.Equals(Representation::Tagged())) {
// TODO(v8:11525): Support this case too.
UNREACHABLE();
}
property_array->set(i, value);
}
return property_array;
}
void WebSnapshotDeserializer::DeserializeObjects() { void WebSnapshotDeserializer::DeserializeObjects() {
RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Objects); RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Objects);
if (!deserializer_->ReadUint32(&object_count_) || if (!deserializer_->ReadUint32(&object_count_) ||
...@@ -2675,26 +2835,7 @@ void WebSnapshotDeserializer::DeserializeObjects() { ...@@ -2675,26 +2835,7 @@ void WebSnapshotDeserializer::DeserializeObjects() {
// TODO(v8:11525): In-object properties. // TODO(v8:11525): In-object properties.
Handle<Map> map(raw_map, isolate_); Handle<Map> map(raw_map, isolate_);
Handle<PropertyArray> property_array = Handle<PropertyArray> property_array =
factory()->NewPropertyArray(no_properties); DeserializePropertyArray(descriptors, no_properties);
for (int i = 0; i < no_properties; ++i) {
Object value = std::get<0>(ReadValue(property_array, i));
DisallowGarbageCollection no_gc;
// Read the representation from the map.
DescriptorArray raw_descriptors = *descriptors;
PropertyDetails details = raw_descriptors.GetDetails(InternalIndex(i));
CHECK_EQ(details.location(), PropertyLocation::kField);
CHECK_EQ(PropertyKind::kData, details.kind());
Representation r = details.representation();
if (r.IsNone()) {
// Switch over to wanted_representation.
details = details.CopyWithRepresentation(Representation::Tagged());
raw_descriptors.SetDetails(InternalIndex(i), details);
} else if (!r.Equals(Representation::Tagged())) {
// TODO(v8:11525): Support this case too.
UNREACHABLE();
}
property_array->set(i, value);
}
object = factory()->NewJSObjectFromMap(map); object = factory()->NewJSObjectFromMap(map);
object->set_raw_properties_or_hash(*property_array, kRelaxedStore); object->set_raw_properties_or_hash(*property_array, kRelaxedStore);
} else { } else {
......
...@@ -208,7 +208,8 @@ class V8_EXPORT WebSnapshotSerializer ...@@ -208,7 +208,8 @@ class V8_EXPORT WebSnapshotSerializer
void DiscoverString(Handle<String> string, void DiscoverString(Handle<String> string,
AllowInPlace can_be_in_place = AllowInPlace::No); AllowInPlace can_be_in_place = AllowInPlace::No);
void DiscoverSymbol(Handle<Symbol> symbol); void DiscoverSymbol(Handle<Symbol> symbol);
void DiscoverMap(Handle<Map> map); void DiscoverMap(Handle<Map> map, bool allow_property_in_descriptor = false);
void DiscoverPropertyKey(Handle<Name> key);
void DiscoverFunction(Handle<JSFunction> function); void DiscoverFunction(Handle<JSFunction> function);
void DiscoverClass(Handle<JSFunction> function); void DiscoverClass(Handle<JSFunction> function);
void DiscoverContextAndPrototype(Handle<JSFunction> function); void DiscoverContextAndPrototype(Handle<JSFunction> function);
...@@ -224,7 +225,7 @@ class V8_EXPORT WebSnapshotSerializer ...@@ -224,7 +225,7 @@ class V8_EXPORT WebSnapshotSerializer
void SerializeFunctionInfo(Handle<JSFunction> function, void SerializeFunctionInfo(Handle<JSFunction> function,
ValueSerializer& serializer); ValueSerializer& serializer);
void SerializeFunctionProperties(Handle<JSFunction> function);
void SerializeString(Handle<String> string, ValueSerializer& serializer); void SerializeString(Handle<String> string, ValueSerializer& serializer);
void SerializeSymbol(Handle<Symbol> symbol); void SerializeSymbol(Handle<Symbol> symbol);
void SerializeMap(Handle<Map> map); void SerializeMap(Handle<Map> map);
...@@ -412,10 +413,15 @@ class V8_EXPORT WebSnapshotDeserializer ...@@ -412,10 +413,15 @@ class V8_EXPORT WebSnapshotDeserializer
void DeserializeObjectPrototypeForFunction(Handle<JSFunction> function); void DeserializeObjectPrototypeForFunction(Handle<JSFunction> function);
void SetPrototype(Handle<Map> map, Handle<Object> prototype); void SetPrototype(Handle<Map> map, Handle<Object> prototype);
bool IsInitialFunctionPrototype(Object prototype);
template <typename T> template <typename T>
void DeserializeObjectPropertiesWithDictionaryMap( void DeserializeObjectPropertiesWithDictionaryMap(
T dict, uint32_t property_count, bool has_custom_property_attributes); T dict, uint32_t property_count, bool has_custom_property_attributes);
Handle<PropertyArray> DeserializePropertyArray(
Handle<DescriptorArray> descriptors, int no_properties);
// Return value: (object, was_deferred) // Return value: (object, was_deferred)
std::tuple<Object, bool> ReadValue( std::tuple<Object, bool> ReadValue(
Handle<HeapObject> object_for_deferred_reference = Handle<HeapObject>(), Handle<HeapObject> object_for_deferred_reference = Handle<HeapObject>(),
...@@ -470,6 +476,7 @@ class V8_EXPORT WebSnapshotDeserializer ...@@ -470,6 +476,7 @@ class V8_EXPORT WebSnapshotDeserializer
Handle<FixedArray> maps_handle_; Handle<FixedArray> maps_handle_;
FixedArray maps_; FixedArray maps_;
std::map<int, Handle<Map>> deserialized_function_maps_;
Handle<FixedArray> contexts_handle_; Handle<FixedArray> contexts_handle_;
FixedArray contexts_; FixedArray contexts_;
......
...@@ -147,3 +147,123 @@ d8.file.execute('test/mjsunit/web-snapshot/web-snapshot-helpers.js'); ...@@ -147,3 +147,123 @@ d8.file.execute('test/mjsunit/web-snapshot/web-snapshot-helpers.js');
assertSame(newAsyncGeneratorFunction.prototype.__proto__, assertSame(newAsyncGeneratorFunction.prototype.__proto__,
asyncGeneratorFunction.prototype.__proto__); asyncGeneratorFunction.prototype.__proto__);
})(); })();
(function TestFunctionWithProperties() {
function createObjects() {
function bar() { return 'bar'; };
bar.key1 = "value1";
bar.key2 = 1;
bar.key3 = 2.2;
bar.key4 = function key4() {
return "key4";
}
bar.key5 = [1, 2];
bar.key6 = {"key":"value"}
globalThis.foo = {
bar: bar,
};
}
const { foo } = takeAndUseWebSnapshot(createObjects, ['foo']);
assertEquals('bar', foo.bar());
assertEquals('value1', foo.bar.key1);
assertEquals(1, foo.bar.key2);
assertEquals(2.2, foo.bar.key3);
assertEquals('key4', foo.bar.key4());
assertEquals([1, 2], foo.bar.key5);
assertEquals({ "key": "value" }, foo.bar.key6 );
})();
(function TestAsyncFunctionWithProperties() {
function createObjects() {
async function bar() { return 'bar'; };
bar.key1 = "value1";
bar.key2 = 1;
bar.key3 = 2.2;
bar.key4 = function key4() {
return "key4";
}
bar.key5 = [1, 2];
bar.key6 = {"key":"value"}
globalThis.foo = {
bar: bar,
};
}
const { foo } = takeAndUseWebSnapshot(createObjects, ['foo']);
assertEquals('value1', foo.bar.key1);
assertEquals(1, foo.bar.key2);
assertEquals(2.2, foo.bar.key3);
assertEquals('key4', foo.bar.key4());
assertEquals([1, 2], foo.bar.key5);
assertEquals({ "key": "value" }, foo.bar.key6 );
})();
(function TestGeneratorFunctionWithProperties() {
function createObjects() {
function *bar() { return 'bar'; };
bar.key1 = "value1";
bar.key2 = 1;
bar.key3 = 2.2;
bar.key4 = function key4() {
return "key4";
}
bar.key5 = [1, 2];
bar.key6 = {"key":"value"}
globalThis.foo = {
bar: bar,
};
}
const { foo } = takeAndUseWebSnapshot(createObjects, ['foo']);
assertEquals('value1', foo.bar.key1);
assertEquals(1, foo.bar.key2);
assertEquals(2.2, foo.bar.key3);
assertEquals('key4', foo.bar.key4());
assertEquals([1, 2], foo.bar.key5);
assertEquals({ "key": "value" }, foo.bar.key6 );
})();
(function TestAsyncGeneratorFunctionWithProperties() {
function createObjects() {
async function *bar() { return 'bar'; };
bar.key1 = "value1";
bar.key2 = 1;
bar.key3 = 2.2;
bar.key4 = function key4() {
return "key4";
}
bar.key5 = [1, 2];
bar.key6 = {"key":"value"}
globalThis.foo = {
bar: bar,
};
}
const { foo } = takeAndUseWebSnapshot(createObjects, ['foo']);
assertEquals('value1', foo.bar.key1);
assertEquals(1, foo.bar.key2);
assertEquals(2.2, foo.bar.key3);
assertEquals('key4', foo.bar.key4());
assertEquals([1, 2], foo.bar.key5);
assertEquals({ "key": "value" }, foo.bar.key6 );
})();
(function TestFunctionsWithSameMap() {
function createObjects() {
function bar1() { return 'bar1'; };
bar1.key = "value";
function bar2() {
return "bar2";
}
bar2.key = "value";
globalThis.foo = {
bar1: bar1,
bar2: bar2
};
}
const { foo } = takeAndUseWebSnapshot(createObjects, ['foo']);
assertEquals('bar1', foo.bar1());
assertEquals('value', foo.bar1.key);
assertEquals('bar2', foo.bar2());
assertEquals('value', foo.bar2.key);
assertTrue(%HaveSameMap(foo.bar1, foo.bar2))
})();
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