Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(412)

Unified Diff: src/value-serializer.cc

Issue 2269923004: Blink-compatible serialization of Map and Set objects. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: StackLimitCheck + HandleScope Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/value-serializer.h ('k') | test/unittests/value-serializer-unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/value-serializer.cc
diff --git a/src/value-serializer.cc b/src/value-serializer.cc
index 0af4838abf27fae8afa123c49d790e6cac45370b..066d4250a88e734abe5f77bb727d8b4afb233d07 100644
--- a/src/value-serializer.cc
+++ b/src/value-serializer.cc
@@ -82,6 +82,14 @@ enum class SerializationTag : uint8_t {
// Regular expression, UTF-8 encoding. byteLength:uint32_t, raw data,
// flags:uint32_t.
kRegExp = 'R',
+ // Beginning of a JS map.
+ kBeginJSMap = ';',
+ // End of a JS map. length:uint32_t.
+ kEndJSMap = ':',
+ // Beginning of a JS set.
+ kBeginJSSet = '\'',
+ // End of a JS set. length:uint32_t.
+ kEndJSSet = ',',
};
ValueSerializer::ValueSerializer(Isolate* isolate)
@@ -289,6 +297,10 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
case JS_REGEXP_TYPE:
WriteJSRegExp(JSRegExp::cast(*receiver));
return Just(true);
+ case JS_MAP_TYPE:
+ return WriteJSMap(Handle<JSMap>::cast(receiver));
+ case JS_SET_TYPE:
+ return WriteJSSet(Handle<JSSet>::cast(receiver));
default:
UNIMPLEMENTED();
break;
@@ -417,6 +429,67 @@ void ValueSerializer::WriteJSRegExp(JSRegExp* regexp) {
WriteVarint(static_cast<uint32_t>(regexp->GetFlags()));
}
+Maybe<bool> ValueSerializer::WriteJSMap(Handle<JSMap> map) {
+ // First copy the key-value pairs, since getters could mutate them.
+ Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
+ int length = table->NumberOfElements() * 2;
+ Handle<FixedArray> entries = isolate_->factory()->NewFixedArray(length);
+ {
+ DisallowHeapAllocation no_gc;
+ Oddball* the_hole = isolate_->heap()->the_hole_value();
+ int capacity = table->UsedCapacity();
+ int result_index = 0;
+ for (int i = 0; i < capacity; i++) {
+ Object* key = table->KeyAt(i);
+ if (key == the_hole) continue;
+ entries->set(result_index++, key);
+ entries->set(result_index++, table->ValueAt(i));
+ }
+ DCHECK_EQ(result_index, length);
+ }
+
+ // Then write it out.
+ WriteTag(SerializationTag::kBeginJSMap);
+ for (int i = 0; i < length; i++) {
+ if (!WriteObject(handle(entries->get(i), isolate_)).FromMaybe(false)) {
+ return Nothing<bool>();
+ }
+ }
+ WriteTag(SerializationTag::kEndJSMap);
+ WriteVarint<uint32_t>(length);
+ return Just(true);
+}
+
+Maybe<bool> ValueSerializer::WriteJSSet(Handle<JSSet> set) {
+ // First copy the element pointers, since getters could mutate them.
+ Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
+ int length = table->NumberOfElements();
+ Handle<FixedArray> entries = isolate_->factory()->NewFixedArray(length);
+ {
+ DisallowHeapAllocation no_gc;
+ Oddball* the_hole = isolate_->heap()->the_hole_value();
+ int capacity = table->UsedCapacity();
+ int result_index = 0;
+ for (int i = 0; i < capacity; i++) {
+ Object* key = table->KeyAt(i);
+ if (key == the_hole) continue;
+ entries->set(result_index++, key);
+ }
+ DCHECK_EQ(result_index, length);
+ }
+
+ // Then write it out.
+ WriteTag(SerializationTag::kBeginJSSet);
+ for (int i = 0; i < length; i++) {
+ if (!WriteObject(handle(entries->get(i), isolate_)).FromMaybe(false)) {
+ return Nothing<bool>();
+ }
+ }
+ WriteTag(SerializationTag::kEndJSSet);
+ WriteVarint<uint32_t>(length);
+ return Just(true);
+}
+
Maybe<uint32_t> ValueSerializer::WriteJSObjectProperties(
Handle<JSObject> object, Handle<FixedArray> keys) {
uint32_t properties_written = 0;
@@ -606,6 +679,10 @@ MaybeHandle<Object> ValueDeserializer::ReadObject() {
return ReadJSValue(tag);
case SerializationTag::kRegExp:
return ReadJSRegExp();
+ case SerializationTag::kBeginJSMap:
+ return ReadJSMap();
+ case SerializationTag::kBeginJSSet:
+ return ReadJSSet();
default:
return MaybeHandle<Object>();
}
@@ -801,6 +878,79 @@ MaybeHandle<JSRegExp> ValueDeserializer::ReadJSRegExp() {
return regexp;
}
+MaybeHandle<JSMap> ValueDeserializer::ReadJSMap() {
+ // If we are at the end of the stack, abort. This function may recurse.
+ if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSMap>();
+
+ HandleScope scope(isolate_);
+ uint32_t id = next_id_++;
+ Handle<JSMap> map = isolate_->factory()->NewJSMap();
+ AddObjectWithID(id, map);
+
+ Handle<JSFunction> map_set = isolate_->map_set();
+ uint32_t length = 0;
+ while (true) {
+ SerializationTag tag;
+ if (!PeekTag().To(&tag)) return MaybeHandle<JSMap>();
+ if (tag == SerializationTag::kEndJSMap) {
+ ConsumeTag(SerializationTag::kEndJSMap);
+ break;
+ }
+
+ Handle<Object> argv[2];
+ if (!ReadObject().ToHandle(&argv[0]) || !ReadObject().ToHandle(&argv[1]) ||
+ Execution::Call(isolate_, map_set, map, arraysize(argv), argv)
+ .is_null()) {
+ return MaybeHandle<JSMap>();
+ }
+ length += 2;
+ }
+
+ uint32_t expected_length;
+ if (!ReadVarint<uint32_t>().To(&expected_length) ||
+ length != expected_length) {
+ return MaybeHandle<JSMap>();
+ }
+ DCHECK(HasObjectWithID(id));
+ return scope.CloseAndEscape(map);
+}
+
+MaybeHandle<JSSet> ValueDeserializer::ReadJSSet() {
+ // If we are at the end of the stack, abort. This function may recurse.
+ if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSSet>();
+
+ HandleScope scope(isolate_);
+ uint32_t id = next_id_++;
+ Handle<JSSet> set = isolate_->factory()->NewJSSet();
+ AddObjectWithID(id, set);
+ Handle<JSFunction> set_add = isolate_->set_add();
+ uint32_t length = 0;
+ while (true) {
+ SerializationTag tag;
+ if (!PeekTag().To(&tag)) return MaybeHandle<JSSet>();
+ if (tag == SerializationTag::kEndJSSet) {
+ ConsumeTag(SerializationTag::kEndJSSet);
+ break;
+ }
+
+ Handle<Object> argv[1];
+ if (!ReadObject().ToHandle(&argv[0]) ||
+ Execution::Call(isolate_, set_add, set, arraysize(argv), argv)
+ .is_null()) {
+ return MaybeHandle<JSSet>();
+ }
+ length++;
+ }
+
+ uint32_t expected_length;
+ if (!ReadVarint<uint32_t>().To(&expected_length) ||
+ length != expected_length) {
+ return MaybeHandle<JSSet>();
+ }
+ DCHECK(HasObjectWithID(id));
+ return scope.CloseAndEscape(set);
+}
+
Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
Handle<JSObject> object, SerializationTag end_tag) {
for (uint32_t num_properties = 0;; num_properties++) {
« no previous file with comments | « src/value-serializer.h ('k') | test/unittests/value-serializer-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698