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