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); |
} |