0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-12-26 00:59:28 -05:00

Add ArrayBuffer::get_backing_store() and new_with_backing_store() (#135)

This commit is contained in:
Bert Belder 2019-12-26 03:32:22 +01:00
parent a2196a7248
commit 76a480e6ff
No known key found for this signature in database
GPG key ID: 7A77887B2E2ED461
6 changed files with 237 additions and 12 deletions

View file

@ -1,6 +1,10 @@
use crate::support::long;
use crate::support::Delete; use crate::support::Delete;
use crate::support::Opaque; use crate::support::Opaque;
use crate::support::Shared;
use crate::support::SharedRef;
use crate::support::UniqueRef; use crate::support::UniqueRef;
use crate::InIsolate;
use crate::Isolate; use crate::Isolate;
use crate::Local; use crate::Local;
use crate::ToLocal; use crate::ToLocal;
@ -8,13 +12,18 @@ use crate::ToLocal;
extern "C" { extern "C" {
fn v8__ArrayBuffer__Allocator__NewDefaultAllocator() -> *mut Allocator; fn v8__ArrayBuffer__Allocator__NewDefaultAllocator() -> *mut Allocator;
fn v8__ArrayBuffer__Allocator__DELETE(this: &'static mut Allocator); fn v8__ArrayBuffer__Allocator__DELETE(this: &'static mut Allocator);
fn v8__ArrayBuffer__New__byte_length(
fn v8__ArrayBuffer__New(
isolate: *mut Isolate, isolate: *mut Isolate,
byte_length: usize, byte_length: usize,
) -> *mut ArrayBuffer; ) -> *mut ArrayBuffer;
fn v8__ArrayBuffer__New__backing_store(
isolate: *mut Isolate,
backing_store: *mut SharedRef<BackingStore>,
) -> *mut ArrayBuffer;
fn v8__ArrayBuffer__ByteLength(self_: *const ArrayBuffer) -> usize; fn v8__ArrayBuffer__ByteLength(self_: *const ArrayBuffer) -> usize;
fn v8__ArrayBuffer__GetBackingStore(
self_: *const ArrayBuffer,
) -> SharedRef<BackingStore>;
fn v8__ArrayBuffer__NewBackingStore( fn v8__ArrayBuffer__NewBackingStore(
isolate: *mut Isolate, isolate: *mut Isolate,
byte_length: usize, byte_length: usize,
@ -22,6 +31,15 @@ extern "C" {
fn v8__BackingStore__ByteLength(self_: &BackingStore) -> usize; fn v8__BackingStore__ByteLength(self_: &BackingStore) -> usize;
fn v8__BackingStore__IsShared(self_: &BackingStore) -> bool; fn v8__BackingStore__IsShared(self_: &BackingStore) -> bool;
fn v8__BackingStore__DELETE(self_: &mut BackingStore); fn v8__BackingStore__DELETE(self_: &mut BackingStore);
fn std__shared_ptr__v8__BackingStore__get(
ptr: *const SharedRef<BackingStore>,
) -> *mut BackingStore;
fn std__shared_ptr__v8__BackingStore__reset(
ptr: *mut SharedRef<BackingStore>,
);
fn std__shared_ptr__v8__BackingStore__use_count(
ptr: *const SharedRef<BackingStore>,
) -> long;
} }
/// A thread-safe allocator that V8 uses to allocate |ArrayBuffer|'s memory. /// A thread-safe allocator that V8 uses to allocate |ArrayBuffer|'s memory.
@ -105,6 +123,18 @@ impl Delete for BackingStore {
} }
} }
impl Shared for BackingStore {
fn deref(ptr: *const SharedRef<Self>) -> *mut Self {
unsafe { std__shared_ptr__v8__BackingStore__get(ptr) }
}
fn reset(ptr: *mut SharedRef<Self>) {
unsafe { std__shared_ptr__v8__BackingStore__reset(ptr) }
}
fn use_count(ptr: *const SharedRef<Self>) -> long {
unsafe { std__shared_ptr__v8__BackingStore__use_count(ptr) }
}
}
/// An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5). /// An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5).
#[repr(C)] #[repr(C)]
pub struct ArrayBuffer(Opaque); pub struct ArrayBuffer(Opaque);
@ -119,7 +149,19 @@ impl ArrayBuffer {
byte_length: usize, byte_length: usize,
) -> Local<'sc, ArrayBuffer> { ) -> Local<'sc, ArrayBuffer> {
let isolate = scope.isolate(); let isolate = scope.isolate();
let ptr = unsafe { v8__ArrayBuffer__New(isolate, byte_length) }; let ptr =
unsafe { v8__ArrayBuffer__New__byte_length(isolate, byte_length) };
unsafe { scope.to_local(ptr) }.unwrap()
}
pub fn new_with_backing_store<'sc>(
scope: &mut impl ToLocal<'sc>,
backing_store: &mut SharedRef<BackingStore>,
) -> Local<'sc, ArrayBuffer> {
let isolate = scope.isolate();
let ptr = unsafe {
v8__ArrayBuffer__New__backing_store(isolate, &mut *backing_store)
};
unsafe { scope.to_local(ptr) }.unwrap() unsafe { scope.to_local(ptr) }.unwrap()
} }
@ -127,6 +169,9 @@ impl ArrayBuffer {
pub fn byte_length(&self) -> usize { pub fn byte_length(&self) -> usize {
unsafe { v8__ArrayBuffer__ByteLength(self) } unsafe { v8__ArrayBuffer__ByteLength(self) }
} }
pub fn get_backing_store(&self) -> SharedRef<BackingStore> {
unsafe { v8__ArrayBuffer__GetBackingStore(self) }
}
/// Returns a new standalone BackingStore that is allocated using the array /// Returns a new standalone BackingStore that is allocated using the array
/// buffer allocator of the isolate. The result can be later passed to /// buffer allocator of the isolate. The result can be later passed to
@ -135,8 +180,8 @@ impl ArrayBuffer {
/// If the allocator returns nullptr, then the function may cause GCs in the /// If the allocator returns nullptr, then the function may cause GCs in the
/// given isolate and re-try the allocation. If GCs do not help, then the /// given isolate and re-try the allocation. If GCs do not help, then the
/// function will crash with an out-of-memory error. /// function will crash with an out-of-memory error.
pub fn new_backing_store<'sc>( pub fn new_backing_store(
scope: &mut impl ToLocal<'sc>, scope: &mut impl InIsolate,
byte_length: usize, byte_length: usize,
) -> UniqueRef<BackingStore> { ) -> UniqueRef<BackingStore> {
unsafe { unsafe {

View file

@ -70,7 +70,6 @@ v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallback(
} }
extern "C" { extern "C" {
void v8__V8__SetFlagsFromCommandLine(int* argc, char** argv) { void v8__V8__SetFlagsFromCommandLine(int* argc, char** argv) {
v8::V8::SetFlagsFromCommandLine(argc, argv, true); v8::V8::SetFlagsFromCommandLine(argc, argv, true);
} }
@ -325,6 +324,10 @@ v8::BackingStore* v8__ArrayBuffer__NewBackingStore(v8::Isolate* isolate,
return u.release(); return u.release();
} }
two_pointers_t v8__ArrayBuffer__GetBackingStore(v8::ArrayBuffer& self) {
return make_pod<two_pointers_t>(self.GetBackingStore());
}
size_t v8__BackingStore__ByteLength(v8::BackingStore& self) { size_t v8__BackingStore__ByteLength(v8::BackingStore& self) {
return self.ByteLength(); return self.ByteLength();
} }
@ -335,6 +338,21 @@ bool v8__BackingStore__IsShared(v8::BackingStore& self) {
void v8__BackingStore__DELETE(v8::BackingStore& self) { delete &self; } void v8__BackingStore__DELETE(v8::BackingStore& self) { delete &self; }
v8::BackingStore* std__shared_ptr__v8__BackingStore__get(
const std::shared_ptr<v8::BackingStore>& ptr) {
return ptr.get();
}
void std__shared_ptr__v8__BackingStore__reset(
std::shared_ptr<v8::BackingStore>& ptr) {
ptr.reset();
}
long std__shared_ptr__v8__BackingStore__use_count(
const std::shared_ptr<v8::BackingStore>& ptr) {
return ptr.use_count();
}
v8::String* v8__String__NewFromUtf8(v8::Isolate* isolate, const char* data, v8::String* v8__String__NewFromUtf8(v8::Isolate* isolate, const char* data,
v8::NewStringType type, int length) { v8::NewStringType type, int length) {
return maybe_local_to_ptr( return maybe_local_to_ptr(
@ -419,11 +437,16 @@ void v8__ArrayBuffer__Allocator__DELETE(v8::ArrayBuffer::Allocator& self) {
delete &self; delete &self;
} }
v8::ArrayBuffer* v8__ArrayBuffer__New(v8::Isolate* isolate, v8::ArrayBuffer* v8__ArrayBuffer__New__byte_length(v8::Isolate* isolate,
size_t byte_length) { size_t byte_length) {
return local_to_ptr(v8::ArrayBuffer::New(isolate, byte_length)); return local_to_ptr(v8::ArrayBuffer::New(isolate, byte_length));
} }
v8::ArrayBuffer* v8__ArrayBuffer__New__backing_store(
v8::Isolate* isolate, std::shared_ptr<v8::BackingStore>& backing_store) {
return local_to_ptr(v8::ArrayBuffer::New(isolate, backing_store));
}
size_t v8__ArrayBuffer__ByteLength(v8::ArrayBuffer& self) { size_t v8__ArrayBuffer__ByteLength(v8::ArrayBuffer& self) {
return self.ByteLength(); return self.ByteLength();
} }

View file

@ -74,6 +74,7 @@ pub use snapshot::{FunctionCodeHandling, SnapshotCreator, StartupData};
pub use string::NewStringType; pub use string::NewStringType;
pub use string::String; pub use string::String;
pub use support::MaybeBool; pub use support::MaybeBool;
pub use support::SharedRef;
pub use support::UniqueRef; pub use support::UniqueRef;
pub use try_catch::{TryCatch, TryCatchScope}; pub use try_catch::{TryCatch, TryCatchScope};
pub use uint8_array::Uint8Array; pub use uint8_array::Uint8Array;

View file

@ -2,6 +2,7 @@
#define SUPPORT_H_ #define SUPPORT_H_
#include <algorithm> #include <algorithm>
#include <array>
#include <cassert> #include <cassert>
#include <memory> #include <memory>
#include <new> #include <new>
@ -11,9 +12,8 @@
#include "v8/include/v8.h" #include "v8/include/v8.h"
// Check assumptions made in binding code. // Check assumptions made in binding code.
// TODO(ry) re-enable the following static_assert(sizeof(bool) == sizeof(uint8_t), "");
// static_assert(sizeof(bool) == sizeof(uint8_t)); static_assert(sizeof(std::unique_ptr<void>) == sizeof(void*), "");
// static_assert(sizeof(std::unique_ptr<void>) == sizeof(void*));
namespace support { namespace support {
template <class T> template <class T>
@ -35,6 +35,44 @@ void construct_in_place(uninit_t<T>& buf, Args... args) {
construct_in_place_helper<T, Args...>(buf, std::forward<Args>(args)...); construct_in_place_helper<T, Args...>(buf, std::forward<Args>(args)...);
} }
template <class P>
struct make_pod {
template <class V>
inline make_pod(V&& value) : pod_(helper<V>(value)) {}
template <class V>
inline make_pod(const V& value) : pod_(helper<V>(value)) {}
inline operator P() { return pod_; }
private:
P pod_;
template <class V>
union helper {
static_assert(std::is_pod<P>::value, "type P must a pod type");
static_assert(sizeof(V) <= sizeof(P),
"type P must be at least as big as type V");
static_assert(alignof(V) <= alignof(P),
"alignment of type P must be compatible with that of type V");
inline helper(V&& value) : value_(value), padding_() {}
inline helper(const V& value) : value_(value), padding_() {}
inline ~helper() {}
inline operator P() {
// Do a memcpy here avoid undefined behavior.
P result;
memcpy(&result, this, sizeof result);
return result;
}
private:
struct {
V value_;
char padding_[sizeof(P) - sizeof(V)];
};
};
};
// The C-ABI compatible equivalent of V8's Maybe<bool>. // The C-ABI compatible equivalent of V8's Maybe<bool>.
enum class MaybeBool { JustFalse = 0, JustTrue = 1, Nothing = 2 }; enum class MaybeBool { JustFalse = 0, JustTrue = 1, Nothing = 2 };
@ -87,6 +125,13 @@ inline static v8::Global<T> ptr_to_global(T* ptr) {
return global; return global;
} }
// Because, for some reason, Clang complains that `std::aray<void*, 2` is an
// incomplete type, incompatible with C linkage.
struct two_pointers_t {
void* a;
void* b;
};
} // namespace support } // namespace support
#endif // SUPPORT_H_ #endif // SUPPORT_H_

View file

@ -8,6 +8,7 @@ use std::ptr::NonNull;
pub use std::os::raw::c_char as char; pub use std::os::raw::c_char as char;
pub use std::os::raw::c_int as int; pub use std::os::raw::c_int as int;
pub use std::os::raw::c_long as long;
pub type Opaque = [usize; 0]; pub type Opaque = [usize; 0];
@ -137,6 +138,61 @@ where
} }
} }
pub trait Shared
where
Self: Sized + 'static,
{
fn deref(shared_ptr: *const SharedRef<Self>) -> *mut Self;
fn reset(shared_ptr: *mut SharedRef<Self>);
fn use_count(shared_ptr: *const SharedRef<Self>) -> long;
}
/// Wrapper around a C++ shared_ptr. The shared_ptr is assumed to contain a
/// value and not be null.
#[repr(C)]
#[derive(Debug)]
pub struct SharedRef<T>([*mut Opaque; 2], PhantomData<T>)
where
T: Shared;
impl<T> SharedRef<T>
where
T: Shared,
{
pub fn use_count(&self) -> long {
<T as Shared>::use_count(self)
}
}
impl<T> Deref for SharedRef<T>
where
T: Shared,
{
// TODO: Maybe this should deref to UnsafeCell<T>?
type Target = T;
fn deref(&self) -> &T {
unsafe { &*<T as Shared>::deref(self) }
}
}
impl<T> DerefMut for SharedRef<T>
where
T: Shared,
{
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *<T as Shared>::deref(self) }
}
}
impl<T> Drop for SharedRef<T>
where
T: Shared,
{
fn drop(&mut self) {
<T as Shared>::reset(self);
}
}
#[repr(C)] #[repr(C)]
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum MaybeBool { pub enum MaybeBool {

View file

@ -227,6 +227,61 @@ fn array_buffer() {
drop(locker); drop(locker);
} }
#[test]
fn array_buffer_with_shared_backing_store() {
setup();
let mut params = v8::Isolate::create_params();
params.set_array_buffer_allocator(v8::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
let ab1 = v8::ArrayBuffer::new(scope, 42);
assert_eq!(42, ab1.byte_length());
let bs1 = ab1.get_backing_store();
assert_eq!(ab1.byte_length(), bs1.byte_length());
assert_eq!(2, v8::SharedRef::use_count(&bs1));
let bs2 = ab1.get_backing_store();
assert_eq!(ab1.byte_length(), bs2.byte_length());
assert_eq!(3, v8::SharedRef::use_count(&bs1));
assert_eq!(3, v8::SharedRef::use_count(&bs2));
let mut bs3 = ab1.get_backing_store();
assert_eq!(ab1.byte_length(), bs3.byte_length());
assert_eq!(4, v8::SharedRef::use_count(&bs1));
assert_eq!(4, v8::SharedRef::use_count(&bs2));
assert_eq!(4, v8::SharedRef::use_count(&bs3));
drop(bs2);
assert_eq!(3, v8::SharedRef::use_count(&bs1));
assert_eq!(3, v8::SharedRef::use_count(&bs3));
drop(bs1);
assert_eq!(2, v8::SharedRef::use_count(&bs3));
let ab2 = v8::ArrayBuffer::new_with_backing_store(scope, &mut bs3);
assert_eq!(ab1.byte_length(), ab2.byte_length());
assert_eq!(3, v8::SharedRef::use_count(&bs3));
let bs4 = ab2.get_backing_store();
assert_eq!(ab2.byte_length(), bs4.byte_length());
assert_eq!(4, v8::SharedRef::use_count(&bs4));
assert_eq!(4, v8::SharedRef::use_count(&bs3));
drop(bs3);
assert_eq!(3, v8::SharedRef::use_count(&bs4));
context.exit();
}
}
fn v8_str<'sc>( fn v8_str<'sc>(
scope: &mut impl v8::ToLocal<'sc>, scope: &mut impl v8::ToLocal<'sc>,
s: &str, s: &str,