diff --git a/build.rs b/build.rs index ade55ed5..0f53e656 100644 --- a/build.rs +++ b/build.rs @@ -11,6 +11,8 @@ use std::process::Stdio; use which::which; fn main() { + println!("cargo:rerun-if-changed=src/binding.cc"); + // Detect if trybuild tests are being compiled. let is_trybuild = env::var_os("DENO_TRYBUILD").is_some(); diff --git a/src/binding.cc b/src/binding.cc index d28744b8..3298734c 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -1926,22 +1926,6 @@ v8::Platform* v8__platform__NewDefaultPlatform() { } void v8__Platform__DELETE(v8::Platform* self) { delete self; } -void v8__Task__BASE__DELETE(v8::Task* self); -void v8__Task__BASE__Run(v8::Task* self); - -struct v8__Task__BASE : public v8::Task { - using Task::Task; - void operator delete(void* ptr) noexcept { - v8__Task__BASE__DELETE(reinterpret_cast(ptr)); - } - void Run() override { v8__Task__BASE__Run(this); } -}; - -void v8__Task__BASE__CONSTRUCT(uninit_t* buf) { - construct_in_place(buf); -} -void v8__Task__DELETE(v8::Task* self) { delete self; } -void v8__Task__Run(v8::Task* self) { self->Run(); } void v8_inspector__V8Inspector__Channel__BASE__sendResponse( v8_inspector::V8Inspector::Channel* self, int callId, diff --git a/src/lib.rs b/src/lib.rs index c0b1b146..77d680d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,10 +111,6 @@ pub use module::*; pub use object::*; pub use platform::new_default_platform; pub use platform::Platform; -pub use platform::Task; -// TODO(ry) TaskBase and TaskImpl ideally shouldn't be part of the public API. -pub use platform::TaskBase; -pub use platform::TaskImpl; pub use primitives::*; pub use private::*; pub use promise::{PromiseRejectEvent, PromiseRejectMessage, PromiseState}; diff --git a/src/platform.rs b/src/platform.rs new file mode 100644 index 00000000..cadbdc91 --- /dev/null +++ b/src/platform.rs @@ -0,0 +1,21 @@ +use crate::support::Opaque; +use crate::support::UniquePtr; + +extern "C" { + fn v8__platform__NewDefaultPlatform() -> *mut Platform; + fn v8__Platform__DELETE(this: *mut Platform); +} + +pub fn new_default_platform() -> UniquePtr { + unsafe { UniquePtr::from_raw(v8__platform__NewDefaultPlatform()) } +} + +#[repr(C)] +#[derive(Debug)] +pub struct Platform(Opaque); + +impl Drop for Platform { + fn drop(&mut self) { + unsafe { v8__Platform__DELETE(self) } + } +} diff --git a/src/platform/mod.rs b/src/platform/mod.rs deleted file mode 100644 index ed96b5a4..00000000 --- a/src/platform/mod.rs +++ /dev/null @@ -1,41 +0,0 @@ -pub mod task; - -pub use task::{Task, TaskBase, TaskImpl}; - -use crate::support::Opaque; -use crate::support::UniquePtr; -use crate::Isolate; - -extern "C" { - // TODO: move this to libplatform.rs? - fn v8__platform__NewDefaultPlatform() -> *mut Platform; - - fn v8__Platform__DELETE(this: *mut Platform); -} - -pub fn new_default_platform() -> UniquePtr { - // TODO: support optional arguments. - unsafe { UniquePtr::from_raw(v8__platform__NewDefaultPlatform()) } -} - -#[repr(C)] -#[derive(Debug)] -pub struct Platform(Opaque); - -impl Drop for Platform { - fn drop(&mut self) { - unsafe { v8__Platform__DELETE(self) } - } -} - -impl Platform { - /// Pumps the message loop for the given isolate. - /// - /// The caller has to make sure that this is called from the right thread. - /// Returns true if a task was executed, and false otherwise. Unless requested - /// through the |behavior| parameter, this call does not block if no task is - /// pending. The |platform| has to be created using |NewDefaultPlatform|. - pub fn pump_message_loop(_platform: &Self, _isolate: &Isolate) -> bool { - todo!() - } -} diff --git a/src/platform/task.rs b/src/platform/task.rs deleted file mode 100644 index f3aae9d4..00000000 --- a/src/platform/task.rs +++ /dev/null @@ -1,239 +0,0 @@ -use std::fmt::{self, Debug, Formatter}; -use std::mem::drop; -use std::mem::forget; -use std::mem::ManuallyDrop; - -use crate::support::CxxVTable; -use crate::support::FieldOffset; -use crate::support::Opaque; -use crate::support::RustVTable; -use crate::support::UniqueRef; - -// class Task { -// public: -// virtual ~Task() = default; -// virtual void Run() = 0; -// }; - -extern "C" { - fn v8__Task__BASE__CONSTRUCT(buf: *mut std::mem::MaybeUninit); - fn v8__Task__DELETE(this: *mut Task); - fn v8__Task__Run(this: *mut Task); -} - -#[no_mangle] -pub unsafe extern "C" fn v8__Task__BASE__DELETE(this: &mut Task) { - drop(TaskBase::dispatch_box(this)) -} - -#[no_mangle] -pub unsafe extern "C" fn v8__Task__BASE__Run(this: &mut Task) { - TaskBase::dispatch_mut(this).run() -} - -#[repr(C)] -#[derive(Debug)] -pub struct Task { - _cxx_vtable: CxxVTable, -} - -impl Task { - pub fn run(&mut self) { - unsafe { v8__Task__Run(self) } - } -} - -impl Drop for Task { - fn drop(&mut self) { - unsafe { v8__Task__DELETE(self) } - } -} - -pub trait AsTask { - fn as_task(&self) -> &Task; - fn as_task_mut(&mut self) -> &mut Task; - - // TODO: this should be a trait in itself. - fn into_unique_ref(mut self: Box) -> UniqueRef - where - Self: 'static, - { - let task = self.as_task_mut() as *mut Task; - forget(self); - unsafe { UniqueRef::from_raw(task) } - } -} - -impl AsTask for Task { - fn as_task(&self) -> &Task { - self - } - fn as_task_mut(&mut self) -> &mut Task { - self - } -} - -impl AsTask for T -where - T: TaskImpl, -{ - fn as_task(&self) -> &Task { - &self.base().cxx_base - } - fn as_task_mut(&mut self) -> &mut Task { - &mut self.base_mut().cxx_base - } -} - -pub trait TaskImpl: AsTask { - fn base(&self) -> &TaskBase; - fn base_mut(&mut self) -> &mut TaskBase; - fn run(&mut self); -} - -pub struct TaskBase { - cxx_base: ManuallyDrop, - offset_within_embedder: FieldOffset, - rust_vtable: RustVTable<&'static dyn TaskImpl>, -} - -impl TaskBase { - fn construct_cxx_base() -> ManuallyDrop { - unsafe { - let mut buf = std::mem::MaybeUninit::::uninit(); - v8__Task__BASE__CONSTRUCT(&mut buf); - ManuallyDrop::new(buf.assume_init()) - } - } - - fn get_cxx_base_offset() -> FieldOffset { - let buf = std::mem::MaybeUninit::::uninit(); - FieldOffset::from_ptrs(buf.as_ptr(), unsafe { &*(*buf.as_ptr()).cxx_base }) - } - - fn get_offset_within_embedder() -> FieldOffset - where - T: TaskImpl, - { - let buf = std::mem::MaybeUninit::::uninit(); - let embedder_ptr: *const T = buf.as_ptr(); - let self_ptr: *const Self = unsafe { (*embedder_ptr).base() }; - FieldOffset::from_ptrs(embedder_ptr, self_ptr) - } - - fn get_rust_vtable() -> RustVTable<&'static dyn TaskImpl> - where - T: TaskImpl, - { - let buf = std::mem::MaybeUninit::::uninit(); - let embedder_ptr = buf.as_ptr(); - let trait_object: *const dyn TaskImpl = embedder_ptr; - let (data_ptr, vtable): (*const T, RustVTable<_>) = - unsafe { std::mem::transmute(trait_object) }; - assert_eq!(data_ptr, embedder_ptr); - vtable - } - - pub fn new() -> Self - where - T: TaskImpl, - { - Self { - cxx_base: Self::construct_cxx_base(), - offset_within_embedder: Self::get_offset_within_embedder::(), - rust_vtable: Self::get_rust_vtable::(), - } - } - - pub unsafe fn dispatch(task: &Task) -> &dyn TaskImpl { - let this = Self::get_cxx_base_offset().to_embedder::(task); - let embedder = this.offset_within_embedder.to_embedder::(this); - std::mem::transmute((embedder, this.rust_vtable)) - } - - pub unsafe fn dispatch_mut(task: &mut Task) -> &mut dyn TaskImpl { - let this = Self::get_cxx_base_offset().to_embedder_mut::(task); - let vtable = this.rust_vtable; - let embedder = this.offset_within_embedder.to_embedder_mut::(this); - std::mem::transmute((embedder, vtable)) - } - - pub unsafe fn dispatch_box(task: &mut Task) -> Box { - std::mem::transmute(Self::dispatch_mut(task)) - } -} - -impl Debug for TaskBase { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("TaskBase") - .field("cxx_base", &self.cxx_base) - .field("offset_within_embedder", &self.offset_within_embedder) - .finish() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::sync::atomic::AtomicUsize; - use std::sync::atomic::Ordering::SeqCst; - - static RUN_COUNT: AtomicUsize = AtomicUsize::new(0); - static DROP_COUNT: AtomicUsize = AtomicUsize::new(0); - - // Using repr(C) to preserve field ordering and test that everything works - // when the TaskBase field is not the first element of the struct. - #[repr(C)] - struct TestTask { - field1: i32, - base: TaskBase, - field2: f64, - } - - impl TestTask { - pub fn new() -> Self { - Self { - base: TaskBase::new::(), - field1: -42, - field2: 4.2, - } - } - } - - impl TaskImpl for TestTask { - fn base(&self) -> &TaskBase { - &self.base - } - fn base_mut(&mut self) -> &mut TaskBase { - &mut self.base - } - fn run(&mut self) { - RUN_COUNT.fetch_add(1, SeqCst); - } - } - - impl Drop for TestTask { - fn drop(&mut self) { - DROP_COUNT.fetch_add(1, SeqCst); - } - } - - #[test] - fn test_task() { - { - let mut task = TestTask::new(); - task.run(); - drop(task); - assert_eq!(RUN_COUNT.swap(0, SeqCst), 1); - assert_eq!(DROP_COUNT.swap(0, SeqCst), 1); - } - { - let mut task = Box::new(TestTask::new()).into_unique_ref(); - task.run(); - task.run(); - drop(task); - assert_eq!(RUN_COUNT.swap(0, SeqCst), 2); - assert_eq!(DROP_COUNT.swap(0, SeqCst), 1); - } - } -}