[web snap] Support Symbols as property keys
Bug: v8:11525,v8:12820 Change-Id: I58bde48322c89bf33f3b28080659387a3c14de91 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3620277 Commit-Queue: Marja Hölttä <marja@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/main@{#80341}
This commit is contained in:
parent
c42e620355
commit
80d8f0c06e
@ -494,18 +494,18 @@ void WebSnapshotSerializer::SerializeSymbol(Handle<Symbol> symbol) {
|
||||
// otherwise
|
||||
// - Property count
|
||||
// - For each property
|
||||
// - String id (name)
|
||||
// - Name: STRING_ID + String id or SYMBOL_ID + Symbol id or in-place string
|
||||
// - If the PropertyAttributesType is CUSTOM: attributes
|
||||
void WebSnapshotSerializer::SerializeMap(Handle<Map> map) {
|
||||
int first_custom_index = -1;
|
||||
std::vector<Handle<String>> keys;
|
||||
std::vector<Handle<Name>> keys;
|
||||
std::vector<uint32_t> attributes;
|
||||
keys.reserve(map->NumberOfOwnDescriptors());
|
||||
attributes.reserve(map->NumberOfOwnDescriptors());
|
||||
for (InternalIndex i : map->IterateOwnDescriptors()) {
|
||||
Handle<Name> key(map->instance_descriptors(kRelaxedLoad).GetKey(i),
|
||||
isolate_);
|
||||
keys.push_back(Handle<String>::cast(key));
|
||||
keys.push_back(key);
|
||||
|
||||
PropertyDetails details =
|
||||
map->instance_descriptors(kRelaxedLoad).GetDetails(i);
|
||||
@ -543,6 +543,15 @@ void WebSnapshotSerializer::SerializeMap(Handle<Map> map) {
|
||||
|
||||
uint32_t default_flags = GetDefaultAttributeFlags();
|
||||
for (size_t i = 0; i < keys.size(); ++i) {
|
||||
if (keys[i]->IsString()) {
|
||||
WriteStringMaybeInPlace(Handle<String>::cast(keys[i]), map_serializer_);
|
||||
} else if (keys[i]->IsSymbol()) {
|
||||
map_serializer_.WriteUint32(ValueType::SYMBOL_ID);
|
||||
map_serializer_.WriteUint32(GetSymbolId(Symbol::cast(*keys[i])));
|
||||
} else {
|
||||
// This error should've been recognized in the discovery phase.
|
||||
CHECK(false);
|
||||
}
|
||||
if (first_custom_index >= 0) {
|
||||
if (static_cast<int>(i) < first_custom_index) {
|
||||
map_serializer_.WriteUint32(default_flags);
|
||||
@ -550,7 +559,6 @@ void WebSnapshotSerializer::SerializeMap(Handle<Map> map) {
|
||||
map_serializer_.WriteUint32(attributes[i - first_custom_index]);
|
||||
}
|
||||
}
|
||||
WriteStringId(keys[i], map_serializer_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -731,11 +739,14 @@ void WebSnapshotSerializer::DiscoverMap(Handle<Map> map) {
|
||||
for (InternalIndex i : map->IterateOwnDescriptors()) {
|
||||
Handle<Name> key(map->instance_descriptors(kRelaxedLoad).GetKey(i),
|
||||
isolate_);
|
||||
if (!key->IsString()) {
|
||||
Throw("Key is not a string");
|
||||
if (key->IsString()) {
|
||||
DiscoverString(Handle<String>::cast(key), AllowInPlace::Yes);
|
||||
} else if (key->IsSymbol()) {
|
||||
DiscoverSymbol(Handle<Symbol>::cast(key));
|
||||
} else {
|
||||
Throw("Map key is not a String / Symbol");
|
||||
return;
|
||||
}
|
||||
DiscoverString(Handle<String>::cast(key));
|
||||
}
|
||||
}
|
||||
|
||||
@ -930,6 +941,11 @@ void WebSnapshotSerializer::DiscoverObject(Handle<JSObject> object) {
|
||||
}
|
||||
|
||||
void WebSnapshotSerializer::DiscoverSymbol(Handle<Symbol> symbol) {
|
||||
if (symbol->is_well_known_symbol()) {
|
||||
// TODO(v8:11525): Support well-known Symbols.
|
||||
Throw("Well known Symbols aren't supported");
|
||||
return;
|
||||
}
|
||||
uint32_t id;
|
||||
if (InsertIntoIndexMap(symbol_ids_, *symbol, id)) return;
|
||||
|
||||
@ -1544,7 +1560,8 @@ void WebSnapshotDeserializer::DeserializeStrings() {
|
||||
}
|
||||
}
|
||||
|
||||
String WebSnapshotDeserializer::ReadString(bool internalize) {
|
||||
String WebSnapshotDeserializer::ReadString(
|
||||
InternalizeStrings internalize_strings) {
|
||||
DCHECK(!strings_handle_->is_null());
|
||||
uint32_t string_id;
|
||||
if (!deserializer_.ReadUint32(&string_id) || string_id >= string_count_) {
|
||||
@ -1552,14 +1569,16 @@ String WebSnapshotDeserializer::ReadString(bool internalize) {
|
||||
return roots_.empty_string();
|
||||
}
|
||||
String string = String::cast(strings_.get(string_id));
|
||||
if (internalize && !string.IsInternalizedString(isolate_)) {
|
||||
if (internalize_strings == InternalizeStrings::kYes &&
|
||||
!string.IsInternalizedString(isolate_)) {
|
||||
string = *factory()->InternalizeString(handle(string, isolate_));
|
||||
strings_.set(string_id, string);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
String WebSnapshotDeserializer::ReadInPlaceString(bool internalize) {
|
||||
String WebSnapshotDeserializer::ReadInPlaceString(
|
||||
InternalizeStrings internalize_strings) {
|
||||
MaybeHandle<String> maybe_string =
|
||||
deserializer_.ReadUtf8String(AllocationType::kOld);
|
||||
Handle<String> string;
|
||||
@ -1567,7 +1586,7 @@ String WebSnapshotDeserializer::ReadInPlaceString(bool internalize) {
|
||||
Throw("Malformed string");
|
||||
return roots_.empty_string();
|
||||
}
|
||||
if (internalize) {
|
||||
if (internalize_strings == InternalizeStrings::kYes) {
|
||||
string = factory()->InternalizeString(string);
|
||||
}
|
||||
return *string;
|
||||
@ -1679,6 +1698,15 @@ void WebSnapshotDeserializer::DeserializeMaps() {
|
||||
Handle<DescriptorArray> descriptors =
|
||||
factory()->NewDescriptorArray(property_count, 0);
|
||||
for (InternalIndex i : InternalIndex::Range(property_count)) {
|
||||
// No deferred references here, since strings and symbols have already
|
||||
// been deserialized.
|
||||
Handle<Object> key =
|
||||
handle(ReadValue(Handle<HeapObject>(), 0, InternalizeStrings::kYes),
|
||||
isolate_);
|
||||
if (!key->IsName()) {
|
||||
Throw("Invalid map key");
|
||||
return;
|
||||
}
|
||||
PropertyAttributes attributes = PropertyAttributes::NONE;
|
||||
if (has_custom_property_attributes) {
|
||||
uint32_t flags;
|
||||
@ -1688,13 +1716,11 @@ void WebSnapshotDeserializer::DeserializeMaps() {
|
||||
}
|
||||
attributes = FlagsToAttributes(flags);
|
||||
}
|
||||
|
||||
Handle<String> key(ReadString(true), isolate_);
|
||||
|
||||
// Use the "none" representation until we see the first object having this
|
||||
// map. At that point, modify the representation.
|
||||
Descriptor desc = Descriptor::DataField(
|
||||
isolate_, key, i.as_int(), attributes, Representation::None());
|
||||
Descriptor desc =
|
||||
Descriptor::DataField(isolate_, Handle<Name>::cast(key), i.as_int(),
|
||||
attributes, Representation::None());
|
||||
descriptors->Set(i, &desc);
|
||||
}
|
||||
DCHECK_EQ(descriptors->number_of_descriptors(), property_count);
|
||||
@ -1780,7 +1806,7 @@ void WebSnapshotDeserializer::DeserializeContexts() {
|
||||
for (int variable_index = 0;
|
||||
variable_index < static_cast<int>(variable_count); ++variable_index) {
|
||||
{
|
||||
String name = ReadString(true);
|
||||
String name = ReadString(InternalizeStrings::kYes);
|
||||
if (has_inlined_local_names) {
|
||||
scope_info->set(context_local_base + variable_index, name);
|
||||
} else {
|
||||
@ -1995,7 +2021,7 @@ void WebSnapshotDeserializer::DeserializeFunctions() {
|
||||
return;
|
||||
}
|
||||
{
|
||||
String source = ReadString(false);
|
||||
String source = ReadString();
|
||||
DisallowGarbageCollection no_gc;
|
||||
if (current_function_count_ == 0) {
|
||||
script_->set_source(source);
|
||||
@ -2055,7 +2081,7 @@ void WebSnapshotDeserializer::DeserializeClasses() {
|
||||
}
|
||||
|
||||
{
|
||||
String source = ReadString(false);
|
||||
String source = ReadString();
|
||||
if (current_function_count_ + current_class_count_ == 0) {
|
||||
script_->set_source(source);
|
||||
} else {
|
||||
@ -2220,7 +2246,8 @@ void WebSnapshotDeserializer::DeserializeExports(bool skip_exports) {
|
||||
// them. This is useful for stress testing; otherwise the GlobalDictionary
|
||||
// handling below dominates.
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
Handle<String> export_name(ReadString(true), isolate_);
|
||||
Handle<String> export_name(ReadString(InternalizeStrings::kYes),
|
||||
isolate_);
|
||||
// No deferred references should occur at this point, since all objects
|
||||
// have been deserialized.
|
||||
Object export_value = ReadValue();
|
||||
@ -2246,7 +2273,7 @@ void WebSnapshotDeserializer::DeserializeExports(bool skip_exports) {
|
||||
// LookupIterator::ExtendingNonExtensible.
|
||||
InternalIndex entry = InternalIndex::NotFound();
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
Handle<String> export_name(ReadString(true), isolate_);
|
||||
Handle<String> export_name(ReadString(InternalizeStrings::kYes), isolate_);
|
||||
// No deferred references should occur at this point, since all objects have
|
||||
// been deserialized.
|
||||
Object export_value = ReadValue();
|
||||
@ -2285,8 +2312,9 @@ void WebSnapshotDeserializer::DeserializeExports(bool skip_exports) {
|
||||
JSObject::InvalidatePrototypeChains(global->map(isolate_));
|
||||
}
|
||||
|
||||
Object WebSnapshotDeserializer::ReadValue(Handle<HeapObject> container,
|
||||
uint32_t container_index) {
|
||||
Object WebSnapshotDeserializer::ReadValue(
|
||||
Handle<HeapObject> container, uint32_t container_index,
|
||||
InternalizeStrings internalize_strings) {
|
||||
uint32_t value_type;
|
||||
// TODO(v8:11525): Consider adding a ReadByte.
|
||||
if (!deserializer_.ReadUint32(&value_type)) {
|
||||
@ -2311,7 +2339,7 @@ Object WebSnapshotDeserializer::ReadValue(Handle<HeapObject> container,
|
||||
case ValueType::DOUBLE:
|
||||
return ReadNumber();
|
||||
case ValueType::STRING_ID:
|
||||
return ReadString(false);
|
||||
return ReadString(internalize_strings);
|
||||
case ValueType::ARRAY_ID:
|
||||
return ReadArray(container, container_index);
|
||||
case ValueType::OBJECT_ID:
|
||||
@ -2327,7 +2355,7 @@ Object WebSnapshotDeserializer::ReadValue(Handle<HeapObject> container,
|
||||
case ValueType::EXTERNAL_ID:
|
||||
return ReadExternalReference();
|
||||
case ValueType::IN_PLACE_STRING_ID:
|
||||
return ReadInPlaceString(false);
|
||||
return ReadInPlaceString(internalize_strings);
|
||||
default:
|
||||
// TODO(v8:11525): Handle other value types.
|
||||
Throw("Unsupported value type");
|
||||
@ -2411,8 +2439,8 @@ Object WebSnapshotDeserializer::ReadClass(Handle<HeapObject> container,
|
||||
}
|
||||
|
||||
Object WebSnapshotDeserializer::ReadRegexp() {
|
||||
Handle<String> pattern(ReadString(false), isolate_);
|
||||
Handle<String> flags_string(ReadString(false), isolate_);
|
||||
Handle<String> pattern(ReadString(), isolate_);
|
||||
Handle<String> flags_string(ReadString(), isolate_);
|
||||
base::Optional<JSRegExp::Flags> flags =
|
||||
JSRegExp::FlagsFromString(isolate_, flags_string);
|
||||
if (!flags.has_value()) {
|
||||
|
@ -321,6 +321,11 @@ class V8_EXPORT WebSnapshotDeserializer
|
||||
MaybeHandle<Object> value() const { return return_value_; }
|
||||
|
||||
private:
|
||||
enum class InternalizeStrings {
|
||||
kNo,
|
||||
kYes,
|
||||
};
|
||||
|
||||
WebSnapshotDeserializer(Isolate* isolate, Handle<Object> script_name,
|
||||
base::Vector<const uint8_t> buffer);
|
||||
base::Vector<const uint8_t> ExtractScriptBuffer(
|
||||
@ -350,12 +355,15 @@ class V8_EXPORT WebSnapshotDeserializer
|
||||
|
||||
Object ReadValue(
|
||||
Handle<HeapObject> object_for_deferred_reference = Handle<HeapObject>(),
|
||||
uint32_t index_for_deferred_reference = 0);
|
||||
uint32_t index_for_deferred_reference = 0,
|
||||
InternalizeStrings internalize_strings = InternalizeStrings::kNo);
|
||||
|
||||
Object ReadInteger();
|
||||
Object ReadNumber();
|
||||
String ReadString(bool internalize = false);
|
||||
String ReadInPlaceString(bool internalize = false);
|
||||
String ReadString(
|
||||
InternalizeStrings internalize_strings = InternalizeStrings::kNo);
|
||||
String ReadInPlaceString(
|
||||
InternalizeStrings internalize_strings = InternalizeStrings::kNo);
|
||||
Object ReadSymbol();
|
||||
Object ReadArray(Handle<HeapObject> container, uint32_t container_index);
|
||||
Object ReadObject(Handle<HeapObject> container, uint32_t container_index);
|
||||
|
@ -16,8 +16,9 @@ namespace {
|
||||
void TestWebSnapshotExtensive(
|
||||
const char* snapshot_source, const char* test_source,
|
||||
std::function<void(v8::Isolate*, v8::Local<v8::Context>)> tester,
|
||||
uint32_t string_count, uint32_t map_count, uint32_t context_count,
|
||||
uint32_t function_count, uint32_t object_count, uint32_t array_count) {
|
||||
uint32_t string_count, uint32_t symbol_count, uint32_t map_count,
|
||||
uint32_t context_count, uint32_t function_count, uint32_t object_count,
|
||||
uint32_t array_count) {
|
||||
CcTest::InitializeVM();
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
|
||||
@ -37,6 +38,7 @@ void TestWebSnapshotExtensive(
|
||||
CHECK(!serializer.has_error());
|
||||
CHECK_NOT_NULL(snapshot_data.buffer);
|
||||
CHECK_EQ(string_count, serializer.string_count());
|
||||
CHECK_EQ(symbol_count, serializer.symbol_count());
|
||||
CHECK_EQ(map_count, serializer.map_count());
|
||||
CHECK_EQ(context_count, serializer.context_count());
|
||||
CHECK_EQ(function_count, serializer.function_count());
|
||||
@ -54,18 +56,20 @@ void TestWebSnapshotExtensive(
|
||||
CHECK(!deserializer.has_error());
|
||||
tester(isolate, new_context);
|
||||
CHECK_EQ(string_count, deserializer.string_count());
|
||||
CHECK_EQ(symbol_count, deserializer.symbol_count());
|
||||
CHECK_EQ(map_count, deserializer.map_count());
|
||||
CHECK_EQ(context_count, deserializer.context_count());
|
||||
CHECK_EQ(function_count, deserializer.function_count());
|
||||
CHECK_EQ(object_count, deserializer.object_count());
|
||||
CHECK_EQ(array_count, deserializer.array_count());
|
||||
}
|
||||
}
|
||||
|
||||
void TestWebSnapshot(const char* snapshot_source, const char* test_source,
|
||||
const char* expected_result, uint32_t string_count,
|
||||
uint32_t map_count, uint32_t context_count,
|
||||
uint32_t function_count, uint32_t object_count,
|
||||
uint32_t array_count) {
|
||||
uint32_t symbol_count, uint32_t map_count,
|
||||
uint32_t context_count, uint32_t function_count,
|
||||
uint32_t object_count, uint32_t array_count) {
|
||||
TestWebSnapshotExtensive(
|
||||
snapshot_source, test_source,
|
||||
[test_source, expected_result](v8::Isolate* isolate,
|
||||
@ -73,8 +77,8 @@ void TestWebSnapshot(const char* snapshot_source, const char* test_source,
|
||||
v8::Local<v8::String> result = CompileRun(test_source).As<v8::String>();
|
||||
CHECK(result->Equals(new_context, v8_str(expected_result)).FromJust());
|
||||
},
|
||||
string_count, map_count, context_count, function_count, object_count,
|
||||
array_count);
|
||||
string_count, symbol_count, map_count, context_count, function_count,
|
||||
object_count, array_count);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -83,21 +87,23 @@ TEST(Minimal) {
|
||||
const char* snapshot_source = "var foo = {'key': 'lol'};";
|
||||
const char* test_source = "foo.key";
|
||||
const char* expected_result = "lol";
|
||||
uint32_t kStringCount = 2; // 'foo', 'key'
|
||||
uint32_t kStringCount = 1; // 'foo'; 'key' is in-place.
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 1;
|
||||
uint32_t kContextCount = 0;
|
||||
uint32_t kFunctionCount = 0;
|
||||
uint32_t kObjectCount = 1;
|
||||
uint32_t kArrayCount = 0;
|
||||
TestWebSnapshot(snapshot_source, test_source, expected_result, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount, kObjectCount,
|
||||
kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
TEST(EmptyObject) {
|
||||
const char* snapshot_source = "var foo = {}";
|
||||
const char* test_source = "foo";
|
||||
uint32_t kStringCount = 1; // 'foo'
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 1;
|
||||
uint32_t kContextCount = 0;
|
||||
uint32_t kFunctionCount = 0;
|
||||
@ -112,8 +118,8 @@ TEST(EmptyObject) {
|
||||
i_isolate->native_context()->object_function().initial_map());
|
||||
};
|
||||
TestWebSnapshotExtensive(snapshot_source, test_source, tester, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount,
|
||||
kFunctionCount, kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
TEST(Numbers) {
|
||||
@ -126,7 +132,8 @@ TEST(Numbers) {
|
||||
" 'f': Number.NEGATIVE_INFINITY,\n"
|
||||
"}";
|
||||
const char* test_source = "foo";
|
||||
uint32_t kStringCount = 7; // 'foo', 'a', ..., 'f'
|
||||
uint32_t kStringCount = 1; // 'foo'; 'a'...'f' are in-place.
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 1;
|
||||
uint32_t kContextCount = 0;
|
||||
uint32_t kFunctionCount = 0;
|
||||
@ -168,8 +175,8 @@ TEST(Numbers) {
|
||||
CHECK_EQ(f, -std::numeric_limits<double>::infinity());
|
||||
};
|
||||
TestWebSnapshotExtensive(snapshot_source, test_source, tester, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount,
|
||||
kFunctionCount, kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
TEST(Oddballs) {
|
||||
@ -180,7 +187,8 @@ TEST(Oddballs) {
|
||||
" 'd': undefined,\n"
|
||||
"}";
|
||||
const char* test_source = "foo";
|
||||
uint32_t kStringCount = 5; // 'foo', 'a', ..., 'd'
|
||||
uint32_t kStringCount = 1; // 'foo'; 'a'...'d' are in-place.
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 1;
|
||||
uint32_t kContextCount = 0;
|
||||
uint32_t kFunctionCount = 0;
|
||||
@ -199,8 +207,8 @@ TEST(Oddballs) {
|
||||
CHECK(d->IsUndefined());
|
||||
};
|
||||
TestWebSnapshotExtensive(snapshot_source, test_source, tester, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount,
|
||||
kFunctionCount, kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
TEST(Function) {
|
||||
@ -208,15 +216,16 @@ TEST(Function) {
|
||||
"var foo = {'key': function() { return '11525'; }};";
|
||||
const char* test_source = "foo.key()";
|
||||
const char* expected_result = "11525";
|
||||
uint32_t kStringCount = 3; // 'foo', 'key', function source code
|
||||
uint32_t kStringCount = 2; // 'foo', function source code. 'key' is in-place.
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 1;
|
||||
uint32_t kContextCount = 0;
|
||||
uint32_t kFunctionCount = 1;
|
||||
uint32_t kObjectCount = 1;
|
||||
uint32_t kArrayCount = 0;
|
||||
TestWebSnapshot(snapshot_source, test_source, expected_result, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount, kObjectCount,
|
||||
kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
TEST(InnerFunctionWithContext) {
|
||||
@ -228,16 +237,17 @@ TEST(InnerFunctionWithContext) {
|
||||
" })()};";
|
||||
const char* test_source = "foo.key()";
|
||||
const char* expected_result = "11525";
|
||||
// Strings: 'foo', 'key', function source code (inner), 'result'
|
||||
uint32_t kStringCount = 4;
|
||||
// Strings: 'foo', 'result', function source code (inner). 'key' is in-place.
|
||||
uint32_t kStringCount = 3;
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 1;
|
||||
uint32_t kContextCount = 1;
|
||||
uint32_t kFunctionCount = 1;
|
||||
uint32_t kObjectCount = 1;
|
||||
uint32_t kArrayCount = 0;
|
||||
TestWebSnapshot(snapshot_source, test_source, expected_result, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount, kObjectCount,
|
||||
kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
TEST(InnerFunctionWithContextAndParentContext) {
|
||||
@ -255,22 +265,24 @@ TEST(InnerFunctionWithContextAndParentContext) {
|
||||
" })()};";
|
||||
const char* test_source = "foo.key()";
|
||||
const char* expected_result = "11525";
|
||||
// Strings: 'foo', 'key', function source code (innerinner), 'part1', 'part2'.
|
||||
uint32_t kStringCount = 5;
|
||||
// Strings: 'foo', function source code (innerinner), 'part1', 'part2'.
|
||||
uint32_t kStringCount = 4;
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 1;
|
||||
uint32_t kContextCount = 2;
|
||||
uint32_t kFunctionCount = 1;
|
||||
uint32_t kObjectCount = 1;
|
||||
uint32_t kArrayCount = 0;
|
||||
TestWebSnapshot(snapshot_source, test_source, expected_result, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount, kObjectCount,
|
||||
kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
TEST(RegExp) {
|
||||
const char* snapshot_source = "var foo = {'re': /ab+c/gi}";
|
||||
const char* test_source = "foo";
|
||||
uint32_t kStringCount = 4; // 'foo', 're', RegExp pattern, RegExp flags
|
||||
uint32_t kStringCount = 3; // 'foo', RegExp pattern, RegExp flags
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 1;
|
||||
uint32_t kContextCount = 0;
|
||||
uint32_t kFunctionCount = 0;
|
||||
@ -293,14 +305,15 @@ TEST(RegExp) {
|
||||
CHECK(no_match->IsNull());
|
||||
};
|
||||
TestWebSnapshotExtensive(snapshot_source, test_source, tester, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount,
|
||||
kFunctionCount, kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
TEST(RegExpNoFlags) {
|
||||
const char* snapshot_source = "var foo = {'re': /ab+c/}";
|
||||
const char* test_source = "foo";
|
||||
uint32_t kStringCount = 4; // 'foo', 're', RegExp pattern, RegExp flags
|
||||
uint32_t kStringCount = 3; // 'foo', RegExp pattern, RegExp flags
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 1;
|
||||
uint32_t kContextCount = 0;
|
||||
uint32_t kFunctionCount = 0;
|
||||
@ -323,8 +336,8 @@ TEST(RegExpNoFlags) {
|
||||
CHECK(no_match->IsNull());
|
||||
};
|
||||
TestWebSnapshotExtensive(snapshot_source, test_source, tester, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount,
|
||||
kFunctionCount, kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
TEST(SFIDeduplication) {
|
||||
@ -689,7 +702,8 @@ TEST(FunctionKinds) {
|
||||
" f: async function*() {}\n"
|
||||
"}";
|
||||
const char* test_source = "foo";
|
||||
uint32_t kStringCount = 8; // 'foo', 'a', ..., 'f', source code
|
||||
uint32_t kStringCount = 2; // 'foo', source code. 'a'...'f' in-place.
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 1;
|
||||
uint32_t kContextCount = 0;
|
||||
uint32_t kFunctionCount = 6;
|
||||
@ -713,8 +727,8 @@ TEST(FunctionKinds) {
|
||||
FunctionKind::kAsyncGeneratorFunction);
|
||||
};
|
||||
TestWebSnapshotExtensive(snapshot_source, test_source, tester, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount,
|
||||
kFunctionCount, kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
// Test that concatenating JS code to the snapshot works.
|
||||
@ -865,14 +879,15 @@ TEST(InPlaceStringsInArrays) {
|
||||
const char* test_source = "foo.join('');";
|
||||
const char* expected_result = "onetwothree";
|
||||
uint32_t kStringCount = 1; // 'foo'; Other strings are in-place.
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 0;
|
||||
uint32_t kContextCount = 0;
|
||||
uint32_t kFunctionCount = 0;
|
||||
uint32_t kObjectCount = 0;
|
||||
uint32_t kArrayCount = 1;
|
||||
TestWebSnapshot(snapshot_source, test_source, expected_result, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount, kObjectCount,
|
||||
kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
TEST(RepeatedInPlaceStringsInArrays) {
|
||||
@ -880,46 +895,49 @@ TEST(RepeatedInPlaceStringsInArrays) {
|
||||
const char* test_source = "foo.join('');";
|
||||
const char* expected_result = "onetwoone";
|
||||
uint32_t kStringCount = 2; // 'foo', 'one'; Other strings are in-place.
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 0;
|
||||
uint32_t kContextCount = 0;
|
||||
uint32_t kFunctionCount = 0;
|
||||
uint32_t kObjectCount = 0;
|
||||
uint32_t kArrayCount = 1;
|
||||
TestWebSnapshot(snapshot_source, test_source, expected_result, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount, kObjectCount,
|
||||
kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
TEST(InPlaceStringsInObjects) {
|
||||
const char* snapshot_source = "var foo = {a: 'one', b: 'two', c: 'three'};";
|
||||
const char* test_source = "foo.a + foo.b + foo.c;";
|
||||
const char* expected_result = "onetwothree";
|
||||
// 'foo', 'a', 'b', 'c'. Other strings are in-place.
|
||||
uint32_t kStringCount = 4;
|
||||
// 'foo'. Other strings are in-place.
|
||||
uint32_t kStringCount = 1;
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 1;
|
||||
uint32_t kContextCount = 0;
|
||||
uint32_t kFunctionCount = 0;
|
||||
uint32_t kObjectCount = 1;
|
||||
uint32_t kArrayCount = 0;
|
||||
TestWebSnapshot(snapshot_source, test_source, expected_result, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount, kObjectCount,
|
||||
kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
TEST(RepeatedInPlaceStringsInObjects) {
|
||||
const char* snapshot_source = "var foo = {a: 'one', b: 'two', c: 'one'};";
|
||||
const char* test_source = "foo.a + foo.b + foo.c;";
|
||||
const char* expected_result = "onetwoone";
|
||||
// 'foo', 'a', 'b', 'c', 'one'. Other strings are in-place.
|
||||
uint32_t kStringCount = 5;
|
||||
// 'foo', 'one'. Other strings are in-place.
|
||||
uint32_t kStringCount = 2;
|
||||
uint32_t kSymbolCount = 0;
|
||||
uint32_t kMapCount = 1;
|
||||
uint32_t kContextCount = 0;
|
||||
uint32_t kFunctionCount = 0;
|
||||
uint32_t kObjectCount = 1;
|
||||
uint32_t kArrayCount = 0;
|
||||
TestWebSnapshot(snapshot_source, test_source, expected_result, kStringCount,
|
||||
kMapCount, kContextCount, kFunctionCount, kObjectCount,
|
||||
kArrayCount);
|
||||
kSymbolCount, kMapCount, kContextCount, kFunctionCount,
|
||||
kObjectCount, kArrayCount);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -358,3 +358,18 @@ d8.file.execute('test/mjsunit/web-snapshot/web-snapshot-helpers.js');
|
||||
assertEquals('this is global', foo.mySymbol.description);
|
||||
assertEquals(Symbol.for('this is global'), foo.mySymbol);
|
||||
})();
|
||||
|
||||
(function TestSymbolAsMapKey() {
|
||||
function createObjects() {
|
||||
globalThis.obj1 = {};
|
||||
const global_symbol = Symbol.for('this is global');
|
||||
obj1[global_symbol] = 'global symbol value';
|
||||
globalThis.obj2 = {};
|
||||
const nonglobal_symbol = Symbol('this is not global');
|
||||
obj2[nonglobal_symbol] = 'nonglobal symbol value';
|
||||
}
|
||||
const {obj1, obj2} = takeAndUseWebSnapshot(createObjects, ['obj1', 'obj2']);
|
||||
assertEquals('global symbol value', obj1[Symbol.for('this is global')]);
|
||||
const nonglobal_symbol = Object.getOwnPropertySymbols(obj2)[0];
|
||||
assertEquals('nonglobal symbol value', obj2[nonglobal_symbol]);
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user