mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Auto merge of #21825 - jdm:backtrace-helpers, r=Manishearth
Optional backtraces for JS errors and WebGL errors This adds two new build-time features to enable useful debugging tools when investigating why JS and WebGL content isn't working. They're optional because they're quite heavyweight. --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes do not require tests because they're optional developer features. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21825) <!-- Reviewable:end -->
This commit is contained in:
commit
57053e03bb
16 changed files with 131 additions and 16 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2981,6 +2981,7 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"audio-video-metadata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"audio-video-metadata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bluetooth_traits 0.0.1",
|
"bluetooth_traits 0.0.1",
|
||||||
|
|
|
@ -9,6 +9,9 @@ publish = false
|
||||||
name = "canvas"
|
name = "canvas"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
webgl_backtrace = ["canvas_traits/webgl_backtrace"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
azure = {git = "https://github.com/servo/rust-azure"}
|
azure = {git = "https://github.com/servo/rust-azure"}
|
||||||
canvas_traits = {path = "../canvas_traits"}
|
canvas_traits = {path = "../canvas_traits"}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use canvas_traits::webgl::{WebGLCommand, WebGLVersion};
|
use canvas_traits::webgl::{WebGLCommand, WebGLVersion, WebGLCommandBacktrace};
|
||||||
use compositing::compositor_thread::{CompositorProxy, self};
|
use compositing::compositor_thread::{CompositorProxy, self};
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
use gleam::gl;
|
use gleam::gl;
|
||||||
|
@ -144,13 +144,18 @@ impl GLContextWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_command(&self, cmd: WebGLCommand, state: &mut GLState) {
|
pub fn apply_command(
|
||||||
|
&self,
|
||||||
|
cmd: WebGLCommand,
|
||||||
|
backtrace: WebGLCommandBacktrace,
|
||||||
|
state: &mut GLState
|
||||||
|
) {
|
||||||
match *self {
|
match *self {
|
||||||
GLContextWrapper::Native(ref ctx) => {
|
GLContextWrapper::Native(ref ctx) => {
|
||||||
WebGLImpl::apply(ctx, state, cmd);
|
WebGLImpl::apply(ctx, state, cmd, backtrace);
|
||||||
}
|
}
|
||||||
GLContextWrapper::OSMesa(ref ctx) => {
|
GLContextWrapper::OSMesa(ref ctx) => {
|
||||||
WebGLImpl::apply(ctx, state, cmd);
|
WebGLImpl::apply(ctx, state, cmd, backtrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,8 +137,8 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
|
||||||
WebGLMsg::RemoveContext(ctx_id) => {
|
WebGLMsg::RemoveContext(ctx_id) => {
|
||||||
self.remove_webgl_context(ctx_id);
|
self.remove_webgl_context(ctx_id);
|
||||||
},
|
},
|
||||||
WebGLMsg::WebGLCommand(ctx_id, command) => {
|
WebGLMsg::WebGLCommand(ctx_id, command, backtrace) => {
|
||||||
self.handle_webgl_command(ctx_id, command);
|
self.handle_webgl_command(ctx_id, command, backtrace);
|
||||||
},
|
},
|
||||||
WebGLMsg::WebVRCommand(ctx_id, command) => {
|
WebGLMsg::WebVRCommand(ctx_id, command) => {
|
||||||
self.handle_webvr_command(ctx_id, command);
|
self.handle_webvr_command(ctx_id, command);
|
||||||
|
@ -164,10 +164,15 @@ impl<VR: WebVRRenderHandler + 'static> WebGLThread<VR> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles a WebGLCommand for a specific WebGLContext
|
/// Handles a WebGLCommand for a specific WebGLContext
|
||||||
fn handle_webgl_command(&mut self, context_id: WebGLContextId, command: WebGLCommand) {
|
fn handle_webgl_command(
|
||||||
|
&mut self,
|
||||||
|
context_id: WebGLContextId,
|
||||||
|
command: WebGLCommand,
|
||||||
|
backtrace: WebGLCommandBacktrace,
|
||||||
|
) {
|
||||||
let data = Self::make_current_if_needed_mut(context_id, &mut self.contexts, &mut self.bound_context_id);
|
let data = Self::make_current_if_needed_mut(context_id, &mut self.contexts, &mut self.bound_context_id);
|
||||||
if let Some(data) = data {
|
if let Some(data) = data {
|
||||||
data.ctx.apply_command(command, &mut data.state);
|
data.ctx.apply_command(command, backtrace, &mut data.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,7 +677,8 @@ impl WebGLImpl {
|
||||||
pub fn apply<Native: NativeGLContextMethods>(
|
pub fn apply<Native: NativeGLContextMethods>(
|
||||||
ctx: &GLContext<Native>,
|
ctx: &GLContext<Native>,
|
||||||
state: &mut GLState,
|
state: &mut GLState,
|
||||||
command: WebGLCommand
|
command: WebGLCommand,
|
||||||
|
_backtrace: WebGLCommandBacktrace,
|
||||||
) {
|
) {
|
||||||
match command {
|
match command {
|
||||||
WebGLCommand::GetContextAttributes(ref sender) =>
|
WebGLCommand::GetContextAttributes(ref sender) =>
|
||||||
|
@ -1193,7 +1199,14 @@ impl WebGLImpl {
|
||||||
// TODO: update test expectations in order to enable debug assertions
|
// TODO: update test expectations in order to enable debug assertions
|
||||||
let error = ctx.gl().get_error();
|
let error = ctx.gl().get_error();
|
||||||
if error != gl::NO_ERROR {
|
if error != gl::NO_ERROR {
|
||||||
error!("Last GL operation failed: {:?}", command)
|
error!("Last GL operation failed: {:?}", command);
|
||||||
|
#[cfg(feature = "webgl_backtrace")]
|
||||||
|
{
|
||||||
|
error!("Backtrace from failed WebGL API:\n{}", _backtrace.backtrace);
|
||||||
|
if let Some(backtrace) = _backtrace.js_backtrace {
|
||||||
|
error!("JS backtrace from failed WebGL API:\n{}", backtrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
assert_eq!(error, gl::NO_ERROR, "Unexpected WebGL error: 0x{:x} ({})", error, error);
|
assert_eq!(error, gl::NO_ERROR, "Unexpected WebGL error: 0x{:x} ({})", error, error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,9 @@ publish = false
|
||||||
name = "canvas_traits"
|
name = "canvas_traits"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
webgl_backtrace = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cssparser = "0.24.0"
|
cssparser = "0.24.0"
|
||||||
euclid = "0.19"
|
euclid = "0.19"
|
||||||
|
|
|
@ -24,6 +24,14 @@ pub use ::webgl_channel::WebGLPipeline;
|
||||||
/// Entry point channel type used for sending WebGLMsg messages to the WebGL renderer.
|
/// Entry point channel type used for sending WebGLMsg messages to the WebGL renderer.
|
||||||
pub use ::webgl_channel::WebGLChan;
|
pub use ::webgl_channel::WebGLChan;
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize, Serialize)]
|
||||||
|
pub struct WebGLCommandBacktrace {
|
||||||
|
#[cfg(feature = "webgl_backtrace")]
|
||||||
|
pub backtrace: String,
|
||||||
|
#[cfg(feature = "webgl_backtrace")]
|
||||||
|
pub js_backtrace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
/// WebGL Message API
|
/// WebGL Message API
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub enum WebGLMsg {
|
pub enum WebGLMsg {
|
||||||
|
@ -35,7 +43,7 @@ pub enum WebGLMsg {
|
||||||
/// Drops a WebGLContext.
|
/// Drops a WebGLContext.
|
||||||
RemoveContext(WebGLContextId),
|
RemoveContext(WebGLContextId),
|
||||||
/// Runs a WebGLCommand in a specific WebGLContext.
|
/// Runs a WebGLCommand in a specific WebGLContext.
|
||||||
WebGLCommand(WebGLContextId, WebGLCommand),
|
WebGLCommand(WebGLContextId, WebGLCommand, WebGLCommandBacktrace),
|
||||||
/// Runs a WebVRCommand in a specific WebGLContext.
|
/// Runs a WebVRCommand in a specific WebGLContext.
|
||||||
WebVRCommand(WebGLContextId, WebVRCommand),
|
WebVRCommand(WebGLContextId, WebVRCommand),
|
||||||
/// Locks a specific WebGLContext. Lock messages are used for a correct synchronization
|
/// Locks a specific WebGLContext. Lock messages are used for a correct synchronization
|
||||||
|
@ -121,8 +129,8 @@ impl WebGLMsgSender {
|
||||||
|
|
||||||
/// Send a WebGLCommand message
|
/// Send a WebGLCommand message
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn send(&self, command: WebGLCommand) -> WebGLSendResult {
|
pub fn send(&self, command: WebGLCommand, backtrace: WebGLCommandBacktrace) -> WebGLSendResult {
|
||||||
self.sender.send(WebGLMsg::WebGLCommand(self.ctx_id, command))
|
self.sender.send(WebGLMsg::WebGLCommand(self.ctx_id, command, backtrace))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a WebVRCommand message
|
/// Send a WebVRCommand message
|
||||||
|
|
|
@ -16,6 +16,8 @@ debugmozjs = ['mozjs/debugmozjs']
|
||||||
unstable = []
|
unstable = []
|
||||||
unrooted_must_root_lint = ["script_plugins/unrooted_must_root_lint"]
|
unrooted_must_root_lint = ["script_plugins/unrooted_must_root_lint"]
|
||||||
default = ["unrooted_must_root_lint"]
|
default = ["unrooted_must_root_lint"]
|
||||||
|
webgl_backtrace = ["backtrace", "canvas_traits/webgl_backtrace"]
|
||||||
|
js_backtrace = ["backtrace"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cmake = "0.1"
|
cmake = "0.1"
|
||||||
|
@ -29,6 +31,7 @@ tinyfiledialogs = "3.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
app_units = "0.7"
|
app_units = "0.7"
|
||||||
audio-video-metadata = "0.1.4"
|
audio-video-metadata = "0.1.4"
|
||||||
|
backtrace = {version = "0.3", optional = true}
|
||||||
base64 = "0.6"
|
base64 = "0.6"
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
bluetooth_traits = {path = "../bluetooth_traits"}
|
bluetooth_traits = {path = "../bluetooth_traits"}
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
|
|
||||||
//! Utilities to throw exceptions from Rust bindings.
|
//! 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::Bindings::DOMExceptionBinding::DOMExceptionMethods;
|
||||||
use dom::bindings::codegen::PrototypeList::proto_id_to_name;
|
use dom::bindings::codegen::PrototypeList::proto_id_to_name;
|
||||||
use dom::bindings::conversions::{ConversionResult, FromJSValConvertible, ToJSValConvertible};
|
use dom::bindings::conversions::{ConversionResult, FromJSValConvertible, ToJSValConvertible};
|
||||||
|
@ -24,6 +28,11 @@ use js::rust::wrappers::JS_SetPendingException;
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
use std::slice::from_raw_parts;
|
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.
|
/// DOM exceptions that can be thrown by a native DOM method.
|
||||||
#[derive(Clone, Debug, MallocSizeOf)]
|
#[derive(Clone, Debug, MallocSizeOf)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -90,6 +99,16 @@ pub type ErrorResult = Fallible<()>;
|
||||||
|
|
||||||
/// Set a pending exception for the given `result` on `cx`.
|
/// Set a pending exception for the given `result` on `cx`.
|
||||||
pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: &GlobalScope, result: Error) {
|
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 {
|
let code = match result {
|
||||||
Error::IndexSize => DOMErrorName::IndexSizeError,
|
Error::IndexSize => DOMErrorName::IndexSizeError,
|
||||||
Error::NotFound => DOMErrorName::NotFoundError,
|
Error::NotFound => DOMErrorName::NotFoundError,
|
||||||
|
@ -244,6 +263,17 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool)
|
||||||
"Error at {}:{}:{} {}",
|
"Error at {}:{}:{} {}",
|
||||||
error_info.filename, error_info.lineno, error_info.column, error_info.message
|
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 {
|
if dispatch_event {
|
||||||
GlobalScope::from_context(cx).report_an_error(error_info, value.handle());
|
GlobalScope::from_context(cx).report_an_error(error_info, value.handle());
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* 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 byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
|
||||||
use canvas_traits::canvas::{byte_swap, multiply_u8_pixel};
|
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::{TexParameter, WebGLCommand, WebGLContextShareMode, WebGLError};
|
||||||
use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender};
|
use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender};
|
||||||
use canvas_traits::webgl::{WebGLProgramId, WebGLResult, WebGLSLVersion, WebGLSender};
|
use canvas_traits::webgl::{WebGLProgramId, WebGLResult, WebGLSLVersion, WebGLSender};
|
||||||
|
@ -316,7 +318,7 @@ impl WebGLRenderingContext {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn send_command(&self, command: WebGLCommand) {
|
pub fn send_command(&self, command: WebGLCommand) {
|
||||||
self.webgl_sender.send(command).unwrap();
|
self.webgl_sender.send(command, capture_webgl_backtrace(self)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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 {
|
impl Drop for WebGLRenderingContext {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let _ = self.webgl_sender.send_remove();
|
let _ = self.webgl_sender.send_remove();
|
||||||
|
@ -1521,9 +1542,10 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
|
||||||
let (sender, receiver) = webgl_channel().unwrap();
|
let (sender, receiver) = webgl_channel().unwrap();
|
||||||
|
|
||||||
// If the send does not succeed, assume context lost
|
// If the send does not succeed, assume context lost
|
||||||
|
let backtrace = capture_webgl_backtrace(self);
|
||||||
if self
|
if self
|
||||||
.webgl_sender
|
.webgl_sender
|
||||||
.send(WebGLCommand::GetContextAttributes(sender))
|
.send(WebGLCommand::GetContextAttributes(sender), backtrace)
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
extern crate app_units;
|
extern crate app_units;
|
||||||
extern crate audio_video_metadata;
|
extern crate audio_video_metadata;
|
||||||
|
#[cfg(any(feature = "webgl_backtrace", feature = "js_backtrace"))]
|
||||||
|
extern crate backtrace;
|
||||||
extern crate base64;
|
extern crate base64;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
|
|
|
@ -17,6 +17,7 @@ webdriver = ["webdriver_server"]
|
||||||
energy-profiling = ["profile_traits/energy-profiling"]
|
energy-profiling = ["profile_traits/energy-profiling"]
|
||||||
debugmozjs = ["script/debugmozjs"]
|
debugmozjs = ["script/debugmozjs"]
|
||||||
googlevr = ["webvr/googlevr"]
|
googlevr = ["webvr/googlevr"]
|
||||||
|
js_backtrace = ["script/js_backtrace"]
|
||||||
webrender_debugger = ["webrender/debugger"]
|
webrender_debugger = ["webrender/debugger"]
|
||||||
oculusvr = ["webvr/oculusvr"]
|
oculusvr = ["webvr/oculusvr"]
|
||||||
unstable = [
|
unstable = [
|
||||||
|
@ -24,6 +25,11 @@ unstable = [
|
||||||
"profile/unstable",
|
"profile/unstable",
|
||||||
"script/unstable",
|
"script/unstable",
|
||||||
]
|
]
|
||||||
|
webgl_backtrace = [
|
||||||
|
"script/webgl_backtrace",
|
||||||
|
"canvas/webgl_backtrace",
|
||||||
|
"canvas_traits/webgl_backtrace",
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bluetooth_traits = {path = "../bluetooth_traits"}
|
bluetooth_traits = {path = "../bluetooth_traits"}
|
||||||
|
|
|
@ -42,3 +42,5 @@ debugmozjs = ["libservo/debugmozjs"]
|
||||||
unstable = ["libservo/unstable"]
|
unstable = ["libservo/unstable"]
|
||||||
googlevr = ["libservo/googlevr"]
|
googlevr = ["libservo/googlevr"]
|
||||||
oculusvr = ["libservo/oculusvr"]
|
oculusvr = ["libservo/oculusvr"]
|
||||||
|
webgl_backtrace = ["libservo/webgl_backtrace"]
|
||||||
|
js_backtrace = ["libservo/js_backtrace"]
|
||||||
|
|
|
@ -30,6 +30,8 @@ webdriver = ["libservo/webdriver"]
|
||||||
energy-profiling = ["libservo/energy-profiling"]
|
energy-profiling = ["libservo/energy-profiling"]
|
||||||
debugmozjs = ["libservo/debugmozjs"]
|
debugmozjs = ["libservo/debugmozjs"]
|
||||||
unstable = ["libservo/unstable"]
|
unstable = ["libservo/unstable"]
|
||||||
|
webgl_backtrace = ["libservo/webgl_backtrace"]
|
||||||
|
js_backtrace = ["libservo/js_backtrace"]
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "android"))'.dependencies]
|
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||||
backtrace = "0.3"
|
backtrace = "0.3"
|
||||||
|
|
|
@ -264,6 +264,11 @@ class MachCommands(CommandBase):
|
||||||
if debug_mozjs:
|
if debug_mozjs:
|
||||||
features += ["debugmozjs"]
|
features += ["debugmozjs"]
|
||||||
|
|
||||||
|
if self.config["build"]["webgl-backtrace"]:
|
||||||
|
features += ["webgl-backtrace"]
|
||||||
|
if self.config["build"]["dom-backtrace"]:
|
||||||
|
features += ["dom-backtrace"]
|
||||||
|
|
||||||
if features:
|
if features:
|
||||||
opts += ["--features", "%s" % ' '.join(features)]
|
opts += ["--features", "%s" % ' '.join(features)]
|
||||||
|
|
||||||
|
|
|
@ -288,6 +288,8 @@ class CommandBase(object):
|
||||||
self.config["build"].setdefault("rustflags", "")
|
self.config["build"].setdefault("rustflags", "")
|
||||||
self.config["build"].setdefault("incremental", None)
|
self.config["build"].setdefault("incremental", None)
|
||||||
self.config["build"].setdefault("thinlto", False)
|
self.config["build"].setdefault("thinlto", False)
|
||||||
|
self.config["build"].setdefault("webgl-backtrace", False)
|
||||||
|
self.config["build"].setdefault("dom-backtrace", False)
|
||||||
|
|
||||||
self.config.setdefault("android", {})
|
self.config.setdefault("android", {})
|
||||||
self.config["android"].setdefault("sdk", "")
|
self.config["android"].setdefault("sdk", "")
|
||||||
|
|
|
@ -32,6 +32,14 @@ android = false
|
||||||
# Set "debug-mozjs" or use `mach build --debug-mozjs` to build a debug spidermonkey.
|
# Set "debug-mozjs" or use `mach build --debug-mozjs` to build a debug spidermonkey.
|
||||||
debug-mozjs = false
|
debug-mozjs = false
|
||||||
|
|
||||||
|
# When a GL error occurs as a result of a WebGL operation, print the stack trace for the content
|
||||||
|
# JS and native Rust code that triggered the failed operation. Warning: very slow.
|
||||||
|
webgl-backtrace = false
|
||||||
|
|
||||||
|
# When a DOM exception is reported, print the stack trace for the content JS and native Rust code
|
||||||
|
# that triggered it.
|
||||||
|
dom-backtrace = false
|
||||||
|
|
||||||
# Set to the path to your ccache binary to enable caching of compiler outputs
|
# Set to the path to your ccache binary to enable caching of compiler outputs
|
||||||
#ccache = "/usr/local/bin/ccache"
|
#ccache = "/usr/local/bin/ccache"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue