aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorSimon Wülker <simon.wuelker@arcor.de>2024-12-19 00:45:06 +0100
committerGitHub <noreply@github.com>2024-12-18 23:45:06 +0000
commit28e330c9b6bf4edfdb42172968268fba85ceecf5 (patch)
tree5ca2f3d21d57cc8372d8f38a4333fa8244c1df1b /components
parentba56494eec49f6d1084e97137aa8be92f72bd65e (diff)
downloadservo-28e330c9b6bf4edfdb42172968268fba85ceecf5.tar.gz
servo-28e330c9b6bf4edfdb42172968268fba85ceecf5.zip
Implement `console.trace` (#34629)
* Include unimplemented console methods in idl file Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Fix console.assert signature The condition is optional and there can be multiple messages. Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Implement console.trace Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * ./mach fmt Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Log stack trace when calling console.trace Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Update wpt expectations Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Include line/column info in console.trace logs Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Move option out of constant Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> * Update mozjs Signed-off-by: Simon Wülker <simon.wuelker@arcor.de> --------- Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
Diffstat (limited to 'components')
-rw-r--r--components/devtools/actors/console.rs10
-rw-r--r--components/devtools/lib.rs1
-rw-r--r--components/script/dom/console.rs115
-rw-r--r--components/script/dom/webidls/Console.webidl14
-rw-r--r--components/shared/devtools/lib.rs18
5 files changed, 134 insertions, 24 deletions
diff --git a/components/devtools/actors/console.rs b/components/devtools/actors/console.rs
index 09666efc2f3..bf949d9219c 100644
--- a/components/devtools/actors/console.rs
+++ b/components/devtools/actors/console.rs
@@ -278,20 +278,22 @@ impl ConsoleActor {
LogLevel::Warn => "warn",
LogLevel::Error => "error",
LogLevel::Clear => "clear",
- _ => "log",
+ LogLevel::Trace => "trace",
+ LogLevel::Log => "log",
}
.to_owned();
let console_api = ConsoleLog {
- level: level.clone(),
- filename: console_message.filename.clone(),
+ level,
+ filename: console_message.filename,
line_number: console_message.line_number as u32,
column_number: console_message.column_number as u32,
time_stamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64,
- arguments: vec![console_message.message.clone()],
+ arguments: vec![console_message.message],
+ stacktrace: console_message.stacktrace,
};
self.cached_events
diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs
index d5802ad7154..f6d5576a355 100644
--- a/components/devtools/lib.rs
+++ b/components/devtools/lib.rs
@@ -694,6 +694,7 @@ fn run_server(
filename: css_error.filename,
line_number: css_error.line as usize,
column_number: css_error.column as usize,
+ stacktrace: vec![],
};
handle_console_message(
actors.clone(),
diff --git a/components/script/dom/console.rs b/components/script/dom/console.rs
index 7effcababd6..9e1c9e56abe 100644
--- a/components/script/dom/console.rs
+++ b/components/script/dom/console.rs
@@ -3,16 +3,16 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::convert::TryFrom;
-use std::io;
+use std::{io, ptr};
-use devtools_traits::{ConsoleMessage, LogLevel, ScriptToDevtoolsControlMsg};
+use devtools_traits::{ConsoleMessage, LogLevel, ScriptToDevtoolsControlMsg, StackFrame};
use js::jsapi::{self, ESClass, PropertyDescriptor};
use js::jsval::UndefinedValue;
use js::rust::wrappers::{
GetBuiltinClass, GetPropertyKeys, JS_GetOwnPropertyDescriptorById, JS_GetPropertyById,
JS_IdToValue, JS_ValueToSource,
};
-use js::rust::{describe_scripted_caller, HandleValue, IdVector};
+use js::rust::{describe_scripted_caller, CapturedJSStack, HandleValue, IdVector};
use crate::dom::bindings::codegen::Bindings::ConsoleBinding::consoleMethods;
use crate::dom::bindings::conversions::jsstring_to_str;
@@ -27,8 +27,8 @@ const MAX_LOG_DEPTH: usize = 10;
/// The maximum elements in an object logged by console methods.
const MAX_LOG_CHILDREN: usize = 15;
-// https://developer.mozilla.org/en-US/docs/Web/API/Console
-pub struct Console(());
+/// <https://developer.mozilla.org/en-US/docs/Web/API/Console>
+pub struct Console;
impl Console {
#[allow(unsafe_code)]
@@ -36,12 +36,14 @@ impl Console {
if let Some(chan) = global.devtools_chan() {
let caller =
unsafe { describe_scripted_caller(*GlobalScope::get_cx()) }.unwrap_or_default();
+
let console_message = ConsoleMessage {
message,
log_level: level,
filename: caller.filename,
line_number: caller.line as usize,
column_number: caller.col as usize,
+ stacktrace: get_js_stack(*GlobalScope::get_cx()),
};
let worker_id = global
.downcast::<WorkerGlobalScope>()
@@ -259,17 +261,20 @@ impl consoleMethods<crate::DomTypeHolder> for Console {
console_messages(global, messages, LogLevel::Error)
}
+ /// <https://console.spec.whatwg.org/#trace>
+ fn Trace(_cx: JSContext, global: &GlobalScope, messages: Vec<HandleValue>) {
+ console_messages(global, messages, LogLevel::Trace)
+ }
+
// https://developer.mozilla.org/en-US/docs/Web/API/Console/assert
- fn Assert(_cx: JSContext, global: &GlobalScope, condition: bool, message: HandleValue) {
+ fn Assert(_cx: JSContext, global: &GlobalScope, condition: bool, messages: Vec<HandleValue>) {
if !condition {
- let message = if message.is_undefined() {
- DOMString::from("no message")
- } else {
- stringify_handle_value(message)
- };
- let message = DOMString::from(format!("Assertion failed: {}", message));
- console_message(global, message, LogLevel::Error)
- };
+ let message = DOMString::from(format!(
+ "Assertion failed: {}",
+ stringify_handle_values(messages)
+ ));
+ console_message(global, message, LogLevel::Error);
+ }
}
// https://console.spec.whatwg.org/#time
@@ -331,3 +336,85 @@ impl consoleMethods<crate::DomTypeHolder> for Console {
}
}
}
+
+#[allow(unsafe_code)]
+fn get_js_stack(cx: *mut jsapi::JSContext) -> Vec<StackFrame> {
+ const MAX_FRAME_COUNT: u32 = 128;
+
+ let mut frames = vec![];
+ rooted!(in(cx) let mut handle = ptr::null_mut());
+ let captured_js_stack = unsafe { CapturedJSStack::new(cx, handle, Some(MAX_FRAME_COUNT)) };
+ let Some(captured_js_stack) = captured_js_stack else {
+ return frames;
+ };
+
+ captured_js_stack.for_each_stack_frame(|frame| {
+ rooted!(in(cx) let mut result: *mut jsapi::JSString = ptr::null_mut());
+
+ // Get function name
+ unsafe {
+ jsapi::GetSavedFrameFunctionDisplayName(
+ cx,
+ ptr::null_mut(),
+ frame.into(),
+ result.handle_mut().into(),
+ jsapi::SavedFrameSelfHosted::Include,
+ );
+ }
+ let function_name = if let Some(nonnull_result) = ptr::NonNull::new(*result) {
+ unsafe { jsstring_to_str(cx, nonnull_result) }.into()
+ } else {
+ "<anonymous>".into()
+ };
+
+ // Get source file name
+ result.set(ptr::null_mut());
+ unsafe {
+ jsapi::GetSavedFrameSource(
+ cx,
+ ptr::null_mut(),
+ frame.into(),
+ result.handle_mut().into(),
+ jsapi::SavedFrameSelfHosted::Include,
+ );
+ }
+ let filename = if let Some(nonnull_result) = ptr::NonNull::new(*result) {
+ unsafe { jsstring_to_str(cx, nonnull_result) }.into()
+ } else {
+ "<anonymous>".into()
+ };
+
+ // get line/column number
+ let mut line_number = 0;
+ unsafe {
+ jsapi::GetSavedFrameLine(
+ cx,
+ ptr::null_mut(),
+ frame.into(),
+ &mut line_number,
+ jsapi::SavedFrameSelfHosted::Include,
+ );
+ }
+
+ let mut column_number = jsapi::JS::TaggedColumnNumberOneOrigin { value_: 0 };
+ unsafe {
+ jsapi::GetSavedFrameColumn(
+ cx,
+ ptr::null_mut(),
+ frame.into(),
+ &mut column_number,
+ jsapi::SavedFrameSelfHosted::Include,
+ );
+ }
+ let frame = StackFrame {
+ filename,
+ function_name,
+ line_number,
+ column_number: column_number.value_,
+ };
+
+ frames.push(frame);
+ });
+
+ frames
+}
diff --git a/components/script/dom/webidls/Console.webidl b/components/script/dom/webidls/Console.webidl
index b6d2d91fd14..2565b6a409c 100644
--- a/components/script/dom/webidls/Console.webidl
+++ b/components/script/dom/webidls/Console.webidl
@@ -5,16 +5,20 @@
// https://console.spec.whatwg.org/
[ClassString="Console",
- Exposed=(Window,Worker,Worklet)]
+ Exposed=*]
namespace console {
// Logging
- undefined log(any... messages);
+ undefined assert(optional boolean condition = false, any... data);
+ undefined clear();
undefined debug(any... messages);
+ undefined error(any... messages);
undefined info(any... messages);
+ undefined log(any... messages);
+ // undefined table(optional any tabularData, optional sequence<DOMString> properties);
+ undefined trace(any... data);
undefined warn(any... messages);
- undefined error(any... messages);
- undefined assert(boolean condition, optional any message);
- undefined clear();
+ // undefined dir(optional any item, optional object? options);
+ // undefined dirxml(any... data);
// Counting
undefined count(optional DOMString label = "default");
diff --git a/components/shared/devtools/lib.rs b/components/shared/devtools/lib.rs
index 29b5a8b0aff..4f26ba7c236 100644
--- a/components/shared/devtools/lib.rs
+++ b/components/shared/devtools/lib.rs
@@ -280,6 +280,7 @@ pub enum LogLevel {
Warn,
Error,
Clear,
+ Trace,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
@@ -290,6 +291,21 @@ pub struct ConsoleMessage {
pub filename: String,
pub line_number: usize,
pub column_number: usize,
+ pub stacktrace: Vec<StackFrame>,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct StackFrame {
+ pub filename: String,
+
+ #[serde(rename = "functionName")]
+ pub function_name: String,
+
+ #[serde(rename = "columnNumber")]
+ pub column_number: u32,
+
+ #[serde(rename = "lineNumber")]
+ pub line_number: u32,
}
bitflags! {
@@ -327,7 +343,7 @@ pub struct ConsoleLog {
pub column_number: u32,
pub time_stamp: u64,
pub arguments: Vec<String>,
- // pub stacktrace: Vec<...>,
+ pub stacktrace: Vec<StackFrame>,
}
#[derive(Debug, Deserialize, Serialize)]