diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/Cargo.toml | 3 | ||||
-rw-r--r-- | components/script/dom/bindings/error.rs | 30 | ||||
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 28 | ||||
-rw-r--r-- | components/script/lib.rs | 2 |
4 files changed, 60 insertions, 3 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 1c8feb0f17e..ca859bb472a 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -16,6 +16,8 @@ debugmozjs = ['mozjs/debugmozjs'] unstable = [] unrooted_must_root_lint = ["script_plugins/unrooted_must_root_lint"] default = ["unrooted_must_root_lint"] +webgl_backtrace = ["backtrace", "canvas_traits/webgl_backtrace"] +js_backtrace = ["backtrace"] [build-dependencies] cmake = "0.1" @@ -29,6 +31,7 @@ tinyfiledialogs = "3.0" [dependencies] app_units = "0.7" audio-video-metadata = "0.1.4" +backtrace = {version = "0.3", optional = true} base64 = "0.6" bitflags = "1.0" bluetooth_traits = {path = "../bluetooth_traits"} diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index ce045b2c9d3..64b581f316d 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -4,6 +4,10 @@ //! Utilities to throw exceptions from Rust bindings. +#[cfg(feature = "js_backtrace")] +use backtrace::Backtrace; +#[cfg(feature = "js_backtrace")] +use dom::bindings::cell::DomRefCell; use dom::bindings::codegen::Bindings::DOMExceptionBinding::DOMExceptionMethods; use dom::bindings::codegen::PrototypeList::proto_id_to_name; use dom::bindings::conversions::{ConversionResult, FromJSValConvertible, ToJSValConvertible}; @@ -24,6 +28,11 @@ use js::rust::wrappers::JS_SetPendingException; use libc::c_uint; use std::slice::from_raw_parts; +/// An optional stringified JS backtrace and stringified native backtrace from the +/// the last DOM exception that was reported. +#[cfg(feature = "js_backtrace")] +thread_local!(static LAST_EXCEPTION_BACKTRACE: DomRefCell<Option<(Option<String>, String)>> = DomRefCell::new(None)); + /// DOM exceptions that can be thrown by a native DOM method. #[derive(Clone, Debug, MallocSizeOf)] pub enum Error { @@ -90,6 +99,16 @@ pub type ErrorResult = Fallible<()>; /// Set a pending exception for the given `result` on `cx`. pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: &GlobalScope, result: Error) { + #[cfg(feature = "js_backtrace")] + { + capture_stack!(in(cx) let stack); + let js_stack = stack.and_then(|s| s.as_string(None)); + let rust_stack = Backtrace::new(); + LAST_EXCEPTION_BACKTRACE.with(|backtrace| { + *backtrace.borrow_mut() = Some((js_stack, format!("{:?}", rust_stack))); + }); + } + let code = match result { Error::IndexSize => DOMErrorName::IndexSizeError, Error::NotFound => DOMErrorName::NotFoundError, @@ -244,6 +263,17 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool) "Error at {}:{}:{} {}", error_info.filename, error_info.lineno, error_info.column, error_info.message ); + #[cfg(feature = "js_backtrace")] + { + LAST_EXCEPTION_BACKTRACE.with(|backtrace| { + if let Some((js_backtrace, rust_backtrace)) = backtrace.borrow_mut().take() { + if let Some(stack) = js_backtrace { + eprintln!("JS backtrace:\n{}", stack); + } + eprintln!("Rust backtrace:\n{}", rust_backtrace); + } + }); + } if dispatch_event { GlobalScope::from_context(cx).report_an_error(error_info, value.handle()); diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 7367a38fdcf..754637ad52b 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -2,9 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#[cfg(feature = "webgl_backtrace")] +use backtrace::Backtrace; use byteorder::{ByteOrder, NativeEndian, WriteBytesExt}; use canvas_traits::canvas::{byte_swap, multiply_u8_pixel}; -use canvas_traits::webgl::{DOMToTextureCommand, Parameter}; +use canvas_traits::webgl::{DOMToTextureCommand, Parameter, WebGLCommandBacktrace}; use canvas_traits::webgl::{TexParameter, WebGLCommand, WebGLContextShareMode, WebGLError}; use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender}; use canvas_traits::webgl::{WebGLProgramId, WebGLResult, WebGLSLVersion, WebGLSender}; @@ -316,7 +318,7 @@ impl WebGLRenderingContext { #[inline] pub fn send_command(&self, command: WebGLCommand) { - self.webgl_sender.send(command).unwrap(); + self.webgl_sender.send(command, capture_webgl_backtrace(self)).unwrap(); } #[inline] @@ -1189,6 +1191,25 @@ impl WebGLRenderingContext { } } +#[cfg(not(feature = "webgl_backtrace"))] +#[inline] +pub fn capture_webgl_backtrace<T: DomObject>(_: &T) -> WebGLCommandBacktrace { + WebGLCommandBacktrace {} +} + +#[cfg(feature = "webgl_backtrace")] +#[cfg_attr(feature = "webgl_backtrace", allow(unsafe_code))] +pub fn capture_webgl_backtrace<T: DomObject>(obj: &T) -> WebGLCommandBacktrace { + let bt = Backtrace::new(); + unsafe { + capture_stack!(in(obj.global().get_cx()) let stack); + WebGLCommandBacktrace { + backtrace: format!("{:?}", bt), + js_backtrace: stack.and_then(|s| s.as_string(None)), + } + } +} + impl Drop for WebGLRenderingContext { fn drop(&mut self) { let _ = self.webgl_sender.send_remove(); @@ -1521,9 +1542,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { let (sender, receiver) = webgl_channel().unwrap(); // If the send does not succeed, assume context lost + let backtrace = capture_webgl_backtrace(self); if self .webgl_sender - .send(WebGLCommand::GetContextAttributes(sender)) + .send(WebGLCommand::GetContextAttributes(sender), backtrace) .is_err() { return None; diff --git a/components/script/lib.rs b/components/script/lib.rs index f8341323466..097f69d7808 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -19,6 +19,8 @@ extern crate app_units; extern crate audio_video_metadata; +#[cfg(any(feature = "webgl_backtrace", feature = "js_backtrace"))] +extern crate backtrace; extern crate base64; #[macro_use] extern crate bitflags; |