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