From bc927c7477570ffc56ff950c78f5ecd54ade3230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Fri, 17 Jan 2020 14:41:12 +0100 Subject: [PATCH] ArrayBuffer::new_backing_store_from_boxed_slice (#202) --- src/array_buffer.rs | 40 ++++++++++++++++++++++++ src/binding.cc | 29 ++++++++++++----- src/shared_array_buffer.rs | 64 ++++++++++++++++++++++++-------------- tests/test_api.rs | 24 ++++++++++++++ 4 files changed, 126 insertions(+), 31 deletions(-) diff --git a/src/array_buffer.rs b/src/array_buffer.rs index c5b2de5e..98d4ab0c 100644 --- a/src/array_buffer.rs +++ b/src/array_buffer.rs @@ -29,6 +29,12 @@ extern "C" { isolate: *mut Isolate, byte_length: usize, ) -> *mut BackingStore; + fn v8__ArrayBuffer__NewBackingStore_FromRaw( + data: *mut std::ffi::c_void, + byte_length: usize, + deleter: BackingStoreDeleterCallback, + ) -> SharedRef; + fn v8__BackingStore__Data(self_: &mut BackingStore) -> *mut std::ffi::c_void; fn v8__BackingStore__ByteLength(self_: &BackingStore) -> usize; fn v8__BackingStore__IsShared(self_: &BackingStore) -> bool; @@ -85,6 +91,21 @@ impl Delete for Allocator { } } +pub type BackingStoreDeleterCallback = unsafe extern "C" fn( + data: *mut std::ffi::c_void, + byte_length: usize, + deleter_data: *mut std::ffi::c_void, +); + +pub unsafe extern "C" fn backing_store_deleter_callback( + data: *mut std::ffi::c_void, + _byte_length: usize, + _deleter_data: *mut std::ffi::c_void, +) { + let b = Box::from_raw(data); + drop(b) +} + /// A wrapper around the backing store (i.e. the raw memory) of an array buffer. /// See a document linked in http://crbug.com/v8/9908 for more information. /// @@ -201,4 +222,23 @@ impl ArrayBuffer { )) } } + + /// Returns a new standalone BackingStore that takes over the ownership of + /// the given buffer. + /// + /// The destructor of the BackingStore frees owned buffer memory. + /// + /// The result can be later passed to ArrayBuffer::New. The raw pointer + /// to the buffer must not be passed again to any V8 API function. + pub unsafe fn new_backing_store_from_boxed_slice( + data: Box<[u8]>, + ) -> SharedRef { + let byte_length = data.len(); + let data_ptr = Box::into_raw(data) as *mut std::ffi::c_void; + v8__ArrayBuffer__NewBackingStore_FromRaw( + data_ptr, + byte_length, + backing_store_deleter_callback, + ) + } } diff --git a/src/binding.cc b/src/binding.cc index 2d9f6bb8..2ce078c7 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -568,6 +568,14 @@ v8::BackingStore* v8__ArrayBuffer__NewBackingStore(v8::Isolate* isolate, return u.release(); } +two_pointers_t v8__ArrayBuffer__NewBackingStore_FromRaw( + void* data, size_t length, v8::BackingStoreDeleterCallback deleter) { + std::unique_ptr u = + v8::ArrayBuffer::NewBackingStore(data, length, deleter, nullptr); + const std::shared_ptr bs = std::move(u); + return make_pod(bs); +} + two_pointers_t v8__ArrayBuffer__GetBackingStore(v8::ArrayBuffer& self) { return make_pod(self.GetBackingStore()); } @@ -1047,14 +1055,6 @@ v8::SharedArrayBuffer* v8__SharedArrayBuffer__New(v8::Isolate* isolate, return local_to_ptr(v8::SharedArrayBuffer::New(isolate, byte_length)); } -v8::SharedArrayBuffer* v8__SharedArrayBuffer__New__DEPRECATED( - v8::Isolate* isolate, void* data_ptr, size_t data_length) { - auto ab = - v8::SharedArrayBuffer::New(isolate, data_ptr, data_length, - v8::ArrayBufferCreationMode::kExternalized); - return local_to_ptr(ab); -} - size_t v8__SharedArrayBuffer__ByteLength(v8::SharedArrayBuffer& self) { return self.ByteLength(); } @@ -1064,6 +1064,19 @@ two_pointers_t v8__SharedArrayBuffer__GetBackingStore( return make_pod(self.GetBackingStore()); } +two_pointers_t v8__SharedArrayBuffer__NewBackingStore_FromRaw( + void* data, size_t length, v8::BackingStoreDeleterCallback deleter) { + std::unique_ptr u = + v8::SharedArrayBuffer::NewBackingStore(data, length, deleter, nullptr); + const std::shared_ptr bs = std::move(u); + return make_pod(bs); +} + +v8::SharedArrayBuffer* v8__SharedArrayBuffer__New__backing_store( + v8::Isolate* isolate, std::shared_ptr& backing_store) { + return local_to_ptr(v8::SharedArrayBuffer::New(isolate, backing_store)); +} + v8::Value* v8__JSON__Parse(v8::Local context, v8::Local json_string) { return maybe_local_to_ptr(v8::JSON::Parse(context, json_string)); diff --git a/src/shared_array_buffer.rs b/src/shared_array_buffer.rs index a8ae6b12..dd370411 100644 --- a/src/shared_array_buffer.rs +++ b/src/shared_array_buffer.rs @@ -1,5 +1,7 @@ +use crate::array_buffer::backing_store_deleter_callback; use crate::support::SharedRef; use crate::BackingStore; +use crate::BackingStoreDeleterCallback; use crate::Isolate; use crate::Local; use crate::SharedArrayBuffer; @@ -21,6 +23,15 @@ extern "C" { fn v8__SharedArrayBuffer__GetBackingStore( self_: *const SharedArrayBuffer, ) -> SharedRef; + fn v8__SharedArrayBuffer__NewBackingStore_FromRaw( + data: *mut std::ffi::c_void, + byte_length: usize, + deleter: BackingStoreDeleterCallback, + ) -> SharedRef; + fn v8__SharedArrayBuffer__New__backing_store( + isolate: *mut Isolate, + backing_store: *mut SharedRef, + ) -> *mut SharedArrayBuffer; } impl SharedArrayBuffer { @@ -37,29 +48,6 @@ impl SharedArrayBuffer { } } - /// DEPRECATED - /// Use the version that takes a BackingStore. - /// See http://crbug.com/v8/9908. - /// - /// - /// Create a new SharedArrayBuffer over an existing memory block. The created - /// array buffer is immediately in externalized state unless otherwise - /// specified. The memory block will not be reclaimed when a created - /// SharedArrayBuffer is garbage-collected. - #[allow(non_snake_case)] - pub unsafe fn new_DEPRECATED<'sc>( - scope: &mut impl ToLocal<'sc>, - data_ptr: *mut std::ffi::c_void, - data_length: usize, - ) -> Local<'sc, SharedArrayBuffer> { - Local::from_raw(v8__SharedArrayBuffer__New__DEPRECATED( - scope.isolate(), - data_ptr, - data_length, - )) - .unwrap() - } - /// Data length in bytes. pub fn byte_length(&self) -> usize { unsafe { v8__SharedArrayBuffer__ByteLength(self) } @@ -72,4 +60,34 @@ impl SharedArrayBuffer { pub fn get_backing_store(&self) -> SharedRef { unsafe { v8__SharedArrayBuffer__GetBackingStore(self) } } + + pub fn new_with_backing_store<'sc>( + scope: &mut impl ToLocal<'sc>, + backing_store: &mut SharedRef, + ) -> Local<'sc, SharedArrayBuffer> { + let isolate = scope.isolate(); + let ptr = unsafe { + v8__SharedArrayBuffer__New__backing_store(isolate, &mut *backing_store) + }; + unsafe { scope.to_local(ptr) }.unwrap() + } + + /// Returns a new standalone BackingStore that takes over the ownership of + /// the given buffer. + /// + /// The destructor of the BackingStore frees owned buffer memory. + /// + /// The result can be later passed to SharedArrayBuffer::New. The raw pointer + /// to the buffer must not be passed again to any V8 API function. + pub unsafe fn new_backing_store_from_boxed_slice( + data: Box<[u8]>, + ) -> SharedRef { + let byte_length = data.len(); + let data_ptr = Box::into_raw(data) as *mut std::ffi::c_void; + v8__SharedArrayBuffer__NewBackingStore_FromRaw( + data_ptr, + byte_length, + backing_store_deleter_callback, + ) + } } diff --git a/tests/test_api.rs b/tests/test_api.rs index 0d692496..cacf5d5c 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -252,6 +252,17 @@ fn array_buffer() { assert_eq!(84, bs.byte_length()); assert_eq!(false, bs.is_shared()); + let data: Box<[u8]> = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9].into_boxed_slice(); + let mut bs = + unsafe { v8::ArrayBuffer::new_backing_store_from_boxed_slice(data) }; + assert_eq!(10, bs.byte_length()); + assert_eq!(false, bs.is_shared()); + let ab = v8::ArrayBuffer::new_with_backing_store(scope, &mut bs); + let mut bs = ab.get_backing_store(); + assert_eq!(10, ab.byte_length()); + let data = bs.data_bytes(); + assert_eq!(data[0], 0); + assert_eq!(data[9], 9); context.exit(); } } @@ -1758,6 +1769,19 @@ fn shared_array_buffer() { assert_eq!(result.value(), 64); assert_eq!(shared_buf[2], 16); assert_eq!(shared_buf[14], 62); + + let data: Box<[u8]> = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9].into_boxed_slice(); + let mut bs = unsafe { + v8::SharedArrayBuffer::new_backing_store_from_boxed_slice(data) + }; + assert_eq!(10, bs.byte_length()); + assert_eq!(true, bs.is_shared()); + let ab = v8::SharedArrayBuffer::new_with_backing_store(s, &mut bs); + let mut bs = ab.get_backing_store(); + assert_eq!(10, ab.byte_length()); + let data = bs.data_bytes(); + assert_eq!(data[0], 0); + assert_eq!(data[9], 9); context.exit(); } }