Skip to content

Commit

Permalink
feat: v8::Inspector::exception_thrown, v8::Inspector::create_stack_tr…
Browse files Browse the repository at this point in the history
…ace (denoland#1149)

Adds APIs required to notify inspector about exceptions raised
by the runtime.
  • Loading branch information
bartlomieju committed Dec 7, 2022
1 parent afe7697 commit 9fc29f4
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 1 deletion.
24 changes: 24 additions & 0 deletions src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2489,6 +2489,30 @@ bool v8_inspector__V8InspectorSession__canDispatchMethod(
return v8_inspector::V8InspectorSession::canDispatchMethod(method);
}

unsigned v8_inspector__V8Inspector__exceptionThrown(
v8_inspector::V8Inspector* self, const v8::Context& context,
v8_inspector::StringView message, const v8::Value& exception,
v8_inspector::StringView detailed_message, v8_inspector::StringView url,
unsigned line_number, unsigned column_number,
v8_inspector::V8StackTrace* stack_trace, int script_id) {
return self->exceptionThrown(
ptr_to_local(&context), message, ptr_to_local(&exception),
detailed_message, url, line_number, column_number,
static_cast<std::unique_ptr<v8_inspector::V8StackTrace>>(stack_trace),
script_id);
}

v8_inspector::V8StackTrace* v8_inspector__V8Inspector__createStackTrace(
v8_inspector::V8Inspector* self, const v8::StackTrace& stack_trace) {
std::unique_ptr<v8_inspector::V8StackTrace> u =
self->createStackTrace(ptr_to_local(&stack_trace));
return u.release();
}

void v8_inspector__V8StackTrace__DELETE(v8_inspector::V8StackTrace* self) {
delete self;
}

void v8_inspector__V8InspectorSession__DELETE(
v8_inspector::V8InspectorSession* self) {
delete self;
Expand Down
66 changes: 66 additions & 0 deletions src/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ use crate::support::UniqueRef;
use crate::Context;
use crate::Isolate;
use crate::Local;
use crate::StackTrace;
use crate::Value;
use std::fmt::{self, Debug, Formatter};

extern "C" {
Expand Down Expand Up @@ -115,6 +117,23 @@ extern "C" {
this: *mut V8Inspector,
context: *const Context,
);
fn v8_inspector__V8Inspector__exceptionThrown(
this: *mut V8Inspector,
context: *const Context,
message: StringView,
exception: *const Value,
detailed_message: StringView,
url: StringView,
line_number: u32,
column_number: u32,
stack_trace: *mut V8StackTrace,
script_id: int,
) -> u32;
fn v8_inspector__V8Inspector__createStackTrace(
this: *mut V8Inspector,
stack_trace: *const StackTrace,
) -> *mut V8StackTrace;
fn v8_inspector__V8StackTrace__DELETE(this: &mut V8StackTrace);
}

#[no_mangle]
Expand Down Expand Up @@ -958,6 +977,47 @@ impl V8Inspector {
pub fn context_destroyed(&mut self, context: Local<Context>) {
unsafe { v8_inspector__V8Inspector__contextDestroyed(self, &*context) }
}

#[allow(clippy::too_many_arguments)]
pub fn exception_thrown(
&mut self,
context: Local<Context>,
message: StringView,
exception: Local<Value>,
detailed_message: StringView,
url: StringView,
line_number: u32,
column_number: u32,
stack_trace: UniquePtr<V8StackTrace>,
script_id: i32,
) -> u32 {
unsafe {
v8_inspector__V8Inspector__exceptionThrown(
self,
&*context,
message,
&*exception,
detailed_message,
url,
line_number,
column_number,
stack_trace.into_raw(),
script_id,
)
}
}

pub fn create_stack_trace(
&mut self,
stack_trace: Local<StackTrace>,
) -> UniquePtr<V8StackTrace> {
unsafe {
UniquePtr::from_raw(v8_inspector__V8Inspector__createStackTrace(
self,
&*stack_trace,
))
}
}
}

impl Drop for V8Inspector {
Expand All @@ -972,5 +1032,11 @@ pub struct V8StackTrace {
_cxx_vtable: CxxVTable,
}

impl Drop for V8StackTrace {
fn drop(&mut self) {
unsafe { v8_inspector__V8StackTrace__DELETE(self) };
}
}

// TODO(bnoordhuis) This needs to be fleshed out more but that can wait
// until it's actually needed.
74 changes: 73 additions & 1 deletion tests/test_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5037,6 +5037,7 @@ struct ChannelCounter {
base: v8::inspector::ChannelBase,
count_send_response: usize,
count_send_notification: usize,
notifications: Vec<String>,
count_flush_protocol_notifications: usize,
}

Expand All @@ -5046,6 +5047,7 @@ impl ChannelCounter {
base: v8::inspector::ChannelBase::new::<Self>(),
count_send_response: 0,
count_send_notification: 0,
notifications: vec![],
count_flush_protocol_notifications: 0,
}
}
Expand Down Expand Up @@ -5074,8 +5076,10 @@ impl v8::inspector::ChannelImpl for ChannelCounter {
&mut self,
message: v8::UniquePtr<v8::inspector::StringBuffer>,
) {
println!("send_notification message {}", message.unwrap().string());
let msg = message.unwrap().string().to_string();
println!("send_notification message {}", msg);
self.count_send_notification += 1;
self.notifications.push(msg);
}
fn flush_protocol_notifications(&mut self) {
self.count_flush_protocol_notifications += 1;
Expand Down Expand Up @@ -5165,6 +5169,74 @@ fn inspector_dispatch_protocol_message() {
inspector.context_destroyed(context);
}

#[test]
fn inspector_exception_thrown() {
let _setup_guard = setup();
let isolate = &mut v8::Isolate::new(Default::default());

use v8::inspector::*;
let mut default_client = ClientCounter::new();
let mut inspector = V8Inspector::create(isolate, &mut default_client);

let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let mut context_scope = v8::ContextScope::new(scope, context);

let name = b"";
let name_view = StringView::from(&name[..]);
let aux_data = b"";
let aux_data_view = StringView::from(&aux_data[..]);
inspector.context_created(context, 1, name_view, aux_data_view);
let mut channel = ChannelCounter::new();
let state = b"{}";
let state_view = StringView::from(&state[..]);
let mut session = inspector.connect(
1,
&mut channel,
state_view,
V8InspectorClientTrustLevel::Untrusted,
);
let message = String::from(r#"{"id":1,"method":"Runtime.enable"}"#);
let message = &message.into_bytes()[..];
let string_view = StringView::from(message);
session.dispatch_protocol_message(string_view);
assert_eq!(channel.count_send_response, 1);
assert_eq!(channel.count_send_notification, 1);
assert_eq!(channel.count_flush_protocol_notifications, 0);

let message = "test exception".to_string();
let message = &message.into_bytes()[..];
let message_string_view = StringView::from(message);
let detailed_message = "detailed message".to_string();
let detailed_message = &detailed_message.into_bytes()[..];
let detailed_message_string_view = StringView::from(detailed_message);
let url = "file:https://exception.js".to_string();
let url = &url.into_bytes()[..];
let url_string_view = StringView::from(url);
let exception_msg =
v8::String::new(&mut context_scope, "This is a test error").unwrap();
let exception = v8::Exception::error(&mut context_scope, exception_msg);
let stack_trace =
v8::Exception::get_stack_trace(&mut context_scope, exception).unwrap();
let stack_trace_ptr = inspector.create_stack_trace(stack_trace);
let _id = inspector.exception_thrown(
context,
message_string_view,
exception,
detailed_message_string_view,
url_string_view,
1,
1,
stack_trace_ptr,
1,
);

assert_eq!(channel.count_send_notification, 2);
let notification = channel.notifications.get(1).unwrap().clone();
let expected_notification = "{\"method\":\"Runtime.exceptionThrown\",\"params\":{\"timestamp\":0,\"exceptionDetails\":{\"exceptionId\":1,\"text\":\"test exception\",\"lineNumber\":0,\"columnNumber\":0,\"scriptId\":\"1\",\"url\":\"file:https://exception.js\",\"exception\":{\"type\":\"object\",\"subtype\":\"error\",\"className\":\"Error\",\"description\":\"Error: This is a test error\",\"objectId\":\"1.1.1\",\"preview\":{\"type\":\"object\",\"subtype\":\"error\",\"description\":\"Error: This is a test error\",\"overflow\":false,\"properties\":[{\"name\":\"stack\",\"type\":\"string\",\"value\":\"Error: This is a test error\"},{\"name\":\"message\",\"type\":\"string\",\"value\":\"This is a test error\"}]}},\"executionContextId\":1}}}";
assert_eq!(notification, expected_notification);
}

#[test]
fn inspector_schedule_pause_on_next_statement() {
let _setup_guard = setup();
Expand Down

0 comments on commit 9fc29f4

Please sign in to comment.