diff options
author | Ms2ger <Ms2ger@gmail.com> | 2016-07-04 16:24:09 +0200 |
---|---|---|
committer | Ms2ger <Ms2ger@gmail.com> | 2016-07-28 13:05:56 +0200 |
commit | 89efccc4267706eec8d1cd32043bb25d7f37f9b2 (patch) | |
tree | d64ac6286bf487cb16e22639e658bc4eaaa35816 /components/script/dom/bindings/error.rs | |
parent | a0c502261dc2bd710e31dcbbbd2d81d2a2c53724 (diff) | |
download | servo-89efccc4267706eec8d1cd32043bb25d7f37f9b2.tar.gz servo-89efccc4267706eec8d1cd32043bb25d7f37f9b2.zip |
Update SpiderMonkey to m-c bcf4ff0c3eef.
This currently breaks Servo on Android, because there are a number of
interdependent changes that cannot easily land serially in a way that
keeps it working throughout. We expect to fix this in the near future.
Diffstat (limited to 'components/script/dom/bindings/error.rs')
-rw-r--r-- | components/script/dom/bindings/error.rs | 109 |
1 files changed, 105 insertions, 4 deletions
diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index d0074335c23..bd63ba84fb1 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -4,15 +4,26 @@ //! Utilities to throw exceptions from Rust bindings. +use dom::bindings::codegen::Bindings::DOMExceptionBinding::DOMExceptionMethods; use dom::bindings::codegen::PrototypeList::proto_id_to_name; -use dom::bindings::conversions::ToJSValConvertible; +use dom::bindings::conversions::root_from_object; +use dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}; use dom::bindings::global::GlobalRef; +use dom::bindings::str::USVString; use dom::domexception::{DOMErrorName, DOMException}; use js::error::{throw_range_error, throw_type_error}; +use js::jsapi::HandleObject; use js::jsapi::JSAutoCompartment; -use js::jsapi::{JSContext, JSObject}; -use js::jsapi::{JS_IsExceptionPending, JS_ReportPendingException, JS_SetPendingException}; +use js::jsapi::JSContext; +use js::jsapi::JSObject; +use js::jsapi::JS_ClearPendingException; +use js::jsapi::JS_ErrorFromException; +use js::jsapi::JS_GetPendingException; +use js::jsapi::JS_IsExceptionPending; +use js::jsapi::JS_SetPendingException; use js::jsval::UndefinedValue; +use libc::c_uint; +use std::slice::from_raw_parts; /// DOM exceptions that can be thrown by a native DOM method. #[derive(Debug, Clone, HeapSizeOf)] @@ -123,11 +134,101 @@ pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef, result: JS_SetPendingException(cx, thrown.handle()); } +struct ErrorInfo { + filename: String, + message: String, + lineno: c_uint, + column: c_uint, +} + +impl ErrorInfo { + unsafe fn from_native_error(cx: *mut JSContext, object: HandleObject) + -> Option<ErrorInfo> { + let report = JS_ErrorFromException(cx, object); + if report.is_null() { + return None; + } + + let filename = { + let filename = (*report).filename as *const u8; + if !filename.is_null() { + let length = (0..).find(|idx| *filename.offset(*idx) == 0).unwrap(); + let filename = from_raw_parts(filename, length as usize); + String::from_utf8_lossy(filename).into_owned() + } else { + "none".to_string() + } + }; + + let lineno = (*report).lineno; + let column = (*report).column; + + let message = { + let message = (*report).ucmessage; + let length = (0..).find(|idx| *message.offset(*idx) == 0).unwrap(); + let message = from_raw_parts(message, length as usize); + String::from_utf16_lossy(message) + }; + + Some(ErrorInfo { + filename: filename, + message: message, + lineno: lineno, + column: column, + }) + } + + fn from_dom_exception(cx: *mut JSContext, object: HandleObject) -> Option<ErrorInfo> { + let exception = match root_from_object::<DOMException>(object.get()) { + Ok(exception) => exception, + Err(_) => return None, + }; + + Some(ErrorInfo { + filename: "".to_string(), + message: exception.Stringifier().into(), + lineno: 0, + column: 0, + }) + } +} + /// Report a pending exception, thereby clearing it. pub unsafe fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) { if JS_IsExceptionPending(cx) { let _ac = JSAutoCompartment::new(cx, obj); - JS_ReportPendingException(cx); + rooted!(in(cx) let mut value = UndefinedValue()); + if !JS_GetPendingException(cx, value.handle_mut()) { + JS_ClearPendingException(cx); + error!("Uncaught exception: JS_GetPendingException failed"); + return; + } + + JS_ClearPendingException(cx); + if !value.is_object() { + match USVString::from_jsval(cx, value.handle(), ()) { + Ok(USVString(string)) => error!("Uncaught exception: {}", string), + Err(_) => error!("Uncaught exception: failed to stringify primitive"), + } + return; + } + + rooted!(in(cx) let object = value.to_object()); + let error_info = ErrorInfo::from_native_error(cx, object.handle()) + .or_else(|| ErrorInfo::from_dom_exception(cx, object.handle())); + let error_info = match error_info { + Some(error_info) => error_info, + None => { + error!("Uncaught exception: failed to extract information"); + return; + } + }; + + error!("Error at {}:{}:{} {}", + error_info.filename, + error_info.lineno, + error_info.column, + error_info.message); } } |