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/objects/value-serializer.h" 6 7#include <type_traits> 8 9#include "include/v8-maybe.h" 10#include "include/v8-value-serializer-version.h" 11#include "include/v8-value-serializer.h" 12#include "include/v8-wasm.h" 13#include "src/api/api-inl.h" 14#include "src/base/logging.h" 15#include "src/base/platform/wrappers.h" 16#include "src/execution/isolate.h" 17#include "src/flags/flags.h" 18#include "src/handles/global-handles-inl.h" 19#include "src/handles/handles-inl.h" 20#include "src/handles/maybe-handles-inl.h" 21#include "src/heap/factory.h" 22#include "src/numbers/conversions.h" 23#include "src/objects/heap-number-inl.h" 24#include "src/objects/js-array-buffer-inl.h" 25#include "src/objects/js-array-inl.h" 26#include "src/objects/js-collection-inl.h" 27#include "src/objects/js-regexp-inl.h" 28#include "src/objects/js-struct-inl.h" 29#include "src/objects/map-updater.h" 30#include "src/objects/objects-inl.h" 31#include "src/objects/objects.h" 32#include "src/objects/oddball-inl.h" 33#include "src/objects/ordered-hash-table-inl.h" 34#include "src/objects/property-descriptor.h" 35#include "src/objects/property-details.h" 36#include "src/objects/smi.h" 37#include "src/objects/transitions-inl.h" 38#include "src/snapshot/code-serializer.h" 39 40#if V8_ENABLE_WEBASSEMBLY 41#include "src/wasm/wasm-objects-inl.h" 42#endif // V8_ENABLE_WEBASSEMBLY 43 44namespace v8 { 45namespace internal { 46 47// Version 9: (imported from Blink) 48// Version 10: one-byte (Latin-1) strings 49// Version 11: properly separate undefined from the hole in arrays 50// Version 12: regexp and string objects share normal string encoding 51// Version 13: host objects have an explicit tag (rather than handling all 52// unknown tags) 53// Version 14: flags for JSArrayBufferViews 54// Version 15: support for shared objects with an explicit tag 55// 56// WARNING: Increasing this value is a change which cannot safely be rolled 57// back without breaking compatibility with data stored on disk. It is 58// strongly recommended that you do not make such changes near a release 59// milestone branch point. 60// 61// Recent changes are routinely reverted in preparation for branch, and this 62// has been the cause of at least one bug in the past. 63static const uint32_t kLatestVersion = 15; 64static_assert(kLatestVersion == v8::CurrentValueSerializerFormatVersion(), 65 "Exported format version must match latest version."); 66 67namespace { 68// For serializing JSArrayBufferView flags. Instead of serializing / 69// deserializing the flags directly, we serialize them bit by bit. This is for 70// ensuring backwards compatilibity in the case where the representation 71// changes. Note that the ValueSerializer data can be stored on disk. 72using JSArrayBufferViewIsLengthTracking = base::BitField<bool, 0, 1>; 73using JSArrayBufferViewIsBackedByRab = 74 JSArrayBufferViewIsLengthTracking::Next<bool, 1>; 75 76} // namespace 77 78template <typename T> 79static size_t BytesNeededForVarint(T value) { 80 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, 81 "Only unsigned integer types can be written as varints."); 82 size_t result = 0; 83 do { 84 result++; 85 value >>= 7; 86 } while (value); 87 return result; 88} 89 90enum class SerializationTag : uint8_t { 91 // version:uint32_t (if at beginning of data, sets version > 0) 92 kVersion = 0xFF, 93 // ignore 94 kPadding = '\0', 95 // refTableSize:uint32_t (previously used for sanity checks; safe to ignore) 96 kVerifyObjectCount = '?', 97 // Oddballs (no data). 98 kTheHole = '-', 99 kUndefined = '_', 100 kNull = '0', 101 kTrue = 'T', 102 kFalse = 'F', 103 // Number represented as 32-bit integer, ZigZag-encoded 104 // (like sint32 in protobuf) 105 kInt32 = 'I', 106 // Number represented as 32-bit unsigned integer, varint-encoded 107 // (like uint32 in protobuf) 108 kUint32 = 'U', 109 // Number represented as a 64-bit double. 110 // Host byte order is used (N.B. this makes the format non-portable). 111 kDouble = 'N', 112 // BigInt. Bitfield:uint32_t, then raw digits storage. 113 kBigInt = 'Z', 114 // byteLength:uint32_t, then raw data 115 kUtf8String = 'S', 116 kOneByteString = '"', 117 kTwoByteString = 'c', 118 // Reference to a serialized object. objectID:uint32_t 119 kObjectReference = '^', 120 // Beginning of a JS object. 121 kBeginJSObject = 'o', 122 // End of a JS object. numProperties:uint32_t 123 kEndJSObject = '{', 124 // Beginning of a sparse JS array. length:uint32_t 125 // Elements and properties are written as key/value pairs, like objects. 126 kBeginSparseJSArray = 'a', 127 // End of a sparse JS array. numProperties:uint32_t length:uint32_t 128 kEndSparseJSArray = '@', 129 // Beginning of a dense JS array. length:uint32_t 130 // |length| elements, followed by properties as key/value pairs 131 kBeginDenseJSArray = 'A', 132 // End of a dense JS array. numProperties:uint32_t length:uint32_t 133 kEndDenseJSArray = '$', 134 // Date. millisSinceEpoch:double 135 kDate = 'D', 136 // Boolean object. No data. 137 kTrueObject = 'y', 138 kFalseObject = 'x', 139 // Number object. value:double 140 kNumberObject = 'n', 141 // BigInt object. Bitfield:uint32_t, then raw digits storage. 142 kBigIntObject = 'z', 143 // String object, UTF-8 encoding. byteLength:uint32_t, then raw data. 144 kStringObject = 's', 145 // Regular expression, UTF-8 encoding. byteLength:uint32_t, raw data, 146 // flags:uint32_t. 147 kRegExp = 'R', 148 // Beginning of a JS map. 149 kBeginJSMap = ';', 150 // End of a JS map. length:uint32_t. 151 kEndJSMap = ':', 152 // Beginning of a JS set. 153 kBeginJSSet = '\'', 154 // End of a JS set. length:uint32_t. 155 kEndJSSet = ',', 156 // Array buffer. byteLength:uint32_t, then raw data. 157 kArrayBuffer = 'B', 158 // Array buffer (transferred). transferID:uint32_t 159 kArrayBufferTransfer = 't', 160 // View into an array buffer. 161 // subtag:ArrayBufferViewTag, byteOffset:uint32_t, byteLength:uint32_t 162 // For typed arrays, byteOffset and byteLength must be divisible by the size 163 // of the element. 164 // Note: kArrayBufferView is special, and should have an ArrayBuffer (or an 165 // ObjectReference to one) serialized just before it. This is a quirk arising 166 // from the previous stack-based implementation. 167 kArrayBufferView = 'V', 168 // Shared array buffer. transferID:uint32_t 169 kSharedArrayBuffer = 'u', 170 // A HeapObject shared across Isolates. sharedValueID:uint32_t 171 kSharedObject = 'p', 172 // A wasm module object transfer. next value is its index. 173 kWasmModuleTransfer = 'w', 174 // The delegate is responsible for processing all following data. 175 // This "escapes" to whatever wire format the delegate chooses. 176 kHostObject = '\\', 177 // A transferred WebAssembly.Memory object. maximumPages:int32_t, then by 178 // SharedArrayBuffer tag and its data. 179 kWasmMemoryTransfer = 'm', 180 // A list of (subtag: ErrorTag, [subtag dependent data]). See ErrorTag for 181 // details. 182 kError = 'r', 183 184 // The following tags are reserved because they were in use in Chromium before 185 // the kHostObject tag was introduced in format version 13, at 186 // v8 refs/heads/master@{#43466} 187 // chromium/src refs/heads/master@{#453568} 188 // 189 // They must not be reused without a version check to prevent old values from 190 // starting to deserialize incorrectly. For simplicity, it's recommended to 191 // avoid them altogether. 192 // 193 // This is the set of tags that existed in SerializationTag.h at that time and 194 // still exist at the time of this writing (i.e., excluding those that were 195 // removed on the Chromium side because there should be no real user data 196 // containing them). 197 // 198 // It might be possible to also free up other tags which were never persisted 199 // (e.g. because they were used only for transfer) in the future. 200 kLegacyReservedMessagePort = 'M', 201 kLegacyReservedBlob = 'b', 202 kLegacyReservedBlobIndex = 'i', 203 kLegacyReservedFile = 'f', 204 kLegacyReservedFileIndex = 'e', 205 kLegacyReservedDOMFileSystem = 'd', 206 kLegacyReservedFileList = 'l', 207 kLegacyReservedFileListIndex = 'L', 208 kLegacyReservedImageData = '#', 209 kLegacyReservedImageBitmap = 'g', 210 kLegacyReservedImageBitmapTransfer = 'G', 211 kLegacyReservedOffscreenCanvas = 'H', 212 kLegacyReservedCryptoKey = 'K', 213 kLegacyReservedRTCCertificate = 'k', 214}; 215 216namespace { 217 218enum class ArrayBufferViewTag : uint8_t { 219 kInt8Array = 'b', 220 kUint8Array = 'B', 221 kUint8ClampedArray = 'C', 222 kInt16Array = 'w', 223 kUint16Array = 'W', 224 kInt32Array = 'd', 225 kUint32Array = 'D', 226 kFloat32Array = 'f', 227 kFloat64Array = 'F', 228 kBigInt64Array = 'q', 229 kBigUint64Array = 'Q', 230 kDataView = '?', 231}; 232 233// Sub-tags only meaningful for error serialization. 234enum class ErrorTag : uint8_t { 235 // The error is a EvalError. No accompanying data. 236 kEvalErrorPrototype = 'E', 237 // The error is a RangeError. No accompanying data. 238 kRangeErrorPrototype = 'R', 239 // The error is a ReferenceError. No accompanying data. 240 kReferenceErrorPrototype = 'F', 241 // The error is a SyntaxError. No accompanying data. 242 kSyntaxErrorPrototype = 'S', 243 // The error is a TypeError. No accompanying data. 244 kTypeErrorPrototype = 'T', 245 // The error is a URIError. No accompanying data. 246 kUriErrorPrototype = 'U', 247 // Followed by message: string. 248 kMessage = 'm', 249 // Followed by a JS object: cause. 250 kCause = 'c', 251 // Followed by stack: string. 252 kStack = 's', 253 // The end of this error information. 254 kEnd = '.', 255}; 256 257} // namespace 258 259ValueSerializer::ValueSerializer(Isolate* isolate, 260 v8::ValueSerializer::Delegate* delegate) 261 : isolate_(isolate), 262 delegate_(delegate), 263 supports_shared_values_(delegate && delegate->SupportsSharedValues()), 264 zone_(isolate->allocator(), ZONE_NAME), 265 id_map_(isolate->heap(), ZoneAllocationPolicy(&zone_)), 266 array_buffer_transfer_map_(isolate->heap(), 267 ZoneAllocationPolicy(&zone_)) {} 268 269ValueSerializer::~ValueSerializer() { 270 if (buffer_) { 271 if (delegate_) { 272 delegate_->FreeBufferMemory(buffer_); 273 } else { 274 base::Free(buffer_); 275 } 276 } 277} 278 279void ValueSerializer::WriteHeader() { 280 WriteTag(SerializationTag::kVersion); 281 WriteVarint(kLatestVersion); 282} 283 284void ValueSerializer::SetTreatArrayBufferViewsAsHostObjects(bool mode) { 285 treat_array_buffer_views_as_host_objects_ = mode; 286} 287 288void ValueSerializer::WriteTag(SerializationTag tag) { 289 uint8_t raw_tag = static_cast<uint8_t>(tag); 290 WriteRawBytes(&raw_tag, sizeof(raw_tag)); 291} 292 293template <typename T> 294void ValueSerializer::WriteVarint(T value) { 295 // Writes an unsigned integer as a base-128 varint. 296 // The number is written, 7 bits at a time, from the least significant to the 297 // most significant 7 bits. Each byte, except the last, has the MSB set. 298 // See also https://developers.google.com/protocol-buffers/docs/encoding 299 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, 300 "Only unsigned integer types can be written as varints."); 301 uint8_t stack_buffer[sizeof(T) * 8 / 7 + 1]; 302 uint8_t* next_byte = &stack_buffer[0]; 303 do { 304 *next_byte = (value & 0x7F) | 0x80; 305 next_byte++; 306 value >>= 7; 307 } while (value); 308 *(next_byte - 1) &= 0x7F; 309 WriteRawBytes(stack_buffer, next_byte - stack_buffer); 310} 311 312template <typename T> 313void ValueSerializer::WriteZigZag(T value) { 314 // Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is 315 // encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on). 316 // See also https://developers.google.com/protocol-buffers/docs/encoding 317 // Note that this implementation relies on the right shift being arithmetic. 318 static_assert(std::is_integral<T>::value && std::is_signed<T>::value, 319 "Only signed integer types can be written as zigzag."); 320 using UnsignedT = typename std::make_unsigned<T>::type; 321 WriteVarint((static_cast<UnsignedT>(value) << 1) ^ 322 (value >> (8 * sizeof(T) - 1))); 323} 324 325template EXPORT_TEMPLATE_DEFINE( 326 V8_EXPORT_PRIVATE) void ValueSerializer::WriteZigZag(int32_t value); 327 328void ValueSerializer::WriteDouble(double value) { 329 // Warning: this uses host endianness. 330 WriteRawBytes(&value, sizeof(value)); 331} 332 333void ValueSerializer::WriteOneByteString(base::Vector<const uint8_t> chars) { 334 WriteVarint<uint32_t>(chars.length()); 335 WriteRawBytes(chars.begin(), chars.length() * sizeof(uint8_t)); 336} 337 338void ValueSerializer::WriteTwoByteString(base::Vector<const base::uc16> chars) { 339 // Warning: this uses host endianness. 340 WriteVarint<uint32_t>(chars.length() * sizeof(base::uc16)); 341 WriteRawBytes(chars.begin(), chars.length() * sizeof(base::uc16)); 342} 343 344void ValueSerializer::WriteBigIntContents(BigInt bigint) { 345 uint32_t bitfield = bigint.GetBitfieldForSerialization(); 346 int bytelength = BigInt::DigitsByteLengthForBitfield(bitfield); 347 WriteVarint<uint32_t>(bitfield); 348 uint8_t* dest; 349 if (ReserveRawBytes(bytelength).To(&dest)) { 350 bigint.SerializeDigits(dest); 351 } 352} 353 354void ValueSerializer::WriteRawBytes(const void* source, size_t length) { 355 uint8_t* dest; 356 if (ReserveRawBytes(length).To(&dest) && length > 0) { 357 memcpy(dest, source, length); 358 } 359} 360 361Maybe<uint8_t*> ValueSerializer::ReserveRawBytes(size_t bytes) { 362 size_t old_size = buffer_size_; 363 size_t new_size = old_size + bytes; 364 if (V8_UNLIKELY(new_size > buffer_capacity_)) { 365 bool ok; 366 if (!ExpandBuffer(new_size).To(&ok)) { 367 return Nothing<uint8_t*>(); 368 } 369 } 370 buffer_size_ = new_size; 371 return Just(&buffer_[old_size]); 372} 373 374Maybe<bool> ValueSerializer::ExpandBuffer(size_t required_capacity) { 375 DCHECK_GT(required_capacity, buffer_capacity_); 376 size_t requested_capacity = 377 std::max(required_capacity, buffer_capacity_ * 2) + 64; 378 size_t provided_capacity = 0; 379 void* new_buffer = nullptr; 380 if (delegate_) { 381 new_buffer = delegate_->ReallocateBufferMemory(buffer_, requested_capacity, 382 &provided_capacity); 383 } else { 384 new_buffer = base::Realloc(buffer_, requested_capacity); 385 provided_capacity = requested_capacity; 386 } 387 if (new_buffer) { 388 DCHECK(provided_capacity >= requested_capacity); 389 buffer_ = reinterpret_cast<uint8_t*>(new_buffer); 390 buffer_capacity_ = provided_capacity; 391 return Just(true); 392 } else { 393 out_of_memory_ = true; 394 return Nothing<bool>(); 395 } 396} 397 398void ValueSerializer::WriteUint32(uint32_t value) { 399 WriteVarint<uint32_t>(value); 400} 401 402void ValueSerializer::WriteUint64(uint64_t value) { 403 WriteVarint<uint64_t>(value); 404} 405 406std::pair<uint8_t*, size_t> ValueSerializer::Release() { 407 auto result = std::make_pair(buffer_, buffer_size_); 408 buffer_ = nullptr; 409 buffer_size_ = 0; 410 buffer_capacity_ = 0; 411 return result; 412} 413 414void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id, 415 Handle<JSArrayBuffer> array_buffer) { 416 DCHECK(!array_buffer_transfer_map_.Find(array_buffer)); 417 DCHECK(!array_buffer->is_shared()); 418 array_buffer_transfer_map_.Insert(array_buffer, transfer_id); 419} 420 421Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) { 422 // There is no sense in trying to proceed if we've previously run out of 423 // memory. Bail immediately, as this likely implies that some write has 424 // previously failed and so the buffer is corrupt. 425 if (V8_UNLIKELY(out_of_memory_)) return ThrowIfOutOfMemory(); 426 427 if (object->IsSmi()) { 428 WriteSmi(Smi::cast(*object)); 429 return ThrowIfOutOfMemory(); 430 } 431 432 DCHECK(object->IsHeapObject()); 433 InstanceType instance_type = 434 HeapObject::cast(*object).map(isolate_).instance_type(); 435 switch (instance_type) { 436 case ODDBALL_TYPE: 437 WriteOddball(Oddball::cast(*object)); 438 return ThrowIfOutOfMemory(); 439 case HEAP_NUMBER_TYPE: 440 WriteHeapNumber(HeapNumber::cast(*object)); 441 return ThrowIfOutOfMemory(); 442 case BIGINT_TYPE: 443 WriteBigInt(BigInt::cast(*object)); 444 return ThrowIfOutOfMemory(); 445 case JS_TYPED_ARRAY_TYPE: 446 case JS_DATA_VIEW_TYPE: { 447 // Despite being JSReceivers, these have their wrapped buffer serialized 448 // first. That makes this logic a little quirky, because it needs to 449 // happen before we assign object IDs. 450 // TODO(jbroman): It may be possible to avoid materializing a typed 451 // array's buffer here. 452 Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(object); 453 if (!id_map_.Find(view) && !treat_array_buffer_views_as_host_objects_) { 454 Handle<JSArrayBuffer> buffer( 455 InstanceTypeChecker::IsJSTypedArray(instance_type) 456 ? Handle<JSTypedArray>::cast(view)->GetBuffer() 457 : handle(JSArrayBuffer::cast(view->buffer()), isolate_)); 458 if (!WriteJSReceiver(buffer).FromMaybe(false)) return Nothing<bool>(); 459 } 460 return WriteJSReceiver(view); 461 } 462 default: 463 if (InstanceTypeChecker::IsString(instance_type)) { 464 auto string = Handle<String>::cast(object); 465 if (FLAG_shared_string_table && supports_shared_values_) { 466 return WriteSharedObject(String::Share(isolate_, string)); 467 } 468 WriteString(string); 469 return ThrowIfOutOfMemory(); 470 } else if (InstanceTypeChecker::IsJSReceiver(instance_type)) { 471 return WriteJSReceiver(Handle<JSReceiver>::cast(object)); 472 } else { 473 return ThrowDataCloneError(MessageTemplate::kDataCloneError, object); 474 } 475 } 476} 477 478void ValueSerializer::WriteOddball(Oddball oddball) { 479 SerializationTag tag = SerializationTag::kUndefined; 480 switch (oddball.kind()) { 481 case Oddball::kUndefined: 482 tag = SerializationTag::kUndefined; 483 break; 484 case Oddball::kFalse: 485 tag = SerializationTag::kFalse; 486 break; 487 case Oddball::kTrue: 488 tag = SerializationTag::kTrue; 489 break; 490 case Oddball::kNull: 491 tag = SerializationTag::kNull; 492 break; 493 default: 494 UNREACHABLE(); 495 } 496 WriteTag(tag); 497} 498 499void ValueSerializer::WriteSmi(Smi smi) { 500 static_assert(kSmiValueSize <= 32, "Expected SMI <= 32 bits."); 501 WriteTag(SerializationTag::kInt32); 502 WriteZigZag<int32_t>(smi.value()); 503} 504 505void ValueSerializer::WriteHeapNumber(HeapNumber number) { 506 WriteTag(SerializationTag::kDouble); 507 WriteDouble(number.value()); 508} 509 510void ValueSerializer::WriteBigInt(BigInt bigint) { 511 WriteTag(SerializationTag::kBigInt); 512 WriteBigIntContents(bigint); 513} 514 515void ValueSerializer::WriteString(Handle<String> string) { 516 string = String::Flatten(isolate_, string); 517 DisallowGarbageCollection no_gc; 518 String::FlatContent flat = string->GetFlatContent(no_gc); 519 DCHECK(flat.IsFlat()); 520 if (flat.IsOneByte()) { 521 base::Vector<const uint8_t> chars = flat.ToOneByteVector(); 522 WriteTag(SerializationTag::kOneByteString); 523 WriteOneByteString(chars); 524 } else if (flat.IsTwoByte()) { 525 base::Vector<const base::uc16> chars = flat.ToUC16Vector(); 526 uint32_t byte_length = chars.length() * sizeof(base::uc16); 527 // The existing reading code expects 16-byte strings to be aligned. 528 if ((buffer_size_ + 1 + BytesNeededForVarint(byte_length)) & 1) 529 WriteTag(SerializationTag::kPadding); 530 WriteTag(SerializationTag::kTwoByteString); 531 WriteTwoByteString(chars); 532 } else { 533 UNREACHABLE(); 534 } 535} 536 537Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) { 538 // If the object has already been serialized, just write its ID. 539 auto find_result = id_map_.FindOrInsert(receiver); 540 if (find_result.already_exists) { 541 WriteTag(SerializationTag::kObjectReference); 542 WriteVarint(*find_result.entry - 1); 543 return ThrowIfOutOfMemory(); 544 } 545 546 // Otherwise, allocate an ID for it. 547 uint32_t id = next_id_++; 548 *find_result.entry = id + 1; 549 550 // Eliminate callable and exotic objects, which should not be serialized. 551 InstanceType instance_type = receiver->map().instance_type(); 552 if (receiver->IsCallable() || (IsSpecialReceiverInstanceType(instance_type) && 553 instance_type != JS_SPECIAL_API_OBJECT_TYPE)) { 554 return ThrowDataCloneError(MessageTemplate::kDataCloneError, receiver); 555 } 556 557 // If we are at the end of the stack, abort. This function may recurse. 558 STACK_CHECK(isolate_, Nothing<bool>()); 559 560 HandleScope scope(isolate_); 561 switch (instance_type) { 562 case JS_ARRAY_TYPE: 563 return WriteJSArray(Handle<JSArray>::cast(receiver)); 564 case JS_ARRAY_ITERATOR_PROTOTYPE_TYPE: 565 case JS_ITERATOR_PROTOTYPE_TYPE: 566 case JS_MAP_ITERATOR_PROTOTYPE_TYPE: 567 case JS_OBJECT_PROTOTYPE_TYPE: 568 case JS_OBJECT_TYPE: 569 case JS_PROMISE_PROTOTYPE_TYPE: 570 case JS_REG_EXP_PROTOTYPE_TYPE: 571 case JS_SET_ITERATOR_PROTOTYPE_TYPE: 572 case JS_SET_PROTOTYPE_TYPE: 573 case JS_STRING_ITERATOR_PROTOTYPE_TYPE: 574 case JS_TYPED_ARRAY_PROTOTYPE_TYPE: 575 case JS_API_OBJECT_TYPE: { 576 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver); 577 if (JSObject::GetEmbedderFieldCount(js_object->map(isolate_))) { 578 return WriteHostObject(js_object); 579 } else { 580 return WriteJSObject(js_object); 581 } 582 } 583 case JS_SPECIAL_API_OBJECT_TYPE: 584 return WriteHostObject(Handle<JSObject>::cast(receiver)); 585 case JS_DATE_TYPE: 586 WriteJSDate(JSDate::cast(*receiver)); 587 return ThrowIfOutOfMemory(); 588 case JS_PRIMITIVE_WRAPPER_TYPE: 589 return WriteJSPrimitiveWrapper( 590 Handle<JSPrimitiveWrapper>::cast(receiver)); 591 case JS_REG_EXP_TYPE: 592 WriteJSRegExp(Handle<JSRegExp>::cast(receiver)); 593 return ThrowIfOutOfMemory(); 594 case JS_MAP_TYPE: 595 return WriteJSMap(Handle<JSMap>::cast(receiver)); 596 case JS_SET_TYPE: 597 return WriteJSSet(Handle<JSSet>::cast(receiver)); 598 case JS_ARRAY_BUFFER_TYPE: 599 return WriteJSArrayBuffer(Handle<JSArrayBuffer>::cast(receiver)); 600 case JS_TYPED_ARRAY_TYPE: 601 case JS_DATA_VIEW_TYPE: 602 return WriteJSArrayBufferView(JSArrayBufferView::cast(*receiver)); 603 case JS_ERROR_TYPE: 604 return WriteJSError(Handle<JSObject>::cast(receiver)); 605 case JS_SHARED_STRUCT_TYPE: 606 return WriteJSSharedStruct(Handle<JSSharedStruct>::cast(receiver)); 607#if V8_ENABLE_WEBASSEMBLY 608 case WASM_MODULE_OBJECT_TYPE: 609 return WriteWasmModule(Handle<WasmModuleObject>::cast(receiver)); 610 case WASM_MEMORY_OBJECT_TYPE: { 611 auto enabled_features = wasm::WasmFeatures::FromIsolate(isolate_); 612 if (enabled_features.has_threads()) { 613 return WriteWasmMemory(Handle<WasmMemoryObject>::cast(receiver)); 614 } 615 break; 616 } 617#endif // V8_ENABLE_WEBASSEMBLY 618 default: 619 break; 620 } 621 622 return ThrowDataCloneError(MessageTemplate::kDataCloneError, receiver); 623} 624 625Maybe<bool> ValueSerializer::WriteJSObject(Handle<JSObject> object) { 626 DCHECK(!object->map().IsCustomElementsReceiverMap()); 627 const bool can_serialize_fast = 628 object->HasFastProperties(isolate_) && object->elements().length() == 0; 629 if (!can_serialize_fast) return WriteJSObjectSlow(object); 630 631 Handle<Map> map(object->map(), isolate_); 632 WriteTag(SerializationTag::kBeginJSObject); 633 634 // Write out fast properties as long as they are only data properties and the 635 // map doesn't change. 636 uint32_t properties_written = 0; 637 bool map_changed = false; 638 for (InternalIndex i : map->IterateOwnDescriptors()) { 639 Handle<Name> key(map->instance_descriptors(isolate_).GetKey(i), isolate_); 640 if (!key->IsString(isolate_)) continue; 641 PropertyDetails details = map->instance_descriptors(isolate_).GetDetails(i); 642 if (details.IsDontEnum()) continue; 643 644 Handle<Object> value; 645 if (V8_LIKELY(!map_changed)) map_changed = *map != object->map(); 646 if (V8_LIKELY(!map_changed && 647 details.location() == PropertyLocation::kField)) { 648 DCHECK_EQ(PropertyKind::kData, details.kind()); 649 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i); 650 value = JSObject::FastPropertyAt(isolate_, object, 651 details.representation(), field_index); 652 } else { 653 // This logic should essentially match WriteJSObjectPropertiesSlow. 654 // If the property is no longer found, do not serialize it. 655 // This could happen if a getter deleted the property. 656 LookupIterator it(isolate_, object, key, LookupIterator::OWN); 657 if (!it.IsFound()) continue; 658 if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<bool>(); 659 } 660 661 if (!WriteObject(key).FromMaybe(false) || 662 !WriteObject(value).FromMaybe(false)) { 663 return Nothing<bool>(); 664 } 665 properties_written++; 666 } 667 668 WriteTag(SerializationTag::kEndJSObject); 669 WriteVarint<uint32_t>(properties_written); 670 return ThrowIfOutOfMemory(); 671} 672 673Maybe<bool> ValueSerializer::WriteJSObjectSlow(Handle<JSObject> object) { 674 WriteTag(SerializationTag::kBeginJSObject); 675 Handle<FixedArray> keys; 676 uint32_t properties_written = 0; 677 if (!KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, 678 ENUMERABLE_STRINGS) 679 .ToHandle(&keys) || 680 !WriteJSObjectPropertiesSlow(object, keys).To(&properties_written)) { 681 return Nothing<bool>(); 682 } 683 WriteTag(SerializationTag::kEndJSObject); 684 WriteVarint<uint32_t>(properties_written); 685 return ThrowIfOutOfMemory(); 686} 687 688Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) { 689 PtrComprCageBase cage_base(isolate_); 690 uint32_t length = 0; 691 bool valid_length = array->length().ToArrayLength(&length); 692 DCHECK(valid_length); 693 USE(valid_length); 694 695 // To keep things simple, for now we decide between dense and sparse 696 // serialization based on elements kind. A more principled heuristic could 697 // count the elements, but would need to take care to note which indices 698 // existed (as only indices which were enumerable own properties at this point 699 // should be serialized). 700 const bool should_serialize_densely = 701 array->HasFastElements(cage_base) && !array->HasHoleyElements(cage_base); 702 703 if (should_serialize_densely) { 704 DCHECK_LE(length, static_cast<uint32_t>(FixedArray::kMaxLength)); 705 WriteTag(SerializationTag::kBeginDenseJSArray); 706 WriteVarint<uint32_t>(length); 707 uint32_t i = 0; 708 709 // Fast paths. Note that PACKED_ELEMENTS in particular can bail due to the 710 // structure of the elements changing. 711 switch (array->GetElementsKind(cage_base)) { 712 case PACKED_SMI_ELEMENTS: { 713 DisallowGarbageCollection no_gc; 714 FixedArray elements = FixedArray::cast(array->elements()); 715 for (i = 0; i < length; i++) 716 WriteSmi(Smi::cast(elements.get(cage_base, i))); 717 break; 718 } 719 case PACKED_DOUBLE_ELEMENTS: { 720 // Elements are empty_fixed_array, not a FixedDoubleArray, if the array 721 // is empty. No elements to encode in this case anyhow. 722 if (length == 0) break; 723 DisallowGarbageCollection no_gc; 724 FixedDoubleArray elements = FixedDoubleArray::cast(array->elements()); 725 for (i = 0; i < length; i++) { 726 WriteTag(SerializationTag::kDouble); 727 WriteDouble(elements.get_scalar(i)); 728 } 729 break; 730 } 731 case PACKED_ELEMENTS: { 732 Handle<Object> old_length(array->length(cage_base), isolate_); 733 for (; i < length; i++) { 734 if (array->length(cage_base) != *old_length || 735 array->GetElementsKind(cage_base) != PACKED_ELEMENTS) { 736 // Fall back to slow path. 737 break; 738 } 739 Handle<Object> element( 740 FixedArray::cast(array->elements()).get(cage_base, i), isolate_); 741 if (!WriteObject(element).FromMaybe(false)) return Nothing<bool>(); 742 } 743 break; 744 } 745 default: 746 break; 747 } 748 749 // If there are elements remaining, serialize them slowly. 750 for (; i < length; i++) { 751 // Serializing the array's elements can have arbitrary side effects, so we 752 // cannot rely on still having fast elements, even if it did to begin 753 // with. 754 Handle<Object> element; 755 LookupIterator it(isolate_, array, i, array, LookupIterator::OWN); 756 if (!it.IsFound()) { 757 // This can happen in the case where an array that was originally dense 758 // became sparse during serialization. It's too late to switch to the 759 // sparse format, but we can mark the elements as absent. 760 WriteTag(SerializationTag::kTheHole); 761 continue; 762 } 763 if (!Object::GetProperty(&it).ToHandle(&element) || 764 !WriteObject(element).FromMaybe(false)) { 765 return Nothing<bool>(); 766 } 767 } 768 769 Handle<FixedArray> keys; 770 if (!KeyAccumulator::GetKeys(array, KeyCollectionMode::kOwnOnly, 771 ENUMERABLE_STRINGS, 772 GetKeysConversion::kKeepNumbers, false, true) 773 .ToHandle(&keys)) { 774 return Nothing<bool>(); 775 } 776 777 uint32_t properties_written; 778 if (!WriteJSObjectPropertiesSlow(array, keys).To(&properties_written)) { 779 return Nothing<bool>(); 780 } 781 WriteTag(SerializationTag::kEndDenseJSArray); 782 WriteVarint<uint32_t>(properties_written); 783 WriteVarint<uint32_t>(length); 784 } else { 785 WriteTag(SerializationTag::kBeginSparseJSArray); 786 WriteVarint<uint32_t>(length); 787 Handle<FixedArray> keys; 788 uint32_t properties_written = 0; 789 if (!KeyAccumulator::GetKeys(array, KeyCollectionMode::kOwnOnly, 790 ENUMERABLE_STRINGS) 791 .ToHandle(&keys) || 792 !WriteJSObjectPropertiesSlow(array, keys).To(&properties_written)) { 793 return Nothing<bool>(); 794 } 795 WriteTag(SerializationTag::kEndSparseJSArray); 796 WriteVarint<uint32_t>(properties_written); 797 WriteVarint<uint32_t>(length); 798 } 799 return ThrowIfOutOfMemory(); 800} 801 802void ValueSerializer::WriteJSDate(JSDate date) { 803 WriteTag(SerializationTag::kDate); 804 WriteDouble(date.value().Number()); 805} 806 807Maybe<bool> ValueSerializer::WriteJSPrimitiveWrapper( 808 Handle<JSPrimitiveWrapper> value) { 809 PtrComprCageBase cage_base(isolate_); 810 { 811 DisallowGarbageCollection no_gc; 812 Object inner_value = value->value(); 813 if (inner_value.IsTrue(isolate_)) { 814 WriteTag(SerializationTag::kTrueObject); 815 } else if (inner_value.IsFalse(isolate_)) { 816 WriteTag(SerializationTag::kFalseObject); 817 } else if (inner_value.IsNumber(cage_base)) { 818 WriteTag(SerializationTag::kNumberObject); 819 WriteDouble(inner_value.Number()); 820 } else if (inner_value.IsBigInt(cage_base)) { 821 WriteTag(SerializationTag::kBigIntObject); 822 WriteBigIntContents(BigInt::cast(inner_value)); 823 } else if (inner_value.IsString(cage_base)) { 824 WriteTag(SerializationTag::kStringObject); 825 WriteString(handle(String::cast(inner_value), isolate_)); 826 } else { 827 AllowGarbageCollection allow_gc; 828 DCHECK(inner_value.IsSymbol()); 829 return ThrowDataCloneError(MessageTemplate::kDataCloneError, value); 830 } 831 } 832 return ThrowIfOutOfMemory(); 833} 834 835void ValueSerializer::WriteJSRegExp(Handle<JSRegExp> regexp) { 836 WriteTag(SerializationTag::kRegExp); 837 WriteString(handle(regexp->source(), isolate_)); 838 WriteVarint(static_cast<uint32_t>(regexp->flags())); 839} 840 841Maybe<bool> ValueSerializer::WriteJSMap(Handle<JSMap> js_map) { 842 // First copy the key-value pairs, since getters could mutate them. 843 Handle<OrderedHashMap> table(OrderedHashMap::cast(js_map->table()), isolate_); 844 int length = table->NumberOfElements() * 2; 845 Handle<FixedArray> entries = isolate_->factory()->NewFixedArray(length); 846 { 847 DisallowGarbageCollection no_gc; 848 OrderedHashMap raw_table = *table; 849 FixedArray raw_entries = *entries; 850 Oddball the_hole = ReadOnlyRoots(isolate_).the_hole_value(); 851 int result_index = 0; 852 for (InternalIndex entry : raw_table.IterateEntries()) { 853 Object key = raw_table.KeyAt(entry); 854 if (key == the_hole) continue; 855 raw_entries.set(result_index++, key); 856 raw_entries.set(result_index++, raw_table.ValueAt(entry)); 857 } 858 DCHECK_EQ(result_index, length); 859 } 860 861 // Then write it out. 862 WriteTag(SerializationTag::kBeginJSMap); 863 for (int i = 0; i < length; i++) { 864 if (!WriteObject(handle(entries->get(i), isolate_)).FromMaybe(false)) { 865 return Nothing<bool>(); 866 } 867 } 868 WriteTag(SerializationTag::kEndJSMap); 869 WriteVarint<uint32_t>(length); 870 return ThrowIfOutOfMemory(); 871} 872 873Maybe<bool> ValueSerializer::WriteJSSet(Handle<JSSet> js_set) { 874 // First copy the element pointers, since getters could mutate them. 875 Handle<OrderedHashSet> table(OrderedHashSet::cast(js_set->table()), isolate_); 876 int length = table->NumberOfElements(); 877 Handle<FixedArray> entries = isolate_->factory()->NewFixedArray(length); 878 { 879 DisallowGarbageCollection no_gc; 880 OrderedHashSet raw_table = *table; 881 FixedArray raw_entries = *entries; 882 Oddball the_hole = ReadOnlyRoots(isolate_).the_hole_value(); 883 int result_index = 0; 884 for (InternalIndex entry : raw_table.IterateEntries()) { 885 Object key = raw_table.KeyAt(entry); 886 if (key == the_hole) continue; 887 raw_entries.set(result_index++, key); 888 } 889 DCHECK_EQ(result_index, length); 890 } 891 892 // Then write it out. 893 WriteTag(SerializationTag::kBeginJSSet); 894 for (int i = 0; i < length; i++) { 895 if (!WriteObject(handle(entries->get(i), isolate_)).FromMaybe(false)) { 896 return Nothing<bool>(); 897 } 898 } 899 WriteTag(SerializationTag::kEndJSSet); 900 WriteVarint<uint32_t>(length); 901 return ThrowIfOutOfMemory(); 902} 903 904Maybe<bool> ValueSerializer::WriteJSArrayBuffer( 905 Handle<JSArrayBuffer> array_buffer) { 906 if (array_buffer->is_shared()) { 907 if (!delegate_) { 908 return ThrowDataCloneError(MessageTemplate::kDataCloneError, 909 array_buffer); 910 } 911 912 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); 913 Maybe<uint32_t> index = delegate_->GetSharedArrayBufferId( 914 v8_isolate, Utils::ToLocalShared(array_buffer)); 915 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>()); 916 917 WriteTag(SerializationTag::kSharedArrayBuffer); 918 WriteVarint(index.FromJust()); 919 return ThrowIfOutOfMemory(); 920 } 921 922 uint32_t* transfer_entry = array_buffer_transfer_map_.Find(array_buffer); 923 if (transfer_entry) { 924 WriteTag(SerializationTag::kArrayBufferTransfer); 925 WriteVarint(*transfer_entry); 926 return ThrowIfOutOfMemory(); 927 } 928 if (array_buffer->was_detached()) { 929 return ThrowDataCloneError( 930 MessageTemplate::kDataCloneErrorDetachedArrayBuffer); 931 } 932 double byte_length = array_buffer->byte_length(); 933 if (byte_length > std::numeric_limits<uint32_t>::max()) { 934 return ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer); 935 } 936 // TODO(v8:11111): Support RAB / GSAB. The wire version will need to be 937 // bumped. 938 WriteTag(SerializationTag::kArrayBuffer); 939 WriteVarint<uint32_t>(byte_length); 940 WriteRawBytes(array_buffer->backing_store(), byte_length); 941 return ThrowIfOutOfMemory(); 942} 943 944Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView view) { 945 if (treat_array_buffer_views_as_host_objects_) { 946 return WriteHostObject(handle(view, isolate_)); 947 } 948 WriteTag(SerializationTag::kArrayBufferView); 949 ArrayBufferViewTag tag = ArrayBufferViewTag::kInt8Array; 950 if (view.IsJSTypedArray()) { 951 switch (JSTypedArray::cast(view).type()) { 952#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \ 953 case kExternal##Type##Array: \ 954 tag = ArrayBufferViewTag::k##Type##Array; \ 955 break; 956 TYPED_ARRAYS(TYPED_ARRAY_CASE) 957#undef TYPED_ARRAY_CASE 958 } 959 } else { 960 DCHECK(view.IsJSDataView()); 961 tag = ArrayBufferViewTag::kDataView; 962 } 963 WriteVarint(static_cast<uint8_t>(tag)); 964 WriteVarint(static_cast<uint32_t>(view.byte_offset())); 965 WriteVarint(static_cast<uint32_t>(view.byte_length())); 966 uint32_t flags = 967 JSArrayBufferViewIsLengthTracking::encode(view.is_length_tracking()) | 968 JSArrayBufferViewIsBackedByRab::encode(view.is_backed_by_rab()); 969 WriteVarint(flags); 970 return ThrowIfOutOfMemory(); 971} 972 973Maybe<bool> ValueSerializer::WriteJSError(Handle<JSObject> error) { 974 Handle<Object> stack; 975 PropertyDescriptor message_desc; 976 Maybe<bool> message_found = JSReceiver::GetOwnPropertyDescriptor( 977 isolate_, error, isolate_->factory()->message_string(), &message_desc); 978 MAYBE_RETURN(message_found, Nothing<bool>()); 979 PropertyDescriptor cause_desc; 980 Maybe<bool> cause_found = JSReceiver::GetOwnPropertyDescriptor( 981 isolate_, error, isolate_->factory()->cause_string(), &cause_desc); 982 983 WriteTag(SerializationTag::kError); 984 985 Handle<Object> name_object; 986 if (!JSObject::GetProperty(isolate_, error, "name").ToHandle(&name_object)) { 987 return Nothing<bool>(); 988 } 989 Handle<String> name; 990 if (!Object::ToString(isolate_, name_object).ToHandle(&name)) { 991 return Nothing<bool>(); 992 } 993 994 if (name->IsOneByteEqualTo(base::CStrVector("EvalError"))) { 995 WriteVarint(static_cast<uint8_t>(ErrorTag::kEvalErrorPrototype)); 996 } else if (name->IsOneByteEqualTo(base::CStrVector("RangeError"))) { 997 WriteVarint(static_cast<uint8_t>(ErrorTag::kRangeErrorPrototype)); 998 } else if (name->IsOneByteEqualTo(base::CStrVector("ReferenceError"))) { 999 WriteVarint(static_cast<uint8_t>(ErrorTag::kReferenceErrorPrototype)); 1000 } else if (name->IsOneByteEqualTo(base::CStrVector("SyntaxError"))) { 1001 WriteVarint(static_cast<uint8_t>(ErrorTag::kSyntaxErrorPrototype)); 1002 } else if (name->IsOneByteEqualTo(base::CStrVector("TypeError"))) { 1003 WriteVarint(static_cast<uint8_t>(ErrorTag::kTypeErrorPrototype)); 1004 } else if (name->IsOneByteEqualTo(base::CStrVector("URIError"))) { 1005 WriteVarint(static_cast<uint8_t>(ErrorTag::kUriErrorPrototype)); 1006 } else { 1007 // The default prototype in the deserialization side is Error.prototype, so 1008 // we don't have to do anything here. 1009 } 1010 1011 if (message_found.FromJust() && 1012 PropertyDescriptor::IsDataDescriptor(&message_desc)) { 1013 Handle<String> message; 1014 if (!Object::ToString(isolate_, message_desc.value()).ToHandle(&message)) { 1015 return Nothing<bool>(); 1016 } 1017 WriteVarint(static_cast<uint8_t>(ErrorTag::kMessage)); 1018 WriteString(message); 1019 } 1020 1021 if (cause_found.FromJust() && 1022 PropertyDescriptor::IsDataDescriptor(&cause_desc)) { 1023 Handle<Object> cause = cause_desc.value(); 1024 WriteVarint(static_cast<uint8_t>(ErrorTag::kCause)); 1025 if (!WriteObject(cause).FromMaybe(false)) { 1026 return Nothing<bool>(); 1027 } 1028 } 1029 1030 if (!Object::GetProperty(isolate_, error, isolate_->factory()->stack_string()) 1031 .ToHandle(&stack)) { 1032 return Nothing<bool>(); 1033 } 1034 if (stack->IsString()) { 1035 WriteVarint(static_cast<uint8_t>(ErrorTag::kStack)); 1036 WriteString(Handle<String>::cast(stack)); 1037 } 1038 1039 WriteVarint(static_cast<uint8_t>(ErrorTag::kEnd)); 1040 return ThrowIfOutOfMemory(); 1041} 1042 1043Maybe<bool> ValueSerializer::WriteJSSharedStruct( 1044 Handle<JSSharedStruct> shared_struct) { 1045 // TODO(v8:12547): Support copying serialization for shared structs as well. 1046 return WriteSharedObject(shared_struct); 1047} 1048 1049#if V8_ENABLE_WEBASSEMBLY 1050Maybe<bool> ValueSerializer::WriteWasmModule(Handle<WasmModuleObject> object) { 1051 if (delegate_ == nullptr) { 1052 return ThrowDataCloneError(MessageTemplate::kDataCloneError, object); 1053 } 1054 1055 // TODO(titzer): introduce a Utils::ToLocal for WasmModuleObject. 1056 Maybe<uint32_t> transfer_id = delegate_->GetWasmModuleTransferId( 1057 reinterpret_cast<v8::Isolate*>(isolate_), 1058 v8::Local<v8::WasmModuleObject>::Cast( 1059 Utils::ToLocal(Handle<JSObject>::cast(object)))); 1060 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>()); 1061 uint32_t id = 0; 1062 if (transfer_id.To(&id)) { 1063 WriteTag(SerializationTag::kWasmModuleTransfer); 1064 WriteVarint<uint32_t>(id); 1065 return Just(true); 1066 } 1067 return ThrowIfOutOfMemory(); 1068} 1069 1070Maybe<bool> ValueSerializer::WriteWasmMemory(Handle<WasmMemoryObject> object) { 1071 if (!object->array_buffer().is_shared()) { 1072 return ThrowDataCloneError(MessageTemplate::kDataCloneError, object); 1073 } 1074 1075 GlobalBackingStoreRegistry::Register( 1076 object->array_buffer().GetBackingStore()); 1077 1078 WriteTag(SerializationTag::kWasmMemoryTransfer); 1079 WriteZigZag<int32_t>(object->maximum_pages()); 1080 return WriteJSReceiver(Handle<JSReceiver>(object->array_buffer(), isolate_)); 1081} 1082#endif // V8_ENABLE_WEBASSEMBLY 1083 1084Maybe<bool> ValueSerializer::WriteSharedObject(Handle<HeapObject> object) { 1085 DCHECK(object->IsShared()); 1086 DCHECK(supports_shared_values_); 1087 DCHECK_NOT_NULL(delegate_); 1088 DCHECK(delegate_->SupportsSharedValues()); 1089 1090 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); 1091 Maybe<uint32_t> index = 1092 delegate_->GetSharedValueId(v8_isolate, Utils::ToLocal(object)); 1093 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>()); 1094 1095 WriteTag(SerializationTag::kSharedObject); 1096 WriteVarint(index.FromJust()); 1097 return ThrowIfOutOfMemory(); 1098} 1099 1100Maybe<bool> ValueSerializer::WriteHostObject(Handle<JSObject> object) { 1101 WriteTag(SerializationTag::kHostObject); 1102 if (!delegate_) { 1103 isolate_->Throw(*isolate_->factory()->NewError( 1104 isolate_->error_function(), MessageTemplate::kDataCloneError, object)); 1105 return Nothing<bool>(); 1106 } 1107 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); 1108 Maybe<bool> result = 1109 delegate_->WriteHostObject(v8_isolate, Utils::ToLocal(object)); 1110 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>()); 1111 USE(result); 1112 DCHECK(!result.IsNothing()); 1113 DCHECK(result.ToChecked()); 1114 return ThrowIfOutOfMemory(); 1115} 1116 1117Maybe<uint32_t> ValueSerializer::WriteJSObjectPropertiesSlow( 1118 Handle<JSObject> object, Handle<FixedArray> keys) { 1119 uint32_t properties_written = 0; 1120 int length = keys->length(); 1121 for (int i = 0; i < length; i++) { 1122 Handle<Object> key(keys->get(i), isolate_); 1123 1124 PropertyKey lookup_key(isolate_, key); 1125 LookupIterator it(isolate_, object, lookup_key, LookupIterator::OWN); 1126 Handle<Object> value; 1127 if (!Object::GetProperty(&it).ToHandle(&value)) return Nothing<uint32_t>(); 1128 1129 // If the property is no longer found, do not serialize it. 1130 // This could happen if a getter deleted the property. 1131 if (!it.IsFound()) continue; 1132 1133 if (!WriteObject(key).FromMaybe(false) || 1134 !WriteObject(value).FromMaybe(false)) { 1135 return Nothing<uint32_t>(); 1136 } 1137 1138 properties_written++; 1139 } 1140 return Just(properties_written); 1141} 1142 1143Maybe<bool> ValueSerializer::ThrowIfOutOfMemory() { 1144 if (out_of_memory_) { 1145 return ThrowDataCloneError(MessageTemplate::kDataCloneErrorOutOfMemory); 1146 } 1147 return Just(true); 1148} 1149 1150Maybe<bool> ValueSerializer::ThrowDataCloneError( 1151 MessageTemplate template_index) { 1152 return ThrowDataCloneError(template_index, 1153 isolate_->factory()->empty_string()); 1154} 1155 1156Maybe<bool> ValueSerializer::ThrowDataCloneError(MessageTemplate index, 1157 Handle<Object> arg0) { 1158 Handle<String> message = MessageFormatter::Format(isolate_, index, arg0); 1159 if (delegate_) { 1160 delegate_->ThrowDataCloneError(Utils::ToLocal(message)); 1161 } else { 1162 isolate_->Throw( 1163 *isolate_->factory()->NewError(isolate_->error_function(), message)); 1164 } 1165 if (isolate_->has_scheduled_exception()) { 1166 isolate_->PromoteScheduledException(); 1167 } 1168 return Nothing<bool>(); 1169} 1170 1171ValueDeserializer::ValueDeserializer(Isolate* isolate, 1172 base::Vector<const uint8_t> data, 1173 v8::ValueDeserializer::Delegate* delegate) 1174 : isolate_(isolate), 1175 delegate_(delegate), 1176 position_(data.begin()), 1177 end_(data.end()), 1178 supports_shared_values_(delegate && delegate->SupportsSharedValues()), 1179 id_map_(isolate->global_handles()->Create( 1180 ReadOnlyRoots(isolate_).empty_fixed_array())) {} 1181 1182ValueDeserializer::ValueDeserializer(Isolate* isolate, const uint8_t* data, 1183 size_t size) 1184 : isolate_(isolate), 1185 delegate_(nullptr), 1186 position_(data), 1187 end_(data + size), 1188 supports_shared_values_(false), 1189 id_map_(isolate->global_handles()->Create( 1190 ReadOnlyRoots(isolate_).empty_fixed_array())) {} 1191 1192ValueDeserializer::~ValueDeserializer() { 1193 GlobalHandles::Destroy(id_map_.location()); 1194 1195 Handle<Object> transfer_map_handle; 1196 if (array_buffer_transfer_map_.ToHandle(&transfer_map_handle)) { 1197 GlobalHandles::Destroy(transfer_map_handle.location()); 1198 } 1199} 1200 1201Maybe<bool> ValueDeserializer::ReadHeader() { 1202 if (position_ < end_ && 1203 *position_ == static_cast<uint8_t>(SerializationTag::kVersion)) { 1204 ReadTag().ToChecked(); 1205 if (!ReadVarint<uint32_t>().To(&version_) || version_ > kLatestVersion) { 1206 isolate_->Throw(*isolate_->factory()->NewError( 1207 MessageTemplate::kDataCloneDeserializationVersionError)); 1208 return Nothing<bool>(); 1209 } 1210 } 1211 return Just(true); 1212} 1213 1214Maybe<SerializationTag> ValueDeserializer::PeekTag() const { 1215 const uint8_t* peek_position = position_; 1216 SerializationTag tag; 1217 do { 1218 if (peek_position >= end_) return Nothing<SerializationTag>(); 1219 tag = static_cast<SerializationTag>(*peek_position); 1220 peek_position++; 1221 } while (tag == SerializationTag::kPadding); 1222 return Just(tag); 1223} 1224 1225void ValueDeserializer::ConsumeTag(SerializationTag peeked_tag) { 1226 SerializationTag actual_tag = ReadTag().ToChecked(); 1227 DCHECK(actual_tag == peeked_tag); 1228 USE(actual_tag); 1229} 1230 1231Maybe<SerializationTag> ValueDeserializer::ReadTag() { 1232 SerializationTag tag; 1233 do { 1234 if (position_ >= end_) return Nothing<SerializationTag>(); 1235 tag = static_cast<SerializationTag>(*position_); 1236 position_++; 1237 } while (tag == SerializationTag::kPadding); 1238 return Just(tag); 1239} 1240 1241template <typename T> 1242Maybe<T> ValueDeserializer::ReadVarint() { 1243 // Reads an unsigned integer as a base-128 varint. 1244 // The number is written, 7 bits at a time, from the least significant to the 1245 // most significant 7 bits. Each byte, except the last, has the MSB set. 1246 // If the varint is larger than T, any more significant bits are discarded. 1247 // See also https://developers.google.com/protocol-buffers/docs/encoding 1248 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, 1249 "Only unsigned integer types can be read as varints."); 1250 if (sizeof(T) > 4) return ReadVarintLoop<T>(); 1251 auto max_read_position = position_ + sizeof(T) + 1; 1252 if (V8_UNLIKELY(max_read_position >= end_)) return ReadVarintLoop<T>(); 1253#ifdef DEBUG 1254 // DCHECK code to make sure the manually unrolled loop yields the exact 1255 // same end state and result. 1256 auto previous_position = position_; 1257 T expected_value = ReadVarintLoop<T>().ToChecked(); 1258 auto expected_position = position_; 1259 position_ = previous_position; 1260#endif // DEBUG 1261#define EXIT_DCHECK() \ 1262 DCHECK_LE(position_, end_); \ 1263 DCHECK_EQ(position_, expected_position); \ 1264 DCHECK_EQ(value, expected_value) 1265 1266 T value = 0; 1267#define ITERATION_SHIFTED(shift) \ 1268 if (shift < sizeof(T) * 8) { \ 1269 uint8_t byte = *position_; \ 1270 position_++; \ 1271 if (byte < 0x80) { \ 1272 value |= static_cast<T>(byte) << shift; \ 1273 EXIT_DCHECK(); \ 1274 return Just(value); \ 1275 } else { \ 1276 value |= static_cast<T>(byte & 0x7F) << shift; \ 1277 } \ 1278 } 1279 // Manually unroll the loop to achieve the best measured peformance. 1280 // This is ~15% faster than ReadVarintLoop. 1281 ITERATION_SHIFTED(0); 1282 ITERATION_SHIFTED(7); 1283 ITERATION_SHIFTED(14); 1284 ITERATION_SHIFTED(21); 1285 ITERATION_SHIFTED(28); 1286 1287 EXIT_DCHECK(); 1288 return Just(value); 1289#undef ITERATION_SHIFTED 1290#undef EXIT_DCHECK 1291} 1292 1293template <typename T> 1294Maybe<T> ValueDeserializer::ReadVarintLoop() { 1295 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, 1296 "Only unsigned integer types can be read as varints."); 1297 T value = 0; 1298 unsigned shift = 0; 1299 bool has_another_byte; 1300 do { 1301 if (position_ >= end_) return Nothing<T>(); 1302 uint8_t byte = *position_; 1303 has_another_byte = byte & 0x80; 1304 if (V8_LIKELY(shift < sizeof(T) * 8)) { 1305 value |= static_cast<T>(byte & 0x7F) << shift; 1306 shift += 7; 1307 } else { 1308 DCHECK(!has_another_byte); 1309 } 1310 position_++; 1311 } while (has_another_byte); 1312 return Just(value); 1313} 1314 1315template <typename T> 1316Maybe<T> ValueDeserializer::ReadZigZag() { 1317 // Writes a signed integer as a varint using ZigZag encoding (i.e. 0 is 1318 // encoded as 0, -1 as 1, 1 as 2, -2 as 3, and so on). 1319 // See also https://developers.google.com/protocol-buffers/docs/encoding 1320 static_assert(std::is_integral<T>::value && std::is_signed<T>::value, 1321 "Only signed integer types can be read as zigzag."); 1322 using UnsignedT = typename std::make_unsigned<T>::type; 1323 UnsignedT unsigned_value; 1324 if (!ReadVarint<UnsignedT>().To(&unsigned_value)) return Nothing<T>(); 1325 return Just(static_cast<T>((unsigned_value >> 1) ^ 1326 -static_cast<T>(unsigned_value & 1))); 1327} 1328 1329template EXPORT_TEMPLATE_DEFINE( 1330 V8_EXPORT_PRIVATE) Maybe<int32_t> ValueDeserializer::ReadZigZag(); 1331 1332Maybe<double> ValueDeserializer::ReadDouble() { 1333 // Warning: this uses host endianness. 1334 if (sizeof(double) > static_cast<unsigned>(end_ - position_)) { 1335 return Nothing<double>(); 1336 } 1337 double value; 1338 memcpy(&value, position_, sizeof(double)); 1339 position_ += sizeof(double); 1340 if (std::isnan(value)) value = std::numeric_limits<double>::quiet_NaN(); 1341 return Just(value); 1342} 1343 1344Maybe<base::Vector<const uint8_t>> ValueDeserializer::ReadRawBytes( 1345 size_t size) { 1346 if (size > static_cast<size_t>(end_ - position_)) { 1347 return Nothing<base::Vector<const uint8_t>>(); 1348 } 1349 const uint8_t* start = position_; 1350 position_ += size; 1351 return Just(base::Vector<const uint8_t>(start, size)); 1352} 1353 1354bool ValueDeserializer::ReadUint32(uint32_t* value) { 1355 return ReadVarint<uint32_t>().To(value); 1356} 1357 1358bool ValueDeserializer::ReadUint64(uint64_t* value) { 1359 return ReadVarint<uint64_t>().To(value); 1360} 1361 1362bool ValueDeserializer::ReadDouble(double* value) { 1363 return ReadDouble().To(value); 1364} 1365 1366bool ValueDeserializer::ReadRawBytes(size_t length, const void** data) { 1367 if (length > static_cast<size_t>(end_ - position_)) return false; 1368 *data = position_; 1369 position_ += length; 1370 return true; 1371} 1372 1373void ValueDeserializer::TransferArrayBuffer( 1374 uint32_t transfer_id, Handle<JSArrayBuffer> array_buffer) { 1375 if (array_buffer_transfer_map_.is_null()) { 1376 array_buffer_transfer_map_ = isolate_->global_handles()->Create( 1377 *SimpleNumberDictionary::New(isolate_, 0)); 1378 } 1379 Handle<SimpleNumberDictionary> dictionary = 1380 array_buffer_transfer_map_.ToHandleChecked(); 1381 Handle<SimpleNumberDictionary> new_dictionary = SimpleNumberDictionary::Set( 1382 isolate_, dictionary, transfer_id, array_buffer); 1383 if (!new_dictionary.is_identical_to(dictionary)) { 1384 GlobalHandles::Destroy(dictionary.location()); 1385 array_buffer_transfer_map_ = 1386 isolate_->global_handles()->Create(*new_dictionary); 1387 } 1388} 1389 1390MaybeHandle<Object> ValueDeserializer::ReadObjectWrapper() { 1391 // We had a bug which produced invalid version 13 data (see 1392 // crbug.com/1284506). This compatibility mode tries to first read the data 1393 // normally, and if it fails, and the version is 13, tries to read the broken 1394 // format. 1395 const uint8_t* original_position = position_; 1396 suppress_deserialization_errors_ = true; 1397 MaybeHandle<Object> result = ReadObject(); 1398 1399 // The deserialization code doesn't throw errors for invalid data. It throws 1400 // errors for stack overflows, though, and in that case we won't retry. 1401 if (result.is_null() && version_ == 13 && 1402 !isolate_->has_pending_exception()) { 1403 version_13_broken_data_mode_ = true; 1404 position_ = original_position; 1405 result = ReadObject(); 1406 } 1407 1408 if (result.is_null() && !isolate_->has_pending_exception()) { 1409 isolate_->Throw(*isolate_->factory()->NewError( 1410 MessageTemplate::kDataCloneDeserializationError)); 1411 } 1412 1413 return result; 1414} 1415 1416MaybeHandle<Object> ValueDeserializer::ReadObject() { 1417 DisallowJavascriptExecution no_js(isolate_); 1418 // If we are at the end of the stack, abort. This function may recurse. 1419 STACK_CHECK(isolate_, MaybeHandle<Object>()); 1420 1421 MaybeHandle<Object> result = ReadObjectInternal(); 1422 1423 // ArrayBufferView is special in that it consumes the value before it, even 1424 // after format version 0. 1425 Handle<Object> object; 1426 SerializationTag tag; 1427 if (result.ToHandle(&object) && V8_UNLIKELY(object->IsJSArrayBuffer()) && 1428 PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) { 1429 ConsumeTag(SerializationTag::kArrayBufferView); 1430 result = ReadJSArrayBufferView(Handle<JSArrayBuffer>::cast(object)); 1431 } 1432 1433 if (result.is_null() && !suppress_deserialization_errors_ && 1434 !isolate_->has_pending_exception()) { 1435 isolate_->Throw(*isolate_->factory()->NewError( 1436 MessageTemplate::kDataCloneDeserializationError)); 1437 } 1438 1439 return result; 1440} 1441 1442MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() { 1443 SerializationTag tag; 1444 if (!ReadTag().To(&tag)) return MaybeHandle<Object>(); 1445 switch (tag) { 1446 case SerializationTag::kVerifyObjectCount: 1447 // Read the count and ignore it. 1448 if (ReadVarint<uint32_t>().IsNothing()) return MaybeHandle<Object>(); 1449 return ReadObject(); 1450 case SerializationTag::kUndefined: 1451 return isolate_->factory()->undefined_value(); 1452 case SerializationTag::kNull: 1453 return isolate_->factory()->null_value(); 1454 case SerializationTag::kTrue: 1455 return isolate_->factory()->true_value(); 1456 case SerializationTag::kFalse: 1457 return isolate_->factory()->false_value(); 1458 case SerializationTag::kInt32: { 1459 Maybe<int32_t> number = ReadZigZag<int32_t>(); 1460 if (number.IsNothing()) return MaybeHandle<Object>(); 1461 return isolate_->factory()->NewNumberFromInt(number.FromJust()); 1462 } 1463 case SerializationTag::kUint32: { 1464 Maybe<uint32_t> number = ReadVarint<uint32_t>(); 1465 if (number.IsNothing()) return MaybeHandle<Object>(); 1466 return isolate_->factory()->NewNumberFromUint(number.FromJust()); 1467 } 1468 case SerializationTag::kDouble: { 1469 Maybe<double> number = ReadDouble(); 1470 if (number.IsNothing()) return MaybeHandle<Object>(); 1471 return isolate_->factory()->NewNumber(number.FromJust()); 1472 } 1473 case SerializationTag::kBigInt: 1474 return ReadBigInt(); 1475 case SerializationTag::kUtf8String: 1476 return ReadUtf8String(); 1477 case SerializationTag::kOneByteString: 1478 return ReadOneByteString(); 1479 case SerializationTag::kTwoByteString: 1480 return ReadTwoByteString(); 1481 case SerializationTag::kObjectReference: { 1482 uint32_t id; 1483 if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>(); 1484 return GetObjectWithID(id); 1485 } 1486 case SerializationTag::kBeginJSObject: 1487 return ReadJSObject(); 1488 case SerializationTag::kBeginSparseJSArray: 1489 return ReadSparseJSArray(); 1490 case SerializationTag::kBeginDenseJSArray: 1491 return ReadDenseJSArray(); 1492 case SerializationTag::kDate: 1493 return ReadJSDate(); 1494 case SerializationTag::kTrueObject: 1495 case SerializationTag::kFalseObject: 1496 case SerializationTag::kNumberObject: 1497 case SerializationTag::kBigIntObject: 1498 case SerializationTag::kStringObject: 1499 return ReadJSPrimitiveWrapper(tag); 1500 case SerializationTag::kRegExp: 1501 return ReadJSRegExp(); 1502 case SerializationTag::kBeginJSMap: 1503 return ReadJSMap(); 1504 case SerializationTag::kBeginJSSet: 1505 return ReadJSSet(); 1506 case SerializationTag::kArrayBuffer: { 1507 const bool is_shared = false; 1508 return ReadJSArrayBuffer(is_shared); 1509 } 1510 case SerializationTag::kArrayBufferTransfer: { 1511 return ReadTransferredJSArrayBuffer(); 1512 } 1513 case SerializationTag::kSharedArrayBuffer: { 1514 const bool is_shared = true; 1515 return ReadJSArrayBuffer(is_shared); 1516 } 1517 case SerializationTag::kError: 1518 return ReadJSError(); 1519#if V8_ENABLE_WEBASSEMBLY 1520 case SerializationTag::kWasmModuleTransfer: 1521 return ReadWasmModuleTransfer(); 1522 case SerializationTag::kWasmMemoryTransfer: 1523 return ReadWasmMemory(); 1524#endif // V8_ENABLE_WEBASSEMBLY 1525 case SerializationTag::kHostObject: 1526 return ReadHostObject(); 1527 case SerializationTag::kSharedObject: 1528 if (version_ >= 15 && supports_shared_values_) { 1529 return ReadSharedObject(); 1530 } 1531 // If the delegate doesn't support shared values (e.g. older version, or 1532 // is for deserializing from storage), treat the tag as unknown. 1533 V8_FALLTHROUGH; 1534 default: 1535 // Before there was an explicit tag for host objects, all unknown tags 1536 // were delegated to the host. 1537 if (version_ < 13) { 1538 position_--; 1539 return ReadHostObject(); 1540 } 1541 return MaybeHandle<Object>(); 1542 } 1543} 1544 1545MaybeHandle<String> ValueDeserializer::ReadString() { 1546 if (version_ < 12) return ReadUtf8String(); 1547 Handle<Object> object; 1548 if (!ReadObject().ToHandle(&object) || !object->IsString(isolate_)) { 1549 return MaybeHandle<String>(); 1550 } 1551 return Handle<String>::cast(object); 1552} 1553 1554MaybeHandle<BigInt> ValueDeserializer::ReadBigInt() { 1555 uint32_t bitfield; 1556 if (!ReadVarint<uint32_t>().To(&bitfield)) return MaybeHandle<BigInt>(); 1557 int bytelength = BigInt::DigitsByteLengthForBitfield(bitfield); 1558 base::Vector<const uint8_t> digits_storage; 1559 if (!ReadRawBytes(bytelength).To(&digits_storage)) { 1560 return MaybeHandle<BigInt>(); 1561 } 1562 return BigInt::FromSerializedDigits(isolate_, bitfield, digits_storage); 1563} 1564 1565MaybeHandle<String> ValueDeserializer::ReadUtf8String( 1566 AllocationType allocation) { 1567 uint32_t utf8_length; 1568 if (!ReadVarint<uint32_t>().To(&utf8_length)) return {}; 1569 // utf8_length is checked in ReadRawBytes. 1570 base::Vector<const uint8_t> utf8_bytes; 1571 if (!ReadRawBytes(utf8_length).To(&utf8_bytes)) return {}; 1572 return isolate_->factory()->NewStringFromUtf8( 1573 base::Vector<const char>::cast(utf8_bytes), allocation); 1574} 1575 1576MaybeHandle<String> ValueDeserializer::ReadOneByteString( 1577 AllocationType allocation) { 1578 uint32_t byte_length; 1579 base::Vector<const uint8_t> bytes; 1580 if (!ReadVarint<uint32_t>().To(&byte_length)) return {}; 1581 // byte_length is checked in ReadRawBytes. 1582 if (!ReadRawBytes(byte_length).To(&bytes)) return {}; 1583 return isolate_->factory()->NewStringFromOneByte(bytes, allocation); 1584} 1585 1586MaybeHandle<String> ValueDeserializer::ReadTwoByteString( 1587 AllocationType allocation) { 1588 uint32_t byte_length; 1589 base::Vector<const uint8_t> bytes; 1590 if (!ReadVarint<uint32_t>().To(&byte_length)) return {}; 1591 // byte_length is checked in ReadRawBytes. 1592 if (byte_length % sizeof(base::uc16) != 0 || 1593 !ReadRawBytes(byte_length).To(&bytes)) { 1594 return MaybeHandle<String>(); 1595 } 1596 1597 // Allocate an uninitialized string so that we can do a raw memcpy into the 1598 // string on the heap (regardless of alignment). 1599 if (byte_length == 0) return isolate_->factory()->empty_string(); 1600 Handle<SeqTwoByteString> string; 1601 if (!isolate_->factory() 1602 ->NewRawTwoByteString(byte_length / sizeof(base::uc16), allocation) 1603 .ToHandle(&string)) { 1604 return MaybeHandle<String>(); 1605 } 1606 1607 // Copy the bytes directly into the new string. 1608 // Warning: this uses host endianness. 1609 DisallowGarbageCollection no_gc; 1610 memcpy(string->GetChars(no_gc), bytes.begin(), bytes.length()); 1611 return string; 1612} 1613 1614bool ValueDeserializer::ReadExpectedString(Handle<String> expected) { 1615 DisallowGarbageCollection no_gc; 1616 // In the case of failure, the position in the stream is reset. 1617 const uint8_t* original_position = position_; 1618 1619 SerializationTag tag; 1620 uint32_t byte_length; 1621 base::Vector<const uint8_t> bytes; 1622 if (!ReadTag().To(&tag) || !ReadVarint<uint32_t>().To(&byte_length)) { 1623 return {}; 1624 } 1625 // Length is also checked in ReadRawBytes. 1626 DCHECK_LE(byte_length, 1627 static_cast<uint32_t>(std::numeric_limits<int32_t>::max())); 1628 if (!ReadRawBytes(byte_length).To(&bytes)) { 1629 position_ = original_position; 1630 return false; 1631 } 1632 1633 String::FlatContent flat = expected->GetFlatContent(no_gc); 1634 1635 // If the bytes are verbatim what is in the flattened string, then the string 1636 // is successfully consumed. 1637 if (tag == SerializationTag::kOneByteString && flat.IsOneByte()) { 1638 base::Vector<const uint8_t> chars = flat.ToOneByteVector(); 1639 if (byte_length == static_cast<size_t>(chars.length()) && 1640 memcmp(bytes.begin(), chars.begin(), byte_length) == 0) { 1641 return true; 1642 } 1643 } else if (tag == SerializationTag::kTwoByteString && flat.IsTwoByte()) { 1644 base::Vector<const base::uc16> chars = flat.ToUC16Vector(); 1645 if (byte_length == 1646 static_cast<unsigned>(chars.length()) * sizeof(base::uc16) && 1647 memcmp(bytes.begin(), chars.begin(), byte_length) == 0) { 1648 return true; 1649 } 1650 } else if (tag == SerializationTag::kUtf8String && flat.IsOneByte()) { 1651 base::Vector<const uint8_t> chars = flat.ToOneByteVector(); 1652 if (byte_length == static_cast<size_t>(chars.length()) && 1653 String::IsAscii(chars.begin(), chars.length()) && 1654 memcmp(bytes.begin(), chars.begin(), byte_length) == 0) { 1655 return true; 1656 } 1657 } 1658 1659 position_ = original_position; 1660 return false; 1661} 1662 1663MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() { 1664 // If we are at the end of the stack, abort. This function may recurse. 1665 STACK_CHECK(isolate_, MaybeHandle<JSObject>()); 1666 1667 uint32_t id = next_id_++; 1668 HandleScope scope(isolate_); 1669 Handle<JSObject> object = 1670 isolate_->factory()->NewJSObject(isolate_->object_function()); 1671 AddObjectWithID(id, object); 1672 1673 uint32_t num_properties; 1674 uint32_t expected_num_properties; 1675 if (!ReadJSObjectProperties(object, SerializationTag::kEndJSObject, true) 1676 .To(&num_properties) || 1677 !ReadVarint<uint32_t>().To(&expected_num_properties) || 1678 num_properties != expected_num_properties) { 1679 return MaybeHandle<JSObject>(); 1680 } 1681 1682 DCHECK(HasObjectWithID(id)); 1683 return scope.CloseAndEscape(object); 1684} 1685 1686MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() { 1687 // If we are at the end of the stack, abort. This function may recurse. 1688 STACK_CHECK(isolate_, MaybeHandle<JSArray>()); 1689 1690 uint32_t length; 1691 if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>(); 1692 1693 uint32_t id = next_id_++; 1694 HandleScope scope(isolate_); 1695 Handle<JSArray> array = 1696 isolate_->factory()->NewJSArray(0, TERMINAL_FAST_ELEMENTS_KIND); 1697 MAYBE_RETURN(JSArray::SetLength(array, length), MaybeHandle<JSArray>()); 1698 AddObjectWithID(id, array); 1699 1700 uint32_t num_properties; 1701 uint32_t expected_num_properties; 1702 uint32_t expected_length; 1703 if (!ReadJSObjectProperties(array, SerializationTag::kEndSparseJSArray, false) 1704 .To(&num_properties) || 1705 !ReadVarint<uint32_t>().To(&expected_num_properties) || 1706 !ReadVarint<uint32_t>().To(&expected_length) || 1707 num_properties != expected_num_properties || length != expected_length) { 1708 return MaybeHandle<JSArray>(); 1709 } 1710 1711 DCHECK(HasObjectWithID(id)); 1712 return scope.CloseAndEscape(array); 1713} 1714 1715MaybeHandle<JSArray> ValueDeserializer::ReadDenseJSArray() { 1716 // If we are at the end of the stack, abort. This function may recurse. 1717 STACK_CHECK(isolate_, MaybeHandle<JSArray>()); 1718 1719 // We shouldn't permit an array larger than the biggest we can request from 1720 // V8. As an additional sanity check, since each entry will take at least one 1721 // byte to encode, if there are fewer bytes than that we can also fail fast. 1722 uint32_t length; 1723 if (!ReadVarint<uint32_t>().To(&length) || 1724 length > static_cast<uint32_t>(FixedArray::kMaxLength) || 1725 length > static_cast<size_t>(end_ - position_)) { 1726 return MaybeHandle<JSArray>(); 1727 } 1728 1729 uint32_t id = next_id_++; 1730 HandleScope scope(isolate_); 1731 Handle<JSArray> array = isolate_->factory()->NewJSArray( 1732 HOLEY_ELEMENTS, length, length, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); 1733 AddObjectWithID(id, array); 1734 1735 Handle<FixedArray> elements(FixedArray::cast(array->elements()), isolate_); 1736 auto elements_length = static_cast<uint32_t>(elements->length()); 1737 for (uint32_t i = 0; i < length; i++) { 1738 SerializationTag tag; 1739 if (PeekTag().To(&tag) && tag == SerializationTag::kTheHole) { 1740 ConsumeTag(SerializationTag::kTheHole); 1741 continue; 1742 } 1743 1744 Handle<Object> element; 1745 if (!ReadObject().ToHandle(&element)) return MaybeHandle<JSArray>(); 1746 1747 // Serialization versions less than 11 encode the hole the same as 1748 // undefined. For consistency with previous behavior, store these as the 1749 // hole. Past version 11, undefined means undefined. 1750 if (version_ < 11 && element->IsUndefined(isolate_)) continue; 1751 1752 // Safety check. 1753 if (i >= elements_length) return MaybeHandle<JSArray>(); 1754 1755 elements->set(i, *element); 1756 } 1757 1758 uint32_t num_properties; 1759 uint32_t expected_num_properties; 1760 uint32_t expected_length; 1761 if (!ReadJSObjectProperties(array, SerializationTag::kEndDenseJSArray, false) 1762 .To(&num_properties) || 1763 !ReadVarint<uint32_t>().To(&expected_num_properties) || 1764 !ReadVarint<uint32_t>().To(&expected_length) || 1765 num_properties != expected_num_properties || length != expected_length) { 1766 return MaybeHandle<JSArray>(); 1767 } 1768 1769 DCHECK(HasObjectWithID(id)); 1770 return scope.CloseAndEscape(array); 1771} 1772 1773MaybeHandle<JSDate> ValueDeserializer::ReadJSDate() { 1774 double value; 1775 if (!ReadDouble().To(&value)) return MaybeHandle<JSDate>(); 1776 uint32_t id = next_id_++; 1777 Handle<JSDate> date; 1778 if (!JSDate::New(isolate_->date_function(), isolate_->date_function(), value) 1779 .ToHandle(&date)) { 1780 return MaybeHandle<JSDate>(); 1781 } 1782 AddObjectWithID(id, date); 1783 return date; 1784} 1785 1786MaybeHandle<JSPrimitiveWrapper> ValueDeserializer::ReadJSPrimitiveWrapper( 1787 SerializationTag tag) { 1788 uint32_t id = next_id_++; 1789 Handle<JSPrimitiveWrapper> value; 1790 switch (tag) { 1791 case SerializationTag::kTrueObject: 1792 value = Handle<JSPrimitiveWrapper>::cast( 1793 isolate_->factory()->NewJSObject(isolate_->boolean_function())); 1794 value->set_value(ReadOnlyRoots(isolate_).true_value()); 1795 break; 1796 case SerializationTag::kFalseObject: 1797 value = Handle<JSPrimitiveWrapper>::cast( 1798 isolate_->factory()->NewJSObject(isolate_->boolean_function())); 1799 value->set_value(ReadOnlyRoots(isolate_).false_value()); 1800 break; 1801 case SerializationTag::kNumberObject: { 1802 double number; 1803 if (!ReadDouble().To(&number)) return MaybeHandle<JSPrimitiveWrapper>(); 1804 value = Handle<JSPrimitiveWrapper>::cast( 1805 isolate_->factory()->NewJSObject(isolate_->number_function())); 1806 Handle<Object> number_object = isolate_->factory()->NewNumber(number); 1807 value->set_value(*number_object); 1808 break; 1809 } 1810 case SerializationTag::kBigIntObject: { 1811 Handle<BigInt> bigint; 1812 if (!ReadBigInt().ToHandle(&bigint)) 1813 return MaybeHandle<JSPrimitiveWrapper>(); 1814 value = Handle<JSPrimitiveWrapper>::cast( 1815 isolate_->factory()->NewJSObject(isolate_->bigint_function())); 1816 value->set_value(*bigint); 1817 break; 1818 } 1819 case SerializationTag::kStringObject: { 1820 Handle<String> string; 1821 if (!ReadString().ToHandle(&string)) 1822 return MaybeHandle<JSPrimitiveWrapper>(); 1823 value = Handle<JSPrimitiveWrapper>::cast( 1824 isolate_->factory()->NewJSObject(isolate_->string_function())); 1825 value->set_value(*string); 1826 break; 1827 } 1828 default: 1829 UNREACHABLE(); 1830 } 1831 AddObjectWithID(id, value); 1832 return value; 1833} 1834 1835MaybeHandle<JSRegExp> ValueDeserializer::ReadJSRegExp() { 1836 uint32_t id = next_id_++; 1837 Handle<String> pattern; 1838 uint32_t raw_flags; 1839 Handle<JSRegExp> regexp; 1840 if (!ReadString().ToHandle(&pattern) || 1841 !ReadVarint<uint32_t>().To(&raw_flags)) { 1842 return MaybeHandle<JSRegExp>(); 1843 } 1844 1845 // Ensure the deserialized flags are valid. 1846 uint32_t bad_flags_mask = static_cast<uint32_t>(-1) << JSRegExp::kFlagCount; 1847 // kLinear is accepted only with the appropriate flag. 1848 if (!FLAG_enable_experimental_regexp_engine) { 1849 bad_flags_mask |= JSRegExp::kLinear; 1850 } 1851 if ((raw_flags & bad_flags_mask) || 1852 !JSRegExp::New(isolate_, pattern, static_cast<JSRegExp::Flags>(raw_flags)) 1853 .ToHandle(®exp)) { 1854 return MaybeHandle<JSRegExp>(); 1855 } 1856 1857 AddObjectWithID(id, regexp); 1858 return regexp; 1859} 1860 1861MaybeHandle<JSMap> ValueDeserializer::ReadJSMap() { 1862 // If we are at the end of the stack, abort. This function may recurse. 1863 STACK_CHECK(isolate_, MaybeHandle<JSMap>()); 1864 1865 HandleScope scope(isolate_); 1866 uint32_t id = next_id_++; 1867 Handle<JSMap> map = isolate_->factory()->NewJSMap(); 1868 AddObjectWithID(id, map); 1869 1870 Handle<JSFunction> map_set = isolate_->map_set(); 1871 uint32_t length = 0; 1872 while (true) { 1873 SerializationTag tag; 1874 if (!PeekTag().To(&tag)) return MaybeHandle<JSMap>(); 1875 if (tag == SerializationTag::kEndJSMap) { 1876 ConsumeTag(SerializationTag::kEndJSMap); 1877 break; 1878 } 1879 1880 Handle<Object> argv[2]; 1881 if (!ReadObject().ToHandle(&argv[0]) || !ReadObject().ToHandle(&argv[1])) { 1882 return MaybeHandle<JSMap>(); 1883 } 1884 1885 AllowJavascriptExecution allow_js(isolate_); 1886 if (Execution::Call(isolate_, map_set, map, arraysize(argv), argv) 1887 .is_null()) { 1888 return MaybeHandle<JSMap>(); 1889 } 1890 length += 2; 1891 } 1892 1893 uint32_t expected_length; 1894 if (!ReadVarint<uint32_t>().To(&expected_length) || 1895 length != expected_length) { 1896 return MaybeHandle<JSMap>(); 1897 } 1898 DCHECK(HasObjectWithID(id)); 1899 return scope.CloseAndEscape(map); 1900} 1901 1902MaybeHandle<JSSet> ValueDeserializer::ReadJSSet() { 1903 // If we are at the end of the stack, abort. This function may recurse. 1904 STACK_CHECK(isolate_, MaybeHandle<JSSet>()); 1905 1906 HandleScope scope(isolate_); 1907 uint32_t id = next_id_++; 1908 Handle<JSSet> set = isolate_->factory()->NewJSSet(); 1909 AddObjectWithID(id, set); 1910 Handle<JSFunction> set_add = isolate_->set_add(); 1911 uint32_t length = 0; 1912 while (true) { 1913 SerializationTag tag; 1914 if (!PeekTag().To(&tag)) return MaybeHandle<JSSet>(); 1915 if (tag == SerializationTag::kEndJSSet) { 1916 ConsumeTag(SerializationTag::kEndJSSet); 1917 break; 1918 } 1919 1920 Handle<Object> argv[1]; 1921 if (!ReadObject().ToHandle(&argv[0])) return MaybeHandle<JSSet>(); 1922 1923 AllowJavascriptExecution allow_js(isolate_); 1924 if (Execution::Call(isolate_, set_add, set, arraysize(argv), argv) 1925 .is_null()) { 1926 return MaybeHandle<JSSet>(); 1927 } 1928 length++; 1929 } 1930 1931 uint32_t expected_length; 1932 if (!ReadVarint<uint32_t>().To(&expected_length) || 1933 length != expected_length) { 1934 return MaybeHandle<JSSet>(); 1935 } 1936 DCHECK(HasObjectWithID(id)); 1937 return scope.CloseAndEscape(set); 1938} 1939 1940MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadJSArrayBuffer( 1941 bool is_shared) { 1942 uint32_t id = next_id_++; 1943 if (is_shared) { 1944 uint32_t clone_id; 1945 Local<SharedArrayBuffer> sab_value; 1946 if (!ReadVarint<uint32_t>().To(&clone_id) || delegate_ == nullptr || 1947 !delegate_ 1948 ->GetSharedArrayBufferFromId( 1949 reinterpret_cast<v8::Isolate*>(isolate_), clone_id) 1950 .ToLocal(&sab_value)) { 1951 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSArrayBuffer); 1952 return MaybeHandle<JSArrayBuffer>(); 1953 } 1954 Handle<JSArrayBuffer> array_buffer = Utils::OpenHandle(*sab_value); 1955 DCHECK_EQ(is_shared, array_buffer->is_shared()); 1956 AddObjectWithID(id, array_buffer); 1957 return array_buffer; 1958 } 1959 uint32_t byte_length; 1960 if (!ReadVarint<uint32_t>().To(&byte_length) || 1961 byte_length > static_cast<size_t>(end_ - position_)) { 1962 return MaybeHandle<JSArrayBuffer>(); 1963 } 1964 MaybeHandle<JSArrayBuffer> result = 1965 isolate_->factory()->NewJSArrayBufferAndBackingStore( 1966 byte_length, InitializedFlag::kUninitialized); 1967 Handle<JSArrayBuffer> array_buffer; 1968 if (!result.ToHandle(&array_buffer)) return result; 1969 1970 if (byte_length > 0) { 1971 memcpy(array_buffer->backing_store(), position_, byte_length); 1972 } 1973 position_ += byte_length; 1974 AddObjectWithID(id, array_buffer); 1975 return array_buffer; 1976} 1977 1978MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadTransferredJSArrayBuffer() { 1979 uint32_t id = next_id_++; 1980 uint32_t transfer_id; 1981 Handle<SimpleNumberDictionary> transfer_map; 1982 if (!ReadVarint<uint32_t>().To(&transfer_id) || 1983 !array_buffer_transfer_map_.ToHandle(&transfer_map)) { 1984 return MaybeHandle<JSArrayBuffer>(); 1985 } 1986 InternalIndex index = transfer_map->FindEntry(isolate_, transfer_id); 1987 if (index.is_not_found()) { 1988 return MaybeHandle<JSArrayBuffer>(); 1989 } 1990 Handle<JSArrayBuffer> array_buffer( 1991 JSArrayBuffer::cast(transfer_map->ValueAt(index)), isolate_); 1992 AddObjectWithID(id, array_buffer); 1993 return array_buffer; 1994} 1995 1996MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView( 1997 Handle<JSArrayBuffer> buffer) { 1998 uint32_t buffer_byte_length = static_cast<uint32_t>(buffer->GetByteLength()); 1999 uint8_t tag = 0; 2000 uint32_t byte_offset = 0; 2001 uint32_t byte_length = 0; 2002 uint32_t flags = 0; 2003 if (!ReadVarint<uint8_t>().To(&tag) || 2004 !ReadVarint<uint32_t>().To(&byte_offset) || 2005 !ReadVarint<uint32_t>().To(&byte_length) || 2006 byte_offset > buffer_byte_length || 2007 byte_length > buffer_byte_length - byte_offset) { 2008 return MaybeHandle<JSArrayBufferView>(); 2009 } 2010 const bool should_read_flags = version_ >= 14 || version_13_broken_data_mode_; 2011 if (should_read_flags && !ReadVarint<uint32_t>().To(&flags)) { 2012 return MaybeHandle<JSArrayBufferView>(); 2013 } 2014 uint32_t id = next_id_++; 2015 ExternalArrayType external_array_type = kExternalInt8Array; 2016 unsigned element_size = 0; 2017 2018 switch (static_cast<ArrayBufferViewTag>(tag)) { 2019 case ArrayBufferViewTag::kDataView: { 2020 Handle<JSDataView> data_view = 2021 isolate_->factory()->NewJSDataView(buffer, byte_offset, byte_length); 2022 AddObjectWithID(id, data_view); 2023 if (!ValidateAndSetJSArrayBufferViewFlags(*data_view, *buffer, flags)) { 2024 return MaybeHandle<JSArrayBufferView>(); 2025 } 2026 return data_view; 2027 } 2028#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \ 2029 case ArrayBufferViewTag::k##Type##Array: \ 2030 external_array_type = kExternal##Type##Array; \ 2031 element_size = sizeof(ctype); \ 2032 break; 2033 TYPED_ARRAYS(TYPED_ARRAY_CASE) 2034#undef TYPED_ARRAY_CASE 2035 } 2036 if (element_size == 0 || byte_offset % element_size != 0 || 2037 byte_length % element_size != 0) { 2038 return MaybeHandle<JSArrayBufferView>(); 2039 } 2040 Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray( 2041 external_array_type, buffer, byte_offset, byte_length / element_size); 2042 if (!ValidateAndSetJSArrayBufferViewFlags(*typed_array, *buffer, flags)) { 2043 return MaybeHandle<JSArrayBufferView>(); 2044 } 2045 AddObjectWithID(id, typed_array); 2046 return typed_array; 2047} 2048 2049bool ValueDeserializer::ValidateAndSetJSArrayBufferViewFlags( 2050 JSArrayBufferView view, JSArrayBuffer buffer, uint32_t serialized_flags) { 2051 bool is_length_tracking = 2052 JSArrayBufferViewIsLengthTracking::decode(serialized_flags); 2053 bool is_backed_by_rab = 2054 JSArrayBufferViewIsBackedByRab::decode(serialized_flags); 2055 2056 // TODO(marja): When the version number is bumped the next time, check that 2057 // serialized_flags doesn't contain spurious 1-bits. 2058 2059 if (is_backed_by_rab || is_length_tracking) { 2060 if (!FLAG_harmony_rab_gsab) { 2061 return false; 2062 } 2063 if (!buffer.is_resizable()) { 2064 return false; 2065 } 2066 if (is_backed_by_rab && buffer.is_shared()) { 2067 return false; 2068 } 2069 } 2070 view.set_is_length_tracking(is_length_tracking); 2071 view.set_is_backed_by_rab(is_backed_by_rab); 2072 return true; 2073} 2074 2075MaybeHandle<Object> ValueDeserializer::ReadJSError() { 2076 uint32_t id = next_id_++; 2077 2078 Handle<Object> message = isolate_->factory()->undefined_value(); 2079 Handle<Object> options = isolate_->factory()->undefined_value(); 2080 Handle<Object> stack = isolate_->factory()->undefined_value(); 2081 Handle<Object> no_caller; 2082 auto constructor = isolate_->error_function(); 2083 bool done = false; 2084 2085 while (!done) { 2086 uint8_t tag; 2087 if (!ReadVarint<uint8_t>().To(&tag)) { 2088 return MaybeHandle<JSObject>(); 2089 } 2090 switch (static_cast<ErrorTag>(tag)) { 2091 case ErrorTag::kEvalErrorPrototype: 2092 constructor = isolate_->eval_error_function(); 2093 break; 2094 case ErrorTag::kRangeErrorPrototype: 2095 constructor = isolate_->range_error_function(); 2096 break; 2097 case ErrorTag::kReferenceErrorPrototype: 2098 constructor = isolate_->reference_error_function(); 2099 break; 2100 case ErrorTag::kSyntaxErrorPrototype: 2101 constructor = isolate_->syntax_error_function(); 2102 break; 2103 case ErrorTag::kTypeErrorPrototype: 2104 constructor = isolate_->type_error_function(); 2105 break; 2106 case ErrorTag::kUriErrorPrototype: 2107 constructor = isolate_->uri_error_function(); 2108 break; 2109 case ErrorTag::kMessage: { 2110 Handle<String> message_string; 2111 if (!ReadString().ToHandle(&message_string)) { 2112 return MaybeHandle<JSObject>(); 2113 } 2114 message = message_string; 2115 break; 2116 } 2117 case ErrorTag::kCause: { 2118 Handle<Object> cause; 2119 if (!ReadObject().ToHandle(&cause)) { 2120 return MaybeHandle<JSObject>(); 2121 } 2122 options = isolate_->factory()->NewJSObject(isolate_->object_function()); 2123 if (JSObject::DefinePropertyOrElementIgnoreAttributes( 2124 Handle<JSObject>::cast(options), 2125 isolate_->factory()->cause_string(), cause, DONT_ENUM) 2126 .is_null()) { 2127 return MaybeHandle<JSObject>(); 2128 } 2129 break; 2130 } 2131 case ErrorTag::kStack: { 2132 Handle<String> stack_string; 2133 if (!ReadString().ToHandle(&stack_string)) { 2134 return MaybeHandle<JSObject>(); 2135 } 2136 stack = stack_string; 2137 break; 2138 } 2139 case ErrorTag::kEnd: 2140 done = true; 2141 break; 2142 default: 2143 return MaybeHandle<JSObject>(); 2144 } 2145 } 2146 2147 Handle<JSObject> error; 2148 if (!ErrorUtils::Construct(isolate_, constructor, constructor, message, 2149 options, SKIP_NONE, no_caller, 2150 ErrorUtils::StackTraceCollection::kDisabled) 2151 .ToHandle(&error)) { 2152 return MaybeHandle<Object>(); 2153 } 2154 2155 ErrorUtils::SetFormattedStack(isolate_, error, stack); 2156 AddObjectWithID(id, error); 2157 return error; 2158} 2159 2160#if V8_ENABLE_WEBASSEMBLY 2161MaybeHandle<JSObject> ValueDeserializer::ReadWasmModuleTransfer() { 2162 uint32_t transfer_id = 0; 2163 Local<Value> module_value; 2164 if (!ReadVarint<uint32_t>().To(&transfer_id) || delegate_ == nullptr || 2165 !delegate_ 2166 ->GetWasmModuleFromId(reinterpret_cast<v8::Isolate*>(isolate_), 2167 transfer_id) 2168 .ToLocal(&module_value)) { 2169 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject); 2170 return MaybeHandle<JSObject>(); 2171 } 2172 uint32_t id = next_id_++; 2173 Handle<JSObject> module = 2174 Handle<JSObject>::cast(Utils::OpenHandle(*module_value)); 2175 AddObjectWithID(id, module); 2176 return module; 2177} 2178 2179MaybeHandle<WasmMemoryObject> ValueDeserializer::ReadWasmMemory() { 2180 uint32_t id = next_id_++; 2181 2182 auto enabled_features = wasm::WasmFeatures::FromIsolate(isolate_); 2183 if (!enabled_features.has_threads()) { 2184 return MaybeHandle<WasmMemoryObject>(); 2185 } 2186 2187 int32_t maximum_pages; 2188 if (!ReadZigZag<int32_t>().To(&maximum_pages)) { 2189 return MaybeHandle<WasmMemoryObject>(); 2190 } 2191 2192 SerializationTag tag; 2193 if (!ReadTag().To(&tag) || tag != SerializationTag::kSharedArrayBuffer) { 2194 return MaybeHandle<WasmMemoryObject>(); 2195 } 2196 2197 const bool is_shared = true; 2198 Handle<JSArrayBuffer> buffer; 2199 if (!ReadJSArrayBuffer(is_shared).ToHandle(&buffer)) { 2200 return MaybeHandle<WasmMemoryObject>(); 2201 } 2202 2203 Handle<WasmMemoryObject> result = 2204 WasmMemoryObject::New(isolate_, buffer, maximum_pages).ToHandleChecked(); 2205 2206 AddObjectWithID(id, result); 2207 return result; 2208} 2209#endif // V8_ENABLE_WEBASSEMBLY 2210 2211MaybeHandle<HeapObject> ValueDeserializer::ReadSharedObject() { 2212 STACK_CHECK(isolate_, MaybeHandle<HeapObject>()); 2213 DCHECK_GE(version_, 15); 2214 DCHECK(supports_shared_values_); 2215 DCHECK_NOT_NULL(delegate_); 2216 DCHECK(delegate_->SupportsSharedValues()); 2217 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); 2218 uint32_t shared_value_id; 2219 Local<Value> shared_value; 2220 if (!ReadVarint<uint32_t>().To(&shared_value_id) || 2221 !delegate_->GetSharedValueFromId(v8_isolate, shared_value_id) 2222 .ToLocal(&shared_value)) { 2223 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, HeapObject); 2224 return MaybeHandle<HeapObject>(); 2225 } 2226 Handle<HeapObject> shared_object = 2227 Handle<HeapObject>::cast(Utils::OpenHandle(*shared_value)); 2228 DCHECK(shared_object->IsShared()); 2229 return shared_object; 2230} 2231 2232MaybeHandle<JSObject> ValueDeserializer::ReadHostObject() { 2233 if (!delegate_) return MaybeHandle<JSObject>(); 2234 STACK_CHECK(isolate_, MaybeHandle<JSObject>()); 2235 uint32_t id = next_id_++; 2236 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); 2237 v8::Local<v8::Object> object; 2238 if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) { 2239 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject); 2240 return MaybeHandle<JSObject>(); 2241 } 2242 Handle<JSObject> js_object = 2243 Handle<JSObject>::cast(Utils::OpenHandle(*object)); 2244 AddObjectWithID(id, js_object); 2245 return js_object; 2246} 2247 2248// Copies a vector of property values into an object, given the map that should 2249// be used. 2250static void CommitProperties(Handle<JSObject> object, Handle<Map> map, 2251 const std::vector<Handle<Object>>& properties) { 2252 JSObject::AllocateStorageForMap(object, map); 2253 DCHECK(!object->map().is_dictionary_map()); 2254 2255 DisallowGarbageCollection no_gc; 2256 DescriptorArray descriptors = object->map().instance_descriptors(); 2257 for (InternalIndex i : InternalIndex::Range(properties.size())) { 2258 // Initializing store. 2259 object->WriteToField(i, descriptors.GetDetails(i), 2260 *properties[i.raw_value()]); 2261 } 2262} 2263 2264static bool IsValidObjectKey(Object value, Isolate* isolate) { 2265 if (value.IsSmi()) return true; 2266 auto instance_type = HeapObject::cast(value).map(isolate).instance_type(); 2267 return InstanceTypeChecker::IsName(instance_type) || 2268 InstanceTypeChecker::IsHeapNumber(instance_type); 2269} 2270 2271Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties( 2272 Handle<JSObject> object, SerializationTag end_tag, 2273 bool can_use_transitions) { 2274 uint32_t num_properties = 0; 2275 2276 // Fast path (following map transitions). 2277 if (can_use_transitions) { 2278 bool transitioning = true; 2279 Handle<Map> map(object->map(), isolate_); 2280 DCHECK(!map->is_dictionary_map()); 2281 DCHECK_EQ(0, map->instance_descriptors(isolate_).number_of_descriptors()); 2282 std::vector<Handle<Object>> properties; 2283 properties.reserve(8); 2284 2285 while (transitioning) { 2286 // If there are no more properties, finish. 2287 SerializationTag tag; 2288 if (!PeekTag().To(&tag)) return Nothing<uint32_t>(); 2289 if (tag == end_tag) { 2290 ConsumeTag(end_tag); 2291 CommitProperties(object, map, properties); 2292 CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max()); 2293 return Just(static_cast<uint32_t>(properties.size())); 2294 } 2295 2296 // Determine the key to be used and the target map to transition to, if 2297 // possible. Transitioning may abort if the key is not a string, or if no 2298 // transition was found. 2299 Handle<Object> key; 2300 Handle<Map> target; 2301 Handle<String> expected_key; 2302 { 2303 TransitionsAccessor transitions(isolate_, *map); 2304 expected_key = transitions.ExpectedTransitionKey(); 2305 if (!expected_key.is_null()) { 2306 target = transitions.ExpectedTransitionTarget(); 2307 } 2308 } 2309 if (!expected_key.is_null() && ReadExpectedString(expected_key)) { 2310 key = expected_key; 2311 } else { 2312 if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(*key, isolate_)) { 2313 return Nothing<uint32_t>(); 2314 } 2315 if (key->IsString(isolate_)) { 2316 key = 2317 isolate_->factory()->InternalizeString(Handle<String>::cast(key)); 2318 // Don't reuse |transitions| because it could be stale. 2319 transitioning = TransitionsAccessor(isolate_, *map) 2320 .FindTransitionToField(Handle<String>::cast(key)) 2321 .ToHandle(&target); 2322 } else { 2323 transitioning = false; 2324 } 2325 } 2326 2327 // Read the value that corresponds to it. 2328 Handle<Object> value; 2329 if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>(); 2330 2331 // If still transitioning and the value fits the field representation 2332 // (though generalization may be required), store the property value so 2333 // that we can copy them all at once. Otherwise, stop transitioning. 2334 if (transitioning) { 2335 InternalIndex descriptor(properties.size()); 2336 PropertyDetails details = 2337 target->instance_descriptors(isolate_).GetDetails(descriptor); 2338 Representation expected_representation = details.representation(); 2339 if (value->FitsRepresentation(expected_representation)) { 2340 if (expected_representation.IsHeapObject() && 2341 !target->instance_descriptors(isolate_) 2342 .GetFieldType(descriptor) 2343 .NowContains(value)) { 2344 Handle<FieldType> value_type = 2345 value->OptimalType(isolate_, expected_representation); 2346 MapUpdater::GeneralizeField(isolate_, target, descriptor, 2347 details.constness(), 2348 expected_representation, value_type); 2349 } 2350 DCHECK(target->instance_descriptors(isolate_) 2351 .GetFieldType(descriptor) 2352 .NowContains(value)); 2353 properties.push_back(value); 2354 map = target; 2355 continue; 2356 } else { 2357 transitioning = false; 2358 } 2359 } 2360 2361 // Fell out of transitioning fast path. Commit the properties gathered so 2362 // far, and then start setting properties slowly instead. 2363 DCHECK(!transitioning); 2364 CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max()); 2365 CommitProperties(object, map, properties); 2366 num_properties = static_cast<uint32_t>(properties.size()); 2367 2368 // We checked earlier that IsValidObjectKey(key). 2369 PropertyKey lookup_key(isolate_, key); 2370 LookupIterator it(isolate_, object, lookup_key, LookupIterator::OWN); 2371 if (it.state() != LookupIterator::NOT_FOUND || 2372 JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE) 2373 .is_null()) { 2374 return Nothing<uint32_t>(); 2375 } 2376 num_properties++; 2377 } 2378 2379 // At this point, transitioning should be done, but at least one property 2380 // should have been written (in the zero-property case, there is an early 2381 // return). 2382 DCHECK(!transitioning); 2383 DCHECK_GE(num_properties, 1u); 2384 } 2385 2386 // Slow path. 2387 for (;; num_properties++) { 2388 SerializationTag tag; 2389 if (!PeekTag().To(&tag)) return Nothing<uint32_t>(); 2390 if (tag == end_tag) { 2391 ConsumeTag(end_tag); 2392 return Just(num_properties); 2393 } 2394 2395 Handle<Object> key; 2396 if (!ReadObject().ToHandle(&key) || !IsValidObjectKey(*key, isolate_)) { 2397 return Nothing<uint32_t>(); 2398 } 2399 Handle<Object> value; 2400 if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>(); 2401 2402 // We checked earlier that IsValidObjectKey(key). 2403 PropertyKey lookup_key(isolate_, key); 2404 LookupIterator it(isolate_, object, lookup_key, LookupIterator::OWN); 2405 if (it.state() != LookupIterator::NOT_FOUND || 2406 JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE) 2407 .is_null()) { 2408 return Nothing<uint32_t>(); 2409 } 2410 } 2411} 2412 2413bool ValueDeserializer::HasObjectWithID(uint32_t id) { 2414 return id < static_cast<unsigned>(id_map_->length()) && 2415 !id_map_->get(id).IsTheHole(isolate_); 2416} 2417 2418MaybeHandle<JSReceiver> ValueDeserializer::GetObjectWithID(uint32_t id) { 2419 if (id >= static_cast<unsigned>(id_map_->length())) { 2420 return MaybeHandle<JSReceiver>(); 2421 } 2422 Object value = id_map_->get(id); 2423 if (value.IsTheHole(isolate_)) return MaybeHandle<JSReceiver>(); 2424 DCHECK(value.IsJSReceiver()); 2425 return Handle<JSReceiver>(JSReceiver::cast(value), isolate_); 2426} 2427 2428void ValueDeserializer::AddObjectWithID(uint32_t id, 2429 Handle<JSReceiver> object) { 2430 DCHECK(!HasObjectWithID(id)); 2431 Handle<FixedArray> new_array = 2432 FixedArray::SetAndGrow(isolate_, id_map_, id, object); 2433 2434 // If the dictionary was reallocated, update the global handle. 2435 if (!new_array.is_identical_to(id_map_)) { 2436 GlobalHandles::Destroy(id_map_.location()); 2437 id_map_ = isolate_->global_handles()->Create(*new_array); 2438 } 2439} 2440 2441static Maybe<bool> SetPropertiesFromKeyValuePairs(Isolate* isolate, 2442 Handle<JSObject> object, 2443 Handle<Object>* data, 2444 uint32_t num_properties) { 2445 for (unsigned i = 0; i < 2 * num_properties; i += 2) { 2446 Handle<Object> key = data[i]; 2447 if (!IsValidObjectKey(*key, isolate)) return Nothing<bool>(); 2448 Handle<Object> value = data[i + 1]; 2449 PropertyKey lookup_key(isolate, key); 2450 LookupIterator it(isolate, object, lookup_key, LookupIterator::OWN); 2451 if (it.state() != LookupIterator::NOT_FOUND || 2452 JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE) 2453 .is_null()) { 2454 return Nothing<bool>(); 2455 } 2456 } 2457 return Just(true); 2458} 2459 2460namespace { 2461 2462// Throws a generic "deserialization failed" exception by default, unless a more 2463// specific exception has already been thrown. 2464void ThrowDeserializationExceptionIfNonePending(Isolate* isolate) { 2465 if (!isolate->has_pending_exception()) { 2466 isolate->Throw(*isolate->factory()->NewError( 2467 MessageTemplate::kDataCloneDeserializationError)); 2468 } 2469 DCHECK(isolate->has_pending_exception()); 2470} 2471 2472} // namespace 2473 2474MaybeHandle<Object> 2475ValueDeserializer::ReadObjectUsingEntireBufferForLegacyFormat() { 2476 DCHECK_EQ(version_, 0u); 2477 HandleScope scope(isolate_); 2478 std::vector<Handle<Object>> stack; 2479 while (position_ < end_) { 2480 SerializationTag tag; 2481 if (!PeekTag().To(&tag)) break; 2482 2483 Handle<Object> new_object; 2484 switch (tag) { 2485 case SerializationTag::kEndJSObject: { 2486 ConsumeTag(SerializationTag::kEndJSObject); 2487 2488 // JS Object: Read the last 2*n values from the stack and use them as 2489 // key-value pairs. 2490 uint32_t num_properties; 2491 if (!ReadVarint<uint32_t>().To(&num_properties) || 2492 stack.size() / 2 < num_properties) { 2493 isolate_->Throw(*isolate_->factory()->NewError( 2494 MessageTemplate::kDataCloneDeserializationError)); 2495 return MaybeHandle<Object>(); 2496 } 2497 2498 size_t begin_properties = 2499 stack.size() - 2 * static_cast<size_t>(num_properties); 2500 Handle<JSObject> js_object = 2501 isolate_->factory()->NewJSObject(isolate_->object_function()); 2502 if (num_properties && 2503 !SetPropertiesFromKeyValuePairs( 2504 isolate_, js_object, &stack[begin_properties], num_properties) 2505 .FromMaybe(false)) { 2506 ThrowDeserializationExceptionIfNonePending(isolate_); 2507 return MaybeHandle<Object>(); 2508 } 2509 2510 stack.resize(begin_properties); 2511 new_object = js_object; 2512 break; 2513 } 2514 case SerializationTag::kEndSparseJSArray: { 2515 ConsumeTag(SerializationTag::kEndSparseJSArray); 2516 2517 // Sparse JS Array: Read the last 2*|num_properties| from the stack. 2518 uint32_t num_properties; 2519 uint32_t length; 2520 if (!ReadVarint<uint32_t>().To(&num_properties) || 2521 !ReadVarint<uint32_t>().To(&length) || 2522 stack.size() / 2 < num_properties) { 2523 isolate_->Throw(*isolate_->factory()->NewError( 2524 MessageTemplate::kDataCloneDeserializationError)); 2525 return MaybeHandle<Object>(); 2526 } 2527 2528 Handle<JSArray> js_array = 2529 isolate_->factory()->NewJSArray(0, TERMINAL_FAST_ELEMENTS_KIND); 2530 MAYBE_RETURN_NULL(JSArray::SetLength(js_array, length)); 2531 size_t begin_properties = 2532 stack.size() - 2 * static_cast<size_t>(num_properties); 2533 if (num_properties && 2534 !SetPropertiesFromKeyValuePairs( 2535 isolate_, js_array, &stack[begin_properties], num_properties) 2536 .FromMaybe(false)) { 2537 ThrowDeserializationExceptionIfNonePending(isolate_); 2538 return MaybeHandle<Object>(); 2539 } 2540 2541 stack.resize(begin_properties); 2542 new_object = js_array; 2543 break; 2544 } 2545 case SerializationTag::kEndDenseJSArray: { 2546 // This was already broken in Chromium, and apparently wasn't missed. 2547 isolate_->Throw(*isolate_->factory()->NewError( 2548 MessageTemplate::kDataCloneDeserializationError)); 2549 return MaybeHandle<Object>(); 2550 } 2551 default: 2552 if (!ReadObject().ToHandle(&new_object)) return MaybeHandle<Object>(); 2553 break; 2554 } 2555 stack.push_back(new_object); 2556 } 2557 2558// Nothing remains but padding. 2559#ifdef DEBUG 2560 while (position_ < end_) { 2561 DCHECK(*position_++ == static_cast<uint8_t>(SerializationTag::kPadding)); 2562 } 2563#endif 2564 position_ = end_; 2565 2566 if (stack.size() != 1) { 2567 isolate_->Throw(*isolate_->factory()->NewError( 2568 MessageTemplate::kDataCloneDeserializationError)); 2569 return MaybeHandle<Object>(); 2570 } 2571 return scope.CloseAndEscape(stack[0]); 2572} 2573 2574} // namespace internal 2575} // namespace v8 2576