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