diff options
author | Michael Wu <mwu@mozilla.com> | 2015-04-06 19:27:56 -0400 |
---|---|---|
committer | Michael Wu <mwu@mozilla.com> | 2015-06-19 18:42:48 -0400 |
commit | 675267b7822d2d6c30c0e36fc22e0191b741b973 (patch) | |
tree | 640b22869e8a7eb7d5657df3074f0b0ccd528c29 /components/script/dom/bindings/callback.rs | |
parent | a256f39796270cd3a5f40f33eaa4e407117b0cc6 (diff) | |
download | servo-675267b7822d2d6c30c0e36fc22e0191b741b973.tar.gz servo-675267b7822d2d6c30c0e36fc22e0191b741b973.zip |
Upgrade to SM 39
Diffstat (limited to 'components/script/dom/bindings/callback.rs')
-rw-r--r-- | components/script/dom/bindings/callback.rs | 117 |
1 files changed, 82 insertions, 35 deletions
diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs index 4baccae098e..bc6077c8cb7 100644 --- a/components/script/dom/bindings/callback.rs +++ b/components/script/dom/bindings/callback.rs @@ -6,15 +6,22 @@ use dom::bindings::error::{Fallible, Error}; 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, JS_GetGlobalObject}; +use js::jsapi::{JSContext, JSObject, JS_WrapObject, IsCallable}; use js::jsapi::{JS_GetProperty, JS_IsExceptionPending, JS_ReportPendingException}; +use js::jsapi::{RootedObject, RootedValue, MutableHandleObject, Heap}; +use js::jsapi::{JSAutoCompartment}; +use js::jsapi::{JS_BeginRequest, JS_EndRequest}; +use js::jsapi::{JS_EnterCompartment, JS_LeaveCompartment, JSCompartment}; +use js::jsapi::GetGlobalForObjectCrossCompartment; +use js::jsapi::{JS_SaveFrameChain, JS_RestoreFrameChain}; use js::jsval::{JSVal, UndefinedValue}; -use js::rust::with_compartment; use std::ffi::CString; use std::ptr; +use std::rc::Rc; +use std::intrinsics::return_address; +use std::default::Default; /// The exception handling used for a call. #[derive(Copy, Clone, PartialEq)] @@ -26,7 +33,7 @@ pub enum ExceptionHandling { } /// A common base class for representing IDL callback function types. -#[derive(Copy, Clone,PartialEq)] +#[derive(PartialEq)] #[jstraceable] pub struct CallbackFunction { object: CallbackObject @@ -34,17 +41,23 @@ pub struct CallbackFunction { impl CallbackFunction { /// Create a new `CallbackFunction` for this object. - pub fn new(callback: *mut JSObject) -> CallbackFunction { + pub fn new() -> CallbackFunction { CallbackFunction { object: CallbackObject { - callback: callback + callback: Heap::default() } } } + + /// Initialize the callback function with a value. + /// Should be called once this object is done moving. + pub fn init(&mut self, callback: *mut JSObject) { + self.object.callback.set(callback); + } } /// A common base class for representing IDL callback interface types. -#[derive(Copy, Clone,PartialEq)] +#[derive(PartialEq)] #[jstraceable] pub struct CallbackInterface { object: CallbackObject @@ -53,18 +66,23 @@ pub struct CallbackInterface { /// A common base class for representing IDL callback function and /// callback interface types. #[allow(raw_pointer_derive)] -#[derive(Copy, Clone,PartialEq)] #[jstraceable] struct CallbackObject { /// The underlying `JSObject`. - callback: *mut JSObject, + callback: Heap<*mut JSObject>, +} + +impl PartialEq for CallbackObject { + fn eq(&self, other: &CallbackObject) -> bool { + self.callback.get() == other.callback.get() + } } /// A trait to be implemented by concrete IDL callback function and /// callback interface types. pub trait CallbackContainer { /// Create a new CallbackContainer object for the given `JSObject`. - fn new(callback: *mut JSObject) -> Self; + fn new(callback: *mut JSObject) -> Rc<Self>; /// Returns the underlying `JSObject`. fn callback(&self) -> *mut JSObject; } @@ -72,83 +90,103 @@ pub trait CallbackContainer { impl CallbackInterface { /// Returns the underlying `JSObject`. pub fn callback(&self) -> *mut JSObject { - self.object.callback + self.object.callback.get() } } impl CallbackFunction { /// Returns the underlying `JSObject`. pub fn callback(&self) -> *mut JSObject { - self.object.callback + self.object.callback.get() } } impl CallbackInterface { /// Create a new CallbackInterface object for the given `JSObject`. - pub fn new(callback: *mut JSObject) -> CallbackInterface { + pub fn new() -> CallbackInterface { CallbackInterface { object: CallbackObject { - callback: callback + callback: Heap::default() } } } + /// Initialize the callback function with a value. + /// Should be called once this object is done moving. + pub fn init(&mut self, callback: *mut JSObject) { + self.object.callback.set(callback); + } + /// Returns the property with the given `name`, if it is a callable object, /// or an error otherwise. pub fn get_callable_property(&self, cx: *mut JSContext, name: &str) -> Fallible<JSVal> { - let mut callable = UndefinedValue(); + let mut callable = RootedValue::new(cx, UndefinedValue()); + let obj = RootedObject::new(cx, self.callback()); unsafe { let c_name = CString::new(name).unwrap(); - if JS_GetProperty(cx, self.callback(), c_name.as_ptr(), &mut callable) == 0 { + if JS_GetProperty(cx, obj.handle(), c_name.as_ptr(), + callable.handle_mut()) == 0 { return Err(Error::JSFailed); } - if !callable.is_object() || - JS_ObjectIsCallable(cx, callable.to_object()) == 0 { + if !callable.ptr.is_object() || + IsCallable(callable.ptr.to_object()) == 0 { return Err(Error::Type( format!("The value of the {} property is not callable", name))); } } - Ok(callable) + Ok(callable.ptr) } } /// Wraps the reflector for `p` into the compartment of `cx`. pub fn wrap_call_this_object<T: Reflectable>(cx: *mut JSContext, - p: JSRef<T>) -> *mut JSObject { - let mut obj = p.reflector().get_jsobject(); - assert!(!obj.is_null()); + p: &T, + mut rval: MutableHandleObject) { + rval.set(p.reflector().get_jsobject().get()); + assert!(!rval.get().is_null()); unsafe { - if JS_WrapObject(cx, &mut obj) == 0 { - return ptr::null_mut(); + if JS_WrapObject(cx, rval) == 0 { + rval.set(ptr::null_mut()); } } - - return obj; } /// A class that performs whatever setup we need to safely make a call while /// this class is on the stack. After `new` returns, the call is safe to make. pub struct CallSetup { + /// The compartment for reporting exceptions. + /// As a RootedObject, this must be the first field in order to + /// determine the final address on the stack correctly. + exception_compartment: RootedObject, /// The `JSContext` used for the call. cx: *mut JSContext, + /// The compartment we were in before the call. + old_compartment: *mut JSCompartment, /// The exception handling used for the call. - _handling: ExceptionHandling, + handling: ExceptionHandling, } impl CallSetup { /// Performs the setup needed to make a call. #[allow(unrooted_must_root)] - pub fn new<T: CallbackContainer>(callback: T, handling: ExceptionHandling) -> CallSetup { + pub fn new<T: CallbackContainer>(callback: &T, handling: ExceptionHandling) -> CallSetup { let global = global_object_for_js_object(callback.callback()); - let global = global.root(); let cx = global.r().get_cx(); + unsafe { JS_BeginRequest(cx); } + let exception_compartment = unsafe { + GetGlobalForObjectCrossCompartment(callback.callback()) + }; CallSetup { + exception_compartment: + RootedObject::new_with_addr(cx, exception_compartment, + unsafe { return_address() }), cx: cx, - _handling: handling, + old_compartment: unsafe { JS_EnterCompartment(cx, callback.callback()) }, + handling: handling, } } @@ -160,14 +198,23 @@ impl CallSetup { impl Drop for CallSetup { fn drop(&mut self) { - let need_to_deal_with_exception = unsafe { JS_IsExceptionPending(self.cx) } != 0; + unsafe { JS_LeaveCompartment(self.cx, self.old_compartment); } + let need_to_deal_with_exception = + self.handling == ExceptionHandling::Report && + unsafe { JS_IsExceptionPending(self.cx) } != 0; if need_to_deal_with_exception { unsafe { - let old_global = JS_GetGlobalObject(self.cx); - with_compartment(self.cx, old_global, || { - JS_ReportPendingException(self.cx) - }); + let old_global = RootedObject::new(self.cx, self.exception_compartment.ptr); + let saved = JS_SaveFrameChain(self.cx) != 0; + { + let _ac = JSAutoCompartment::new(self.cx, old_global.ptr); + JS_ReportPendingException(self.cx); + } + if saved { + JS_RestoreFrameChain(self.cx); + } } } + unsafe { JS_EndRequest(self.cx); } } } |