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