| 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++) {
|
|
|