diff --git a/.vscode/settings.json b/.vscode/settings.json index 553eb564..50314abb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,6 @@ { - "C_Cpp.clang_format_style": "Chromium" + "C_Cpp.clang_format_style": "Chromium", + "files.associations": { + "memory": "cpp" + } } \ No newline at end of file diff --git a/src/cxx_util.rs b/src/cxx_util.rs index ec4c282e..95fb9406 100644 --- a/src/cxx_util.rs +++ b/src/cxx_util.rs @@ -13,6 +13,7 @@ where /// Pointer to object allocated on the C++ heap. #[repr(transparent)] +#[derive(Debug)] pub struct UniquePtr(Option<&'static mut T>) where T: Delete; diff --git a/src/lib.cpp b/src/lib.cpp index 1f49cccd..6bbdbe25 100644 --- a/src/lib.cpp +++ b/src/lib.cpp @@ -6,101 +6,13 @@ #include #include +#include "../v8/include/v8-inspector.h" namespace v8_inspector { -class StringView { - public: - StringView() : m_is8Bit(true), m_length(0), m_characters8(nullptr) {} - - StringView(const uint8_t* characters, size_t length) - : m_is8Bit(true), m_length(length), m_characters8(characters) {} - - StringView(const uint16_t* characters, size_t length) - : m_is8Bit(false), m_length(length), m_characters16(characters) {} - - bool is8Bit() const { return m_is8Bit; } - size_t length() const { return m_length; } - - // TODO(dgozman): add DCHECK(m_is8Bit) to accessors once platform can be used - // here. - const uint8_t* characters8() const { return m_characters8; } - const uint16_t* characters16() const { return m_characters16; } - - private: - bool m_is8Bit; - size_t m_length; - union { - const uint8_t* m_characters8; - const uint16_t* m_characters16; - }; -}; - -class StringBuffer { - public: - virtual ~StringBuffer() = default; - virtual const StringView& string() = 0; - // This method copies contents. - static std::unique_ptr create(const StringView&); -}; - -class Channel { - public: - Channel() {} - virtual ~Channel() {} - - virtual void method1(int32_t arg) { - std::cout << "default v8_inspector::Channel::method1(" << arg << ") called" - << std::endl; - } - - virtual int32_t method2() const = 0; -}; -} // namespace v8_inspector - -#include "v8_inspector/string_buffer.h" - -extern "C" { -void v8_inspector__Channel__EXTENDER__method1(v8_inspector::Channel& self, - int32_t arg); -int32_t v8_inspector__Channel__EXTENDER__method2( - const v8_inspector::Channel& self); +using Channel = V8Inspector::Channel; } -namespace extender { template -using uninit_t = typename ::std::aligned_storage::type; +using uninit_t = typename std::aligned_storage::type; -namespace v8_inspector { -struct Channel : public ::v8_inspector::Channel { - using ::v8_inspector::Channel::Channel; - - void method1(int32_t arg) override { - v8_inspector__Channel__EXTENDER__method1(*this, arg); - } - - int32_t method2() const override { - return v8_inspector__Channel__EXTENDER__method2(*this); - } -}; -} // namespace v8_inspector -} // namespace extender - -extern "C" { -void v8_inspector__Channel__DTOR(::v8_inspector::Channel& self) { - self.~Channel(); -} -void v8_inspector__Channel__method1(::v8_inspector::Channel& self, - int32_t arg) { - self.method1(arg); -} -void v8_inspector__Channel__Channel__method1(::v8_inspector::Channel& self, - int32_t arg) { - self.::v8_inspector::Channel::method1(arg); -} -int32_t v8_inspector__Channel__method2(const ::v8_inspector::Channel& self) { - return self.method2(); -} -void v8_inspector__Channel__EXTENDER__CTOR( - ::extender::uninit_t<::extender::v8_inspector::Channel>& buf) { - new (::std::launder(&buf))::extender::v8_inspector::Channel(); -} -} // extern "C" \ No newline at end of file +#include "v8_inspector/channel.h" +#include "v8_inspector/string_buffer.h" diff --git a/src/main.rs b/src/main.rs index b89d35f8..c9a2aab8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,13 @@ #![allow(dead_code)] +#![allow(non_snake_case)] mod cxx_util; mod v8_inspector; mod example { + use crate::cxx_util::UniquePtr; use crate::v8_inspector::channel::*; + use crate::v8_inspector::*; pub struct Example { a: i32, @@ -19,16 +22,11 @@ mod example { fn extender_mut(&mut self) -> &mut ChannelExtender { &mut self.channel_extender } - fn method1(&mut self, arg: i32) { - println!("overriden method1({}) called", arg); - self.a += self.b * arg; - let arg = self.a; - ChannelDefaults::method1(self.as_channel_mut(), arg); - } - fn method2(&self) -> i32 { - println!("overriden method2() called"); - self.a * self.b + fn sendResponse(&mut self, call_id: i32, message: UniquePtr) { + println!("call_id: {:?}, message: '{:?}'", call_id, message); } + fn sendNotification(&mut self, message: UniquePtr) {} + fn flushProtocolNotifications(&mut self) {} } impl Example { @@ -44,9 +42,12 @@ mod example { fn main() { use crate::v8_inspector::channel::*; + use crate::v8_inspector::*; use example::*; let mut ex = Example::new(); let chan = ex.as_channel_mut(); - chan.method1(3); - println!("{}", chan.method2()); + let message = b"hello"; + let message = StringView::from(&message[..]); + let message = StringBuffer::create(&message); + chan.sendResponse(3, message); } diff --git a/src/v8_inspector/channel.rs b/src/v8_inspector/channel.rs index 4595e51f..1d13d971 100644 --- a/src/v8_inspector/channel.rs +++ b/src/v8_inspector/channel.rs @@ -1,44 +1,64 @@ +use std::os::raw::c_int; + use crate::cxx_util::CxxVTable; use crate::cxx_util::FieldOffset; use crate::cxx_util::Opaque; use crate::cxx_util::RustVTable; +use crate::cxx_util::UniquePtr; + +use super::StringBuffer; + +// class Channel { +// public: +// virtual ~Channel() = default; +// virtual void sendResponse(int callId, +// std::unique_ptr message) = 0; +// virtual void sendNotification(std::unique_ptr message) = 0; +// virtual void flushProtocolNotifications() = 0; +// }; 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, ) -> (); + fn v8_inspector__Channel__DTOR(this: &mut Channel) -> (); + + fn v8_inspector__Channel__sendResponse( + this: &mut Channel, + callId: c_int, + message: UniquePtr, + ) -> (); + fn v8_inspector__Channel__sendNotification( + this: &mut Channel, + message: UniquePtr, + ) -> (); + fn v8_inspector__Channel__flushProtocolNotifications( + this: &mut Channel, + ) -> (); } -#[allow(non_snake_case)] #[no_mangle] -pub unsafe extern "C" fn v8_inspector__Channel__EXTENDER__method1( +pub unsafe extern "C" fn v8_inspector__Channel__EXTENDER__sendResponse( this: &mut Channel, - arg: i32, -) { - ChannelExtender::dispatch_mut(this).method1(arg) + callId: c_int, + message: UniquePtr, +) -> () { + ChannelExtender::dispatch_mut(this).sendResponse(callId, message) } -#[allow(non_snake_case)] #[no_mangle] -pub unsafe extern "C" fn v8_inspector__Channel__EXTENDER__method2( - this: &Channel, -) -> i32 { - ChannelExtender::dispatch(this).method2() +pub unsafe extern "C" fn v8_inspector__Channel__EXTENDER__sendNotification( + this: &mut Channel, + message: UniquePtr, +) -> () { + ChannelExtender::dispatch_mut(this).sendNotification(message) +} + +#[no_mangle] +pub unsafe extern "C" fn v8_inspector__Channel__EXTENDER__flushProtocolNotifications( + this: &mut Channel, +) -> () { + ChannelExtender::dispatch_mut(this).flushProtocolNotifications() } #[repr(C)] @@ -47,11 +67,18 @@ pub struct Channel { } impl Channel { - pub fn method1(&mut self, arg: i32) { - unsafe { v8_inspector__Channel__method1(self, arg) } + pub fn sendResponse( + &mut self, + callId: c_int, + message: UniquePtr, + ) -> () { + unsafe { v8_inspector__Channel__sendResponse(self, callId, message) } } - pub fn method2(&self) -> i32 { - unsafe { v8_inspector__Channel__method2(self) } + pub fn sendNotification(&mut self, message: UniquePtr) -> () { + unsafe { v8_inspector__Channel__sendNotification(self, message) } + } + pub fn flushProtocolNotifications(&mut self) -> () { + unsafe { v8_inspector__Channel__flushProtocolNotifications(self) } } } @@ -87,21 +114,17 @@ where } } -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; + fn sendResponse( + &mut self, + callId: i32, + message: UniquePtr, + ) -> (); + fn sendNotification(&mut self, message: UniquePtr) -> (); + fn flushProtocolNotifications(&mut self) -> (); } pub struct ChannelExtender { diff --git a/src/v8_inspector/string_buffer.h b/src/v8_inspector/string_buffer.h index 3458b72c..339316f8 100644 --- a/src/v8_inspector/string_buffer.h +++ b/src/v8_inspector/string_buffer.h @@ -1,16 +1,16 @@ extern "C" { -void v8_inspector__StringBuffer__DELETE(::v8_inspector::StringBuffer& self) { +using namespace v8_inspector; + +void v8_inspector__StringBuffer__DELETE(StringBuffer& self) { delete &self; } -const ::v8_inspector::StringView& v8_inspector__StringBuffer__string( - ::v8_inspector::StringBuffer& self) { +const StringView& v8_inspector__StringBuffer__string(StringBuffer& self) { return self.string(); } -::v8_inspector::StringBuffer* v8_inspector__StringBuffer__create( - const ::v8_inspector::StringView& source) { - return ::v8_inspector::StringBuffer::create(source).release(); +StringBuffer* v8_inspector__StringBuffer__create(const StringView& source) { + return StringBuffer::create(source).release(); } } \ No newline at end of file diff --git a/src/v8_inspector/string_view.rs b/src/v8_inspector/string_view.rs index dd91c96e..4c16bd40 100644 --- a/src/v8_inspector/string_view.rs +++ b/src/v8_inspector/string_view.rs @@ -10,7 +10,7 @@ use std::slice; // same size. TODO: find/open upstream issue to allow #[repr(bool)] support. // ```cpp -// class V8_EXPORT StringView { +// class StringView { // public: // StringView() : m_is8Bit(true), m_length(0), m_characters8(nullptr) {} // @@ -63,7 +63,7 @@ impl<'a> From<&'a [u16]> for StringView<'a> { } impl<'a> StringView<'a> { - pub fn is_8bit(&self) -> bool { + pub fn is8Bit(&self) -> bool { match self { Self::U16(..) => false, Self::U8(..) => true, diff --git a/v8-inspector.h b/v8-inspector.h deleted file mode 100644 index 5f53f21d..00000000 --- a/v8-inspector.h +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_V8_INSPECTOR_H_ -#define V8_V8_INSPECTOR_H_ - -#include -#include - -#include - -#include "v8.h" // NOLINT(build/include) - -namespace v8_inspector { - -namespace protocol { -namespace Debugger { -namespace API { -class SearchMatch; -} -} -namespace Runtime { -namespace API { -class RemoteObject; -class StackTrace; -class StackTraceId; -} -} -namespace Schema { -namespace API { -class Domain; -} -} -} // namespace protocol - -class V8_EXPORT StringView { - public: - StringView() : m_is8Bit(true), m_length(0), m_characters8(nullptr) {} - - StringView(const uint8_t* characters, size_t length) - : m_is8Bit(true), m_length(length), m_characters8(characters) {} - - StringView(const uint16_t* characters, size_t length) - : m_is8Bit(false), m_length(length), m_characters16(characters) {} - - bool is8Bit() const { return m_is8Bit; } - size_t length() const { return m_length; } - - // TODO(dgozman): add DCHECK(m_is8Bit) to accessors once platform can be used - // here. - const uint8_t* characters8() const { return m_characters8; } - const uint16_t* characters16() const { return m_characters16; } - - private: - bool m_is8Bit; - size_t m_length; - union { - const uint8_t* m_characters8; - const uint16_t* m_characters16; - }; -}; - -class V8_EXPORT StringBuffer { - public: - virtual ~StringBuffer() = default; - virtual const StringView& string() = 0; - // This method copies contents. - static std::unique_ptr create(const StringView&); -}; - -class V8_EXPORT V8ContextInfo { - public: - V8ContextInfo(v8::Local context, int contextGroupId, - const StringView& humanReadableName) - : context(context), - contextGroupId(contextGroupId), - humanReadableName(humanReadableName), - hasMemoryOnConsole(false) {} - - v8::Local context; - // Each v8::Context is a part of a group. The group id must be non-zero. - int contextGroupId; - StringView humanReadableName; - StringView origin; - StringView auxData; - bool hasMemoryOnConsole; - - static int executionContextId(v8::Local context); - - // Disallow copying and allocating this one. - enum NotNullTagEnum { NotNullLiteral }; - void* operator new(size_t) = delete; - void* operator new(size_t, NotNullTagEnum, void*) = delete; - void* operator new(size_t, void*) = delete; - V8ContextInfo(const V8ContextInfo&) = delete; - V8ContextInfo& operator=(const V8ContextInfo&) = delete; -}; - -class V8_EXPORT V8StackTrace { - public: - virtual StringView firstNonEmptySourceURL() const = 0; - virtual bool isEmpty() const = 0; - virtual StringView topSourceURL() const = 0; - virtual int topLineNumber() const = 0; - virtual int topColumnNumber() const = 0; - virtual StringView topScriptId() const = 0; - virtual StringView topFunctionName() const = 0; - - virtual ~V8StackTrace() = default; - virtual std::unique_ptr - buildInspectorObject() const = 0; - virtual std::unique_ptr - buildInspectorObject(int maxAsyncDepth) const = 0; - virtual std::unique_ptr toString() const = 0; - - // Safe to pass between threads, drops async chain. - virtual std::unique_ptr clone() = 0; -}; - -class V8_EXPORT V8InspectorSession { - public: - virtual ~V8InspectorSession() = default; - - // Cross-context inspectable values (DOM nodes in different worlds, etc.). - class V8_EXPORT Inspectable { - public: - virtual v8::Local get(v8::Local) = 0; - virtual ~Inspectable() = default; - }; - virtual void addInspectedObject(std::unique_ptr) = 0; - - // Dispatching protocol messages. - static bool canDispatchMethod(const StringView& method); - virtual void dispatchProtocolMessage(const StringView& message) = 0; - virtual std::vector state() = 0; - virtual std::vector> - supportedDomains() = 0; - - // Debugger actions. - virtual void schedulePauseOnNextStatement(const StringView& breakReason, - const StringView& breakDetails) = 0; - virtual void cancelPauseOnNextStatement() = 0; - virtual void breakProgram(const StringView& breakReason, - const StringView& breakDetails) = 0; - virtual void setSkipAllPauses(bool) = 0; - virtual void resume() = 0; - virtual void stepOver() = 0; - virtual std::vector> - searchInTextByLines(const StringView& text, const StringView& query, - bool caseSensitive, bool isRegex) = 0; - - // Remote objects. - virtual std::unique_ptr wrapObject( - v8::Local, v8::Local, const StringView& groupName, - bool generatePreview) = 0; - - virtual bool unwrapObject(std::unique_ptr* error, - const StringView& objectId, v8::Local*, - v8::Local*, - std::unique_ptr* objectGroup) = 0; - virtual void releaseObjectGroup(const StringView&) = 0; -}; - -class V8_EXPORT 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) {} - - // TODO(dgozman): this was added to support service worker shadow page. We - // should not connect at all. - virtual bool canExecuteScripts(int contextGroupId) { return true; } - - virtual void maxAsyncCallStackDepthChanged(int depth) {} - - virtual std::unique_ptr resourceNameToUrl( - const StringView& resourceName) { - return nullptr; - } -}; - -// These stack trace ids are intended to be passed between debuggers and be -// resolved later. This allows to track cross-debugger calls and step between -// them if a single client connects to multiple debuggers. -struct V8_EXPORT V8StackTraceId { - uintptr_t id; - std::pair debugger_id; - bool should_pause = false; - - V8StackTraceId(); - V8StackTraceId(const V8StackTraceId&) = default; - V8StackTraceId(uintptr_t id, const std::pair debugger_id); - V8StackTraceId(uintptr_t id, const std::pair debugger_id, - bool should_pause); - explicit V8StackTraceId(const StringView&); - V8StackTraceId& operator=(const V8StackTraceId&) = default; - V8StackTraceId& operator=(V8StackTraceId&&) noexcept = default; - ~V8StackTraceId() = default; - - bool IsInvalid() const; - std::unique_ptr ToString(); -}; - -class V8_EXPORT V8Inspector { - public: - static std::unique_ptr create(v8::Isolate*, V8InspectorClient*); - virtual ~V8Inspector() = default; - - // Contexts instrumentation. - virtual void contextCreated(const V8ContextInfo&) = 0; - virtual void contextDestroyed(v8::Local) = 0; - virtual void resetContextGroup(int contextGroupId) = 0; - virtual v8::MaybeLocal contextById(int contextId) = 0; - - // Various instrumentation. - virtual void idleStarted() = 0; - virtual void idleFinished() = 0; - - // Async stack traces instrumentation. - virtual void asyncTaskScheduled(const StringView& taskName, void* task, - bool recurring) = 0; - virtual void asyncTaskCanceled(void* task) = 0; - virtual void asyncTaskStarted(void* task) = 0; - virtual void asyncTaskFinished(void* task) = 0; - virtual void allAsyncTasksCanceled() = 0; - - virtual V8StackTraceId storeCurrentStackTrace( - const StringView& description) = 0; - virtual void externalAsyncTaskStarted(const V8StackTraceId& parent) = 0; - virtual void externalAsyncTaskFinished(const V8StackTraceId& parent) = 0; - - // Exceptions instrumentation. - virtual unsigned exceptionThrown( - v8::Local, const StringView& message, - v8::Local exception, const StringView& detailedMessage, - const StringView& url, unsigned lineNumber, unsigned columnNumber, - std::unique_ptr, int scriptId) = 0; - virtual void exceptionRevoked(v8::Local, unsigned exceptionId, - const StringView& message) = 0; - - // Connection. - class V8_EXPORT Channel { - public: - virtual ~Channel() = default; - virtual void sendResponse(int callId, - std::unique_ptr message) = 0; - virtual void sendNotification(std::unique_ptr message) = 0; - virtual void flushProtocolNotifications() = 0; - }; - virtual std::unique_ptr connect( - int contextGroupId, Channel*, const StringView& state) = 0; - - // API methods. - virtual std::unique_ptr createStackTrace( - v8::Local) = 0; - virtual std::unique_ptr captureStackTrace(bool fullStack) = 0; -}; - -} // namespace v8_inspector - -#endif // V8_V8_INSPECTOR_H_