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