diff options
author | Josh Matthews <josh@joshmatthews.net> | 2014-09-09 15:13:18 -0400 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2015-01-14 12:54:46 -0500 |
commit | 159235b3d00fcb1718becf2840186b5fa8f878ce (patch) | |
tree | 9c0edaa271ac153741d2bf1345daf4b278c1c292 /components/script/dom/bindings/callback.rs | |
parent | dfad8763a846d0ae2e2950a4d78240cbdbc5d541 (diff) | |
download | servo-159235b3d00fcb1718becf2840186b5fa8f878ce.tar.gz servo-159235b3d00fcb1718becf2840186b5fa8f878ce.zip |
Add handling for unreported exceptions when invoking callback objects.
Diffstat (limited to 'components/script/dom/bindings/callback.rs')
-rw-r--r-- | components/script/dom/bindings/callback.rs | 54 |
1 files changed, 47 insertions, 7 deletions
diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs index c9718b6e026..4cee0c5a2cd 100644 --- a/components/script/dom/bindings/callback.rs +++ b/components/script/dom/bindings/callback.rs @@ -9,19 +9,21 @@ use dom::bindings::global::global_object_for_js_object; use dom::bindings::js::JSRef; use dom::bindings::utils::Reflectable; -use js::jsapi::{JSContext, JSObject, JS_WrapObject, JS_ObjectIsCallable}; -use js::jsapi::JS_GetProperty; +use js::jsapi::{JSContext, JSObject, JS_WrapObject, JS_ObjectIsCallable, JS_GetGlobalObject}; +use js::jsapi::{JS_GetProperty, JS_IsExceptionPending, JS_ReportPendingException}; +use js::jsapi::{JS_GetPendingException}; use js::jsval::{JSVal, UndefinedValue}; +use js::rust::with_compartment; use std::ptr; /// The exception handling used for a call. -#[deriving(Copy)] +#[deriving(Copy, PartialEq)] pub enum ExceptionHandling { /// Report any exception and don't throw it to the caller code. - ReportExceptions, + Report, /// Throw any exception to the caller code. - RethrowExceptions + Rethrow } /// A common base class for representing IDL callback function types. @@ -135,7 +137,7 @@ pub struct CallSetup { /// The `JSContext` used for the call. cx: *mut JSContext, /// The exception handling used for the call. - _handling: ExceptionHandling + handling: ExceptionHandling, } impl CallSetup { @@ -145,9 +147,10 @@ impl CallSetup { let global = global_object_for_js_object(callback.callback()); let global = global.root(); let cx = global.r().get_cx(); + CallSetup { cx: cx, - _handling: handling + handling: handling, } } @@ -156,3 +159,40 @@ impl CallSetup { self.cx } } + +impl Drop for CallSetup { + fn drop(&mut self) { + let mut need_to_deal_with_exception = unsafe { JS_IsExceptionPending(self.cx) } != 0; + if self.handling == ExceptionHandling::Rethrow && need_to_deal_with_exception { + let mut exn = UndefinedValue(); + let got_exn = unsafe { + JS_GetPendingException(self.cx, &mut exn) != 0 + }; + + if got_exn { + //TODO: actually rethrow instead of eagerly reporting. + // Gecko stores a mutable reference to an ErrorResult + // abstraction that can store a JS exception and + // report it at content boundaries. Our return value + // wrappers around Result<U,V> make that more difficult. + unsafe { + JS_ReportPendingException(self.cx); + } + need_to_deal_with_exception = false; + } + } + + if need_to_deal_with_exception { + // Either we're supposed to report our exceptions, or we're supposed to + // re-throw them but we failed to JS_GetPendingException. Either way, + // just report the pending exception, if any. + + unsafe { + let old_global = JS_GetGlobalObject(self.cx); + with_compartment(self.cx, old_global, || { + JS_ReportPendingException(self.cx) + }); + } + } + } +} |