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