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