• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/value-serializer.h"
6 
7 #include <type_traits>
8 
9 #include "include/v8-value-serializer-version.h"
10 #include "src/api-inl.h"
11 #include "src/base/logging.h"
12 #include "src/conversions.h"
13 #include "src/flags.h"
14 #include "src/handles-inl.h"
15 #include "src/heap/factory.h"
16 #include "src/isolate.h"
17 #include "src/maybe-handles-inl.h"
18 #include "src/objects-inl.h"
19 #include "src/objects/js-array-inl.h"
20 #include "src/objects/js-collection-inl.h"
21 #include "src/objects/js-regexp-inl.h"
22 #include "src/objects/ordered-hash-table-inl.h"
23 #include "src/snapshot/code-serializer.h"
24 #include "src/transitions.h"
25 #include "src/wasm/wasm-engine.h"
26 #include "src/wasm/wasm-objects-inl.h"
27 #include "src/wasm/wasm-result.h"
28 #include "src/wasm/wasm-serialization.h"
29 
30 namespace v8 {
31 namespace internal {
32 
33 // Version 9: (imported from Blink)
34 // Version 10: one-byte (Latin-1) strings
35 // Version 11: properly separate undefined from the hole in arrays
36 // Version 12: regexp and string objects share normal string encoding
37 // Version 13: host objects have an explicit tag (rather than handling all
38 //             unknown tags)
39 //
40 // WARNING: Increasing this value is a change which cannot safely be rolled
41 // back without breaking compatibility with data stored on disk. It is
42 // strongly recommended that you do not make such changes near a release
43 // milestone branch point.
44 //
45 // Recent changes are routinely reverted in preparation for branch, and this
46 // has been the cause of at least one bug in the past.
47 static const uint32_t kLatestVersion = 13;
48 static_assert(kLatestVersion == v8::CurrentValueSerializerFormatVersion(),
49               "Exported format version must match latest version.");
50 
51 static const int kPretenureThreshold = 100 * KB;
52 
53 template <typename T>
BytesNeededForVarint(T value)54 static size_t BytesNeededForVarint(T value) {
55   static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
56                 "Only unsigned integer types can be written as varints.");
57   size_t result = 0;
58   do {
59     result++;
60     value >>= 7;
61   } while (value);
62   return result;
63 }
64 
65 // Note that some additional tag values are defined in Blink's
66 // Source/bindings/core/v8/serialization/SerializationTag.h, which must
67 // not clash with values defined here.
68 enum class SerializationTag : uint8_t {
69   // version:uint32_t (if at beginning of data, sets version > 0)
70   kVersion = 0xFF,
71   // ignore
72   kPadding = '\0',
73   // refTableSize:uint32_t (previously used for sanity checks; safe to ignore)
74   kVerifyObjectCount = '?',
75   // Oddballs (no data).
76   kTheHole = '-',
77   kUndefined = '_',
78   kNull = '0',
79   kTrue = 'T',
80   kFalse = 'F',
81   // Number represented as 32-bit integer, ZigZag-encoded
82   // (like sint32 in protobuf)
83   kInt32 = 'I',
84   // Number represented as 32-bit unsigned integer, varint-encoded
85   // (like uint32 in protobuf)
86   kUint32 = 'U',
87   // Number represented as a 64-bit double.
88   // Host byte order is used (N.B. this makes the format non-portable).
89   kDouble = 'N',
90   // BigInt. Bitfield:uint32_t, then raw digits storage.
91   kBigInt = 'Z',
92   // byteLength:uint32_t, then raw data
93   kUtf8String = 'S',
94   kOneByteString = '"',
95   kTwoByteString = 'c',
96   // Reference to a serialized object. objectID:uint32_t
97   kObjectReference = '^',
98   // Beginning of a JS object.
99   kBeginJSObject = 'o',
100   // End of a JS object. numProperties:uint32_t
101   kEndJSObject = '{',
102   // Beginning of a sparse JS array. length:uint32_t
103   // Elements and properties are written as key/value pairs, like objects.
104   kBeginSparseJSArray = 'a',
105   // End of a sparse JS array. numProperties:uint32_t length:uint32_t
106   kEndSparseJSArray = '@',
107   // Beginning of a dense JS array. length:uint32_t
108   // |length| elements, followed by properties as key/value pairs
109   kBeginDenseJSArray = 'A',
110   // End of a dense JS array. numProperties:uint32_t length:uint32_t
111   kEndDenseJSArray = '$',
112   // Date. millisSinceEpoch:double
113   kDate = 'D',
114   // Boolean object. No data.
115   kTrueObject = 'y',
116   kFalseObject = 'x',
117   // Number object. value:double
118   kNumberObject = 'n',
119   // BigInt object. Bitfield:uint32_t, then raw digits storage.
120   kBigIntObject = 'z',
121   // String object, UTF-8 encoding. byteLength:uint32_t, then raw data.
122   kStringObject = 's',
123   // Regular expression, UTF-8 encoding. byteLength:uint32_t, raw data,
124   // flags:uint32_t.
125   kRegExp = 'R',
126   // Beginning of a JS map.
127   kBeginJSMap = ';',
128   // End of a JS map. length:uint32_t.
129   kEndJSMap = ':',
130   // Beginning of a JS set.
131   kBeginJSSet = '\'',
132   // End of a JS set. length:uint32_t.
133   kEndJSSet = ',',
134   // Array buffer. byteLength:uint32_t, then raw data.
135   kArrayBuffer = 'B',
136   // Array buffer (transferred). transferID:uint32_t
137   kArrayBufferTransfer = 't',
138   // View into an array buffer.
139   // subtag:ArrayBufferViewTag, byteOffset:uint32_t, byteLength:uint32_t
140   // For typed arrays, byteOffset and byteLength must be divisible by the size
141   // of the element.
142   // Note: kArrayBufferView is special, and should have an ArrayBuffer (or an
143   // ObjectReference to one) serialized just before it. This is a quirk arising
144   // from the previous stack-based implementation.
145   kArrayBufferView = 'V',
146   // Shared array buffer. transferID:uint32_t
147   kSharedArrayBuffer = 'u',
148   // Compiled WebAssembly module. encodingType:(one-byte tag).
149   // If encodingType == 'y' (raw bytes):
150   //  wasmWireByteLength:uint32_t, then raw data
151   //  compiledDataLength:uint32_t, then raw data
152   kWasmModule = 'W',
153   // A wasm module object transfer. next value is its index.
154   kWasmModuleTransfer = 'w',
155   // The delegate is responsible for processing all following data.
156   // This "escapes" to whatever wire format the delegate chooses.
157   kHostObject = '\\',
158   // A transferred WebAssembly.Memory object. maximumPages:int32_t, then by
159   // SharedArrayBuffer tag and its data.
160   kWasmMemoryTransfer = 'm',
161 };
162 
163 namespace {
164 
165 enum class ArrayBufferViewTag : uint8_t {
166   kInt8Array = 'b',
167   kUint8Array = 'B',
168   kUint8ClampedArray = 'C',
169   kInt16Array = 'w',
170   kUint16Array = 'W',
171   kInt32Array = 'd',
172   kUint32Array = 'D',
173   kFloat32Array = 'f',
174   kFloat64Array = 'F',
175   kBigInt64Array = 'q',
176   kBigUint64Array = 'Q',
177   kDataView = '?',
178 };
179 
180 enum class WasmEncodingTag : uint8_t {
181   kRawBytes = 'y',
182 };
183 
184 }  // namespace
185 
ValueSerializer(Isolate * isolate,v8::ValueSerializer::Delegate * delegate)186 ValueSerializer::ValueSerializer(Isolate* isolate,
187                                  v8::ValueSerializer::Delegate* delegate)
188     : isolate_(isolate),
189       delegate_(delegate),
190       zone_(isolate->allocator(), ZONE_NAME),
191       id_map_(isolate->heap(), ZoneAllocationPolicy(&zone_)),
192       array_buffer_transfer_map_(isolate->heap(),
193                                  ZoneAllocationPolicy(&zone_)) {}
194 
~ValueSerializer()195 ValueSerializer::~ValueSerializer() {
196   if (buffer_) {
197     if (delegate_) {
198       delegate_->FreeBufferMemory(buffer_);
199     } else {
200       free(buffer_);
201     }
202   }
203 }
204 
WriteHeader()205 void ValueSerializer::WriteHeader() {
206   WriteTag(SerializationTag::kVersion);
207   WriteVarint(kLatestVersion);
208 }
209 
SetTreatArrayBufferViewsAsHostObjects(bool mode)210 void ValueSerializer::SetTreatArrayBufferViewsAsHostObjects(bool mode) {
211   treat_array_buffer_views_as_host_objects_ = mode;
212 }
213 
WriteTag(SerializationTag tag)214 void ValueSerializer::WriteTag(SerializationTag tag) {
215   uint8_t raw_tag = static_cast<uint8_t>(tag);
216   WriteRawBytes(&raw_tag, sizeof(raw_tag));
217 }
218 
219 template <typename T>
WriteVarint(T value)220 void ValueSerializer::WriteVarint(T value) {
221   // Writes an unsigned integer as a base-128 varint.
222   // The number is written, 7 bits at a time, from the least significant to the
223   // most significant 7 bits. Each byte, except the last, has the MSB set.
224   // See also https://developers.google.com/protocol-buffers/docs/encoding
225   static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
226                 "Only unsigned integer types can be written as varints.");
227   uint8_t stack_buffer[sizeof(T) * 8 / 7 + 1];
228   uint8_t* next_byte = &stack_buffer[0];
229   do {
230     *next_byte = (value & 0x7F) | 0x80;
231     next_byte++;
232     value >>= 7;
233   } while (value);
234   *(next_byte - 1) &= 0x7F;
235   WriteRawBytes(stack_buffer, next_byte - stack_buffer);
236 }
237 
238 template <typename T>
WriteZigZag(T value)239 void ValueSerializer::WriteZigZag(T value) {
240   // Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is
241   // encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on).
242   // See also https://developers.google.com/protocol-buffers/docs/encoding
243   // Note that this implementation relies on the right shift being arithmetic.
244   static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
245                 "Only signed integer types can be written as zigzag.");
246   using UnsignedT = typename std::make_unsigned<T>::type;
247   WriteVarint((static_cast<UnsignedT>(value) << 1) ^
248               (value >> (8 * sizeof(T) - 1)));
249 }
250 
WriteDouble(double value)251 void ValueSerializer::WriteDouble(double value) {
252   // Warning: this uses host endianness.
253   WriteRawBytes(&value, sizeof(value));
254 }
255 
WriteOneByteString(Vector<const uint8_t> chars)256 void ValueSerializer::WriteOneByteString(Vector<const uint8_t> chars) {
257   WriteVarint<uint32_t>(chars.length());
258   WriteRawBytes(chars.begin(), chars.length() * sizeof(uint8_t));
259 }
260 
WriteTwoByteString(Vector<const uc16> chars)261 void ValueSerializer::WriteTwoByteString(Vector<const uc16> chars) {
262   // Warning: this uses host endianness.
263   WriteVarint<uint32_t>(chars.length() * sizeof(uc16));
264   WriteRawBytes(chars.begin(), chars.length() * sizeof(uc16));
265 }
266 
WriteBigIntContents(BigInt * bigint)267 void ValueSerializer::WriteBigIntContents(BigInt* bigint) {
268   uint32_t bitfield = bigint->GetBitfieldForSerialization();
269   int bytelength = BigInt::DigitsByteLengthForBitfield(bitfield);
270   WriteVarint<uint32_t>(bitfield);
271   uint8_t* dest;
272   if (ReserveRawBytes(bytelength).To(&dest)) {
273     bigint->SerializeDigits(dest);
274   }
275 }
276 
WriteRawBytes(const void * source,size_t length)277 void ValueSerializer::WriteRawBytes(const void* source, size_t length) {
278   uint8_t* dest;
279   if (ReserveRawBytes(length).To(&dest)) {
280     memcpy(dest, source, length);
281   }
282 }
283 
ReserveRawBytes(size_t bytes)284 Maybe<uint8_t*> ValueSerializer::ReserveRawBytes(size_t bytes) {
285   size_t old_size = buffer_size_;
286   size_t new_size = old_size + bytes;
287   if (V8_UNLIKELY(new_size > buffer_capacity_)) {
288     bool ok;
289     if (!ExpandBuffer(new_size).To(&ok)) {
290       return Nothing<uint8_t*>();
291     }
292   }
293   buffer_size_ = new_size;
294   return Just(&buffer_[old_size]);
295 }
296 
ExpandBuffer(size_t required_capacity)297 Maybe<bool> ValueSerializer::ExpandBuffer(size_t required_capacity) {
298   DCHECK_GT(required_capacity, buffer_capacity_);
299   size_t requested_capacity =
300       std::max(required_capacity, buffer_capacity_ * 2) + 64;
301   size_t provided_capacity = 0;
302   void* new_buffer = nullptr;
303   if (delegate_) {
304     new_buffer = delegate_->ReallocateBufferMemory(buffer_, requested_capacity,
305                                                    &provided_capacity);
306   } else {
307     new_buffer = realloc(buffer_, requested_capacity);
308     provided_capacity = requested_capacity;
309   }
310   if (new_buffer) {
311     DCHECK(provided_capacity >= requested_capacity);
312     buffer_ = reinterpret_cast<uint8_t*>(new_buffer);
313     buffer_capacity_ = provided_capacity;
314     return Just(true);
315   } else {
316     out_of_memory_ = true;
317     return Nothing<bool>();
318   }
319 }
320 
WriteUint32(uint32_t value)321 void ValueSerializer::WriteUint32(uint32_t value) {
322   WriteVarint<uint32_t>(value);
323 }
324 
WriteUint64(uint64_t value)325 void ValueSerializer::WriteUint64(uint64_t value) {
326   WriteVarint<uint64_t>(value);
327 }
328 
ReleaseBuffer()329 std::vector<uint8_t> ValueSerializer::ReleaseBuffer() {
330   return std::vector<uint8_t>(buffer_, buffer_ + buffer_size_);
331 }
332 
Release()333 std::pair<uint8_t*, size_t> ValueSerializer::Release() {
334   auto result = std::make_pair(buffer_, buffer_size_);
335   buffer_ = nullptr;
336   buffer_size_ = 0;
337   buffer_capacity_ = 0;
338   return result;
339 }
340 
TransferArrayBuffer(uint32_t transfer_id,Handle<JSArrayBuffer> array_buffer)341 void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id,
342                                           Handle<JSArrayBuffer> array_buffer) {
343   DCHECK(!array_buffer_transfer_map_.Find(array_buffer));
344   DCHECK(!array_buffer->is_shared());
345   array_buffer_transfer_map_.Set(array_buffer, transfer_id);
346 }
347 
WriteObject(Handle<Object> object)348 Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
349   out_of_memory_ = false;
350   if (object->IsSmi()) {
351     WriteSmi(Smi::cast(*object));
352     return ThrowIfOutOfMemory();
353   }
354 
355   DCHECK(object->IsHeapObject());
356   switch (HeapObject::cast(*object)->map()->instance_type()) {
357     case ODDBALL_TYPE:
358       WriteOddball(Oddball::cast(*object));
359       return ThrowIfOutOfMemory();
360     case HEAP_NUMBER_TYPE:
361       WriteHeapNumber(HeapNumber::cast(*object));
362       return ThrowIfOutOfMemory();
363     case MUTABLE_HEAP_NUMBER_TYPE:
364       WriteMutableHeapNumber(MutableHeapNumber::cast(*object));
365       return ThrowIfOutOfMemory();
366     case BIGINT_TYPE:
367       WriteBigInt(BigInt::cast(*object));
368       return ThrowIfOutOfMemory();
369     case JS_TYPED_ARRAY_TYPE:
370     case JS_DATA_VIEW_TYPE: {
371       // Despite being JSReceivers, these have their wrapped buffer serialized
372       // first. That makes this logic a little quirky, because it needs to
373       // happen before we assign object IDs.
374       // TODO(jbroman): It may be possible to avoid materializing a typed
375       // array's buffer here.
376       Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(object);
377       if (!id_map_.Find(view) && !treat_array_buffer_views_as_host_objects_) {
378         Handle<JSArrayBuffer> buffer(
379             view->IsJSTypedArray()
380                 ? Handle<JSTypedArray>::cast(view)->GetBuffer()
381                 : handle(JSArrayBuffer::cast(view->buffer()), isolate_));
382         if (!WriteJSReceiver(buffer).FromMaybe(false)) return Nothing<bool>();
383       }
384       return WriteJSReceiver(view);
385     }
386     default:
387       if (object->IsString()) {
388         WriteString(Handle<String>::cast(object));
389         return ThrowIfOutOfMemory();
390       } else if (object->IsJSReceiver()) {
391         return WriteJSReceiver(Handle<JSReceiver>::cast(object));
392       } else {
393         ThrowDataCloneError(MessageTemplate::kDataCloneError, object);
394         return Nothing<bool>();
395       }
396   }
397 }
398 
WriteOddball(Oddball * oddball)399 void ValueSerializer::WriteOddball(Oddball* oddball) {
400   SerializationTag tag = SerializationTag::kUndefined;
401   switch (oddball->kind()) {
402     case Oddball::kUndefined:
403       tag = SerializationTag::kUndefined;
404       break;
405     case Oddball::kFalse:
406       tag = SerializationTag::kFalse;
407       break;
408     case Oddball::kTrue:
409       tag = SerializationTag::kTrue;
410       break;
411     case Oddball::kNull:
412       tag = SerializationTag::kNull;
413       break;
414     default:
415       UNREACHABLE();
416       break;
417   }
418   WriteTag(tag);
419 }
420 
WriteSmi(Smi * smi)421 void ValueSerializer::WriteSmi(Smi* smi) {
422   static_assert(kSmiValueSize <= 32, "Expected SMI <= 32 bits.");
423   WriteTag(SerializationTag::kInt32);
424   WriteZigZag<int32_t>(smi->value());
425 }
426 
WriteHeapNumber(HeapNumber * number)427 void ValueSerializer::WriteHeapNumber(HeapNumber* number) {
428   WriteTag(SerializationTag::kDouble);
429   WriteDouble(number->value());
430 }
431 
WriteMutableHeapNumber(MutableHeapNumber * number)432 void ValueSerializer::WriteMutableHeapNumber(MutableHeapNumber* number) {
433   WriteTag(SerializationTag::kDouble);
434   WriteDouble(number->value());
435 }
436 
WriteBigInt(BigInt * bigint)437 void ValueSerializer::WriteBigInt(BigInt* bigint) {
438   WriteTag(SerializationTag::kBigInt);
439   WriteBigIntContents(bigint);
440 }
441 
WriteString(Handle<String> string)442 void ValueSerializer::WriteString(Handle<String> string) {
443   string = String::Flatten(isolate_, string);
444   DisallowHeapAllocation no_gc;
445   String::FlatContent flat = string->GetFlatContent();
446   DCHECK(flat.IsFlat());
447   if (flat.IsOneByte()) {
448     Vector<const uint8_t> chars = flat.ToOneByteVector();
449     WriteTag(SerializationTag::kOneByteString);
450     WriteOneByteString(chars);
451   } else if (flat.IsTwoByte()) {
452     Vector<const uc16> chars = flat.ToUC16Vector();
453     uint32_t byte_length = chars.length() * sizeof(uc16);
454     // The existing reading code expects 16-byte strings to be aligned.
455     if ((buffer_size_ + 1 + BytesNeededForVarint(byte_length)) & 1)
456       WriteTag(SerializationTag::kPadding);
457     WriteTag(SerializationTag::kTwoByteString);
458     WriteTwoByteString(chars);
459   } else {
460     UNREACHABLE();
461   }
462 }
463 
WriteJSReceiver(Handle<JSReceiver> receiver)464 Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
465   // If the object has already been serialized, just write its ID.
466   uint32_t* id_map_entry = id_map_.Get(receiver);
467   if (uint32_t id = *id_map_entry) {
468     WriteTag(SerializationTag::kObjectReference);
469     WriteVarint(id - 1);
470     return ThrowIfOutOfMemory();
471   }
472 
473   // Otherwise, allocate an ID for it.
474   uint32_t id = next_id_++;
475   *id_map_entry = id + 1;
476 
477   // Eliminate callable and exotic objects, which should not be serialized.
478   InstanceType instance_type = receiver->map()->instance_type();
479   if (receiver->IsCallable() || (IsSpecialReceiverInstanceType(instance_type) &&
480                                  instance_type != JS_SPECIAL_API_OBJECT_TYPE)) {
481     ThrowDataCloneError(MessageTemplate::kDataCloneError, receiver);
482     return Nothing<bool>();
483   }
484 
485   // If we are at the end of the stack, abort. This function may recurse.
486   STACK_CHECK(isolate_, Nothing<bool>());
487 
488   HandleScope scope(isolate_);
489   switch (instance_type) {
490     case JS_ARRAY_TYPE:
491       return WriteJSArray(Handle<JSArray>::cast(receiver));
492     case JS_OBJECT_TYPE:
493     case JS_API_OBJECT_TYPE: {
494       Handle<JSObject> js_object = Handle<JSObject>::cast(receiver);
495       if (JSObject::GetEmbedderFieldCount(js_object->map())) {
496         return WriteHostObject(js_object);
497       } else {
498         return WriteJSObject(js_object);
499       }
500     }
501     case JS_SPECIAL_API_OBJECT_TYPE:
502       return WriteHostObject(Handle<JSObject>::cast(receiver));
503     case JS_DATE_TYPE:
504       WriteJSDate(JSDate::cast(*receiver));
505       return ThrowIfOutOfMemory();
506     case JS_VALUE_TYPE:
507       return WriteJSValue(Handle<JSValue>::cast(receiver));
508     case JS_REGEXP_TYPE:
509       WriteJSRegExp(JSRegExp::cast(*receiver));
510       return ThrowIfOutOfMemory();
511     case JS_MAP_TYPE:
512       return WriteJSMap(Handle<JSMap>::cast(receiver));
513     case JS_SET_TYPE:
514       return WriteJSSet(Handle<JSSet>::cast(receiver));
515     case JS_ARRAY_BUFFER_TYPE:
516       return WriteJSArrayBuffer(Handle<JSArrayBuffer>::cast(receiver));
517     case JS_TYPED_ARRAY_TYPE:
518     case JS_DATA_VIEW_TYPE:
519       return WriteJSArrayBufferView(JSArrayBufferView::cast(*receiver));
520     case WASM_MODULE_TYPE: {
521       auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
522       if (!FLAG_wasm_disable_structured_cloning || enabled_features.threads) {
523         // Only write WebAssembly modules if not disabled by a flag.
524         return WriteWasmModule(Handle<WasmModuleObject>::cast(receiver));
525       }
526       break;
527     }
528     case WASM_MEMORY_TYPE: {
529       auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
530       if (enabled_features.threads) {
531         return WriteWasmMemory(Handle<WasmMemoryObject>::cast(receiver));
532       }
533       break;
534     }
535     default:
536       break;
537   }
538 
539   ThrowDataCloneError(MessageTemplate::kDataCloneError, receiver);
540   return Nothing<bool>();
541 }
542 
WriteJSObject(Handle<JSObject> object)543 Maybe<bool> ValueSerializer::WriteJSObject(Handle<JSObject> object) {
544   DCHECK(!object->map()->IsCustomElementsReceiverMap());
545   const bool can_serialize_fast =
546       object->HasFastProperties() && object->elements()->length() == 0;
547   if (!can_serialize_fast) return WriteJSObjectSlow(object);
548 
549   Handle<Map> map(object->map(), isolate_);
550   WriteTag(SerializationTag::kBeginJSObject);
551 
552   // Write out fast properties as long as they are only data properties and the
553   // map doesn't change.
554   uint32_t properties_written = 0;
555   bool map_changed = false;
556   for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
557     Handle<Name> key(map->instance_descriptors()->GetKey(i), isolate_);
558     if (!key->IsString()) continue;
559     PropertyDetails details = map->instance_descriptors()->GetDetails(i);
560     if (details.IsDontEnum()) continue;
561 
562     Handle<Object> value;
563     if (V8_LIKELY(!map_changed)) map_changed = *map == object->map();
564     if (V8_LIKELY(!map_changed && details.location() == kField)) {
565       DCHECK_EQ(kData, details.kind());
566       FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
567       value = JSObject::FastPropertyAt(object, details.representation(),
568                                        field_index);
569     } else {
570       // This logic should essentially match WriteJSObjectPropertiesSlow.
571       // If the property is no longer found, do not serialize it.
572       // This could happen if a getter deleted the property.
573       LookupIterator it(isolate_, object, key, LookupIterator::OWN);
574       if (!it.IsFound()) continue;
575       if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<bool>();
576     }
577 
578     if (!WriteObject(key).FromMaybe(false) ||
579         !WriteObject(value).FromMaybe(false)) {
580       return Nothing<bool>();
581     }
582     properties_written++;
583   }
584 
585   WriteTag(SerializationTag::kEndJSObject);
586   WriteVarint<uint32_t>(properties_written);
587   return ThrowIfOutOfMemory();
588 }
589 
WriteJSObjectSlow(Handle<JSObject> object)590 Maybe<bool> ValueSerializer::WriteJSObjectSlow(Handle<JSObject> object) {
591   WriteTag(SerializationTag::kBeginJSObject);
592   Handle<FixedArray> keys;
593   uint32_t properties_written = 0;
594   if (!KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
595                                ENUMERABLE_STRINGS)
596            .ToHandle(&keys) ||
597       !WriteJSObjectPropertiesSlow(object, keys).To(&properties_written)) {
598     return Nothing<bool>();
599   }
600   WriteTag(SerializationTag::kEndJSObject);
601   WriteVarint<uint32_t>(properties_written);
602   return ThrowIfOutOfMemory();
603 }
604 
WriteJSArray(Handle<JSArray> array)605 Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) {
606   uint32_t length = 0;
607   bool valid_length = array->length()->ToArrayLength(&length);
608   DCHECK(valid_length);
609   USE(valid_length);
610 
611   // To keep things simple, for now we decide between dense and sparse
612   // serialization based on elements kind. A more principled heuristic could
613   // count the elements, but would need to take care to note which indices
614   // existed (as only indices which were enumerable own properties at this point
615   // should be serialized).
616   const bool should_serialize_densely =
617       array->HasFastElements() && !array->HasHoleyElements();
618 
619   if (should_serialize_densely) {
620     DCHECK_LE(length, static_cast<uint32_t>(FixedArray::kMaxLength));
621     WriteTag(SerializationTag::kBeginDenseJSArray);
622     WriteVarint<uint32_t>(length);
623     uint32_t i = 0;
624 
625     // Fast paths. Note that PACKED_ELEMENTS in particular can bail due to the
626     // structure of the elements changing.
627     switch (array->GetElementsKind()) {
628       case PACKED_SMI_ELEMENTS: {
629         Handle<FixedArray> elements(FixedArray::cast(array->elements()),
630                                     isolate_);
631         for (; i < length; i++) WriteSmi(Smi::cast(elements->get(i)));
632         break;
633       }
634       case PACKED_DOUBLE_ELEMENTS: {
635         // Elements are empty_fixed_array, not a FixedDoubleArray, if the array
636         // is empty. No elements to encode in this case anyhow.
637         if (length == 0) break;
638         Handle<FixedDoubleArray> elements(
639             FixedDoubleArray::cast(array->elements()), isolate_);
640         for (; i < length; i++) {
641           WriteTag(SerializationTag::kDouble);
642           WriteDouble(elements->get_scalar(i));
643         }
644         break;
645       }
646       case PACKED_ELEMENTS: {
647         Handle<Object> old_length(array->length(), isolate_);
648         for (; i < length; i++) {
649           if (array->length() != *old_length ||
650               array->GetElementsKind() != PACKED_ELEMENTS) {
651             // Fall back to slow path.
652             break;
653           }
654           Handle<Object> element(FixedArray::cast(array->elements())->get(i),
655                                  isolate_);
656           if (!WriteObject(element).FromMaybe(false)) return Nothing<bool>();
657         }
658         break;
659       }
660       default:
661         break;
662     }
663 
664     // If there are elements remaining, serialize them slowly.
665     for (; i < length; i++) {
666       // Serializing the array's elements can have arbitrary side effects, so we
667       // cannot rely on still having fast elements, even if it did to begin
668       // with.
669       Handle<Object> element;
670       LookupIterator it(isolate_, array, i, array, LookupIterator::OWN);
671       if (!it.IsFound()) {
672         // This can happen in the case where an array that was originally dense
673         // became sparse during serialization. It's too late to switch to the
674         // sparse format, but we can mark the elements as absent.
675         WriteTag(SerializationTag::kTheHole);
676         continue;
677       }
678       if (!Object::GetProperty(&it).ToHandle(&element) ||
679           !WriteObject(element).FromMaybe(false)) {
680         return Nothing<bool>();
681       }
682     }
683 
684     KeyAccumulator accumulator(isolate_, KeyCollectionMode::kOwnOnly,
685                                ENUMERABLE_STRINGS);
686     if (!accumulator.CollectOwnPropertyNames(array, array).FromMaybe(false)) {
687       return Nothing<bool>();
688     }
689     Handle<FixedArray> keys =
690         accumulator.GetKeys(GetKeysConversion::kConvertToString);
691     uint32_t properties_written;
692     if (!WriteJSObjectPropertiesSlow(array, keys).To(&properties_written)) {
693       return Nothing<bool>();
694     }
695     WriteTag(SerializationTag::kEndDenseJSArray);
696     WriteVarint<uint32_t>(properties_written);
697     WriteVarint<uint32_t>(length);
698   } else {
699     WriteTag(SerializationTag::kBeginSparseJSArray);
700     WriteVarint<uint32_t>(length);
701     Handle<FixedArray> keys;
702     uint32_t properties_written = 0;
703     if (!KeyAccumulator::GetKeys(array, KeyCollectionMode::kOwnOnly,
704                                  ENUMERABLE_STRINGS)
705              .ToHandle(&keys) ||
706         !WriteJSObjectPropertiesSlow(array, keys).To(&properties_written)) {
707       return Nothing<bool>();
708     }
709     WriteTag(SerializationTag::kEndSparseJSArray);
710     WriteVarint<uint32_t>(properties_written);
711     WriteVarint<uint32_t>(length);
712   }
713   return ThrowIfOutOfMemory();
714 }
715 
WriteJSDate(JSDate * date)716 void ValueSerializer::WriteJSDate(JSDate* date) {
717   WriteTag(SerializationTag::kDate);
718   WriteDouble(date->value()->Number());
719 }
720 
WriteJSValue(Handle<JSValue> value)721 Maybe<bool> ValueSerializer::WriteJSValue(Handle<JSValue> value) {
722   Object* inner_value = value->value();
723   if (inner_value->IsTrue(isolate_)) {
724     WriteTag(SerializationTag::kTrueObject);
725   } else if (inner_value->IsFalse(isolate_)) {
726     WriteTag(SerializationTag::kFalseObject);
727   } else if (inner_value->IsNumber()) {
728     WriteTag(SerializationTag::kNumberObject);
729     WriteDouble(inner_value->Number());
730   } else if (inner_value->IsBigInt()) {
731     WriteTag(SerializationTag::kBigIntObject);
732     WriteBigIntContents(BigInt::cast(inner_value));
733   } else if (inner_value->IsString()) {
734     WriteTag(SerializationTag::kStringObject);
735     WriteString(handle(String::cast(inner_value), isolate_));
736   } else {
737     DCHECK(inner_value->IsSymbol());
738     ThrowDataCloneError(MessageTemplate::kDataCloneError, value);
739     return Nothing<bool>();
740   }
741   return ThrowIfOutOfMemory();
742 }
743 
WriteJSRegExp(JSRegExp * regexp)744 void ValueSerializer::WriteJSRegExp(JSRegExp* regexp) {
745   WriteTag(SerializationTag::kRegExp);
746   WriteString(handle(regexp->Pattern(), isolate_));
747   WriteVarint(static_cast<uint32_t>(regexp->GetFlags()));
748 }
749 
WriteJSMap(Handle<JSMap> map)750 Maybe<bool> ValueSerializer::WriteJSMap(Handle<JSMap> map) {
751   // First copy the key-value pairs, since getters could mutate them.
752   Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()), isolate_);
753   int length = table->NumberOfElements() * 2;
754   Handle<FixedArray> entries = isolate_->factory()->NewFixedArray(length);
755   {
756     DisallowHeapAllocation no_gc;
757     Oddball* the_hole = ReadOnlyRoots(isolate_).the_hole_value();
758     int capacity = table->UsedCapacity();
759     int result_index = 0;
760     for (int i = 0; i < capacity; i++) {
761       Object* key = table->KeyAt(i);
762       if (key == the_hole) continue;
763       entries->set(result_index++, key);
764       entries->set(result_index++, table->ValueAt(i));
765     }
766     DCHECK_EQ(result_index, length);
767   }
768 
769   // Then write it out.
770   WriteTag(SerializationTag::kBeginJSMap);
771   for (int i = 0; i < length; i++) {
772     if (!WriteObject(handle(entries->get(i), isolate_)).FromMaybe(false)) {
773       return Nothing<bool>();
774     }
775   }
776   WriteTag(SerializationTag::kEndJSMap);
777   WriteVarint<uint32_t>(length);
778   return ThrowIfOutOfMemory();
779 }
780 
WriteJSSet(Handle<JSSet> set)781 Maybe<bool> ValueSerializer::WriteJSSet(Handle<JSSet> set) {
782   // First copy the element pointers, since getters could mutate them.
783   Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()), isolate_);
784   int length = table->NumberOfElements();
785   Handle<FixedArray> entries = isolate_->factory()->NewFixedArray(length);
786   {
787     DisallowHeapAllocation no_gc;
788     Oddball* the_hole = ReadOnlyRoots(isolate_).the_hole_value();
789     int capacity = table->UsedCapacity();
790     int result_index = 0;
791     for (int i = 0; i < capacity; i++) {
792       Object* key = table->KeyAt(i);
793       if (key == the_hole) continue;
794       entries->set(result_index++, key);
795     }
796     DCHECK_EQ(result_index, length);
797   }
798 
799   // Then write it out.
800   WriteTag(SerializationTag::kBeginJSSet);
801   for (int i = 0; i < length; i++) {
802     if (!WriteObject(handle(entries->get(i), isolate_)).FromMaybe(false)) {
803       return Nothing<bool>();
804     }
805   }
806   WriteTag(SerializationTag::kEndJSSet);
807   WriteVarint<uint32_t>(length);
808   return ThrowIfOutOfMemory();
809 }
810 
WriteJSArrayBuffer(Handle<JSArrayBuffer> array_buffer)811 Maybe<bool> ValueSerializer::WriteJSArrayBuffer(
812     Handle<JSArrayBuffer> array_buffer) {
813   if (array_buffer->is_shared()) {
814     if (!delegate_) {
815       ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer);
816       return Nothing<bool>();
817     }
818 
819     v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
820     Maybe<uint32_t> index = delegate_->GetSharedArrayBufferId(
821         v8_isolate, Utils::ToLocalShared(array_buffer));
822     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
823 
824     WriteTag(SerializationTag::kSharedArrayBuffer);
825     WriteVarint(index.FromJust());
826     return ThrowIfOutOfMemory();
827   }
828 
829   uint32_t* transfer_entry = array_buffer_transfer_map_.Find(array_buffer);
830   if (transfer_entry) {
831     WriteTag(SerializationTag::kArrayBufferTransfer);
832     WriteVarint(*transfer_entry);
833     return ThrowIfOutOfMemory();
834   }
835   if (array_buffer->was_neutered()) {
836     ThrowDataCloneError(MessageTemplate::kDataCloneErrorNeuteredArrayBuffer);
837     return Nothing<bool>();
838   }
839   double byte_length = array_buffer->byte_length()->Number();
840   if (byte_length > std::numeric_limits<uint32_t>::max()) {
841     ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer);
842     return Nothing<bool>();
843   }
844   WriteTag(SerializationTag::kArrayBuffer);
845   WriteVarint<uint32_t>(byte_length);
846   WriteRawBytes(array_buffer->backing_store(), byte_length);
847   return ThrowIfOutOfMemory();
848 }
849 
WriteJSArrayBufferView(JSArrayBufferView * view)850 Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView* view) {
851   if (treat_array_buffer_views_as_host_objects_) {
852     return WriteHostObject(handle(view, isolate_));
853   }
854   WriteTag(SerializationTag::kArrayBufferView);
855   ArrayBufferViewTag tag = ArrayBufferViewTag::kInt8Array;
856   if (view->IsJSTypedArray()) {
857     switch (JSTypedArray::cast(view)->type()) {
858 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
859   case kExternal##Type##Array:                    \
860     tag = ArrayBufferViewTag::k##Type##Array;     \
861     break;
862       TYPED_ARRAYS(TYPED_ARRAY_CASE)
863 #undef TYPED_ARRAY_CASE
864     }
865   } else {
866     DCHECK(view->IsJSDataView());
867     tag = ArrayBufferViewTag::kDataView;
868   }
869   WriteVarint(static_cast<uint8_t>(tag));
870   WriteVarint(NumberToUint32(view->byte_offset()));
871   WriteVarint(NumberToUint32(view->byte_length()));
872   return ThrowIfOutOfMemory();
873 }
874 
WriteWasmModule(Handle<WasmModuleObject> object)875 Maybe<bool> ValueSerializer::WriteWasmModule(Handle<WasmModuleObject> object) {
876   if (delegate_ != nullptr) {
877     // TODO(titzer): introduce a Utils::ToLocal for WasmModuleObject.
878     Maybe<uint32_t> transfer_id = delegate_->GetWasmModuleTransferId(
879         reinterpret_cast<v8::Isolate*>(isolate_),
880         v8::Local<v8::WasmCompiledModule>::Cast(
881             Utils::ToLocal(Handle<JSObject>::cast(object))));
882     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
883     uint32_t id = 0;
884     if (transfer_id.To(&id)) {
885       WriteTag(SerializationTag::kWasmModuleTransfer);
886       WriteVarint<uint32_t>(id);
887       return Just(true);
888     }
889   }
890 
891   WasmEncodingTag encoding_tag = WasmEncodingTag::kRawBytes;
892   WriteTag(SerializationTag::kWasmModule);
893   WriteRawBytes(&encoding_tag, sizeof(encoding_tag));
894 
895   wasm::NativeModule* native_module = object->native_module();
896   Vector<const uint8_t> wire_bytes = native_module->wire_bytes();
897   WriteVarint<uint32_t>(static_cast<uint32_t>(wire_bytes.size()));
898   uint8_t* destination;
899   if (ReserveRawBytes(wire_bytes.size()).To(&destination)) {
900     memcpy(destination, wire_bytes.start(), wire_bytes.size());
901   }
902 
903   wasm::WasmSerializer wasm_serializer(isolate_, native_module);
904   size_t module_size = wasm_serializer.GetSerializedNativeModuleSize();
905   CHECK_GE(std::numeric_limits<uint32_t>::max(), module_size);
906   WriteVarint<uint32_t>(static_cast<uint32_t>(module_size));
907   uint8_t* module_buffer;
908   if (ReserveRawBytes(module_size).To(&module_buffer)) {
909     if (!wasm_serializer.SerializeNativeModule({module_buffer, module_size})) {
910       return Nothing<bool>();
911     }
912   }
913   return ThrowIfOutOfMemory();
914 }
915 
WriteWasmMemory(Handle<WasmMemoryObject> object)916 Maybe<bool> ValueSerializer::WriteWasmMemory(Handle<WasmMemoryObject> object) {
917   if (!object->array_buffer()->is_shared()) {
918     ThrowDataCloneError(MessageTemplate::kDataCloneError, object);
919     return Nothing<bool>();
920   }
921 
922   WriteTag(SerializationTag::kWasmMemoryTransfer);
923   WriteZigZag<int32_t>(object->maximum_pages());
924   return WriteJSReceiver(Handle<JSReceiver>(object->array_buffer(), isolate_));
925 }
926 
WriteHostObject(Handle<JSObject> object)927 Maybe<bool> ValueSerializer::WriteHostObject(Handle<JSObject> object) {
928   WriteTag(SerializationTag::kHostObject);
929   if (!delegate_) {
930     isolate_->Throw(*isolate_->factory()->NewError(
931         isolate_->error_function(), MessageTemplate::kDataCloneError, object));
932     return Nothing<bool>();
933   }
934   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
935   Maybe<bool> result =
936       delegate_->WriteHostObject(v8_isolate, Utils::ToLocal(object));
937   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
938   DCHECK(!result.IsNothing());
939   return result;
940 }
941 
WriteJSObjectPropertiesSlow(Handle<JSObject> object,Handle<FixedArray> keys)942 Maybe<uint32_t> ValueSerializer::WriteJSObjectPropertiesSlow(
943     Handle<JSObject> object, Handle<FixedArray> keys) {
944   uint32_t properties_written = 0;
945   int length = keys->length();
946   for (int i = 0; i < length; i++) {
947     Handle<Object> key(keys->get(i), isolate_);
948 
949     bool success;
950     LookupIterator it = LookupIterator::PropertyOrElement(
951         isolate_, object, key, &success, LookupIterator::OWN);
952     DCHECK(success);
953     Handle<Object> value;
954     if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<uint32_t>();
955 
956     // If the property is no longer found, do not serialize it.
957     // This could happen if a getter deleted the property.
958     if (!it.IsFound()) continue;
959 
960     if (!WriteObject(key).FromMaybe(false) ||
961         !WriteObject(value).FromMaybe(false)) {
962       return Nothing<uint32_t>();
963     }
964 
965     properties_written++;
966   }
967   return Just(properties_written);
968 }
969 
ThrowDataCloneError(MessageTemplate::Template template_index)970 void ValueSerializer::ThrowDataCloneError(
971     MessageTemplate::Template template_index) {
972   return ThrowDataCloneError(template_index,
973                              isolate_->factory()->empty_string());
974 }
975 
ThrowIfOutOfMemory()976 Maybe<bool> ValueSerializer::ThrowIfOutOfMemory() {
977   if (out_of_memory_) {
978     ThrowDataCloneError(MessageTemplate::kDataCloneErrorOutOfMemory);
979     return Nothing<bool>();
980   }
981   return Just(true);
982 }
983 
ThrowDataCloneError(MessageTemplate::Template template_index,Handle<Object> arg0)984 void ValueSerializer::ThrowDataCloneError(
985     MessageTemplate::Template template_index, Handle<Object> arg0) {
986   Handle<String> message =
987       MessageTemplate::FormatMessage(isolate_, template_index, arg0);
988   if (delegate_) {
989     delegate_->ThrowDataCloneError(Utils::ToLocal(message));
990   } else {
991     isolate_->Throw(
992         *isolate_->factory()->NewError(isolate_->error_function(), message));
993   }
994   if (isolate_->has_scheduled_exception()) {
995     isolate_->PromoteScheduledException();
996   }
997 }
998 
ValueDeserializer(Isolate * isolate,Vector<const uint8_t> data,v8::ValueDeserializer::Delegate * delegate)999 ValueDeserializer::ValueDeserializer(Isolate* isolate,
1000                                      Vector<const uint8_t> data,
1001                                      v8::ValueDeserializer::Delegate* delegate)
1002     : isolate_(isolate),
1003       delegate_(delegate),
1004       position_(data.start()),
1005       end_(data.start() + data.length()),
1006       pretenure_(data.length() > kPretenureThreshold ? TENURED : NOT_TENURED),
1007       id_map_(isolate->global_handles()->Create(
1008           ReadOnlyRoots(isolate_).empty_fixed_array())) {}
1009 
~ValueDeserializer()1010 ValueDeserializer::~ValueDeserializer() {
1011   GlobalHandles::Destroy(Handle<Object>::cast(id_map_).location());
1012 
1013   Handle<Object> transfer_map_handle;
1014   if (array_buffer_transfer_map_.ToHandle(&transfer_map_handle)) {
1015     GlobalHandles::Destroy(transfer_map_handle.location());
1016   }
1017 }
1018 
ReadHeader()1019 Maybe<bool> ValueDeserializer::ReadHeader() {
1020   if (position_ < end_ &&
1021       *position_ == static_cast<uint8_t>(SerializationTag::kVersion)) {
1022     ReadTag().ToChecked();
1023     if (!ReadVarint<uint32_t>().To(&version_) || version_ > kLatestVersion) {
1024       isolate_->Throw(*isolate_->factory()->NewError(
1025           MessageTemplate::kDataCloneDeserializationVersionError));
1026       return Nothing<bool>();
1027     }
1028   }
1029   return Just(true);
1030 }
1031 
PeekTag() const1032 Maybe<SerializationTag> ValueDeserializer::PeekTag() const {
1033   const uint8_t* peek_position = position_;
1034   SerializationTag tag;
1035   do {
1036     if (peek_position >= end_) return Nothing<SerializationTag>();
1037     tag = static_cast<SerializationTag>(*peek_position);
1038     peek_position++;
1039   } while (tag == SerializationTag::kPadding);
1040   return Just(tag);
1041 }
1042 
ConsumeTag(SerializationTag peeked_tag)1043 void ValueDeserializer::ConsumeTag(SerializationTag peeked_tag) {
1044   SerializationTag actual_tag = ReadTag().ToChecked();
1045   DCHECK(actual_tag == peeked_tag);
1046   USE(actual_tag);
1047 }
1048 
ReadTag()1049 Maybe<SerializationTag> ValueDeserializer::ReadTag() {
1050   SerializationTag tag;
1051   do {
1052     if (position_ >= end_) return Nothing<SerializationTag>();
1053     tag = static_cast<SerializationTag>(*position_);
1054     position_++;
1055   } while (tag == SerializationTag::kPadding);
1056   return Just(tag);
1057 }
1058 
1059 template <typename T>
ReadVarint()1060 Maybe<T> ValueDeserializer::ReadVarint() {
1061   // Reads an unsigned integer as a base-128 varint.
1062   // The number is written, 7 bits at a time, from the least significant to the
1063   // most significant 7 bits. Each byte, except the last, has the MSB set.
1064   // If the varint is larger than T, any more significant bits are discarded.
1065   // See also https://developers.google.com/protocol-buffers/docs/encoding
1066   static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
1067                 "Only unsigned integer types can be read as varints.");
1068   T value = 0;
1069   unsigned shift = 0;
1070   bool has_another_byte;
1071   do {
1072     if (position_ >= end_) return Nothing<T>();
1073     uint8_t byte = *position_;
1074     if (V8_LIKELY(shift < sizeof(T) * 8)) {
1075       value |= static_cast<T>(byte & 0x7F) << shift;
1076       shift += 7;
1077     }
1078     has_another_byte = byte & 0x80;
1079     position_++;
1080   } while (has_another_byte);
1081   return Just(value);
1082 }
1083 
1084 template <typename T>
ReadZigZag()1085 Maybe<T> ValueDeserializer::ReadZigZag() {
1086   // Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is
1087   // encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on).
1088   // See also https://developers.google.com/protocol-buffers/docs/encoding
1089   static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
1090                 "Only signed integer types can be read as zigzag.");
1091   using UnsignedT = typename std::make_unsigned<T>::type;
1092   UnsignedT unsigned_value;
1093   if (!ReadVarint<UnsignedT>().To(&unsigned_value)) return Nothing<T>();
1094   return Just(static_cast<T>((unsigned_value >> 1) ^
1095                              -static_cast<T>(unsigned_value & 1)));
1096 }
1097 
ReadDouble()1098 Maybe<double> ValueDeserializer::ReadDouble() {
1099   // Warning: this uses host endianness.
1100   if (position_ > end_ - sizeof(double)) return Nothing<double>();
1101   double value;
1102   memcpy(&value, position_, sizeof(double));
1103   position_ += sizeof(double);
1104   if (std::isnan(value)) value = std::numeric_limits<double>::quiet_NaN();
1105   return Just(value);
1106 }
1107 
ReadRawBytes(int size)1108 Maybe<Vector<const uint8_t>> ValueDeserializer::ReadRawBytes(int size) {
1109   if (size > end_ - position_) return Nothing<Vector<const uint8_t>>();
1110   const uint8_t* start = position_;
1111   position_ += size;
1112   return Just(Vector<const uint8_t>(start, size));
1113 }
1114 
ReadUint32(uint32_t * value)1115 bool ValueDeserializer::ReadUint32(uint32_t* value) {
1116   return ReadVarint<uint32_t>().To(value);
1117 }
1118 
ReadUint64(uint64_t * value)1119 bool ValueDeserializer::ReadUint64(uint64_t* value) {
1120   return ReadVarint<uint64_t>().To(value);
1121 }
1122 
ReadDouble(double * value)1123 bool ValueDeserializer::ReadDouble(double* value) {
1124   return ReadDouble().To(value);
1125 }
1126 
ReadRawBytes(size_t length,const void ** data)1127 bool ValueDeserializer::ReadRawBytes(size_t length, const void** data) {
1128   if (length > static_cast<size_t>(end_ - position_)) return false;
1129   *data = position_;
1130   position_ += length;
1131   return true;
1132 }
1133 
TransferArrayBuffer(uint32_t transfer_id,Handle<JSArrayBuffer> array_buffer)1134 void ValueDeserializer::TransferArrayBuffer(
1135     uint32_t transfer_id, Handle<JSArrayBuffer> array_buffer) {
1136   if (array_buffer_transfer_map_.is_null()) {
1137     array_buffer_transfer_map_ = isolate_->global_handles()->Create(
1138         *SimpleNumberDictionary::New(isolate_, 0));
1139   }
1140   Handle<SimpleNumberDictionary> dictionary =
1141       array_buffer_transfer_map_.ToHandleChecked();
1142   Handle<SimpleNumberDictionary> new_dictionary = SimpleNumberDictionary::Set(
1143       isolate_, dictionary, transfer_id, array_buffer);
1144   if (!new_dictionary.is_identical_to(dictionary)) {
1145     GlobalHandles::Destroy(Handle<Object>::cast(dictionary).location());
1146     array_buffer_transfer_map_ =
1147         isolate_->global_handles()->Create(*new_dictionary);
1148   }
1149 }
1150 
ReadObject()1151 MaybeHandle<Object> ValueDeserializer::ReadObject() {
1152   MaybeHandle<Object> result = ReadObjectInternal();
1153 
1154   // ArrayBufferView is special in that it consumes the value before it, even
1155   // after format version 0.
1156   Handle<Object> object;
1157   SerializationTag tag;
1158   if (result.ToHandle(&object) && V8_UNLIKELY(object->IsJSArrayBuffer()) &&
1159       PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) {
1160     ConsumeTag(SerializationTag::kArrayBufferView);
1161     result = ReadJSArrayBufferView(Handle<JSArrayBuffer>::cast(object));
1162   }
1163 
1164   if (result.is_null() && !isolate_->has_pending_exception()) {
1165     isolate_->Throw(*isolate_->factory()->NewError(
1166         MessageTemplate::kDataCloneDeserializationError));
1167   }
1168 
1169   return result;
1170 }
1171 
ReadObjectInternal()1172 MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() {
1173   SerializationTag tag;
1174   if (!ReadTag().To(&tag)) return MaybeHandle<Object>();
1175   switch (tag) {
1176     case SerializationTag::kVerifyObjectCount:
1177       // Read the count and ignore it.
1178       if (ReadVarint<uint32_t>().IsNothing()) return MaybeHandle<Object>();
1179       return ReadObject();
1180     case SerializationTag::kUndefined:
1181       return isolate_->factory()->undefined_value();
1182     case SerializationTag::kNull:
1183       return isolate_->factory()->null_value();
1184     case SerializationTag::kTrue:
1185       return isolate_->factory()->true_value();
1186     case SerializationTag::kFalse:
1187       return isolate_->factory()->false_value();
1188     case SerializationTag::kInt32: {
1189       Maybe<int32_t> number = ReadZigZag<int32_t>();
1190       if (number.IsNothing()) return MaybeHandle<Object>();
1191       return isolate_->factory()->NewNumberFromInt(number.FromJust(),
1192                                                    pretenure_);
1193     }
1194     case SerializationTag::kUint32: {
1195       Maybe<uint32_t> number = ReadVarint<uint32_t>();
1196       if (number.IsNothing()) return MaybeHandle<Object>();
1197       return isolate_->factory()->NewNumberFromUint(number.FromJust(),
1198                                                     pretenure_);
1199     }
1200     case SerializationTag::kDouble: {
1201       Maybe<double> number = ReadDouble();
1202       if (number.IsNothing()) return MaybeHandle<Object>();
1203       return isolate_->factory()->NewNumber(number.FromJust(), pretenure_);
1204     }
1205     case SerializationTag::kBigInt:
1206       return ReadBigInt();
1207     case SerializationTag::kUtf8String:
1208       return ReadUtf8String();
1209     case SerializationTag::kOneByteString:
1210       return ReadOneByteString();
1211     case SerializationTag::kTwoByteString:
1212       return ReadTwoByteString();
1213     case SerializationTag::kObjectReference: {
1214       uint32_t id;
1215       if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>();
1216       return GetObjectWithID(id);
1217     }
1218     case SerializationTag::kBeginJSObject:
1219       return ReadJSObject();
1220     case SerializationTag::kBeginSparseJSArray:
1221       return ReadSparseJSArray();
1222     case SerializationTag::kBeginDenseJSArray:
1223       return ReadDenseJSArray();
1224     case SerializationTag::kDate:
1225       return ReadJSDate();
1226     case SerializationTag::kTrueObject:
1227     case SerializationTag::kFalseObject:
1228     case SerializationTag::kNumberObject:
1229     case SerializationTag::kBigIntObject:
1230     case SerializationTag::kStringObject:
1231       return ReadJSValue(tag);
1232     case SerializationTag::kRegExp:
1233       return ReadJSRegExp();
1234     case SerializationTag::kBeginJSMap:
1235       return ReadJSMap();
1236     case SerializationTag::kBeginJSSet:
1237       return ReadJSSet();
1238     case SerializationTag::kArrayBuffer: {
1239       const bool is_shared = false;
1240       return ReadJSArrayBuffer(is_shared);
1241     }
1242     case SerializationTag::kArrayBufferTransfer: {
1243       return ReadTransferredJSArrayBuffer();
1244     }
1245     case SerializationTag::kSharedArrayBuffer: {
1246       const bool is_shared = true;
1247       return ReadJSArrayBuffer(is_shared);
1248     }
1249     case SerializationTag::kWasmModule:
1250       return ReadWasmModule();
1251     case SerializationTag::kWasmModuleTransfer:
1252       return ReadWasmModuleTransfer();
1253     case SerializationTag::kWasmMemoryTransfer:
1254       return ReadWasmMemory();
1255     case SerializationTag::kHostObject:
1256       return ReadHostObject();
1257     default:
1258       // Before there was an explicit tag for host objects, all unknown tags
1259       // were delegated to the host.
1260       if (version_ < 13) {
1261         position_--;
1262         return ReadHostObject();
1263       }
1264       return MaybeHandle<Object>();
1265   }
1266 }
1267 
ReadString()1268 MaybeHandle<String> ValueDeserializer::ReadString() {
1269   if (version_ < 12) return ReadUtf8String();
1270   Handle<Object> object;
1271   if (!ReadObject().ToHandle(&object) || !object->IsString()) {
1272     return MaybeHandle<String>();
1273   }
1274   return Handle<String>::cast(object);
1275 }
1276 
ReadBigInt()1277 MaybeHandle<BigInt> ValueDeserializer::ReadBigInt() {
1278   if (!FLAG_harmony_bigint) return MaybeHandle<BigInt>();
1279   uint32_t bitfield;
1280   if (!ReadVarint<uint32_t>().To(&bitfield)) return MaybeHandle<BigInt>();
1281   int bytelength = BigInt::DigitsByteLengthForBitfield(bitfield);
1282   Vector<const uint8_t> digits_storage;
1283   if (!ReadRawBytes(bytelength).To(&digits_storage)) {
1284     return MaybeHandle<BigInt>();
1285   }
1286   return BigInt::FromSerializedDigits(isolate_, bitfield, digits_storage,
1287                                       pretenure_);
1288 }
1289 
ReadUtf8String()1290 MaybeHandle<String> ValueDeserializer::ReadUtf8String() {
1291   uint32_t utf8_length;
1292   Vector<const uint8_t> utf8_bytes;
1293   if (!ReadVarint<uint32_t>().To(&utf8_length) ||
1294       utf8_length >
1295           static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
1296       !ReadRawBytes(utf8_length).To(&utf8_bytes)) {
1297     return MaybeHandle<String>();
1298   }
1299   return isolate_->factory()->NewStringFromUtf8(
1300       Vector<const char>::cast(utf8_bytes), pretenure_);
1301 }
1302 
ReadOneByteString()1303 MaybeHandle<String> ValueDeserializer::ReadOneByteString() {
1304   uint32_t byte_length;
1305   Vector<const uint8_t> bytes;
1306   if (!ReadVarint<uint32_t>().To(&byte_length) ||
1307       byte_length >
1308           static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
1309       !ReadRawBytes(byte_length).To(&bytes)) {
1310     return MaybeHandle<String>();
1311   }
1312   return isolate_->factory()->NewStringFromOneByte(bytes, pretenure_);
1313 }
1314 
ReadTwoByteString()1315 MaybeHandle<String> ValueDeserializer::ReadTwoByteString() {
1316   uint32_t byte_length;
1317   Vector<const uint8_t> bytes;
1318   if (!ReadVarint<uint32_t>().To(&byte_length) ||
1319       byte_length >
1320           static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
1321       byte_length % sizeof(uc16) != 0 ||
1322       !ReadRawBytes(byte_length).To(&bytes)) {
1323     return MaybeHandle<String>();
1324   }
1325 
1326   // Allocate an uninitialized string so that we can do a raw memcpy into the
1327   // string on the heap (regardless of alignment).
1328   if (byte_length == 0) return isolate_->factory()->empty_string();
1329   Handle<SeqTwoByteString> string;
1330   if (!isolate_->factory()
1331            ->NewRawTwoByteString(byte_length / sizeof(uc16), pretenure_)
1332            .ToHandle(&string)) {
1333     return MaybeHandle<String>();
1334   }
1335 
1336   // Copy the bytes directly into the new string.
1337   // Warning: this uses host endianness.
1338   memcpy(string->GetChars(), bytes.begin(), bytes.length());
1339   return string;
1340 }
1341 
ReadExpectedString(Handle<String> expected)1342 bool ValueDeserializer::ReadExpectedString(Handle<String> expected) {
1343   DisallowHeapAllocation no_gc;
1344   // In the case of failure, the position in the stream is reset.
1345   const uint8_t* original_position = position_;
1346 
1347   SerializationTag tag;
1348   uint32_t byte_length;
1349   Vector<const uint8_t> bytes;
1350   if (!ReadTag().To(&tag) || !ReadVarint<uint32_t>().To(&byte_length) ||
1351       byte_length >
1352           static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
1353       !ReadRawBytes(byte_length).To(&bytes)) {
1354     position_ = original_position;
1355     return false;
1356   }
1357 
1358   String::FlatContent flat = expected->GetFlatContent();
1359 
1360   // If the bytes are verbatim what is in the flattened string, then the string
1361   // is successfully consumed.
1362   if (tag == SerializationTag::kOneByteString && flat.IsOneByte()) {
1363     Vector<const uint8_t> chars = flat.ToOneByteVector();
1364     if (byte_length == static_cast<size_t>(chars.length()) &&
1365         memcmp(bytes.begin(), chars.begin(), byte_length) == 0) {
1366       return true;
1367     }
1368   } else if (tag == SerializationTag::kTwoByteString && flat.IsTwoByte()) {
1369     Vector<const uc16> chars = flat.ToUC16Vector();
1370     if (byte_length == static_cast<unsigned>(chars.length()) * sizeof(uc16) &&
1371         memcmp(bytes.begin(), chars.begin(), byte_length) == 0) {
1372       return true;
1373     }
1374   } else if (tag == SerializationTag::kUtf8String && flat.IsOneByte()) {
1375     Vector<const uint8_t> chars = flat.ToOneByteVector();
1376     if (byte_length == static_cast<size_t>(chars.length()) &&
1377         String::IsAscii(chars.begin(), chars.length()) &&
1378         memcmp(bytes.begin(), chars.begin(), byte_length) == 0) {
1379       return true;
1380     }
1381   }
1382 
1383   position_ = original_position;
1384   return false;
1385 }
1386 
ReadJSObject()1387 MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() {
1388   // If we are at the end of the stack, abort. This function may recurse.
1389   STACK_CHECK(isolate_, MaybeHandle<JSObject>());
1390 
1391   uint32_t id = next_id_++;
1392   HandleScope scope(isolate_);
1393   Handle<JSObject> object =
1394       isolate_->factory()->NewJSObject(isolate_->object_function(), pretenure_);
1395   AddObjectWithID(id, object);
1396 
1397   uint32_t num_properties;
1398   uint32_t expected_num_properties;
1399   if (!ReadJSObjectProperties(object, SerializationTag::kEndJSObject, true)
1400            .To(&num_properties) ||
1401       !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1402       num_properties != expected_num_properties) {
1403     return MaybeHandle<JSObject>();
1404   }
1405 
1406   DCHECK(HasObjectWithID(id));
1407   return scope.CloseAndEscape(object);
1408 }
1409 
ReadSparseJSArray()1410 MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() {
1411   // If we are at the end of the stack, abort. This function may recurse.
1412   STACK_CHECK(isolate_, MaybeHandle<JSArray>());
1413 
1414   uint32_t length;
1415   if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>();
1416 
1417   uint32_t id = next_id_++;
1418   HandleScope scope(isolate_);
1419   Handle<JSArray> array = isolate_->factory()->NewJSArray(
1420       0, TERMINAL_FAST_ELEMENTS_KIND, pretenure_);
1421   JSArray::SetLength(array, length);
1422   AddObjectWithID(id, array);
1423 
1424   uint32_t num_properties;
1425   uint32_t expected_num_properties;
1426   uint32_t expected_length;
1427   if (!ReadJSObjectProperties(array, SerializationTag::kEndSparseJSArray, false)
1428            .To(&num_properties) ||
1429       !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1430       !ReadVarint<uint32_t>().To(&expected_length) ||
1431       num_properties != expected_num_properties || length != expected_length) {
1432     return MaybeHandle<JSArray>();
1433   }
1434 
1435   DCHECK(HasObjectWithID(id));
1436   return scope.CloseAndEscape(array);
1437 }
1438 
ReadDenseJSArray()1439 MaybeHandle<JSArray> ValueDeserializer::ReadDenseJSArray() {
1440   // If we are at the end of the stack, abort. This function may recurse.
1441   STACK_CHECK(isolate_, MaybeHandle<JSArray>());
1442 
1443   // We shouldn't permit an array larger than the biggest we can request from
1444   // V8. As an additional sanity check, since each entry will take at least one
1445   // byte to encode, if there are fewer bytes than that we can also fail fast.
1446   uint32_t length;
1447   if (!ReadVarint<uint32_t>().To(&length) ||
1448       length > static_cast<uint32_t>(FixedArray::kMaxLength) ||
1449       length > static_cast<size_t>(end_ - position_)) {
1450     return MaybeHandle<JSArray>();
1451   }
1452 
1453   uint32_t id = next_id_++;
1454   HandleScope scope(isolate_);
1455   Handle<JSArray> array = isolate_->factory()->NewJSArray(
1456       HOLEY_ELEMENTS, length, length, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE,
1457       pretenure_);
1458   AddObjectWithID(id, array);
1459 
1460   Handle<FixedArray> elements(FixedArray::cast(array->elements()), isolate_);
1461   for (uint32_t i = 0; i < length; i++) {
1462     SerializationTag tag;
1463     if (PeekTag().To(&tag) && tag == SerializationTag::kTheHole) {
1464       ConsumeTag(SerializationTag::kTheHole);
1465       continue;
1466     }
1467 
1468     Handle<Object> element;
1469     if (!ReadObject().ToHandle(&element)) return MaybeHandle<JSArray>();
1470 
1471     // Serialization versions less than 11 encode the hole the same as
1472     // undefined. For consistency with previous behavior, store these as the
1473     // hole. Past version 11, undefined means undefined.
1474     if (version_ < 11 && element->IsUndefined(isolate_)) continue;
1475 
1476     elements->set(i, *element);
1477   }
1478 
1479   uint32_t num_properties;
1480   uint32_t expected_num_properties;
1481   uint32_t expected_length;
1482   if (!ReadJSObjectProperties(array, SerializationTag::kEndDenseJSArray, false)
1483            .To(&num_properties) ||
1484       !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1485       !ReadVarint<uint32_t>().To(&expected_length) ||
1486       num_properties != expected_num_properties || length != expected_length) {
1487     return MaybeHandle<JSArray>();
1488   }
1489 
1490   DCHECK(HasObjectWithID(id));
1491   return scope.CloseAndEscape(array);
1492 }
1493 
ReadJSDate()1494 MaybeHandle<JSDate> ValueDeserializer::ReadJSDate() {
1495   double value;
1496   if (!ReadDouble().To(&value)) return MaybeHandle<JSDate>();
1497   uint32_t id = next_id_++;
1498   Handle<JSDate> date;
1499   if (!JSDate::New(isolate_->date_function(), isolate_->date_function(), value)
1500            .ToHandle(&date)) {
1501     return MaybeHandle<JSDate>();
1502   }
1503   AddObjectWithID(id, date);
1504   return date;
1505 }
1506 
ReadJSValue(SerializationTag tag)1507 MaybeHandle<JSValue> ValueDeserializer::ReadJSValue(SerializationTag tag) {
1508   uint32_t id = next_id_++;
1509   Handle<JSValue> value;
1510   switch (tag) {
1511     case SerializationTag::kTrueObject:
1512       value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
1513           isolate_->boolean_function(), pretenure_));
1514       value->set_value(ReadOnlyRoots(isolate_).true_value());
1515       break;
1516     case SerializationTag::kFalseObject:
1517       value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
1518           isolate_->boolean_function(), pretenure_));
1519       value->set_value(ReadOnlyRoots(isolate_).false_value());
1520       break;
1521     case SerializationTag::kNumberObject: {
1522       double number;
1523       if (!ReadDouble().To(&number)) return MaybeHandle<JSValue>();
1524       value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
1525           isolate_->number_function(), pretenure_));
1526       Handle<Object> number_object =
1527           isolate_->factory()->NewNumber(number, pretenure_);
1528       value->set_value(*number_object);
1529       break;
1530     }
1531     case SerializationTag::kBigIntObject: {
1532       Handle<BigInt> bigint;
1533       if (!ReadBigInt().ToHandle(&bigint)) return MaybeHandle<JSValue>();
1534       value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
1535           isolate_->bigint_function(), pretenure_));
1536       value->set_value(*bigint);
1537       break;
1538     }
1539     case SerializationTag::kStringObject: {
1540       Handle<String> string;
1541       if (!ReadString().ToHandle(&string)) return MaybeHandle<JSValue>();
1542       value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
1543           isolate_->string_function(), pretenure_));
1544       value->set_value(*string);
1545       break;
1546     }
1547     default:
1548       UNREACHABLE();
1549   }
1550   AddObjectWithID(id, value);
1551   return value;
1552 }
1553 
ReadJSRegExp()1554 MaybeHandle<JSRegExp> ValueDeserializer::ReadJSRegExp() {
1555   uint32_t id = next_id_++;
1556   Handle<String> pattern;
1557   uint32_t raw_flags;
1558   Handle<JSRegExp> regexp;
1559   if (!ReadString().ToHandle(&pattern) ||
1560       !ReadVarint<uint32_t>().To(&raw_flags)) {
1561     return MaybeHandle<JSRegExp>();
1562   }
1563 
1564   // Ensure the deserialized flags are valid.
1565   // TODO(adamk): Can we remove this check now that dotAll is always-on?
1566   uint32_t flags_mask = static_cast<uint32_t>(-1) << JSRegExp::FlagCount();
1567   if ((raw_flags & flags_mask) ||
1568       !JSRegExp::New(isolate_, pattern, static_cast<JSRegExp::Flags>(raw_flags))
1569            .ToHandle(&regexp)) {
1570     return MaybeHandle<JSRegExp>();
1571   }
1572 
1573   AddObjectWithID(id, regexp);
1574   return regexp;
1575 }
1576 
ReadJSMap()1577 MaybeHandle<JSMap> ValueDeserializer::ReadJSMap() {
1578   // If we are at the end of the stack, abort. This function may recurse.
1579   STACK_CHECK(isolate_, MaybeHandle<JSMap>());
1580 
1581   HandleScope scope(isolate_);
1582   uint32_t id = next_id_++;
1583   Handle<JSMap> map = isolate_->factory()->NewJSMap();
1584   AddObjectWithID(id, map);
1585 
1586   Handle<JSFunction> map_set = isolate_->map_set();
1587   uint32_t length = 0;
1588   while (true) {
1589     SerializationTag tag;
1590     if (!PeekTag().To(&tag)) return MaybeHandle<JSMap>();
1591     if (tag == SerializationTag::kEndJSMap) {
1592       ConsumeTag(SerializationTag::kEndJSMap);
1593       break;
1594     }
1595 
1596     Handle<Object> argv[2];
1597     if (!ReadObject().ToHandle(&argv[0]) || !ReadObject().ToHandle(&argv[1]) ||
1598         Execution::Call(isolate_, map_set, map, arraysize(argv), argv)
1599             .is_null()) {
1600       return MaybeHandle<JSMap>();
1601     }
1602     length += 2;
1603   }
1604 
1605   uint32_t expected_length;
1606   if (!ReadVarint<uint32_t>().To(&expected_length) ||
1607       length != expected_length) {
1608     return MaybeHandle<JSMap>();
1609   }
1610   DCHECK(HasObjectWithID(id));
1611   return scope.CloseAndEscape(map);
1612 }
1613 
ReadJSSet()1614 MaybeHandle<JSSet> ValueDeserializer::ReadJSSet() {
1615   // If we are at the end of the stack, abort. This function may recurse.
1616   STACK_CHECK(isolate_, MaybeHandle<JSSet>());
1617 
1618   HandleScope scope(isolate_);
1619   uint32_t id = next_id_++;
1620   Handle<JSSet> set = isolate_->factory()->NewJSSet();
1621   AddObjectWithID(id, set);
1622   Handle<JSFunction> set_add = isolate_->set_add();
1623   uint32_t length = 0;
1624   while (true) {
1625     SerializationTag tag;
1626     if (!PeekTag().To(&tag)) return MaybeHandle<JSSet>();
1627     if (tag == SerializationTag::kEndJSSet) {
1628       ConsumeTag(SerializationTag::kEndJSSet);
1629       break;
1630     }
1631 
1632     Handle<Object> argv[1];
1633     if (!ReadObject().ToHandle(&argv[0]) ||
1634         Execution::Call(isolate_, set_add, set, arraysize(argv), argv)
1635             .is_null()) {
1636       return MaybeHandle<JSSet>();
1637     }
1638     length++;
1639   }
1640 
1641   uint32_t expected_length;
1642   if (!ReadVarint<uint32_t>().To(&expected_length) ||
1643       length != expected_length) {
1644     return MaybeHandle<JSSet>();
1645   }
1646   DCHECK(HasObjectWithID(id));
1647   return scope.CloseAndEscape(set);
1648 }
1649 
ReadJSArrayBuffer(bool is_shared)1650 MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadJSArrayBuffer(
1651     bool is_shared) {
1652   uint32_t id = next_id_++;
1653   if (is_shared) {
1654     uint32_t clone_id;
1655     Local<SharedArrayBuffer> sab_value;
1656     if (!ReadVarint<uint32_t>().To(&clone_id) || delegate_ == nullptr ||
1657         !delegate_
1658              ->GetSharedArrayBufferFromId(
1659                  reinterpret_cast<v8::Isolate*>(isolate_), clone_id)
1660              .ToLocal(&sab_value)) {
1661       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSArrayBuffer);
1662       return MaybeHandle<JSArrayBuffer>();
1663     }
1664     Handle<JSArrayBuffer> array_buffer = Utils::OpenHandle(*sab_value);
1665     DCHECK_EQ(is_shared, array_buffer->is_shared());
1666     AddObjectWithID(id, array_buffer);
1667     return array_buffer;
1668   }
1669   uint32_t byte_length;
1670   if (!ReadVarint<uint32_t>().To(&byte_length) ||
1671       byte_length > static_cast<size_t>(end_ - position_)) {
1672     return MaybeHandle<JSArrayBuffer>();
1673   }
1674   const bool should_initialize = false;
1675   Handle<JSArrayBuffer> array_buffer =
1676       isolate_->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, pretenure_);
1677   if (!JSArrayBuffer::SetupAllocatingData(array_buffer, isolate_, byte_length,
1678                                           should_initialize)) {
1679     return MaybeHandle<JSArrayBuffer>();
1680   }
1681   memcpy(array_buffer->backing_store(), position_, byte_length);
1682   position_ += byte_length;
1683   AddObjectWithID(id, array_buffer);
1684   return array_buffer;
1685 }
1686 
ReadTransferredJSArrayBuffer()1687 MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadTransferredJSArrayBuffer() {
1688   uint32_t id = next_id_++;
1689   uint32_t transfer_id;
1690   Handle<SimpleNumberDictionary> transfer_map;
1691   if (!ReadVarint<uint32_t>().To(&transfer_id) ||
1692       !array_buffer_transfer_map_.ToHandle(&transfer_map)) {
1693     return MaybeHandle<JSArrayBuffer>();
1694   }
1695   int index = transfer_map->FindEntry(isolate_, transfer_id);
1696   if (index == SimpleNumberDictionary::kNotFound) {
1697     return MaybeHandle<JSArrayBuffer>();
1698   }
1699   Handle<JSArrayBuffer> array_buffer(
1700       JSArrayBuffer::cast(transfer_map->ValueAt(index)), isolate_);
1701   AddObjectWithID(id, array_buffer);
1702   return array_buffer;
1703 }
1704 
ReadJSArrayBufferView(Handle<JSArrayBuffer> buffer)1705 MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
1706     Handle<JSArrayBuffer> buffer) {
1707   uint32_t buffer_byte_length = NumberToUint32(buffer->byte_length());
1708   uint8_t tag = 0;
1709   uint32_t byte_offset = 0;
1710   uint32_t byte_length = 0;
1711   if (!ReadVarint<uint8_t>().To(&tag) ||
1712       !ReadVarint<uint32_t>().To(&byte_offset) ||
1713       !ReadVarint<uint32_t>().To(&byte_length) ||
1714       byte_offset > buffer_byte_length ||
1715       byte_length > buffer_byte_length - byte_offset) {
1716     return MaybeHandle<JSArrayBufferView>();
1717   }
1718   uint32_t id = next_id_++;
1719   ExternalArrayType external_array_type = kExternalInt8Array;
1720   unsigned element_size = 0;
1721 
1722   if (!FLAG_harmony_bigint) {
1723     // Refuse to construct BigInt64Arrays unless the flag is on.
1724     ArrayBufferViewTag cast_tag = static_cast<ArrayBufferViewTag>(tag);
1725     if (cast_tag == ArrayBufferViewTag::kBigInt64Array ||
1726         cast_tag == ArrayBufferViewTag::kBigUint64Array) {
1727       return MaybeHandle<JSArrayBufferView>();
1728     }
1729   }
1730 
1731   switch (static_cast<ArrayBufferViewTag>(tag)) {
1732     case ArrayBufferViewTag::kDataView: {
1733       Handle<JSDataView> data_view =
1734           isolate_->factory()->NewJSDataView(buffer, byte_offset, byte_length);
1735       AddObjectWithID(id, data_view);
1736       return data_view;
1737     }
1738 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
1739   case ArrayBufferViewTag::k##Type##Array:        \
1740     external_array_type = kExternal##Type##Array; \
1741     element_size = sizeof(ctype);                 \
1742     break;
1743       TYPED_ARRAYS(TYPED_ARRAY_CASE)
1744 #undef TYPED_ARRAY_CASE
1745   }
1746   if (element_size == 0 || byte_offset % element_size != 0 ||
1747       byte_length % element_size != 0) {
1748     return MaybeHandle<JSArrayBufferView>();
1749   }
1750   Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray(
1751       external_array_type, buffer, byte_offset, byte_length / element_size,
1752       pretenure_);
1753   AddObjectWithID(id, typed_array);
1754   return typed_array;
1755 }
1756 
ReadWasmModuleTransfer()1757 MaybeHandle<JSObject> ValueDeserializer::ReadWasmModuleTransfer() {
1758   auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
1759   if ((FLAG_wasm_disable_structured_cloning && !enabled_features.threads) ||
1760       expect_inline_wasm()) {
1761     return MaybeHandle<JSObject>();
1762   }
1763 
1764   uint32_t transfer_id = 0;
1765   Local<Value> module_value;
1766   if (!ReadVarint<uint32_t>().To(&transfer_id) || delegate_ == nullptr ||
1767       !delegate_
1768            ->GetWasmModuleFromId(reinterpret_cast<v8::Isolate*>(isolate_),
1769                                  transfer_id)
1770            .ToLocal(&module_value)) {
1771     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject);
1772     return MaybeHandle<JSObject>();
1773   }
1774   uint32_t id = next_id_++;
1775   Handle<JSObject> module =
1776       Handle<JSObject>::cast(Utils::OpenHandle(*module_value));
1777   AddObjectWithID(id, module);
1778   return module;
1779 }
1780 
ReadWasmModule()1781 MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() {
1782   auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
1783   if ((FLAG_wasm_disable_structured_cloning && !enabled_features.threads) ||
1784       !expect_inline_wasm()) {
1785     return MaybeHandle<JSObject>();
1786   }
1787 
1788   Vector<const uint8_t> encoding_tag;
1789   if (!ReadRawBytes(sizeof(WasmEncodingTag)).To(&encoding_tag) ||
1790       encoding_tag[0] != static_cast<uint8_t>(WasmEncodingTag::kRawBytes)) {
1791     return MaybeHandle<JSObject>();
1792   }
1793 
1794   // Extract the data from the buffer: wasm wire bytes, followed by V8 compiled
1795   // script data.
1796   static_assert(sizeof(int) <= sizeof(uint32_t),
1797                 "max int must fit in uint32_t");
1798   const uint32_t max_valid_size = std::numeric_limits<int>::max();
1799   uint32_t wire_bytes_length = 0;
1800   Vector<const uint8_t> wire_bytes;
1801   uint32_t compiled_bytes_length = 0;
1802   Vector<const uint8_t> compiled_bytes;
1803   if (!ReadVarint<uint32_t>().To(&wire_bytes_length) ||
1804       wire_bytes_length > max_valid_size ||
1805       !ReadRawBytes(wire_bytes_length).To(&wire_bytes) ||
1806       !ReadVarint<uint32_t>().To(&compiled_bytes_length) ||
1807       compiled_bytes_length > max_valid_size ||
1808       !ReadRawBytes(compiled_bytes_length).To(&compiled_bytes)) {
1809     return MaybeHandle<JSObject>();
1810   }
1811 
1812   // Try to deserialize the compiled module first.
1813   MaybeHandle<WasmModuleObject> result =
1814       wasm::DeserializeNativeModule(isolate_, compiled_bytes, wire_bytes);
1815   if (result.is_null()) {
1816     wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule");
1817     // TODO(titzer): are the current features appropriate for deserializing?
1818     auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
1819     result = isolate_->wasm_engine()->SyncCompile(
1820         isolate_, enabled_features, &thrower,
1821         wasm::ModuleWireBytes(wire_bytes));
1822   }
1823   uint32_t id = next_id_++;
1824   if (!result.is_null()) {
1825     AddObjectWithID(id, result.ToHandleChecked());
1826   }
1827   return result;
1828 }
1829 
ReadWasmMemory()1830 MaybeHandle<WasmMemoryObject> ValueDeserializer::ReadWasmMemory() {
1831   uint32_t id = next_id_++;
1832 
1833   auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
1834   if (!enabled_features.threads) {
1835     return MaybeHandle<WasmMemoryObject>();
1836   }
1837 
1838   int32_t maximum_pages;
1839   if (!ReadZigZag<int32_t>().To(&maximum_pages)) {
1840     return MaybeHandle<WasmMemoryObject>();
1841   }
1842 
1843   SerializationTag tag;
1844   if (!ReadTag().To(&tag) || tag != SerializationTag::kSharedArrayBuffer) {
1845     return MaybeHandle<WasmMemoryObject>();
1846   }
1847 
1848   const bool is_shared = true;
1849   Handle<JSArrayBuffer> buffer;
1850   if (!ReadJSArrayBuffer(is_shared).ToHandle(&buffer)) {
1851     return MaybeHandle<WasmMemoryObject>();
1852   }
1853 
1854   Handle<WasmMemoryObject> result =
1855       WasmMemoryObject::New(isolate_, buffer, maximum_pages);
1856 
1857   AddObjectWithID(id, result);
1858   return result;
1859 }
1860 
ReadHostObject()1861 MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() {
1862   if (!delegate_) return MaybeHandle<JSObject>();
1863   STACK_CHECK(isolate_, MaybeHandle<JSObject>());
1864   uint32_t id = next_id_++;
1865   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
1866   v8::Local<v8::Object> object;
1867   if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) {
1868     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject);
1869     return MaybeHandle<JSObject>();
1870   }
1871   Handle<JSObject> js_object =
1872       Handle<JSObject>::cast(Utils::OpenHandle(*object));
1873   AddObjectWithID(id, js_object);
1874   return js_object;
1875 }
1876 
1877 // Copies a vector of property values into an object, given the map that should
1878 // be used.
CommitProperties(Handle<JSObject> object,Handle<Map> map,const std::vector<Handle<Object>> & properties)1879 static void CommitProperties(Handle<JSObject> object, Handle<Map> map,
1880                              const std::vector<Handle<Object>>& properties) {
1881   JSObject::AllocateStorageForMap(object, map);
1882   DCHECK(!object->map()->is_dictionary_map());
1883 
1884   DisallowHeapAllocation no_gc;
1885   DescriptorArray* descriptors = object->map()->instance_descriptors();
1886   for (unsigned i = 0; i < properties.size(); i++) {
1887     // Initializing store.
1888     object->WriteToField(i, descriptors->GetDetails(i), *properties[i]);
1889   }
1890 }
1891 
IsValidObjectKey(Handle<Object> value)1892 static bool IsValidObjectKey(Handle<Object> value) {
1893   return value->IsName() || value->IsNumber();
1894 }
1895 
ReadJSObjectProperties(Handle<JSObject> object,SerializationTag end_tag,bool can_use_transitions)1896 Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
1897     Handle<JSObject> object, SerializationTag end_tag,
1898     bool can_use_transitions) {
1899   uint32_t num_properties = 0;
1900 
1901   // Fast path (following map transitions).
1902   if (can_use_transitions) {
1903     bool transitioning = true;
1904     Handle<Map> map(object->map(), isolate_);
1905     DCHECK(!map->is_dictionary_map());
1906     DCHECK_EQ(0, map->instance_descriptors()->number_of_descriptors());
1907     std::vector<Handle<Object>> properties;
1908     properties.reserve(8);
1909 
1910     while (transitioning) {
1911       // If there are no more properties, finish.
1912       SerializationTag tag;
1913       if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
1914       if (tag == end_tag) {
1915         ConsumeTag(end_tag);
1916         CommitProperties(object, map, properties);
1917         CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max());
1918         return Just(static_cast<uint32_t>(properties.size()));
1919       }
1920 
1921       // Determine the key to be used and the target map to transition to, if
1922       // possible. Transitioning may abort if the key is not a string, or if no
1923       // transition was found.
1924       Handle<Object> key;
1925       Handle<Map> target;
1926       TransitionsAccessor transitions(isolate_, map);
1927       Handle<String> expected_key = transitions.ExpectedTransitionKey();
1928       if (!expected_key.is_null() && ReadExpectedString(expected_key)) {
1929         key = expected_key;
1930         target = transitions.ExpectedTransitionTarget();
1931       } else {
1932         if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(key)) {
1933           return Nothing<uint32_t>();
1934         }
1935         if (key->IsString()) {
1936           key =
1937               isolate_->factory()->InternalizeString(Handle<String>::cast(key));
1938           // Don't reuse |transitions| because it could be stale.
1939           transitioning = TransitionsAccessor(isolate_, map)
1940                               .FindTransitionToField(Handle<String>::cast(key))
1941                               .ToHandle(&target);
1942         } else {
1943           transitioning = false;
1944         }
1945       }
1946 
1947       // Read the value that corresponds to it.
1948       Handle<Object> value;
1949       if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
1950 
1951       // If still transitioning and the value fits the field representation
1952       // (though generalization may be required), store the property value so
1953       // that we can copy them all at once. Otherwise, stop transitioning.
1954       if (transitioning) {
1955         int descriptor = static_cast<int>(properties.size());
1956         PropertyDetails details =
1957             target->instance_descriptors()->GetDetails(descriptor);
1958         Representation expected_representation = details.representation();
1959         if (value->FitsRepresentation(expected_representation)) {
1960           if (expected_representation.IsHeapObject() &&
1961               !target->instance_descriptors()
1962                    ->GetFieldType(descriptor)
1963                    ->NowContains(value)) {
1964             Handle<FieldType> value_type =
1965                 value->OptimalType(isolate_, expected_representation);
1966             Map::GeneralizeField(isolate_, target, descriptor,
1967                                  details.constness(), expected_representation,
1968                                  value_type);
1969           }
1970           DCHECK(target->instance_descriptors()
1971                      ->GetFieldType(descriptor)
1972                      ->NowContains(value));
1973           properties.push_back(value);
1974           map = target;
1975           continue;
1976         } else {
1977           transitioning = false;
1978         }
1979       }
1980 
1981       // Fell out of transitioning fast path. Commit the properties gathered so
1982       // far, and then start setting properties slowly instead.
1983       DCHECK(!transitioning);
1984       CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max());
1985       CommitProperties(object, map, properties);
1986       num_properties = static_cast<uint32_t>(properties.size());
1987 
1988       bool success;
1989       LookupIterator it = LookupIterator::PropertyOrElement(
1990           isolate_, object, key, &success, LookupIterator::OWN);
1991       if (!success ||
1992           JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
1993               .is_null()) {
1994         return Nothing<uint32_t>();
1995       }
1996       num_properties++;
1997     }
1998 
1999     // At this point, transitioning should be done, but at least one property
2000     // should have been written (in the zero-property case, there is an early
2001     // return).
2002     DCHECK(!transitioning);
2003     DCHECK_GE(num_properties, 1u);
2004   }
2005 
2006   // Slow path.
2007   for (;; num_properties++) {
2008     SerializationTag tag;
2009     if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
2010     if (tag == end_tag) {
2011       ConsumeTag(end_tag);
2012       return Just(num_properties);
2013     }
2014 
2015     Handle<Object> key;
2016     if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(key)) {
2017       return Nothing<uint32_t>();
2018     }
2019     Handle<Object> value;
2020     if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
2021 
2022     bool success;
2023     LookupIterator it = LookupIterator::PropertyOrElement(
2024         isolate_, object, key, &success, LookupIterator::OWN);
2025     if (!success ||
2026         JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
2027             .is_null()) {
2028       return Nothing<uint32_t>();
2029     }
2030   }
2031 }
2032 
HasObjectWithID(uint32_t id)2033 bool ValueDeserializer::HasObjectWithID(uint32_t id) {
2034   return id < static_cast<unsigned>(id_map_->length()) &&
2035          !id_map_->get(id)->IsTheHole(isolate_);
2036 }
2037 
GetObjectWithID(uint32_t id)2038 MaybeHandle<JSReceiver> ValueDeserializer::GetObjectWithID(uint32_t id) {
2039   if (id >= static_cast<unsigned>(id_map_->length())) {
2040     return MaybeHandle<JSReceiver>();
2041   }
2042   Object* value = id_map_->get(id);
2043   if (value->IsTheHole(isolate_)) return MaybeHandle<JSReceiver>();
2044   DCHECK(value->IsJSReceiver());
2045   return Handle<JSReceiver>(JSReceiver::cast(value), isolate_);
2046 }
2047 
AddObjectWithID(uint32_t id,Handle<JSReceiver> object)2048 void ValueDeserializer::AddObjectWithID(uint32_t id,
2049                                         Handle<JSReceiver> object) {
2050   DCHECK(!HasObjectWithID(id));
2051   Handle<FixedArray> new_array =
2052       FixedArray::SetAndGrow(isolate_, id_map_, id, object);
2053 
2054   // If the dictionary was reallocated, update the global handle.
2055   if (!new_array.is_identical_to(id_map_)) {
2056     GlobalHandles::Destroy(Handle<Object>::cast(id_map_).location());
2057     id_map_ = isolate_->global_handles()->Create(*new_array);
2058   }
2059 }
2060 
SetPropertiesFromKeyValuePairs(Isolate * isolate,Handle<JSObject> object,Handle<Object> * data,uint32_t num_properties)2061 static Maybe<bool> SetPropertiesFromKeyValuePairs(Isolate* isolate,
2062                                                   Handle<JSObject> object,
2063                                                   Handle<Object>* data,
2064                                                   uint32_t num_properties) {
2065   for (unsigned i = 0; i < 2 * num_properties; i += 2) {
2066     Handle<Object> key = data[i];
2067     if (!IsValidObjectKey(key)) return Nothing<bool>();
2068     Handle<Object> value = data[i + 1];
2069     bool success;
2070     LookupIterator it = LookupIterator::PropertyOrElement(
2071         isolate, object, key, &success, LookupIterator::OWN);
2072     if (!success ||
2073         JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
2074             .is_null()) {
2075       return Nothing<bool>();
2076     }
2077   }
2078   return Just(true);
2079 }
2080 
2081 namespace {
2082 
2083 // Throws a generic "deserialization failed" exception by default, unless a more
2084 // specific exception has already been thrown.
ThrowDeserializationExceptionIfNonePending(Isolate * isolate)2085 void ThrowDeserializationExceptionIfNonePending(Isolate* isolate) {
2086   if (!isolate->has_pending_exception()) {
2087     isolate->Throw(*isolate->factory()->NewError(
2088         MessageTemplate::kDataCloneDeserializationError));
2089   }
2090   DCHECK(isolate->has_pending_exception());
2091 }
2092 
2093 }  // namespace
2094 
2095 MaybeHandle<Object>
ReadObjectUsingEntireBufferForLegacyFormat()2096 ValueDeserializer::ReadObjectUsingEntireBufferForLegacyFormat() {
2097   DCHECK_EQ(version_, 0u);
2098   HandleScope scope(isolate_);
2099   std::vector<Handle<Object>> stack;
2100   while (position_ < end_) {
2101     SerializationTag tag;
2102     if (!PeekTag().To(&tag)) break;
2103 
2104     Handle<Object> new_object;
2105     switch (tag) {
2106       case SerializationTag::kEndJSObject: {
2107         ConsumeTag(SerializationTag::kEndJSObject);
2108 
2109         // JS Object: Read the last 2*n values from the stack and use them as
2110         // key-value pairs.
2111         uint32_t num_properties;
2112         if (!ReadVarint<uint32_t>().To(&num_properties) ||
2113             stack.size() / 2 < num_properties) {
2114           isolate_->Throw(*isolate_->factory()->NewError(
2115               MessageTemplate::kDataCloneDeserializationError));
2116           return MaybeHandle<Object>();
2117         }
2118 
2119         size_t begin_properties =
2120             stack.size() - 2 * static_cast<size_t>(num_properties);
2121         Handle<JSObject> js_object = isolate_->factory()->NewJSObject(
2122             isolate_->object_function(), pretenure_);
2123         if (num_properties &&
2124             !SetPropertiesFromKeyValuePairs(
2125                  isolate_, js_object, &stack[begin_properties], num_properties)
2126                  .FromMaybe(false)) {
2127           ThrowDeserializationExceptionIfNonePending(isolate_);
2128           return MaybeHandle<Object>();
2129         }
2130 
2131         stack.resize(begin_properties);
2132         new_object = js_object;
2133         break;
2134       }
2135       case SerializationTag::kEndSparseJSArray: {
2136         ConsumeTag(SerializationTag::kEndSparseJSArray);
2137 
2138         // Sparse JS Array: Read the last 2*|num_properties| from the stack.
2139         uint32_t num_properties;
2140         uint32_t length;
2141         if (!ReadVarint<uint32_t>().To(&num_properties) ||
2142             !ReadVarint<uint32_t>().To(&length) ||
2143             stack.size() / 2 < num_properties) {
2144           isolate_->Throw(*isolate_->factory()->NewError(
2145               MessageTemplate::kDataCloneDeserializationError));
2146           return MaybeHandle<Object>();
2147         }
2148 
2149         Handle<JSArray> js_array = isolate_->factory()->NewJSArray(
2150             0, TERMINAL_FAST_ELEMENTS_KIND, pretenure_);
2151         JSArray::SetLength(js_array, length);
2152         size_t begin_properties =
2153             stack.size() - 2 * static_cast<size_t>(num_properties);
2154         if (num_properties &&
2155             !SetPropertiesFromKeyValuePairs(
2156                  isolate_, js_array, &stack[begin_properties], num_properties)
2157                  .FromMaybe(false)) {
2158           ThrowDeserializationExceptionIfNonePending(isolate_);
2159           return MaybeHandle<Object>();
2160         }
2161 
2162         stack.resize(begin_properties);
2163         new_object = js_array;
2164         break;
2165       }
2166       case SerializationTag::kEndDenseJSArray: {
2167         // This was already broken in Chromium, and apparently wasn't missed.
2168         isolate_->Throw(*isolate_->factory()->NewError(
2169             MessageTemplate::kDataCloneDeserializationError));
2170         return MaybeHandle<Object>();
2171       }
2172       default:
2173         if (!ReadObject().ToHandle(&new_object)) return MaybeHandle<Object>();
2174         break;
2175     }
2176     stack.push_back(new_object);
2177   }
2178 
2179 // Nothing remains but padding.
2180 #ifdef DEBUG
2181   while (position_ < end_) {
2182     DCHECK(*position_++ == static_cast<uint8_t>(SerializationTag::kPadding));
2183   }
2184 #endif
2185   position_ = end_;
2186 
2187   if (stack.size() != 1) {
2188     isolate_->Throw(*isolate_->factory()->NewError(
2189         MessageTemplate::kDataCloneDeserializationError));
2190     return MaybeHandle<Object>();
2191   }
2192   return scope.CloseAndEscape(stack[0]);
2193 }
2194 
2195 }  // namespace internal
2196 }  // namespace v8
2197