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