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:
parent
a2196a7248
commit
76a480e6ff
6 changed files with 237 additions and 12 deletions
|
@ -1,6 +1,10 @@
|
|||
use crate::support::long;
|
||||
use crate::support::Delete;
|
||||
use crate::support::Opaque;
|
||||
use crate::support::Shared;
|
||||
use crate::support::SharedRef;
|
||||
use crate::support::UniqueRef;
|
||||
use crate::InIsolate;
|
||||
use crate::Isolate;
|
||||
use crate::Local;
|
||||
use crate::ToLocal;
|
||||
|
@ -8,13 +12,18 @@ use crate::ToLocal;
|
|||
extern "C" {
|
||||
fn v8__ArrayBuffer__Allocator__NewDefaultAllocator() -> *mut Allocator;
|
||||
fn v8__ArrayBuffer__Allocator__DELETE(this: &'static mut Allocator);
|
||||
|
||||
fn v8__ArrayBuffer__New(
|
||||
fn v8__ArrayBuffer__New__byte_length(
|
||||
isolate: *mut Isolate,
|
||||
byte_length: usize,
|
||||
) -> *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__GetBackingStore(
|
||||
self_: *const ArrayBuffer,
|
||||
) -> SharedRef<BackingStore>;
|
||||
fn v8__ArrayBuffer__NewBackingStore(
|
||||
isolate: *mut Isolate,
|
||||
byte_length: usize,
|
||||
|
@ -22,6 +31,15 @@ extern "C" {
|
|||
fn v8__BackingStore__ByteLength(self_: &BackingStore) -> usize;
|
||||
fn v8__BackingStore__IsShared(self_: &BackingStore) -> bool;
|
||||
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.
|
||||
|
@ -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).
|
||||
#[repr(C)]
|
||||
pub struct ArrayBuffer(Opaque);
|
||||
|
@ -119,7 +149,19 @@ impl ArrayBuffer {
|
|||
byte_length: usize,
|
||||
) -> Local<'sc, ArrayBuffer> {
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -127,6 +169,9 @@ impl ArrayBuffer {
|
|||
pub fn byte_length(&self) -> usize {
|
||||
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
|
||||
/// 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
|
||||
/// given isolate and re-try the allocation. If GCs do not help, then the
|
||||
/// function will crash with an out-of-memory error.
|
||||
pub fn new_backing_store<'sc>(
|
||||
scope: &mut impl ToLocal<'sc>,
|
||||
pub fn new_backing_store(
|
||||
scope: &mut impl InIsolate,
|
||||
byte_length: usize,
|
||||
) -> UniqueRef<BackingStore> {
|
||||
unsafe {
|
||||
|
|
|
@ -70,7 +70,6 @@ v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallback(
|
|||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void v8__V8__SetFlagsFromCommandLine(int* argc, char** argv) {
|
||||
v8::V8::SetFlagsFromCommandLine(argc, argv, true);
|
||||
}
|
||||
|
@ -325,6 +324,10 @@ v8::BackingStore* v8__ArrayBuffer__NewBackingStore(v8::Isolate* isolate,
|
|||
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) {
|
||||
return self.ByteLength();
|
||||
}
|
||||
|
@ -335,6 +338,21 @@ bool v8__BackingStore__IsShared(v8::BackingStore& 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::NewStringType type, int length) {
|
||||
return maybe_local_to_ptr(
|
||||
|
@ -419,11 +437,16 @@ void v8__ArrayBuffer__Allocator__DELETE(v8::ArrayBuffer::Allocator& 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) {
|
||||
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) {
|
||||
return self.ByteLength();
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ pub use snapshot::{FunctionCodeHandling, SnapshotCreator, StartupData};
|
|||
pub use string::NewStringType;
|
||||
pub use string::String;
|
||||
pub use support::MaybeBool;
|
||||
pub use support::SharedRef;
|
||||
pub use support::UniqueRef;
|
||||
pub use try_catch::{TryCatch, TryCatchScope};
|
||||
pub use uint8_array::Uint8Array;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define SUPPORT_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
|
@ -11,9 +12,8 @@
|
|||
#include "v8/include/v8.h"
|
||||
|
||||
// Check assumptions made in binding code.
|
||||
// TODO(ry) re-enable the following
|
||||
// static_assert(sizeof(bool) == sizeof(uint8_t));
|
||||
// static_assert(sizeof(std::unique_ptr<void>) == sizeof(void*));
|
||||
static_assert(sizeof(bool) == sizeof(uint8_t), "");
|
||||
static_assert(sizeof(std::unique_ptr<void>) == sizeof(void*), "");
|
||||
|
||||
namespace support {
|
||||
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)...);
|
||||
}
|
||||
|
||||
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>.
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
#endif // SUPPORT_H_
|
||||
|
|
|
@ -8,6 +8,7 @@ use std::ptr::NonNull;
|
|||
|
||||
pub use std::os::raw::c_char as char;
|
||||
pub use std::os::raw::c_int as int;
|
||||
pub use std::os::raw::c_long as long;
|
||||
|
||||
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)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum MaybeBool {
|
||||
|
|
|
@ -227,6 +227,61 @@ fn array_buffer() {
|
|||
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>(
|
||||
scope: &mut impl v8::ToLocal<'sc>,
|
||||
s: &str,
|
||||
|
|
Loading…
Reference in a new issue