LCOV - code coverage report
Current view: top level - src - value-serializer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 736 791 93.0 %
Date: 2017-04-26 Functions: 79 89 88.8 %

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

Generated by: LCOV version 1.10