| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/value-serializer.h" | 5 #include "src/value-serializer.h" |
| 6 | 6 |
| 7 #include <type_traits> | 7 #include <type_traits> |
| 8 | 8 |
| 9 #include "src/base/logging.h" | 9 #include "src/base/logging.h" |
| 10 #include "src/conversions.h" | 10 #include "src/conversions.h" |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 WriteRawBytes(chars.begin(), chars.length() * sizeof(uint8_t)); | 210 WriteRawBytes(chars.begin(), chars.length() * sizeof(uint8_t)); |
| 211 } | 211 } |
| 212 | 212 |
| 213 void ValueSerializer::WriteTwoByteString(Vector<const uc16> chars) { | 213 void ValueSerializer::WriteTwoByteString(Vector<const uc16> chars) { |
| 214 // Warning: this uses host endianness. | 214 // Warning: this uses host endianness. |
| 215 WriteVarint<uint32_t>(chars.length() * sizeof(uc16)); | 215 WriteVarint<uint32_t>(chars.length() * sizeof(uc16)); |
| 216 WriteRawBytes(chars.begin(), chars.length() * sizeof(uc16)); | 216 WriteRawBytes(chars.begin(), chars.length() * sizeof(uc16)); |
| 217 } | 217 } |
| 218 | 218 |
| 219 void ValueSerializer::WriteRawBytes(const void* source, size_t length) { | 219 void ValueSerializer::WriteRawBytes(const void* source, size_t length) { |
| 220 memcpy(ReserveRawBytes(length), source, length); | 220 uint8_t* dest; |
| 221 if (ReserveRawBytes(length).To(&dest)) { |
| 222 memcpy(dest, source, length); |
| 223 } |
| 221 } | 224 } |
| 222 | 225 |
| 223 uint8_t* ValueSerializer::ReserveRawBytes(size_t bytes) { | 226 Maybe<uint8_t*> ValueSerializer::ReserveRawBytes(size_t bytes) { |
| 224 size_t old_size = buffer_size_; | 227 size_t old_size = buffer_size_; |
| 225 size_t new_size = old_size + bytes; | 228 size_t new_size = old_size + bytes; |
| 226 if (new_size > buffer_capacity_) ExpandBuffer(new_size); | 229 if (new_size > buffer_capacity_) { |
| 230 bool ok; |
| 231 if (!ExpandBuffer(new_size).To(&ok)) { |
| 232 return Nothing<uint8_t*>(); |
| 233 } |
| 234 } |
| 227 buffer_size_ = new_size; | 235 buffer_size_ = new_size; |
| 228 return &buffer_[old_size]; | 236 return Just(&buffer_[old_size]); |
| 229 } | 237 } |
| 230 | 238 |
| 231 void ValueSerializer::ExpandBuffer(size_t required_capacity) { | 239 Maybe<bool> ValueSerializer::ExpandBuffer(size_t required_capacity) { |
| 232 DCHECK_GT(required_capacity, buffer_capacity_); | 240 DCHECK_GT(required_capacity, buffer_capacity_); |
| 233 size_t requested_capacity = | 241 size_t requested_capacity = |
| 234 std::max(required_capacity, buffer_capacity_ * 2) + 64; | 242 std::max(required_capacity, buffer_capacity_ * 2) + 64; |
| 235 size_t provided_capacity = 0; | 243 size_t provided_capacity = 0; |
| 236 void* new_buffer = nullptr; | 244 void* new_buffer = nullptr; |
| 237 if (delegate_) { | 245 if (delegate_) { |
| 238 new_buffer = delegate_->ReallocateBufferMemory(buffer_, requested_capacity, | 246 new_buffer = delegate_->ReallocateBufferMemory(buffer_, requested_capacity, |
| 239 &provided_capacity); | 247 &provided_capacity); |
| 240 } else { | 248 } else { |
| 241 new_buffer = realloc(buffer_, requested_capacity); | 249 new_buffer = realloc(buffer_, requested_capacity); |
| 242 provided_capacity = requested_capacity; | 250 provided_capacity = requested_capacity; |
| 243 } | 251 } |
| 244 DCHECK_GE(provided_capacity, requested_capacity); | 252 if (new_buffer) { |
| 245 buffer_ = reinterpret_cast<uint8_t*>(new_buffer); | 253 DCHECK(provided_capacity >= requested_capacity); |
| 246 buffer_capacity_ = provided_capacity; | 254 buffer_ = reinterpret_cast<uint8_t*>(new_buffer); |
| 255 buffer_capacity_ = provided_capacity; |
| 256 return Just(true); |
| 257 } else { |
| 258 out_of_memory_ = true; |
| 259 return Nothing<bool>(); |
| 260 } |
| 247 } | 261 } |
| 248 | 262 |
| 249 void ValueSerializer::WriteUint32(uint32_t value) { | 263 void ValueSerializer::WriteUint32(uint32_t value) { |
| 250 WriteVarint<uint32_t>(value); | 264 WriteVarint<uint32_t>(value); |
| 251 } | 265 } |
| 252 | 266 |
| 253 void ValueSerializer::WriteUint64(uint64_t value) { | 267 void ValueSerializer::WriteUint64(uint64_t value) { |
| 254 WriteVarint<uint64_t>(value); | 268 WriteVarint<uint64_t>(value); |
| 255 } | 269 } |
| 256 | 270 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 267 } | 281 } |
| 268 | 282 |
| 269 void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id, | 283 void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id, |
| 270 Handle<JSArrayBuffer> array_buffer) { | 284 Handle<JSArrayBuffer> array_buffer) { |
| 271 DCHECK(!array_buffer_transfer_map_.Find(array_buffer)); | 285 DCHECK(!array_buffer_transfer_map_.Find(array_buffer)); |
| 272 DCHECK(!array_buffer->is_shared()); | 286 DCHECK(!array_buffer->is_shared()); |
| 273 array_buffer_transfer_map_.Set(array_buffer, transfer_id); | 287 array_buffer_transfer_map_.Set(array_buffer, transfer_id); |
| 274 } | 288 } |
| 275 | 289 |
| 276 Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) { | 290 Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) { |
| 291 out_of_memory_ = false; |
| 277 if (object->IsSmi()) { | 292 if (object->IsSmi()) { |
| 278 WriteSmi(Smi::cast(*object)); | 293 WriteSmi(Smi::cast(*object)); |
| 279 return Just(true); | 294 return ThrowIfOutOfMemory(); |
| 280 } | 295 } |
| 281 | 296 |
| 282 DCHECK(object->IsHeapObject()); | 297 DCHECK(object->IsHeapObject()); |
| 283 switch (HeapObject::cast(*object)->map()->instance_type()) { | 298 switch (HeapObject::cast(*object)->map()->instance_type()) { |
| 284 case ODDBALL_TYPE: | 299 case ODDBALL_TYPE: |
| 285 WriteOddball(Oddball::cast(*object)); | 300 WriteOddball(Oddball::cast(*object)); |
| 286 return Just(true); | 301 return ThrowIfOutOfMemory(); |
| 287 case HEAP_NUMBER_TYPE: | 302 case HEAP_NUMBER_TYPE: |
| 288 case MUTABLE_HEAP_NUMBER_TYPE: | 303 case MUTABLE_HEAP_NUMBER_TYPE: |
| 289 WriteHeapNumber(HeapNumber::cast(*object)); | 304 WriteHeapNumber(HeapNumber::cast(*object)); |
| 290 return Just(true); | 305 return ThrowIfOutOfMemory(); |
| 291 case JS_TYPED_ARRAY_TYPE: | 306 case JS_TYPED_ARRAY_TYPE: |
| 292 case JS_DATA_VIEW_TYPE: { | 307 case JS_DATA_VIEW_TYPE: { |
| 293 // Despite being JSReceivers, these have their wrapped buffer serialized | 308 // Despite being JSReceivers, these have their wrapped buffer serialized |
| 294 // first. That makes this logic a little quirky, because it needs to | 309 // first. That makes this logic a little quirky, because it needs to |
| 295 // happen before we assign object IDs. | 310 // happen before we assign object IDs. |
| 296 // TODO(jbroman): It may be possible to avoid materializing a typed | 311 // TODO(jbroman): It may be possible to avoid materializing a typed |
| 297 // array's buffer here. | 312 // array's buffer here. |
| 298 Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(object); | 313 Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(object); |
| 299 if (!id_map_.Find(view)) { | 314 if (!id_map_.Find(view)) { |
| 300 Handle<JSArrayBuffer> buffer( | 315 Handle<JSArrayBuffer> buffer( |
| 301 view->IsJSTypedArray() | 316 view->IsJSTypedArray() |
| 302 ? Handle<JSTypedArray>::cast(view)->GetBuffer() | 317 ? Handle<JSTypedArray>::cast(view)->GetBuffer() |
| 303 : handle(JSArrayBuffer::cast(view->buffer()), isolate_)); | 318 : handle(JSArrayBuffer::cast(view->buffer()), isolate_)); |
| 304 if (!WriteJSReceiver(buffer).FromMaybe(false)) return Nothing<bool>(); | 319 if (!WriteJSReceiver(buffer).FromMaybe(false)) return Nothing<bool>(); |
| 305 } | 320 } |
| 306 return WriteJSReceiver(view); | 321 return WriteJSReceiver(view); |
| 307 } | 322 } |
| 308 default: | 323 default: |
| 309 if (object->IsString()) { | 324 if (object->IsString()) { |
| 310 WriteString(Handle<String>::cast(object)); | 325 WriteString(Handle<String>::cast(object)); |
| 311 return Just(true); | 326 return ThrowIfOutOfMemory(); |
| 312 } else if (object->IsJSReceiver()) { | 327 } else if (object->IsJSReceiver()) { |
| 313 return WriteJSReceiver(Handle<JSReceiver>::cast(object)); | 328 return WriteJSReceiver(Handle<JSReceiver>::cast(object)); |
| 314 } else { | 329 } else { |
| 315 ThrowDataCloneError(MessageTemplate::kDataCloneError, object); | 330 ThrowDataCloneError(MessageTemplate::kDataCloneError, object); |
| 316 return Nothing<bool>(); | 331 return Nothing<bool>(); |
| 317 } | 332 } |
| 318 } | 333 } |
| 319 } | 334 } |
| 320 | 335 |
| 321 void ValueSerializer::WriteOddball(Oddball* oddball) { | 336 void ValueSerializer::WriteOddball(Oddball* oddball) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 // TODO(jbroman): In a future format version, consider adding a tag for | 377 // TODO(jbroman): In a future format version, consider adding a tag for |
| 363 // Latin-1 strings, so that this can be skipped. | 378 // Latin-1 strings, so that this can be skipped. |
| 364 WriteTag(SerializationTag::kUtf8String); | 379 WriteTag(SerializationTag::kUtf8String); |
| 365 Vector<const uint8_t> chars = flat.ToOneByteVector(); | 380 Vector<const uint8_t> chars = flat.ToOneByteVector(); |
| 366 if (String::IsAscii(chars.begin(), chars.length())) { | 381 if (String::IsAscii(chars.begin(), chars.length())) { |
| 367 WriteOneByteString(chars); | 382 WriteOneByteString(chars); |
| 368 } else { | 383 } else { |
| 369 v8::Local<v8::String> api_string = Utils::ToLocal(string); | 384 v8::Local<v8::String> api_string = Utils::ToLocal(string); |
| 370 uint32_t utf8_length = api_string->Utf8Length(); | 385 uint32_t utf8_length = api_string->Utf8Length(); |
| 371 WriteVarint(utf8_length); | 386 WriteVarint(utf8_length); |
| 372 api_string->WriteUtf8( | 387 uint8_t* dest; |
| 373 reinterpret_cast<char*>(ReserveRawBytes(utf8_length)), utf8_length, | 388 if (ReserveRawBytes(utf8_length).To(&dest)) { |
| 374 nullptr, v8::String::NO_NULL_TERMINATION); | 389 api_string->WriteUtf8(reinterpret_cast<char*>(dest), utf8_length, |
| 390 nullptr, v8::String::NO_NULL_TERMINATION); |
| 391 } |
| 375 } | 392 } |
| 376 } else if (flat.IsTwoByte()) { | 393 } else if (flat.IsTwoByte()) { |
| 377 Vector<const uc16> chars = flat.ToUC16Vector(); | 394 Vector<const uc16> chars = flat.ToUC16Vector(); |
| 378 uint32_t byte_length = chars.length() * sizeof(uc16); | 395 uint32_t byte_length = chars.length() * sizeof(uc16); |
| 379 // The existing reading code expects 16-byte strings to be aligned. | 396 // The existing reading code expects 16-byte strings to be aligned. |
| 380 if ((buffer_size_ + 1 + BytesNeededForVarint(byte_length)) & 1) | 397 if ((buffer_size_ + 1 + BytesNeededForVarint(byte_length)) & 1) |
| 381 WriteTag(SerializationTag::kPadding); | 398 WriteTag(SerializationTag::kPadding); |
| 382 WriteTag(SerializationTag::kTwoByteString); | 399 WriteTag(SerializationTag::kTwoByteString); |
| 383 WriteTwoByteString(chars); | 400 WriteTwoByteString(chars); |
| 384 } else { | 401 } else { |
| 385 UNREACHABLE(); | 402 UNREACHABLE(); |
| 386 } | 403 } |
| 387 } | 404 } |
| 388 | 405 |
| 389 Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) { | 406 Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) { |
| 390 // If the object has already been serialized, just write its ID. | 407 // If the object has already been serialized, just write its ID. |
| 391 uint32_t* id_map_entry = id_map_.Get(receiver); | 408 uint32_t* id_map_entry = id_map_.Get(receiver); |
| 392 if (uint32_t id = *id_map_entry) { | 409 if (uint32_t id = *id_map_entry) { |
| 393 WriteTag(SerializationTag::kObjectReference); | 410 WriteTag(SerializationTag::kObjectReference); |
| 394 WriteVarint(id - 1); | 411 WriteVarint(id - 1); |
| 395 return Just(true); | 412 return ThrowIfOutOfMemory(); |
| 396 } | 413 } |
| 397 | 414 |
| 398 // Otherwise, allocate an ID for it. | 415 // Otherwise, allocate an ID for it. |
| 399 uint32_t id = next_id_++; | 416 uint32_t id = next_id_++; |
| 400 *id_map_entry = id + 1; | 417 *id_map_entry = id + 1; |
| 401 | 418 |
| 402 // Eliminate callable and exotic objects, which should not be serialized. | 419 // Eliminate callable and exotic objects, which should not be serialized. |
| 403 InstanceType instance_type = receiver->map()->instance_type(); | 420 InstanceType instance_type = receiver->map()->instance_type(); |
| 404 if (receiver->IsCallable() || (IsSpecialReceiverInstanceType(instance_type) && | 421 if (receiver->IsCallable() || (IsSpecialReceiverInstanceType(instance_type) && |
| 405 instance_type != JS_SPECIAL_API_OBJECT_TYPE)) { | 422 instance_type != JS_SPECIAL_API_OBJECT_TYPE)) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 425 } else if (JSObject::GetInternalFieldCount(map)) { | 442 } else if (JSObject::GetInternalFieldCount(map)) { |
| 426 return WriteHostObject(js_object); | 443 return WriteHostObject(js_object); |
| 427 } else { | 444 } else { |
| 428 return WriteJSObject(js_object); | 445 return WriteJSObject(js_object); |
| 429 } | 446 } |
| 430 } | 447 } |
| 431 case JS_SPECIAL_API_OBJECT_TYPE: | 448 case JS_SPECIAL_API_OBJECT_TYPE: |
| 432 return WriteHostObject(Handle<JSObject>::cast(receiver)); | 449 return WriteHostObject(Handle<JSObject>::cast(receiver)); |
| 433 case JS_DATE_TYPE: | 450 case JS_DATE_TYPE: |
| 434 WriteJSDate(JSDate::cast(*receiver)); | 451 WriteJSDate(JSDate::cast(*receiver)); |
| 435 return Just(true); | 452 return ThrowIfOutOfMemory(); |
| 436 case JS_VALUE_TYPE: | 453 case JS_VALUE_TYPE: |
| 437 return WriteJSValue(Handle<JSValue>::cast(receiver)); | 454 return WriteJSValue(Handle<JSValue>::cast(receiver)); |
| 438 case JS_REGEXP_TYPE: | 455 case JS_REGEXP_TYPE: |
| 439 WriteJSRegExp(JSRegExp::cast(*receiver)); | 456 WriteJSRegExp(JSRegExp::cast(*receiver)); |
| 440 return Just(true); | 457 return ThrowIfOutOfMemory(); |
| 441 case JS_MAP_TYPE: | 458 case JS_MAP_TYPE: |
| 442 return WriteJSMap(Handle<JSMap>::cast(receiver)); | 459 return WriteJSMap(Handle<JSMap>::cast(receiver)); |
| 443 case JS_SET_TYPE: | 460 case JS_SET_TYPE: |
| 444 return WriteJSSet(Handle<JSSet>::cast(receiver)); | 461 return WriteJSSet(Handle<JSSet>::cast(receiver)); |
| 445 case JS_ARRAY_BUFFER_TYPE: | 462 case JS_ARRAY_BUFFER_TYPE: |
| 446 return WriteJSArrayBuffer(Handle<JSArrayBuffer>::cast(receiver)); | 463 return WriteJSArrayBuffer(Handle<JSArrayBuffer>::cast(receiver)); |
| 447 case JS_TYPED_ARRAY_TYPE: | 464 case JS_TYPED_ARRAY_TYPE: |
| 448 case JS_DATA_VIEW_TYPE: | 465 case JS_DATA_VIEW_TYPE: |
| 449 return WriteJSArrayBufferView(JSArrayBufferView::cast(*receiver)); | 466 return WriteJSArrayBufferView(JSArrayBufferView::cast(*receiver)); |
| 450 default: | 467 default: |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 | 508 |
| 492 if (!WriteObject(key).FromMaybe(false) || | 509 if (!WriteObject(key).FromMaybe(false) || |
| 493 !WriteObject(value).FromMaybe(false)) { | 510 !WriteObject(value).FromMaybe(false)) { |
| 494 return Nothing<bool>(); | 511 return Nothing<bool>(); |
| 495 } | 512 } |
| 496 properties_written++; | 513 properties_written++; |
| 497 } | 514 } |
| 498 | 515 |
| 499 WriteTag(SerializationTag::kEndJSObject); | 516 WriteTag(SerializationTag::kEndJSObject); |
| 500 WriteVarint<uint32_t>(properties_written); | 517 WriteVarint<uint32_t>(properties_written); |
| 501 return Just(true); | 518 return ThrowIfOutOfMemory(); |
| 502 } | 519 } |
| 503 | 520 |
| 504 Maybe<bool> ValueSerializer::WriteJSObjectSlow(Handle<JSObject> object) { | 521 Maybe<bool> ValueSerializer::WriteJSObjectSlow(Handle<JSObject> object) { |
| 505 WriteTag(SerializationTag::kBeginJSObject); | 522 WriteTag(SerializationTag::kBeginJSObject); |
| 506 Handle<FixedArray> keys; | 523 Handle<FixedArray> keys; |
| 507 uint32_t properties_written; | 524 uint32_t properties_written; |
| 508 if (!KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, | 525 if (!KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, |
| 509 ENUMERABLE_STRINGS) | 526 ENUMERABLE_STRINGS) |
| 510 .ToHandle(&keys) || | 527 .ToHandle(&keys) || |
| 511 !WriteJSObjectPropertiesSlow(object, keys).To(&properties_written)) { | 528 !WriteJSObjectPropertiesSlow(object, keys).To(&properties_written)) { |
| 512 return Nothing<bool>(); | 529 return Nothing<bool>(); |
| 513 } | 530 } |
| 514 WriteTag(SerializationTag::kEndJSObject); | 531 WriteTag(SerializationTag::kEndJSObject); |
| 515 WriteVarint<uint32_t>(properties_written); | 532 WriteVarint<uint32_t>(properties_written); |
| 516 return Just(true); | 533 return ThrowIfOutOfMemory(); |
| 517 } | 534 } |
| 518 | 535 |
| 519 Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) { | 536 Maybe<bool> ValueSerializer::WriteJSArray(Handle<JSArray> array) { |
| 520 uint32_t length = 0; | 537 uint32_t length = 0; |
| 521 bool valid_length = array->length()->ToArrayLength(&length); | 538 bool valid_length = array->length()->ToArrayLength(&length); |
| 522 DCHECK(valid_length); | 539 DCHECK(valid_length); |
| 523 USE(valid_length); | 540 USE(valid_length); |
| 524 | 541 |
| 525 // To keep things simple, for now we decide between dense and sparse | 542 // To keep things simple, for now we decide between dense and sparse |
| 526 // serialization based on elements kind. A more principled heuristic could | 543 // serialization based on elements kind. A more principled heuristic could |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 611 if (!KeyAccumulator::GetKeys(array, KeyCollectionMode::kOwnOnly, | 628 if (!KeyAccumulator::GetKeys(array, KeyCollectionMode::kOwnOnly, |
| 612 ENUMERABLE_STRINGS) | 629 ENUMERABLE_STRINGS) |
| 613 .ToHandle(&keys) || | 630 .ToHandle(&keys) || |
| 614 !WriteJSObjectPropertiesSlow(array, keys).To(&properties_written)) { | 631 !WriteJSObjectPropertiesSlow(array, keys).To(&properties_written)) { |
| 615 return Nothing<bool>(); | 632 return Nothing<bool>(); |
| 616 } | 633 } |
| 617 WriteTag(SerializationTag::kEndSparseJSArray); | 634 WriteTag(SerializationTag::kEndSparseJSArray); |
| 618 WriteVarint<uint32_t>(properties_written); | 635 WriteVarint<uint32_t>(properties_written); |
| 619 WriteVarint<uint32_t>(length); | 636 WriteVarint<uint32_t>(length); |
| 620 } | 637 } |
| 621 return Just(true); | 638 return ThrowIfOutOfMemory(); |
| 622 } | 639 } |
| 623 | 640 |
| 624 void ValueSerializer::WriteJSDate(JSDate* date) { | 641 void ValueSerializer::WriteJSDate(JSDate* date) { |
| 625 WriteTag(SerializationTag::kDate); | 642 WriteTag(SerializationTag::kDate); |
| 626 WriteDouble(date->value()->Number()); | 643 WriteDouble(date->value()->Number()); |
| 627 } | 644 } |
| 628 | 645 |
| 629 Maybe<bool> ValueSerializer::WriteJSValue(Handle<JSValue> value) { | 646 Maybe<bool> ValueSerializer::WriteJSValue(Handle<JSValue> value) { |
| 630 Object* inner_value = value->value(); | 647 Object* inner_value = value->value(); |
| 631 if (inner_value->IsTrue(isolate_)) { | 648 if (inner_value->IsTrue(isolate_)) { |
| 632 WriteTag(SerializationTag::kTrueObject); | 649 WriteTag(SerializationTag::kTrueObject); |
| 633 } else if (inner_value->IsFalse(isolate_)) { | 650 } else if (inner_value->IsFalse(isolate_)) { |
| 634 WriteTag(SerializationTag::kFalseObject); | 651 WriteTag(SerializationTag::kFalseObject); |
| 635 } else if (inner_value->IsNumber()) { | 652 } else if (inner_value->IsNumber()) { |
| 636 WriteTag(SerializationTag::kNumberObject); | 653 WriteTag(SerializationTag::kNumberObject); |
| 637 WriteDouble(inner_value->Number()); | 654 WriteDouble(inner_value->Number()); |
| 638 } else if (inner_value->IsString()) { | 655 } else if (inner_value->IsString()) { |
| 639 // TODO(jbroman): Replace UTF-8 encoding with the same options available for | 656 // TODO(jbroman): Replace UTF-8 encoding with the same options available for |
| 640 // ordinary strings. | 657 // ordinary strings. |
| 641 WriteTag(SerializationTag::kStringObject); | 658 WriteTag(SerializationTag::kStringObject); |
| 642 v8::Local<v8::String> api_string = | 659 v8::Local<v8::String> api_string = |
| 643 Utils::ToLocal(handle(String::cast(inner_value), isolate_)); | 660 Utils::ToLocal(handle(String::cast(inner_value), isolate_)); |
| 644 uint32_t utf8_length = api_string->Utf8Length(); | 661 uint32_t utf8_length = api_string->Utf8Length(); |
| 645 WriteVarint(utf8_length); | 662 WriteVarint(utf8_length); |
| 646 api_string->WriteUtf8(reinterpret_cast<char*>(ReserveRawBytes(utf8_length)), | 663 uint8_t* dest; |
| 647 utf8_length, nullptr, | 664 if (ReserveRawBytes(utf8_length).To(&dest)) { |
| 648 v8::String::NO_NULL_TERMINATION); | 665 api_string->WriteUtf8(reinterpret_cast<char*>(dest), utf8_length, nullptr, |
| 666 v8::String::NO_NULL_TERMINATION); |
| 667 } |
| 649 } else { | 668 } else { |
| 650 DCHECK(inner_value->IsSymbol()); | 669 DCHECK(inner_value->IsSymbol()); |
| 651 ThrowDataCloneError(MessageTemplate::kDataCloneError, value); | 670 ThrowDataCloneError(MessageTemplate::kDataCloneError, value); |
| 652 return Nothing<bool>(); | 671 return Nothing<bool>(); |
| 653 } | 672 } |
| 654 return Just(true); | 673 return ThrowIfOutOfMemory(); |
| 655 } | 674 } |
| 656 | 675 |
| 657 void ValueSerializer::WriteJSRegExp(JSRegExp* regexp) { | 676 void ValueSerializer::WriteJSRegExp(JSRegExp* regexp) { |
| 658 WriteTag(SerializationTag::kRegExp); | 677 WriteTag(SerializationTag::kRegExp); |
| 659 v8::Local<v8::String> api_string = | 678 v8::Local<v8::String> api_string = |
| 660 Utils::ToLocal(handle(regexp->Pattern(), isolate_)); | 679 Utils::ToLocal(handle(regexp->Pattern(), isolate_)); |
| 661 uint32_t utf8_length = api_string->Utf8Length(); | 680 uint32_t utf8_length = api_string->Utf8Length(); |
| 662 WriteVarint(utf8_length); | 681 WriteVarint(utf8_length); |
| 663 api_string->WriteUtf8(reinterpret_cast<char*>(ReserveRawBytes(utf8_length)), | 682 uint8_t* dest; |
| 664 utf8_length, nullptr, v8::String::NO_NULL_TERMINATION); | 683 if (ReserveRawBytes(utf8_length).To(&dest)) { |
| 684 api_string->WriteUtf8(reinterpret_cast<char*>(dest), utf8_length, nullptr, |
| 685 v8::String::NO_NULL_TERMINATION); |
| 686 } |
| 665 WriteVarint(static_cast<uint32_t>(regexp->GetFlags())); | 687 WriteVarint(static_cast<uint32_t>(regexp->GetFlags())); |
| 666 } | 688 } |
| 667 | 689 |
| 668 Maybe<bool> ValueSerializer::WriteJSMap(Handle<JSMap> map) { | 690 Maybe<bool> ValueSerializer::WriteJSMap(Handle<JSMap> map) { |
| 669 // First copy the key-value pairs, since getters could mutate them. | 691 // First copy the key-value pairs, since getters could mutate them. |
| 670 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table())); | 692 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table())); |
| 671 int length = table->NumberOfElements() * 2; | 693 int length = table->NumberOfElements() * 2; |
| 672 Handle<FixedArray> entries = isolate_->factory()->NewFixedArray(length); | 694 Handle<FixedArray> entries = isolate_->factory()->NewFixedArray(length); |
| 673 { | 695 { |
| 674 DisallowHeapAllocation no_gc; | 696 DisallowHeapAllocation no_gc; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 686 | 708 |
| 687 // Then write it out. | 709 // Then write it out. |
| 688 WriteTag(SerializationTag::kBeginJSMap); | 710 WriteTag(SerializationTag::kBeginJSMap); |
| 689 for (int i = 0; i < length; i++) { | 711 for (int i = 0; i < length; i++) { |
| 690 if (!WriteObject(handle(entries->get(i), isolate_)).FromMaybe(false)) { | 712 if (!WriteObject(handle(entries->get(i), isolate_)).FromMaybe(false)) { |
| 691 return Nothing<bool>(); | 713 return Nothing<bool>(); |
| 692 } | 714 } |
| 693 } | 715 } |
| 694 WriteTag(SerializationTag::kEndJSMap); | 716 WriteTag(SerializationTag::kEndJSMap); |
| 695 WriteVarint<uint32_t>(length); | 717 WriteVarint<uint32_t>(length); |
| 696 return Just(true); | 718 return ThrowIfOutOfMemory(); |
| 697 } | 719 } |
| 698 | 720 |
| 699 Maybe<bool> ValueSerializer::WriteJSSet(Handle<JSSet> set) { | 721 Maybe<bool> ValueSerializer::WriteJSSet(Handle<JSSet> set) { |
| 700 // First copy the element pointers, since getters could mutate them. | 722 // First copy the element pointers, since getters could mutate them. |
| 701 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table())); | 723 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table())); |
| 702 int length = table->NumberOfElements(); | 724 int length = table->NumberOfElements(); |
| 703 Handle<FixedArray> entries = isolate_->factory()->NewFixedArray(length); | 725 Handle<FixedArray> entries = isolate_->factory()->NewFixedArray(length); |
| 704 { | 726 { |
| 705 DisallowHeapAllocation no_gc; | 727 DisallowHeapAllocation no_gc; |
| 706 Oddball* the_hole = isolate_->heap()->the_hole_value(); | 728 Oddball* the_hole = isolate_->heap()->the_hole_value(); |
| 707 int capacity = table->UsedCapacity(); | 729 int capacity = table->UsedCapacity(); |
| 708 int result_index = 0; | 730 int result_index = 0; |
| 709 for (int i = 0; i < capacity; i++) { | 731 for (int i = 0; i < capacity; i++) { |
| 710 Object* key = table->KeyAt(i); | 732 Object* key = table->KeyAt(i); |
| 711 if (key == the_hole) continue; | 733 if (key == the_hole) continue; |
| 712 entries->set(result_index++, key); | 734 entries->set(result_index++, key); |
| 713 } | 735 } |
| 714 DCHECK_EQ(result_index, length); | 736 DCHECK_EQ(result_index, length); |
| 715 } | 737 } |
| 716 | 738 |
| 717 // Then write it out. | 739 // Then write it out. |
| 718 WriteTag(SerializationTag::kBeginJSSet); | 740 WriteTag(SerializationTag::kBeginJSSet); |
| 719 for (int i = 0; i < length; i++) { | 741 for (int i = 0; i < length; i++) { |
| 720 if (!WriteObject(handle(entries->get(i), isolate_)).FromMaybe(false)) { | 742 if (!WriteObject(handle(entries->get(i), isolate_)).FromMaybe(false)) { |
| 721 return Nothing<bool>(); | 743 return Nothing<bool>(); |
| 722 } | 744 } |
| 723 } | 745 } |
| 724 WriteTag(SerializationTag::kEndJSSet); | 746 WriteTag(SerializationTag::kEndJSSet); |
| 725 WriteVarint<uint32_t>(length); | 747 WriteVarint<uint32_t>(length); |
| 726 return Just(true); | 748 return ThrowIfOutOfMemory(); |
| 727 } | 749 } |
| 728 | 750 |
| 729 Maybe<bool> ValueSerializer::WriteJSArrayBuffer( | 751 Maybe<bool> ValueSerializer::WriteJSArrayBuffer( |
| 730 Handle<JSArrayBuffer> array_buffer) { | 752 Handle<JSArrayBuffer> array_buffer) { |
| 731 if (array_buffer->is_shared()) { | 753 if (array_buffer->is_shared()) { |
| 732 if (!delegate_) { | 754 if (!delegate_) { |
| 733 ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer); | 755 ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer); |
| 734 return Nothing<bool>(); | 756 return Nothing<bool>(); |
| 735 } | 757 } |
| 736 | 758 |
| 737 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); | 759 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); |
| 738 Maybe<uint32_t> index = delegate_->GetSharedArrayBufferId( | 760 Maybe<uint32_t> index = delegate_->GetSharedArrayBufferId( |
| 739 v8_isolate, Utils::ToLocalShared(array_buffer)); | 761 v8_isolate, Utils::ToLocalShared(array_buffer)); |
| 740 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>()); | 762 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>()); |
| 741 | 763 |
| 742 WriteTag(SerializationTag::kSharedArrayBuffer); | 764 WriteTag(SerializationTag::kSharedArrayBuffer); |
| 743 WriteVarint(index.FromJust()); | 765 WriteVarint(index.FromJust()); |
| 744 return Just(true); | 766 return ThrowIfOutOfMemory(); |
| 745 } | 767 } |
| 746 | 768 |
| 747 uint32_t* transfer_entry = array_buffer_transfer_map_.Find(array_buffer); | 769 uint32_t* transfer_entry = array_buffer_transfer_map_.Find(array_buffer); |
| 748 if (transfer_entry) { | 770 if (transfer_entry) { |
| 749 WriteTag(SerializationTag::kArrayBufferTransfer); | 771 WriteTag(SerializationTag::kArrayBufferTransfer); |
| 750 WriteVarint(*transfer_entry); | 772 WriteVarint(*transfer_entry); |
| 751 return Just(true); | 773 return ThrowIfOutOfMemory(); |
| 752 } | 774 } |
| 753 if (array_buffer->was_neutered()) { | 775 if (array_buffer->was_neutered()) { |
| 754 ThrowDataCloneError(MessageTemplate::kDataCloneErrorNeuteredArrayBuffer); | 776 ThrowDataCloneError(MessageTemplate::kDataCloneErrorNeuteredArrayBuffer); |
| 755 return Nothing<bool>(); | 777 return Nothing<bool>(); |
| 756 } | 778 } |
| 757 double byte_length = array_buffer->byte_length()->Number(); | 779 double byte_length = array_buffer->byte_length()->Number(); |
| 758 if (byte_length > std::numeric_limits<uint32_t>::max()) { | 780 if (byte_length > std::numeric_limits<uint32_t>::max()) { |
| 759 ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer); | 781 ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer); |
| 760 return Nothing<bool>(); | 782 return Nothing<bool>(); |
| 761 } | 783 } |
| 762 WriteTag(SerializationTag::kArrayBuffer); | 784 WriteTag(SerializationTag::kArrayBuffer); |
| 763 WriteVarint<uint32_t>(byte_length); | 785 WriteVarint<uint32_t>(byte_length); |
| 764 WriteRawBytes(array_buffer->backing_store(), byte_length); | 786 WriteRawBytes(array_buffer->backing_store(), byte_length); |
| 765 return Just(true); | 787 return ThrowIfOutOfMemory(); |
| 766 } | 788 } |
| 767 | 789 |
| 768 Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView* view) { | 790 Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView* view) { |
| 769 WriteTag(SerializationTag::kArrayBufferView); | 791 WriteTag(SerializationTag::kArrayBufferView); |
| 770 ArrayBufferViewTag tag = ArrayBufferViewTag::kInt8Array; | 792 ArrayBufferViewTag tag = ArrayBufferViewTag::kInt8Array; |
| 771 if (view->IsJSTypedArray()) { | 793 if (view->IsJSTypedArray()) { |
| 772 switch (JSTypedArray::cast(view)->type()) { | 794 switch (JSTypedArray::cast(view)->type()) { |
| 773 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | 795 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
| 774 case kExternal##Type##Array: \ | 796 case kExternal##Type##Array: \ |
| 775 tag = ArrayBufferViewTag::k##Type##Array; \ | 797 tag = ArrayBufferViewTag::k##Type##Array; \ |
| 776 break; | 798 break; |
| 777 TYPED_ARRAYS(TYPED_ARRAY_CASE) | 799 TYPED_ARRAYS(TYPED_ARRAY_CASE) |
| 778 #undef TYPED_ARRAY_CASE | 800 #undef TYPED_ARRAY_CASE |
| 779 } | 801 } |
| 780 } else { | 802 } else { |
| 781 DCHECK(view->IsJSDataView()); | 803 DCHECK(view->IsJSDataView()); |
| 782 tag = ArrayBufferViewTag::kDataView; | 804 tag = ArrayBufferViewTag::kDataView; |
| 783 } | 805 } |
| 784 WriteVarint(static_cast<uint8_t>(tag)); | 806 WriteVarint(static_cast<uint8_t>(tag)); |
| 785 WriteVarint(NumberToUint32(view->byte_offset())); | 807 WriteVarint(NumberToUint32(view->byte_offset())); |
| 786 WriteVarint(NumberToUint32(view->byte_length())); | 808 WriteVarint(NumberToUint32(view->byte_length())); |
| 787 return Just(true); | 809 return ThrowIfOutOfMemory(); |
| 788 } | 810 } |
| 789 | 811 |
| 790 Maybe<bool> ValueSerializer::WriteWasmModule(Handle<JSObject> object) { | 812 Maybe<bool> ValueSerializer::WriteWasmModule(Handle<JSObject> object) { |
| 791 Handle<WasmCompiledModule> compiled_part( | 813 Handle<WasmCompiledModule> compiled_part( |
| 792 WasmCompiledModule::cast(object->GetInternalField(0)), isolate_); | 814 WasmCompiledModule::cast(object->GetInternalField(0)), isolate_); |
| 793 WasmEncodingTag encoding_tag = WasmEncodingTag::kRawBytes; | 815 WasmEncodingTag encoding_tag = WasmEncodingTag::kRawBytes; |
| 794 WriteTag(SerializationTag::kWasmModule); | 816 WriteTag(SerializationTag::kWasmModule); |
| 795 WriteRawBytes(&encoding_tag, sizeof(encoding_tag)); | 817 WriteRawBytes(&encoding_tag, sizeof(encoding_tag)); |
| 796 | 818 |
| 797 Handle<String> wire_bytes(compiled_part->module_bytes(), isolate_); | 819 Handle<String> wire_bytes(compiled_part->module_bytes(), isolate_); |
| 798 int wire_bytes_length = wire_bytes->length(); | 820 int wire_bytes_length = wire_bytes->length(); |
| 799 WriteVarint<uint32_t>(wire_bytes_length); | 821 WriteVarint<uint32_t>(wire_bytes_length); |
| 800 uint8_t* destination = ReserveRawBytes(wire_bytes_length); | 822 uint8_t* destination; |
| 801 String::WriteToFlat(*wire_bytes, destination, 0, wire_bytes_length); | 823 if (ReserveRawBytes(wire_bytes_length).To(&destination)) { |
| 824 String::WriteToFlat(*wire_bytes, destination, 0, wire_bytes_length); |
| 825 } |
| 802 | 826 |
| 803 std::unique_ptr<ScriptData> script_data = | 827 std::unique_ptr<ScriptData> script_data = |
| 804 WasmCompiledModuleSerializer::SerializeWasmModule(isolate_, | 828 WasmCompiledModuleSerializer::SerializeWasmModule(isolate_, |
| 805 compiled_part); | 829 compiled_part); |
| 806 int script_data_length = script_data->length(); | 830 int script_data_length = script_data->length(); |
| 807 WriteVarint<uint32_t>(script_data_length); | 831 WriteVarint<uint32_t>(script_data_length); |
| 808 WriteRawBytes(script_data->data(), script_data_length); | 832 WriteRawBytes(script_data->data(), script_data_length); |
| 809 | 833 |
| 810 return Just(true); | 834 return ThrowIfOutOfMemory(); |
| 811 } | 835 } |
| 812 | 836 |
| 813 Maybe<bool> ValueSerializer::WriteHostObject(Handle<JSObject> object) { | 837 Maybe<bool> ValueSerializer::WriteHostObject(Handle<JSObject> object) { |
| 814 if (!delegate_) { | 838 if (!delegate_) { |
| 815 isolate_->Throw(*isolate_->factory()->NewError( | 839 isolate_->Throw(*isolate_->factory()->NewError( |
| 816 isolate_->error_function(), MessageTemplate::kDataCloneError, object)); | 840 isolate_->error_function(), MessageTemplate::kDataCloneError, object)); |
| 817 return Nothing<bool>(); | 841 return Nothing<bool>(); |
| 818 } | 842 } |
| 819 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); | 843 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_); |
| 820 Maybe<bool> result = | 844 Maybe<bool> result = |
| (...skipping 30 matching lines...) Expand all Loading... |
| 851 } | 875 } |
| 852 return Just(properties_written); | 876 return Just(properties_written); |
| 853 } | 877 } |
| 854 | 878 |
| 855 void ValueSerializer::ThrowDataCloneError( | 879 void ValueSerializer::ThrowDataCloneError( |
| 856 MessageTemplate::Template template_index) { | 880 MessageTemplate::Template template_index) { |
| 857 return ThrowDataCloneError(template_index, | 881 return ThrowDataCloneError(template_index, |
| 858 isolate_->factory()->empty_string()); | 882 isolate_->factory()->empty_string()); |
| 859 } | 883 } |
| 860 | 884 |
| 885 Maybe<bool> ValueSerializer::ThrowIfOutOfMemory() { |
| 886 if (out_of_memory_) { |
| 887 ThrowDataCloneError(MessageTemplate::kDataCloneErrorOutOfMemory); |
| 888 return Nothing<bool>(); |
| 889 } |
| 890 return Just(true); |
| 891 } |
| 892 |
| 861 void ValueSerializer::ThrowDataCloneError( | 893 void ValueSerializer::ThrowDataCloneError( |
| 862 MessageTemplate::Template template_index, Handle<Object> arg0) { | 894 MessageTemplate::Template template_index, Handle<Object> arg0) { |
| 863 Handle<String> message = | 895 Handle<String> message = |
| 864 MessageTemplate::FormatMessage(isolate_, template_index, arg0); | 896 MessageTemplate::FormatMessage(isolate_, template_index, arg0); |
| 865 if (delegate_) { | 897 if (delegate_) { |
| 866 delegate_->ThrowDataCloneError(Utils::ToLocal(message)); | 898 delegate_->ThrowDataCloneError(Utils::ToLocal(message)); |
| 867 } else { | 899 } else { |
| 868 isolate_->Throw( | 900 isolate_->Throw( |
| 869 *isolate_->factory()->NewError(isolate_->error_function(), message)); | 901 *isolate_->factory()->NewError(isolate_->error_function(), message)); |
| 870 } | 902 } |
| (...skipping 1013 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1884 if (stack.size() != 1) { | 1916 if (stack.size() != 1) { |
| 1885 isolate_->Throw(*isolate_->factory()->NewError( | 1917 isolate_->Throw(*isolate_->factory()->NewError( |
| 1886 MessageTemplate::kDataCloneDeserializationError)); | 1918 MessageTemplate::kDataCloneDeserializationError)); |
| 1887 return MaybeHandle<Object>(); | 1919 return MaybeHandle<Object>(); |
| 1888 } | 1920 } |
| 1889 return scope.CloseAndEscape(stack[0]); | 1921 return scope.CloseAndEscape(stack[0]); |
| 1890 } | 1922 } |
| 1891 | 1923 |
| 1892 } // namespace internal | 1924 } // namespace internal |
| 1893 } // namespace v8 | 1925 } // namespace v8 |
| OLD | NEW |