mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-11-21 20:28:58 +00:00
feat: new_backing_store_from_bytes and empty for ArrayBuffer and SharedArrayBuffer (#1334)
This commit is contained in:
parent
12dca0cf03
commit
bf277f4f8e
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -127,6 +127,12 @@ version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
|
||||
[[package]]
|
||||
name = "calloop"
|
||||
version = "0.9.3"
|
||||
@ -1315,6 +1321,7 @@ version = "0.78.0"
|
||||
dependencies = [
|
||||
"align-data",
|
||||
"bitflags 1.3.2",
|
||||
"bytes",
|
||||
"fslock",
|
||||
"once_cell",
|
||||
"trybuild",
|
||||
|
@ -88,6 +88,7 @@ fslock = "0.1.8"
|
||||
which = "4.2.5"
|
||||
|
||||
[dev-dependencies]
|
||||
bytes = "1"
|
||||
align-data = "0.1.0"
|
||||
fslock = "0.1.8"
|
||||
trybuild = "1.0.61"
|
||||
|
@ -5,7 +5,6 @@ use std::ffi::c_void;
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
use std::ptr::null;
|
||||
use std::ptr::null_mut;
|
||||
use std::ptr::NonNull;
|
||||
use std::slice;
|
||||
|
||||
@ -60,6 +59,7 @@ extern "C" {
|
||||
deleter: BackingStoreDeleterCallback,
|
||||
deleter_data: *mut c_void,
|
||||
) -> *mut BackingStore;
|
||||
fn v8__BackingStore__EmptyBackingStore(shared: bool) -> *mut BackingStore;
|
||||
|
||||
fn v8__BackingStore__Data(this: *const BackingStore) -> *mut c_void;
|
||||
fn v8__BackingStore__ByteLength(this: *const BackingStore) -> usize;
|
||||
@ -246,25 +246,50 @@ pub type BackingStoreDeleterCallback = unsafe extern "C" fn(
|
||||
deleter_data: *mut c_void,
|
||||
);
|
||||
|
||||
pub unsafe extern "C" fn boxed_slice_deleter_callback(
|
||||
data: *mut c_void,
|
||||
byte_length: usize,
|
||||
_deleter_data: *mut c_void,
|
||||
) {
|
||||
let slice_ptr = ptr::slice_from_raw_parts_mut(data as *mut u8, byte_length);
|
||||
let b = Box::from_raw(slice_ptr);
|
||||
drop(b);
|
||||
pub(crate) mod sealed {
|
||||
pub trait Rawable<T: ?Sized> {
|
||||
fn into_raw(self) -> *const ();
|
||||
unsafe fn drop_raw(ptr: *const (), size: usize);
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
impl sealed::Rawable<[u8]> for Vec<u8> {
|
||||
unsafe fn drop_raw(ptr: *const (), size: usize) {
|
||||
<Box<[u8]> as sealed::Rawable<[u8]>>::drop_raw(ptr, size);
|
||||
}
|
||||
|
||||
fn into_raw(self) -> *const () {
|
||||
self.into_boxed_slice().into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! rawable {
|
||||
($container:ident) => {
|
||||
impl<T: Sized> sealed::Rawable<T> for $container<T> {
|
||||
fn into_raw(self) -> *const () {
|
||||
Self::into_raw(self) as _
|
||||
}
|
||||
|
||||
unsafe fn drop_raw(ptr: *const (), _len: usize) {
|
||||
_ = Self::from_raw(ptr as _);
|
||||
}
|
||||
}
|
||||
|
||||
impl sealed::Rawable<[u8]> for $container<[u8]> {
|
||||
fn into_raw(self) -> *const () {
|
||||
Self::into_raw(self) as _
|
||||
}
|
||||
|
||||
unsafe fn drop_raw(ptr: *const (), len: usize) {
|
||||
_ = Self::from_raw(ptr::slice_from_raw_parts_mut(ptr as _, len));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Implement Rawable for single-ownership container types
|
||||
rawable!(Box);
|
||||
|
||||
/// 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.
|
||||
///
|
||||
@ -396,6 +421,16 @@ impl ArrayBuffer {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Create a new, empty ArrayBuffer.
|
||||
#[inline(always)]
|
||||
pub fn empty<'s>(scope: &mut HandleScope<'s>) -> Local<'s, ArrayBuffer> {
|
||||
// SAFETY: This is a v8-provided empty backing store
|
||||
let backing_store = unsafe {
|
||||
UniqueRef::from_raw(v8__BackingStore__EmptyBackingStore(false))
|
||||
};
|
||||
Self::with_backing_store(scope, &backing_store.make_shared())
|
||||
}
|
||||
|
||||
/// Data length in bytes.
|
||||
#[inline(always)]
|
||||
pub fn byte_length(&self) -> usize {
|
||||
@ -489,16 +524,7 @@ impl ArrayBuffer {
|
||||
pub fn new_backing_store_from_boxed_slice(
|
||||
data: Box<[u8]>,
|
||||
) -> UniqueRef<BackingStore> {
|
||||
let byte_length = data.len();
|
||||
let data_ptr = Box::into_raw(data) as *mut c_void;
|
||||
unsafe {
|
||||
UniqueRef::from_raw(v8__ArrayBuffer__NewBackingStore__with_data(
|
||||
data_ptr,
|
||||
byte_length,
|
||||
boxed_slice_deleter_callback,
|
||||
null_mut(),
|
||||
))
|
||||
}
|
||||
Self::new_backing_store_from_bytes(data)
|
||||
}
|
||||
|
||||
/// Returns a new standalone BackingStore that takes over the ownership of
|
||||
@ -509,20 +535,59 @@ impl ArrayBuffer {
|
||||
/// 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.
|
||||
#[inline(always)]
|
||||
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);
|
||||
pub fn new_backing_store_from_vec(data: Vec<u8>) -> UniqueRef<BackingStore> {
|
||||
Self::new_backing_store_from_bytes(data)
|
||||
}
|
||||
|
||||
/// Returns a new standalone BackingStore backed by a container that dereferences
|
||||
/// to a mutable slice of bytes. The object is dereferenced once, and the resulting slice's
|
||||
/// memory is used for the lifetime of the buffer.
|
||||
///
|
||||
/// This method may be called with most single-ownership containers that implement `AsMut<[u8]>`, including
|
||||
/// `Box<[u8]>`, and `Vec<u8>`. This will also support most other mutable bytes containers (including `bytes::BytesMut`),
|
||||
/// though these buffers will need to be boxed to manage ownership of memory.
|
||||
///
|
||||
/// ```
|
||||
/// // Vector of bytes
|
||||
/// let backing_store = v8::ArrayBuffer::new_backing_store_from_bytes(vec![1, 2, 3]);
|
||||
/// // Boxes slice of bytes
|
||||
/// let boxed_slice: Box<[u8]> = vec![1, 2, 3].into_boxed_slice();
|
||||
/// let backing_store = v8::ArrayBuffer::new_backing_store_from_bytes(boxed_slice);
|
||||
/// // BytesMut from bytes crate
|
||||
/// let backing_store = v8::ArrayBuffer::new_backing_store_from_bytes(Box::new(bytes::BytesMut::new()));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn new_backing_store_from_bytes<T, U>(
|
||||
mut bytes: T,
|
||||
) -> UniqueRef<BackingStore>
|
||||
where
|
||||
U: ?Sized,
|
||||
U: AsMut<[u8]>,
|
||||
T: AsMut<U>,
|
||||
T: sealed::Rawable<U>,
|
||||
{
|
||||
let len = bytes.as_mut().as_mut().len();
|
||||
let slice = bytes.as_mut().as_mut().as_mut_ptr();
|
||||
let ptr = T::into_raw(bytes);
|
||||
|
||||
extern "C" fn drop_rawable<T: sealed::Rawable<U>, U: ?Sized>(
|
||||
_ptr: *mut c_void,
|
||||
len: usize,
|
||||
data: *mut c_void,
|
||||
) {
|
||||
// SAFETY: We know that data is a raw T from above
|
||||
unsafe { <T as sealed::Rawable<U>>::drop_raw(data as _, len) }
|
||||
}
|
||||
|
||||
// SAFETY: We are extending the lifetime of a slice, but we're locking away the box that we
|
||||
// derefed from so there's no way to get another mutable reference.
|
||||
unsafe {
|
||||
UniqueRef::from_raw(v8__ArrayBuffer__NewBackingStore__with_data(
|
||||
data_ptr,
|
||||
byte_length,
|
||||
vec_deleter_callback,
|
||||
capacity as *mut c_void,
|
||||
))
|
||||
Self::new_backing_store_from_ptr(
|
||||
slice as _,
|
||||
len,
|
||||
drop_rawable::<T, U>,
|
||||
ptr as _,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -866,6 +866,12 @@ two_pointers_t v8__ArrayBuffer__GetBackingStore(const v8::ArrayBuffer& self) {
|
||||
return make_pod<two_pointers_t>(ptr_to_local(&self)->GetBackingStore());
|
||||
}
|
||||
|
||||
v8::BackingStore* v8__BackingStore__EmptyBackingStore(bool shared) {
|
||||
std::unique_ptr<i::BackingStoreBase> u =
|
||||
i::BackingStore::EmptyBackingStore(shared ? i::SharedFlag::kShared : i::SharedFlag::kNotShared);
|
||||
return static_cast<v8::BackingStore*>(u.release());
|
||||
}
|
||||
|
||||
bool v8__BackingStore__IsResizableByUserJavaScript(
|
||||
const v8::BackingStore& self) {
|
||||
return ptr_to_local(&self)->IsResizableByUserJavaScript();
|
||||
|
@ -1,10 +1,7 @@
|
||||
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::ffi::c_void;
|
||||
use std::ptr::null_mut;
|
||||
|
||||
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;
|
||||
@ -38,6 +35,7 @@ extern "C" {
|
||||
deleter: BackingStoreDeleterCallback,
|
||||
deleter_data: *mut c_void,
|
||||
) -> *mut BackingStore;
|
||||
fn v8__BackingStore__EmptyBackingStore(shared: bool) -> *mut BackingStore;
|
||||
}
|
||||
|
||||
impl SharedArrayBuffer {
|
||||
@ -76,6 +74,17 @@ impl SharedArrayBuffer {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Create a new, empty SharedArrayBuffer.
|
||||
#[inline(always)]
|
||||
pub fn empty<'s>(
|
||||
scope: &mut HandleScope<'s>,
|
||||
) -> Local<'s, SharedArrayBuffer> {
|
||||
// SAFETY: This is a v8-provided empty backing store
|
||||
let backing_store =
|
||||
unsafe { UniqueRef::from_raw(v8__BackingStore__EmptyBackingStore(true)) };
|
||||
Self::with_backing_store(scope, &backing_store.make_shared())
|
||||
}
|
||||
|
||||
/// Data length in bytes.
|
||||
#[inline(always)]
|
||||
pub fn byte_length(&self) -> usize {
|
||||
@ -124,16 +133,7 @@ impl SharedArrayBuffer {
|
||||
pub fn new_backing_store_from_boxed_slice(
|
||||
data: Box<[u8]>,
|
||||
) -> UniqueRef<BackingStore> {
|
||||
let byte_length = data.len();
|
||||
let data_ptr = Box::into_raw(data) as *mut c_void;
|
||||
unsafe {
|
||||
UniqueRef::from_raw(v8__SharedArrayBuffer__NewBackingStore__with_data(
|
||||
data_ptr,
|
||||
byte_length,
|
||||
boxed_slice_deleter_callback,
|
||||
null_mut(),
|
||||
))
|
||||
}
|
||||
Self::new_backing_store_from_bytes(data)
|
||||
}
|
||||
|
||||
/// Returns a new standalone BackingStore that takes over the ownership of
|
||||
@ -144,19 +144,83 @@ impl SharedArrayBuffer {
|
||||
/// 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.
|
||||
#[inline(always)]
|
||||
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);
|
||||
pub fn new_backing_store_from_vec(data: Vec<u8>) -> UniqueRef<BackingStore> {
|
||||
Self::new_backing_store_from_bytes(data)
|
||||
}
|
||||
|
||||
/// Returns a new standalone BackingStore backed by a container that dereferences
|
||||
/// to a mutable slice of bytes. The object is dereferenced once, and the resulting slice's
|
||||
/// memory is used for the lifetime of the buffer.
|
||||
///
|
||||
/// This method may be called with most single-ownership containers that implement `AsMut<[u8]>`, including
|
||||
/// `Box<[u8]>`, and `Vec<u8>`. This will also support most other mutable bytes containers (including `bytes::BytesMut`),
|
||||
/// though these buffers will need to be boxed to manage ownership of memory.
|
||||
///
|
||||
/// ```
|
||||
/// // Vector of bytes
|
||||
/// let backing_store = v8::ArrayBuffer::new_backing_store_from_bytes(vec![1, 2, 3]);
|
||||
/// // Boxes slice of bytes
|
||||
/// let boxed_slice: Box<[u8]> = vec![1, 2, 3].into_boxed_slice();
|
||||
/// let backing_store = v8::ArrayBuffer::new_backing_store_from_bytes(boxed_slice);
|
||||
/// // BytesMut from bytes crate
|
||||
/// let backing_store = v8::ArrayBuffer::new_backing_store_from_bytes(Box::new(bytes::BytesMut::new()));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn new_backing_store_from_bytes<T, U>(
|
||||
mut bytes: T,
|
||||
) -> UniqueRef<BackingStore>
|
||||
where
|
||||
U: ?Sized,
|
||||
U: AsMut<[u8]>,
|
||||
T: AsMut<U>,
|
||||
T: crate::array_buffer::sealed::Rawable<U>,
|
||||
{
|
||||
let len = bytes.as_mut().as_mut().len();
|
||||
let slice = bytes.as_mut().as_mut().as_mut_ptr();
|
||||
let ptr = T::into_raw(bytes);
|
||||
|
||||
extern "C" fn drop_rawable<
|
||||
T: crate::array_buffer::sealed::Rawable<U>,
|
||||
U: ?Sized,
|
||||
>(
|
||||
_ptr: *mut c_void,
|
||||
len: usize,
|
||||
data: *mut c_void,
|
||||
) {
|
||||
// SAFETY: We know that data is a raw T from above
|
||||
unsafe {
|
||||
<T as crate::array_buffer::sealed::Rawable<U>>::drop_raw(data as _, len)
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: We are extending the lifetime of a slice, but we're locking away the box that we
|
||||
// derefed from so there's no way to get another mutable reference.
|
||||
unsafe {
|
||||
UniqueRef::from_raw(v8__SharedArrayBuffer__NewBackingStore__with_data(
|
||||
data_ptr,
|
||||
byte_length,
|
||||
vec_deleter_callback,
|
||||
null_mut(),
|
||||
))
|
||||
Self::new_backing_store_from_ptr(
|
||||
slice as _,
|
||||
len,
|
||||
drop_rawable::<T, U>,
|
||||
ptr as _,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a new standalone shared BackingStore backed by given ptr.
|
||||
///
|
||||
/// SAFETY: This API consumes raw pointers so is inherently
|
||||
/// unsafe. Usually you should use new_backing_store_from_boxed_slice.
|
||||
#[inline(always)]
|
||||
pub unsafe fn new_backing_store_from_ptr(
|
||||
data_ptr: *mut c_void,
|
||||
byte_length: usize,
|
||||
deleter_callback: BackingStoreDeleterCallback,
|
||||
deleter_data: *mut c_void,
|
||||
) -> UniqueRef<BackingStore> {
|
||||
UniqueRef::from_raw(v8__SharedArrayBuffer__NewBackingStore__with_data(
|
||||
data_ptr,
|
||||
byte_length,
|
||||
deleter_callback,
|
||||
deleter_data,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -828,6 +828,24 @@ 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);
|
||||
|
||||
// Empty
|
||||
let ab = v8::ArrayBuffer::empty(scope);
|
||||
assert_eq!(0, ab.byte_length());
|
||||
assert!(!ab.get_backing_store().is_shared());
|
||||
|
||||
// From a bytes::BytesMut
|
||||
let mut data = bytes::BytesMut::new();
|
||||
data.extend_from_slice(&[0; 16]);
|
||||
data[0] = 1;
|
||||
let unique_bs =
|
||||
v8::ArrayBuffer::new_backing_store_from_bytes(Box::new(data));
|
||||
assert_eq!(unique_bs.get(0).unwrap().get(), 1);
|
||||
|
||||
let ab =
|
||||
v8::ArrayBuffer::with_backing_store(scope, &unique_bs.make_shared());
|
||||
assert_eq!(ab.byte_length(), 16);
|
||||
assert_eq!(ab.get_backing_store().get(0).unwrap().get(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5607,6 +5625,11 @@ fn shared_array_buffer() {
|
||||
assert_eq!(shared_bs_3.byte_length(), 10);
|
||||
assert_eq!(shared_bs_3[0].get(), 0);
|
||||
assert_eq!(shared_bs_3[9].get(), 9);
|
||||
|
||||
// Empty
|
||||
let ab = v8::SharedArrayBuffer::empty(scope);
|
||||
assert_eq!(ab.byte_length(), 0);
|
||||
assert!(ab.get_backing_store().is_shared());
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user