From f36e74a648855fba031599132ffef13da8d60abc Mon Sep 17 00:00:00 2001 From: Ry Dahl Date: Sat, 21 Dec 2019 11:05:51 -0500 Subject: [PATCH] First pass at BackingStore (#108) --- src/array_buffer.rs | 67 +++++++++++++++++++++++++++++++++++++++++++++ src/binding.cc | 17 ++++++++++++ src/lib.rs | 1 + tests/test_api.rs | 4 +++ 4 files changed, 89 insertions(+) diff --git a/src/array_buffer.rs b/src/array_buffer.rs index 673c57f8..5f587021 100644 --- a/src/array_buffer.rs +++ b/src/array_buffer.rs @@ -14,6 +14,14 @@ extern "C" { byte_length: usize, ) -> *mut ArrayBuffer; fn v8__ArrayBuffer__ByteLength(self_: *const ArrayBuffer) -> usize; + + fn v8__ArrayBuffer__NewBackingStore( + isolate: *mut Isolate, + byte_length: usize, + ) -> *mut BackingStore; + fn v8__BackingStore__ByteLength(self_: &BackingStore) -> usize; + fn v8__BackingStore__IsShared(self_: &BackingStore) -> bool; + fn v8__BackingStore__DELETE(self_: &mut BackingStore); } /// A thread-safe allocator that V8 uses to allocate |ArrayBuffer|'s memory. @@ -59,6 +67,46 @@ impl Delete for Allocator { } } +/// 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. +/// +/// The allocation and destruction of backing stores is generally managed by +/// V8. Clients should always use standard C++ memory ownership types (i.e. +/// std::unique_ptr and std::shared_ptr) to manage lifetimes of backing stores +/// properly, since V8 internal objects may alias backing stores. +/// +/// This object does not keep the underlying |ArrayBuffer::Allocator| alive by +/// default. Use Isolate::CreateParams::array_buffer_allocator_shared when +/// creating the Isolate to make it hold a reference to the allocator itself. +#[repr(C)] +pub struct BackingStore([usize; 6]); + +impl BackingStore { + /// Return a pointer to the beginning of the memory block for this backing + /// store. The pointer is only valid as long as this backing store object + /// lives. + pub fn data(&self) -> std::ffi::c_void { + unimplemented!() + } + + /// The length (in bytes) of this backing store. + pub fn byte_length(&self) -> usize { + unsafe { v8__BackingStore__ByteLength(self) } + } + + /// Indicates whether the backing store was created for an ArrayBuffer or + /// a SharedArrayBuffer. + pub fn is_shared(&self) -> bool { + unsafe { v8__BackingStore__IsShared(self) } + } +} + +impl Delete for BackingStore { + fn delete(&mut self) { + unsafe { v8__BackingStore__DELETE(self) }; + } +} + /// An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5). #[repr(C)] pub struct ArrayBuffer(Opaque); @@ -82,4 +130,23 @@ impl ArrayBuffer { pub fn byte_length(&self) -> usize { unsafe { v8__ArrayBuffer__ByteLength(self) } } + + /// Returns a new standalone BackingStore that is allocated using the array + /// buffer allocator of the isolate. The result can be later passed to + /// ArrayBuffer::New. + /// + /// 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 HandleScope<'sc>, + byte_length: usize, + ) -> UniqueRef { + unsafe { + UniqueRef::from_raw(v8__ArrayBuffer__NewBackingStore( + scope.as_mut(), + byte_length, + )) + } + } } diff --git a/src/binding.cc b/src/binding.cc index a016428f..935788d1 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -189,6 +189,23 @@ v8::Primitive* v8__PrimitiveArray__Get(v8::PrimitiveArray& self, return local_to_ptr(self.Get(isolate, index)); } +v8::BackingStore* v8__ArrayBuffer__NewBackingStore(v8::Isolate* isolate, + size_t length) { + std::unique_ptr u = + v8::ArrayBuffer::NewBackingStore(isolate, length); + return u.release(); +} + +size_t v8__BackingStore__ByteLength(v8::BackingStore& self) { + return self.ByteLength(); +} + +bool v8__BackingStore__IsShared(v8::BackingStore& self) { + return self.IsShared(); +} + +void v8__BackingStore__DELETE(v8::BackingStore& self) { delete &self; } + v8::String* v8__String__NewFromUtf8(v8::Isolate* isolate, const char* data, v8::NewStringType type, int length) { return maybe_local_to_ptr( diff --git a/src/lib.rs b/src/lib.rs index 9c43ebfc..519d2ec2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,7 @@ pub mod V8; pub use array_buffer::Allocator; pub use array_buffer::ArrayBuffer; +pub use array_buffer::BackingStore; pub use context::Context; pub use exception::*; pub use function::{ diff --git a/tests/test_api.rs b/tests/test_api.rs index f088fce4..ebaacccd 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -107,6 +107,10 @@ fn array_buffer() { let ab = v8::ArrayBuffer::new(scope, 42); assert_eq!(42, ab.byte_length()); + let bs = v8::ArrayBuffer::new_backing_store(scope, 84); + assert_eq!(84, bs.byte_length()); + assert_eq!(false, bs.is_shared()); + context.exit(); }); drop(locker);