| Index: src/value-serializer.cc
|
| diff --git a/src/value-serializer.cc b/src/value-serializer.cc
|
| index 8416ea3cd61dea9ad11ba148f83339153b4e4f4a..50457870a5bf09e6572953fb5bcae47ee126a979 100644
|
| --- a/src/value-serializer.cc
|
| +++ b/src/value-serializer.cc
|
| @@ -124,11 +124,29 @@ enum class ArrayBufferViewTag : uint8_t {
|
|
|
| } // namespace
|
|
|
| +struct ValueSerializer::State {
|
| + enum Kind {
|
| + kJSObjectPropertiesSlow,
|
| + kDenseArrayElementsSlow,
|
| + kDenseArrayPropertiesSlow,
|
| + kSparseArrayPropertiesSlow,
|
| + kJSMap,
|
| + kJSSet,
|
| + };
|
| + Kind kind;
|
| + uint32_t index;
|
| + uint32_t array_length;
|
| + uint32_t properties_written;
|
| + Handle<JSObject> receiver;
|
| + Handle<FixedArray> data;
|
| +};
|
| +
|
| ValueSerializer::ValueSerializer(Isolate* isolate)
|
| : isolate_(isolate),
|
| zone_(isolate->allocator()),
|
| id_map_(isolate->heap(), &zone_),
|
| - array_buffer_transfer_map_(isolate->heap(), &zone_) {}
|
| + array_buffer_transfer_map_(isolate->heap(), &zone_),
|
| + states_(&zone_) {}
|
|
|
| ValueSerializer::~ValueSerializer() {}
|
|
|
| @@ -209,7 +227,100 @@ void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id,
|
| array_buffer_transfer_map_.Set(array_buffer, transfer_id);
|
| }
|
|
|
| -Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
|
| +Maybe<bool> ValueSerializer::WriteObject(Handle<Object> outer_object) {
|
| + size_t stack_size = states_.size();
|
| + if (!WriteObjectInternal(outer_object).FromMaybe(false)) {
|
| + return Nothing<bool>();
|
| + }
|
| + while (states_.size() > stack_size) {
|
| + // Warning: it is illegal to access |state| after invoking
|
| + // WriteObjectInternal, because the vector may have reallocated.
|
| + size_t state_index = states_.size() - 1;
|
| + State& state = states_[state_index];
|
| +
|
| + switch (state.kind) {
|
| + case State::kJSObjectPropertiesSlow:
|
| + case State::kDenseArrayPropertiesSlow:
|
| + case State::kSparseArrayPropertiesSlow: {
|
| + Handle<FixedArray> keys = state.data;
|
| + if (state.index >= keys->length()) {
|
| + DCHECK_EQ(state.index, keys->length());
|
| + if (state.kind == State::kJSObjectPropertiesSlow) {
|
| + WriteTag(SerializationTag::kEndJSObject);
|
| + WriteVarint<uint32_t>(state.properties_written);
|
| + } else if (state.kind == State::kDenseArrayPropertiesSlow) {
|
| + WriteTag(SerializationTag::kEndDenseJSArray);
|
| + WriteVarint<uint32_t>(state.properties_written);
|
| + WriteVarint<uint32_t>(state.array_length);
|
| + } else if (state.kind == State::kSparseArrayPropertiesSlow) {
|
| + WriteTag(SerializationTag::kEndSparseJSArray);
|
| + WriteVarint<uint32_t>(state.properties_written);
|
| + WriteVarint<uint32_t>(state.array_length);
|
| + }
|
| + states_.pop_back();
|
| + continue;
|
| + }
|
| +
|
| + Handle<Object> key(keys->get(state.index++), isolate_);
|
| + bool success;
|
| + LookupIterator it = LookupIterator::PropertyOrElement(
|
| + isolate_, state.receiver, key, &success, LookupIterator::OWN);
|
| + DCHECK(success);
|
| + Handle<Object> value;
|
| + if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<bool>();
|
| +
|
| + // If the property is no longer found, do not serialize it.
|
| + // This could happen if a getter deleted the property.
|
| + if (!it.IsFound()) continue;
|
| +
|
| + if (!WriteObjectInternal(key).FromMaybe(false)) return Nothing<bool>();
|
| + DCHECK_EQ(states_.size(), state_index + 1);
|
| + if (!WriteObjectInternal(value).FromMaybe(false)) {
|
| + return Nothing<bool>();
|
| + }
|
| + states_[state_index].properties_written++;
|
| + break;
|
| + }
|
| + case State::kDenseArrayElementsSlow: {
|
| + if (state.index >= state.array_length) {
|
| + DCHECK_EQ(state.index, state.array_length);
|
| + state.kind = State::kDenseArrayPropertiesSlow;
|
| + state.index = 0;
|
| + continue;
|
| + }
|
| + LookupIterator it(isolate_, state.receiver, state.index++,
|
| + state.receiver, LookupIterator::OWN);
|
| + Handle<Object> element;
|
| + if (!Object::GetProperty(&it).ToHandle(&element) ||
|
| + !WriteObjectInternal(element).FromMaybe(false)) {
|
| + return Nothing<bool>();
|
| + }
|
| + break;
|
| + }
|
| + case State::kJSMap:
|
| + case State::kJSSet: {
|
| + Handle<FixedArray> collection = state.data;
|
| + if (state.index >= collection->length()) {
|
| + DCHECK_EQ(state.index, collection->length());
|
| + WriteTag(state.kind == State::kJSMap ? SerializationTag::kEndJSMap
|
| + : SerializationTag::kEndJSSet);
|
| + WriteVarint<uint32_t>(collection->length());
|
| + states_.pop_back();
|
| + continue;
|
| + }
|
| + Handle<Object> value(collection->get(state.index++), isolate_);
|
| + if (!WriteObjectInternal(value).FromMaybe(false)) {
|
| + return Nothing<bool>();
|
| + }
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + DCHECK_EQ(states_.size(), stack_size);
|
| + return Just(true);
|
| +}
|
| +
|
| +Maybe<bool> ValueSerializer::WriteObjectInternal(Handle<Object> object) {
|
| if (object->IsSmi()) {
|
| WriteSmi(Smi::cast(*object));
|
| return Just(true);
|
| @@ -343,7 +454,6 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
|
| // If we are at the end of the stack, abort. This function may recurse.
|
| if (StackLimitCheck(isolate_).HasOverflowed()) return Nothing<bool>();
|
|
|
| - HandleScope scope(isolate_);
|
| switch (instance_type) {
|
| case JS_ARRAY_TYPE:
|
| return WriteJSArray(Handle<JSArray>::cast(receiver));
|
| @@ -377,15 +487,12 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
|
| Maybe<bool> ValueSerializer::WriteJSObject(Handle<JSObject> object) {
|
| WriteTag(SerializationTag::kBeginJSObject);
|
| Handle<FixedArray> keys;
|
| - uint32_t properties_written;
|
| if (!KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
|
| ENUMERABLE_STRINGS)
|
| - .ToHandle(&keys) ||
|
| - !WriteJSObjectProperties(object, keys).To(&properties_written)) {
|
| + .ToHandle(&keys)) {
|
| return Nothing<bool>();
|
| }
|
| - WriteTag(SerializationTag::kEndJSObject);
|
| - WriteVarint<uint32_t>(properties_written);
|
| + states_.push_back({State::kJSObjectPropertiesSlow, 0, 0, 0, object, keys});
|
| return Just(true);
|
| }
|
|
|
| @@ -409,17 +516,6 @@ Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) {
|
| // format changes.
|
| WriteTag(SerializationTag::kBeginDenseJSArray);
|
| WriteVarint<uint32_t>(length);
|
| - for (uint32_t i = 0; i < length; i++) {
|
| - // Serializing the array's elements can have arbitrary side effects, so we
|
| - // cannot rely on still having fast elements, even if it did to begin
|
| - // with.
|
| - Handle<Object> element;
|
| - LookupIterator it(isolate_, array, i, array, LookupIterator::OWN);
|
| - if (!Object::GetProperty(&it).ToHandle(&element) ||
|
| - !WriteObject(element).FromMaybe(false)) {
|
| - return Nothing<bool>();
|
| - }
|
| - }
|
| KeyAccumulator accumulator(isolate_, KeyCollectionMode::kOwnOnly,
|
| ENUMERABLE_STRINGS);
|
| if (!accumulator.CollectOwnPropertyNames(array, array).FromMaybe(false)) {
|
| @@ -427,13 +523,8 @@ Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) {
|
| }
|
| Handle<FixedArray> keys =
|
| accumulator.GetKeys(GetKeysConversion::kConvertToString);
|
| - uint32_t properties_written;
|
| - if (!WriteJSObjectProperties(array, keys).To(&properties_written)) {
|
| - return Nothing<bool>();
|
| - }
|
| - WriteTag(SerializationTag::kEndDenseJSArray);
|
| - WriteVarint<uint32_t>(properties_written);
|
| - WriteVarint<uint32_t>(length);
|
| + states_.push_back(
|
| + {State::kDenseArrayElementsSlow, 0, length, 0, array, keys});
|
| } else {
|
| WriteTag(SerializationTag::kBeginSparseJSArray);
|
| WriteVarint<uint32_t>(length);
|
| @@ -441,13 +532,11 @@ Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) {
|
| uint32_t properties_written;
|
| if (!KeyAccumulator::GetKeys(array, KeyCollectionMode::kOwnOnly,
|
| ENUMERABLE_STRINGS)
|
| - .ToHandle(&keys) ||
|
| - !WriteJSObjectProperties(array, keys).To(&properties_written)) {
|
| + .ToHandle(&keys)) {
|
| return Nothing<bool>();
|
| }
|
| - WriteTag(SerializationTag::kEndSparseJSArray);
|
| - WriteVarint<uint32_t>(properties_written);
|
| - WriteVarint<uint32_t>(length);
|
| + states_.push_back(
|
| + {State::kSparseArrayPropertiesSlow, 0, length, 0, array, keys});
|
| }
|
| return Just(true);
|
| }
|
| @@ -513,16 +602,8 @@ Maybe<bool> ValueSerializer::WriteJSMap(Handle<JSMap> map) {
|
| }
|
| 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);
|
| + states_.push_back({State::kJSMap, 0, 0, 0, map, entries});
|
| return Just(true);
|
| }
|
|
|
| @@ -543,16 +624,8 @@ Maybe<bool> ValueSerializer::WriteJSSet(Handle<JSSet> set) {
|
| }
|
| 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);
|
| + states_.push_back({State::kJSSet, 0, 0, 0, set, entries});
|
| return Just(true);
|
| }
|
|
|
| @@ -601,33 +674,24 @@ Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView* view) {
|
| return Just(true);
|
| }
|
|
|
| -Maybe<uint32_t> ValueSerializer::WriteJSObjectProperties(
|
| - Handle<JSObject> object, Handle<FixedArray> keys) {
|
| - uint32_t properties_written = 0;
|
| - int length = keys->length();
|
| - for (int i = 0; i < length; i++) {
|
| - Handle<Object> key(keys->get(i), isolate_);
|
| -
|
| - bool success;
|
| - LookupIterator it = LookupIterator::PropertyOrElement(
|
| - isolate_, object, key, &success, LookupIterator::OWN);
|
| - DCHECK(success);
|
| - Handle<Object> value;
|
| - if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<uint32_t>();
|
| -
|
| - // If the property is no longer found, do not serialize it.
|
| - // This could happen if a getter deleted the property.
|
| - if (!it.IsFound()) continue;
|
| -
|
| - if (!WriteObject(key).FromMaybe(false) ||
|
| - !WriteObject(value).FromMaybe(false)) {
|
| - return Nothing<uint32_t>();
|
| - }
|
| -
|
| - properties_written++;
|
| - }
|
| - return Just(properties_written);
|
| -}
|
| +struct ValueDeserializer::State {
|
| + enum Kind {
|
| + kJSObjectProperties,
|
| + kDenseArrayElements,
|
| + kDenseArrayProperties,
|
| + kSparseArrayProperties,
|
| + kJSMapKey,
|
| + kJSMapValue,
|
| + kJSSet,
|
| + };
|
| + Kind kind;
|
| + uint32_t index;
|
| + uint32_t array_length;
|
| + uint32_t num_properties;
|
| + Handle<JSObject> receiver;
|
| + Handle<Object> elements_or_function;
|
| + Handle<Object> map_key;
|
| +};
|
|
|
| ValueDeserializer::ValueDeserializer(Isolate* isolate,
|
| Vector<const uint8_t> data)
|
| @@ -761,29 +825,158 @@ void ValueDeserializer::TransferArrayBuffer(
|
| }
|
|
|
| MaybeHandle<Object> ValueDeserializer::ReadObject() {
|
| - MaybeHandle<Object> result = ReadObjectInternal();
|
| + size_t stack_size = states_.size();
|
| + Handle<Object> result;
|
| + if (!ReadObjectInternal().ToHandle(&result)) return MaybeHandle<Object>();
|
| +
|
| + while (states_.size() > stack_size) {
|
| + size_t state_index = states_.size() - 1;
|
| + State& state = states_[state_index];
|
| + switch (state.kind) {
|
| + case State::kJSObjectProperties:
|
| + case State::kDenseArrayProperties:
|
| + case State::kSparseArrayProperties: {
|
| + SerializationTag tag;
|
| + if (!PeekTag().To(&tag)) return MaybeHandle<Object>();
|
| + const SerializationTag expected_tag =
|
| + state.kind == State::kDenseArrayProperties
|
| + ? SerializationTag::kEndDenseJSArray
|
| + : state.kind == State::kSparseArrayProperties
|
| + ? SerializationTag::kEndSparseJSArray
|
| + : SerializationTag::kEndJSObject;
|
| + if (tag == expected_tag) {
|
| + ConsumeTag(expected_tag);
|
| + uint32_t expected_num_properties;
|
| + if (!ReadVarint<uint32_t>().To(&expected_num_properties) ||
|
| + state.num_properties != expected_num_properties) {
|
| + return MaybeHandle<Object>();
|
| + }
|
| + if (tag != SerializationTag::kEndJSObject) {
|
| + uint32_t expected_length;
|
| + if (!ReadVarint<uint32_t>().To(&expected_length) ||
|
| + state.array_length != expected_length) {
|
| + return MaybeHandle<Object>();
|
| + }
|
| + }
|
| + states_.pop_back();
|
| + continue;
|
| + }
|
| + state.num_properties++;
|
| + Handle<Object> receiver = state.receiver;
|
| + Handle<Object> key;
|
| + Handle<Object> value;
|
| + if (!ReadObjectInternal().ToHandle(&key)) return MaybeHandle<Object>();
|
| + DCHECK_EQ(states_.size(), state_index + 1);
|
| + if (!ReadObjectInternal().ToHandle(&value)) {
|
| + return MaybeHandle<Object>();
|
| + }
|
|
|
| - // ArrayBufferView is special in that it consumes the value before it, even
|
| - // after format version 0.
|
| - Handle<Object> object;
|
| - SerializationTag tag;
|
| - if (result.ToHandle(&object) && V8_UNLIKELY(object->IsJSArrayBuffer()) &&
|
| - PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) {
|
| - ConsumeTag(SerializationTag::kArrayBufferView);
|
| - result = ReadJSArrayBufferView(Handle<JSArrayBuffer>::cast(object));
|
| + bool success;
|
| + LookupIterator it = LookupIterator::PropertyOrElement(
|
| + isolate_, receiver, key, &success, LookupIterator::OWN);
|
| + if (!success ||
|
| + JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
|
| + .is_null()) {
|
| + return MaybeHandle<Object>();
|
| + }
|
| + break;
|
| + }
|
| + case State::kDenseArrayElements: {
|
| + if (state.index >= state.array_length) {
|
| + DCHECK_EQ(state.index, state.array_length);
|
| + state.kind = State::kDenseArrayProperties;
|
| + state.index = 0;
|
| + continue;
|
| + }
|
| + Handle<FixedArray> elements =
|
| + Handle<FixedArray>::cast(state.elements_or_function);
|
| + uint32_t index = state.index++;
|
| + Handle<Object> element;
|
| + if (!ReadObjectInternal().ToHandle(&element)) {
|
| + return MaybeHandle<Object>();
|
| + }
|
| + // TODO(jbroman): Distinguish between undefined and a hole.
|
| + if (element->IsUndefined(isolate_)) continue;
|
| + elements->set(index, *element);
|
| + break;
|
| + }
|
| + case State::kJSMapKey: {
|
| + SerializationTag tag;
|
| + if (!PeekTag().To(&tag)) return MaybeHandle<Object>();
|
| + if (tag == SerializationTag::kEndJSMap) {
|
| + ConsumeTag(SerializationTag::kEndJSMap);
|
| + uint32_t expected_length;
|
| + if (!ReadVarint<uint32_t>().To(&expected_length) ||
|
| + state.index != expected_length) {
|
| + return MaybeHandle<Object>();
|
| + }
|
| + states_.pop_back();
|
| + continue;
|
| + }
|
| + state.index++;
|
| + Handle<Object> key;
|
| + if (!ReadObjectInternal().ToHandle(&key)) return MaybeHandle<Object>();
|
| + State& new_state = states_[state_index];
|
| + new_state.kind = State::kJSMapValue;
|
| + new_state.map_key = key;
|
| + break;
|
| + }
|
| + case State::kJSMapValue: {
|
| + state.index++;
|
| + Handle<JSFunction> map_set =
|
| + Handle<JSFunction>::cast(state.elements_or_function);
|
| + Handle<JSMap> map = Handle<JSMap>::cast(state.receiver);
|
| + Handle<Object> argv[2] = {state.map_key, Handle<Object>()};
|
| + state.kind = State::kJSMapKey;
|
| + state.map_key = Handle<Object>();
|
| + if (!ReadObjectInternal().ToHandle(&argv[1]) ||
|
| + Execution::Call(isolate_, map_set, map, arraysize(argv), argv)
|
| + .is_null()) {
|
| + return MaybeHandle<Object>();
|
| + }
|
| + break;
|
| + }
|
| + case State::kJSSet: {
|
| + SerializationTag tag;
|
| + if (!PeekTag().To(&tag)) return MaybeHandle<Object>();
|
| + if (tag == SerializationTag::kEndJSSet) {
|
| + ConsumeTag(SerializationTag::kEndJSSet);
|
| + uint32_t expected_length;
|
| + if (!ReadVarint<uint32_t>().To(&expected_length) ||
|
| + state.index != expected_length) {
|
| + return MaybeHandle<Object>();
|
| + }
|
| + states_.pop_back();
|
| + continue;
|
| + }
|
| + state.index++;
|
| + Handle<JSFunction> set_add =
|
| + Handle<JSFunction>::cast(state.elements_or_function);
|
| + Handle<JSSet> set = Handle<JSSet>::cast(state.receiver);
|
| + Handle<Object> argv[1];
|
| + if (!ReadObjectInternal().ToHandle(&argv[0]) ||
|
| + Execution::Call(isolate_, set_add, set, arraysize(argv), argv)
|
| + .is_null()) {
|
| + return MaybeHandle<Object>();
|
| + }
|
| + break;
|
| + }
|
| + }
|
| }
|
| -
|
| + DCHECK_EQ(states_.size(), stack_size);
|
| return result;
|
| }
|
|
|
| MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() {
|
| + MaybeHandle<Object> result;
|
| SerializationTag tag;
|
| if (!ReadTag().To(&tag)) return MaybeHandle<Object>();
|
| switch (tag) {
|
| case SerializationTag::kVerifyObjectCount:
|
| // Read the count and ignore it.
|
| if (ReadVarint<uint32_t>().IsNothing()) return MaybeHandle<Object>();
|
| - return ReadObject();
|
| + result = ReadObject();
|
| + break;
|
| case SerializationTag::kUndefined:
|
| return isolate_->factory()->undefined_value();
|
| case SerializationTag::kNull:
|
| @@ -814,7 +1007,8 @@ MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() {
|
| case SerializationTag::kObjectReference: {
|
| uint32_t id;
|
| if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>();
|
| - return GetObjectWithID(id);
|
| + result = GetObjectWithID(id);
|
| + break;
|
| }
|
| case SerializationTag::kBeginJSObject:
|
| return ReadJSObject();
|
| @@ -836,18 +1030,32 @@ MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() {
|
| case SerializationTag::kBeginJSSet:
|
| return ReadJSSet();
|
| case SerializationTag::kArrayBuffer:
|
| - return ReadJSArrayBuffer();
|
| + result = ReadJSArrayBuffer();
|
| + break;
|
| case SerializationTag::kArrayBufferTransfer: {
|
| const bool is_shared = false;
|
| - return ReadTransferredJSArrayBuffer(is_shared);
|
| + result = ReadTransferredJSArrayBuffer(is_shared);
|
| + break;
|
| }
|
| case SerializationTag::kSharedArrayBufferTransfer: {
|
| const bool is_shared = true;
|
| - return ReadTransferredJSArrayBuffer(is_shared);
|
| + result = ReadTransferredJSArrayBuffer(is_shared);
|
| + break;
|
| }
|
| default:
|
| return MaybeHandle<Object>();
|
| }
|
| +
|
| + // ArrayBufferView is special in that it consumes the value before it, even
|
| + // after format version 0.
|
| + Handle<Object> object;
|
| + if (result.ToHandle(&object) && V8_UNLIKELY(object->IsJSArrayBuffer()) &&
|
| + PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) {
|
| + ConsumeTag(SerializationTag::kArrayBufferView);
|
| + return ReadJSArrayBufferView(Handle<JSArrayBuffer>::cast(object));
|
| + }
|
| +
|
| + return result;
|
| }
|
|
|
| MaybeHandle<String> ValueDeserializer::ReadUtf8String() {
|
| @@ -886,91 +1094,41 @@ MaybeHandle<String> ValueDeserializer::ReadTwoByteString() {
|
| }
|
|
|
| MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() {
|
| - // If we are at the end of the stack, abort. This function may recurse.
|
| - if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSObject>();
|
| -
|
| uint32_t id = next_id_++;
|
| - HandleScope scope(isolate_);
|
| Handle<JSObject> object =
|
| isolate_->factory()->NewJSObject(isolate_->object_function());
|
| AddObjectWithID(id, object);
|
| -
|
| - uint32_t num_properties;
|
| - uint32_t expected_num_properties;
|
| - if (!ReadJSObjectProperties(object, SerializationTag::kEndJSObject)
|
| - .To(&num_properties) ||
|
| - !ReadVarint<uint32_t>().To(&expected_num_properties) ||
|
| - num_properties != expected_num_properties) {
|
| - return MaybeHandle<JSObject>();
|
| - }
|
| -
|
| - DCHECK(HasObjectWithID(id));
|
| - return scope.CloseAndEscape(object);
|
| + states_.push_back({State::kJSObjectProperties, 0, 0, 0, object,
|
| + Handle<FixedArray>(), Handle<Object>()});
|
| + return object;
|
| }
|
|
|
| MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() {
|
| - // If we are at the end of the stack, abort. This function may recurse.
|
| - if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSArray>();
|
| -
|
| uint32_t length;
|
| if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>();
|
|
|
| uint32_t id = next_id_++;
|
| - HandleScope scope(isolate_);
|
| Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
|
| JSArray::SetLength(array, length);
|
| AddObjectWithID(id, array);
|
| -
|
| - uint32_t num_properties;
|
| - uint32_t expected_num_properties;
|
| - uint32_t expected_length;
|
| - if (!ReadJSObjectProperties(array, SerializationTag::kEndSparseJSArray)
|
| - .To(&num_properties) ||
|
| - !ReadVarint<uint32_t>().To(&expected_num_properties) ||
|
| - !ReadVarint<uint32_t>().To(&expected_length) ||
|
| - num_properties != expected_num_properties || length != expected_length) {
|
| - return MaybeHandle<JSArray>();
|
| - }
|
| -
|
| - DCHECK(HasObjectWithID(id));
|
| - return scope.CloseAndEscape(array);
|
| + states_.push_back({State::kSparseArrayProperties, 0, length, 0, array,
|
| + Handle<FixedArray>(), Handle<Object>()});
|
| + return array;
|
| }
|
|
|
| MaybeHandle<JSArray> ValueDeserializer::ReadDenseJSArray() {
|
| - // If we are at the end of the stack, abort. This function may recurse.
|
| - if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSArray>();
|
| -
|
| uint32_t length;
|
| if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>();
|
|
|
| uint32_t id = next_id_++;
|
| - HandleScope scope(isolate_);
|
| Handle<JSArray> array = isolate_->factory()->NewJSArray(
|
| FAST_HOLEY_ELEMENTS, length, length, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
|
| AddObjectWithID(id, array);
|
|
|
| Handle<FixedArray> elements(FixedArray::cast(array->elements()), isolate_);
|
| - for (uint32_t i = 0; i < length; i++) {
|
| - Handle<Object> element;
|
| - if (!ReadObject().ToHandle(&element)) return MaybeHandle<JSArray>();
|
| - // TODO(jbroman): Distinguish between undefined and a hole.
|
| - if (element->IsUndefined(isolate_)) continue;
|
| - elements->set(i, *element);
|
| - }
|
| -
|
| - uint32_t num_properties;
|
| - uint32_t expected_num_properties;
|
| - uint32_t expected_length;
|
| - if (!ReadJSObjectProperties(array, SerializationTag::kEndDenseJSArray)
|
| - .To(&num_properties) ||
|
| - !ReadVarint<uint32_t>().To(&expected_num_properties) ||
|
| - !ReadVarint<uint32_t>().To(&expected_length) ||
|
| - num_properties != expected_num_properties || length != expected_length) {
|
| - return MaybeHandle<JSArray>();
|
| - }
|
| -
|
| - DCHECK(HasObjectWithID(id));
|
| - return scope.CloseAndEscape(array);
|
| + states_.push_back({State::kDenseArrayElements, 0, length, 0, array, elements,
|
| + Handle<Object>()});
|
| + return array;
|
| }
|
|
|
| MaybeHandle<JSDate> ValueDeserializer::ReadJSDate() {
|
| @@ -1041,76 +1199,21 @@ MaybeHandle<JSRegExp> ValueDeserializer::ReadJSRegExp() {
|
| }
|
|
|
| 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);
|
| + states_.push_back(
|
| + {State::kJSMapKey, 0, 0, 0, map, isolate_->map_set(), Handle<Object>()});
|
| + return 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);
|
| + states_.push_back(
|
| + {State::kJSSet, 0, 0, 0, set, isolate_->set_add(), Handle<Object>()});
|
| + return set;
|
| }
|
|
|
| MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadJSArrayBuffer() {
|
| @@ -1191,32 +1294,6 @@ MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
|
| return typed_array;
|
| }
|
|
|
| -Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
|
| - Handle<JSObject> object, SerializationTag end_tag) {
|
| - for (uint32_t num_properties = 0;; num_properties++) {
|
| - SerializationTag tag;
|
| - if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
|
| - if (tag == end_tag) {
|
| - ConsumeTag(end_tag);
|
| - return Just(num_properties);
|
| - }
|
| -
|
| - Handle<Object> key;
|
| - if (!ReadObject().ToHandle(&key)) return Nothing<uint32_t>();
|
| - Handle<Object> value;
|
| - if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
|
| -
|
| - bool success;
|
| - LookupIterator it = LookupIterator::PropertyOrElement(
|
| - isolate_, object, key, &success, LookupIterator::OWN);
|
| - if (!success ||
|
| - JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
|
| - .is_null()) {
|
| - return Nothing<uint32_t>();
|
| - }
|
| - }
|
| -}
|
| -
|
| bool ValueDeserializer::HasObjectWithID(uint32_t id) {
|
| return id_map_->Has(isolate_, id);
|
| }
|
|
|