mirror of
https://github.com/denoland/deno.git
synced 2025-09-22 10:22:34 +00:00

Some checks are pending
ci / test debug linux-aarch64 (push) Blocked by required conditions
ci / test release linux-aarch64 (push) Blocked by required conditions
ci / build libs (push) Blocked by required conditions
ci / pre-build (push) Waiting to run
ci / test debug macos-aarch64 (push) Blocked by required conditions
ci / test release macos-aarch64 (push) Blocked by required conditions
ci / lint debug linux-x86_64 (push) Blocked by required conditions
ci / lint debug macos-x86_64 (push) Blocked by required conditions
ci / lint debug windows-x86_64 (push) Blocked by required conditions
ci / test debug macos-x86_64 (push) Blocked by required conditions
ci / test release macos-x86_64 (push) Blocked by required conditions
ci / bench release linux-x86_64 (push) Blocked by required conditions
ci / test debug linux-x86_64 (push) Blocked by required conditions
ci / test release linux-x86_64 (push) Blocked by required conditions
ci / test debug windows-x86_64 (push) Blocked by required conditions
ci / test release windows-x86_64 (push) Blocked by required conditions
ci / publish canary (push) Blocked by required conditions
Based on https://github.com/denoland/deno_core/pull/1193. This commit rewrites 3 parts of the system to use a new "sync" V8 inspector API exposed by `deno_core`: - REPL - coverage collection - hot module replacement Turns out the async abstraction over V8 inspector was unnecessary and actually greatly complicated usage of the inspector. Towards https://github.com/denoland/deno/issues/13572 Towards https://github.com/denoland/deno/issues/13206
184 lines
4.7 KiB
Rust
184 lines
4.7 KiB
Rust
// Copyright 2018-2025 the Deno authors. MIT license.
|
|
|
|
use std::cell::RefCell;
|
|
use std::rc::Rc;
|
|
|
|
use deno_core::GarbageCollected;
|
|
use deno_core::InspectorMsg;
|
|
use deno_core::InspectorSessionKind;
|
|
use deno_core::InspectorSessionOptions;
|
|
use deno_core::JsRuntimeInspector;
|
|
use deno_core::OpState;
|
|
use deno_core::op2;
|
|
use deno_core::v8;
|
|
use deno_error::JsErrorBox;
|
|
|
|
use crate::NodePermissions;
|
|
|
|
#[op2(fast)]
|
|
pub fn op_inspector_enabled() -> bool {
|
|
// TODO: hook up to InspectorServer
|
|
false
|
|
}
|
|
|
|
#[op2(stack_trace)]
|
|
pub fn op_inspector_open<P>(
|
|
_state: &mut OpState,
|
|
_port: Option<u16>,
|
|
#[string] _host: Option<String>,
|
|
) -> Result<(), JsErrorBox>
|
|
where
|
|
P: NodePermissions + 'static,
|
|
{
|
|
// TODO: hook up to InspectorServer
|
|
/*
|
|
let server = state.borrow_mut::<InspectorServer>();
|
|
if let Some(host) = host {
|
|
server.set_host(host);
|
|
}
|
|
if let Some(port) = port {
|
|
server.set_port(port);
|
|
}
|
|
state
|
|
.borrow_mut::<P>()
|
|
.check_net((server.host(), Some(server.port())), "inspector.open")?;
|
|
*/
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[op2(fast)]
|
|
pub fn op_inspector_close() {
|
|
// TODO: hook up to InspectorServer
|
|
}
|
|
|
|
#[op2]
|
|
#[string]
|
|
pub fn op_inspector_url() -> Option<String> {
|
|
// TODO: hook up to InspectorServer
|
|
None
|
|
}
|
|
|
|
#[op2(fast)]
|
|
pub fn op_inspector_wait(state: &OpState) -> bool {
|
|
match state.try_borrow::<Rc<RefCell<JsRuntimeInspector>>>() {
|
|
Some(inspector) => {
|
|
inspector
|
|
.borrow_mut()
|
|
.wait_for_session_and_break_on_next_statement();
|
|
true
|
|
}
|
|
None => false,
|
|
}
|
|
}
|
|
|
|
#[op2(fast)]
|
|
pub fn op_inspector_emit_protocol_event(
|
|
#[string] _event_name: String,
|
|
#[string] _params: String,
|
|
) {
|
|
// TODO: inspector channel & protocol notifications
|
|
}
|
|
|
|
struct JSInspectorSession {
|
|
session: RefCell<Option<deno_core::LocalInspectorSession>>,
|
|
}
|
|
|
|
// SAFETY: we're sure this can be GCed
|
|
unsafe impl GarbageCollected for JSInspectorSession {
|
|
fn trace(&self, _visitor: &mut deno_core::v8::cppgc::Visitor) {}
|
|
|
|
fn get_name(&self) -> &'static std::ffi::CStr {
|
|
c"JSInspectorSession"
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, thiserror::Error, deno_error::JsError)]
|
|
pub enum InspectorConnectError {
|
|
#[class(inherit)]
|
|
#[error(transparent)]
|
|
Permission(
|
|
#[from]
|
|
#[inherit]
|
|
deno_permissions::PermissionCheckError,
|
|
),
|
|
#[class(generic)]
|
|
#[error("connectToMainThread not supported")]
|
|
ConnectToMainThreadUnsupported,
|
|
}
|
|
|
|
#[op2(stack_trace)]
|
|
#[cppgc]
|
|
pub fn op_inspector_connect<'s, P>(
|
|
isolate: *mut v8::Isolate,
|
|
scope: &mut v8::HandleScope<'s>,
|
|
state: &mut OpState,
|
|
connect_to_main_thread: bool,
|
|
callback: v8::Local<'s, v8::Function>,
|
|
) -> Result<JSInspectorSession, InspectorConnectError>
|
|
where
|
|
P: NodePermissions + 'static,
|
|
{
|
|
state
|
|
.borrow_mut::<P>()
|
|
.check_sys("inspector", "inspector.Session.connect")?;
|
|
|
|
if connect_to_main_thread {
|
|
return Err(InspectorConnectError::ConnectToMainThreadUnsupported);
|
|
}
|
|
|
|
let context = scope.get_current_context();
|
|
let context = v8::Global::new(scope, context);
|
|
let callback = v8::Global::new(scope, callback);
|
|
|
|
let inspector = state.borrow::<Rc<RefCell<JsRuntimeInspector>>>().clone();
|
|
|
|
// The inspector connection does not keep the event loop alive but
|
|
// when the inspector sends a message to the frontend, the JS that
|
|
// that runs may keep the event loop alive so we have to call back
|
|
// synchronously, instead of using the usual LocalInspectorSession
|
|
// UnboundedReceiver<InspectorMsg> API.
|
|
let callback = Box::new(move |message: InspectorMsg| {
|
|
// SAFETY: This function is called directly by the inspector, so
|
|
// 1) The isolate is still valid
|
|
// 2) We are on the same thread as the Isolate
|
|
let scope = unsafe { &mut v8::CallbackScope::new(&mut *isolate) };
|
|
let context = v8::Local::new(scope, context.clone());
|
|
let scope = &mut v8::ContextScope::new(scope, context);
|
|
let scope = &mut v8::TryCatch::new(scope);
|
|
let recv = v8::undefined(scope);
|
|
if let Some(message) = v8::String::new(scope, &message.content) {
|
|
let callback = v8::Local::new(scope, callback.clone());
|
|
callback.call(scope, recv.into(), &[message.into()]);
|
|
}
|
|
});
|
|
|
|
let session = JsRuntimeInspector::create_local_session(
|
|
inspector,
|
|
callback,
|
|
InspectorSessionOptions {
|
|
kind: InspectorSessionKind::NonBlocking {
|
|
wait_for_disconnect: false,
|
|
},
|
|
},
|
|
);
|
|
|
|
Ok(JSInspectorSession {
|
|
session: RefCell::new(Some(session)),
|
|
})
|
|
}
|
|
|
|
#[op2(fast)]
|
|
pub fn op_inspector_dispatch(
|
|
#[cppgc] session: &JSInspectorSession,
|
|
#[string] message: String,
|
|
) {
|
|
if let Some(session) = &mut *session.session.borrow_mut() {
|
|
session.dispatch(message);
|
|
}
|
|
}
|
|
|
|
#[op2(fast)]
|
|
pub fn op_inspector_disconnect(#[cppgc] session: &JSInspectorSession) {
|
|
drop(session.session.borrow_mut().take());
|
|
}
|