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