LCOV - code coverage report
Current view: top level - src - value-serializer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 848 942 90.0 %
Date: 2019-03-21 Functions: 83 93 89.2 %

          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        2022 : 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        6072 :                                  ZoneAllocationPolicy(&zone_)) {}
     197             : 
     198        4055 : ValueSerializer::~ValueSerializer() {
     199        2027 :   if (buffer_) {
     200          36 :     if (delegate_) {
     201          30 :       delegate_->FreeBufferMemory(buffer_);
     202             :     } else {
     203           6 :       free(buffer_);
     204             :     }
     205             :   }
     206        2028 : }
     207             : 
     208        1858 : void ValueSerializer::WriteHeader() {
     209             :   WriteTag(SerializationTag::kVersion);
     210        1863 :   WriteVarint(kLatestVersion);
     211        1858 : }
     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       14686 :   uint8_t raw_tag = static_cast<uint8_t>(tag);
     219       14686 :   WriteRawBytes(&raw_tag, sizeof(raw_tag));
     220           0 : }
     221             : 
     222             : template <typename T>
     223       11567 : 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       11752 :   do {
     233       11752 :     *next_byte = (value & 0x7F) | 0x80;
     234       11752 :     next_byte++;
     235       11752 :     value >>= 7;
     236             :   } while (value);
     237       11567 :   *(next_byte - 1) &= 0x7F;
     238       11567 :   WriteRawBytes(stack_buffer, next_byte - stack_buffer);
     239       11584 : }
     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        1225 :   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          24 :   WriteRawBytes(&value, sizeof(value));
     257           4 : }
     258             : 
     259           0 : void ValueSerializer::WriteOneByteString(Vector<const uint8_t> chars) {
     260        4253 :   WriteVarint<uint32_t>(chars.length());
     261        4252 :   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       30585 : void ValueSerializer::WriteRawBytes(const void* source, size_t length) {
     281             :   uint8_t* dest;
     282       61192 :   if (ReserveRawBytes(length).To(&dest) && length > 0) {
     283             :     memcpy(dest, source, length);
     284             :   }
     285       30607 : }
     286             : 
     287       30607 : Maybe<uint8_t*> ValueSerializer::ReserveRawBytes(size_t bytes) {
     288       30607 :   size_t old_size = buffer_size_;
     289       30607 :   size_t new_size = old_size + bytes;
     290       30607 :   if (V8_UNLIKELY(new_size > buffer_capacity_)) {
     291             :     bool ok;
     292        3861 :     if (!ExpandBuffer(new_size).To(&ok)) {
     293             :       return Nothing<uint8_t*>();
     294             :     }
     295             :   }
     296       30611 :   buffer_size_ = new_size;
     297       30611 :   return Just(&buffer_[old_size]);
     298             : }
     299             : 
     300        1928 : Maybe<bool> ValueSerializer::ExpandBuffer(size_t required_capacity) {
     301             :   DCHECK_GT(required_capacity, buffer_capacity_);
     302             :   size_t requested_capacity =
     303        3856 :       std::max(required_capacity, buffer_capacity_ * 2) + 64;
     304        1928 :   size_t provided_capacity = 0;
     305             :   void* new_buffer = nullptr;
     306        1928 :   if (delegate_) {
     307        1788 :     new_buffer = delegate_->ReallocateBufferMemory(buffer_, requested_capacity,
     308        3576 :                                                    &provided_capacity);
     309             :   } else {
     310         140 :     new_buffer = realloc(buffer_, requested_capacity);
     311         140 :     provided_capacity = requested_capacity;
     312             :   }
     313        1934 :   if (new_buffer) {
     314             :     DCHECK(provided_capacity >= requested_capacity);
     315        1931 :     buffer_ = reinterpret_cast<uint8_t*>(new_buffer);
     316        1931 :     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        1810 : std::pair<uint8_t*, size_t> ValueSerializer::Release() {
     333             :   auto result = std::make_pair(buffer_, buffer_size_);
     334        1810 :   buffer_ = nullptr;
     335        1810 :   buffer_size_ = 0;
     336        1810 :   buffer_capacity_ = 0;
     337        1810 :   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             :   array_buffer_transfer_map_.Set(array_buffer, transfer_id);
     345          47 : }
     346             : 
     347       11990 : 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       11990 :   if (V8_UNLIKELY(out_of_memory_)) return ThrowIfOutOfMemory();
     352             : 
     353       11990 :   if (object->IsSmi()) {
     354        1066 :     WriteSmi(Smi::cast(*object));
     355        1072 :     return ThrowIfOutOfMemory();
     356             :   }
     357             : 
     358             :   DCHECK(object->IsHeapObject());
     359       10924 :   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          13 :       WriteHeapNumber(HeapNumber::cast(*object));
     365          13 :       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             :       Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(object);
     380          55 :       if (!id_map_.Find(view) && !treat_array_buffer_views_as_host_objects_) {
     381             :         Handle<JSArrayBuffer> buffer(
     382             :             view->IsJSTypedArray()
     383         103 :                 ? Handle<JSTypedArray>::cast(view)->GetBuffer()
     384         103 :                 : handle(JSArrayBuffer::cast(view->buffer()), isolate_));
     385         104 :         if (!WriteJSReceiver(buffer).FromMaybe(false)) return Nothing<bool>();
     386             :       }
     387          55 :       return WriteJSReceiver(view);
     388             :     }
     389             :     default:
     390       10717 :       if (object->IsString()) {
     391        4260 :         WriteString(Handle<String>::cast(object));
     392        4257 :         return ThrowIfOutOfMemory();
     393        6457 :       } else if (object->IsJSReceiver()) {
     394        6457 :         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        1073 : 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        1080 : }
     429             : 
     430          13 : void ValueSerializer::WriteHeapNumber(HeapNumber number) {
     431             :   WriteTag(SerializationTag::kDouble);
     432             :   WriteDouble(number->value());
     433          13 : }
     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        4266 : void ValueSerializer::WriteString(Handle<String> string) {
     446        4266 :   string = String::Flatten(isolate_, string);
     447             :   DisallowHeapAllocation no_gc;
     448        4267 :   String::FlatContent flat = string->GetFlatContent(no_gc);
     449             :   DCHECK(flat.IsFlat());
     450        4264 :   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        4265 : }
     466             : 
     467        6712 : Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
     468             :   // If the object has already been serialized, just write its ID.
     469             :   uint32_t* id_map_entry = id_map_.Get(receiver);
     470        6711 :   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        6672 :   uint32_t id = next_id_++;
     478        6672 :   *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        6672 :   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       13344 :   STACK_CHECK(isolate_, Nothing<bool>());
     490             : 
     491        6670 :   HandleScope scope(isolate_);
     492        6670 :   switch (instance_type) {
     493             :     case JS_ARRAY_TYPE:
     494        2694 :       return WriteJSArray(Handle<JSArray>::cast(receiver));
     495             :     case JS_OBJECT_TYPE:
     496             :     case JS_API_OBJECT_TYPE: {
     497             :       Handle<JSObject> js_object = Handle<JSObject>::cast(receiver);
     498        3102 :       if (JSObject::GetEmbedderFieldCount(js_object->map())) {
     499          15 :         return WriteHostObject(js_object);
     500             :       } else {
     501        3087 :         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         508 :       return WriteJSArrayBuffer(Handle<JSArrayBuffer>::cast(receiver));
     520             :     case JS_TYPED_ARRAY_TYPE:
     521             :     case JS_DATA_VIEW_TYPE:
     522          53 :       return WriteJSArrayBufferView(JSArrayBufferView::cast(*receiver));
     523             :     case WASM_MODULE_TYPE: {
     524         124 :       auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
     525         124 :       if (!FLAG_wasm_disable_structured_cloning || enabled_features.threads) {
     526             :         // Only write WebAssembly modules if not disabled by a flag.
     527         124 :         return WriteWasmModule(Handle<WasmModuleObject>::cast(receiver));
     528             :       }
     529           0 :       break;
     530             :     }
     531             :     case WASM_MEMORY_TYPE: {
     532         161 :       auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
     533         161 :       if (enabled_features.threads) {
     534         161 :         return WriteWasmMemory(Handle<WasmMemoryObject>::cast(receiver));
     535             :       }
     536           0 :       break;
     537             :     }
     538             :     default:
     539             :       break;
     540             :   }
     541             : 
     542           0 :   ThrowDataCloneError(MessageTemplate::kDataCloneError, receiver);
     543             :   return Nothing<bool>();
     544             : }
     545             : 
     546        3087 : Maybe<bool> ValueSerializer::WriteJSObject(Handle<JSObject> object) {
     547             :   DCHECK(!object->map()->IsCustomElementsReceiverMap());
     548             :   const bool can_serialize_fast =
     549        6143 :       object->HasFastProperties() && object->elements()->length() == 0;
     550        3091 :   if (!can_serialize_fast) return WriteJSObjectSlow(object);
     551             : 
     552        3057 :   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        5239 :   for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
     560       10874 :     Handle<Name> key(map->instance_descriptors()->GetKey(i), isolate_);
     561        3626 :     if (!key->IsString()) continue;
     562        3623 :     PropertyDetails details = map->instance_descriptors()->GetDetails(i);
     563        3623 :     if (details.IsDontEnum()) continue;
     564             : 
     565             :     Handle<Object> value;
     566        3622 :     if (V8_LIKELY(!map_changed)) map_changed = *map == object->map();
     567        3622 :     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        3622 :       LookupIterator it(isolate_, object, key, LookupIterator::OWN);
     577        3624 :       if (!it.IsFound()) continue;
     578        7247 :       if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<bool>();
     579             :     }
     580             : 
     581       10844 :     if (!WriteObject(key).FromMaybe(false) ||
     582        3614 :         !WriteObject(value).FromMaybe(false)) {
     583             :       return Nothing<bool>();
     584             :     }
     585        1091 :     properties_written++;
     586             :   }
     587             : 
     588             :   WriteTag(SerializationTag::kEndJSObject);
     589         520 :   WriteVarint<uint32_t>(properties_written);
     590         522 :   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         102 :   if (!KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
     598          34 :                                ENUMERABLE_STRINGS)
     599          68 :            .ToHandle(&keys) ||
     600          34 :       !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        2694 : Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) {
     609        2694 :   uint32_t length = 0;
     610        5388 :   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       10770 :       array->HasFastElements() && !array->HasHoleyElements();
     621             : 
     622        2694 :   if (should_serialize_densely) {
     623             :     DCHECK_LE(length, static_cast<uint32_t>(FixedArray::kMaxLength));
     624             :     WriteTag(SerializationTag::kBeginDenseJSArray);
     625        2681 :     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        2681 :     switch (array->GetElementsKind()) {
     631             :       case PACKED_SMI_ELEMENTS: {
     632             :         Handle<FixedArray> elements(FixedArray::cast(array->elements()),
     633          11 :                                     isolate_);
     634          25 :         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        2670 :         Handle<Object> old_length(array->length(), isolate_);
     651        2858 :         for (; i < length; i++) {
     652        8185 :           if (array->length() != *old_length ||
     653        5456 :               array->GetElementsKind() != PACKED_ELEMENTS) {
     654             :             // Fall back to slow path.
     655             :             break;
     656             :           }
     657             :           Handle<Object> element(FixedArray::cast(array->elements())->get(i),
     658        2724 :                                  isolate_);
     659        5448 :           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          65 :     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           6 :       if (!Object::GetProperty(&it).ToHandle(&element) ||
     682           2 :           !WriteObject(element).FromMaybe(false)) {
     683           0 :         return Nothing<bool>();
     684             :       }
     685             :     }
     686             : 
     687          51 :     KeyAccumulator accumulator(isolate_, KeyCollectionMode::kOwnOnly,
     688             :                                ENUMERABLE_STRINGS);
     689         102 :     if (!accumulator.CollectOwnPropertyNames(array, array).FromMaybe(false)) {
     690             :       return Nothing<bool>();
     691             :     }
     692             :     Handle<FixedArray> keys =
     693          51 :         accumulator.GetKeys(GetKeysConversion::kConvertToString);
     694             :     uint32_t properties_written;
     695         102 :     if (!WriteJSObjectPropertiesSlow(array, keys).To(&properties_written)) {
     696             :       return Nothing<bool>();
     697             :     }
     698             :     WriteTag(SerializationTag::kEndDenseJSArray);
     699          51 :     WriteVarint<uint32_t>(properties_written);
     700          51 :     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          39 :     if (!KeyAccumulator::GetKeys(array, KeyCollectionMode::kOwnOnly,
     707          13 :                                  ENUMERABLE_STRINGS)
     708          26 :              .ToHandle(&keys) ||
     709          13 :         !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          64 :   return ThrowIfOutOfMemory();
     717             : }
     718             : 
     719           4 : void ValueSerializer::WriteJSDate(JSDate date) {
     720             :   WriteTag(SerializationTag::kDate);
     721             :   WriteDouble(date->value()->Number());
     722           4 : }
     723             : 
     724          11 : Maybe<bool> ValueSerializer::WriteJSValue(Handle<JSValue> value) {
     725             :   Object inner_value = value->value();
     726          22 :   if (inner_value->IsTrue(isolate_)) {
     727             :     WriteTag(SerializationTag::kTrueObject);
     728           9 :   } else if (inner_value->IsFalse(isolate_)) {
     729             :     WriteTag(SerializationTag::kFalseObject);
     730           8 :   } else if (inner_value->IsNumber()) {
     731             :     WriteTag(SerializationTag::kNumberObject);
     732             :     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          25 :     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          45 :   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             :   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          27 :     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          27 :   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         508 : Maybe<bool> ValueSerializer::WriteJSArrayBuffer(
     815             :     Handle<JSArrayBuffer> array_buffer) {
     816         508 :   if (array_buffer->is_shared()) {
     817         416 :     if (!delegate_) {
     818           0 :       ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer);
     819             :       return Nothing<bool>();
     820             :     }
     821             : 
     822         416 :     v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
     823             :     Maybe<uint32_t> index = delegate_->GetSharedArrayBufferId(
     824         416 :         v8_isolate, Utils::ToLocalShared(array_buffer));
     825         832 :     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
     826             : 
     827             :     WriteTag(SerializationTag::kSharedArrayBuffer);
     828         416 :     WriteVarint(index.FromJust());
     829         416 :     return ThrowIfOutOfMemory();
     830             :   }
     831             : 
     832             :   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          53 : Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView view) {
     854          53 :   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          52 :   if (view->IsJSTypedArray()) {
     860          51 :     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          11 :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
     866             : #undef TYPED_ARRAY_CASE
     867             :     }
     868             :   } else {
     869             :     DCHECK(view->IsJSDataView());
     870             :     tag = ArrayBufferViewTag::kDataView;
     871             :   }
     872          52 :   WriteVarint(static_cast<uint8_t>(tag));
     873          52 :   WriteVarint(static_cast<uint32_t>(view->byte_offset()));
     874          52 :   WriteVarint(static_cast<uint32_t>(view->byte_length()));
     875          52 :   return ThrowIfOutOfMemory();
     876             : }
     877             : 
     878         124 : Maybe<bool> ValueSerializer::WriteWasmModule(Handle<WasmModuleObject> object) {
     879         124 :   if (delegate_ != nullptr) {
     880             :     // TODO(titzer): introduce a Utils::ToLocal for WasmModuleObject.
     881             :     Maybe<uint32_t> transfer_id = delegate_->GetWasmModuleTransferId(
     882         119 :         reinterpret_cast<v8::Isolate*>(isolate_),
     883             :         v8::Local<v8::WasmModuleObject>::Cast(
     884         238 :             Utils::ToLocal(Handle<JSObject>::cast(object))));
     885         357 :     RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
     886             :     uint32_t id = 0;
     887         118 :     if (transfer_id.To(&id)) {
     888             :       WriteTag(SerializationTag::kWasmModuleTransfer);
     889         118 :       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         161 : Maybe<bool> ValueSerializer::WriteWasmMemory(Handle<WasmMemoryObject> object) {
     920         161 :   if (!object->array_buffer()->is_shared()) {
     921           8 :     ThrowDataCloneError(MessageTemplate::kDataCloneError, object);
     922             :     return Nothing<bool>();
     923             :   }
     924             : 
     925         153 :   isolate_->wasm_engine()->memory_tracker()->RegisterWasmMemoryAsShared(
     926         153 :       object, isolate_);
     927             : 
     928             :   WriteTag(SerializationTag::kWasmMemoryTransfer);
     929             :   WriteZigZag<int32_t>(object->maximum_pages());
     930         306 :   return WriteJSReceiver(Handle<JSReceiver>(object->array_buffer(), isolate_));
     931             : }
     932             : 
     933          16 : Maybe<bool> ValueSerializer::WriteHostObject(Handle<JSObject> object) {
     934             :   WriteTag(SerializationTag::kHostObject);
     935          16 :   if (!delegate_) {
     936           6 :     isolate_->Throw(*isolate_->factory()->NewError(
     937           6 :         isolate_->error_function(), MessageTemplate::kDataCloneError, object));
     938             :     return Nothing<bool>();
     939             :   }
     940          14 :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
     941             :   Maybe<bool> result =
     942          14 :       delegate_->WriteHostObject(v8_isolate, Utils::ToLocal(object));
     943          28 :   RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
     944             :   USE(result);
     945             :   DCHECK(!result.IsNothing());
     946             :   DCHECK(result.ToChecked());
     947          14 :   return ThrowIfOutOfMemory();
     948             : }
     949             : 
     950          98 : Maybe<uint32_t> ValueSerializer::WriteJSObjectPropertiesSlow(
     951             :     Handle<JSObject> object, Handle<FixedArray> keys) {
     952             :   uint32_t properties_written = 0;
     953             :   int length = keys->length();
     954         264 :   for (int i = 0; i < length; i++) {
     955          84 :     Handle<Object> key(keys->get(i), isolate_);
     956             : 
     957             :     bool success;
     958             :     LookupIterator it = LookupIterator::PropertyOrElement(
     959          84 :         isolate_, object, key, &success, LookupIterator::OWN);
     960             :     DCHECK(success);
     961             :     Handle<Object> value;
     962         169 :     if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<uint32_t>();
     963             : 
     964             :     // If the property is no longer found, do not serialize it.
     965             :     // This could happen if a getter deleted the property.
     966          90 :     if (!it.IsFound()) continue;
     967             : 
     968         228 :     if (!WriteObject(key).FromMaybe(false) ||
     969          76 :         !WriteObject(value).FromMaybe(false)) {
     970             :       return Nothing<uint32_t>();
     971             :     }
     972             : 
     973          76 :     properties_written++;
     974             :   }
     975             :   return Just(properties_written);
     976             : }
     977             : 
     978           0 : void ValueSerializer::ThrowDataCloneError(MessageTemplate template_index) {
     979           3 :   return ThrowDataCloneError(template_index,
     980           6 :                              isolate_->factory()->empty_string());
     981             : }
     982             : 
     983        6737 : Maybe<bool> ValueSerializer::ThrowIfOutOfMemory() {
     984        6737 :   if (out_of_memory_) {
     985             :     ThrowDataCloneError(MessageTemplate::kDataCloneErrorOutOfMemory);
     986             :     return Nothing<bool>();
     987             :   }
     988             :   return Just(true);
     989             : }
     990             : 
     991          12 : void ValueSerializer::ThrowDataCloneError(MessageTemplate index,
     992             :                                           Handle<Object> arg0) {
     993          12 :   Handle<String> message = MessageFormatter::Format(isolate_, index, arg0);
     994          12 :   if (delegate_) {
     995          11 :     delegate_->ThrowDataCloneError(Utils::ToLocal(message));
     996             :   } else {
     997           1 :     isolate_->Throw(
     998           2 :         *isolate_->factory()->NewError(isolate_->error_function(), message));
     999             :   }
    1000          24 :   if (isolate_->has_scheduled_exception()) {
    1001          11 :     isolate_->PromoteScheduledException();
    1002             :   }
    1003          12 : }
    1004             : 
    1005        1917 : ValueDeserializer::ValueDeserializer(Isolate* isolate,
    1006             :                                      Vector<const uint8_t> data,
    1007             :                                      v8::ValueDeserializer::Delegate* delegate)
    1008             :     : isolate_(isolate),
    1009             :       delegate_(delegate),
    1010             :       position_(data.start()),
    1011        1917 :       end_(data.start() + data.length()),
    1012             :       allocation_(data.length() > kPretenureThreshold ? AllocationType::kOld
    1013             :                                                       : AllocationType::kYoung),
    1014             :       id_map_(isolate->global_handles()->Create(
    1015        7668 :           ReadOnlyRoots(isolate_).empty_fixed_array())) {}
    1016             : 
    1017        3834 : ValueDeserializer::~ValueDeserializer() {
    1018        1917 :   GlobalHandles::Destroy(id_map_.location());
    1019             : 
    1020             :   Handle<Object> transfer_map_handle;
    1021        1917 :   if (array_buffer_transfer_map_.ToHandle(&transfer_map_handle)) {
    1022          29 :     GlobalHandles::Destroy(transfer_map_handle.location());
    1023             :   }
    1024        1917 : }
    1025             : 
    1026        1917 : Maybe<bool> ValueDeserializer::ReadHeader() {
    1027        3834 :   if (position_ < end_ &&
    1028        1917 :       *position_ == static_cast<uint8_t>(SerializationTag::kVersion)) {
    1029             :     ReadTag().ToChecked();
    1030        3810 :     if (!ReadVarint<uint32_t>().To(&version_) || version_ > kLatestVersion) {
    1031           6 :       isolate_->Throw(*isolate_->factory()->NewError(
    1032           4 :           MessageTemplate::kDataCloneDeserializationVersionError));
    1033             :       return Nothing<bool>();
    1034             :     }
    1035             :   }
    1036             :   return Just(true);
    1037             : }
    1038             : 
    1039           0 : Maybe<SerializationTag> ValueDeserializer::PeekTag() const {
    1040        7992 :   const uint8_t* peek_position = position_;
    1041             :   SerializationTag tag;
    1042             :   do {
    1043        8055 :     if (peek_position >= end_) return Nothing<SerializationTag>();
    1044        7992 :     tag = static_cast<SerializationTag>(*peek_position);
    1045        7992 :     peek_position++;
    1046        7992 :   } while (tag == SerializationTag::kPadding);
    1047             :   return Just(tag);
    1048             : }
    1049             : 
    1050         684 : void ValueDeserializer::ConsumeTag(SerializationTag peeked_tag) {
    1051             :   SerializationTag actual_tag = ReadTag().ToChecked();
    1052             :   DCHECK(actual_tag == peeked_tag);
    1053             :   USE(actual_tag);
    1054         684 : }
    1055             : 
    1056           0 : Maybe<SerializationTag> ValueDeserializer::ReadTag() {
    1057             :   SerializationTag tag;
    1058             :   do {
    1059       24042 :     if (position_ >= end_) return Nothing<SerializationTag>();
    1060       24042 :     tag = static_cast<SerializationTag>(*position_);
    1061       24042 :     position_++;
    1062       24042 :   } while (tag == SerializationTag::kPadding);
    1063             :   return Just(tag);
    1064             : }
    1065             : 
    1066             : template <typename T>
    1067       21534 : Maybe<T> ValueDeserializer::ReadVarint() {
    1068             :   // Reads an unsigned integer as a base-128 varint.
    1069             :   // The number is written, 7 bits at a time, from the least significant to the
    1070             :   // most significant 7 bits. Each byte, except the last, has the MSB set.
    1071             :   // If the varint is larger than T, any more significant bits are discarded.
    1072             :   // See also https://developers.google.com/protocol-buffers/docs/encoding
    1073             :   static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
    1074             :                 "Only unsigned integer types can be read as varints.");
    1075             :   T value = 0;
    1076             :   unsigned shift = 0;
    1077             :   bool has_another_byte;
    1078       21739 :   do {
    1079       21741 :     if (position_ >= end_) return Nothing<T>();
    1080       21739 :     uint8_t byte = *position_;
    1081       21739 :     if (V8_LIKELY(shift < sizeof(T) * 8)) {
    1082       21739 :       value |= static_cast<T>(byte & 0x7F) << shift;
    1083       21739 :       shift += 7;
    1084             :     }
    1085       21739 :     has_another_byte = byte & 0x80;
    1086       21739 :     position_++;
    1087             :   } while (has_another_byte);
    1088             :   return Just(value);
    1089             : }
    1090             : 
    1091             : template <typename T>
    1092        1287 : Maybe<T> ValueDeserializer::ReadZigZag() {
    1093             :   // Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is
    1094             :   // encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on).
    1095             :   // See also https://developers.google.com/protocol-buffers/docs/encoding
    1096             :   static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
    1097             :                 "Only signed integer types can be read as zigzag.");
    1098             :   using UnsignedT = typename std::make_unsigned<T>::type;
    1099             :   UnsignedT unsigned_value;
    1100        2574 :   if (!ReadVarint<UnsignedT>().To(&unsigned_value)) return Nothing<T>();
    1101        1287 :   return Just(static_cast<T>((unsigned_value >> 1) ^
    1102             :                              -static_cast<T>(unsigned_value & 1)));
    1103             : }
    1104             : 
    1105           0 : Maybe<double> ValueDeserializer::ReadDouble() {
    1106             :   // Warning: this uses host endianness.
    1107          34 :   if (position_ > end_ - sizeof(double)) return Nothing<double>();
    1108             :   double value;
    1109             :   memcpy(&value, position_, sizeof(double));
    1110          34 :   position_ += sizeof(double);
    1111          34 :   if (std::isnan(value)) value = std::numeric_limits<double>::quiet_NaN();
    1112             :   return Just(value);
    1113             : }
    1114             : 
    1115           0 : Maybe<Vector<const uint8_t>> ValueDeserializer::ReadRawBytes(int size) {
    1116        3782 :   if (size > end_ - position_) return Nothing<Vector<const uint8_t>>();
    1117             :   const uint8_t* start = position_;
    1118        3779 :   position_ += size;
    1119             :   return Just(Vector<const uint8_t>(start, size));
    1120             : }
    1121             : 
    1122           2 : bool ValueDeserializer::ReadUint32(uint32_t* value) {
    1123           4 :   return ReadVarint<uint32_t>().To(value);
    1124             : }
    1125             : 
    1126           2 : bool ValueDeserializer::ReadUint64(uint64_t* value) {
    1127           2 :   return ReadVarint<uint64_t>().To(value);
    1128             : }
    1129             : 
    1130           4 : bool ValueDeserializer::ReadDouble(double* value) {
    1131           4 :   return ReadDouble().To(value);
    1132             : }
    1133             : 
    1134          13 : bool ValueDeserializer::ReadRawBytes(size_t length, const void** data) {
    1135          13 :   if (length > static_cast<size_t>(end_ - position_)) return false;
    1136          13 :   *data = position_;
    1137          13 :   position_ += length;
    1138          13 :   return true;
    1139             : }
    1140             : 
    1141          29 : void ValueDeserializer::TransferArrayBuffer(
    1142             :     uint32_t transfer_id, Handle<JSArrayBuffer> array_buffer) {
    1143          29 :   if (array_buffer_transfer_map_.is_null()) {
    1144          29 :     array_buffer_transfer_map_ = isolate_->global_handles()->Create(
    1145          58 :         *SimpleNumberDictionary::New(isolate_, 0));
    1146             :   }
    1147             :   Handle<SimpleNumberDictionary> dictionary =
    1148             :       array_buffer_transfer_map_.ToHandleChecked();
    1149             :   Handle<SimpleNumberDictionary> new_dictionary = SimpleNumberDictionary::Set(
    1150          29 :       isolate_, dictionary, transfer_id, array_buffer);
    1151          29 :   if (!new_dictionary.is_identical_to(dictionary)) {
    1152           0 :     GlobalHandles::Destroy(dictionary.location());
    1153             :     array_buffer_transfer_map_ =
    1154           0 :         isolate_->global_handles()->Create(*new_dictionary);
    1155             :   }
    1156          29 : }
    1157             : 
    1158       21271 : MaybeHandle<Object> ValueDeserializer::ReadObject() {
    1159       42542 :   DisallowJavascriptExecution no_js(isolate_);
    1160             :   // If we are at the end of the stack, abort. This function may recurse.
    1161       42542 :   STACK_CHECK(isolate_, MaybeHandle<Object>());
    1162             : 
    1163       21269 :   MaybeHandle<Object> result = ReadObjectInternal();
    1164             : 
    1165             :   // ArrayBufferView is special in that it consumes the value before it, even
    1166             :   // after format version 0.
    1167             :   Handle<Object> object;
    1168             :   SerializationTag tag;
    1169       28206 :   if (result.ToHandle(&object) && V8_UNLIKELY(object->IsJSArrayBuffer()) &&
    1170       21605 :       PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) {
    1171          73 :     ConsumeTag(SerializationTag::kArrayBufferView);
    1172          73 :     result = ReadJSArrayBufferView(Handle<JSArrayBuffer>::cast(object));
    1173             :   }
    1174             : 
    1175       35997 :   if (result.is_null() && !isolate_->has_pending_exception()) {
    1176          75 :     isolate_->Throw(*isolate_->factory()->NewError(
    1177          50 :         MessageTemplate::kDataCloneDeserializationError));
    1178             :   }
    1179             : 
    1180       21269 :   return result;
    1181             : }
    1182             : 
    1183       21269 : MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() {
    1184             :   SerializationTag tag;
    1185       21269 :   if (!ReadTag().To(&tag)) return MaybeHandle<Object>();
    1186       21269 :   switch (tag) {
    1187             :     case SerializationTag::kVerifyObjectCount:
    1188             :       // Read the count and ignore it.
    1189       18368 :       if (ReadVarint<uint32_t>().IsNothing()) return MaybeHandle<Object>();
    1190        9184 :       return ReadObject();
    1191             :     case SerializationTag::kUndefined:
    1192         186 :       return isolate_->factory()->undefined_value();
    1193             :     case SerializationTag::kNull:
    1194          26 :       return isolate_->factory()->null_value();
    1195             :     case SerializationTag::kTrue:
    1196          62 :       return isolate_->factory()->true_value();
    1197             :     case SerializationTag::kFalse:
    1198          26 :       return isolate_->factory()->false_value();
    1199             :     case SerializationTag::kInt32: {
    1200        1134 :       Maybe<int32_t> number = ReadZigZag<int32_t>();
    1201        1134 :       if (number.IsNothing()) return MaybeHandle<Object>();
    1202        1134 :       return isolate_->factory()->NewNumberFromInt(number.FromJust(),
    1203        2268 :                                                    allocation_);
    1204             :     }
    1205             :     case SerializationTag::kUint32: {
    1206           8 :       Maybe<uint32_t> number = ReadVarint<uint32_t>();
    1207           8 :       if (number.IsNothing()) return MaybeHandle<Object>();
    1208           8 :       return isolate_->factory()->NewNumberFromUint(number.FromJust(),
    1209          16 :                                                     allocation_);
    1210             :     }
    1211             :     case SerializationTag::kDouble: {
    1212             :       Maybe<double> number = ReadDouble();
    1213          16 :       if (number.IsNothing()) return MaybeHandle<Object>();
    1214          32 :       return isolate_->factory()->NewNumber(number.FromJust(), allocation_);
    1215             :     }
    1216             :     case SerializationTag::kBigInt:
    1217           9 :       return ReadBigInt();
    1218             :     case SerializationTag::kUtf8String:
    1219          48 :       return ReadUtf8String();
    1220             :     case SerializationTag::kOneByteString:
    1221        3660 :       return ReadOneByteString();
    1222             :     case SerializationTag::kTwoByteString:
    1223          16 :       return ReadTwoByteString();
    1224             :     case SerializationTag::kObjectReference: {
    1225             :       uint32_t id;
    1226         112 :       if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>();
    1227          56 :       return GetObjectWithID(id);
    1228             :     }
    1229             :     case SerializationTag::kBeginJSObject:
    1230        2494 :       return ReadJSObject();
    1231             :     case SerializationTag::kBeginSparseJSArray:
    1232          19 :       return ReadSparseJSArray();
    1233             :     case SerializationTag::kBeginDenseJSArray:
    1234        3756 :       return ReadDenseJSArray();
    1235             :     case SerializationTag::kDate:
    1236           8 :       return ReadJSDate();
    1237             :     case SerializationTag::kTrueObject:
    1238             :     case SerializationTag::kFalseObject:
    1239             :     case SerializationTag::kNumberObject:
    1240             :     case SerializationTag::kBigIntObject:
    1241             :     case SerializationTag::kStringObject:
    1242          21 :       return ReadJSValue(tag);
    1243             :     case SerializationTag::kRegExp:
    1244          12 :       return ReadJSRegExp();
    1245             :     case SerializationTag::kBeginJSMap:
    1246           8 :       return ReadJSMap();
    1247             :     case SerializationTag::kBeginJSSet:
    1248           8 :       return ReadJSSet();
    1249             :     case SerializationTag::kArrayBuffer: {
    1250             :       const bool is_shared = false;
    1251          78 :       return ReadJSArrayBuffer(is_shared);
    1252             :     }
    1253             :     case SerializationTag::kArrayBufferTransfer: {
    1254          29 :       return ReadTransferredJSArrayBuffer();
    1255             :     }
    1256             :     case SerializationTag::kSharedArrayBuffer: {
    1257             :       const bool is_shared = true;
    1258         263 :       return ReadJSArrayBuffer(is_shared);
    1259             :     }
    1260             :     case SerializationTag::kWasmModule:
    1261           8 :       return ReadWasmModule();
    1262             :     case SerializationTag::kWasmModuleTransfer:
    1263         118 :       return ReadWasmModuleTransfer();
    1264             :     case SerializationTag::kWasmMemoryTransfer:
    1265         153 :       return ReadWasmMemory();
    1266             :     case SerializationTag::kHostObject:
    1267          12 :       return ReadHostObject();
    1268             :     default:
    1269             :       // Before there was an explicit tag for host objects, all unknown tags
    1270             :       // were delegated to the host.
    1271           1 :       if (version_ < 13) {
    1272           1 :         position_--;
    1273           1 :         return ReadHostObject();
    1274             :       }
    1275           0 :       return MaybeHandle<Object>();
    1276             :   }
    1277             : }
    1278             : 
    1279          19 : MaybeHandle<String> ValueDeserializer::ReadString() {
    1280          19 :   if (version_ < 12) return ReadUtf8String();
    1281             :   Handle<Object> object;
    1282          27 :   if (!ReadObject().ToHandle(&object) || !object->IsString()) {
    1283           0 :     return MaybeHandle<String>();
    1284             :   }
    1285           9 :   return Handle<String>::cast(object);
    1286             : }
    1287             : 
    1288          11 : MaybeHandle<BigInt> ValueDeserializer::ReadBigInt() {
    1289             :   uint32_t bitfield;
    1290          22 :   if (!ReadVarint<uint32_t>().To(&bitfield)) return MaybeHandle<BigInt>();
    1291          11 :   int bytelength = BigInt::DigitsByteLengthForBitfield(bitfield);
    1292          11 :   Vector<const uint8_t> digits_storage;
    1293          11 :   if (!ReadRawBytes(bytelength).To(&digits_storage)) {
    1294           0 :     return MaybeHandle<BigInt>();
    1295             :   }
    1296          11 :   return BigInt::FromSerializedDigits(isolate_, bitfield, digits_storage,
    1297          22 :                                       allocation_);
    1298             : }
    1299             : 
    1300          58 : MaybeHandle<String> ValueDeserializer::ReadUtf8String() {
    1301             :   uint32_t utf8_length;
    1302             :   Vector<const uint8_t> utf8_bytes;
    1303         174 :   if (!ReadVarint<uint32_t>().To(&utf8_length) ||
    1304             :       utf8_length >
    1305         116 :           static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
    1306          58 :       !ReadRawBytes(utf8_length).To(&utf8_bytes)) {
    1307           1 :     return MaybeHandle<String>();
    1308             :   }
    1309          57 :   return isolate_->factory()->NewStringFromUtf8(
    1310         114 :       Vector<const char>::cast(utf8_bytes), allocation_);
    1311             : }
    1312             : 
    1313        3660 : MaybeHandle<String> ValueDeserializer::ReadOneByteString() {
    1314             :   uint32_t byte_length;
    1315        3660 :   Vector<const uint8_t> bytes;
    1316       10980 :   if (!ReadVarint<uint32_t>().To(&byte_length) ||
    1317             :       byte_length >
    1318        7320 :           static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
    1319        3660 :       !ReadRawBytes(byte_length).To(&bytes)) {
    1320           1 :     return MaybeHandle<String>();
    1321             :   }
    1322        3659 :   return isolate_->factory()->NewStringFromOneByte(bytes, allocation_);
    1323             : }
    1324             : 
    1325          16 : MaybeHandle<String> ValueDeserializer::ReadTwoByteString() {
    1326             :   uint32_t byte_length;
    1327             :   Vector<const uint8_t> bytes;
    1328          48 :   if (!ReadVarint<uint32_t>().To(&byte_length) ||
    1329             :       byte_length >
    1330          16 :           static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
    1331          31 :       byte_length % sizeof(uc16) != 0 ||
    1332          15 :       !ReadRawBytes(byte_length).To(&bytes)) {
    1333           2 :     return MaybeHandle<String>();
    1334             :   }
    1335             : 
    1336             :   // Allocate an uninitialized string so that we can do a raw memcpy into the
    1337             :   // string on the heap (regardless of alignment).
    1338          15 :   if (byte_length == 0) return isolate_->factory()->empty_string();
    1339             :   Handle<SeqTwoByteString> string;
    1340          26 :   if (!isolate_->factory()
    1341          39 :            ->NewRawTwoByteString(byte_length / sizeof(uc16), allocation_)
    1342             :            .ToHandle(&string)) {
    1343           0 :     return MaybeHandle<String>();
    1344             :   }
    1345             : 
    1346             :   // Copy the bytes directly into the new string.
    1347             :   // Warning: this uses host endianness.
    1348             :   DisallowHeapAllocation no_gc;
    1349          13 :   memcpy(string->GetChars(no_gc), bytes.begin(), bytes.length());
    1350          13 :   return string;
    1351             : }
    1352             : 
    1353          26 : bool ValueDeserializer::ReadExpectedString(Handle<String> expected) {
    1354             :   DisallowHeapAllocation no_gc;
    1355             :   // In the case of failure, the position in the stream is reset.
    1356          26 :   const uint8_t* original_position = position_;
    1357             : 
    1358             :   SerializationTag tag;
    1359             :   uint32_t byte_length;
    1360             :   Vector<const uint8_t> bytes;
    1361          78 :   if (!ReadTag().To(&tag) || !ReadVarint<uint32_t>().To(&byte_length) ||
    1362             :       byte_length >
    1363          52 :           static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
    1364          26 :       !ReadRawBytes(byte_length).To(&bytes)) {
    1365           0 :     position_ = original_position;
    1366           0 :     return false;
    1367             :   }
    1368             : 
    1369          26 :   String::FlatContent flat = expected->GetFlatContent(no_gc);
    1370             : 
    1371             :   // If the bytes are verbatim what is in the flattened string, then the string
    1372             :   // is successfully consumed.
    1373          26 :   if (tag == SerializationTag::kOneByteString && flat.IsOneByte()) {
    1374             :     Vector<const uint8_t> chars = flat.ToOneByteVector();
    1375          46 :     if (byte_length == static_cast<size_t>(chars.length()) &&
    1376          23 :         memcmp(bytes.begin(), chars.begin(), byte_length) == 0) {
    1377             :       return true;
    1378             :     }
    1379           3 :   } else if (tag == SerializationTag::kTwoByteString && flat.IsTwoByte()) {
    1380             :     Vector<const uc16> chars = flat.ToUC16Vector();
    1381           2 :     if (byte_length == static_cast<unsigned>(chars.length()) * sizeof(uc16) &&
    1382           1 :         memcmp(bytes.begin(), chars.begin(), byte_length) == 0) {
    1383             :       return true;
    1384             :     }
    1385           2 :   } else if (tag == SerializationTag::kUtf8String && flat.IsOneByte()) {
    1386             :     Vector<const uint8_t> chars = flat.ToOneByteVector();
    1387           0 :     if (byte_length == static_cast<size_t>(chars.length()) &&
    1388           0 :         String::IsAscii(chars.begin(), chars.length()) &&
    1389           0 :         memcmp(bytes.begin(), chars.begin(), byte_length) == 0) {
    1390             :       return true;
    1391             :     }
    1392             :   }
    1393             : 
    1394           4 :   position_ = original_position;
    1395           4 :   return false;
    1396             : }
    1397             : 
    1398        2494 : MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() {
    1399             :   // If we are at the end of the stack, abort. This function may recurse.
    1400        4988 :   STACK_CHECK(isolate_, MaybeHandle<JSObject>());
    1401             : 
    1402        2494 :   uint32_t id = next_id_++;
    1403        2494 :   HandleScope scope(isolate_);
    1404        2494 :   Handle<JSObject> object = isolate_->factory()->NewJSObject(
    1405        4988 :       isolate_->object_function(), allocation_);
    1406        2494 :   AddObjectWithID(id, object);
    1407             : 
    1408             :   uint32_t num_properties;
    1409             :   uint32_t expected_num_properties;
    1410        4988 :   if (!ReadJSObjectProperties(object, SerializationTag::kEndJSObject, true)
    1411         521 :            .To(&num_properties) ||
    1412        3015 :       !ReadVarint<uint32_t>().To(&expected_num_properties) ||
    1413             :       num_properties != expected_num_properties) {
    1414        1973 :     return MaybeHandle<JSObject>();
    1415             :   }
    1416             : 
    1417             :   DCHECK(HasObjectWithID(id));
    1418         521 :   return scope.CloseAndEscape(object);
    1419             : }
    1420             : 
    1421          19 : MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() {
    1422             :   // If we are at the end of the stack, abort. This function may recurse.
    1423          38 :   STACK_CHECK(isolate_, MaybeHandle<JSArray>());
    1424             : 
    1425             :   uint32_t length;
    1426          38 :   if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>();
    1427             : 
    1428          19 :   uint32_t id = next_id_++;
    1429          19 :   HandleScope scope(isolate_);
    1430          19 :   Handle<JSArray> array = isolate_->factory()->NewJSArray(
    1431          19 :       0, TERMINAL_FAST_ELEMENTS_KIND, allocation_);
    1432          19 :   JSArray::SetLength(array, length);
    1433          19 :   AddObjectWithID(id, array);
    1434             : 
    1435             :   uint32_t num_properties;
    1436             :   uint32_t expected_num_properties;
    1437             :   uint32_t expected_length;
    1438          38 :   if (!ReadJSObjectProperties(array, SerializationTag::kEndSparseJSArray, false)
    1439          19 :            .To(&num_properties) ||
    1440          38 :       !ReadVarint<uint32_t>().To(&expected_num_properties) ||
    1441          38 :       !ReadVarint<uint32_t>().To(&expected_length) ||
    1442          38 :       num_properties != expected_num_properties || length != expected_length) {
    1443           0 :     return MaybeHandle<JSArray>();
    1444             :   }
    1445             : 
    1446             :   DCHECK(HasObjectWithID(id));
    1447          19 :   return scope.CloseAndEscape(array);
    1448             : }
    1449             : 
    1450        3756 : MaybeHandle<JSArray> ValueDeserializer::ReadDenseJSArray() {
    1451             :   // If we are at the end of the stack, abort. This function may recurse.
    1452        7512 :   STACK_CHECK(isolate_, MaybeHandle<JSArray>());
    1453             : 
    1454             :   // We shouldn't permit an array larger than the biggest we can request from
    1455             :   // V8. As an additional sanity check, since each entry will take at least one
    1456             :   // byte to encode, if there are fewer bytes than that we can also fail fast.
    1457             :   uint32_t length;
    1458       11265 :   if (!ReadVarint<uint32_t>().To(&length) ||
    1459        7509 :       length > static_cast<uint32_t>(FixedArray::kMaxLength) ||
    1460        3754 :       length > static_cast<size_t>(end_ - position_)) {
    1461           2 :     return MaybeHandle<JSArray>();
    1462             :   }
    1463             : 
    1464        3753 :   uint32_t id = next_id_++;
    1465        3753 :   HandleScope scope(isolate_);
    1466        3753 :   Handle<JSArray> array = isolate_->factory()->NewJSArray(
    1467             :       HOLEY_ELEMENTS, length, length, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE,
    1468        7506 :       allocation_);
    1469        3753 :   AddObjectWithID(id, array);
    1470             : 
    1471        3753 :   Handle<FixedArray> elements(FixedArray::cast(array->elements()), isolate_);
    1472        3971 :   for (uint32_t i = 0; i < length; i++) {
    1473             :     SerializationTag tag;
    1474        3820 :     if (PeekTag().To(&tag) && tag == SerializationTag::kTheHole) {
    1475           6 :       ConsumeTag(SerializationTag::kTheHole);
    1476           6 :       continue;
    1477             :     }
    1478             : 
    1479             :     Handle<Object> element;
    1480        7628 :     if (!ReadObject().ToHandle(&element)) return MaybeHandle<JSArray>();
    1481             : 
    1482             :     // Serialization versions less than 11 encode the hole the same as
    1483             :     // undefined. For consistency with previous behavior, store these as the
    1484             :     // hole. Past version 11, undefined means undefined.
    1485         114 :     if (version_ < 11 && element->IsUndefined(isolate_)) continue;
    1486             : 
    1487             :     // Safety check.
    1488         102 :     if (i >= static_cast<uint32_t>(elements->length())) {
    1489           0 :       return MaybeHandle<JSArray>();
    1490             :     }
    1491             : 
    1492         102 :     elements->set(i, *element);
    1493             :   }
    1494             : 
    1495             :   uint32_t num_properties;
    1496             :   uint32_t expected_num_properties;
    1497             :   uint32_t expected_length;
    1498          84 :   if (!ReadJSObjectProperties(array, SerializationTag::kEndDenseJSArray, false)
    1499          40 :            .To(&num_properties) ||
    1500          80 :       !ReadVarint<uint32_t>().To(&expected_num_properties) ||
    1501          80 :       !ReadVarint<uint32_t>().To(&expected_length) ||
    1502          82 :       num_properties != expected_num_properties || length != expected_length) {
    1503           2 :     return MaybeHandle<JSArray>();
    1504             :   }
    1505             : 
    1506             :   DCHECK(HasObjectWithID(id));
    1507          40 :   return scope.CloseAndEscape(array);
    1508             : }
    1509             : 
    1510           8 : MaybeHandle<JSDate> ValueDeserializer::ReadJSDate() {
    1511             :   double value;
    1512           8 :   if (!ReadDouble().To(&value)) return MaybeHandle<JSDate>();
    1513           8 :   uint32_t id = next_id_++;
    1514             :   Handle<JSDate> date;
    1515          24 :   if (!JSDate::New(isolate_->date_function(), isolate_->date_function(), value)
    1516             :            .ToHandle(&date)) {
    1517           0 :     return MaybeHandle<JSDate>();
    1518             :   }
    1519           8 :   AddObjectWithID(id, date);
    1520           8 :   return date;
    1521             : }
    1522             : 
    1523          21 : MaybeHandle<JSValue> ValueDeserializer::ReadJSValue(SerializationTag tag) {
    1524          21 :   uint32_t id = next_id_++;
    1525             :   Handle<JSValue> value;
    1526          21 :   switch (tag) {
    1527             :     case SerializationTag::kTrueObject:
    1528           4 :       value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
    1529           8 :           isolate_->boolean_function(), allocation_));
    1530          12 :       value->set_value(ReadOnlyRoots(isolate_).true_value());
    1531           4 :       break;
    1532             :     case SerializationTag::kFalseObject:
    1533           2 :       value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
    1534           4 :           isolate_->boolean_function(), allocation_));
    1535           6 :       value->set_value(ReadOnlyRoots(isolate_).false_value());
    1536           2 :       break;
    1537             :     case SerializationTag::kNumberObject: {
    1538             :       double number;
    1539           6 :       if (!ReadDouble().To(&number)) return MaybeHandle<JSValue>();
    1540           6 :       value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
    1541          12 :           isolate_->number_function(), allocation_));
    1542             :       Handle<Object> number_object =
    1543           6 :           isolate_->factory()->NewNumber(number, allocation_);
    1544           6 :       value->set_value(*number_object);
    1545           6 :       break;
    1546             :     }
    1547             :     case SerializationTag::kBigIntObject: {
    1548             :       Handle<BigInt> bigint;
    1549           4 :       if (!ReadBigInt().ToHandle(&bigint)) return MaybeHandle<JSValue>();
    1550           2 :       value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
    1551           4 :           isolate_->bigint_function(), allocation_));
    1552           4 :       value->set_value(*bigint);
    1553             :       break;
    1554             :     }
    1555             :     case SerializationTag::kStringObject: {
    1556             :       Handle<String> string;
    1557          14 :       if (!ReadString().ToHandle(&string)) return MaybeHandle<JSValue>();
    1558           7 :       value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
    1559          14 :           isolate_->string_function(), allocation_));
    1560          14 :       value->set_value(*string);
    1561             :       break;
    1562             :     }
    1563             :     default:
    1564           0 :       UNREACHABLE();
    1565             :   }
    1566          21 :   AddObjectWithID(id, value);
    1567          21 :   return value;
    1568             : }
    1569             : 
    1570          12 : MaybeHandle<JSRegExp> ValueDeserializer::ReadJSRegExp() {
    1571          12 :   uint32_t id = next_id_++;
    1572             :   Handle<String> pattern;
    1573             :   uint32_t raw_flags;
    1574             :   Handle<JSRegExp> regexp;
    1575          36 :   if (!ReadString().ToHandle(&pattern) ||
    1576          12 :       !ReadVarint<uint32_t>().To(&raw_flags)) {
    1577           0 :     return MaybeHandle<JSRegExp>();
    1578             :   }
    1579             : 
    1580             :   // Ensure the deserialized flags are valid.
    1581             :   // TODO(adamk): Can we remove this check now that dotAll is always-on?
    1582             :   uint32_t flags_mask = static_cast<uint32_t>(-1) << JSRegExp::FlagCount();
    1583          23 :   if ((raw_flags & flags_mask) ||
    1584          22 :       !JSRegExp::New(isolate_, pattern, static_cast<JSRegExp::Flags>(raw_flags))
    1585             :            .ToHandle(&regexp)) {
    1586           1 :     return MaybeHandle<JSRegExp>();
    1587             :   }
    1588             : 
    1589          11 :   AddObjectWithID(id, regexp);
    1590          11 :   return regexp;
    1591             : }
    1592             : 
    1593           8 : MaybeHandle<JSMap> ValueDeserializer::ReadJSMap() {
    1594             :   // If we are at the end of the stack, abort. This function may recurse.
    1595          16 :   STACK_CHECK(isolate_, MaybeHandle<JSMap>());
    1596             : 
    1597           8 :   HandleScope scope(isolate_);
    1598           8 :   uint32_t id = next_id_++;
    1599           8 :   Handle<JSMap> map = isolate_->factory()->NewJSMap();
    1600           8 :   AddObjectWithID(id, map);
    1601             : 
    1602           8 :   Handle<JSFunction> map_set = isolate_->map_set();
    1603             :   uint32_t length = 0;
    1604             :   while (true) {
    1605             :     SerializationTag tag;
    1606          24 :     if (!PeekTag().To(&tag)) return MaybeHandle<JSMap>();
    1607          24 :     if (tag == SerializationTag::kEndJSMap) {
    1608           8 :       ConsumeTag(SerializationTag::kEndJSMap);
    1609           8 :       break;
    1610             :     }
    1611             : 
    1612          80 :     Handle<Object> argv[2];
    1613          48 :     if (!ReadObject().ToHandle(&argv[0]) || !ReadObject().ToHandle(&argv[1])) {
    1614           0 :       return MaybeHandle<JSMap>();
    1615             :     }
    1616             : 
    1617          32 :     AllowJavascriptExecution allow_js(isolate_);
    1618          32 :     if (Execution::Call(isolate_, map_set, map, arraysize(argv), argv)
    1619             :             .is_null()) {
    1620           0 :       return MaybeHandle<JSMap>();
    1621             :     }
    1622          16 :     length += 2;
    1623             :   }
    1624             : 
    1625             :   uint32_t expected_length;
    1626          24 :   if (!ReadVarint<uint32_t>().To(&expected_length) ||
    1627             :       length != expected_length) {
    1628           0 :     return MaybeHandle<JSMap>();
    1629             :   }
    1630             :   DCHECK(HasObjectWithID(id));
    1631           8 :   return scope.CloseAndEscape(map);
    1632             : }
    1633             : 
    1634           8 : MaybeHandle<JSSet> ValueDeserializer::ReadJSSet() {
    1635             :   // If we are at the end of the stack, abort. This function may recurse.
    1636          16 :   STACK_CHECK(isolate_, MaybeHandle<JSSet>());
    1637             : 
    1638           8 :   HandleScope scope(isolate_);
    1639           8 :   uint32_t id = next_id_++;
    1640           8 :   Handle<JSSet> set = isolate_->factory()->NewJSSet();
    1641           8 :   AddObjectWithID(id, set);
    1642           8 :   Handle<JSFunction> set_add = isolate_->set_add();
    1643             :   uint32_t length = 0;
    1644             :   while (true) {
    1645             :     SerializationTag tag;
    1646          26 :     if (!PeekTag().To(&tag)) return MaybeHandle<JSSet>();
    1647          26 :     if (tag == SerializationTag::kEndJSSet) {
    1648           8 :       ConsumeTag(SerializationTag::kEndJSSet);
    1649           8 :       break;
    1650             :     }
    1651             : 
    1652          54 :     Handle<Object> argv[1];
    1653          36 :     if (!ReadObject().ToHandle(&argv[0])) return MaybeHandle<JSSet>();
    1654             : 
    1655          36 :     AllowJavascriptExecution allow_js(isolate_);
    1656          36 :     if (Execution::Call(isolate_, set_add, set, arraysize(argv), argv)
    1657             :             .is_null()) {
    1658           0 :       return MaybeHandle<JSSet>();
    1659             :     }
    1660          18 :     length++;
    1661             :   }
    1662             : 
    1663             :   uint32_t expected_length;
    1664          24 :   if (!ReadVarint<uint32_t>().To(&expected_length) ||
    1665             :       length != expected_length) {
    1666           0 :     return MaybeHandle<JSSet>();
    1667             :   }
    1668             :   DCHECK(HasObjectWithID(id));
    1669           8 :   return scope.CloseAndEscape(set);
    1670             : }
    1671             : 
    1672         494 : MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadJSArrayBuffer(
    1673             :     bool is_shared) {
    1674         494 :   uint32_t id = next_id_++;
    1675         494 :   if (is_shared) {
    1676             :     uint32_t clone_id;
    1677             :     Local<SharedArrayBuffer> sab_value;
    1678        1248 :     if (!ReadVarint<uint32_t>().To(&clone_id) || delegate_ == nullptr ||
    1679             :         !delegate_
    1680         416 :              ->GetSharedArrayBufferFromId(
    1681         416 :                  reinterpret_cast<v8::Isolate*>(isolate_), clone_id)
    1682             :              .ToLocal(&sab_value)) {
    1683           0 :       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSArrayBuffer);
    1684           0 :       return MaybeHandle<JSArrayBuffer>();
    1685             :     }
    1686             :     Handle<JSArrayBuffer> array_buffer = Utils::OpenHandle(*sab_value);
    1687             :     DCHECK_EQ(is_shared, array_buffer->is_shared());
    1688         416 :     AddObjectWithID(id, array_buffer);
    1689         416 :     return array_buffer;
    1690             :   }
    1691             :   uint32_t byte_length;
    1692         234 :   if (!ReadVarint<uint32_t>().To(&byte_length) ||
    1693          78 :       byte_length > static_cast<size_t>(end_ - position_)) {
    1694           1 :     return MaybeHandle<JSArrayBuffer>();
    1695             :   }
    1696             :   const bool should_initialize = false;
    1697          77 :   Handle<JSArrayBuffer> array_buffer = isolate_->factory()->NewJSArrayBuffer(
    1698         154 :       SharedFlag::kNotShared, allocation_);
    1699          77 :   if (!JSArrayBuffer::SetupAllocatingData(array_buffer, isolate_, byte_length,
    1700             :                                           should_initialize)) {
    1701           1 :     return MaybeHandle<JSArrayBuffer>();
    1702             :   }
    1703          76 :   if (byte_length > 0) {
    1704          72 :     memcpy(array_buffer->backing_store(), position_, byte_length);
    1705             :   }
    1706          76 :   position_ += byte_length;
    1707          76 :   AddObjectWithID(id, array_buffer);
    1708          76 :   return array_buffer;
    1709             : }
    1710             : 
    1711          29 : MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadTransferredJSArrayBuffer() {
    1712          29 :   uint32_t id = next_id_++;
    1713             :   uint32_t transfer_id;
    1714             :   Handle<SimpleNumberDictionary> transfer_map;
    1715          87 :   if (!ReadVarint<uint32_t>().To(&transfer_id) ||
    1716             :       !array_buffer_transfer_map_.ToHandle(&transfer_map)) {
    1717           0 :     return MaybeHandle<JSArrayBuffer>();
    1718             :   }
    1719          58 :   int index = transfer_map->FindEntry(isolate_, transfer_id);
    1720          29 :   if (index == SimpleNumberDictionary::kNotFound) {
    1721           0 :     return MaybeHandle<JSArrayBuffer>();
    1722             :   }
    1723             :   Handle<JSArrayBuffer> array_buffer(
    1724          87 :       JSArrayBuffer::cast(transfer_map->ValueAt(index)), isolate_);
    1725          29 :   AddObjectWithID(id, array_buffer);
    1726          29 :   return array_buffer;
    1727             : }
    1728             : 
    1729          73 : MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
    1730             :     Handle<JSArrayBuffer> buffer) {
    1731          73 :   uint32_t buffer_byte_length = static_cast<uint32_t>(buffer->byte_length());
    1732             :   uint8_t tag = 0;
    1733             :   uint32_t byte_offset = 0;
    1734             :   uint32_t byte_length = 0;
    1735         219 :   if (!ReadVarint<uint8_t>().To(&tag) ||
    1736         146 :       !ReadVarint<uint32_t>().To(&byte_offset) ||
    1737         145 :       !ReadVarint<uint32_t>().To(&byte_length) ||
    1738         143 :       byte_offset > buffer_byte_length ||
    1739          70 :       byte_length > buffer_byte_length - byte_offset) {
    1740           5 :     return MaybeHandle<JSArrayBufferView>();
    1741             :   }
    1742          68 :   uint32_t id = next_id_++;
    1743             :   ExternalArrayType external_array_type = kExternalInt8Array;
    1744             :   unsigned element_size = 0;
    1745             : 
    1746          68 :   switch (static_cast<ArrayBufferViewTag>(tag)) {
    1747             :     case ArrayBufferViewTag::kDataView: {
    1748             :       Handle<JSDataView> data_view =
    1749           2 :           isolate_->factory()->NewJSDataView(buffer, byte_offset, byte_length);
    1750           2 :       AddObjectWithID(id, data_view);
    1751           2 :       return data_view;
    1752             :     }
    1753             : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
    1754             :   case ArrayBufferViewTag::k##Type##Array:        \
    1755             :     external_array_type = kExternal##Type##Array; \
    1756             :     element_size = sizeof(ctype);                 \
    1757             :     break;
    1758          14 :       TYPED_ARRAYS(TYPED_ARRAY_CASE)
    1759             : #undef TYPED_ARRAY_CASE
    1760             :   }
    1761         131 :   if (element_size == 0 || byte_offset % element_size != 0 ||
    1762          65 :       byte_length % element_size != 0) {
    1763           2 :     return MaybeHandle<JSArrayBufferView>();
    1764             :   }
    1765          64 :   Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray(
    1766          64 :       external_array_type, buffer, byte_offset, byte_length / element_size,
    1767         192 :       allocation_);
    1768          64 :   AddObjectWithID(id, typed_array);
    1769          64 :   return typed_array;
    1770             : }
    1771             : 
    1772         118 : MaybeHandle<JSObject> ValueDeserializer::ReadWasmModuleTransfer() {
    1773         118 :   auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
    1774         118 :   if ((FLAG_wasm_disable_structured_cloning && !enabled_features.threads) ||
    1775             :       expect_inline_wasm()) {
    1776           1 :     return MaybeHandle<JSObject>();
    1777             :   }
    1778             : 
    1779             :   uint32_t transfer_id = 0;
    1780             :   Local<Value> module_value;
    1781         351 :   if (!ReadVarint<uint32_t>().To(&transfer_id) || delegate_ == nullptr ||
    1782             :       !delegate_
    1783         117 :            ->GetWasmModuleFromId(reinterpret_cast<v8::Isolate*>(isolate_),
    1784         117 :                                  transfer_id)
    1785             :            .ToLocal(&module_value)) {
    1786           2 :     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject);
    1787           0 :     return MaybeHandle<JSObject>();
    1788             :   }
    1789         116 :   uint32_t id = next_id_++;
    1790             :   Handle<JSObject> module =
    1791             :       Handle<JSObject>::cast(Utils::OpenHandle(*module_value));
    1792         116 :   AddObjectWithID(id, module);
    1793         116 :   return module;
    1794             : }
    1795             : 
    1796           8 : MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() {
    1797           8 :   auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
    1798           8 :   if ((FLAG_wasm_disable_structured_cloning && !enabled_features.threads) ||
    1799             :       !expect_inline_wasm()) {
    1800           4 :     return MaybeHandle<JSObject>();
    1801             :   }
    1802             : 
    1803             :   Vector<const uint8_t> encoding_tag;
    1804           8 :   if (!ReadRawBytes(sizeof(WasmEncodingTag)).To(&encoding_tag) ||
    1805           4 :       encoding_tag[0] != static_cast<uint8_t>(WasmEncodingTag::kRawBytes)) {
    1806           0 :     return MaybeHandle<JSObject>();
    1807             :   }
    1808             : 
    1809             :   // Extract the data from the buffer: wasm wire bytes, followed by V8 compiled
    1810             :   // script data.
    1811             :   static_assert(sizeof(int) <= sizeof(uint32_t),
    1812             :                 "max int must fit in uint32_t");
    1813             :   const uint32_t max_valid_size = std::numeric_limits<int>::max();
    1814             :   uint32_t wire_bytes_length = 0;
    1815             :   Vector<const uint8_t> wire_bytes;
    1816             :   uint32_t compiled_bytes_length = 0;
    1817           4 :   Vector<const uint8_t> compiled_bytes;
    1818          12 :   if (!ReadVarint<uint32_t>().To(&wire_bytes_length) ||
    1819           8 :       wire_bytes_length > max_valid_size ||
    1820           4 :       !ReadRawBytes(wire_bytes_length).To(&wire_bytes) ||
    1821           8 :       !ReadVarint<uint32_t>().To(&compiled_bytes_length) ||
    1822          12 :       compiled_bytes_length > max_valid_size ||
    1823             :       !ReadRawBytes(compiled_bytes_length).To(&compiled_bytes)) {
    1824           0 :     return MaybeHandle<JSObject>();
    1825             :   }
    1826             : 
    1827             :   // Try to deserialize the compiled module first.
    1828             :   MaybeHandle<WasmModuleObject> result =
    1829           4 :       wasm::DeserializeNativeModule(isolate_, compiled_bytes, wire_bytes);
    1830           4 :   if (result.is_null()) {
    1831           0 :     wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule");
    1832             :     // TODO(titzer): are the current features appropriate for deserializing?
    1833           0 :     auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
    1834           0 :     result = isolate_->wasm_engine()->SyncCompile(
    1835             :         isolate_, enabled_features, &thrower,
    1836           0 :         wasm::ModuleWireBytes(wire_bytes));
    1837             :   }
    1838           4 :   uint32_t id = next_id_++;
    1839           4 :   if (!result.is_null()) {
    1840           4 :     AddObjectWithID(id, result.ToHandleChecked());
    1841             :   }
    1842           4 :   return result;
    1843             : }
    1844             : 
    1845         153 : MaybeHandle<WasmMemoryObject> ValueDeserializer::ReadWasmMemory() {
    1846         153 :   uint32_t id = next_id_++;
    1847             : 
    1848         153 :   auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
    1849         153 :   if (!enabled_features.threads) {
    1850           0 :     return MaybeHandle<WasmMemoryObject>();
    1851             :   }
    1852             : 
    1853             :   int32_t maximum_pages;
    1854         306 :   if (!ReadZigZag<int32_t>().To(&maximum_pages)) {
    1855           0 :     return MaybeHandle<WasmMemoryObject>();
    1856             :   }
    1857             : 
    1858             :   SerializationTag tag;
    1859         153 :   if (!ReadTag().To(&tag) || tag != SerializationTag::kSharedArrayBuffer) {
    1860           0 :     return MaybeHandle<WasmMemoryObject>();
    1861             :   }
    1862             : 
    1863             :   const bool is_shared = true;
    1864             :   Handle<JSArrayBuffer> buffer;
    1865         306 :   if (!ReadJSArrayBuffer(is_shared).ToHandle(&buffer)) {
    1866           0 :     return MaybeHandle<WasmMemoryObject>();
    1867             :   }
    1868             : 
    1869             :   Handle<WasmMemoryObject> result =
    1870         306 :       WasmMemoryObject::New(isolate_, buffer, maximum_pages);
    1871             : 
    1872         153 :   isolate_->wasm_engine()->memory_tracker()->RegisterWasmMemoryAsShared(
    1873         153 :       result, isolate_);
    1874             : 
    1875         153 :   AddObjectWithID(id, result);
    1876         153 :   return result;
    1877             : }
    1878             : 
    1879          13 : MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() {
    1880          13 :   if (!delegate_) return MaybeHandle<JSObject>();
    1881          24 :   STACK_CHECK(isolate_, MaybeHandle<JSObject>());
    1882          12 :   uint32_t id = next_id_++;
    1883          12 :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
    1884             :   v8::Local<v8::Object> object;
    1885          24 :   if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) {
    1886           0 :     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject);
    1887           0 :     return MaybeHandle<JSObject>();
    1888             :   }
    1889             :   Handle<JSObject> js_object =
    1890             :       Handle<JSObject>::cast(Utils::OpenHandle(*object));
    1891          12 :   AddObjectWithID(id, js_object);
    1892          12 :   return js_object;
    1893             : }
    1894             : 
    1895             : // Copies a vector of property values into an object, given the map that should
    1896             : // be used.
    1897         521 : static void CommitProperties(Handle<JSObject> object, Handle<Map> map,
    1898             :                              const std::vector<Handle<Object>>& properties) {
    1899         521 :   JSObject::AllocateStorageForMap(object, map);
    1900             :   DCHECK(!object->map()->is_dictionary_map());
    1901             : 
    1902             :   DisallowHeapAllocation no_gc;
    1903         521 :   DescriptorArray descriptors = object->map()->instance_descriptors();
    1904        1372 :   for (unsigned i = 0; i < properties.size(); i++) {
    1905             :     // Initializing store.
    1906         220 :     object->WriteToField(i, descriptors->GetDetails(i), *properties[i]);
    1907             :   }
    1908         521 : }
    1909             : 
    1910        3143 : static bool IsValidObjectKey(Handle<Object> value) {
    1911        3183 :   return value->IsName() || value->IsNumber();
    1912             : }
    1913             : 
    1914        2555 : Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
    1915             :     Handle<JSObject> object, SerializationTag end_tag,
    1916             :     bool can_use_transitions) {
    1917             :   uint32_t num_properties = 0;
    1918             : 
    1919             :   // Fast path (following map transitions).
    1920        2555 :   if (can_use_transitions) {
    1921             :     bool transitioning = true;
    1922        2494 :     Handle<Map> map(object->map(), isolate_);
    1923             :     DCHECK(!map->is_dictionary_map());
    1924             :     DCHECK_EQ(0, map->instance_descriptors()->number_of_descriptors());
    1925             :     std::vector<Handle<Object>> properties;
    1926        2494 :     properties.reserve(8);
    1927             : 
    1928        3040 :     while (transitioning) {
    1929             :       // If there are no more properties, finish.
    1930             :       SerializationTag tag;
    1931        4662 :       if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
    1932        2604 :       if (tag == end_tag) {
    1933          85 :         ConsumeTag(end_tag);
    1934          85 :         CommitProperties(object, map, properties);
    1935          85 :         CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max());
    1936          85 :         return Just(static_cast<uint32_t>(properties.size()));
    1937             :       }
    1938             : 
    1939             :       // Determine the key to be used and the target map to transition to, if
    1940             :       // possible. Transitioning may abort if the key is not a string, or if no
    1941             :       // transition was found.
    1942             :       Handle<Object> key;
    1943             :       Handle<Map> target;
    1944        2519 :       TransitionsAccessor transitions(isolate_, map);
    1945        2519 :       Handle<String> expected_key = transitions.ExpectedTransitionKey();
    1946        2519 :       if (!expected_key.is_null() && ReadExpectedString(expected_key)) {
    1947             :         key = expected_key;
    1948          22 :         target = transitions.ExpectedTransitionTarget();
    1949             :       } else {
    1950        4994 :         if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(key)) {
    1951             :           return Nothing<uint32_t>();
    1952             :         }
    1953        2495 :         if (key->IsString()) {
    1954             :           key =
    1955        2491 :               isolate_->factory()->InternalizeString(Handle<String>::cast(key));
    1956             :           // Don't reuse |transitions| because it could be stale.
    1957        2491 :           transitioning = TransitionsAccessor(isolate_, map)
    1958        2491 :                               .FindTransitionToField(Handle<String>::cast(key))
    1959             :                               .ToHandle(&target);
    1960             :         } else {
    1961             :           transitioning = false;
    1962             :         }
    1963             :       }
    1964             : 
    1965             :       // Read the value that corresponds to it.
    1966             :       Handle<Object> value;
    1967        5034 :       if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
    1968             : 
    1969             :       // If still transitioning and the value fits the field representation
    1970             :       // (though generalization may be required), store the property value so
    1971             :       // that we can copy them all at once. Otherwise, stop transitioning.
    1972         546 :       if (transitioning) {
    1973         111 :         int descriptor = static_cast<int>(properties.size());
    1974             :         PropertyDetails details =
    1975         111 :             target->instance_descriptors()->GetDetails(descriptor);
    1976             :         Representation expected_representation = details.representation();
    1977         111 :         if (value->FitsRepresentation(expected_representation)) {
    1978         263 :           if (expected_representation.IsHeapObject() &&
    1979         153 :               !target->instance_descriptors()
    1980         153 :                    ->GetFieldType(descriptor)
    1981             :                    ->NowContains(value)) {
    1982             :             Handle<FieldType> value_type =
    1983           8 :                 value->OptimalType(isolate_, expected_representation);
    1984           4 :             Map::GeneralizeField(isolate_, target, descriptor,
    1985             :                                  details.constness(), expected_representation,
    1986           4 :                                  value_type);
    1987             :           }
    1988             :           DCHECK(target->instance_descriptors()
    1989             :                      ->GetFieldType(descriptor)
    1990             :                      ->NowContains(value));
    1991         110 :           properties.push_back(value);
    1992             :           map = target;
    1993             :           continue;
    1994             :         } else {
    1995             :           transitioning = false;
    1996             :         }
    1997             :       }
    1998             : 
    1999             :       // Fell out of transitioning fast path. Commit the properties gathered so
    2000             :       // far, and then start setting properties slowly instead.
    2001             :       DCHECK(!transitioning);
    2002         436 :       CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max());
    2003         436 :       CommitProperties(object, map, properties);
    2004         436 :       num_properties = static_cast<uint32_t>(properties.size());
    2005             : 
    2006             :       bool success;
    2007             :       LookupIterator it = LookupIterator::PropertyOrElement(
    2008         436 :           isolate_, object, key, &success, LookupIterator::OWN);
    2009         872 :       if (!success || it.state() != LookupIterator::NOT_FOUND ||
    2010         436 :           JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
    2011             :               .is_null()) {
    2012             :         return Nothing<uint32_t>();
    2013             :       }
    2014         436 :       num_properties++;
    2015             :     }
    2016             : 
    2017             :     // At this point, transitioning should be done, but at least one property
    2018             :     // should have been written (in the zero-property case, there is an early
    2019             :     // return).
    2020             :     DCHECK(!transitioning);
    2021             :     DCHECK_GE(num_properties, 1u);
    2022             :   }
    2023             : 
    2024             :   // Slow path.
    2025         632 :   for (;; num_properties++) {
    2026             :     SerializationTag tag;
    2027        1626 :     if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
    2028        1129 :     if (tag == end_tag) {
    2029         495 :       ConsumeTag(end_tag);
    2030             :       return Just(num_properties);
    2031             :     }
    2032             : 
    2033             :     Handle<Object> key;
    2034        1268 :     if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(key)) {
    2035             :       return Nothing<uint32_t>();
    2036             :     }
    2037             :     Handle<Object> value;
    2038        1268 :     if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
    2039             : 
    2040             :     bool success;
    2041             :     LookupIterator it = LookupIterator::PropertyOrElement(
    2042         634 :         isolate_, object, key, &success, LookupIterator::OWN);
    2043        1266 :     if (!success || it.state() != LookupIterator::NOT_FOUND ||
    2044         632 :         JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
    2045             :             .is_null()) {
    2046             :       return Nothing<uint32_t>();
    2047             :     }
    2048             :   }
    2049             : }
    2050             : 
    2051           0 : bool ValueDeserializer::HasObjectWithID(uint32_t id) {
    2052           0 :   return id < static_cast<unsigned>(id_map_->length()) &&
    2053           0 :          !id_map_->get(id)->IsTheHole(isolate_);
    2054             : }
    2055             : 
    2056          56 : MaybeHandle<JSReceiver> ValueDeserializer::GetObjectWithID(uint32_t id) {
    2057          56 :   if (id >= static_cast<unsigned>(id_map_->length())) {
    2058           0 :     return MaybeHandle<JSReceiver>();
    2059             :   }
    2060          56 :   Object value = id_map_->get(id);
    2061         112 :   if (value->IsTheHole(isolate_)) return MaybeHandle<JSReceiver>();
    2062             :   DCHECK(value->IsJSReceiver());
    2063          56 :   return Handle<JSReceiver>(JSReceiver::cast(value), isolate_);
    2064             : }
    2065             : 
    2066        7194 : void ValueDeserializer::AddObjectWithID(uint32_t id,
    2067             :                                         Handle<JSReceiver> object) {
    2068             :   DCHECK(!HasObjectWithID(id));
    2069             :   Handle<FixedArray> new_array =
    2070        7194 :       FixedArray::SetAndGrow(isolate_, id_map_, id, object);
    2071             : 
    2072             :   // If the dictionary was reallocated, update the global handle.
    2073        7194 :   if (!new_array.is_identical_to(id_map_)) {
    2074         797 :     GlobalHandles::Destroy(id_map_.location());
    2075        1594 :     id_map_ = isolate_->global_handles()->Create(*new_array);
    2076             :   }
    2077        7194 : }
    2078             : 
    2079           7 : static Maybe<bool> SetPropertiesFromKeyValuePairs(Isolate* isolate,
    2080             :                                                   Handle<JSObject> object,
    2081             :                                                   Handle<Object>* data,
    2082             :                                                   uint32_t num_properties) {
    2083          33 :   for (unsigned i = 0; i < 2 * num_properties; i += 2) {
    2084          13 :     Handle<Object> key = data[i];
    2085          13 :     if (!IsValidObjectKey(key)) return Nothing<bool>();
    2086          13 :     Handle<Object> value = data[i + 1];
    2087             :     bool success;
    2088             :     LookupIterator it = LookupIterator::PropertyOrElement(
    2089          13 :         isolate, object, key, &success, LookupIterator::OWN);
    2090          26 :     if (!success || it.state() != LookupIterator::NOT_FOUND ||
    2091          13 :         JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
    2092             :             .is_null()) {
    2093             :       return Nothing<bool>();
    2094             :     }
    2095             :   }
    2096             :   return Just(true);
    2097             : }
    2098             : 
    2099             : namespace {
    2100             : 
    2101             : // Throws a generic "deserialization failed" exception by default, unless a more
    2102             : // specific exception has already been thrown.
    2103           0 : void ThrowDeserializationExceptionIfNonePending(Isolate* isolate) {
    2104           0 :   if (!isolate->has_pending_exception()) {
    2105           0 :     isolate->Throw(*isolate->factory()->NewError(
    2106           0 :         MessageTemplate::kDataCloneDeserializationError));
    2107             :   }
    2108             :   DCHECK(isolate->has_pending_exception());
    2109           0 : }
    2110             : 
    2111             : }  // namespace
    2112             : 
    2113             : MaybeHandle<Object>
    2114          12 : ValueDeserializer::ReadObjectUsingEntireBufferForLegacyFormat() {
    2115             :   DCHECK_EQ(version_, 0u);
    2116          12 :   HandleScope scope(isolate_);
    2117             :   std::vector<Handle<Object>> stack;
    2118          88 :   while (position_ < end_) {
    2119             :     SerializationTag tag;
    2120          48 :     if (!PeekTag().To(&tag)) break;
    2121             : 
    2122             :     Handle<Object> new_object;
    2123          38 :     switch (tag) {
    2124             :       case SerializationTag::kEndJSObject: {
    2125           5 :         ConsumeTag(SerializationTag::kEndJSObject);
    2126             : 
    2127             :         // JS Object: Read the last 2*n values from the stack and use them as
    2128             :         // key-value pairs.
    2129             :         uint32_t num_properties;
    2130          15 :         if (!ReadVarint<uint32_t>().To(&num_properties) ||
    2131           5 :             stack.size() / 2 < num_properties) {
    2132           0 :           isolate_->Throw(*isolate_->factory()->NewError(
    2133           0 :               MessageTemplate::kDataCloneDeserializationError));
    2134           0 :           return MaybeHandle<Object>();
    2135             :         }
    2136             : 
    2137             :         size_t begin_properties =
    2138           5 :             stack.size() - 2 * static_cast<size_t>(num_properties);
    2139           5 :         Handle<JSObject> js_object = isolate_->factory()->NewJSObject(
    2140          10 :             isolate_->object_function(), allocation_);
    2141           9 :         if (num_properties &&
    2142           4 :             !SetPropertiesFromKeyValuePairs(
    2143           4 :                  isolate_, js_object, &stack[begin_properties], num_properties)
    2144             :                  .FromMaybe(false)) {
    2145           0 :           ThrowDeserializationExceptionIfNonePending(isolate_);
    2146           0 :           return MaybeHandle<Object>();
    2147             :         }
    2148             : 
    2149           5 :         stack.resize(begin_properties);
    2150           5 :         new_object = js_object;
    2151           5 :         break;
    2152             :       }
    2153             :       case SerializationTag::kEndSparseJSArray: {
    2154           4 :         ConsumeTag(SerializationTag::kEndSparseJSArray);
    2155             : 
    2156             :         // Sparse JS Array: Read the last 2*|num_properties| from the stack.
    2157             :         uint32_t num_properties;
    2158             :         uint32_t length;
    2159          12 :         if (!ReadVarint<uint32_t>().To(&num_properties) ||
    2160           8 :             !ReadVarint<uint32_t>().To(&length) ||
    2161           4 :             stack.size() / 2 < num_properties) {
    2162           0 :           isolate_->Throw(*isolate_->factory()->NewError(
    2163           0 :               MessageTemplate::kDataCloneDeserializationError));
    2164           0 :           return MaybeHandle<Object>();
    2165             :         }
    2166             : 
    2167           4 :         Handle<JSArray> js_array = isolate_->factory()->NewJSArray(
    2168           4 :             0, TERMINAL_FAST_ELEMENTS_KIND, allocation_);
    2169           4 :         JSArray::SetLength(js_array, length);
    2170             :         size_t begin_properties =
    2171           4 :             stack.size() - 2 * static_cast<size_t>(num_properties);
    2172           7 :         if (num_properties &&
    2173           3 :             !SetPropertiesFromKeyValuePairs(
    2174           3 :                  isolate_, js_array, &stack[begin_properties], num_properties)
    2175             :                  .FromMaybe(false)) {
    2176           0 :           ThrowDeserializationExceptionIfNonePending(isolate_);
    2177           0 :           return MaybeHandle<Object>();
    2178             :         }
    2179             : 
    2180           4 :         stack.resize(begin_properties);
    2181           4 :         new_object = js_array;
    2182             :         break;
    2183             :       }
    2184             :       case SerializationTag::kEndDenseJSArray: {
    2185             :         // This was already broken in Chromium, and apparently wasn't missed.
    2186           0 :         isolate_->Throw(*isolate_->factory()->NewError(
    2187           0 :             MessageTemplate::kDataCloneDeserializationError));
    2188           0 :         return MaybeHandle<Object>();
    2189             :       }
    2190             :       default:
    2191          58 :         if (!ReadObject().ToHandle(&new_object)) return MaybeHandle<Object>();
    2192             :         break;
    2193             :     }
    2194          38 :     stack.push_back(new_object);
    2195             :   }
    2196             : 
    2197             : // Nothing remains but padding.
    2198             : #ifdef DEBUG
    2199             :   while (position_ < end_) {
    2200             :     DCHECK(*position_++ == static_cast<uint8_t>(SerializationTag::kPadding));
    2201             :   }
    2202             : #endif
    2203          12 :   position_ = end_;
    2204             : 
    2205          12 :   if (stack.size() != 1) {
    2206           0 :     isolate_->Throw(*isolate_->factory()->NewError(
    2207           0 :         MessageTemplate::kDataCloneDeserializationError));
    2208           0 :     return MaybeHandle<Object>();
    2209             :   }
    2210          12 :   return scope.CloseAndEscape(stack[0]);
    2211             : }
    2212             : 
    2213             : }  // namespace internal
    2214      120216 : }  // namespace v8

Generated by: LCOV version 1.10