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

Unified Diff: src/value-serializer.cc

Issue 2302023002: DO NOT SUBMIT: switch to an on-heap stack for nested object serialization/deserialization
Patch Set: Created 4 years, 3 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') | no next file » | 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 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);
}
« no previous file with comments | « src/value-serializer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698