LCOV - code coverage report
Current view: top level - src - value-serializer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 780 859 90.8 %
Date: 2017-10-20 Functions: 81 90 90.0 %

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

Generated by: LCOV version 1.10