LCOV - code coverage report
Current view: top level - src - value-serializer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 851 937 90.8 %
Date: 2019-02-19 Functions: 86 95 90.5 %

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

Generated by: LCOV version 1.10