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