aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings/error.rs
diff options
context:
space:
mode:
authorMs2ger <Ms2ger@gmail.com>2016-07-04 16:24:09 +0200
committerMs2ger <Ms2ger@gmail.com>2016-07-28 13:05:56 +0200
commit89efccc4267706eec8d1cd32043bb25d7f37f9b2 (patch)
treed64ac6286bf487cb16e22639e658bc4eaaa35816 /components/script/dom/bindings/error.rs
parenta0c502261dc2bd710e31dcbbbd2d81d2a2c53724 (diff)
downloadservo-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.rs109
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);
}
}