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