diff options
author | Simon Wülker <simon.wuelker@arcor.de> | 2024-12-19 00:45:06 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-18 23:45:06 +0000 |
commit | 28e330c9b6bf4edfdb42172968268fba85ceecf5 (patch) | |
tree | 5ca2f3d21d57cc8372d8f38a4333fa8244c1df1b /components | |
parent | ba56494eec49f6d1084e97137aa8be92f72bd65e (diff) | |
download | servo-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.rs | 10 | ||||
-rw-r--r-- | components/devtools/lib.rs | 1 | ||||
-rw-r--r-- | components/script/dom/console.rs | 115 | ||||
-rw-r--r-- | components/script/dom/webidls/Console.webidl | 14 | ||||
-rw-r--r-- | components/shared/devtools/lib.rs | 18 |
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)] |