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