0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-11-21 15:04:33 -05:00

feat: v8::ArrayBuffer::new_backing_store_from_vec (#946)

So we can avoid `.into_boxed_slice()` calls which may require a (costly) memmove when instantiating from a Vec
This commit is contained in:
Aaron O'Mullan 2022-04-20 14:36:10 -03:00 committed by GitHub
parent 7a5d1cd10c
commit 7772779210
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 4 deletions

View file

@ -232,7 +232,7 @@ pub type BackingStoreDeleterCallback = unsafe extern "C" fn(
deleter_data: *mut c_void,
);
pub unsafe extern "C" fn backing_store_deleter_callback(
pub unsafe extern "C" fn boxed_slice_deleter_callback(
data: *mut c_void,
byte_length: usize,
_deleter_data: *mut c_void,
@ -242,6 +242,15 @@ pub unsafe extern "C" fn backing_store_deleter_callback(
drop(b);
}
pub unsafe extern "C" fn vec_deleter_callback(
data: *mut c_void,
byte_length: usize,
deleter_data: *mut c_void,
) {
let capacity = deleter_data as usize;
drop(Vec::from_raw_parts(data as *mut u8, byte_length, capacity))
}
/// 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.
///
@ -425,12 +434,36 @@ impl ArrayBuffer {
UniqueRef::from_raw(v8__ArrayBuffer__NewBackingStore__with_data(
data_ptr,
byte_length,
backing_store_deleter_callback,
boxed_slice_deleter_callback,
null_mut(),
))
}
}
/// 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 fn new_backing_store_from_vec(
mut data: Vec<u8>,
) -> UniqueRef<BackingStore> {
let byte_length = data.len();
let capacity = data.capacity();
let data_ptr = data.as_mut_ptr() as *mut c_void;
std::mem::forget(data);
unsafe {
UniqueRef::from_raw(v8__ArrayBuffer__NewBackingStore__with_data(
data_ptr,
byte_length,
vec_deleter_callback,
capacity as *mut c_void,
))
}
}
/// Returns a new standalone BackingStore backed by given ptr.
///
/// SAFETY: This API consumes raw pointers so is inherently

View file

@ -3,7 +3,8 @@
use std::ffi::c_void;
use std::ptr::null_mut;
use crate::array_buffer::backing_store_deleter_callback;
use crate::array_buffer::boxed_slice_deleter_callback;
use crate::array_buffer::vec_deleter_callback;
use crate::support::SharedRef;
use crate::support::UniqueRef;
use crate::BackingStore;
@ -123,7 +124,30 @@ impl SharedArrayBuffer {
UniqueRef::from_raw(v8__SharedArrayBuffer__NewBackingStore__with_data(
data_ptr,
byte_length,
backing_store_deleter_callback,
boxed_slice_deleter_callback,
null_mut(),
))
}
}
/// 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 fn new_backing_store_from_vec(
mut data: Vec<u8>,
) -> UniqueRef<BackingStore> {
let byte_length = data.len();
let data_ptr = data.as_mut_ptr() as *mut c_void;
std::mem::forget(data);
unsafe {
UniqueRef::from_raw(v8__SharedArrayBuffer__NewBackingStore__with_data(
data_ptr,
byte_length,
vec_deleter_callback,
null_mut(),
))
}

View file

@ -570,6 +570,7 @@ fn array_buffer() {
assert_eq!(unique_bs[0].get(), 0);
assert_eq!(unique_bs[9].get(), 9);
// From Box<[u8]>
let data: Box<[u8]> = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9].into_boxed_slice();
let unique_bs = v8::ArrayBuffer::new_backing_store_from_boxed_slice(data);
assert_eq!(10, unique_bs.byte_length());
@ -588,6 +589,26 @@ fn array_buffer() {
assert_eq!(10, shared_bs_2.byte_length());
assert_eq!(shared_bs_2[0].get(), 0);
assert_eq!(shared_bs_2[9].get(), 9);
// From Vec<u8>
let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let unique_bs = v8::ArrayBuffer::new_backing_store_from_vec(data);
assert_eq!(10, unique_bs.byte_length());
assert!(!unique_bs.is_shared());
assert_eq!(unique_bs[0].get(), 0);
assert_eq!(unique_bs[9].get(), 9);
let shared_bs_1 = unique_bs.make_shared();
assert_eq!(10, shared_bs_1.byte_length());
assert!(!shared_bs_1.is_shared());
assert_eq!(shared_bs_1[0].get(), 0);
assert_eq!(shared_bs_1[9].get(), 9);
let ab = v8::ArrayBuffer::with_backing_store(scope, &shared_bs_1);
let shared_bs_2 = ab.get_backing_store();
assert_eq!(10, shared_bs_2.byte_length());
assert_eq!(shared_bs_2[0].get(), 0);
assert_eq!(shared_bs_2[9].get(), 9);
}
}
@ -6078,6 +6099,20 @@ fn backing_store_from_empty_boxed_slice() {
let _ = v8::ArrayBuffer::with_backing_store(&mut scope, &store);
}
#[test]
fn backing_store_from_empty_vec() {
let _setup_guard = setup();
let mut isolate = v8::Isolate::new(Default::default());
let mut scope = v8::HandleScope::new(&mut isolate);
let context = v8::Context::new(&mut scope);
let mut scope = v8::ContextScope::new(&mut scope, context);
let store =
v8::ArrayBuffer::new_backing_store_from_vec(Vec::new()).make_shared();
let _ = v8::ArrayBuffer::with_backing_store(&mut scope, &store);
}
#[test]
fn current_stack_trace() {
// Setup isolate