From 7b8e882546da113af3a241f00e36521ed534d0a4 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sat, 19 Oct 2019 17:15:23 -0700 Subject: [PATCH] Client binding + clean-ups --- .vscode/settings.json | 3 +- _git2_a11280 | 1 - src/cxx_util.rs | 2 + src/lib.cpp | 4 +- src/main.rs | 2 +- src/v8_inspector/channel.h | 5 +- src/v8_inspector/channel.rs | 11 +- src/v8_inspector/channel.rs.template | 176 -------------------- src/v8_inspector/client.h | 54 ++++++ src/v8_inspector/client.rs | 236 +++++++++++++++++++++++++++ src/v8_inspector/mod.rs | 2 + src/v8_inspector/string_buffer.rs | 2 + 12 files changed, 307 insertions(+), 191 deletions(-) delete mode 120000 _git2_a11280 delete mode 100644 src/v8_inspector/channel.rs.template create mode 100644 src/v8_inspector/client.h diff --git a/.vscode/settings.json b/.vscode/settings.json index 50314abb..d01fed2a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "C_Cpp.clang_format_style": "Chromium", "files.associations": { - "memory": "cpp" + "memory": "cpp", + "vector": "cpp" } } \ No newline at end of file diff --git a/_git2_a11280 b/_git2_a11280 deleted file mode 120000 index 9a2c7732..00000000 --- a/_git2_a11280 +++ /dev/null @@ -1 +0,0 @@ -testing \ No newline at end of file diff --git a/src/cxx_util.rs b/src/cxx_util.rs index 95fb9406..9f6ea22a 100644 --- a/src/cxx_util.rs +++ b/src/cxx_util.rs @@ -2,6 +2,8 @@ use std::marker::PhantomData; use std::mem::size_of; use std::ops::{Deref, DerefMut}; +pub use std::os::raw::c_int as int; + pub type Opaque = [usize; 0]; pub trait Delete diff --git a/src/lib.cpp b/src/lib.cpp index 58138e25..03079983 100644 --- a/src/lib.cpp +++ b/src/lib.cpp @@ -7,9 +7,6 @@ #include #include "../goog/v8/include/v8-inspector.h" -namespace v8_inspector { -using Channel = V8Inspector::Channel; -} template using uninit_t = typename std::aligned_storage::type; @@ -21,4 +18,5 @@ auto launder(T ptr) { } #include "v8_inspector/channel.h" +#include "v8_inspector/client.h" #include "v8_inspector/string_buffer.h" diff --git a/src/main.rs b/src/main.rs index be73977c..311ad8e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,7 +33,7 @@ mod example { message.as_mut().unwrap().string().characters16().unwrap() ); } - fn sendNotification(&mut self, message: UniquePtr) {} + fn sendNotification(&mut self, _message: UniquePtr) {} fn flushProtocolNotifications(&mut self) {} } diff --git a/src/v8_inspector/channel.h b/src/v8_inspector/channel.h index e256bee6..c94824a2 100644 --- a/src/v8_inspector/channel.h +++ b/src/v8_inspector/channel.h @@ -1,9 +1,10 @@ #include #include -extern "C" { using namespace v8_inspector; +using Channel = V8Inspector::Channel; +extern "C" { void v8_inspector__Channel__EXTENDER__sendResponse(Channel& self, int callId, StringBuffer* message); @@ -33,8 +34,6 @@ struct Channel__EXTENDER : public Channel { } // namespace v8_inspector extern "C" { -using namespace v8_inspector; - void v8_inspector__Channel__EXTENDER__CTOR(uninit_t& buf) { new (launder(&buf)) Channel__EXTENDER(); } diff --git a/src/v8_inspector/channel.rs b/src/v8_inspector/channel.rs index 1d13d971..9eb8775e 100644 --- a/src/v8_inspector/channel.rs +++ b/src/v8_inspector/channel.rs @@ -1,5 +1,4 @@ -use std::os::raw::c_int; - +use crate::cxx_util::int; use crate::cxx_util::CxxVTable; use crate::cxx_util::FieldOffset; use crate::cxx_util::Opaque; @@ -25,7 +24,7 @@ extern "C" { fn v8_inspector__Channel__sendResponse( this: &mut Channel, - callId: c_int, + callId: int, message: UniquePtr, ) -> (); fn v8_inspector__Channel__sendNotification( @@ -40,7 +39,7 @@ extern "C" { #[no_mangle] pub unsafe extern "C" fn v8_inspector__Channel__EXTENDER__sendResponse( this: &mut Channel, - callId: c_int, + callId: int, message: UniquePtr, ) -> () { ChannelExtender::dispatch_mut(this).sendResponse(callId, message) @@ -69,7 +68,7 @@ pub struct Channel { impl Channel { pub fn sendResponse( &mut self, - callId: c_int, + callId: int, message: UniquePtr, ) -> () { unsafe { v8_inspector__Channel__sendResponse(self, callId, message) } @@ -120,7 +119,7 @@ pub trait ChannelOverrides: AsChannel { fn sendResponse( &mut self, - callId: i32, + callId: int, message: UniquePtr, ) -> (); fn sendNotification(&mut self, message: UniquePtr) -> (); diff --git a/src/v8_inspector/channel.rs.template b/src/v8_inspector/channel.rs.template deleted file mode 100644 index 2b6bd1f9..00000000 --- a/src/v8_inspector/channel.rs.template +++ /dev/null @@ -1,176 +0,0 @@ -use crate::cxx_util::FieldOffset; -use crate::cxx_util::Opaque; -use crate::cxx_util::RustVTable; - -extern "C" { - // Call a method/destructor; virtual methods use C++ dynamic dispatch. - fn v8_inspector__Channel__DTOR(this: &mut Channel) -> (); - fn v8_inspector__Channel__method1(this: &mut Channel, arg: i32) -> (); - fn v8_inspector__Channel__method2(this: &Channel) -> i32; - - // Call a method of a specific class implementation, bypassing dynamic - // dispatch. C++ equivalent: `my_channel.Channel::a()`. - fn v8_inspector__Channel__Channel__method1( - this: &mut Channel, - arg: i32, - ) -> (); - - // Constructs a special class derived from Channel that forwards all - // virtual method invocations to rust. It is assumed that this subclass - // has the same size and memory layout as the class it's deriving from. - fn v8_inspector__Channel__EXTENDER__CTOR( - buf: &mut std::mem::MaybeUninit, - ) -> (); -} - -#[allow(non_snake_case)] -#[no_mangle] -pub unsafe extern "C" fn v8_inspector__Channel__EXTENDER__method1( - this: &mut Channel, - arg: i32, -) { - ChannelExtender::dispatch_mut(this).method1(arg) -} - -#[allow(non_snake_case)] -#[no_mangle] -pub unsafe extern "C" fn v8_inspector__Channel__EXTENDER__method2( - this: &Channel, -) -> i32 { - ChannelExtender::dispatch(this).method2() -} - -#[repr(C)] -pub struct Channel { - _cxx_vtable: *const Opaque, -} - -impl Channel { - pub fn method1(&mut self, arg: i32) { - unsafe { v8_inspector__Channel__method1(self, arg) } - } - pub fn method2(&self) -> i32 { - unsafe { v8_inspector__Channel__method2(self) } - } -} - -impl Drop for Channel { - fn drop(&mut self) { - unsafe { v8_inspector__Channel__DTOR(self) } - } -} - -pub trait AsChannel { - fn as_channel(&self) -> &Channel; - fn as_channel_mut(&mut self) -> &mut Channel; -} - -impl AsChannel for Channel { - fn as_channel(&self) -> &Channel { - self - } - fn as_channel_mut(&mut self) -> &mut Channel { - self - } -} - -impl AsChannel for T -where - T: ChannelOverrides, -{ - fn as_channel(&self) -> &Channel { - &self.extender().cxx_channel - } - fn as_channel_mut(&mut self) -> &mut Channel { - &mut self.extender_mut().cxx_channel - } -} - -pub struct ChannelDefaults; -impl ChannelDefaults { - pub fn method1(channel: &mut Channel, arg: i32) { - unsafe { v8_inspector__Channel__Channel__method1(channel, arg) } - } -} - -pub trait ChannelOverrides: AsChannel { - fn extender(&self) -> &ChannelExtender; - fn extender_mut(&mut self) -> &mut ChannelExtender; - - fn method1(&mut self, arg: i32) { - ChannelDefaults::method1(self.as_channel_mut(), arg) - } - fn method2(&self) -> i32; -} - -pub struct ChannelExtender { - cxx_channel: Channel, - extender_offset: FieldOffset, - rust_vtable: RustVTable<&'static dyn ChannelOverrides>, -} - -impl ChannelExtender { - fn construct_cxx_channel() -> Channel { - unsafe { - let mut buf = std::mem::MaybeUninit::::uninit(); - v8_inspector__Channel__EXTENDER__CTOR(&mut buf); - buf.assume_init() - } - } - - fn get_extender_offset() -> FieldOffset - where - T: ChannelOverrides, - { - let buf = std::mem::MaybeUninit::::uninit(); - let embedder_ptr: *const T = buf.as_ptr(); - let self_ptr: *const Self = unsafe { (*embedder_ptr).extender() }; - FieldOffset::from_ptrs(embedder_ptr, self_ptr) - } - - fn get_rust_vtable() -> RustVTable<&'static dyn ChannelOverrides> - where - T: ChannelOverrides, - { - let buf = std::mem::MaybeUninit::::uninit(); - let embedder_ptr = buf.as_ptr(); - let trait_object: *const dyn ChannelOverrides = 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: ChannelOverrides, - { - Self { - cxx_channel: Self::construct_cxx_channel(), - extender_offset: Self::get_extender_offset::(), - rust_vtable: Self::get_rust_vtable::(), - } - } - - fn get_channel_offset() -> FieldOffset { - let buf = std::mem::MaybeUninit::::uninit(); - FieldOffset::from_ptrs(buf.as_ptr(), unsafe { - &(*buf.as_ptr()).cxx_channel - }) - } - - pub unsafe fn dispatch(channel: &Channel) -> &dyn ChannelOverrides { - let this = Self::get_channel_offset().to_embedder::(channel); - let embedder = this.extender_offset.to_embedder::(this); - std::mem::transmute((embedder, this.rust_vtable)) - } - - pub unsafe fn dispatch_mut( - channel: &mut Channel, - ) -> &mut dyn ChannelOverrides { - let this = Self::get_channel_offset().to_embedder_mut::(channel); - let vtable = this.rust_vtable; - let embedder = this.extender_offset.to_embedder_mut::(this); - std::mem::transmute((embedder, vtable)) - } -} diff --git a/src/v8_inspector/client.h b/src/v8_inspector/client.h new file mode 100644 index 00000000..fa4c7452 --- /dev/null +++ b/src/v8_inspector/client.h @@ -0,0 +1,54 @@ +#include +#include + +using namespace v8_inspector; +using Client = V8InspectorClient; + +extern "C" { +void v8_inspector__Client__EXTENDER__runMessageLoopOnPause(Client& self, + int contextGroupId); +void v8_inspector__Client__EXTENDER__quitMessageLoopOnPause(Client& self); +void v8_inspector__Client__EXTENDER__runIfWaitingForDebugger( + Client& self, + int contextGroupId); + +} // extern "C" + +namespace v8_inspector { +struct Client__EXTENDER : public Client { + using Client::Client; + + void runMessageLoopOnPause(int contextGroupId) override { + v8_inspector__Client__EXTENDER__runMessageLoopOnPause(*this, + contextGroupId); + } + void quitMessageLoopOnPause() override { + v8_inspector__Client__EXTENDER__quitMessageLoopOnPause(*this); + } + void runIfWaitingForDebugger(int contextGroupId) override { + v8_inspector__Client__EXTENDER__runIfWaitingForDebugger(*this, + contextGroupId); + } +}; +} // namespace v8_inspector + +extern "C" { +void v8_inspector__Client__EXTENDER__CTOR(uninit_t& buf) { + new (launder(&buf)) Client__EXTENDER(); +} +void v8_inspector__Client__DTOR(Client& self) { + self.~Client(); +} + +void v8_inspector__Client__runMessageLoopOnPause(Client& self, + int contextGroupId) { + self.runMessageLoopOnPause(contextGroupId); +} +void v8_inspector__Client__quitMessageLoopOnPause(Client& self) { + self.quitMessageLoopOnPause(); +} +void v8_inspector__Client__runIfWaitingForDebugger(Client& self, + int contextGroupId) { + self.runIfWaitingForDebugger(contextGroupId); +} +} // extern "C" \ No newline at end of file diff --git a/src/v8_inspector/client.rs b/src/v8_inspector/client.rs index e69de29b..7ef71d63 100644 --- a/src/v8_inspector/client.rs +++ b/src/v8_inspector/client.rs @@ -0,0 +1,236 @@ +use crate::cxx_util::int; +use crate::cxx_util::CxxVTable; +use crate::cxx_util::FieldOffset; +use crate::cxx_util::Opaque; +use crate::cxx_util::RustVTable; + +// class V8InspectorClient { +// public: +// virtual ~V8InspectorClient() = default; +// +// virtual void runMessageLoopOnPause(int contextGroupId) {} +// virtual void quitMessageLoopOnPause() {} +// virtual void runIfWaitingForDebugger(int contextGroupId) {} +// +// virtual void muteMetrics(int contextGroupId) {} +// virtual void unmuteMetrics(int contextGroupId) {} +// +// virtual void beginUserGesture() {} +// virtual void endUserGesture() {} +// +// virtual std::unique_ptr valueSubtype(v8::Local) { +// return nullptr; +// } +// virtual bool formatAccessorsAsProperties(v8::Local) { +// return false; +// } +// virtual bool isInspectableHeapObject(v8::Local) { +// return true; +// } +// +// virtual v8::Local ensureDefaultContextInGroup( +// int contextGroupId) { +// return v8::Local(); +// } +// virtual void beginEnsureAllContextsInGroup(int contextGroupId) {} +// virtual void endEnsureAllContextsInGroup(int contextGroupId) {} +// +// virtual void installAdditionalCommandLineAPI(v8::Local, +// v8::Local) {} +// virtual void consoleAPIMessage(int contextGroupId, +// v8::Isolate::MessageErrorLevel level, +// const StringView& message, +// const StringView& url, unsigned lineNumber, +// unsigned columnNumber, V8StackTrace*) {} +// virtual v8::MaybeLocal memoryInfo(v8::Isolate*, +// v8::Local) { +// return v8::MaybeLocal(); +// } +// +// virtual void consoleTime(const StringView& title) {} +// virtual void consoleTimeEnd(const StringView& title) {} +// virtual void consoleTimeStamp(const StringView& title) {} +// virtual void consoleClear(int contextGroupId) {} +// virtual double currentTimeMS() { return 0; } +// typedef void (*TimerCallback)(void*); +// virtual void startRepeatingTimer(double, TimerCallback, void* data) {} +// virtual void cancelTimer(void* data) {} +// +// virtual bool canExecuteScripts(int contextGroupId) { return true; } +// +// virtual void maxAsyncCallStackDepthChanged(int depth) {} +// +// virtual std::unique_ptr resourceNameToUrl( +// const StringView& resourceName) { +// return nullptr; +// } +// }; + +extern "C" { + fn v8_inspector__Client__EXTENDER__CTOR( + buf: &mut std::mem::MaybeUninit, + ) -> (); + fn v8_inspector__Client__DTOR(this: &mut Client) -> (); + + fn v8_inspector__Client__runMessageLoopOnPause( + this: &mut Client, + contextGroupId: int, + ) -> (); + fn v8_inspector__Client__quitMessageLoopOnPause(this: &mut Client) -> (); + fn v8_inspector__Client__runIfWaitingForDebugger( + this: &mut Client, + contextGroupId: int, + ) -> (); +} + +#[no_mangle] +pub unsafe extern "C" fn v8_inspector__Client__EXTENDER__runMessageLoopOnPause( + this: &mut Client, + contextGroupId: int, +) -> () { + ClientExtender::dispatch_mut(this).runMessageLoopOnPause(contextGroupId) +} + +#[no_mangle] +pub unsafe extern "C" fn v8_inspector__Client__EXTENDER__quitMessageLoopOnPause( + this: &mut Client, +) -> () { + ClientExtender::dispatch_mut(this).quitMessageLoopOnPause() +} + +#[no_mangle] +pub unsafe extern "C" fn v8_inspector__Client__EXTENDER__runIfWaitingForDebugger( + this: &mut Client, + contextGroupId: int, +) -> () { + ClientExtender::dispatch_mut(this).runIfWaitingForDebugger(contextGroupId) +} + +#[repr(C)] +pub struct Client { + _cxx_vtable: CxxVTable, +} + +impl Client { + pub fn runMessageLoopOnPause(&mut self, contextGroupId: int) -> () { + unsafe { v8_inspector__Client__runMessageLoopOnPause(self, contextGroupId) } + } + pub fn quitMessageLoopOnPause(&mut self) -> () { + unsafe { v8_inspector__Client__quitMessageLoopOnPause(self) } + } + pub fn runIfWaitingForDebugger(&mut self, contextGroupId: int) -> () { + unsafe { + v8_inspector__Client__runIfWaitingForDebugger(self, contextGroupId) + } + } +} + +impl Drop for Client { + fn drop(&mut self) { + unsafe { v8_inspector__Client__DTOR(self) } + } +} + +pub trait AsClient { + fn as_client(&self) -> &Client; + fn as_client_mut(&mut self) -> &mut Client; +} + +impl AsClient for Client { + fn as_client(&self) -> &Client { + self + } + fn as_client_mut(&mut self) -> &mut Client { + self + } +} + +impl AsClient for T +where + T: ClientOverrides, +{ + fn as_client(&self) -> &Client { + &self.extender().cxx_client + } + fn as_client_mut(&mut self) -> &mut Client { + &mut self.extender_mut().cxx_client + } +} + +#[allow(unused_variables)] +pub trait ClientOverrides: AsClient { + fn extender(&self) -> &ClientExtender; + fn extender_mut(&mut self) -> &mut ClientExtender; + + fn runMessageLoopOnPause(&mut self, contextGroupId: int) -> () {} + fn quitMessageLoopOnPause(&mut self) -> () {} + fn runIfWaitingForDebugger(&mut self, contextGroupId: int) -> () {} +} + +pub struct ClientExtender { + cxx_client: Client, + extender_offset: FieldOffset, + rust_vtable: RustVTable<&'static dyn ClientOverrides>, +} + +impl ClientExtender { + fn construct_cxx_client() -> Client { + unsafe { + let mut buf = std::mem::MaybeUninit::::uninit(); + v8_inspector__Client__EXTENDER__CTOR(&mut buf); + buf.assume_init() + } + } + + fn get_extender_offset() -> FieldOffset + where + T: ClientOverrides, + { + let buf = std::mem::MaybeUninit::::uninit(); + let embedder_ptr: *const T = buf.as_ptr(); + let self_ptr: *const Self = unsafe { (*embedder_ptr).extender() }; + FieldOffset::from_ptrs(embedder_ptr, self_ptr) + } + + fn get_rust_vtable() -> RustVTable<&'static dyn ClientOverrides> + where + T: ClientOverrides, + { + let buf = std::mem::MaybeUninit::::uninit(); + let embedder_ptr = buf.as_ptr(); + let trait_object: *const dyn ClientOverrides = 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: ClientOverrides, + { + Self { + cxx_client: Self::construct_cxx_client(), + extender_offset: Self::get_extender_offset::(), + rust_vtable: Self::get_rust_vtable::(), + } + } + + fn get_client_offset() -> FieldOffset { + let buf = std::mem::MaybeUninit::::uninit(); + FieldOffset::from_ptrs(buf.as_ptr(), unsafe { &(*buf.as_ptr()).cxx_client }) + } + + pub unsafe fn dispatch(client: &Client) -> &dyn ClientOverrides { + let this = Self::get_client_offset().to_embedder::(client); + let embedder = this.extender_offset.to_embedder::(this); + std::mem::transmute((embedder, this.rust_vtable)) + } + + pub unsafe fn dispatch_mut(client: &mut Client) -> &mut dyn ClientOverrides { + let this = Self::get_client_offset().to_embedder_mut::(client); + let vtable = this.rust_vtable; + let embedder = this.extender_offset.to_embedder_mut::(this); + std::mem::transmute((embedder, vtable)) + } +} diff --git a/src/v8_inspector/mod.rs b/src/v8_inspector/mod.rs index 3afe82f7..67acf894 100644 --- a/src/v8_inspector/mod.rs +++ b/src/v8_inspector/mod.rs @@ -1,7 +1,9 @@ pub mod channel; +pub mod client; pub mod string_buffer; pub mod string_view; pub use channel::Channel; +pub use client::Client; pub use string_buffer::StringBuffer; pub use string_view::StringView; diff --git a/src/v8_inspector/string_buffer.rs b/src/v8_inspector/string_buffer.rs index a7ebe83f..c1948124 100644 --- a/src/v8_inspector/string_buffer.rs +++ b/src/v8_inspector/string_buffer.rs @@ -28,6 +28,8 @@ pub struct StringBuffer { } impl StringBuffer { + // The C++ class definition does not declare `string()` to be a const method, + // therefore we declare self as mutable here. pub fn string(&mut self) -> &StringView { unsafe { v8_inspector__StringBuffer__string(self) } }