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 4086 : 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 8158 : ZoneAllocationPolicy(&zone_)) {}
197 :
198 4083 : ValueSerializer::~ValueSerializer() {
199 2040 : if (buffer_) {
200 37 : if (delegate_) {
201 31 : delegate_->FreeBufferMemory(buffer_);
202 : } else {
203 6 : free(buffer_);
204 : }
205 : }
206 2041 : }
207 :
208 1871 : void ValueSerializer::WriteHeader() {
209 : WriteTag(SerializationTag::kVersion);
210 1885 : WriteVarint(kLatestVersion);
211 1880 : }
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 11762 : uint8_t raw_tag = static_cast<uint8_t>(tag);
219 11762 : WriteRawBytes(&raw_tag, sizeof(raw_tag));
220 0 : }
221 :
222 : template <typename T>
223 9564 : 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 9723 : do {
233 9723 : *next_byte = (value & 0x7F) | 0x80;
234 9723 : next_byte++;
235 9723 : value >>= 7;
236 : } while (value);
237 9564 : *(next_byte - 1) &= 0x7F;
238 9564 : WriteRawBytes(stack_buffer, next_byte - stack_buffer);
239 9587 : }
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 1241 : 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 3291 : WriteVarint<uint32_t>(chars.length());
261 3290 : 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 24719 : void ValueSerializer::WriteRawBytes(const void* source, size_t length) {
281 : uint8_t* dest;
282 49475 : if (ReserveRawBytes(length).To(&dest)) {
283 : memcpy(dest, source, length);
284 : }
285 24756 : }
286 :
287 24741 : Maybe<uint8_t*> ValueSerializer::ReserveRawBytes(size_t bytes) {
288 24741 : size_t old_size = buffer_size_;
289 24741 : size_t new_size = old_size + bytes;
290 24741 : if (V8_UNLIKELY(new_size > buffer_capacity_)) {
291 : bool ok;
292 3893 : if (!ExpandBuffer(new_size).To(&ok)) {
293 : return Nothing<uint8_t*>();
294 : }
295 : }
296 24757 : buffer_size_ = new_size;
297 24757 : return Just(&buffer_[old_size]);
298 : }
299 :
300 1941 : Maybe<bool> ValueSerializer::ExpandBuffer(size_t required_capacity) {
301 : DCHECK_GT(required_capacity, buffer_capacity_);
302 : size_t requested_capacity =
303 3882 : std::max(required_capacity, buffer_capacity_ * 2) + 64;
304 1941 : size_t provided_capacity = 0;
305 : void* new_buffer = nullptr;
306 1941 : if (delegate_) {
307 : new_buffer = delegate_->ReallocateBufferMemory(buffer_, requested_capacity,
308 1803 : &provided_capacity);
309 : } else {
310 138 : new_buffer = realloc(buffer_, requested_capacity);
311 138 : provided_capacity = requested_capacity;
312 : }
313 1956 : if (new_buffer) {
314 : DCHECK(provided_capacity >= requested_capacity);
315 1953 : buffer_ = reinterpret_cast<uint8_t*>(new_buffer);
316 1953 : 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 1824 : std::pair<uint8_t*, size_t> ValueSerializer::Release() {
333 1824 : auto result = std::make_pair(buffer_, buffer_size_);
334 1824 : buffer_ = nullptr;
335 1824 : buffer_size_ = 0;
336 1824 : buffer_capacity_ = 0;
337 1824 : 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 9119 : 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 9119 : if (V8_UNLIKELY(out_of_memory_)) return ThrowIfOutOfMemory();
352 :
353 18239 : if (object->IsSmi()) {
354 1123 : WriteSmi(Smi::cast(*object));
355 1125 : return ThrowIfOutOfMemory();
356 : }
357 :
358 : DCHECK(object->IsHeapObject());
359 8001 : 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 132 : : 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 15608 : if (object->IsString()) {
391 3288 : WriteString(Handle<String>::cast(object));
392 3297 : return ThrowIfOutOfMemory();
393 9029 : } else if (object->IsJSReceiver()) {
394 4513 : 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 1119 : 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 1131 : }
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 3295 : void ValueSerializer::WriteString(Handle<String> string) {
446 3295 : string = String::Flatten(isolate_, string);
447 : DisallowHeapAllocation no_gc;
448 3299 : String::FlatContent flat = string->GetFlatContent(no_gc);
449 : DCHECK(flat.IsFlat());
450 3300 : 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 3303 : }
466 :
467 4722 : Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
468 : // If the object has already been serialized, just write its ID.
469 4722 : uint32_t* id_map_entry = id_map_.Get(receiver);
470 4724 : if (uint32_t id = *id_map_entry) {
471 : WriteTag(SerializationTag::kObjectReference);
472 41 : WriteVarint(id - 1);
473 41 : return ThrowIfOutOfMemory();
474 : }
475 :
476 : // Otherwise, allocate an ID for it.
477 4683 : uint32_t id = next_id_++;
478 4683 : *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 9366 : 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 9363 : STACK_CHECK(isolate_, Nothing<bool>());
490 :
491 4678 : HandleScope scope(isolate_);
492 4678 : switch (instance_type) {
493 : case JS_ARRAY_TYPE:
494 1721 : return WriteJSArray(Handle<JSArray>::cast(receiver));
495 : case JS_OBJECT_TYPE:
496 : case JS_API_OBJECT_TYPE: {
497 2169 : Handle<JSObject> js_object = Handle<JSObject>::cast(receiver);
498 2170 : if (JSObject::GetEmbedderFieldCount(js_object->map())) {
499 15 : return WriteHostObject(js_object);
500 : } else {
501 2155 : 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 475 : 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 111 : auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
525 111 : if (!FLAG_wasm_disable_structured_cloning || enabled_features.threads) {
526 : // Only write WebAssembly modules if not disabled by a flag.
527 111 : return WriteWasmModule(Handle<WasmModuleObject>::cast(receiver));
528 : }
529 0 : break;
530 : }
531 : case WASM_MEMORY_TYPE: {
532 127 : auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
533 127 : if (enabled_features.threads) {
534 127 : 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 2155 : Maybe<bool> ValueSerializer::WriteJSObject(Handle<JSObject> object) {
547 : DCHECK(!object->map()->IsCustomElementsReceiverMap());
548 : const bool can_serialize_fast =
549 6408 : object->HasFastProperties() && object->elements()->length() == 0;
550 2159 : if (!can_serialize_fast) return WriteJSObjectSlow(object);
551 :
552 2125 : 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 6339 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
560 8012 : Handle<Name> key(map->instance_descriptors()->GetKey(i), isolate_);
561 5346 : if (!key->IsString()) continue;
562 2671 : PropertyDetails details = map->instance_descriptors()->GetDetails(i);
563 2670 : if (details.IsDontEnum()) continue;
564 :
565 : Handle<Object> value;
566 2669 : if (V8_LIKELY(!map_changed)) map_changed = *map == object->map();
567 2671 : 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 2671 : LookupIterator it(isolate_, object, key, LookupIterator::OWN);
577 2669 : if (!it.IsFound()) continue;
578 5335 : if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<bool>();
579 : }
580 :
581 10645 : if (!WriteObject(key).FromMaybe(false) ||
582 5324 : !WriteObject(value).FromMaybe(false)) {
583 : return Nothing<bool>();
584 : }
585 1046 : properties_written++;
586 : }
587 :
588 : WriteTag(SerializationTag::kEndJSObject);
589 499 : WriteVarint<uint32_t>(properties_written);
590 497 : 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 1721 : Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) {
609 1721 : uint32_t length = 0;
610 3442 : 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 5160 : array->HasFastElements() && !array->HasHoleyElements();
621 :
622 1721 : if (should_serialize_densely) {
623 : DCHECK_LE(length, static_cast<uint32_t>(FixedArray::kMaxLength));
624 : WriteTag(SerializationTag::kBeginDenseJSArray);
625 1708 : 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 1708 : 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 5091 : Handle<Object> old_length(array->length(), isolate_);
651 1781 : for (; i < length; i++) {
652 6994 : if (array->length() != *old_length ||
653 3496 : array->GetElementsKind() != PACKED_ELEMENTS) {
654 : // Fall back to slow path.
655 : break;
656 : }
657 3488 : Handle<Object> element(FixedArray::cast(array->elements())->get(i),
658 1744 : isolate_);
659 3488 : 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 48 : ENUMERABLE_STRINGS);
689 96 : if (!accumulator.CollectOwnPropertyNames(array, array).FromMaybe(false)) {
690 : return Nothing<bool>();
691 : }
692 : Handle<FixedArray> keys =
693 48 : accumulator.GetKeys(GetKeysConversion::kConvertToString);
694 : uint32_t properties_written;
695 96 : if (!WriteJSObjectPropertiesSlow(array, keys).To(&properties_written)) {
696 : return Nothing<bool>();
697 : }
698 : WriteTag(SerializationTag::kEndDenseJSArray);
699 48 : WriteVarint<uint32_t>(properties_written);
700 48 : 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 61 : 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 15 : 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 15 : 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 475 : Maybe<bool> ValueSerializer::WriteJSArrayBuffer(
815 : Handle<JSArrayBuffer> array_buffer) {
816 475 : if (array_buffer->is_shared()) {
817 381 : if (!delegate_) {
818 0 : ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer);
819 : return Nothing<bool>();
820 : }
821 :
822 381 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
823 : Maybe<uint32_t> index = delegate_->GetSharedArrayBufferId(
824 381 : v8_isolate, Utils::ToLocalShared(array_buffer));
825 381 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
826 :
827 : WriteTag(SerializationTag::kSharedArrayBuffer);
828 381 : WriteVarint(index.FromJust());
829 381 : return ThrowIfOutOfMemory();
830 : }
831 :
832 94 : uint32_t* transfer_entry = array_buffer_transfer_map_.Find(array_buffer);
833 94 : if (transfer_entry) {
834 : WriteTag(SerializationTag::kArrayBufferTransfer);
835 38 : WriteVarint(*transfer_entry);
836 38 : return ThrowIfOutOfMemory();
837 : }
838 56 : if (array_buffer->was_detached()) {
839 : ThrowDataCloneError(MessageTemplate::kDataCloneErrorDetachedArrayBuffer);
840 : return Nothing<bool>();
841 : }
842 56 : double byte_length = array_buffer->byte_length();
843 56 : 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 56 : WriteVarint<uint32_t>(byte_length);
849 112 : WriteRawBytes(array_buffer->backing_store(), byte_length);
850 56 : 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 111 : Maybe<bool> ValueSerializer::WriteWasmModule(Handle<WasmModuleObject> object) {
879 111 : 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 106 : Utils::ToLocal(Handle<JSObject>::cast(object))));
885 212 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
886 : uint32_t id = 0;
887 105 : if (transfer_id.To(&id)) {
888 : WriteTag(SerializationTag::kWasmModuleTransfer);
889 105 : 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 127 : Maybe<bool> ValueSerializer::WriteWasmMemory(Handle<WasmMemoryObject> object) {
920 254 : if (!object->array_buffer()->is_shared()) {
921 9 : ThrowDataCloneError(MessageTemplate::kDataCloneError, object);
922 : return Nothing<bool>();
923 : }
924 :
925 : WriteTag(SerializationTag::kWasmMemoryTransfer);
926 : WriteZigZag<int32_t>(object->maximum_pages());
927 354 : 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 95 : Maybe<uint32_t> ValueSerializer::WriteJSObjectPropertiesSlow(
948 : Handle<JSObject> object, Handle<FixedArray> keys) {
949 : uint32_t properties_written = 0;
950 : int length = keys->length();
951 178 : 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 5745 : Maybe<bool> ValueSerializer::ThrowIfOutOfMemory() {
981 5745 : if (out_of_memory_) {
982 : ThrowDataCloneError(MessageTemplate::kDataCloneErrorOutOfMemory);
983 : return Nothing<bool>();
984 : }
985 : return Just(true);
986 : }
987 :
988 13 : void ValueSerializer::ThrowDataCloneError(MessageTemplate index,
989 : Handle<Object> arg0) {
990 : Handle<String> message =
991 13 : MessageFormatter::FormatMessage(isolate_, index, arg0);
992 13 : if (delegate_) {
993 12 : delegate_->ThrowDataCloneError(Utils::ToLocal(message));
994 : } else {
995 : isolate_->Throw(
996 2 : *isolate_->factory()->NewError(isolate_->error_function(), message));
997 : }
998 13 : if (isolate_->has_scheduled_exception()) {
999 12 : isolate_->PromoteScheduledException();
1000 : }
1001 13 : }
1002 :
1003 3870 : 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 1935 : end_(data.start() + data.length()),
1010 : pretenure_(data.length() > kPretenureThreshold ? TENURED : NOT_TENURED),
1011 : id_map_(isolate->global_handles()->Create(
1012 5805 : ReadOnlyRoots(isolate_).empty_fixed_array())) {}
1013 :
1014 1935 : ValueDeserializer::~ValueDeserializer() {
1015 1935 : GlobalHandles::Destroy(id_map_.location());
1016 :
1017 : Handle<Object> transfer_map_handle;
1018 1935 : if (array_buffer_transfer_map_.ToHandle(&transfer_map_handle)) {
1019 29 : GlobalHandles::Destroy(transfer_map_handle.location());
1020 : }
1021 1935 : }
1022 :
1023 3855 : Maybe<bool> ValueDeserializer::ReadHeader() {
1024 3867 : if (position_ < end_ &&
1025 1934 : *position_ == static_cast<uint8_t>(SerializationTag::kVersion)) {
1026 : ReadTag().ToChecked();
1027 3845 : 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 7479 : const uint8_t* peek_position = position_;
1038 : SerializationTag tag;
1039 7479 : do {
1040 7542 : if (peek_position >= end_) return Nothing<SerializationTag>();
1041 7479 : tag = static_cast<SerializationTag>(*peek_position);
1042 7479 : peek_position++;
1043 : } while (tag == SerializationTag::kPadding);
1044 : return Just(tag);
1045 : }
1046 :
1047 647 : void ValueDeserializer::ConsumeTag(SerializationTag peeked_tag) {
1048 : SerializationTag actual_tag = ReadTag().ToChecked();
1049 : DCHECK(actual_tag == peeked_tag);
1050 : USE(actual_tag);
1051 647 : }
1052 :
1053 0 : Maybe<SerializationTag> ValueDeserializer::ReadTag() {
1054 : SerializationTag tag;
1055 21239 : do {
1056 21240 : if (position_ >= end_) return Nothing<SerializationTag>();
1057 21239 : tag = static_cast<SerializationTag>(*position_);
1058 21239 : position_++;
1059 : } while (tag == SerializationTag::kPadding);
1060 : return Just(tag);
1061 : }
1062 :
1063 : template <typename T>
1064 18963 : 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 19140 : do {
1076 19142 : if (position_ >= end_) return Nothing<T>();
1077 19140 : uint8_t byte = *position_;
1078 19140 : if (V8_LIKELY(shift < sizeof(T) * 8)) {
1079 19140 : value |= static_cast<T>(byte & 0x7F) << shift;
1080 19140 : shift += 7;
1081 : }
1082 19140 : has_another_byte = byte & 0x80;
1083 19140 : position_++;
1084 : } while (has_another_byte);
1085 : return Just(value);
1086 : }
1087 :
1088 : template <typename T>
1089 1298 : 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 2596 : if (!ReadVarint<UnsignedT>().To(&unsigned_value)) return Nothing<T>();
1098 : return Just(static_cast<T>((unsigned_value >> 1) ^
1099 1298 : -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 3500 : if (size > end_ - position_) return Nothing<Vector<const uint8_t>>();
1114 : const uint8_t* start = position_;
1115 3497 : 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 18524 : MaybeHandle<Object> ValueDeserializer::ReadObject() {
1156 18524 : DisallowJavascriptExecution no_js(isolate_);
1157 : // If we are at the end of the stack, abort. This function may recurse.
1158 37048 : STACK_CHECK(isolate_, MaybeHandle<Object>());
1159 :
1160 18521 : 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 31391 : if (result.ToHandle(&object) && V8_UNLIKELY(object->IsJSArrayBuffer()) &&
1167 18862 : PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) {
1168 65 : ConsumeTag(SerializationTag::kArrayBufferView);
1169 65 : result = ReadJSArrayBufferView(Handle<JSArrayBuffer>::cast(object));
1170 : }
1171 :
1172 18523 : if (result.is_null() && !isolate_->has_pending_exception()) {
1173 : isolate_->Throw(*isolate_->factory()->NewError(
1174 50 : MessageTemplate::kDataCloneDeserializationError));
1175 : }
1176 :
1177 18523 : return result;
1178 : }
1179 :
1180 18522 : MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() {
1181 : SerializationTag tag;
1182 18522 : if (!ReadTag().To(&tag)) return MaybeHandle<Object>();
1183 18522 : 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 1180 : Maybe<int32_t> number = ReadZigZag<int32_t>();
1198 1180 : if (number.IsNothing()) return MaybeHandle<Object>();
1199 : return isolate_->factory()->NewNumberFromInt(number.FromJust(),
1200 2360 : 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 3378 : return ReadOneByteString();
1219 : case SerializationTag::kTwoByteString:
1220 16 : return ReadTwoByteString();
1221 : case SerializationTag::kObjectReference: {
1222 : uint32_t id;
1223 116 : if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>();
1224 58 : return GetObjectWithID(id);
1225 : }
1226 : case SerializationTag::kBeginJSObject:
1227 2247 : return ReadJSObject();
1228 : case SerializationTag::kBeginSparseJSArray:
1229 19 : return ReadSparseJSArray();
1230 : case SerializationTag::kBeginDenseJSArray:
1231 3544 : 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 80 : 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 105 : return ReadWasmModuleTransfer();
1261 : case SerializationTag::kWasmMemoryTransfer:
1262 118 : 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 6756 : MaybeHandle<String> ValueDeserializer::ReadOneByteString() {
1311 : uint32_t byte_length;
1312 3378 : Vector<const uint8_t> bytes;
1313 10134 : if (!ReadVarint<uint32_t>().To(&byte_length) ||
1314 : byte_length >
1315 6756 : static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
1316 3378 : !ReadRawBytes(byte_length).To(&bytes)) {
1317 1 : return MaybeHandle<String>();
1318 : }
1319 3377 : 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 2742 : MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() {
1396 : // If we are at the end of the stack, abort. This function may recurse.
1397 4494 : STACK_CHECK(isolate_, MaybeHandle<JSObject>());
1398 :
1399 2247 : uint32_t id = next_id_++;
1400 2247 : HandleScope scope(isolate_);
1401 : Handle<JSObject> object =
1402 2247 : isolate_->factory()->NewJSObject(isolate_->object_function(), pretenure_);
1403 2248 : AddObjectWithID(id, object);
1404 :
1405 : uint32_t num_properties;
1406 : uint32_t expected_num_properties;
1407 2248 : if (!ReadJSObjectProperties(object, SerializationTag::kEndJSObject, true)
1408 4991 : .To(&num_properties) ||
1409 3238 : !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 495 : 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 7162 : MaybeHandle<JSArray> ValueDeserializer::ReadDenseJSArray() {
1448 : // If we are at the end of the stack, abort. This function may recurse.
1449 7088 : 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 10632 : if (!ReadVarint<uint32_t>().To(&length) ||
1456 7087 : length > static_cast<uint32_t>(FixedArray::kMaxLength) ||
1457 3543 : length > static_cast<size_t>(end_ - position_)) {
1458 2 : return MaybeHandle<JSArray>();
1459 : }
1460 :
1461 3542 : uint32_t id = next_id_++;
1462 3542 : HandleScope scope(isolate_);
1463 : Handle<JSArray> array = isolate_->factory()->NewJSArray(
1464 : HOLEY_ELEMENTS, length, length, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE,
1465 3542 : pretenure_);
1466 3542 : AddObjectWithID(id, array);
1467 :
1468 10626 : Handle<FixedArray> elements(FixedArray::cast(array->elements()), isolate_);
1469 3641 : for (uint32_t i = 0; i < length; i++) {
1470 : SerializationTag tag;
1471 3602 : if (PeekTag().To(&tag) && tag == SerializationTag::kTheHole) {
1472 6 : ConsumeTag(SerializationTag::kTheHole);
1473 6 : continue;
1474 : }
1475 :
1476 : Handle<Object> element;
1477 7192 : 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 115 : if (version_ < 11 && element->IsUndefined(isolate_)) continue;
1483 :
1484 : // Safety check.
1485 92 : if (i >= static_cast<uint32_t>(elements->length())) {
1486 0 : return MaybeHandle<JSArray>();
1487 : }
1488 :
1489 184 : elements->set(i, *element);
1490 : }
1491 :
1492 : uint32_t num_properties;
1493 : uint32_t expected_num_properties;
1494 : uint32_t expected_length;
1495 39 : if (!ReadJSObjectProperties(array, SerializationTag::kEndDenseJSArray, false)
1496 115 : .To(&num_properties) ||
1497 113 : !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1498 113 : !ReadVarint<uint32_t>().To(&expected_length) ||
1499 76 : num_properties != expected_num_properties || length != expected_length) {
1500 2 : return MaybeHandle<JSArray>();
1501 : }
1502 :
1503 : DCHECK(HasObjectWithID(id));
1504 37 : 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 461 : MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadJSArrayBuffer(
1670 461 : bool is_shared) {
1671 461 : uint32_t id = next_id_++;
1672 461 : if (is_shared) {
1673 : uint32_t clone_id;
1674 : Local<SharedArrayBuffer> sab_value;
1675 1143 : if (!ReadVarint<uint32_t>().To(&clone_id) || delegate_ == nullptr ||
1676 : !delegate_
1677 : ->GetSharedArrayBufferFromId(
1678 381 : reinterpret_cast<v8::Isolate*>(isolate_), clone_id)
1679 381 : .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 381 : AddObjectWithID(id, array_buffer);
1686 381 : return array_buffer;
1687 : }
1688 : uint32_t byte_length;
1689 240 : if (!ReadVarint<uint32_t>().To(&byte_length) ||
1690 80 : 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 79 : isolate_->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, pretenure_);
1696 79 : if (!JSArrayBuffer::SetupAllocatingData(array_buffer, isolate_, byte_length,
1697 79 : should_initialize)) {
1698 1 : return MaybeHandle<JSArrayBuffer>();
1699 : }
1700 78 : memcpy(array_buffer->backing_store(), position_, byte_length);
1701 78 : position_ += byte_length;
1702 78 : AddObjectWithID(id, array_buffer);
1703 78 : return array_buffer;
1704 : }
1705 :
1706 58 : MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadTransferredJSArrayBuffer() {
1707 29 : uint32_t id = next_id_++;
1708 : uint32_t transfer_id;
1709 : Handle<SimpleNumberDictionary> transfer_map;
1710 87 : if (!ReadVarint<uint32_t>().To(&transfer_id) ||
1711 : !array_buffer_transfer_map_.ToHandle(&transfer_map)) {
1712 0 : return MaybeHandle<JSArrayBuffer>();
1713 : }
1714 58 : int index = transfer_map->FindEntry(isolate_, transfer_id);
1715 29 : if (index == SimpleNumberDictionary::kNotFound) {
1716 0 : return MaybeHandle<JSArrayBuffer>();
1717 : }
1718 : Handle<JSArrayBuffer> array_buffer(
1719 87 : JSArrayBuffer::cast(transfer_map->ValueAt(index)), isolate_);
1720 29 : AddObjectWithID(id, array_buffer);
1721 29 : return array_buffer;
1722 : }
1723 :
1724 65 : MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
1725 195 : Handle<JSArrayBuffer> buffer) {
1726 65 : uint32_t buffer_byte_length = static_cast<uint32_t>(buffer->byte_length());
1727 : uint8_t tag = 0;
1728 : uint32_t byte_offset = 0;
1729 : uint32_t byte_length = 0;
1730 195 : if (!ReadVarint<uint8_t>().To(&tag) ||
1731 195 : !ReadVarint<uint32_t>().To(&byte_offset) ||
1732 194 : !ReadVarint<uint32_t>().To(&byte_length) ||
1733 127 : byte_offset > buffer_byte_length ||
1734 62 : byte_length > buffer_byte_length - byte_offset) {
1735 5 : return MaybeHandle<JSArrayBufferView>();
1736 : }
1737 60 : uint32_t id = next_id_++;
1738 : ExternalArrayType external_array_type = kExternalInt8Array;
1739 : unsigned element_size = 0;
1740 :
1741 60 : switch (static_cast<ArrayBufferViewTag>(tag)) {
1742 : case ArrayBufferViewTag::kDataView: {
1743 : Handle<JSDataView> data_view =
1744 2 : isolate_->factory()->NewJSDataView(buffer, byte_offset, byte_length);
1745 2 : AddObjectWithID(id, data_view);
1746 2 : return data_view;
1747 : }
1748 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
1749 : case ArrayBufferViewTag::k##Type##Array: \
1750 : external_array_type = kExternal##Type##Array; \
1751 : element_size = sizeof(ctype); \
1752 : break;
1753 6 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
1754 : #undef TYPED_ARRAY_CASE
1755 : }
1756 115 : if (element_size == 0 || byte_offset % element_size != 0 ||
1757 57 : byte_length % element_size != 0) {
1758 2 : return MaybeHandle<JSArrayBufferView>();
1759 : }
1760 : Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray(
1761 56 : external_array_type, buffer, byte_offset, byte_length / element_size,
1762 112 : pretenure_);
1763 56 : AddObjectWithID(id, typed_array);
1764 56 : return typed_array;
1765 : }
1766 :
1767 314 : MaybeHandle<JSObject> ValueDeserializer::ReadWasmModuleTransfer() {
1768 105 : auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
1769 210 : if ((FLAG_wasm_disable_structured_cloning && !enabled_features.threads) ||
1770 : expect_inline_wasm()) {
1771 1 : return MaybeHandle<JSObject>();
1772 : }
1773 :
1774 : uint32_t transfer_id = 0;
1775 : Local<Value> module_value;
1776 312 : if (!ReadVarint<uint32_t>().To(&transfer_id) || delegate_ == nullptr ||
1777 : !delegate_
1778 : ->GetWasmModuleFromId(reinterpret_cast<v8::Isolate*>(isolate_),
1779 104 : transfer_id)
1780 104 : .ToLocal(&module_value)) {
1781 1 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject);
1782 0 : return MaybeHandle<JSObject>();
1783 : }
1784 103 : uint32_t id = next_id_++;
1785 : Handle<JSObject> module =
1786 103 : Handle<JSObject>::cast(Utils::OpenHandle(*module_value));
1787 103 : AddObjectWithID(id, module);
1788 103 : return module;
1789 : }
1790 :
1791 16 : MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() {
1792 8 : auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
1793 16 : if ((FLAG_wasm_disable_structured_cloning && !enabled_features.threads) ||
1794 : !expect_inline_wasm()) {
1795 4 : return MaybeHandle<JSObject>();
1796 : }
1797 :
1798 : Vector<const uint8_t> encoding_tag;
1799 8 : if (!ReadRawBytes(sizeof(WasmEncodingTag)).To(&encoding_tag) ||
1800 4 : encoding_tag[0] != static_cast<uint8_t>(WasmEncodingTag::kRawBytes)) {
1801 0 : return MaybeHandle<JSObject>();
1802 : }
1803 :
1804 : // Extract the data from the buffer: wasm wire bytes, followed by V8 compiled
1805 : // script data.
1806 : static_assert(sizeof(int) <= sizeof(uint32_t),
1807 : "max int must fit in uint32_t");
1808 : const uint32_t max_valid_size = std::numeric_limits<int>::max();
1809 : uint32_t wire_bytes_length = 0;
1810 : Vector<const uint8_t> wire_bytes;
1811 : uint32_t compiled_bytes_length = 0;
1812 4 : Vector<const uint8_t> compiled_bytes;
1813 12 : if (!ReadVarint<uint32_t>().To(&wire_bytes_length) ||
1814 8 : wire_bytes_length > max_valid_size ||
1815 4 : !ReadRawBytes(wire_bytes_length).To(&wire_bytes) ||
1816 12 : !ReadVarint<uint32_t>().To(&compiled_bytes_length) ||
1817 12 : compiled_bytes_length > max_valid_size ||
1818 : !ReadRawBytes(compiled_bytes_length).To(&compiled_bytes)) {
1819 0 : return MaybeHandle<JSObject>();
1820 : }
1821 :
1822 : // Try to deserialize the compiled module first.
1823 : MaybeHandle<WasmModuleObject> result =
1824 4 : wasm::DeserializeNativeModule(isolate_, compiled_bytes, wire_bytes);
1825 4 : if (result.is_null()) {
1826 0 : wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule");
1827 : // TODO(titzer): are the current features appropriate for deserializing?
1828 0 : auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
1829 : result = isolate_->wasm_engine()->SyncCompile(
1830 : isolate_, enabled_features, &thrower,
1831 0 : wasm::ModuleWireBytes(wire_bytes));
1832 : }
1833 4 : uint32_t id = next_id_++;
1834 4 : if (!result.is_null()) {
1835 4 : AddObjectWithID(id, result.ToHandleChecked());
1836 : }
1837 4 : return result;
1838 : }
1839 :
1840 118 : MaybeHandle<WasmMemoryObject> ValueDeserializer::ReadWasmMemory() {
1841 118 : uint32_t id = next_id_++;
1842 :
1843 118 : auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
1844 118 : if (!enabled_features.threads) {
1845 0 : return MaybeHandle<WasmMemoryObject>();
1846 : }
1847 :
1848 : int32_t maximum_pages;
1849 236 : if (!ReadZigZag<int32_t>().To(&maximum_pages)) {
1850 0 : return MaybeHandle<WasmMemoryObject>();
1851 : }
1852 :
1853 : SerializationTag tag;
1854 118 : if (!ReadTag().To(&tag) || tag != SerializationTag::kSharedArrayBuffer) {
1855 0 : return MaybeHandle<WasmMemoryObject>();
1856 : }
1857 :
1858 : const bool is_shared = true;
1859 : Handle<JSArrayBuffer> buffer;
1860 236 : if (!ReadJSArrayBuffer(is_shared).ToHandle(&buffer)) {
1861 0 : return MaybeHandle<WasmMemoryObject>();
1862 : }
1863 :
1864 : Handle<WasmMemoryObject> result =
1865 236 : WasmMemoryObject::New(isolate_, buffer, maximum_pages);
1866 :
1867 118 : AddObjectWithID(id, result);
1868 118 : return result;
1869 : }
1870 :
1871 13 : MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() {
1872 13 : if (!delegate_) return MaybeHandle<JSObject>();
1873 24 : STACK_CHECK(isolate_, MaybeHandle<JSObject>());
1874 12 : uint32_t id = next_id_++;
1875 12 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
1876 : v8::Local<v8::Object> object;
1877 24 : if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) {
1878 0 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject);
1879 0 : return MaybeHandle<JSObject>();
1880 : }
1881 : Handle<JSObject> js_object =
1882 12 : Handle<JSObject>::cast(Utils::OpenHandle(*object));
1883 12 : AddObjectWithID(id, js_object);
1884 12 : return js_object;
1885 : }
1886 :
1887 : // Copies a vector of property values into an object, given the map that should
1888 : // be used.
1889 495 : static void CommitProperties(Handle<JSObject> object, Handle<Map> map,
1890 607 : const std::vector<Handle<Object>>& properties) {
1891 495 : JSObject::AllocateStorageForMap(object, map);
1892 : DCHECK(!object->map()->is_dictionary_map());
1893 :
1894 : DisallowHeapAllocation no_gc;
1895 495 : DescriptorArray descriptors = object->map()->instance_descriptors();
1896 1214 : for (unsigned i = 0; i < properties.size(); i++) {
1897 : // Initializing store.
1898 224 : object->WriteToField(i, descriptors->GetDetails(i), *properties[i]);
1899 : }
1900 495 : }
1901 :
1902 2874 : static bool IsValidObjectKey(Handle<Object> value) {
1903 5828 : return value->IsName() || value->IsNumber();
1904 : }
1905 :
1906 2306 : Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
1907 : Handle<JSObject> object, SerializationTag end_tag,
1908 : bool can_use_transitions) {
1909 : uint32_t num_properties = 0;
1910 :
1911 : // Fast path (following map transitions).
1912 2306 : if (can_use_transitions) {
1913 : bool transitioning = true;
1914 2248 : Handle<Map> map(object->map(), isolate_);
1915 : DCHECK(!map->is_dictionary_map());
1916 : DCHECK_EQ(0, map->instance_descriptors()->number_of_descriptors());
1917 : std::vector<Handle<Object>> properties;
1918 2248 : properties.reserve(8);
1919 :
1920 5016 : while (transitioning) {
1921 : // If there are no more properties, finish.
1922 : SerializationTag tag;
1923 4200 : if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
1924 2360 : if (tag == end_tag) {
1925 87 : ConsumeTag(end_tag);
1926 87 : CommitProperties(object, map, properties);
1927 174 : CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max());
1928 87 : return Just(static_cast<uint32_t>(properties.size()));
1929 : }
1930 :
1931 : // Determine the key to be used and the target map to transition to, if
1932 : // possible. Transitioning may abort if the key is not a string, or if no
1933 : // transition was found.
1934 : Handle<Object> key;
1935 : Handle<Map> target;
1936 2273 : TransitionsAccessor transitions(isolate_, map);
1937 2273 : Handle<String> expected_key = transitions.ExpectedTransitionKey();
1938 2273 : if (!expected_key.is_null() && ReadExpectedString(expected_key)) {
1939 : key = expected_key;
1940 22 : target = transitions.ExpectedTransitionTarget();
1941 : } else {
1942 4502 : if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(key)) {
1943 : return Nothing<uint32_t>();
1944 : }
1945 4498 : if (key->IsString()) {
1946 : key =
1947 2245 : isolate_->factory()->InternalizeString(Handle<String>::cast(key));
1948 : // Don't reuse |transitions| because it could be stale.
1949 : transitioning = TransitionsAccessor(isolate_, map)
1950 4490 : .FindTransitionToField(Handle<String>::cast(key))
1951 : .ToHandle(&target);
1952 : } else {
1953 : transitioning = false;
1954 : }
1955 : }
1956 :
1957 : // Read the value that corresponds to it.
1958 : Handle<Object> value;
1959 4542 : if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
1960 :
1961 : // If still transitioning and the value fits the field representation
1962 : // (though generalization may be required), store the property value so
1963 : // that we can copy them all at once. Otherwise, stop transitioning.
1964 520 : if (transitioning) {
1965 226 : int descriptor = static_cast<int>(properties.size());
1966 : PropertyDetails details =
1967 113 : target->instance_descriptors()->GetDetails(descriptor);
1968 : Representation expected_representation = details.representation();
1969 113 : if (value->FitsRepresentation(expected_representation)) {
1970 336 : if (expected_representation.IsHeapObject() &&
1971 202 : !target->instance_descriptors()
1972 157 : ->GetFieldType(descriptor)
1973 157 : ->NowContains(value)) {
1974 : Handle<FieldType> value_type =
1975 8 : value->OptimalType(isolate_, expected_representation);
1976 : Map::GeneralizeField(isolate_, target, descriptor,
1977 : details.constness(), expected_representation,
1978 4 : value_type);
1979 : }
1980 : DCHECK(target->instance_descriptors()
1981 : ->GetFieldType(descriptor)
1982 : ->NowContains(value));
1983 112 : properties.push_back(value);
1984 112 : map = target;
1985 : continue;
1986 : } else {
1987 : transitioning = false;
1988 : }
1989 : }
1990 :
1991 : // Fell out of transitioning fast path. Commit the properties gathered so
1992 : // far, and then start setting properties slowly instead.
1993 : DCHECK(!transitioning);
1994 816 : CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max());
1995 408 : CommitProperties(object, map, properties);
1996 816 : num_properties = static_cast<uint32_t>(properties.size());
1997 :
1998 : bool success;
1999 : LookupIterator it = LookupIterator::PropertyOrElement(
2000 408 : isolate_, object, key, &success, LookupIterator::OWN);
2001 1224 : if (!success || it.state() != LookupIterator::NOT_FOUND ||
2002 : JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
2003 1224 : .is_null()) {
2004 : return Nothing<uint32_t>();
2005 : }
2006 408 : num_properties++;
2007 : }
2008 :
2009 : // At this point, transitioning should be done, but at least one property
2010 : // should have been written (in the zero-property case, there is an early
2011 : // return).
2012 : DCHECK(!transitioning);
2013 : DCHECK_GE(num_properties, 1u);
2014 : }
2015 :
2016 : // Slow path.
2017 609 : for (;; num_properties++) {
2018 : SerializationTag tag;
2019 1541 : if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
2020 1075 : if (tag == end_tag) {
2021 464 : ConsumeTag(end_tag);
2022 : return Just(num_properties);
2023 : }
2024 :
2025 : Handle<Object> key;
2026 1222 : if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(key)) {
2027 : return Nothing<uint32_t>();
2028 : }
2029 : Handle<Object> value;
2030 1222 : if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
2031 :
2032 : bool success;
2033 : LookupIterator it = LookupIterator::PropertyOrElement(
2034 611 : isolate_, object, key, &success, LookupIterator::OWN);
2035 1833 : if (!success || it.state() != LookupIterator::NOT_FOUND ||
2036 : JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
2037 1829 : .is_null()) {
2038 : return Nothing<uint32_t>();
2039 : }
2040 609 : }
2041 : }
2042 :
2043 0 : bool ValueDeserializer::HasObjectWithID(uint32_t id) {
2044 0 : return id < static_cast<unsigned>(id_map_->length()) &&
2045 0 : !id_map_->get(id)->IsTheHole(isolate_);
2046 : }
2047 :
2048 58 : MaybeHandle<JSReceiver> ValueDeserializer::GetObjectWithID(uint32_t id) {
2049 58 : if (id >= static_cast<unsigned>(id_map_->length())) {
2050 0 : return MaybeHandle<JSReceiver>();
2051 : }
2052 116 : Object value = id_map_->get(id);
2053 116 : if (value->IsTheHole(isolate_)) return MaybeHandle<JSReceiver>();
2054 : DCHECK(value->IsJSReceiver());
2055 116 : return Handle<JSReceiver>(JSReceiver::cast(value), isolate_);
2056 : }
2057 :
2058 6648 : void ValueDeserializer::AddObjectWithID(uint32_t id,
2059 : Handle<JSReceiver> object) {
2060 : DCHECK(!HasObjectWithID(id));
2061 : Handle<FixedArray> new_array =
2062 7426 : FixedArray::SetAndGrow(isolate_, id_map_, id, object);
2063 :
2064 : // If the dictionary was reallocated, update the global handle.
2065 6648 : if (!new_array.is_identical_to(id_map_)) {
2066 778 : GlobalHandles::Destroy(id_map_.location());
2067 1556 : id_map_ = isolate_->global_handles()->Create(*new_array);
2068 : }
2069 6648 : }
2070 :
2071 7 : static Maybe<bool> SetPropertiesFromKeyValuePairs(Isolate* isolate,
2072 : Handle<JSObject> object,
2073 : Handle<Object>* data,
2074 : uint32_t num_properties) {
2075 40 : for (unsigned i = 0; i < 2 * num_properties; i += 2) {
2076 13 : Handle<Object> key = data[i];
2077 13 : if (!IsValidObjectKey(key)) return Nothing<bool>();
2078 13 : Handle<Object> value = data[i + 1];
2079 : bool success;
2080 : LookupIterator it = LookupIterator::PropertyOrElement(
2081 13 : isolate, object, key, &success, LookupIterator::OWN);
2082 39 : if (!success || it.state() != LookupIterator::NOT_FOUND ||
2083 : JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
2084 39 : .is_null()) {
2085 : return Nothing<bool>();
2086 : }
2087 : }
2088 : return Just(true);
2089 : }
2090 :
2091 : namespace {
2092 :
2093 : // Throws a generic "deserialization failed" exception by default, unless a more
2094 : // specific exception has already been thrown.
2095 0 : void ThrowDeserializationExceptionIfNonePending(Isolate* isolate) {
2096 0 : if (!isolate->has_pending_exception()) {
2097 : isolate->Throw(*isolate->factory()->NewError(
2098 0 : MessageTemplate::kDataCloneDeserializationError));
2099 : }
2100 : DCHECK(isolate->has_pending_exception());
2101 0 : }
2102 :
2103 : } // namespace
2104 :
2105 : MaybeHandle<Object>
2106 25 : ValueDeserializer::ReadObjectUsingEntireBufferForLegacyFormat() {
2107 : DCHECK_EQ(version_, 0u);
2108 12 : HandleScope scope(isolate_);
2109 : std::vector<Handle<Object>> stack;
2110 50 : while (position_ < end_) {
2111 : SerializationTag tag;
2112 48 : if (!PeekTag().To(&tag)) break;
2113 :
2114 : Handle<Object> new_object;
2115 38 : switch (tag) {
2116 : case SerializationTag::kEndJSObject: {
2117 5 : ConsumeTag(SerializationTag::kEndJSObject);
2118 :
2119 : // JS Object: Read the last 2*n values from the stack and use them as
2120 : // key-value pairs.
2121 : uint32_t num_properties;
2122 15 : if (!ReadVarint<uint32_t>().To(&num_properties) ||
2123 10 : stack.size() / 2 < num_properties) {
2124 : isolate_->Throw(*isolate_->factory()->NewError(
2125 0 : MessageTemplate::kDataCloneDeserializationError));
2126 0 : return MaybeHandle<Object>();
2127 : }
2128 :
2129 : size_t begin_properties =
2130 10 : stack.size() - 2 * static_cast<size_t>(num_properties);
2131 : Handle<JSObject> js_object = isolate_->factory()->NewJSObject(
2132 5 : isolate_->object_function(), pretenure_);
2133 14 : if (num_properties &&
2134 : !SetPropertiesFromKeyValuePairs(
2135 8 : isolate_, js_object, &stack[begin_properties], num_properties)
2136 9 : .FromMaybe(false)) {
2137 0 : ThrowDeserializationExceptionIfNonePending(isolate_);
2138 0 : return MaybeHandle<Object>();
2139 : }
2140 :
2141 5 : stack.resize(begin_properties);
2142 5 : new_object = js_object;
2143 5 : break;
2144 : }
2145 : case SerializationTag::kEndSparseJSArray: {
2146 4 : ConsumeTag(SerializationTag::kEndSparseJSArray);
2147 :
2148 : // Sparse JS Array: Read the last 2*|num_properties| from the stack.
2149 : uint32_t num_properties;
2150 : uint32_t length;
2151 12 : if (!ReadVarint<uint32_t>().To(&num_properties) ||
2152 12 : !ReadVarint<uint32_t>().To(&length) ||
2153 8 : stack.size() / 2 < num_properties) {
2154 : isolate_->Throw(*isolate_->factory()->NewError(
2155 0 : MessageTemplate::kDataCloneDeserializationError));
2156 0 : return MaybeHandle<Object>();
2157 : }
2158 :
2159 : Handle<JSArray> js_array = isolate_->factory()->NewJSArray(
2160 4 : 0, TERMINAL_FAST_ELEMENTS_KIND, pretenure_);
2161 4 : JSArray::SetLength(js_array, length);
2162 : size_t begin_properties =
2163 8 : stack.size() - 2 * static_cast<size_t>(num_properties);
2164 11 : if (num_properties &&
2165 : !SetPropertiesFromKeyValuePairs(
2166 7 : isolate_, js_array, &stack[begin_properties], num_properties)
2167 7 : .FromMaybe(false)) {
2168 0 : ThrowDeserializationExceptionIfNonePending(isolate_);
2169 0 : return MaybeHandle<Object>();
2170 : }
2171 :
2172 4 : stack.resize(begin_properties);
2173 4 : new_object = js_array;
2174 4 : break;
2175 : }
2176 : case SerializationTag::kEndDenseJSArray: {
2177 : // This was already broken in Chromium, and apparently wasn't missed.
2178 : isolate_->Throw(*isolate_->factory()->NewError(
2179 0 : MessageTemplate::kDataCloneDeserializationError));
2180 0 : return MaybeHandle<Object>();
2181 : }
2182 : default:
2183 58 : if (!ReadObject().ToHandle(&new_object)) return MaybeHandle<Object>();
2184 : break;
2185 : }
2186 38 : stack.push_back(new_object);
2187 : }
2188 :
2189 : // Nothing remains but padding.
2190 : #ifdef DEBUG
2191 : while (position_ < end_) {
2192 : DCHECK(*position_++ == static_cast<uint8_t>(SerializationTag::kPadding));
2193 : }
2194 : #endif
2195 12 : position_ = end_;
2196 :
2197 24 : if (stack.size() != 1) {
2198 : isolate_->Throw(*isolate_->factory()->NewError(
2199 0 : MessageTemplate::kDataCloneDeserializationError));
2200 0 : return MaybeHandle<Object>();
2201 : }
2202 12 : return scope.CloseAndEscape(stack[0]);
2203 : }
2204 :
2205 : } // namespace internal
2206 183867 : } // namespace v8
|