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