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