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