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>
BytesNeededForVarint(T value)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 
ValueSerializer(Isolate * isolate,v8::ValueSerializer::Delegate * delegate)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 
~ValueSerializer()151 ValueSerializer::~ValueSerializer() {
152   if (buffer_) {
153     if (delegate_) {
154       delegate_->FreeBufferMemory(buffer_);
155     } else {
156       free(buffer_);
157     }
158   }
159 }
160 
WriteHeader()161 void ValueSerializer::WriteHeader() {
162   WriteTag(SerializationTag::kVersion);
163   WriteVarint(kLatestVersion);
164 }
165 
WriteTag(SerializationTag tag)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>
WriteVarint(T value)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>
WriteZigZag(T value)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 
WriteDouble(double value)203 void ValueSerializer::WriteDouble(double value) {
204   // Warning: this uses host endianness.
205   WriteRawBytes(&value, sizeof(value));
206 }
207 
WriteOneByteString(Vector<const uint8_t> chars)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 
WriteTwoByteString(Vector<const uc16> chars)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 
WriteRawBytes(const void * source,size_t length)219 void ValueSerializer::WriteRawBytes(const void* source, size_t length) {
220   memcpy(ReserveRawBytes(length), source, length);
221 }
222 
ReserveRawBytes(size_t bytes)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 
ExpandBuffer(size_t required_capacity)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 
WriteUint32(uint32_t value)249 void ValueSerializer::WriteUint32(uint32_t value) {
250   WriteVarint<uint32_t>(value);
251 }
252 
WriteUint64(uint64_t value)253 void ValueSerializer::WriteUint64(uint64_t value) {
254   WriteVarint<uint64_t>(value);
255 }
256 
ReleaseBuffer()257 std::vector<uint8_t> ValueSerializer::ReleaseBuffer() {
258   return std::vector<uint8_t>(buffer_, buffer_ + buffer_size_);
259 }
260 
Release()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 
TransferArrayBuffer(uint32_t transfer_id,Handle<JSArrayBuffer> array_buffer)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 
WriteObject(Handle<Object> object)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 
WriteOddball(Oddball * oddball)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 
WriteSmi(Smi * smi)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 
WriteHeapNumber(HeapNumber * number)348 void ValueSerializer::WriteHeapNumber(HeapNumber* number) {
349   WriteTag(SerializationTag::kDouble);
350   WriteDouble(number->value());
351 }
352 
WriteString(Handle<String> string)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 
WriteJSReceiver(Handle<JSReceiver> receiver)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 
WriteJSObject(Handle<JSObject> object)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 
WriteJSObjectSlow(Handle<JSObject> object)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 
WriteJSArray(Handle<JSArray> array)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 
WriteJSDate(JSDate * date)622 void ValueSerializer::WriteJSDate(JSDate* date) {
623   WriteTag(SerializationTag::kDate);
624   WriteDouble(date->value()->Number());
625 }
626 
WriteJSValue(Handle<JSValue> value)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 
WriteJSRegExp(JSRegExp * regexp)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 
WriteJSMap(Handle<JSMap> map)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 
WriteJSSet(Handle<JSSet> set)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 
WriteJSArrayBuffer(JSArrayBuffer * array_buffer)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 
WriteJSArrayBufferView(JSArrayBufferView * view)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 
WriteWasmModule(Handle<JSObject> object)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 
WriteHostObject(Handle<JSObject> object)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 
WriteJSObjectPropertiesSlow(Handle<JSObject> object,Handle<FixedArray> keys)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 
ThrowDataCloneError(MessageTemplate::Template template_index)844 void ValueSerializer::ThrowDataCloneError(
845     MessageTemplate::Template template_index) {
846   return ThrowDataCloneError(template_index,
847                              isolate_->factory()->empty_string());
848 }
849 
ThrowDataCloneError(MessageTemplate::Template template_index,Handle<Object> arg0)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 
ValueDeserializer(Isolate * isolate,Vector<const uint8_t> data,v8::ValueDeserializer::Delegate * delegate)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 
~ValueDeserializer()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 
ReadHeader()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 
PeekTag() const898 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 
ConsumeTag(SerializationTag peeked_tag)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 
ReadTag()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>
ReadVarint()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>
ReadZigZag()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 
ReadDouble()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 
ReadRawBytes(int size)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 
ReadUint32(uint32_t * value)981 bool ValueDeserializer::ReadUint32(uint32_t* value) {
982   return ReadVarint<uint32_t>().To(value);
983 }
984 
ReadUint64(uint64_t * value)985 bool ValueDeserializer::ReadUint64(uint64_t* value) {
986   return ReadVarint<uint64_t>().To(value);
987 }
988 
ReadDouble(double * value)989 bool ValueDeserializer::ReadDouble(double* value) {
990   return ReadDouble().To(value);
991 }
992 
ReadRawBytes(size_t length,const void ** data)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 
TransferArrayBuffer(uint32_t transfer_id,Handle<JSArrayBuffer> array_buffer)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 
ReadObject()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 
ReadObjectInternal()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 
ReadUtf8String()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 
ReadTwoByteString()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 
ReadExpectedString(Handle<String> expected)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 
ReadJSObject()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 
ReadSparseJSArray()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 
ReadDenseJSArray()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 
ReadJSDate()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 
ReadJSValue(SerializationTag tag)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 
ReadJSRegExp()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 
ReadJSMap()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 
ReadJSSet()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 
ReadJSArrayBuffer()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 
ReadTransferredJSArrayBuffer(bool is_shared)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 
ReadJSArrayBufferView(Handle<JSArrayBuffer> buffer)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 
ReadWasmModule()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 
ReadHostObject()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.
CommitProperties(Handle<JSObject> object,Handle<Map> map,const std::vector<Handle<Object>> & properties)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 
ReadJSObjectProperties(Handle<JSObject> object,SerializationTag end_tag,bool can_use_transitions)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 
HasObjectWithID(uint32_t id)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 
GetObjectWithID(uint32_t id)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 
AddObjectWithID(uint32_t id,Handle<JSReceiver> object)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 
SetPropertiesFromKeyValuePairs(Isolate * isolate,Handle<JSObject> object,Handle<Object> * data,uint32_t num_properties)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>
ReadObjectUsingEntireBufferForLegacyFormat()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