@@ -25,6 +25,7 @@ using v8::MaybeLocal; |
25 | 25 | using v8::NewStringType; |
26 | 26 | using v8::Number; |
27 | 27 | using v8::Object; |
| 28 | +using v8::SharedArrayBuffer; |
28 | 29 | using v8::String; |
29 | 30 | using v8::Value; |
30 | 31 |
|
@@ -675,26 +676,17 @@ void ExportBytes(const FunctionCallbackInfo<Value>& args) { |
675 | 676 | return; |
676 | 677 | } |
677 | 678 |
|
678 | | - const uint8_t* source_data = nullptr; |
679 | | - size_t source_len = 0; |
| 679 | + // This needs to be kept alive until the data |
| 680 | + // is actually copied. |
| 681 | + ArrayBufferViewContents<uint8_t> view; |
680 | 682 |
|
681 | | - if (args[0]->IsArrayBuffer()) { |
682 | | - Local<ArrayBuffer> array_buffer = args[0].As<ArrayBuffer>(); |
683 | | - std::shared_ptr<BackingStore> store = array_buffer->GetBackingStore(); |
684 | | - if (!store) { |
685 | | - THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBuffer backing store"); |
686 | | - return; |
687 | | - } |
688 | | - source_data = static_cast<const uint8_t*>(store->Data()); |
689 | | - source_len = array_buffer->ByteLength(); |
690 | | - } else if (args[0]->IsArrayBufferView()) { |
691 | | - ArrayBufferViewContents<uint8_t> view(args[0]); |
| 683 | + if (args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer() || |
| 684 | + args[0]->IsArrayBufferView()) { |
| 685 | + view.ReadValue(args[0]); |
692 | 686 | if (view.WasDetached()) { |
693 | 687 | THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBufferView backing store"); |
694 | 688 | return; |
695 | 689 | } |
696 | | - source_data = view.data(); |
697 | | - source_len = view.length(); |
698 | 690 | } else { |
699 | 691 | THROW_ERR_INVALID_ARG_TYPE( |
700 | 692 | env, |
@@ -713,12 +705,12 @@ void ExportBytes(const FunctionCallbackInfo<Value>& args) { |
713 | 705 | return; |
714 | 706 | } |
715 | 707 |
|
716 | | - if (len < source_len) { |
| 708 | + if (len < view.length()) { |
717 | 709 | THROW_ERR_OUT_OF_RANGE(env, "The length must be >= source byte length"); |
718 | 710 | return; |
719 | 711 | } |
720 | 712 |
|
721 | | - if (ptr == 0 && source_len > 0) { |
| 713 | + if (ptr == 0 && view.length() > 0) { |
722 | 714 | THROW_ERR_FFI_INVALID_POINTER(env, |
723 | 715 | "Cannot create a buffer from a null pointer"); |
724 | 716 | return; |
@@ -733,9 +725,7 @@ void ExportBytes(const FunctionCallbackInfo<Value>& args) { |
733 | 725 | return; |
734 | 726 | } |
735 | 727 |
|
736 | | - if (source_len > 0) { |
737 | | - std::memcpy(reinterpret_cast<void*>(ptr), source_data, source_len); |
738 | | - } |
| 728 | + std::memcpy(reinterpret_cast<void*>(ptr), view.data(), view.length()); |
739 | 729 | } |
740 | 730 |
|
741 | 731 | void GetRawPointer(const FunctionCallbackInfo<Value>& args) { |
@@ -752,28 +742,34 @@ void GetRawPointer(const FunctionCallbackInfo<Value>& args) { |
752 | 742 | } |
753 | 743 |
|
754 | 744 | uintptr_t ptr = 0; |
| 745 | + size_t offset = 0; |
| 746 | + std::shared_ptr<BackingStore> store; |
755 | 747 |
|
756 | 748 | if (args[0]->IsArrayBuffer()) { |
757 | | - Local<ArrayBuffer> array_buffer = args[0].As<ArrayBuffer>(); |
758 | | - std::shared_ptr<BackingStore> store = array_buffer->GetBackingStore(); |
759 | | - if (!store) { |
760 | | - THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBuffer backing store"); |
761 | | - return; |
762 | | - } |
763 | | - ptr = reinterpret_cast<uintptr_t>(store->Data()); |
| 749 | + store = args[0].As<ArrayBuffer>()->GetBackingStore(); |
| 750 | + } else if (args[0]->IsSharedArrayBuffer()) { |
| 751 | + store = args[0].As<SharedArrayBuffer>()->GetBackingStore(); |
764 | 752 | } else if (args[0]->IsArrayBufferView()) { |
765 | | - ArrayBufferViewContents<uint8_t> view(args[0]); |
766 | | - if (view.WasDetached()) { |
767 | | - THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBufferView backing store"); |
768 | | - return; |
769 | | - } |
770 | | - ptr = reinterpret_cast<uintptr_t>(view.data()); |
| 753 | + // Access the store here to ensure that it exists. Small typed arrays |
| 754 | + // may not have a store until this point and can instead be stored |
| 755 | + // entirely in-heap. |
| 756 | + store = args[0].As<ArrayBufferView>()->Buffer()->GetBackingStore(); |
| 757 | + offset = args[0].As<ArrayBufferView>()->ByteOffset(); |
771 | 758 | } else { |
772 | | - THROW_ERR_INVALID_ARG_TYPE( |
773 | | - env, |
774 | | - "The first argument must be a Buffer, ArrayBuffer, or ArrayBufferView"); |
| 759 | + THROW_ERR_INVALID_ARG_TYPE(env, |
| 760 | + "The first argument must be a Buffer, " |
| 761 | + "ArrayBuffer, or ArrayBufferView"); |
| 762 | + return; |
| 763 | + } |
| 764 | + |
| 765 | + // WARNING: There is no inherent guarantee that the pointer returned |
| 766 | + // from this function will be valid beyond the lifetime of the BackingStore |
| 767 | + // instance! |
| 768 | + if (!store) { |
| 769 | + THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBuffer backing store"); |
775 | 770 | return; |
776 | 771 | } |
| 772 | + ptr = reinterpret_cast<uintptr_t>(store->Data()) + offset; |
777 | 773 |
|
778 | 774 | args.GetReturnValue().Set( |
779 | 775 | BigInt::NewFromUnsigned(isolate, static_cast<uint64_t>(ptr))); |
|