mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-12-27 17:49:12 -05:00
502 lines
14 KiB
Rust
502 lines
14 KiB
Rust
use crate::ArrayBuffer;
|
|
use crate::Context;
|
|
use crate::Exception;
|
|
use crate::HandleScope;
|
|
use crate::Isolate;
|
|
use crate::Local;
|
|
use crate::Object;
|
|
use crate::SharedArrayBuffer;
|
|
use crate::String;
|
|
use crate::Value;
|
|
use crate::WasmModuleObject;
|
|
|
|
use std::alloc::alloc;
|
|
use std::alloc::dealloc;
|
|
use std::alloc::realloc;
|
|
use std::alloc::Layout;
|
|
use std::mem::MaybeUninit;
|
|
use std::ptr::addr_of;
|
|
|
|
use crate::support::CxxVTable;
|
|
use crate::support::FieldOffset;
|
|
use crate::support::MaybeBool;
|
|
|
|
use std::ffi::c_void;
|
|
use std::pin::Pin;
|
|
|
|
// Must be == sizeof(v8::ValueSerializer::Delegate),
|
|
// see v8__ValueSerializer__Delegate__CONSTRUCT().
|
|
#[repr(C)]
|
|
pub struct CxxValueSerializerDelegate {
|
|
_cxx_vtable: CxxVTable,
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__ThrowDataCloneError(
|
|
this: &mut CxxValueSerializerDelegate,
|
|
message: Local<String>,
|
|
) {
|
|
let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this);
|
|
let scope =
|
|
&mut crate::scope::CallbackScope::new(value_serializer_heap.context);
|
|
value_serializer_heap
|
|
.value_serializer_impl
|
|
.as_mut()
|
|
.throw_data_clone_error(scope, message)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__HasCustomHostObject(
|
|
this: &mut CxxValueSerializerDelegate,
|
|
isolate: *mut Isolate,
|
|
) -> bool {
|
|
let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this);
|
|
value_serializer_heap
|
|
.value_serializer_impl
|
|
.as_mut()
|
|
.has_custom_host_object(&mut *isolate)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__IsHostObject(
|
|
this: &mut CxxValueSerializerDelegate,
|
|
_isolate: *mut Isolate,
|
|
object: Local<Object>,
|
|
) -> MaybeBool {
|
|
let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this);
|
|
let scope =
|
|
&mut crate::scope::CallbackScope::new(value_serializer_heap.context);
|
|
let value_serializer_impl =
|
|
value_serializer_heap.value_serializer_impl.as_mut();
|
|
MaybeBool::from(value_serializer_impl.is_host_object(scope, object))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__WriteHostObject(
|
|
this: &mut CxxValueSerializerDelegate,
|
|
_isolate: *mut Isolate,
|
|
object: Local<Object>,
|
|
) -> MaybeBool {
|
|
let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this);
|
|
let scope =
|
|
&mut crate::scope::CallbackScope::new(value_serializer_heap.context);
|
|
let value_serializer_impl =
|
|
value_serializer_heap.value_serializer_impl.as_mut();
|
|
MaybeBool::from(value_serializer_impl.write_host_object(
|
|
scope,
|
|
object,
|
|
&mut value_serializer_heap.cxx_value_serializer,
|
|
))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__GetSharedArrayBufferId(
|
|
this: &mut CxxValueSerializerDelegate,
|
|
_isolate: *mut Isolate,
|
|
shared_array_buffer: Local<SharedArrayBuffer>,
|
|
clone_id: *mut u32,
|
|
) -> bool {
|
|
let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this);
|
|
let scope =
|
|
&mut crate::scope::CallbackScope::new(value_serializer_heap.context);
|
|
match value_serializer_heap
|
|
.value_serializer_impl
|
|
.as_mut()
|
|
.get_shared_array_buffer_id(scope, shared_array_buffer)
|
|
{
|
|
Some(x) => {
|
|
*clone_id = x;
|
|
true
|
|
}
|
|
None => false,
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__GetWasmModuleTransferId(
|
|
this: &mut CxxValueSerializerDelegate,
|
|
_isolate: *mut Isolate,
|
|
module: Local<WasmModuleObject>,
|
|
transfer_id: *mut u32,
|
|
) -> bool {
|
|
let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this);
|
|
let scope =
|
|
&mut crate::scope::CallbackScope::new(value_serializer_heap.context);
|
|
match value_serializer_heap
|
|
.value_serializer_impl
|
|
.as_mut()
|
|
.get_wasm_module_transfer_id(scope, module)
|
|
{
|
|
Some(x) => {
|
|
*transfer_id = x;
|
|
true
|
|
}
|
|
None => false,
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__ReallocateBufferMemory(
|
|
this: &mut CxxValueSerializerDelegate,
|
|
old_buffer: *mut c_void,
|
|
size: usize,
|
|
actual_size: *mut usize,
|
|
) -> *mut c_void {
|
|
let base = ValueSerializerHeap::dispatch_mut(this);
|
|
|
|
let new_buffer = if old_buffer.is_null() {
|
|
let layout = Layout::from_size_align(size, 1).unwrap();
|
|
alloc(layout)
|
|
} else {
|
|
let old_layout = Layout::from_size_align(base.buffer_size, 1).unwrap();
|
|
realloc(old_buffer as *mut _, old_layout, size)
|
|
};
|
|
|
|
base.buffer_size = size;
|
|
|
|
*actual_size = size;
|
|
new_buffer as *mut c_void
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn v8__ValueSerializer__Delegate__FreeBufferMemory(
|
|
this: &mut CxxValueSerializerDelegate,
|
|
buffer: *mut c_void,
|
|
) {
|
|
let base = ValueSerializerHeap::dispatch_mut(this);
|
|
if !buffer.is_null() {
|
|
let layout = Layout::from_size_align(base.buffer_size, 1).unwrap();
|
|
dealloc(buffer as *mut _, layout)
|
|
};
|
|
}
|
|
|
|
extern "C" {
|
|
fn v8__ValueSerializer__Delegate__CONSTRUCT(
|
|
buf: *mut MaybeUninit<CxxValueSerializerDelegate>,
|
|
);
|
|
}
|
|
|
|
// Must be == sizeof(v8::ValueSerializer), see v8__ValueSerializer__CONSTRUCT().
|
|
#[repr(C)]
|
|
pub struct CxxValueSerializer {
|
|
_cxx_vtable: CxxVTable,
|
|
}
|
|
|
|
extern "C" {
|
|
fn v8__ValueSerializer__CONSTRUCT(
|
|
buf: *mut MaybeUninit<CxxValueSerializer>,
|
|
isolate: *mut Isolate,
|
|
delegate: *mut CxxValueSerializerDelegate,
|
|
);
|
|
|
|
fn v8__ValueSerializer__DESTRUCT(this: *mut CxxValueSerializer);
|
|
|
|
fn v8__ValueSerializer__Release(
|
|
this: *mut CxxValueSerializer,
|
|
ptr: *mut *mut u8,
|
|
size: *mut usize,
|
|
);
|
|
|
|
fn v8__ValueSerializer__TransferArrayBuffer(
|
|
this: *mut CxxValueSerializer,
|
|
transfer_id: u32,
|
|
array_buffer: Local<ArrayBuffer>,
|
|
);
|
|
|
|
fn v8__ValueSerializer__WriteHeader(this: *mut CxxValueSerializer);
|
|
fn v8__ValueSerializer__WriteValue(
|
|
this: *mut CxxValueSerializer,
|
|
context: Local<Context>,
|
|
value: Local<Value>,
|
|
) -> MaybeBool;
|
|
fn v8__ValueSerializer__WriteUint32(
|
|
this: *mut CxxValueSerializer,
|
|
value: u32,
|
|
);
|
|
fn v8__ValueSerializer__WriteUint64(
|
|
this: *mut CxxValueSerializer,
|
|
value: u64,
|
|
);
|
|
fn v8__ValueSerializer__WriteDouble(
|
|
this: *mut CxxValueSerializer,
|
|
value: f64,
|
|
);
|
|
fn v8__ValueSerializer__WriteRawBytes(
|
|
this: *mut CxxValueSerializer,
|
|
source: *const c_void,
|
|
length: usize,
|
|
);
|
|
}
|
|
|
|
/// The ValueSerializerImpl trait allows for
|
|
/// custom callback functions used by v8.
|
|
pub trait ValueSerializerImpl {
|
|
fn throw_data_clone_error<'s>(
|
|
&mut self,
|
|
scope: &mut HandleScope<'s>,
|
|
message: Local<'s, String>,
|
|
);
|
|
|
|
fn has_custom_host_object(&mut self, _isolate: &mut Isolate) -> bool {
|
|
false
|
|
}
|
|
|
|
fn is_host_object<'s>(
|
|
&mut self,
|
|
scope: &mut HandleScope<'s>,
|
|
_object: Local<'s, Object>,
|
|
) -> Option<bool> {
|
|
let msg =
|
|
String::new(scope, "Deno serializer: is_host_object not implemented")
|
|
.unwrap();
|
|
let exc = Exception::error(scope, msg);
|
|
scope.throw_exception(exc);
|
|
None
|
|
}
|
|
|
|
fn write_host_object<'s>(
|
|
&mut self,
|
|
scope: &mut HandleScope<'s>,
|
|
_object: Local<'s, Object>,
|
|
_value_serializer: &mut dyn ValueSerializerHelper,
|
|
) -> Option<bool> {
|
|
let msg =
|
|
String::new(scope, "Deno serializer: write_host_object not implemented")
|
|
.unwrap();
|
|
let exc = Exception::error(scope, msg);
|
|
scope.throw_exception(exc);
|
|
None
|
|
}
|
|
|
|
fn get_shared_array_buffer_id<'s>(
|
|
&mut self,
|
|
_scope: &mut HandleScope<'s>,
|
|
_shared_array_buffer: Local<'s, SharedArrayBuffer>,
|
|
) -> Option<u32> {
|
|
None
|
|
}
|
|
|
|
fn get_wasm_module_transfer_id(
|
|
&mut self,
|
|
scope: &mut HandleScope<'_>,
|
|
_module: Local<WasmModuleObject>,
|
|
) -> Option<u32> {
|
|
let msg = String::new(
|
|
scope,
|
|
"Deno serializer: get_wasm_module_transfer_id not implemented",
|
|
)
|
|
.unwrap();
|
|
let exc = Exception::error(scope, msg);
|
|
scope.throw_exception(exc);
|
|
None
|
|
}
|
|
}
|
|
|
|
/// The ValueSerializerHeap object contains all objects related to serializer.
|
|
/// This object has to be pinned to the heap because of the Cpp pointers that
|
|
/// have to remain valid. Moving this object would result in the Cpp pointer
|
|
/// to the delegate to become invalid and thus causing the delegate callback
|
|
/// to fail. Additionally the serializer and implementation are also pinned
|
|
/// in memory because these have to be accessable from within the delegate
|
|
/// callback methods.
|
|
pub struct ValueSerializerHeap<'a, 's> {
|
|
value_serializer_impl: Box<dyn ValueSerializerImpl + 'a>,
|
|
cxx_value_serializer_delegate: CxxValueSerializerDelegate,
|
|
cxx_value_serializer: CxxValueSerializer,
|
|
buffer_size: usize,
|
|
context: Local<'s, Context>,
|
|
}
|
|
|
|
impl<'a, 's> ValueSerializerHeap<'a, 's> {
|
|
fn get_cxx_value_serializer_delegate_offset(
|
|
) -> FieldOffset<CxxValueSerializerDelegate> {
|
|
let buf = std::mem::MaybeUninit::<Self>::uninit();
|
|
let delegate =
|
|
unsafe { addr_of!((*buf.as_ptr()).cxx_value_serializer_delegate) };
|
|
FieldOffset::from_ptrs(buf.as_ptr(), delegate)
|
|
}
|
|
|
|
/// Starting from 'this' pointer a ValueSerializerHeap ref can be created
|
|
#[allow(dead_code)]
|
|
pub unsafe fn dispatch(
|
|
value_serializer_delegate: &'s CxxValueSerializerDelegate,
|
|
) -> &Self {
|
|
Self::get_cxx_value_serializer_delegate_offset()
|
|
.to_embedder::<Self>(value_serializer_delegate)
|
|
}
|
|
|
|
/// Starting from 'this' pointer the ValueSerializerHeap mut ref can be
|
|
/// created
|
|
pub unsafe fn dispatch_mut(
|
|
value_serializer_delegate: &'s mut CxxValueSerializerDelegate,
|
|
) -> &mut Self {
|
|
Self::get_cxx_value_serializer_delegate_offset()
|
|
.to_embedder_mut::<Self>(value_serializer_delegate)
|
|
}
|
|
}
|
|
|
|
impl<'a, 's> Drop for ValueSerializerHeap<'a, 's> {
|
|
fn drop(&mut self) {
|
|
unsafe { v8__ValueSerializer__DESTRUCT(&mut self.cxx_value_serializer) };
|
|
}
|
|
}
|
|
|
|
/// Trait used for direct write to the serialization buffer.
|
|
/// Mostly used by the write_host_object callback function in the
|
|
/// ValueSerializerImpl trait to create custom serialization logic.
|
|
pub trait ValueSerializerHelper {
|
|
fn get_cxx_value_serializer(&mut self) -> &mut CxxValueSerializer;
|
|
|
|
fn write_header(&mut self) {
|
|
unsafe {
|
|
v8__ValueSerializer__WriteHeader(self.get_cxx_value_serializer())
|
|
};
|
|
}
|
|
|
|
fn write_value(
|
|
&mut self,
|
|
context: Local<Context>,
|
|
value: Local<Value>,
|
|
) -> Option<bool> {
|
|
unsafe {
|
|
v8__ValueSerializer__WriteValue(
|
|
self.get_cxx_value_serializer(),
|
|
context,
|
|
value,
|
|
)
|
|
}
|
|
.into()
|
|
}
|
|
|
|
fn write_uint32(&mut self, value: u32) {
|
|
unsafe {
|
|
v8__ValueSerializer__WriteUint32(self.get_cxx_value_serializer(), value)
|
|
};
|
|
}
|
|
|
|
fn write_uint64(&mut self, value: u64) {
|
|
unsafe {
|
|
v8__ValueSerializer__WriteUint64(self.get_cxx_value_serializer(), value)
|
|
};
|
|
}
|
|
|
|
fn write_double(&mut self, value: f64) {
|
|
unsafe {
|
|
v8__ValueSerializer__WriteDouble(self.get_cxx_value_serializer(), value)
|
|
};
|
|
}
|
|
|
|
fn write_raw_bytes(&mut self, source: &[u8]) {
|
|
unsafe {
|
|
v8__ValueSerializer__WriteRawBytes(
|
|
self.get_cxx_value_serializer(),
|
|
source.as_ptr() as *const _,
|
|
source.len(),
|
|
)
|
|
};
|
|
}
|
|
|
|
fn transfer_array_buffer(
|
|
&mut self,
|
|
transfer_id: u32,
|
|
array_buffer: Local<ArrayBuffer>,
|
|
) {
|
|
unsafe {
|
|
v8__ValueSerializer__TransferArrayBuffer(
|
|
self.get_cxx_value_serializer(),
|
|
transfer_id,
|
|
array_buffer,
|
|
)
|
|
};
|
|
}
|
|
}
|
|
|
|
impl ValueSerializerHelper for CxxValueSerializer {
|
|
fn get_cxx_value_serializer(&mut self) -> &mut CxxValueSerializer {
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<'a, 's> ValueSerializerHelper for ValueSerializerHeap<'a, 's> {
|
|
fn get_cxx_value_serializer(&mut self) -> &mut CxxValueSerializer {
|
|
&mut self.cxx_value_serializer
|
|
}
|
|
}
|
|
|
|
impl<'a, 's> ValueSerializerHelper for ValueSerializer<'a, 's> {
|
|
fn get_cxx_value_serializer(&mut self) -> &mut CxxValueSerializer {
|
|
&mut self.value_serializer_heap.cxx_value_serializer
|
|
}
|
|
}
|
|
|
|
pub struct ValueSerializer<'a, 's> {
|
|
value_serializer_heap: Pin<Box<ValueSerializerHeap<'a, 's>>>,
|
|
}
|
|
|
|
/// ValueSerializer is a stack object used as entry-point for an owned and
|
|
/// pinned heap object ValueSerializerHeap.
|
|
/// The 'a lifetime is the lifetime of the ValueSerializerImpl implementation.
|
|
/// The 's lifetime is the lifetime of the HandleScope which is used to retrieve
|
|
/// a Local<'s, Context> for the CallbackScopes
|
|
impl<'a, 's> ValueSerializer<'a, 's> {
|
|
pub fn new<D: ValueSerializerImpl + 'a>(
|
|
scope: &mut HandleScope<'s>,
|
|
value_serializer_impl: Box<D>,
|
|
) -> Self {
|
|
// create dummy ValueSerializerHeap 'a, and move to heap + pin to address
|
|
let mut value_serializer_heap = Box::pin(ValueSerializerHeap {
|
|
value_serializer_impl,
|
|
cxx_value_serializer: CxxValueSerializer {
|
|
_cxx_vtable: CxxVTable(std::ptr::null()),
|
|
},
|
|
cxx_value_serializer_delegate: CxxValueSerializerDelegate {
|
|
_cxx_vtable: CxxVTable(std::ptr::null()),
|
|
},
|
|
buffer_size: 0,
|
|
context: scope.get_current_context(),
|
|
});
|
|
|
|
unsafe {
|
|
v8__ValueSerializer__Delegate__CONSTRUCT(
|
|
&mut value_serializer_heap.cxx_value_serializer_delegate
|
|
as *mut CxxValueSerializerDelegate
|
|
as *mut std::mem::MaybeUninit<CxxValueSerializerDelegate>,
|
|
);
|
|
|
|
v8__ValueSerializer__CONSTRUCT(
|
|
&mut value_serializer_heap.cxx_value_serializer
|
|
as *mut CxxValueSerializer
|
|
as *mut std::mem::MaybeUninit<CxxValueSerializer>,
|
|
scope.get_isolate_ptr(),
|
|
&mut value_serializer_heap.cxx_value_serializer_delegate,
|
|
);
|
|
};
|
|
|
|
Self {
|
|
value_serializer_heap,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, 's> ValueSerializer<'a, 's> {
|
|
pub fn release(mut self) -> Vec<u8> {
|
|
unsafe {
|
|
let mut size: usize = 0;
|
|
let mut ptr: *mut u8 = &mut 0;
|
|
v8__ValueSerializer__Release(
|
|
&mut self.value_serializer_heap.cxx_value_serializer,
|
|
&mut ptr,
|
|
&mut size,
|
|
);
|
|
Vec::from_raw_parts(ptr, size, self.value_serializer_heap.buffer_size)
|
|
}
|
|
}
|
|
|
|
pub fn write_value(
|
|
&mut self,
|
|
context: Local<Context>,
|
|
value: Local<Value>,
|
|
) -> Option<bool> {
|
|
self.value_serializer_heap.write_value(context, value)
|
|
}
|
|
}
|