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 2022 : 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 6072 : ZoneAllocationPolicy(&zone_)) {}
197 :
198 4055 : ValueSerializer::~ValueSerializer() {
199 2027 : if (buffer_) {
200 36 : if (delegate_) {
201 30 : delegate_->FreeBufferMemory(buffer_);
202 : } else {
203 6 : free(buffer_);
204 : }
205 : }
206 2028 : }
207 :
208 1858 : void ValueSerializer::WriteHeader() {
209 : WriteTag(SerializationTag::kVersion);
210 1863 : WriteVarint(kLatestVersion);
211 1858 : }
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 14686 : uint8_t raw_tag = static_cast<uint8_t>(tag);
219 14686 : WriteRawBytes(&raw_tag, sizeof(raw_tag));
220 0 : }
221 :
222 : template <typename T>
223 11567 : 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 11752 : do {
233 11752 : *next_byte = (value & 0x7F) | 0x80;
234 11752 : next_byte++;
235 11752 : value >>= 7;
236 : } while (value);
237 11567 : *(next_byte - 1) &= 0x7F;
238 11567 : WriteRawBytes(stack_buffer, next_byte - stack_buffer);
239 11584 : }
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 1225 : 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 24 : WriteRawBytes(&value, sizeof(value));
257 4 : }
258 :
259 0 : void ValueSerializer::WriteOneByteString(Vector<const uint8_t> chars) {
260 4253 : WriteVarint<uint32_t>(chars.length());
261 4252 : 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 30585 : void ValueSerializer::WriteRawBytes(const void* source, size_t length) {
281 : uint8_t* dest;
282 61192 : if (ReserveRawBytes(length).To(&dest) && length > 0) {
283 : memcpy(dest, source, length);
284 : }
285 30607 : }
286 :
287 30607 : Maybe<uint8_t*> ValueSerializer::ReserveRawBytes(size_t bytes) {
288 30607 : size_t old_size = buffer_size_;
289 30607 : size_t new_size = old_size + bytes;
290 30607 : if (V8_UNLIKELY(new_size > buffer_capacity_)) {
291 : bool ok;
292 3861 : if (!ExpandBuffer(new_size).To(&ok)) {
293 : return Nothing<uint8_t*>();
294 : }
295 : }
296 30611 : buffer_size_ = new_size;
297 30611 : return Just(&buffer_[old_size]);
298 : }
299 :
300 1928 : Maybe<bool> ValueSerializer::ExpandBuffer(size_t required_capacity) {
301 : DCHECK_GT(required_capacity, buffer_capacity_);
302 : size_t requested_capacity =
303 3856 : std::max(required_capacity, buffer_capacity_ * 2) + 64;
304 1928 : size_t provided_capacity = 0;
305 : void* new_buffer = nullptr;
306 1928 : if (delegate_) {
307 1788 : new_buffer = delegate_->ReallocateBufferMemory(buffer_, requested_capacity,
308 3576 : &provided_capacity);
309 : } else {
310 140 : new_buffer = realloc(buffer_, requested_capacity);
311 140 : provided_capacity = requested_capacity;
312 : }
313 1934 : if (new_buffer) {
314 : DCHECK(provided_capacity >= requested_capacity);
315 1931 : buffer_ = reinterpret_cast<uint8_t*>(new_buffer);
316 1931 : 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 1810 : std::pair<uint8_t*, size_t> ValueSerializer::Release() {
333 : auto result = std::make_pair(buffer_, buffer_size_);
334 1810 : buffer_ = nullptr;
335 1810 : buffer_size_ = 0;
336 1810 : buffer_capacity_ = 0;
337 1810 : 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 : array_buffer_transfer_map_.Set(array_buffer, transfer_id);
345 47 : }
346 :
347 11990 : 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 11990 : if (V8_UNLIKELY(out_of_memory_)) return ThrowIfOutOfMemory();
352 :
353 11990 : if (object->IsSmi()) {
354 1066 : WriteSmi(Smi::cast(*object));
355 1072 : return ThrowIfOutOfMemory();
356 : }
357 :
358 : DCHECK(object->IsHeapObject());
359 10924 : 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 13 : WriteHeapNumber(HeapNumber::cast(*object));
365 13 : 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 : Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(object);
380 55 : if (!id_map_.Find(view) && !treat_array_buffer_views_as_host_objects_) {
381 : Handle<JSArrayBuffer> buffer(
382 : view->IsJSTypedArray()
383 103 : ? Handle<JSTypedArray>::cast(view)->GetBuffer()
384 103 : : handle(JSArrayBuffer::cast(view->buffer()), isolate_));
385 104 : if (!WriteJSReceiver(buffer).FromMaybe(false)) return Nothing<bool>();
386 : }
387 55 : return WriteJSReceiver(view);
388 : }
389 : default:
390 10717 : if (object->IsString()) {
391 4260 : WriteString(Handle<String>::cast(object));
392 4257 : return ThrowIfOutOfMemory();
393 6457 : } else if (object->IsJSReceiver()) {
394 6457 : 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 1073 : 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 1080 : }
429 :
430 13 : void ValueSerializer::WriteHeapNumber(HeapNumber number) {
431 : WriteTag(SerializationTag::kDouble);
432 : WriteDouble(number->value());
433 13 : }
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 4266 : void ValueSerializer::WriteString(Handle<String> string) {
446 4266 : string = String::Flatten(isolate_, string);
447 : DisallowHeapAllocation no_gc;
448 4267 : String::FlatContent flat = string->GetFlatContent(no_gc);
449 : DCHECK(flat.IsFlat());
450 4264 : 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 4265 : }
466 :
467 6712 : Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
468 : // If the object has already been serialized, just write its ID.
469 : uint32_t* id_map_entry = id_map_.Get(receiver);
470 6711 : 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 6672 : uint32_t id = next_id_++;
478 6672 : *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 6672 : 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 13344 : STACK_CHECK(isolate_, Nothing<bool>());
490 :
491 6670 : HandleScope scope(isolate_);
492 6670 : switch (instance_type) {
493 : case JS_ARRAY_TYPE:
494 2694 : return WriteJSArray(Handle<JSArray>::cast(receiver));
495 : case JS_OBJECT_TYPE:
496 : case JS_API_OBJECT_TYPE: {
497 : Handle<JSObject> js_object = Handle<JSObject>::cast(receiver);
498 3102 : if (JSObject::GetEmbedderFieldCount(js_object->map())) {
499 15 : return WriteHostObject(js_object);
500 : } else {
501 3087 : 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 508 : return WriteJSArrayBuffer(Handle<JSArrayBuffer>::cast(receiver));
520 : case JS_TYPED_ARRAY_TYPE:
521 : case JS_DATA_VIEW_TYPE:
522 53 : return WriteJSArrayBufferView(JSArrayBufferView::cast(*receiver));
523 : case WASM_MODULE_TYPE: {
524 124 : auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
525 124 : if (!FLAG_wasm_disable_structured_cloning || enabled_features.threads) {
526 : // Only write WebAssembly modules if not disabled by a flag.
527 124 : return WriteWasmModule(Handle<WasmModuleObject>::cast(receiver));
528 : }
529 0 : break;
530 : }
531 : case WASM_MEMORY_TYPE: {
532 161 : auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
533 161 : if (enabled_features.threads) {
534 161 : return WriteWasmMemory(Handle<WasmMemoryObject>::cast(receiver));
535 : }
536 0 : break;
537 : }
538 : default:
539 : break;
540 : }
541 :
542 0 : ThrowDataCloneError(MessageTemplate::kDataCloneError, receiver);
543 : return Nothing<bool>();
544 : }
545 :
546 3087 : Maybe<bool> ValueSerializer::WriteJSObject(Handle<JSObject> object) {
547 : DCHECK(!object->map()->IsCustomElementsReceiverMap());
548 : const bool can_serialize_fast =
549 6143 : object->HasFastProperties() && object->elements()->length() == 0;
550 3091 : if (!can_serialize_fast) return WriteJSObjectSlow(object);
551 :
552 3057 : 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 5239 : for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
560 10874 : Handle<Name> key(map->instance_descriptors()->GetKey(i), isolate_);
561 3626 : if (!key->IsString()) continue;
562 3623 : PropertyDetails details = map->instance_descriptors()->GetDetails(i);
563 3623 : if (details.IsDontEnum()) continue;
564 :
565 : Handle<Object> value;
566 3622 : if (V8_LIKELY(!map_changed)) map_changed = *map == object->map();
567 3622 : 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 3622 : LookupIterator it(isolate_, object, key, LookupIterator::OWN);
577 3624 : if (!it.IsFound()) continue;
578 7247 : if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<bool>();
579 : }
580 :
581 10844 : if (!WriteObject(key).FromMaybe(false) ||
582 3614 : !WriteObject(value).FromMaybe(false)) {
583 : return Nothing<bool>();
584 : }
585 1091 : properties_written++;
586 : }
587 :
588 : WriteTag(SerializationTag::kEndJSObject);
589 520 : WriteVarint<uint32_t>(properties_written);
590 522 : 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 102 : if (!KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly,
598 34 : ENUMERABLE_STRINGS)
599 68 : .ToHandle(&keys) ||
600 34 : !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 2694 : Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) {
609 2694 : uint32_t length = 0;
610 5388 : 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 10770 : array->HasFastElements() && !array->HasHoleyElements();
621 :
622 2694 : if (should_serialize_densely) {
623 : DCHECK_LE(length, static_cast<uint32_t>(FixedArray::kMaxLength));
624 : WriteTag(SerializationTag::kBeginDenseJSArray);
625 2681 : 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 2681 : switch (array->GetElementsKind()) {
631 : case PACKED_SMI_ELEMENTS: {
632 : Handle<FixedArray> elements(FixedArray::cast(array->elements()),
633 11 : isolate_);
634 25 : 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 2670 : Handle<Object> old_length(array->length(), isolate_);
651 2858 : for (; i < length; i++) {
652 8185 : if (array->length() != *old_length ||
653 5456 : array->GetElementsKind() != PACKED_ELEMENTS) {
654 : // Fall back to slow path.
655 : break;
656 : }
657 : Handle<Object> element(FixedArray::cast(array->elements())->get(i),
658 2724 : isolate_);
659 5448 : 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 65 : 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 6 : if (!Object::GetProperty(&it).ToHandle(&element) ||
682 2 : !WriteObject(element).FromMaybe(false)) {
683 0 : return Nothing<bool>();
684 : }
685 : }
686 :
687 51 : KeyAccumulator accumulator(isolate_, KeyCollectionMode::kOwnOnly,
688 : ENUMERABLE_STRINGS);
689 102 : if (!accumulator.CollectOwnPropertyNames(array, array).FromMaybe(false)) {
690 : return Nothing<bool>();
691 : }
692 : Handle<FixedArray> keys =
693 51 : accumulator.GetKeys(GetKeysConversion::kConvertToString);
694 : uint32_t properties_written;
695 102 : if (!WriteJSObjectPropertiesSlow(array, keys).To(&properties_written)) {
696 : return Nothing<bool>();
697 : }
698 : WriteTag(SerializationTag::kEndDenseJSArray);
699 51 : WriteVarint<uint32_t>(properties_written);
700 51 : 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 39 : if (!KeyAccumulator::GetKeys(array, KeyCollectionMode::kOwnOnly,
707 13 : ENUMERABLE_STRINGS)
708 26 : .ToHandle(&keys) ||
709 13 : !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 64 : return ThrowIfOutOfMemory();
717 : }
718 :
719 4 : void ValueSerializer::WriteJSDate(JSDate date) {
720 : WriteTag(SerializationTag::kDate);
721 : WriteDouble(date->value()->Number());
722 4 : }
723 :
724 11 : Maybe<bool> ValueSerializer::WriteJSValue(Handle<JSValue> value) {
725 : Object inner_value = value->value();
726 22 : if (inner_value->IsTrue(isolate_)) {
727 : WriteTag(SerializationTag::kTrueObject);
728 9 : } else if (inner_value->IsFalse(isolate_)) {
729 : WriteTag(SerializationTag::kFalseObject);
730 8 : } else if (inner_value->IsNumber()) {
731 : WriteTag(SerializationTag::kNumberObject);
732 : 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 25 : 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 45 : 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 : 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 27 : 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 27 : 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 508 : Maybe<bool> ValueSerializer::WriteJSArrayBuffer(
815 : Handle<JSArrayBuffer> array_buffer) {
816 508 : if (array_buffer->is_shared()) {
817 416 : if (!delegate_) {
818 0 : ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer);
819 : return Nothing<bool>();
820 : }
821 :
822 416 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
823 : Maybe<uint32_t> index = delegate_->GetSharedArrayBufferId(
824 416 : v8_isolate, Utils::ToLocalShared(array_buffer));
825 832 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
826 :
827 : WriteTag(SerializationTag::kSharedArrayBuffer);
828 416 : WriteVarint(index.FromJust());
829 416 : return ThrowIfOutOfMemory();
830 : }
831 :
832 : 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 53 : Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView view) {
854 53 : 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 52 : if (view->IsJSTypedArray()) {
860 51 : 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 11 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
866 : #undef TYPED_ARRAY_CASE
867 : }
868 : } else {
869 : DCHECK(view->IsJSDataView());
870 : tag = ArrayBufferViewTag::kDataView;
871 : }
872 52 : WriteVarint(static_cast<uint8_t>(tag));
873 52 : WriteVarint(static_cast<uint32_t>(view->byte_offset()));
874 52 : WriteVarint(static_cast<uint32_t>(view->byte_length()));
875 52 : return ThrowIfOutOfMemory();
876 : }
877 :
878 124 : Maybe<bool> ValueSerializer::WriteWasmModule(Handle<WasmModuleObject> object) {
879 124 : if (delegate_ != nullptr) {
880 : // TODO(titzer): introduce a Utils::ToLocal for WasmModuleObject.
881 : Maybe<uint32_t> transfer_id = delegate_->GetWasmModuleTransferId(
882 119 : reinterpret_cast<v8::Isolate*>(isolate_),
883 : v8::Local<v8::WasmModuleObject>::Cast(
884 238 : Utils::ToLocal(Handle<JSObject>::cast(object))));
885 357 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
886 : uint32_t id = 0;
887 118 : if (transfer_id.To(&id)) {
888 : WriteTag(SerializationTag::kWasmModuleTransfer);
889 118 : 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 161 : Maybe<bool> ValueSerializer::WriteWasmMemory(Handle<WasmMemoryObject> object) {
920 161 : if (!object->array_buffer()->is_shared()) {
921 8 : ThrowDataCloneError(MessageTemplate::kDataCloneError, object);
922 : return Nothing<bool>();
923 : }
924 :
925 153 : isolate_->wasm_engine()->memory_tracker()->RegisterWasmMemoryAsShared(
926 153 : object, isolate_);
927 :
928 : WriteTag(SerializationTag::kWasmMemoryTransfer);
929 : WriteZigZag<int32_t>(object->maximum_pages());
930 306 : return WriteJSReceiver(Handle<JSReceiver>(object->array_buffer(), isolate_));
931 : }
932 :
933 16 : Maybe<bool> ValueSerializer::WriteHostObject(Handle<JSObject> object) {
934 : WriteTag(SerializationTag::kHostObject);
935 16 : if (!delegate_) {
936 6 : isolate_->Throw(*isolate_->factory()->NewError(
937 6 : isolate_->error_function(), MessageTemplate::kDataCloneError, object));
938 : return Nothing<bool>();
939 : }
940 14 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
941 : Maybe<bool> result =
942 14 : delegate_->WriteHostObject(v8_isolate, Utils::ToLocal(object));
943 28 : RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
944 : USE(result);
945 : DCHECK(!result.IsNothing());
946 : DCHECK(result.ToChecked());
947 14 : return ThrowIfOutOfMemory();
948 : }
949 :
950 98 : Maybe<uint32_t> ValueSerializer::WriteJSObjectPropertiesSlow(
951 : Handle<JSObject> object, Handle<FixedArray> keys) {
952 : uint32_t properties_written = 0;
953 : int length = keys->length();
954 264 : for (int i = 0; i < length; i++) {
955 84 : Handle<Object> key(keys->get(i), isolate_);
956 :
957 : bool success;
958 : LookupIterator it = LookupIterator::PropertyOrElement(
959 84 : isolate_, object, key, &success, LookupIterator::OWN);
960 : DCHECK(success);
961 : Handle<Object> value;
962 169 : if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<uint32_t>();
963 :
964 : // If the property is no longer found, do not serialize it.
965 : // This could happen if a getter deleted the property.
966 90 : if (!it.IsFound()) continue;
967 :
968 228 : if (!WriteObject(key).FromMaybe(false) ||
969 76 : !WriteObject(value).FromMaybe(false)) {
970 : return Nothing<uint32_t>();
971 : }
972 :
973 76 : properties_written++;
974 : }
975 : return Just(properties_written);
976 : }
977 :
978 0 : void ValueSerializer::ThrowDataCloneError(MessageTemplate template_index) {
979 3 : return ThrowDataCloneError(template_index,
980 6 : isolate_->factory()->empty_string());
981 : }
982 :
983 6737 : Maybe<bool> ValueSerializer::ThrowIfOutOfMemory() {
984 6737 : if (out_of_memory_) {
985 : ThrowDataCloneError(MessageTemplate::kDataCloneErrorOutOfMemory);
986 : return Nothing<bool>();
987 : }
988 : return Just(true);
989 : }
990 :
991 12 : void ValueSerializer::ThrowDataCloneError(MessageTemplate index,
992 : Handle<Object> arg0) {
993 12 : Handle<String> message = MessageFormatter::Format(isolate_, index, arg0);
994 12 : if (delegate_) {
995 11 : delegate_->ThrowDataCloneError(Utils::ToLocal(message));
996 : } else {
997 1 : isolate_->Throw(
998 2 : *isolate_->factory()->NewError(isolate_->error_function(), message));
999 : }
1000 24 : if (isolate_->has_scheduled_exception()) {
1001 11 : isolate_->PromoteScheduledException();
1002 : }
1003 12 : }
1004 :
1005 1917 : ValueDeserializer::ValueDeserializer(Isolate* isolate,
1006 : Vector<const uint8_t> data,
1007 : v8::ValueDeserializer::Delegate* delegate)
1008 : : isolate_(isolate),
1009 : delegate_(delegate),
1010 : position_(data.start()),
1011 1917 : end_(data.start() + data.length()),
1012 : allocation_(data.length() > kPretenureThreshold ? AllocationType::kOld
1013 : : AllocationType::kYoung),
1014 : id_map_(isolate->global_handles()->Create(
1015 7668 : ReadOnlyRoots(isolate_).empty_fixed_array())) {}
1016 :
1017 3834 : ValueDeserializer::~ValueDeserializer() {
1018 1917 : GlobalHandles::Destroy(id_map_.location());
1019 :
1020 : Handle<Object> transfer_map_handle;
1021 1917 : if (array_buffer_transfer_map_.ToHandle(&transfer_map_handle)) {
1022 29 : GlobalHandles::Destroy(transfer_map_handle.location());
1023 : }
1024 1917 : }
1025 :
1026 1917 : Maybe<bool> ValueDeserializer::ReadHeader() {
1027 3834 : if (position_ < end_ &&
1028 1917 : *position_ == static_cast<uint8_t>(SerializationTag::kVersion)) {
1029 : ReadTag().ToChecked();
1030 3810 : if (!ReadVarint<uint32_t>().To(&version_) || version_ > kLatestVersion) {
1031 6 : isolate_->Throw(*isolate_->factory()->NewError(
1032 4 : MessageTemplate::kDataCloneDeserializationVersionError));
1033 : return Nothing<bool>();
1034 : }
1035 : }
1036 : return Just(true);
1037 : }
1038 :
1039 0 : Maybe<SerializationTag> ValueDeserializer::PeekTag() const {
1040 7992 : const uint8_t* peek_position = position_;
1041 : SerializationTag tag;
1042 : do {
1043 8055 : if (peek_position >= end_) return Nothing<SerializationTag>();
1044 7992 : tag = static_cast<SerializationTag>(*peek_position);
1045 7992 : peek_position++;
1046 7992 : } while (tag == SerializationTag::kPadding);
1047 : return Just(tag);
1048 : }
1049 :
1050 684 : void ValueDeserializer::ConsumeTag(SerializationTag peeked_tag) {
1051 : SerializationTag actual_tag = ReadTag().ToChecked();
1052 : DCHECK(actual_tag == peeked_tag);
1053 : USE(actual_tag);
1054 684 : }
1055 :
1056 0 : Maybe<SerializationTag> ValueDeserializer::ReadTag() {
1057 : SerializationTag tag;
1058 : do {
1059 24042 : if (position_ >= end_) return Nothing<SerializationTag>();
1060 24042 : tag = static_cast<SerializationTag>(*position_);
1061 24042 : position_++;
1062 24042 : } while (tag == SerializationTag::kPadding);
1063 : return Just(tag);
1064 : }
1065 :
1066 : template <typename T>
1067 21534 : Maybe<T> ValueDeserializer::ReadVarint() {
1068 : // Reads an unsigned integer as a base-128 varint.
1069 : // The number is written, 7 bits at a time, from the least significant to the
1070 : // most significant 7 bits. Each byte, except the last, has the MSB set.
1071 : // If the varint is larger than T, any more significant bits are discarded.
1072 : // See also https://developers.google.com/protocol-buffers/docs/encoding
1073 : static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
1074 : "Only unsigned integer types can be read as varints.");
1075 : T value = 0;
1076 : unsigned shift = 0;
1077 : bool has_another_byte;
1078 21739 : do {
1079 21741 : if (position_ >= end_) return Nothing<T>();
1080 21739 : uint8_t byte = *position_;
1081 21739 : if (V8_LIKELY(shift < sizeof(T) * 8)) {
1082 21739 : value |= static_cast<T>(byte & 0x7F) << shift;
1083 21739 : shift += 7;
1084 : }
1085 21739 : has_another_byte = byte & 0x80;
1086 21739 : position_++;
1087 : } while (has_another_byte);
1088 : return Just(value);
1089 : }
1090 :
1091 : template <typename T>
1092 1287 : Maybe<T> ValueDeserializer::ReadZigZag() {
1093 : // Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is
1094 : // encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on).
1095 : // See also https://developers.google.com/protocol-buffers/docs/encoding
1096 : static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
1097 : "Only signed integer types can be read as zigzag.");
1098 : using UnsignedT = typename std::make_unsigned<T>::type;
1099 : UnsignedT unsigned_value;
1100 2574 : if (!ReadVarint<UnsignedT>().To(&unsigned_value)) return Nothing<T>();
1101 1287 : return Just(static_cast<T>((unsigned_value >> 1) ^
1102 : -static_cast<T>(unsigned_value & 1)));
1103 : }
1104 :
1105 0 : Maybe<double> ValueDeserializer::ReadDouble() {
1106 : // Warning: this uses host endianness.
1107 34 : if (position_ > end_ - sizeof(double)) return Nothing<double>();
1108 : double value;
1109 : memcpy(&value, position_, sizeof(double));
1110 34 : position_ += sizeof(double);
1111 34 : if (std::isnan(value)) value = std::numeric_limits<double>::quiet_NaN();
1112 : return Just(value);
1113 : }
1114 :
1115 0 : Maybe<Vector<const uint8_t>> ValueDeserializer::ReadRawBytes(int size) {
1116 3782 : if (size > end_ - position_) return Nothing<Vector<const uint8_t>>();
1117 : const uint8_t* start = position_;
1118 3779 : position_ += size;
1119 : return Just(Vector<const uint8_t>(start, size));
1120 : }
1121 :
1122 2 : bool ValueDeserializer::ReadUint32(uint32_t* value) {
1123 4 : return ReadVarint<uint32_t>().To(value);
1124 : }
1125 :
1126 2 : bool ValueDeserializer::ReadUint64(uint64_t* value) {
1127 2 : return ReadVarint<uint64_t>().To(value);
1128 : }
1129 :
1130 4 : bool ValueDeserializer::ReadDouble(double* value) {
1131 4 : return ReadDouble().To(value);
1132 : }
1133 :
1134 13 : bool ValueDeserializer::ReadRawBytes(size_t length, const void** data) {
1135 13 : if (length > static_cast<size_t>(end_ - position_)) return false;
1136 13 : *data = position_;
1137 13 : position_ += length;
1138 13 : return true;
1139 : }
1140 :
1141 29 : void ValueDeserializer::TransferArrayBuffer(
1142 : uint32_t transfer_id, Handle<JSArrayBuffer> array_buffer) {
1143 29 : if (array_buffer_transfer_map_.is_null()) {
1144 29 : array_buffer_transfer_map_ = isolate_->global_handles()->Create(
1145 58 : *SimpleNumberDictionary::New(isolate_, 0));
1146 : }
1147 : Handle<SimpleNumberDictionary> dictionary =
1148 : array_buffer_transfer_map_.ToHandleChecked();
1149 : Handle<SimpleNumberDictionary> new_dictionary = SimpleNumberDictionary::Set(
1150 29 : isolate_, dictionary, transfer_id, array_buffer);
1151 29 : if (!new_dictionary.is_identical_to(dictionary)) {
1152 0 : GlobalHandles::Destroy(dictionary.location());
1153 : array_buffer_transfer_map_ =
1154 0 : isolate_->global_handles()->Create(*new_dictionary);
1155 : }
1156 29 : }
1157 :
1158 21271 : MaybeHandle<Object> ValueDeserializer::ReadObject() {
1159 42542 : DisallowJavascriptExecution no_js(isolate_);
1160 : // If we are at the end of the stack, abort. This function may recurse.
1161 42542 : STACK_CHECK(isolate_, MaybeHandle<Object>());
1162 :
1163 21269 : MaybeHandle<Object> result = ReadObjectInternal();
1164 :
1165 : // ArrayBufferView is special in that it consumes the value before it, even
1166 : // after format version 0.
1167 : Handle<Object> object;
1168 : SerializationTag tag;
1169 28206 : if (result.ToHandle(&object) && V8_UNLIKELY(object->IsJSArrayBuffer()) &&
1170 21605 : PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) {
1171 73 : ConsumeTag(SerializationTag::kArrayBufferView);
1172 73 : result = ReadJSArrayBufferView(Handle<JSArrayBuffer>::cast(object));
1173 : }
1174 :
1175 35997 : if (result.is_null() && !isolate_->has_pending_exception()) {
1176 75 : isolate_->Throw(*isolate_->factory()->NewError(
1177 50 : MessageTemplate::kDataCloneDeserializationError));
1178 : }
1179 :
1180 21269 : return result;
1181 : }
1182 :
1183 21269 : MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() {
1184 : SerializationTag tag;
1185 21269 : if (!ReadTag().To(&tag)) return MaybeHandle<Object>();
1186 21269 : switch (tag) {
1187 : case SerializationTag::kVerifyObjectCount:
1188 : // Read the count and ignore it.
1189 18368 : if (ReadVarint<uint32_t>().IsNothing()) return MaybeHandle<Object>();
1190 9184 : return ReadObject();
1191 : case SerializationTag::kUndefined:
1192 186 : return isolate_->factory()->undefined_value();
1193 : case SerializationTag::kNull:
1194 26 : return isolate_->factory()->null_value();
1195 : case SerializationTag::kTrue:
1196 62 : return isolate_->factory()->true_value();
1197 : case SerializationTag::kFalse:
1198 26 : return isolate_->factory()->false_value();
1199 : case SerializationTag::kInt32: {
1200 1134 : Maybe<int32_t> number = ReadZigZag<int32_t>();
1201 1134 : if (number.IsNothing()) return MaybeHandle<Object>();
1202 1134 : return isolate_->factory()->NewNumberFromInt(number.FromJust(),
1203 2268 : allocation_);
1204 : }
1205 : case SerializationTag::kUint32: {
1206 8 : Maybe<uint32_t> number = ReadVarint<uint32_t>();
1207 8 : if (number.IsNothing()) return MaybeHandle<Object>();
1208 8 : return isolate_->factory()->NewNumberFromUint(number.FromJust(),
1209 16 : allocation_);
1210 : }
1211 : case SerializationTag::kDouble: {
1212 : Maybe<double> number = ReadDouble();
1213 16 : if (number.IsNothing()) return MaybeHandle<Object>();
1214 32 : return isolate_->factory()->NewNumber(number.FromJust(), allocation_);
1215 : }
1216 : case SerializationTag::kBigInt:
1217 9 : return ReadBigInt();
1218 : case SerializationTag::kUtf8String:
1219 48 : return ReadUtf8String();
1220 : case SerializationTag::kOneByteString:
1221 3660 : return ReadOneByteString();
1222 : case SerializationTag::kTwoByteString:
1223 16 : return ReadTwoByteString();
1224 : case SerializationTag::kObjectReference: {
1225 : uint32_t id;
1226 112 : if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>();
1227 56 : return GetObjectWithID(id);
1228 : }
1229 : case SerializationTag::kBeginJSObject:
1230 2494 : return ReadJSObject();
1231 : case SerializationTag::kBeginSparseJSArray:
1232 19 : return ReadSparseJSArray();
1233 : case SerializationTag::kBeginDenseJSArray:
1234 3756 : return ReadDenseJSArray();
1235 : case SerializationTag::kDate:
1236 8 : return ReadJSDate();
1237 : case SerializationTag::kTrueObject:
1238 : case SerializationTag::kFalseObject:
1239 : case SerializationTag::kNumberObject:
1240 : case SerializationTag::kBigIntObject:
1241 : case SerializationTag::kStringObject:
1242 21 : return ReadJSValue(tag);
1243 : case SerializationTag::kRegExp:
1244 12 : return ReadJSRegExp();
1245 : case SerializationTag::kBeginJSMap:
1246 8 : return ReadJSMap();
1247 : case SerializationTag::kBeginJSSet:
1248 8 : return ReadJSSet();
1249 : case SerializationTag::kArrayBuffer: {
1250 : const bool is_shared = false;
1251 78 : return ReadJSArrayBuffer(is_shared);
1252 : }
1253 : case SerializationTag::kArrayBufferTransfer: {
1254 29 : return ReadTransferredJSArrayBuffer();
1255 : }
1256 : case SerializationTag::kSharedArrayBuffer: {
1257 : const bool is_shared = true;
1258 263 : return ReadJSArrayBuffer(is_shared);
1259 : }
1260 : case SerializationTag::kWasmModule:
1261 8 : return ReadWasmModule();
1262 : case SerializationTag::kWasmModuleTransfer:
1263 118 : return ReadWasmModuleTransfer();
1264 : case SerializationTag::kWasmMemoryTransfer:
1265 153 : return ReadWasmMemory();
1266 : case SerializationTag::kHostObject:
1267 12 : return ReadHostObject();
1268 : default:
1269 : // Before there was an explicit tag for host objects, all unknown tags
1270 : // were delegated to the host.
1271 1 : if (version_ < 13) {
1272 1 : position_--;
1273 1 : return ReadHostObject();
1274 : }
1275 0 : return MaybeHandle<Object>();
1276 : }
1277 : }
1278 :
1279 19 : MaybeHandle<String> ValueDeserializer::ReadString() {
1280 19 : if (version_ < 12) return ReadUtf8String();
1281 : Handle<Object> object;
1282 27 : if (!ReadObject().ToHandle(&object) || !object->IsString()) {
1283 0 : return MaybeHandle<String>();
1284 : }
1285 9 : return Handle<String>::cast(object);
1286 : }
1287 :
1288 11 : MaybeHandle<BigInt> ValueDeserializer::ReadBigInt() {
1289 : uint32_t bitfield;
1290 22 : if (!ReadVarint<uint32_t>().To(&bitfield)) return MaybeHandle<BigInt>();
1291 11 : int bytelength = BigInt::DigitsByteLengthForBitfield(bitfield);
1292 11 : Vector<const uint8_t> digits_storage;
1293 11 : if (!ReadRawBytes(bytelength).To(&digits_storage)) {
1294 0 : return MaybeHandle<BigInt>();
1295 : }
1296 11 : return BigInt::FromSerializedDigits(isolate_, bitfield, digits_storage,
1297 22 : allocation_);
1298 : }
1299 :
1300 58 : MaybeHandle<String> ValueDeserializer::ReadUtf8String() {
1301 : uint32_t utf8_length;
1302 : Vector<const uint8_t> utf8_bytes;
1303 174 : if (!ReadVarint<uint32_t>().To(&utf8_length) ||
1304 : utf8_length >
1305 116 : static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
1306 58 : !ReadRawBytes(utf8_length).To(&utf8_bytes)) {
1307 1 : return MaybeHandle<String>();
1308 : }
1309 57 : return isolate_->factory()->NewStringFromUtf8(
1310 114 : Vector<const char>::cast(utf8_bytes), allocation_);
1311 : }
1312 :
1313 3660 : MaybeHandle<String> ValueDeserializer::ReadOneByteString() {
1314 : uint32_t byte_length;
1315 3660 : Vector<const uint8_t> bytes;
1316 10980 : if (!ReadVarint<uint32_t>().To(&byte_length) ||
1317 : byte_length >
1318 7320 : static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
1319 3660 : !ReadRawBytes(byte_length).To(&bytes)) {
1320 1 : return MaybeHandle<String>();
1321 : }
1322 3659 : return isolate_->factory()->NewStringFromOneByte(bytes, allocation_);
1323 : }
1324 :
1325 16 : MaybeHandle<String> ValueDeserializer::ReadTwoByteString() {
1326 : uint32_t byte_length;
1327 : Vector<const uint8_t> bytes;
1328 48 : if (!ReadVarint<uint32_t>().To(&byte_length) ||
1329 : byte_length >
1330 16 : static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
1331 31 : byte_length % sizeof(uc16) != 0 ||
1332 15 : !ReadRawBytes(byte_length).To(&bytes)) {
1333 2 : return MaybeHandle<String>();
1334 : }
1335 :
1336 : // Allocate an uninitialized string so that we can do a raw memcpy into the
1337 : // string on the heap (regardless of alignment).
1338 15 : if (byte_length == 0) return isolate_->factory()->empty_string();
1339 : Handle<SeqTwoByteString> string;
1340 26 : if (!isolate_->factory()
1341 39 : ->NewRawTwoByteString(byte_length / sizeof(uc16), allocation_)
1342 : .ToHandle(&string)) {
1343 0 : return MaybeHandle<String>();
1344 : }
1345 :
1346 : // Copy the bytes directly into the new string.
1347 : // Warning: this uses host endianness.
1348 : DisallowHeapAllocation no_gc;
1349 13 : memcpy(string->GetChars(no_gc), bytes.begin(), bytes.length());
1350 13 : return string;
1351 : }
1352 :
1353 26 : bool ValueDeserializer::ReadExpectedString(Handle<String> expected) {
1354 : DisallowHeapAllocation no_gc;
1355 : // In the case of failure, the position in the stream is reset.
1356 26 : const uint8_t* original_position = position_;
1357 :
1358 : SerializationTag tag;
1359 : uint32_t byte_length;
1360 : Vector<const uint8_t> bytes;
1361 78 : if (!ReadTag().To(&tag) || !ReadVarint<uint32_t>().To(&byte_length) ||
1362 : byte_length >
1363 52 : static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
1364 26 : !ReadRawBytes(byte_length).To(&bytes)) {
1365 0 : position_ = original_position;
1366 0 : return false;
1367 : }
1368 :
1369 26 : String::FlatContent flat = expected->GetFlatContent(no_gc);
1370 :
1371 : // If the bytes are verbatim what is in the flattened string, then the string
1372 : // is successfully consumed.
1373 26 : if (tag == SerializationTag::kOneByteString && flat.IsOneByte()) {
1374 : Vector<const uint8_t> chars = flat.ToOneByteVector();
1375 46 : if (byte_length == static_cast<size_t>(chars.length()) &&
1376 23 : memcmp(bytes.begin(), chars.begin(), byte_length) == 0) {
1377 : return true;
1378 : }
1379 3 : } else if (tag == SerializationTag::kTwoByteString && flat.IsTwoByte()) {
1380 : Vector<const uc16> chars = flat.ToUC16Vector();
1381 2 : if (byte_length == static_cast<unsigned>(chars.length()) * sizeof(uc16) &&
1382 1 : memcmp(bytes.begin(), chars.begin(), byte_length) == 0) {
1383 : return true;
1384 : }
1385 2 : } else if (tag == SerializationTag::kUtf8String && flat.IsOneByte()) {
1386 : Vector<const uint8_t> chars = flat.ToOneByteVector();
1387 0 : if (byte_length == static_cast<size_t>(chars.length()) &&
1388 0 : String::IsAscii(chars.begin(), chars.length()) &&
1389 0 : memcmp(bytes.begin(), chars.begin(), byte_length) == 0) {
1390 : return true;
1391 : }
1392 : }
1393 :
1394 4 : position_ = original_position;
1395 4 : return false;
1396 : }
1397 :
1398 2494 : MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() {
1399 : // If we are at the end of the stack, abort. This function may recurse.
1400 4988 : STACK_CHECK(isolate_, MaybeHandle<JSObject>());
1401 :
1402 2494 : uint32_t id = next_id_++;
1403 2494 : HandleScope scope(isolate_);
1404 2494 : Handle<JSObject> object = isolate_->factory()->NewJSObject(
1405 4988 : isolate_->object_function(), allocation_);
1406 2494 : AddObjectWithID(id, object);
1407 :
1408 : uint32_t num_properties;
1409 : uint32_t expected_num_properties;
1410 4988 : if (!ReadJSObjectProperties(object, SerializationTag::kEndJSObject, true)
1411 521 : .To(&num_properties) ||
1412 3015 : !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1413 : num_properties != expected_num_properties) {
1414 1973 : return MaybeHandle<JSObject>();
1415 : }
1416 :
1417 : DCHECK(HasObjectWithID(id));
1418 521 : return scope.CloseAndEscape(object);
1419 : }
1420 :
1421 19 : MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() {
1422 : // If we are at the end of the stack, abort. This function may recurse.
1423 38 : STACK_CHECK(isolate_, MaybeHandle<JSArray>());
1424 :
1425 : uint32_t length;
1426 38 : if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>();
1427 :
1428 19 : uint32_t id = next_id_++;
1429 19 : HandleScope scope(isolate_);
1430 19 : Handle<JSArray> array = isolate_->factory()->NewJSArray(
1431 19 : 0, TERMINAL_FAST_ELEMENTS_KIND, allocation_);
1432 19 : JSArray::SetLength(array, length);
1433 19 : AddObjectWithID(id, array);
1434 :
1435 : uint32_t num_properties;
1436 : uint32_t expected_num_properties;
1437 : uint32_t expected_length;
1438 38 : if (!ReadJSObjectProperties(array, SerializationTag::kEndSparseJSArray, false)
1439 19 : .To(&num_properties) ||
1440 38 : !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1441 38 : !ReadVarint<uint32_t>().To(&expected_length) ||
1442 38 : num_properties != expected_num_properties || length != expected_length) {
1443 0 : return MaybeHandle<JSArray>();
1444 : }
1445 :
1446 : DCHECK(HasObjectWithID(id));
1447 19 : return scope.CloseAndEscape(array);
1448 : }
1449 :
1450 3756 : MaybeHandle<JSArray> ValueDeserializer::ReadDenseJSArray() {
1451 : // If we are at the end of the stack, abort. This function may recurse.
1452 7512 : STACK_CHECK(isolate_, MaybeHandle<JSArray>());
1453 :
1454 : // We shouldn't permit an array larger than the biggest we can request from
1455 : // V8. As an additional sanity check, since each entry will take at least one
1456 : // byte to encode, if there are fewer bytes than that we can also fail fast.
1457 : uint32_t length;
1458 11265 : if (!ReadVarint<uint32_t>().To(&length) ||
1459 7509 : length > static_cast<uint32_t>(FixedArray::kMaxLength) ||
1460 3754 : length > static_cast<size_t>(end_ - position_)) {
1461 2 : return MaybeHandle<JSArray>();
1462 : }
1463 :
1464 3753 : uint32_t id = next_id_++;
1465 3753 : HandleScope scope(isolate_);
1466 3753 : Handle<JSArray> array = isolate_->factory()->NewJSArray(
1467 : HOLEY_ELEMENTS, length, length, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE,
1468 7506 : allocation_);
1469 3753 : AddObjectWithID(id, array);
1470 :
1471 3753 : Handle<FixedArray> elements(FixedArray::cast(array->elements()), isolate_);
1472 3971 : for (uint32_t i = 0; i < length; i++) {
1473 : SerializationTag tag;
1474 3820 : if (PeekTag().To(&tag) && tag == SerializationTag::kTheHole) {
1475 6 : ConsumeTag(SerializationTag::kTheHole);
1476 6 : continue;
1477 : }
1478 :
1479 : Handle<Object> element;
1480 7628 : if (!ReadObject().ToHandle(&element)) return MaybeHandle<JSArray>();
1481 :
1482 : // Serialization versions less than 11 encode the hole the same as
1483 : // undefined. For consistency with previous behavior, store these as the
1484 : // hole. Past version 11, undefined means undefined.
1485 114 : if (version_ < 11 && element->IsUndefined(isolate_)) continue;
1486 :
1487 : // Safety check.
1488 102 : if (i >= static_cast<uint32_t>(elements->length())) {
1489 0 : return MaybeHandle<JSArray>();
1490 : }
1491 :
1492 102 : elements->set(i, *element);
1493 : }
1494 :
1495 : uint32_t num_properties;
1496 : uint32_t expected_num_properties;
1497 : uint32_t expected_length;
1498 84 : if (!ReadJSObjectProperties(array, SerializationTag::kEndDenseJSArray, false)
1499 40 : .To(&num_properties) ||
1500 80 : !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1501 80 : !ReadVarint<uint32_t>().To(&expected_length) ||
1502 82 : num_properties != expected_num_properties || length != expected_length) {
1503 2 : return MaybeHandle<JSArray>();
1504 : }
1505 :
1506 : DCHECK(HasObjectWithID(id));
1507 40 : return scope.CloseAndEscape(array);
1508 : }
1509 :
1510 8 : MaybeHandle<JSDate> ValueDeserializer::ReadJSDate() {
1511 : double value;
1512 8 : if (!ReadDouble().To(&value)) return MaybeHandle<JSDate>();
1513 8 : uint32_t id = next_id_++;
1514 : Handle<JSDate> date;
1515 24 : if (!JSDate::New(isolate_->date_function(), isolate_->date_function(), value)
1516 : .ToHandle(&date)) {
1517 0 : return MaybeHandle<JSDate>();
1518 : }
1519 8 : AddObjectWithID(id, date);
1520 8 : return date;
1521 : }
1522 :
1523 21 : MaybeHandle<JSValue> ValueDeserializer::ReadJSValue(SerializationTag tag) {
1524 21 : uint32_t id = next_id_++;
1525 : Handle<JSValue> value;
1526 21 : switch (tag) {
1527 : case SerializationTag::kTrueObject:
1528 4 : value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
1529 8 : isolate_->boolean_function(), allocation_));
1530 12 : value->set_value(ReadOnlyRoots(isolate_).true_value());
1531 4 : break;
1532 : case SerializationTag::kFalseObject:
1533 2 : value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
1534 4 : isolate_->boolean_function(), allocation_));
1535 6 : value->set_value(ReadOnlyRoots(isolate_).false_value());
1536 2 : break;
1537 : case SerializationTag::kNumberObject: {
1538 : double number;
1539 6 : if (!ReadDouble().To(&number)) return MaybeHandle<JSValue>();
1540 6 : value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
1541 12 : isolate_->number_function(), allocation_));
1542 : Handle<Object> number_object =
1543 6 : isolate_->factory()->NewNumber(number, allocation_);
1544 6 : value->set_value(*number_object);
1545 6 : break;
1546 : }
1547 : case SerializationTag::kBigIntObject: {
1548 : Handle<BigInt> bigint;
1549 4 : if (!ReadBigInt().ToHandle(&bigint)) return MaybeHandle<JSValue>();
1550 2 : value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
1551 4 : isolate_->bigint_function(), allocation_));
1552 4 : value->set_value(*bigint);
1553 : break;
1554 : }
1555 : case SerializationTag::kStringObject: {
1556 : Handle<String> string;
1557 14 : if (!ReadString().ToHandle(&string)) return MaybeHandle<JSValue>();
1558 7 : value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject(
1559 14 : isolate_->string_function(), allocation_));
1560 14 : value->set_value(*string);
1561 : break;
1562 : }
1563 : default:
1564 0 : UNREACHABLE();
1565 : }
1566 21 : AddObjectWithID(id, value);
1567 21 : return value;
1568 : }
1569 :
1570 12 : MaybeHandle<JSRegExp> ValueDeserializer::ReadJSRegExp() {
1571 12 : uint32_t id = next_id_++;
1572 : Handle<String> pattern;
1573 : uint32_t raw_flags;
1574 : Handle<JSRegExp> regexp;
1575 36 : if (!ReadString().ToHandle(&pattern) ||
1576 12 : !ReadVarint<uint32_t>().To(&raw_flags)) {
1577 0 : return MaybeHandle<JSRegExp>();
1578 : }
1579 :
1580 : // Ensure the deserialized flags are valid.
1581 : // TODO(adamk): Can we remove this check now that dotAll is always-on?
1582 : uint32_t flags_mask = static_cast<uint32_t>(-1) << JSRegExp::FlagCount();
1583 23 : if ((raw_flags & flags_mask) ||
1584 22 : !JSRegExp::New(isolate_, pattern, static_cast<JSRegExp::Flags>(raw_flags))
1585 : .ToHandle(®exp)) {
1586 1 : return MaybeHandle<JSRegExp>();
1587 : }
1588 :
1589 11 : AddObjectWithID(id, regexp);
1590 11 : return regexp;
1591 : }
1592 :
1593 8 : MaybeHandle<JSMap> ValueDeserializer::ReadJSMap() {
1594 : // If we are at the end of the stack, abort. This function may recurse.
1595 16 : STACK_CHECK(isolate_, MaybeHandle<JSMap>());
1596 :
1597 8 : HandleScope scope(isolate_);
1598 8 : uint32_t id = next_id_++;
1599 8 : Handle<JSMap> map = isolate_->factory()->NewJSMap();
1600 8 : AddObjectWithID(id, map);
1601 :
1602 8 : Handle<JSFunction> map_set = isolate_->map_set();
1603 : uint32_t length = 0;
1604 : while (true) {
1605 : SerializationTag tag;
1606 24 : if (!PeekTag().To(&tag)) return MaybeHandle<JSMap>();
1607 24 : if (tag == SerializationTag::kEndJSMap) {
1608 8 : ConsumeTag(SerializationTag::kEndJSMap);
1609 8 : break;
1610 : }
1611 :
1612 80 : Handle<Object> argv[2];
1613 48 : if (!ReadObject().ToHandle(&argv[0]) || !ReadObject().ToHandle(&argv[1])) {
1614 0 : return MaybeHandle<JSMap>();
1615 : }
1616 :
1617 32 : AllowJavascriptExecution allow_js(isolate_);
1618 32 : if (Execution::Call(isolate_, map_set, map, arraysize(argv), argv)
1619 : .is_null()) {
1620 0 : return MaybeHandle<JSMap>();
1621 : }
1622 16 : length += 2;
1623 : }
1624 :
1625 : uint32_t expected_length;
1626 24 : if (!ReadVarint<uint32_t>().To(&expected_length) ||
1627 : length != expected_length) {
1628 0 : return MaybeHandle<JSMap>();
1629 : }
1630 : DCHECK(HasObjectWithID(id));
1631 8 : return scope.CloseAndEscape(map);
1632 : }
1633 :
1634 8 : MaybeHandle<JSSet> ValueDeserializer::ReadJSSet() {
1635 : // If we are at the end of the stack, abort. This function may recurse.
1636 16 : STACK_CHECK(isolate_, MaybeHandle<JSSet>());
1637 :
1638 8 : HandleScope scope(isolate_);
1639 8 : uint32_t id = next_id_++;
1640 8 : Handle<JSSet> set = isolate_->factory()->NewJSSet();
1641 8 : AddObjectWithID(id, set);
1642 8 : Handle<JSFunction> set_add = isolate_->set_add();
1643 : uint32_t length = 0;
1644 : while (true) {
1645 : SerializationTag tag;
1646 26 : if (!PeekTag().To(&tag)) return MaybeHandle<JSSet>();
1647 26 : if (tag == SerializationTag::kEndJSSet) {
1648 8 : ConsumeTag(SerializationTag::kEndJSSet);
1649 8 : break;
1650 : }
1651 :
1652 54 : Handle<Object> argv[1];
1653 36 : if (!ReadObject().ToHandle(&argv[0])) return MaybeHandle<JSSet>();
1654 :
1655 36 : AllowJavascriptExecution allow_js(isolate_);
1656 36 : if (Execution::Call(isolate_, set_add, set, arraysize(argv), argv)
1657 : .is_null()) {
1658 0 : return MaybeHandle<JSSet>();
1659 : }
1660 18 : length++;
1661 : }
1662 :
1663 : uint32_t expected_length;
1664 24 : if (!ReadVarint<uint32_t>().To(&expected_length) ||
1665 : length != expected_length) {
1666 0 : return MaybeHandle<JSSet>();
1667 : }
1668 : DCHECK(HasObjectWithID(id));
1669 8 : return scope.CloseAndEscape(set);
1670 : }
1671 :
1672 494 : MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadJSArrayBuffer(
1673 : bool is_shared) {
1674 494 : uint32_t id = next_id_++;
1675 494 : if (is_shared) {
1676 : uint32_t clone_id;
1677 : Local<SharedArrayBuffer> sab_value;
1678 1248 : if (!ReadVarint<uint32_t>().To(&clone_id) || delegate_ == nullptr ||
1679 : !delegate_
1680 416 : ->GetSharedArrayBufferFromId(
1681 416 : reinterpret_cast<v8::Isolate*>(isolate_), clone_id)
1682 : .ToLocal(&sab_value)) {
1683 0 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSArrayBuffer);
1684 0 : return MaybeHandle<JSArrayBuffer>();
1685 : }
1686 : Handle<JSArrayBuffer> array_buffer = Utils::OpenHandle(*sab_value);
1687 : DCHECK_EQ(is_shared, array_buffer->is_shared());
1688 416 : AddObjectWithID(id, array_buffer);
1689 416 : return array_buffer;
1690 : }
1691 : uint32_t byte_length;
1692 234 : if (!ReadVarint<uint32_t>().To(&byte_length) ||
1693 78 : byte_length > static_cast<size_t>(end_ - position_)) {
1694 1 : return MaybeHandle<JSArrayBuffer>();
1695 : }
1696 : const bool should_initialize = false;
1697 77 : Handle<JSArrayBuffer> array_buffer = isolate_->factory()->NewJSArrayBuffer(
1698 154 : SharedFlag::kNotShared, allocation_);
1699 77 : if (!JSArrayBuffer::SetupAllocatingData(array_buffer, isolate_, byte_length,
1700 : should_initialize)) {
1701 1 : return MaybeHandle<JSArrayBuffer>();
1702 : }
1703 76 : if (byte_length > 0) {
1704 72 : memcpy(array_buffer->backing_store(), position_, byte_length);
1705 : }
1706 76 : position_ += byte_length;
1707 76 : AddObjectWithID(id, array_buffer);
1708 76 : return array_buffer;
1709 : }
1710 :
1711 29 : MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadTransferredJSArrayBuffer() {
1712 29 : uint32_t id = next_id_++;
1713 : uint32_t transfer_id;
1714 : Handle<SimpleNumberDictionary> transfer_map;
1715 87 : if (!ReadVarint<uint32_t>().To(&transfer_id) ||
1716 : !array_buffer_transfer_map_.ToHandle(&transfer_map)) {
1717 0 : return MaybeHandle<JSArrayBuffer>();
1718 : }
1719 58 : int index = transfer_map->FindEntry(isolate_, transfer_id);
1720 29 : if (index == SimpleNumberDictionary::kNotFound) {
1721 0 : return MaybeHandle<JSArrayBuffer>();
1722 : }
1723 : Handle<JSArrayBuffer> array_buffer(
1724 87 : JSArrayBuffer::cast(transfer_map->ValueAt(index)), isolate_);
1725 29 : AddObjectWithID(id, array_buffer);
1726 29 : return array_buffer;
1727 : }
1728 :
1729 73 : MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView(
1730 : Handle<JSArrayBuffer> buffer) {
1731 73 : uint32_t buffer_byte_length = static_cast<uint32_t>(buffer->byte_length());
1732 : uint8_t tag = 0;
1733 : uint32_t byte_offset = 0;
1734 : uint32_t byte_length = 0;
1735 219 : if (!ReadVarint<uint8_t>().To(&tag) ||
1736 146 : !ReadVarint<uint32_t>().To(&byte_offset) ||
1737 145 : !ReadVarint<uint32_t>().To(&byte_length) ||
1738 143 : byte_offset > buffer_byte_length ||
1739 70 : byte_length > buffer_byte_length - byte_offset) {
1740 5 : return MaybeHandle<JSArrayBufferView>();
1741 : }
1742 68 : uint32_t id = next_id_++;
1743 : ExternalArrayType external_array_type = kExternalInt8Array;
1744 : unsigned element_size = 0;
1745 :
1746 68 : switch (static_cast<ArrayBufferViewTag>(tag)) {
1747 : case ArrayBufferViewTag::kDataView: {
1748 : Handle<JSDataView> data_view =
1749 2 : isolate_->factory()->NewJSDataView(buffer, byte_offset, byte_length);
1750 2 : AddObjectWithID(id, data_view);
1751 2 : return data_view;
1752 : }
1753 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
1754 : case ArrayBufferViewTag::k##Type##Array: \
1755 : external_array_type = kExternal##Type##Array; \
1756 : element_size = sizeof(ctype); \
1757 : break;
1758 14 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
1759 : #undef TYPED_ARRAY_CASE
1760 : }
1761 131 : if (element_size == 0 || byte_offset % element_size != 0 ||
1762 65 : byte_length % element_size != 0) {
1763 2 : return MaybeHandle<JSArrayBufferView>();
1764 : }
1765 64 : Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray(
1766 64 : external_array_type, buffer, byte_offset, byte_length / element_size,
1767 192 : allocation_);
1768 64 : AddObjectWithID(id, typed_array);
1769 64 : return typed_array;
1770 : }
1771 :
1772 118 : MaybeHandle<JSObject> ValueDeserializer::ReadWasmModuleTransfer() {
1773 118 : auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
1774 118 : if ((FLAG_wasm_disable_structured_cloning && !enabled_features.threads) ||
1775 : expect_inline_wasm()) {
1776 1 : return MaybeHandle<JSObject>();
1777 : }
1778 :
1779 : uint32_t transfer_id = 0;
1780 : Local<Value> module_value;
1781 351 : if (!ReadVarint<uint32_t>().To(&transfer_id) || delegate_ == nullptr ||
1782 : !delegate_
1783 117 : ->GetWasmModuleFromId(reinterpret_cast<v8::Isolate*>(isolate_),
1784 117 : transfer_id)
1785 : .ToLocal(&module_value)) {
1786 2 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject);
1787 0 : return MaybeHandle<JSObject>();
1788 : }
1789 116 : uint32_t id = next_id_++;
1790 : Handle<JSObject> module =
1791 : Handle<JSObject>::cast(Utils::OpenHandle(*module_value));
1792 116 : AddObjectWithID(id, module);
1793 116 : return module;
1794 : }
1795 :
1796 8 : MaybeHandle<JSObject> ValueDeserializer::ReadWasmModule() {
1797 8 : auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
1798 8 : if ((FLAG_wasm_disable_structured_cloning && !enabled_features.threads) ||
1799 : !expect_inline_wasm()) {
1800 4 : return MaybeHandle<JSObject>();
1801 : }
1802 :
1803 : Vector<const uint8_t> encoding_tag;
1804 8 : if (!ReadRawBytes(sizeof(WasmEncodingTag)).To(&encoding_tag) ||
1805 4 : encoding_tag[0] != static_cast<uint8_t>(WasmEncodingTag::kRawBytes)) {
1806 0 : return MaybeHandle<JSObject>();
1807 : }
1808 :
1809 : // Extract the data from the buffer: wasm wire bytes, followed by V8 compiled
1810 : // script data.
1811 : static_assert(sizeof(int) <= sizeof(uint32_t),
1812 : "max int must fit in uint32_t");
1813 : const uint32_t max_valid_size = std::numeric_limits<int>::max();
1814 : uint32_t wire_bytes_length = 0;
1815 : Vector<const uint8_t> wire_bytes;
1816 : uint32_t compiled_bytes_length = 0;
1817 4 : Vector<const uint8_t> compiled_bytes;
1818 12 : if (!ReadVarint<uint32_t>().To(&wire_bytes_length) ||
1819 8 : wire_bytes_length > max_valid_size ||
1820 4 : !ReadRawBytes(wire_bytes_length).To(&wire_bytes) ||
1821 8 : !ReadVarint<uint32_t>().To(&compiled_bytes_length) ||
1822 12 : compiled_bytes_length > max_valid_size ||
1823 : !ReadRawBytes(compiled_bytes_length).To(&compiled_bytes)) {
1824 0 : return MaybeHandle<JSObject>();
1825 : }
1826 :
1827 : // Try to deserialize the compiled module first.
1828 : MaybeHandle<WasmModuleObject> result =
1829 4 : wasm::DeserializeNativeModule(isolate_, compiled_bytes, wire_bytes);
1830 4 : if (result.is_null()) {
1831 0 : wasm::ErrorThrower thrower(isolate_, "ValueDeserializer::ReadWasmModule");
1832 : // TODO(titzer): are the current features appropriate for deserializing?
1833 0 : auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
1834 0 : result = isolate_->wasm_engine()->SyncCompile(
1835 : isolate_, enabled_features, &thrower,
1836 0 : wasm::ModuleWireBytes(wire_bytes));
1837 : }
1838 4 : uint32_t id = next_id_++;
1839 4 : if (!result.is_null()) {
1840 4 : AddObjectWithID(id, result.ToHandleChecked());
1841 : }
1842 4 : return result;
1843 : }
1844 :
1845 153 : MaybeHandle<WasmMemoryObject> ValueDeserializer::ReadWasmMemory() {
1846 153 : uint32_t id = next_id_++;
1847 :
1848 153 : auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_);
1849 153 : if (!enabled_features.threads) {
1850 0 : return MaybeHandle<WasmMemoryObject>();
1851 : }
1852 :
1853 : int32_t maximum_pages;
1854 306 : if (!ReadZigZag<int32_t>().To(&maximum_pages)) {
1855 0 : return MaybeHandle<WasmMemoryObject>();
1856 : }
1857 :
1858 : SerializationTag tag;
1859 153 : if (!ReadTag().To(&tag) || tag != SerializationTag::kSharedArrayBuffer) {
1860 0 : return MaybeHandle<WasmMemoryObject>();
1861 : }
1862 :
1863 : const bool is_shared = true;
1864 : Handle<JSArrayBuffer> buffer;
1865 306 : if (!ReadJSArrayBuffer(is_shared).ToHandle(&buffer)) {
1866 0 : return MaybeHandle<WasmMemoryObject>();
1867 : }
1868 :
1869 : Handle<WasmMemoryObject> result =
1870 306 : WasmMemoryObject::New(isolate_, buffer, maximum_pages);
1871 :
1872 153 : isolate_->wasm_engine()->memory_tracker()->RegisterWasmMemoryAsShared(
1873 153 : result, isolate_);
1874 :
1875 153 : AddObjectWithID(id, result);
1876 153 : return result;
1877 : }
1878 :
1879 13 : MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() {
1880 13 : if (!delegate_) return MaybeHandle<JSObject>();
1881 24 : STACK_CHECK(isolate_, MaybeHandle<JSObject>());
1882 12 : uint32_t id = next_id_++;
1883 12 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
1884 : v8::Local<v8::Object> object;
1885 24 : if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) {
1886 0 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject);
1887 0 : return MaybeHandle<JSObject>();
1888 : }
1889 : Handle<JSObject> js_object =
1890 : Handle<JSObject>::cast(Utils::OpenHandle(*object));
1891 12 : AddObjectWithID(id, js_object);
1892 12 : return js_object;
1893 : }
1894 :
1895 : // Copies a vector of property values into an object, given the map that should
1896 : // be used.
1897 521 : static void CommitProperties(Handle<JSObject> object, Handle<Map> map,
1898 : const std::vector<Handle<Object>>& properties) {
1899 521 : JSObject::AllocateStorageForMap(object, map);
1900 : DCHECK(!object->map()->is_dictionary_map());
1901 :
1902 : DisallowHeapAllocation no_gc;
1903 521 : DescriptorArray descriptors = object->map()->instance_descriptors();
1904 1372 : for (unsigned i = 0; i < properties.size(); i++) {
1905 : // Initializing store.
1906 220 : object->WriteToField(i, descriptors->GetDetails(i), *properties[i]);
1907 : }
1908 521 : }
1909 :
1910 3143 : static bool IsValidObjectKey(Handle<Object> value) {
1911 3183 : return value->IsName() || value->IsNumber();
1912 : }
1913 :
1914 2555 : Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
1915 : Handle<JSObject> object, SerializationTag end_tag,
1916 : bool can_use_transitions) {
1917 : uint32_t num_properties = 0;
1918 :
1919 : // Fast path (following map transitions).
1920 2555 : if (can_use_transitions) {
1921 : bool transitioning = true;
1922 2494 : Handle<Map> map(object->map(), isolate_);
1923 : DCHECK(!map->is_dictionary_map());
1924 : DCHECK_EQ(0, map->instance_descriptors()->number_of_descriptors());
1925 : std::vector<Handle<Object>> properties;
1926 2494 : properties.reserve(8);
1927 :
1928 3040 : while (transitioning) {
1929 : // If there are no more properties, finish.
1930 : SerializationTag tag;
1931 4662 : if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
1932 2604 : if (tag == end_tag) {
1933 85 : ConsumeTag(end_tag);
1934 85 : CommitProperties(object, map, properties);
1935 85 : CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max());
1936 85 : return Just(static_cast<uint32_t>(properties.size()));
1937 : }
1938 :
1939 : // Determine the key to be used and the target map to transition to, if
1940 : // possible. Transitioning may abort if the key is not a string, or if no
1941 : // transition was found.
1942 : Handle<Object> key;
1943 : Handle<Map> target;
1944 2519 : TransitionsAccessor transitions(isolate_, map);
1945 2519 : Handle<String> expected_key = transitions.ExpectedTransitionKey();
1946 2519 : if (!expected_key.is_null() && ReadExpectedString(expected_key)) {
1947 : key = expected_key;
1948 22 : target = transitions.ExpectedTransitionTarget();
1949 : } else {
1950 4994 : if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(key)) {
1951 : return Nothing<uint32_t>();
1952 : }
1953 2495 : if (key->IsString()) {
1954 : key =
1955 2491 : isolate_->factory()->InternalizeString(Handle<String>::cast(key));
1956 : // Don't reuse |transitions| because it could be stale.
1957 2491 : transitioning = TransitionsAccessor(isolate_, map)
1958 2491 : .FindTransitionToField(Handle<String>::cast(key))
1959 : .ToHandle(&target);
1960 : } else {
1961 : transitioning = false;
1962 : }
1963 : }
1964 :
1965 : // Read the value that corresponds to it.
1966 : Handle<Object> value;
1967 5034 : if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
1968 :
1969 : // If still transitioning and the value fits the field representation
1970 : // (though generalization may be required), store the property value so
1971 : // that we can copy them all at once. Otherwise, stop transitioning.
1972 546 : if (transitioning) {
1973 111 : int descriptor = static_cast<int>(properties.size());
1974 : PropertyDetails details =
1975 111 : target->instance_descriptors()->GetDetails(descriptor);
1976 : Representation expected_representation = details.representation();
1977 111 : if (value->FitsRepresentation(expected_representation)) {
1978 263 : if (expected_representation.IsHeapObject() &&
1979 153 : !target->instance_descriptors()
1980 153 : ->GetFieldType(descriptor)
1981 : ->NowContains(value)) {
1982 : Handle<FieldType> value_type =
1983 8 : value->OptimalType(isolate_, expected_representation);
1984 4 : Map::GeneralizeField(isolate_, target, descriptor,
1985 : details.constness(), expected_representation,
1986 4 : value_type);
1987 : }
1988 : DCHECK(target->instance_descriptors()
1989 : ->GetFieldType(descriptor)
1990 : ->NowContains(value));
1991 110 : properties.push_back(value);
1992 : map = target;
1993 : continue;
1994 : } else {
1995 : transitioning = false;
1996 : }
1997 : }
1998 :
1999 : // Fell out of transitioning fast path. Commit the properties gathered so
2000 : // far, and then start setting properties slowly instead.
2001 : DCHECK(!transitioning);
2002 436 : CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max());
2003 436 : CommitProperties(object, map, properties);
2004 436 : num_properties = static_cast<uint32_t>(properties.size());
2005 :
2006 : bool success;
2007 : LookupIterator it = LookupIterator::PropertyOrElement(
2008 436 : isolate_, object, key, &success, LookupIterator::OWN);
2009 872 : if (!success || it.state() != LookupIterator::NOT_FOUND ||
2010 436 : JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
2011 : .is_null()) {
2012 : return Nothing<uint32_t>();
2013 : }
2014 436 : num_properties++;
2015 : }
2016 :
2017 : // At this point, transitioning should be done, but at least one property
2018 : // should have been written (in the zero-property case, there is an early
2019 : // return).
2020 : DCHECK(!transitioning);
2021 : DCHECK_GE(num_properties, 1u);
2022 : }
2023 :
2024 : // Slow path.
2025 632 : for (;; num_properties++) {
2026 : SerializationTag tag;
2027 1626 : if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
2028 1129 : if (tag == end_tag) {
2029 495 : ConsumeTag(end_tag);
2030 : return Just(num_properties);
2031 : }
2032 :
2033 : Handle<Object> key;
2034 1268 : if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(key)) {
2035 : return Nothing<uint32_t>();
2036 : }
2037 : Handle<Object> value;
2038 1268 : if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
2039 :
2040 : bool success;
2041 : LookupIterator it = LookupIterator::PropertyOrElement(
2042 634 : isolate_, object, key, &success, LookupIterator::OWN);
2043 1266 : if (!success || it.state() != LookupIterator::NOT_FOUND ||
2044 632 : JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
2045 : .is_null()) {
2046 : return Nothing<uint32_t>();
2047 : }
2048 : }
2049 : }
2050 :
2051 0 : bool ValueDeserializer::HasObjectWithID(uint32_t id) {
2052 0 : return id < static_cast<unsigned>(id_map_->length()) &&
2053 0 : !id_map_->get(id)->IsTheHole(isolate_);
2054 : }
2055 :
2056 56 : MaybeHandle<JSReceiver> ValueDeserializer::GetObjectWithID(uint32_t id) {
2057 56 : if (id >= static_cast<unsigned>(id_map_->length())) {
2058 0 : return MaybeHandle<JSReceiver>();
2059 : }
2060 56 : Object value = id_map_->get(id);
2061 112 : if (value->IsTheHole(isolate_)) return MaybeHandle<JSReceiver>();
2062 : DCHECK(value->IsJSReceiver());
2063 56 : return Handle<JSReceiver>(JSReceiver::cast(value), isolate_);
2064 : }
2065 :
2066 7194 : void ValueDeserializer::AddObjectWithID(uint32_t id,
2067 : Handle<JSReceiver> object) {
2068 : DCHECK(!HasObjectWithID(id));
2069 : Handle<FixedArray> new_array =
2070 7194 : FixedArray::SetAndGrow(isolate_, id_map_, id, object);
2071 :
2072 : // If the dictionary was reallocated, update the global handle.
2073 7194 : if (!new_array.is_identical_to(id_map_)) {
2074 797 : GlobalHandles::Destroy(id_map_.location());
2075 1594 : id_map_ = isolate_->global_handles()->Create(*new_array);
2076 : }
2077 7194 : }
2078 :
2079 7 : static Maybe<bool> SetPropertiesFromKeyValuePairs(Isolate* isolate,
2080 : Handle<JSObject> object,
2081 : Handle<Object>* data,
2082 : uint32_t num_properties) {
2083 33 : for (unsigned i = 0; i < 2 * num_properties; i += 2) {
2084 13 : Handle<Object> key = data[i];
2085 13 : if (!IsValidObjectKey(key)) return Nothing<bool>();
2086 13 : Handle<Object> value = data[i + 1];
2087 : bool success;
2088 : LookupIterator it = LookupIterator::PropertyOrElement(
2089 13 : isolate, object, key, &success, LookupIterator::OWN);
2090 26 : if (!success || it.state() != LookupIterator::NOT_FOUND ||
2091 13 : JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
2092 : .is_null()) {
2093 : return Nothing<bool>();
2094 : }
2095 : }
2096 : return Just(true);
2097 : }
2098 :
2099 : namespace {
2100 :
2101 : // Throws a generic "deserialization failed" exception by default, unless a more
2102 : // specific exception has already been thrown.
2103 0 : void ThrowDeserializationExceptionIfNonePending(Isolate* isolate) {
2104 0 : if (!isolate->has_pending_exception()) {
2105 0 : isolate->Throw(*isolate->factory()->NewError(
2106 0 : MessageTemplate::kDataCloneDeserializationError));
2107 : }
2108 : DCHECK(isolate->has_pending_exception());
2109 0 : }
2110 :
2111 : } // namespace
2112 :
2113 : MaybeHandle<Object>
2114 12 : ValueDeserializer::ReadObjectUsingEntireBufferForLegacyFormat() {
2115 : DCHECK_EQ(version_, 0u);
2116 12 : HandleScope scope(isolate_);
2117 : std::vector<Handle<Object>> stack;
2118 88 : while (position_ < end_) {
2119 : SerializationTag tag;
2120 48 : if (!PeekTag().To(&tag)) break;
2121 :
2122 : Handle<Object> new_object;
2123 38 : switch (tag) {
2124 : case SerializationTag::kEndJSObject: {
2125 5 : ConsumeTag(SerializationTag::kEndJSObject);
2126 :
2127 : // JS Object: Read the last 2*n values from the stack and use them as
2128 : // key-value pairs.
2129 : uint32_t num_properties;
2130 15 : if (!ReadVarint<uint32_t>().To(&num_properties) ||
2131 5 : stack.size() / 2 < num_properties) {
2132 0 : isolate_->Throw(*isolate_->factory()->NewError(
2133 0 : MessageTemplate::kDataCloneDeserializationError));
2134 0 : return MaybeHandle<Object>();
2135 : }
2136 :
2137 : size_t begin_properties =
2138 5 : stack.size() - 2 * static_cast<size_t>(num_properties);
2139 5 : Handle<JSObject> js_object = isolate_->factory()->NewJSObject(
2140 10 : isolate_->object_function(), allocation_);
2141 9 : if (num_properties &&
2142 4 : !SetPropertiesFromKeyValuePairs(
2143 4 : isolate_, js_object, &stack[begin_properties], num_properties)
2144 : .FromMaybe(false)) {
2145 0 : ThrowDeserializationExceptionIfNonePending(isolate_);
2146 0 : return MaybeHandle<Object>();
2147 : }
2148 :
2149 5 : stack.resize(begin_properties);
2150 5 : new_object = js_object;
2151 5 : break;
2152 : }
2153 : case SerializationTag::kEndSparseJSArray: {
2154 4 : ConsumeTag(SerializationTag::kEndSparseJSArray);
2155 :
2156 : // Sparse JS Array: Read the last 2*|num_properties| from the stack.
2157 : uint32_t num_properties;
2158 : uint32_t length;
2159 12 : if (!ReadVarint<uint32_t>().To(&num_properties) ||
2160 8 : !ReadVarint<uint32_t>().To(&length) ||
2161 4 : stack.size() / 2 < num_properties) {
2162 0 : isolate_->Throw(*isolate_->factory()->NewError(
2163 0 : MessageTemplate::kDataCloneDeserializationError));
2164 0 : return MaybeHandle<Object>();
2165 : }
2166 :
2167 4 : Handle<JSArray> js_array = isolate_->factory()->NewJSArray(
2168 4 : 0, TERMINAL_FAST_ELEMENTS_KIND, allocation_);
2169 4 : JSArray::SetLength(js_array, length);
2170 : size_t begin_properties =
2171 4 : stack.size() - 2 * static_cast<size_t>(num_properties);
2172 7 : if (num_properties &&
2173 3 : !SetPropertiesFromKeyValuePairs(
2174 3 : isolate_, js_array, &stack[begin_properties], num_properties)
2175 : .FromMaybe(false)) {
2176 0 : ThrowDeserializationExceptionIfNonePending(isolate_);
2177 0 : return MaybeHandle<Object>();
2178 : }
2179 :
2180 4 : stack.resize(begin_properties);
2181 4 : new_object = js_array;
2182 : break;
2183 : }
2184 : case SerializationTag::kEndDenseJSArray: {
2185 : // This was already broken in Chromium, and apparently wasn't missed.
2186 0 : isolate_->Throw(*isolate_->factory()->NewError(
2187 0 : MessageTemplate::kDataCloneDeserializationError));
2188 0 : return MaybeHandle<Object>();
2189 : }
2190 : default:
2191 58 : if (!ReadObject().ToHandle(&new_object)) return MaybeHandle<Object>();
2192 : break;
2193 : }
2194 38 : stack.push_back(new_object);
2195 : }
2196 :
2197 : // Nothing remains but padding.
2198 : #ifdef DEBUG
2199 : while (position_ < end_) {
2200 : DCHECK(*position_++ == static_cast<uint8_t>(SerializationTag::kPadding));
2201 : }
2202 : #endif
2203 12 : position_ = end_;
2204 :
2205 12 : if (stack.size() != 1) {
2206 0 : isolate_->Throw(*isolate_->factory()->NewError(
2207 0 : MessageTemplate::kDataCloneDeserializationError));
2208 0 : return MaybeHandle<Object>();
2209 : }
2210 12 : return scope.CloseAndEscape(stack[0]);
2211 : }
2212 :
2213 : } // namespace internal
2214 120216 : } // namespace v8
|