diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 7bbaaa2bfe9b..de7987e307d2 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -521,6 +521,7 @@ pub struct LayoutElement<'le> { impl<'le> LayoutElement<'le> { pub fn style_attribute(&self) -> &'le Option { + use script::dom::element::ElementHelpers; let style: &Option = unsafe { &*self.element.style_attribute().borrow_for_layout() }; @@ -536,6 +537,7 @@ impl<'le> TElement<'le> for LayoutElement<'le> { #[inline] fn get_namespace(self) -> &'le Namespace { + use script::dom::element::ElementHelpers; self.element.namespace() } diff --git a/components/plugins/lints/unrooted_must_root.rs b/components/plugins/lints/unrooted_must_root.rs index 7c1d8161f673..f9e9c7b6db17 100644 --- a/components/plugins/lints/unrooted_must_root.rs +++ b/components/plugins/lints/unrooted_must_root.rs @@ -34,8 +34,7 @@ pub struct UnrootedPass; // TODO (#3874, sort of): unwrap other types like Vec/Option/HashMap/etc fn lint_unrooted_ty(cx: &Context, ty: &ast::Ty, warning: &str) { match ty.node { - ast::TyVec(ref t) | ast::TyFixedLengthVec(ref t, _) | - ast::TyPtr(ast::MutTy { ty: ref t, ..}) | ast::TyRptr(_, ast::MutTy { ty: ref t, ..}) => + ast::TyVec(ref t) | ast::TyFixedLengthVec(ref t, _) => lint_unrooted_ty(cx, &**t, warning), ast::TyPath(..) => { match cx.tcx.def_map.borrow()[&ty.id] { @@ -47,7 +46,7 @@ fn lint_unrooted_ty(cx: &Context, ty: &ast::Ty, warning: &str) { _ => (), } } - _ => (), + _ => (), }; } diff --git a/components/plugins/reflector.rs b/components/plugins/reflector.rs index 68a6011e7d43..6bb43552a3e6 100644 --- a/components/plugins/reflector.rs +++ b/components/plugins/reflector.rs @@ -25,6 +25,9 @@ pub fn expand_reflector(cx: &mut ExtCtxt, span: Span, _: &MetaItem, annotatable: fn reflector<'a>(&'a self) -> &'a ::dom::bindings::utils::Reflector { &self.$field_name } + fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) { + self.$field_name.set_jsobject(obj); + } } ); impl_item.map(|it| push(Annotatable::Item(it))) @@ -37,6 +40,9 @@ pub fn expand_reflector(cx: &mut ExtCtxt, span: Span, _: &MetaItem, annotatable: fn reflector<'a>(&'a self) -> &'a ::dom::bindings::utils::Reflector { self.$field_name.reflector() } + fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) { + self.$field_name.init_reflector(obj); + } } ); impl_item.map(|it| push(Annotatable::Item(it))) diff --git a/components/script/devtools.rs b/components/script/devtools.rs index f14e19999a54..ea79a3850a11 100644 --- a/components/script/devtools.rs +++ b/components/script/devtools.rs @@ -6,18 +6,19 @@ use devtools_traits::{CachedConsoleMessage, CachedConsoleMessageTypes, PAGE_ERRO use devtools_traits::{EvaluateJSReply, NodeInfo, Modification, TimelineMarker, TimelineMarkerType}; use dom::bindings::conversions::FromJSValConvertible; use dom::bindings::conversions::StringificationBehavior; -use dom::bindings::js::{JSRef, OptionalRootable, Rootable, Temporary}; +use dom::bindings::js::Root; use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast}; use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::Bindings::DOMRectBinding::{DOMRectMethods}; use dom::bindings::codegen::Bindings::ElementBinding::{ElementMethods}; use dom::node::{Node, NodeHelpers}; use dom::window::{WindowHelpers, ScriptHelpers}; -use dom::element::Element; use dom::document::DocumentHelpers; use page::{IterablePage, Page}; use msg::constellation_msg::PipelineId; use script_task::{get_page, ScriptTask}; +use js::jsapi::RootedValue; +use js::jsval::UndefinedValue; use std::sync::mpsc::Sender; use std::rc::Rc; @@ -25,53 +26,54 @@ use std::rc::Rc; pub fn handle_evaluate_js(page: &Rc, pipeline: PipelineId, eval: String, reply: Sender){ let page = get_page(&*page, pipeline); - let window = page.window().root(); + let window = page.window(); let cx = window.r().get_cx(); - let rval = window.r().evaluate_js_on_global_with_result(&eval); + let mut rval = RootedValue::new(cx, UndefinedValue()); + window.r().evaluate_js_on_global_with_result(&eval, rval.handle_mut()); - reply.send(if rval.is_undefined() { + reply.send(if rval.ptr.is_undefined() { EvaluateJSReply::VoidValue - } else if rval.is_boolean() { - EvaluateJSReply::BooleanValue(rval.to_boolean()) - } else if rval.is_double() { - EvaluateJSReply::NumberValue(FromJSValConvertible::from_jsval(cx, rval, ()).unwrap()) - } else if rval.is_string() { + } else if rval.ptr.is_boolean() { + EvaluateJSReply::BooleanValue(rval.ptr.to_boolean()) + } else if rval.ptr.is_double() { + EvaluateJSReply::NumberValue(FromJSValConvertible::from_jsval(cx, rval.handle(), ()).unwrap()) + } else if rval.ptr.is_string() { //FIXME: use jsstring_to_str when jsval grows to_jsstring EvaluateJSReply::StringValue( - FromJSValConvertible::from_jsval(cx, rval, StringificationBehavior::Default).unwrap()) - } else if rval.is_null() { + FromJSValConvertible::from_jsval(cx, rval.handle(), StringificationBehavior::Default).unwrap()) + } else if rval.ptr.is_null() { EvaluateJSReply::NullValue } else { //FIXME: jsvals don't have an is_int32/is_number yet - assert!(rval.is_object()); + assert!(rval.ptr.is_object()); panic!("object values unimplemented") }).unwrap(); } pub fn handle_get_root_node(page: &Rc, pipeline: PipelineId, reply: Sender) { let page = get_page(&*page, pipeline); - let document = page.document().root(); + let document = page.document(); - let node: JSRef = NodeCast::from_ref(document.r()); + let node = NodeCast::from_ref(document.r()); reply.send(node.summarize()).unwrap(); } pub fn handle_get_document_element(page: &Rc, pipeline: PipelineId, reply: Sender) { let page = get_page(&*page, pipeline); - let document = page.document().root(); - let document_element = document.r().GetDocumentElement().root().unwrap(); + let document = page.document(); + let document_element = document.r().GetDocumentElement().unwrap(); - let node: JSRef = NodeCast::from_ref(document_element.r()); + let node = NodeCast::from_ref(document_element.r()); reply.send(node.summarize()).unwrap(); } -fn find_node_by_unique_id(page: &Rc, pipeline: PipelineId, node_id: String) -> Temporary { +fn find_node_by_unique_id(page: &Rc, pipeline: PipelineId, node_id: String) -> Root { let page = get_page(&*page, pipeline); - let document = page.document().root(); - let node: JSRef = NodeCast::from_ref(document.r()); + let document = page.document(); + let node = NodeCast::from_ref(document.r()); for candidate in node.traverse_preorder() { - if candidate.root().r().get_unique_id() == node_id { + if candidate.r().get_unique_id() == node_id { return candidate; } } @@ -80,18 +82,17 @@ fn find_node_by_unique_id(page: &Rc, pipeline: PipelineId, node_id: String } pub fn handle_get_children(page: &Rc, pipeline: PipelineId, node_id: String, reply: Sender>) { - let parent = find_node_by_unique_id(&*page, pipeline, node_id).root(); + let parent = find_node_by_unique_id(&*page, pipeline, node_id); let children = parent.r().children().map(|child| { - let child = child.root(); child.r().summarize() }).collect(); reply.send(children).unwrap(); } pub fn handle_get_layout(page: &Rc, pipeline: PipelineId, node_id: String, reply: Sender<(f32, f32)>) { - let node = find_node_by_unique_id(&*page, pipeline, node_id).root(); - let elem: JSRef = ElementCast::to_ref(node.r()).expect("should be getting layout of element"); - let rect = elem.GetBoundingClientRect().root(); + let node = find_node_by_unique_id(&*page, pipeline, node_id); + let elem = ElementCast::to_ref(node.r()).expect("should be getting layout of element"); + let rect = elem.GetBoundingClientRect(); let width = *rect.r().Width(); let height = *rect.r().Height(); reply.send((width, height)).unwrap(); @@ -141,8 +142,8 @@ pub fn handle_modify_attribute(page: &Rc, pipeline: PipelineId, node_id: String, modifications: Vec) { - let node = find_node_by_unique_id(&*page, pipeline, node_id).root(); - let elem: JSRef = ElementCast::to_ref(node.r()).expect("should be getting layout of element"); + let node = find_node_by_unique_id(&*page, pipeline, node_id); + let elem = ElementCast::to_ref(node.r()).expect("should be getting layout of element"); for modification in modifications.iter(){ match modification.newValue { @@ -156,7 +157,7 @@ pub fn handle_modify_attribute(page: &Rc, pub fn handle_wants_live_notifications(page: &Rc, pipeline_id: PipelineId, send_notifications: bool) { let page = get_page(&*page, pipeline_id); - let window = page.window().root(); + let window = page.window(); window.r().set_devtools_wants_updates(send_notifications); } @@ -167,7 +168,7 @@ pub fn handle_set_timeline_markers(page: &Rc, for marker_type in &marker_types { match *marker_type { TimelineMarkerType::Reflow => { - let window = page.window().root(); + let window = page.window(); window.r().set_devtools_timeline_marker(TimelineMarkerType::Reflow, reply.clone()); } TimelineMarkerType::DOMEvent => { @@ -180,7 +181,7 @@ pub fn handle_set_timeline_markers(page: &Rc, pub fn handle_drop_timeline_markers(page: &Rc, script_task: &ScriptTask, marker_types: Vec) { - let window = page.window().root(); + let window = page.window(); for marker_type in &marker_types { match *marker_type { TimelineMarkerType::Reflow => { @@ -195,6 +196,6 @@ pub fn handle_drop_timeline_markers(page: &Rc, pub fn handle_request_animation_frame(page: &Rc, id: PipelineId, callback: Box) { let page = page.find(id).expect("There is no such page"); - let doc = page.document().root(); + let doc = page.document(); doc.r().request_animation_frame(callback); } diff --git a/components/script/dom/activation.rs b/components/script/dom/activation.rs index dbbe4689e1b4..67dc0f1b7313 100644 --- a/components/script/dom/activation.rs +++ b/components/script/dom/activation.rs @@ -4,7 +4,6 @@ use dom::bindings::codegen::Bindings::EventBinding::EventMethods; use dom::bindings::codegen::InheritTypes::{EventCast, EventTargetCast}; -use dom::bindings::js::{JSRef, Temporary, OptionalRootable, Rootable}; use dom::element::{Element, ActivationElementHelpers}; use dom::event::{Event, EventHelpers, EventBubbles, EventCancelable}; use dom::eventtarget::EventTarget; @@ -15,7 +14,7 @@ use std::borrow::ToOwned; /// Trait for elements with defined activation behavior pub trait Activatable { - fn as_element(&self) -> Temporary; + fn as_element<'a>(&'a self) -> &'a Element; // Is this particular instance of the element activatable? fn is_instance_activatable(&self) -> bool; @@ -27,32 +26,32 @@ pub trait Activatable { fn canceled_activation(&self); // https://html.spec.whatwg.org/multipage/#run-post-click-activation-steps - fn activation_behavior(&self, event: JSRef, target: JSRef); + fn activation_behavior(&self, event: &Event, target: &EventTarget); // https://html.spec.whatwg.org/multipage/#implicit-submission fn implicit_submission(&self, ctrlKey: bool, shiftKey: bool, altKey: bool, metaKey: bool); // https://html.spec.whatwg.org/multipage/#run-synthetic-click-activation-steps fn synthetic_click_activation(&self, ctrlKey: bool, shiftKey: bool, altKey: bool, metaKey: bool) { - let element = self.as_element().root(); + let element = self.as_element(); // Step 1 - if element.r().click_in_progress() { + if element.click_in_progress() { return; } // Step 2 - element.r().set_click_in_progress(true); + element.set_click_in_progress(true); // Step 3 self.pre_click_activation(); // Step 4 // https://html.spec.whatwg.org/multipage/#fire-a-synthetic-mouse-event - let win = window_from_node(element.r()).root(); - let target: JSRef = EventTargetCast::from_ref(element.r()); + let win = window_from_node(element); + let target = EventTargetCast::from_ref(element); let mouse = MouseEvent::new(win.r(), "click".to_owned(), EventBubbles::DoesNotBubble, EventCancelable::NotCancelable, Some(win.r()), 1, 0, 0, 0, 0, ctrlKey, shiftKey, altKey, metaKey, - 0, None).root(); - let event: JSRef = EventCast::from_ref(mouse.r()); + 0, None); + let event = EventCast::from_ref(mouse.r()); event.fire(target); // Step 5 @@ -64,6 +63,6 @@ pub trait Activatable { } // Step 6 - element.r().set_click_in_progress(false); + element.set_click_in_progress(false); } } diff --git a/components/script/dom/attr.rs b/components/script/dom/attr.rs index 299d7408eafe..5ec04a8df877 100644 --- a/components/script/dom/attr.rs +++ b/components/script/dom/attr.rs @@ -6,11 +6,10 @@ use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::AttrBinding::{self, AttrMethods}; use dom::bindings::codegen::InheritTypes::NodeCast; use dom::bindings::global::GlobalRef; -use dom::bindings::js::{JS, JSRef, MutNullableHeap, Temporary}; -use dom::bindings::js::{OptionalRootable, Rootable, RootedReference}; +use dom::bindings::js::{JS, MutNullableHeap}; +use dom::bindings::js::{Root, RootedReference}; use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::element::{Element, AttributeHandlers}; -use dom::node::Node; use dom::window::Window; use dom::virtualmethods::vtable_for; @@ -125,7 +124,7 @@ pub struct Attr { impl Attr { fn new_inherited(local_name: Atom, value: AttrValue, name: Atom, namespace: Namespace, - prefix: Option, owner: Option>) -> Attr { + prefix: Option, owner: Option<&Element>) -> Attr { Attr { reflector_: Reflector::new(), local_name: local_name, @@ -133,13 +132,13 @@ impl Attr { name: name, namespace: namespace, prefix: prefix, - owner: MutNullableHeap::new(owner.map(JS::from_rooted)), + owner: MutNullableHeap::new(owner.map(JS::from_ref)), } } - pub fn new(window: JSRef, local_name: Atom, value: AttrValue, + pub fn new(window: &Window, local_name: Atom, value: AttrValue, name: Atom, namespace: Namespace, - prefix: Option, owner: Option>) -> Temporary { + prefix: Option, owner: Option<&Element>) -> Root { reflect_dom_object( box Attr::new_inherited(local_name, value, name, namespace, prefix, owner), GlobalRef::Window(window), @@ -162,7 +161,7 @@ impl Attr { } } -impl<'a> AttrMethods for JSRef<'a, Attr> { +impl<'a> AttrMethods for &'a Attr { // https://dom.spec.whatwg.org/#dom-attr-localname fn LocalName(self) -> DOMString { (**self.local_name()).to_owned() @@ -177,8 +176,7 @@ impl<'a> AttrMethods for JSRef<'a, Attr> { fn SetValue(self, value: DOMString) { match self.owner() { None => *self.value.borrow_mut() = AttrValue::String(value), - Some(o) => { - let owner = o.root(); + Some(owner) => { let value = owner.r().parse_attribute(&self.namespace, self.local_name(), value); self.set_value(AttrSettingType::ReplacedAttr, value, owner.r()); } @@ -225,7 +223,7 @@ impl<'a> AttrMethods for JSRef<'a, Attr> { } // https://dom.spec.whatwg.org/#dom-attr-ownerelement - fn GetOwnerElement(self) -> Option> { + fn GetOwnerElement(self) -> Option> { self.owner() } @@ -236,19 +234,19 @@ impl<'a> AttrMethods for JSRef<'a, Attr> { } pub trait AttrHelpers<'a> { - fn set_value(self, set_type: AttrSettingType, value: AttrValue, owner: JSRef); + fn set_value(self, set_type: AttrSettingType, value: AttrValue, owner: &Element); fn value(self) -> Ref<'a, AttrValue>; fn local_name(self) -> &'a Atom; - fn set_owner(self, owner: Option>); - fn owner(self) -> Option>; + fn set_owner(self, owner: Option<&Element>); + fn owner(self) -> Option>; fn summarize(self) -> AttrInfo; } -impl<'a> AttrHelpers<'a> for JSRef<'a, Attr> { - fn set_value(self, set_type: AttrSettingType, value: AttrValue, owner: JSRef) { - assert!(Some(owner) == self.owner().root().r()); +impl<'a> AttrHelpers<'a> for &'a Attr { + fn set_value(self, set_type: AttrSettingType, value: AttrValue, owner: &Element) { + assert!(Some(owner) == self.owner().r()); - let node: JSRef = NodeCast::from_ref(owner); + let node = NodeCast::from_ref(owner); let namespace_is_null = self.namespace == ns!(""); match set_type { @@ -265,21 +263,21 @@ impl<'a> AttrHelpers<'a> for JSRef<'a, Attr> { } fn value(self) -> Ref<'a, AttrValue> { - self.extended_deref().value.borrow() + self.value.borrow() } fn local_name(self) -> &'a Atom { - &self.extended_deref().local_name + &self.local_name } /// Sets the owner element. Should be called after the attribute is added /// or removed from its older parent. - fn set_owner(self, owner: Option>) { + fn set_owner(self, owner: Option<&Element>) { let ref ns = self.namespace; - match (self.owner().root().r(), owner) { + match (self.owner().r(), owner) { (None, Some(new)) => { // Already in the list of attributes of new owner. - assert!(new.get_attribute(&ns, &self.local_name).root().r() == Some(self)) + assert!(new.get_attribute(&ns, &self.local_name) == Some(Root::from_ref(self))) } (Some(old), None) => { // Already gone from the list of attributes of old owner. @@ -287,11 +285,11 @@ impl<'a> AttrHelpers<'a> for JSRef<'a, Attr> { } (old, new) => assert!(old == new) } - self.owner.set(owner.map(JS::from_rooted)) + self.owner.set(owner.map(JS::from_ref)) } - fn owner(self) -> Option> { - self.owner.get().map(Temporary::from_rooted) + fn owner(self) -> Option> { + self.owner.get().map(Root::from_rooted) } fn summarize(self) -> AttrInfo { @@ -311,7 +309,7 @@ pub trait AttrHelpersForLayout { unsafe fn value_atom_forever(&self) -> Option; unsafe fn value_tokens_forever(&self) -> Option<&'static [Atom]>; unsafe fn local_name_atom_forever(&self) -> Atom; - unsafe fn value(&self) -> &AttrValue; + unsafe fn value_for_layout(&self) -> &AttrValue; } #[allow(unsafe_code)] @@ -354,7 +352,7 @@ impl AttrHelpersForLayout for Attr { } #[inline] - unsafe fn value(&self) -> &AttrValue { + unsafe fn value_for_layout(&self) -> &AttrValue { self.value.borrow_for_layout() } } diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs index 4baccae098e3..bc6077c8cb79 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; /// 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 { - 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(cx: *mut JSContext, - p: JSRef) -> *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(callback: T, handling: ExceptionHandling) -> CallSetup { + pub fn new(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); } } } diff --git a/components/script/dom/bindings/cell.rs b/components/script/dom/bindings/cell.rs index 177fed9397b8..6513e2501667 100644 --- a/components/script/dom/bindings/cell.rs +++ b/components/script/dom/bindings/cell.rs @@ -40,7 +40,9 @@ impl DOMRefCell { /// so you have to be careful in trace code! #[allow(unsafe_code)] pub unsafe fn borrow_for_gc_trace<'a>(&'a self) -> &'a T { - debug_assert!(task_state::get().contains(SCRIPT | IN_GC)); + // FIXME: IN_GC isn't reliable enough - doesn't catch minor GCs + // https://github.com/servo/servo/issues/6389 + //debug_assert!(task_state::get().contains(SCRIPT | IN_GC)); &*self.value.as_unsafe_cell().get() } diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 439ddfbd59e3..48b6067d00c4 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -15,7 +15,7 @@ DOMInterfaces = { 'Window': { - 'outerObjectHook': 'Some(bindings::utils::outerize_global as extern fn(*mut JSContext, JSHandleObject) -> *mut JSObject)', + 'outerObjectHook': 'Some(bindings::utils::outerize_global)', }, #FIXME(jdm): This should be 'register': False, but then we don't generate enum types diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index aa1b1ae14d31..f9e929c68daf 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -8,12 +8,15 @@ import os import re import string +import textwrap +import functools from WebIDL import ( BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLType, + IDLInterfaceMember, IDLUndefinedValue, ) @@ -103,15 +106,16 @@ class CastableObjectUnwrapper(): codeOnFailure is the code to run if unwrapping fails. """ - def __init__(self, descriptor, source, codeOnFailure): + def __init__(self, descriptor, source, codeOnFailure, handletype): self.substitution = { "source": source, "codeOnFailure": CGIndenter(CGGeneric(codeOnFailure), 8).define(), + "handletype": handletype, } def __str__(self): return string.Template("""\ -match native_from_reflector_jsmanaged(${source}) { +match native_from_handle${handletype}(${source}) { Ok(val) => val, Err(()) => { ${codeOnFailure} @@ -119,6 +123,136 @@ def __str__(self): }""").substitute(self.substitution) +# We'll want to insert the indent at the beginnings of lines, but we +# don't want to indent empty lines. So only indent lines that have a +# non-newline character on them. +lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE) + + +def indent(s, indentLevel=2): + """ + Indent C++ code. + + Weird secret feature: this doesn't indent lines that start with # (such as + #include lines or #ifdef/#endif). + """ + if s == "": + return s + return re.sub(lineStartDetector, indentLevel * " ", s) + + +# dedent() and fill() are often called on the same string multiple +# times. We want to memoize their return values so we don't keep +# recomputing them all the time. +def memoize(fn): + """ + Decorator to memoize a function of one argument. The cache just + grows without bound. + """ + cache = {} + @functools.wraps(fn) + def wrapper(arg): + retval = cache.get(arg) + if retval is None: + retval = cache[arg] = fn(arg) + return retval + return wrapper + +@memoize +def dedent(s): + """ + Remove all leading whitespace from s, and remove a blank line + at the beginning. + """ + if s.startswith('\n'): + s = s[1:] + return textwrap.dedent(s) + + +# This works by transforming the fill()-template to an equivalent +# string.Template. +fill_multiline_substitution_re = re.compile(r"( *)\$\*{(\w+)}(\n)?") + + +@memoize +def compile_fill_template(template): + """ + Helper function for fill(). Given the template string passed to fill(), + do the reusable part of template processing and return a pair (t, + argModList) that can be used every time fill() is called with that + template argument. + + argsModList is list of tuples that represent modifications to be + made to args. Each modification has, in order: i) the arg name, + ii) the modified name, iii) the indent depth. + """ + t = dedent(template) + assert t.endswith("\n") or "\n" not in t + argModList = [] + + def replace(match): + """ + Replaces a line like ' $*{xyz}\n' with '${xyz_n}', + where n is the indent depth, and add a corresponding entry to + argModList. + + Note that this needs to close over argModList, so it has to be + defined inside compile_fill_template(). + """ + indentation, name, nl = match.groups() + depth = len(indentation) + + # Check that $*{xyz} appears by itself on a line. + prev = match.string[:match.start()] + if (prev and not prev.endswith("\n")) or nl is None: + raise ValueError("Invalid fill() template: $*{%s} must appear by itself on a line" % name) + + # Now replace this whole line of template with the indented equivalent. + modified_name = name + "_" + str(depth) + argModList.append((name, modified_name, depth)) + return "${" + modified_name + "}" + + t = re.sub(fill_multiline_substitution_re, replace, t) + return (string.Template(t), argModList) + +def fill(template, **args): + """ + Convenience function for filling in a multiline template. + + `fill(template, name1=v1, name2=v2)` is a lot like + `string.Template(template).substitute({"name1": v1, "name2": v2})`. + + However, it's shorter, and has a few nice features: + + * If `template` is indented, fill() automatically dedents it! + This makes code using fill() with Python's multiline strings + much nicer to look at. + + * If `template` starts with a blank line, fill() strips it off. + (Again, convenient with multiline strings.) + + * fill() recognizes a special kind of substitution + of the form `$*{name}`. + + Use this to paste in, and automatically indent, multiple lines. + (Mnemonic: The `*` is for "multiple lines"). + + A `$*` substitution must appear by itself on a line, with optional + preceding indentation (spaces only). The whole line is replaced by the + corresponding keyword argument, indented appropriately. If the + argument is an empty string, no output is generated, not even a blank + line. + """ + + t, argModList = compile_fill_template(template) + # Now apply argModList to args + for (name, modified_name, depth) in argModList: + if not (args[name] == "" or args[name].endswith("\n")): + raise ValueError("Argument %s with value %r is missing a newline" % (name, args[name])) + args[modified_name] = indent(args[name], depth) + + return t.substitute(args) + class CGThing(): """ Abstract base class for things that spit out code. @@ -232,14 +366,13 @@ def getPerSignatureCall(signature, argConversionStartsAt=0): # Doesn't matter which of the possible signatures we use, since # they all have the same types up to that point; just use # possibleSignatures[0] - caseBody = [CGGeneric("let argv_start = JS_ARGV(cx, vp);")] - caseBody.extend([ CGArgumentConverter(possibleSignatures[0][1][i], - i, "argv_start", "argc", + caseBody = [ CGArgumentConverter(possibleSignatures[0][1][i], + i, "args", "argc", descriptor) for i in - range(0, distinguishingIndex) ]) + range(0, distinguishingIndex) ] # Select the right overload from our set. - distinguishingArg = "(*argv_start.offset(%d))" % distinguishingIndex + distinguishingArg = "args.get(%d)" % distinguishingIndex def pickFirstSignature(condition, filterLambda): sigs = filter(filterLambda, possibleSignatures) @@ -282,7 +415,7 @@ def pickFirstSignature(condition, filterLambda): # also allow the unwrapping test to skip having to do codegen # for the null-or-undefined case, which we already handled # above. - caseBody.append(CGGeneric("if (%s).is_object() {" % + caseBody.append(CGGeneric("if %s.get().is_object() {" % (distinguishingArg))) for idx, sig in enumerate(interfacesSigs): caseBody.append(CGIndenter(CGGeneric("loop {"))); @@ -319,7 +452,7 @@ def pickFirstSignature(condition, filterLambda): # XXXbz Now we're supposed to check for distinguishingArg being # an array or a platform object that supports indexed # properties... skip that last for now. It's a bit of a pain. - pickFirstSignature("%s.isObject() && IsArrayLike(cx, &%s.toObject())" % + pickFirstSignature("%s.get().isObject() && IsArrayLike(cx, &%s.get().toObject())" % (distinguishingArg, distinguishingArg), lambda s: (s[1][distinguishingIndex].type.isArray() or @@ -328,14 +461,14 @@ def pickFirstSignature(condition, filterLambda): # Check for Date objects # XXXbz Do we need to worry about security wrappers around the Date? - pickFirstSignature("%s.isObject() && JS_ObjectIsDate(cx, &%s.toObject())" % + pickFirstSignature("%s.get().isObject() && JS_ObjectIsDate(cx, &%s.get().toObject())" % (distinguishingArg, distinguishingArg), lambda s: (s[1][distinguishingIndex].type.isDate() or s[1][distinguishingIndex].type.isObject())) # Check for vanilla JS objects # XXXbz Do we need to worry about security wrappers? - pickFirstSignature("%s.is_object() && !is_platform_object(%s.to_object())" % + pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object())" % (distinguishingArg, distinguishingArg), lambda s: (s[1][distinguishingIndex].type.isCallback() or s[1][distinguishingIndex].type.isCallbackInterface() or @@ -524,7 +657,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, # failureCode will prevent pending exceptions from being set in cases when # they really should be! if exceptionCode is None: - exceptionCode = "return 0;" + exceptionCode = "return JSFalse;" needsRooting = typeNeedsRooting(type, descriptorProvider) @@ -581,11 +714,11 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, # Handle the non-object cases by wrapping up the whole # thing in an if cascade. templateBody = ( - "if (${val}).is_object() {\n" + + "if ${val}.get().is_object() {\n" + CGIndenter(CGGeneric(templateBody)).define() + "\n") if type.nullable(): templateBody += ( - "} else if (${val}).is_null_or_undefined() {\n" + "} else if ${val}.get().is_null_or_undefined() {\n" " %s\n") % nullValue templateBody += ( "} else {\n" + @@ -621,8 +754,8 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, if descriptor.interface.isCallback(): name = descriptor.nativeType - declType = CGGeneric(name) - template = "%s::new((${val}).to_object())" % name + declType = CGWrapper(CGGeneric(name), pre="Rc<", post=">") + template = "%s::new(${val}.get().to_object())" % name if type.nullable(): declType = CGWrapper(declType, pre="Option<", post=">") template = wrapObjectTemplate("Some(%s)" % template, "None", @@ -658,17 +791,15 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, templateBody = str(CastableObjectUnwrapper( descriptor, - "(${val}).to_object()", - unwrapFailureCode)) + "${val}", + unwrapFailureCode, + "value")) declType = CGGeneric(descriptorType) if type.nullable(): templateBody = "Some(%s)" % templateBody declType = CGWrapper(declType, pre="Option<", post=">") - if isMember: - templateBody += ".root()" - templateBody = wrapObjectTemplate(templateBody, "None", isDefinitelyObject, type, failureCode) @@ -681,8 +812,8 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, assert not isEnforceRange and not isClamp treatAs = { - "Default": "Default", - "EmptyString": "Empty", + "Default": "StringificationBehavior::Default", + "EmptyString": "StringificationBehavior::Empty", } if treatNullAs not in treatAs: raise TypeError("We don't support [TreatNullAs=%s]" % treatNullAs) @@ -794,23 +925,25 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull() declType = CGGeneric('%s::%s' % (type.unroll().module(), type.unroll().identifier.name)) + finalDeclType = CGTemplatedType("Rc", declType) conversion = CGCallbackTempRoot(declType.define()) if type.nullable(): declType = CGTemplatedType("Option", declType) + finalDeclType = CGTemplatedType("Option", finalDeclType) conversion = CGWrapper(conversion, pre="Some(", post=")") if allowTreatNonObjectAsNull and type.treatNonObjectAsNull(): if not isDefinitelyObject: - haveObject = "${val}.is_object()" + haveObject = "${val}.get().is_object()" template = CGIfElseWrapper(haveObject, conversion, CGGeneric("None")).define() else: template = conversion else: - template = CGIfElseWrapper("JS_ObjectIsCallable(cx, ${val}.to_object()) != 0", + template = CGIfElseWrapper("IsCallable(${val}.get().to_object()) != 0", conversion, onFailureNotCallable(failureCode)).define() template = wrapObjectTemplate( @@ -829,29 +962,47 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, else: default = None - return JSToNativeConversionInfo(template, default, declType, needsRooting=needsRooting) + return JSToNativeConversionInfo(template, default, finalDeclType, needsRooting=needsRooting) if type.isAny(): assert not isEnforceRange and not isClamp - declType = CGGeneric("JSVal") - - if defaultValue is None: - default = None - elif isinstance(defaultValue, IDLNullValue): - default = "NullValue()" - elif isinstance(defaultValue, IDLUndefinedValue): - default = "UndefinedValue()" + declType = "" + default = "" + if isMember == "Dictionary": + # TODO: Need to properly root dictionaries + # https://github.com/servo/servo/issues/6381 + declType = CGGeneric("JSVal") + + if defaultValue is None: + default = None + elif isinstance(defaultValue, IDLNullValue): + default = "NullValue()" + elif isinstance(defaultValue, IDLUndefinedValue): + default = "UndefinedValue()" + else: + raise TypeError("Can't handle non-null, non-undefined default value here") else: - raise TypeError("Can't handle non-null, non-undefined default value here") + declType = CGGeneric("HandleValue") + + if defaultValue is None: + default = None + elif isinstance(defaultValue, IDLNullValue): + default = "HandleValue::null()" + elif isinstance(defaultValue, IDLUndefinedValue): + default = "HandleValue::undefined()" + else: + raise TypeError("Can't handle non-null, non-undefined default value here") return handleOptional("${val}", declType, default) if type.isObject(): assert not isEnforceRange and not isClamp + # TODO: Need to root somehow + # https://github.com/servo/servo/issues/6382 declType = CGGeneric("*mut JSObject") - templateBody = wrapObjectTemplate("${val}.to_object()", + templateBody = wrapObjectTemplate("${val}.get().to_object()", "ptr::null_mut()", isDefinitelyObject, type, failureCode) @@ -871,7 +1022,7 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type, " Err(_) => return 0,\n" "}" % typeName) - return handleOptional(template, declType, handleDefaultNull("%s::empty()" % typeName)) + return handleOptional(template, declType, handleDefaultNull("%s::empty(cx)" % typeName)) if type.isVoid(): # This one only happens for return values, and its easy: Just @@ -948,11 +1099,6 @@ def instantiateJSToNativeConversionTemplate(templateBody, replacements, # conversion. result.append(CGGeneric("")) - if needsRooting: - rootBody = "let %s = %s.root();" % (declName, declName) - result.append(CGGeneric(rootBody)) - result.append(CGGeneric("")) - return result; def convertConstIDLValueToJSVal(value): @@ -979,7 +1125,7 @@ class CGArgumentConverter(CGThing): argument list, and the argv and argc strings and generates code to unwrap the argument to the right native type. """ - def __init__(self, argument, index, argv, argc, descriptorProvider, + def __init__(self, argument, index, args, argc, descriptorProvider, invalidEnumValueFatal=True): CGThing.__init__(self) assert(not argument.defaultValue or argument.optional) @@ -987,12 +1133,12 @@ def __init__(self, argument, index, argv, argc, descriptorProvider, replacer = { "index": index, "argc": argc, - "argv": argv + "args": args } condition = string.Template("${index} < ${argc}").substitute(replacer) replacementVariables = { - "val": string.Template("(*${argv}.offset(${index}))").substitute(replacer), + "val": string.Template("${args}.get(${index})").substitute(replacer), } info = getJSToNativeConversionInfo( @@ -1032,7 +1178,7 @@ def __init__(self, argument, index, argv, argc, descriptorProvider, else: assert argument.optional variadicConversion = { - "val": string.Template("(*${argv}.offset(variadicArg as isize))").substitute(replacer), + "val": string.Template("${args}.get(variadicArg)").substitute(replacer), } innerConverter = instantiateJSToNativeConversionTemplate( template, variadicConversion, declType, "slot", @@ -1066,16 +1212,17 @@ def define(self): return self.converter.define() -def wrapForType(jsvalRef, result='result', successCode='return 1;'): +def wrapForType(jsvalRef, result='result', successCode='return 1;', pre=''): """ Reflect a Rust value into JS. - * 'jsvalRef': a Rust reference to the JSVal in which to store the result + * 'jsvalRef': a MutableHandleValue in which to store the result of the conversion; * 'result': the name of the variable in which the Rust value is stored; * 'successCode': the code to run once we have done the conversion. + * 'pre': code to run before the conversion if rooting is necessary """ - wrap = "%s = (%s).to_jsval(cx);" % (jsvalRef, result) + wrap = "%s\n(%s).to_jsval(cx, %s);" % (pre, result, jsvalRef) if successCode: wrap += "\n%s" % successCode return wrap @@ -1142,8 +1289,8 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): result = CGWrapper(result, pre="Option<", post=">") return result if returnType.isCallback(): - result = CGGeneric('%s::%s' % (returnType.unroll().module(), - returnType.unroll().identifier.name)) + result = CGGeneric('Rc<%s::%s>' % (returnType.unroll().module(), + returnType.unroll().identifier.name)) if returnType.nullable(): result = CGWrapper(result, pre="Option<", post=">") return result @@ -1152,6 +1299,8 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): if returnType.nullable(): result = CGWrapper(result, pre="Option<", post=">") return result + # TODO: Return the value through a MutableHandleValue outparam + # https://github.com/servo/servo/issues/6307 if returnType.isAny(): return CGGeneric("JSVal") if returnType.isObject() or returnType.isSpiderMonkeyInterface(): @@ -1258,9 +1407,9 @@ def __init__(self, descriptor, name, static): # FIXME Check for an existing iterator on the interface first. if any(m.isGetter() and m.isIndexed() for m in methods): - self.regular.append({"name": 'iterator', + self.regular.append({"name": '@@iterator', "methodInfo": False, - "nativeName": "JS_ArrayIterator", + "selfHostedName": "ArrayValues", "length": 0, "flags": "JSPROP_ENUMERATE" }) @@ -1280,21 +1429,31 @@ def generateArray(self, array, name): return "" def specData(m): - if m.get("methodInfo", True): - identifier = m.get("nativeName", m["name"]) - jitinfo = "&%s_methodinfo" % identifier - accessor = "genericMethod as NonNullJSNative" - else: + # TODO: Use something like JS_FNSPEC + # https://github.com/servo/servo/issues/6391 + if "selfHostedName" in m: + selfHostedName = '%s as *const u8 as *const i8' % str_to_const_array(m["selfHostedName"]) + assert not m.get("methodInfo", True) + accessor = "None" jitinfo = "0 as *const JSJitInfo" - accessor = m.get("nativeName", m["name"]) - if accessor[0:3] != 'JS_': - accessor = "%s as NonNullJSNative" % accessor - return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], m["flags"]) + else: + selfHostedName = "0 as *const i8" + if m.get("methodInfo", True): + identifier = m.get("nativeName", m["name"]) + jitinfo = "&%s_methodinfo" % identifier + accessor = "Some(genericMethod)" + else: + jitinfo = "0 as *const JSJitInfo" + accessor = 'Some(%s)' % m.get("nativeName", m["name"]) + if m["name"].startswith("@@"): + return ('(SymbolCode::%s as i32 + 1)' % m["name"][2:], accessor, jitinfo, m["length"], m["flags"], selfHostedName) + return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], m["flags"], selfHostedName) + return self.generatePrefableArray( array, name, - ' JSFunctionSpec { name: %s as *const u8 as *const libc::c_char, call: JSNativeWrapper {op: Some(%s), info: %s}, nargs: %s, flags: %s as u16, selfHostedName: 0 as *const libc::c_char }', - ' JSFunctionSpec { name: 0 as *const libc::c_char, call: JSNativeWrapper {op: None, info: 0 as *const JSJitInfo}, nargs: 0, flags: 0, selfHostedName: 0 as *const libc::c_char }', + ' JSFunctionSpec { name: %s as *const u8 as *const libc::c_char, call: JSNativeWrapper {op: %s, info: %s}, nargs: %s, flags: %s as u16, selfHostedName: %s }', + ' JSFunctionSpec { name: 0 as *const i8, call: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }, nargs: 0, flags: 0, selfHostedName: 0 as *const i8 }', 'JSFunctionSpec', specData) @@ -1314,12 +1473,12 @@ def generateArray(self, array, name): return "" def flags(attr): - return "JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS" + return "JSPROP_SHARED | JSPROP_ENUMERATE" def getter(attr): if self.static: accessor = 'get_' + attr.identifier.name - jitinfo = "0" + jitinfo = "0 as *const JSJitInfo" else: if attr.hasLenientThis(): accessor = "genericLenientGetter" @@ -1327,17 +1486,17 @@ def getter(attr): accessor = "genericGetter" jitinfo = "&%s_getterinfo" % attr.identifier.name - return ("JSPropertyOpWrapper {op: Some(%(native)s as NonNullJSNative), info: %(info)s as *const JSJitInfo}" + return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }" % {"info" : jitinfo, "native" : accessor}) def setter(attr): if attr.readonly and not attr.getExtendedAttribute("PutForwards"): - return "JSStrictPropertyOpWrapper {op: None, info: 0 as *const JSJitInfo}" + return "JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }" if self.static: accessor = 'set_' + attr.identifier.name - jitinfo = "0" + jitinfo = "0 as *const JSJitInfo" else: if attr.hasLenientThis(): accessor = "genericLenientSetter" @@ -1345,7 +1504,7 @@ def setter(attr): accessor = "genericSetter" jitinfo = "&%s_setterinfo" % attr.identifier.name - return ("JSStrictPropertyOpWrapper {op: Some(%(native)s as NonNullJSNative), info: %(info)s as *const JSJitInfo}" + return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }" % {"info" : jitinfo, "native" : accessor}) @@ -1355,8 +1514,8 @@ def specData(attr): return self.generatePrefableArray( array, name, - ' JSPropertySpec { name: %s as *const u8 as *const libc::c_char, tinyid: 0, flags: ((%s) & 0xFF) as u8, getter: %s, setter: %s }', - ' JSPropertySpec { name: 0 as *const libc::c_char, tinyid: 0, flags: 0, getter: JSPropertyOpWrapper {op: None, info: 0 as *const JSJitInfo}, setter: JSStrictPropertyOpWrapper {op: None, info: 0 as *const JSJitInfo} }', + ' JSPropertySpec { name: %s as *const u8 as *const libc::c_char, flags: ((%s) & 0xFF) as u8, getter: %s, setter: %s }', + ' JSPropertySpec { name: 0 as *const i8, flags: 0, getter: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }, setter: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo } }', 'JSPropertySpec', specData) @@ -1562,8 +1721,9 @@ def __init__(self, descriptor): self.descriptor = descriptor def define(self): - traceHook = 'Some(%s as unsafe extern "C" fn(*mut JSTracer, *mut JSObject))' % TRACE_HOOK_NAME + traceHook = 'Some(%s)' % TRACE_HOOK_NAME if self.descriptor.isGlobal(): + traceHook = "Some(js::jsapi::_Z24JS_GlobalObjectTraceHookP8JSTracerP8JSObject)" flags = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL" slots = "JSCLASS_GLOBAL_SLOT_COUNT + 1" else: @@ -1571,66 +1731,54 @@ def define(self): slots = "1" return """\ static Class: DOMJSClass = DOMJSClass { - base: js::Class { + base: js::jsapi::Class { name: %s as *const u8 as *const libc::c_char, - flags: JSCLASS_IS_DOMJSCLASS | %s | (((%s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT), //JSCLASS_HAS_RESERVED_SLOTS(%s), - addProperty: Some(JS_PropertyStub), - delProperty: Some(JS_PropertyStub), - getProperty: Some(JS_PropertyStub), - setProperty: Some(JS_StrictPropertyStub), - enumerate: Some(JS_EnumerateStub), - resolve: Some(JS_ResolveStub), - convert: Some(JS_ConvertStub), - finalize: Some(%s as unsafe extern "C" fn(*mut JSFreeOp, *mut JSObject)), - checkAccess: None, + flags: JSCLASS_IS_DOMJSCLASS | JSCLASS_IMPLEMENTS_BARRIERS | %s | (((%s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT), //JSCLASS_HAS_RESERVED_SLOTS(%s), + addProperty: None, + delProperty: None, + getProperty: None, + setProperty: None, + enumerate: None, + resolve: None, + convert: None, + finalize: Some(%s), call: None, hasInstance: None, construct: None, trace: %s, - ext: js::ClassExtension { - equality: 0 as *const u8, + spec: js::jsapi::ClassSpec { + createConstructor: None, + createPrototype: None, + constructorFunctions: 0 as *const js::jsapi::JSFunctionSpec, + constructorProperties: 0 as *const js::jsapi::JSPropertySpec, + prototypeFunctions: 0 as *const js::jsapi::JSFunctionSpec, + prototypeProperties: 0 as *const js::jsapi::JSPropertySpec, + finishInit: None, + flags: 0, + }, + + ext: js::jsapi::ClassExtension { outerObject: %s, innerObject: None, - iteratorObject: 0 as *const u8, - unused: 0 as *const u8, - isWrappedNative: 0 as *const u8, + isWrappedNative: 0, + weakmapKeyDelegateOp: None, + objectMovedOp: None, }, - ops: js::ObjectOps { - lookupGeneric: 0 as *const u8, - lookupProperty: 0 as *const u8, - lookupElement: 0 as *const u8, - lookupSpecial: 0 as *const u8, - defineGeneric: 0 as *const u8, - defineProperty: 0 as *const u8, - defineElement: 0 as *const u8, - defineSpecial: 0 as *const u8, - getGeneric: 0 as *const u8, - getProperty: 0 as *const u8, - getElement: 0 as *const u8, - getElementIfPresent: 0 as *const u8, - getSpecial: 0 as *const u8, - setGeneric: 0 as *const u8, - setProperty: 0 as *const u8, - setElement: 0 as *const u8, - setSpecial: 0 as *const u8, - getGenericAttributes: 0 as *const u8, - getPropertyAttributes: 0 as *const u8, - getElementAttributes: 0 as *const u8, - getSpecialAttributes: 0 as *const u8, - setGenericAttributes: 0 as *const u8, - setPropertyAttributes: 0 as *const u8, - setElementAttributes: 0 as *const u8, - setSpecialAttributes: 0 as *const u8, - deleteProperty: 0 as *const u8, - deleteElement: 0 as *const u8, - deleteSpecial: 0 as *const u8, - - enumerate: 0 as *const u8, - typeOf: 0 as *const u8, + ops: js::jsapi::ObjectOps { + lookupProperty: None, + defineProperty: None, + hasProperty: None, + getProperty: None, + setProperty: None, + getOwnPropertyDescriptor: None, + deleteProperty: None, + watch: None, + unwatch: None, + getElements: None, + enumerate: None, thisObject: %s, - clear: 0 as *const u8, }, }, dom_class: %s @@ -1640,7 +1788,7 @@ def define(self): FINALIZE_HOOK_NAME, traceHook, self.descriptor.outerObjectHook, self.descriptor.outerObjectHook, - CGIndenter(CGGeneric(DOMClass(self.descriptor))).define()) + CGGeneric(DOMClass(self.descriptor)).define()) def str_to_const_array(s): return "b\"%s\\0\"" % s @@ -1655,20 +1803,19 @@ def define(self): static PrototypeClass: JSClass = JSClass { name: %s as *const u8 as *const libc::c_char, flags: (1 & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT, //JSCLASS_HAS_RESERVED_SLOTS(1) - addProperty: Some(JS_PropertyStub), - delProperty: Some(JS_PropertyStub), - getProperty: Some(JS_PropertyStub), - setProperty: Some(JS_StrictPropertyStub), - enumerate: Some(JS_EnumerateStub), - resolve: Some(JS_ResolveStub), - convert: Some(JS_ConvertStub), + addProperty: None, + delProperty: None, + getProperty: None, + setProperty: None, + enumerate: None, + resolve: None, + convert: None, finalize: None, - checkAccess: None, call: None, hasInstance: None, construct: None, trace: None, - reserved: [0 as *mut libc::c_void; 40] + reserved: [0 as *mut libc::c_void; 25] }; """ % str_to_const_array(self.descriptor.interface.identifier.name + "Prototype") @@ -1742,13 +1889,7 @@ def define(self): class CGCallbackTempRoot(CGGeneric): def __init__(self, name): - val = "%s::new(tempRoot)" % name - define = """\ -{ - let tempRoot = ${val}.to_object(); - %s -}""" % val - CGGeneric.__init__(self, define) + CGGeneric.__init__(self, "%s::new(${val}.get().to_object())" % name) def getAllTypes(descriptors, dictionaries, callbacks): @@ -1792,12 +1933,13 @@ def UnionTypes(descriptors, dictionaries, callbacks, config): 'dom::bindings::codegen::PrototypeList', 'dom::bindings::conversions::FromJSValConvertible', 'dom::bindings::conversions::ToJSValConvertible', - 'dom::bindings::conversions::native_from_reflector_jsmanaged', - 'dom::bindings::conversions::StringificationBehavior::Default', + 'dom::bindings::conversions::native_from_handlevalue', + 'dom::bindings::conversions::StringificationBehavior', 'dom::bindings::error::throw_not_in_union', - 'dom::bindings::js::Unrooted', + 'dom::bindings::js::Root', 'dom::types::*', 'js::jsapi::JSContext', + 'js::jsapi::{HandleValue, MutableHandleValue}', 'js::jsval::JSVal', 'util::str::DOMString', ] @@ -1917,32 +2059,36 @@ def definition_body(self): assert(False) # Override me! def CreateBindingJSObject(descriptor, parent=None): - create = "let mut raw: Unrooted<%s> = Unrooted::from_raw(&*object);\n" % descriptor.concreteType + create = "let mut raw = boxed::into_raw(object);\nlet _rt = RootedTraceable::new(&*raw);\n" if descriptor.proxy: assert not descriptor.isGlobal() create += """ let handler = RegisterBindings::proxy_handlers[PrototypeList::Proxies::%s as usize]; -let mut private = PrivateValue(boxed::into_raw(object) as *const libc::c_void); -let obj = with_compartment(cx, proto, || { +let private = RootedValue::new(cx, PrivateValue(raw as *const libc::c_void)); +let obj = { + let _ac = JSAutoCompartment::new(cx, proto.ptr); NewProxyObject(cx, handler, - &private, - proto, %s, + private.handle(), + proto.ptr, %s.get(), ptr::null_mut(), ptr::null_mut()) -}); -assert!(!obj.is_null());\ +}; +assert!(!obj.is_null()); +let obj = RootedObject::new(cx, obj);\ """ % (descriptor.name, parent) else: if descriptor.isGlobal(): - create += "let obj = create_dom_global(cx, &Class.base as *const js::Class as *const JSClass);\n" + create += "let obj = RootedObject::new(cx, create_dom_global(cx, &Class.base as *const js::jsapi::Class as *const JSClass, Some(%s)));\n" % TRACE_HOOK_NAME else: - create += ("let obj = with_compartment(cx, proto, || {\n" - " JS_NewObject(cx, &Class.base as *const js::Class as *const JSClass, &*proto, &*%s)\n" - "});\n" % parent) + create += ("let obj = {\n" + " let _ac = JSAutoCompartment::new(cx, proto.ptr);\n" + " JS_NewObjectWithGivenProto(cx, &Class.base as *const js::jsapi::Class as *const JSClass, proto.handle())\n" + "};\n" + "let obj = RootedObject::new(cx, obj);\n") create += """\ -assert!(!obj.is_null()); +assert!(!obj.ptr.is_null()); -JS_SetReservedSlot(obj, DOM_OBJECT_SLOT, - PrivateValue(boxed::into_raw(object) as *const libc::c_void));""" +JS_SetReservedSlot(obj.ptr, DOM_OBJECT_SLOT, + PrivateValue(raw as *const libc::c_void));""" return create class CGWrapMethod(CGAbstractMethod): @@ -1958,37 +2104,46 @@ def __init__(self, descriptor): else: args = [Argument('*mut JSContext', 'cx'), Argument("Box<%s>" % descriptor.concreteType, 'object', mutable=True)] - retval = 'Temporary<%s>' % descriptor.concreteType + retval = 'Root<%s>' % descriptor.concreteType CGAbstractMethod.__init__(self, descriptor, 'Wrap', retval, args, pub=True) def definition_body(self): if not self.descriptor.isGlobal(): return CGGeneric("""\ +let _ar = JSAutoRequest::new(cx); let scope = scope.reflector().get_jsobject(); -assert!(!scope.is_null()); -assert!(((*JS_GetClass(scope)).flags & JSCLASS_IS_GLOBAL) != 0); +assert!(!scope.get().is_null()); +assert!(((*JS_GetClass(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0); -let proto = with_compartment(cx, scope, || GetProtoObject(cx, scope, scope)); -assert!(!proto.is_null()); +let mut proto = RootedObject::new(cx, ptr::null_mut()); +{ + let _ac = JSAutoCompartment::new(cx, scope.get()); + GetProtoObject(cx, scope, scope, proto.handle_mut()) +} +assert!(!proto.ptr.is_null()); %s -raw.reflector().set_jsobject(obj); +(*raw).init_reflector(obj.ptr); -Temporary::from_unrooted(raw)""" % CreateBindingJSObject(self.descriptor, "scope")) +Root::from_ref(&*raw)""" % CreateBindingJSObject(self.descriptor, "scope")) else: return CGGeneric("""\ +let _ar = JSAutoRequest::new(cx); %s -with_compartment(cx, obj, || { - let proto = GetProtoObject(cx, obj, obj); - JS_SetPrototype(cx, obj, proto); - raw.reflector().set_jsobject(obj); +let _ac = JSAutoCompartment::new(cx, obj.ptr); +let mut proto = RootedObject::new(cx, ptr::null_mut()); +GetProtoObject(cx, obj.handle(), obj.handle(), proto.handle_mut()); +JS_SetPrototype(cx, obj.handle(), proto.handle()); + +(*raw).init_reflector(obj.ptr); - RegisterBindings::Register(cx, obj); -}); +let ret = Root::from_ref(&*raw); -Temporary::from_unrooted(raw)""" % CreateBindingJSObject(self.descriptor)) +RegisterBindings::Register(cx, obj.handle()); + +ret""" % CreateBindingJSObject(self.descriptor)) class CGIDLInterface(CGThing): @@ -2083,21 +2238,23 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): properties should be a PropertyArrays instance. """ def __init__(self, descriptor, properties): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'global'), - Argument('*mut JSObject', 'receiver')] - CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', '*mut JSObject', args) + args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'), + Argument('HandleObject', 'receiver'), + Argument('MutableHandleObject', 'rval')] + CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args) self.properties = properties def definition_body(self): protoChain = self.descriptor.prototypeChain if len(protoChain) == 1: - getParentProto = "JS_GetObjectPrototype(cx, global)" + getParentProto = "parent_proto.ptr = JS_GetObjectPrototype(cx, global)" else: parentProtoName = self.descriptor.prototypeChain[-2] - getParentProto = ("%s::GetProtoObject(cx, global, receiver)" % + getParentProto = ("%s::GetProtoObject(cx, global, receiver, parent_proto.handle_mut())" % toBindingNamespace(parentProtoName)) - getParentProto = ("let parent_proto: *mut JSObject = %s;\n" - "assert!(!parent_proto.is_null());\n") % getParentProto + getParentProto = ("let mut parent_proto = RootedObject::new(cx, ptr::null_mut());\n" + "%s;\n" + "assert!(!parent_proto.ptr.is_null());\n") % getParentProto if self.descriptor.interface.isCallback(): protoClass = "None" @@ -2127,10 +2284,10 @@ def definition_body(self): constructor = 'None' call = """\ -return do_create_interface_objects(cx, global, receiver, parent_proto, - %s, %s, - %s, - &sNativeProperties);""" % (protoClass, constructor, domClass) +do_create_interface_objects(cx, receiver, parent_proto.handle(), + %s, %s, + %s, + &sNativeProperties, rval);""" % (protoClass, constructor, domClass) return CGList([ CGGeneric(getParentProto), @@ -2143,10 +2300,11 @@ class CGGetPerInterfaceObject(CGAbstractMethod): constructor object). """ def __init__(self, descriptor, name, idPrefix="", pub=False): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'global'), - Argument('*mut JSObject', 'receiver')] + args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'), + Argument('HandleObject', 'receiver'), + Argument('MutableHandleObject', 'rval')] CGAbstractMethod.__init__(self, descriptor, name, - '*mut JSObject', args, pub=pub) + 'void', args, pub=pub) self.id = idPrefix + "ID::" + self.descriptor.name def definition_body(self): return CGGeneric(""" @@ -2157,19 +2315,22 @@ def definition_body(self): wrapper and global is the sandbox's global. */ -assert!(((*JS_GetClass(global)).flags & JSCLASS_DOM_GLOBAL) != 0); +assert!(((*JS_GetClass(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0); /* Check to see whether the interface objects are already installed */ -let proto_or_iface_array = get_proto_or_iface_array(global); -let cached_object: *mut JSObject = (*proto_or_iface_array)[%s as usize]; -if cached_object.is_null() { - let tmp: *mut JSObject = CreateInterfaceObjects(cx, global, receiver); - assert!(!tmp.is_null()); - (*proto_or_iface_array)[%s as usize] = tmp; - tmp -} else { - cached_object -}""" % (self.id, self.id)) +let proto_or_iface_array = get_proto_or_iface_array(global.get()); +rval.set((*proto_or_iface_array)[%s as usize]); +if !rval.get().is_null() { + return; +} + +CreateInterfaceObjects(cx, global, receiver, rval); +assert!(!rval.get().is_null()); +(*proto_or_iface_array)[%s as usize] = rval.get(); +if <*mut JSObject>::needs_post_barrier(rval.get()) { + <*mut JSObject>::post_barrier((*proto_or_iface_array).as_mut_ptr().offset(%s as isize)) +} +""" % (self.id, self.id, self.id)) class CGGetProtoObjectMethod(CGGetPerInterfaceObject): """ @@ -2224,40 +2385,39 @@ def definition_body(self): body = """\ let traps = ProxyTraps { - getPropertyDescriptor: Some(get_property_descriptor as unsafe extern "C" fn(*mut JSContext, *mut JSObject, jsid, bool, *mut JSPropertyDescriptor) -> bool), - getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor as unsafe extern "C" fn(*mut JSContext, *mut JSObject, jsid, bool, *mut JSPropertyDescriptor) -> bool), - defineProperty: Some(%s as unsafe extern "C" fn(*mut JSContext, *mut JSObject, jsid, *mut JSPropertyDescriptor) -> bool), - getOwnPropertyNames: Some(proxyhandler::get_own_property_names as unsafe extern "C" fn(*mut JSContext, *mut JSObject, *mut AutoIdVector) -> bool), - delete_: Some(%s as unsafe extern "C" fn(*mut JSContext, *mut JSObject, jsid, *mut bool) -> bool), - enumerate: Some(proxyhandler::enumerate as unsafe extern "C" fn(*mut JSContext, *mut JSObject, *mut AutoIdVector) -> bool), - + enter: None, + getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor), + defineProperty: Some(%s), + ownPropertyKeys: Some(proxyhandler::own_property_keys), + delete_: Some(%s), + enumerate: None, + preventExtensions: Some(proxyhandler::prevent_extensions), + isExtensible: Some(proxyhandler::is_extensible), has: None, - hasOwn: Some(hasOwn as unsafe extern "C" fn(*mut JSContext, *mut JSObject, jsid, *mut bool) -> bool), - get: Some(get as unsafe extern "C" fn(*mut JSContext, *mut JSObject, *mut JSObject, jsid, *mut JSVal) -> bool), + get: Some(get), set: None, - keys: None, - iterate: None, - call: None, construct: None, - nativeCall: ptr::null(), + getPropertyDescriptor: Some(get_property_descriptor), + hasOwn: Some(hasOwn), + getOwnEnumerablePropertyKeys: None, + nativeCall: None, hasInstance: None, - typeOf: None, objectClassIs: None, - obj_toString: Some(obj_toString as unsafe extern "C" fn(*mut JSContext, *mut JSObject) -> *mut js::jsapi::JSString), + className: Some(className), fun_toString: None, - //regexp_toShared: ptr::null(), + boxedValue_unbox: None, defaultValue: None, - iteratorNext: None, - finalize: Some(%s as unsafe extern "C" fn(*mut JSFreeOp, *mut JSObject)), - getElementIfPresent: None, - getPrototypeOf: None, - trace: Some(%s as unsafe extern "C" fn(*mut JSTracer, *mut JSObject)) + trace: Some(%s), + finalize: Some(%s), + objectMoved: None, + isCallable: None, + isConstructor: None, }; CreateProxyHandler(&traps, &Class as *const _ as *const _)\ -""" % (customDefineProperty, customDelete, FINALIZE_HOOK_NAME, - TRACE_HOOK_NAME) +""" % (customDefineProperty, customDelete, TRACE_HOOK_NAME, + FINALIZE_HOOK_NAME) return CGGeneric(body) @@ -2270,7 +2430,7 @@ def __init__(self, descriptor): assert descriptor.interface.hasInterfaceObject() args = [ Argument('*mut JSContext', 'cx'), - Argument('*mut JSObject', 'global'), + Argument('HandleObject', 'global'), ] CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'void', args, pub=True) @@ -2279,10 +2439,17 @@ def define(self): def definition_body(self): if self.descriptor.interface.isCallback(): - code = "CreateInterfaceObjects(cx, global, global);" + code = """\ +let mut obj = RootedObject::new(cx, ptr::null_mut()); +CreateInterfaceObjects(cx, global, global, obj.handle_mut()); +""" else: - code = "assert!(!GetProtoObject(cx, global, global).is_null());" - return CGGeneric("assert!(!global.is_null());\n" + code) + code = """\ +let mut proto = RootedObject::new(cx, ptr::null_mut()); +GetProtoObject(cx, global, global, proto.handle_mut()); +assert!(!proto.ptr.is_null()); +""" + return CGGeneric("assert!(!global.get().is_null());\n" + code) def needCx(returnType, arguments, considerTypes): return (considerTypes and @@ -2329,7 +2496,7 @@ def __init__(self, errorResult, arguments, argsPre, returnType, if static: call = CGWrapper(call, pre="%s::" % descriptorProvider.interface.identifier.name) else: - call = CGWrapper(call, pre="%s.r()." % object) + call = CGWrapper(call, pre="%s." % object) call = CGList([call, CGWrapper(args, pre="(", post=")")]) self.cgRoot.append(CGList([ @@ -2344,8 +2511,7 @@ def __init__(self, errorResult, arguments, argsPre, returnType, if static: glob = "" else: - glob = " let global = global_object_for_js_object(this.r().reflector().get_jsobject());\n"\ - " let global = global.root();\n" + glob = " let global = global_object_for_js_object(this.reflector().get_jsobject().get());\n" self.cgRoot.append(CGGeneric( "let result = match result {\n" @@ -2357,9 +2523,6 @@ def __init__(self, errorResult, arguments, argsPre, returnType, " },\n" "};" % (glob, errorResult))) - if typeRetValNeedsRooting(returnType): - self.cgRoot.append(CGGeneric("let result = result.root();")) - def define(self): return self.cgRoot.define() @@ -2403,22 +2566,15 @@ def __init__(self, returnType, argsPre, arguments, nativeMethodName, static, self.argsPre = argsPre self.arguments = arguments self.argCount = len(arguments) - if self.argCount > argConversionStartsAt: - # Insert our argv in there - cgThings = [CGGeneric(self.getArgvDecl())] - else: - cgThings = [] - cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgv(), + cgThings = [] + cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgs(), self.getArgc(), self.descriptor, invalidEnumValueFatal=not setter) for i in range(argConversionStartsAt, self.argCount)]) errorResult = None if self.isFallible(): - if nativeMethodName == "NamedSetter": - errorResult = " false" - else: - errorResult = " false as JSBool" + errorResult = " JSFalse" cgThings.append(CGCallGenerator( errorResult, @@ -2427,10 +2583,8 @@ def __init__(self, returnType, argsPre, arguments, nativeMethodName, static, static)) self.cgRoot = CGList(cgThings, "\n") - def getArgv(self): - return "argv" if self.argCount > 0 else "" - def getArgvDecl(self): - return "\nlet argv = JS_ARGV(cx, vp);\n" + def getArgs(self): + return "args" if self.argCount > 0 else "" def getArgc(self): return "argc" def getArguments(self): @@ -2445,7 +2599,7 @@ def isFallible(self): return not 'infallible' in self.extendedAttributes def wrap_return_value(self): - return wrapForType('*vp') + return wrapForType('args.rval()') def define(self): return (self.cgRoot.define() + "\n" + self.wrap_return_value()) @@ -2551,7 +2705,7 @@ class CGAbstractBindingMethod(CGAbstractExternMethod): CGThing which is already properly indented. """ def __init__(self, descriptor, name, args, unwrapFailureCode=None): - CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args) + CGAbstractExternMethod.__init__(self, descriptor, name, "u8", args) if unwrapFailureCode is None: self.unwrapFailureCode = ( @@ -2568,14 +2722,20 @@ def definition_body(self): # consumption by FailureFatalCastableObjectUnwrapper. unwrapThis = str(CastableObjectUnwrapper( FakeCastableDescriptor(self.descriptor), - "obj", self.unwrapFailureCode)) + "obj.handle()", self.unwrapFailureCode, "object")) unwrapThis = CGGeneric( - "let obj: *mut JSObject = JS_THIS_OBJECT(cx, vp as *mut JSVal);\n" - "if obj.is_null() {\n" - " return false as JSBool;\n" + "let args = CallArgs::from_vp(vp, argc);\n" + "let thisobj = args.thisv();\n" + "if !thisobj.get().is_null_or_undefined() && !thisobj.get().is_object() {\n" + " return JSFalse;\n" "}\n" + "let obj = if thisobj.get().is_object() {\n" + " RootedObject::new(cx, thisobj.get().to_object())\n" + "} else {\n" + " RootedObject::new(cx, GetGlobalForObjectCrossCompartment(JS_CALLEE(cx, vp).to_object_or_null()))\n" + "};\n" "\n" - "let this: Unrooted<%s> = %s;\n" % (self.descriptor.concreteType, unwrapThis)) + "let this: Root<%s> = %s;\n" % (self.descriptor.concreteType, unwrapThis)) return CGList([ unwrapThis, self.generate_code() ], "\n") def generate_code(self): @@ -2596,12 +2756,11 @@ def __init__(self, descriptor, name): Argument('libc::c_uint', 'argc'), Argument('*mut JSVal', 'vp'), ] - CGAbstractMethod.__init__(self, descriptor, name, "JSBool", args, extern=True) + CGAbstractMethod.__init__(self, descriptor, name, "u8", args, extern=True) def definition_body(self): preamble = CGGeneric("""\ let global = global_object_for_js_object(JS_CALLEE(cx, vp).to_object()); -let global = global.root(); """) return CGList([preamble, self.generate_code()]) @@ -2621,7 +2780,7 @@ def __init__(self, descriptor): def generate_code(self): return CGGeneric( "let _info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" - "return CallJitMethodOp(_info, cx, obj, this.unsafe_get() as *mut libc::c_void, argc, vp);") + "return CallJitMethodOp(_info, cx, obj.handle(), this.r() as *const _ as *const libc::c_void as *mut libc::c_void, argc, vp);") class CGSpecializedMethod(CGAbstractExternMethod): """ @@ -2631,18 +2790,19 @@ class CGSpecializedMethod(CGAbstractExternMethod): def __init__(self, descriptor, method): self.method = method name = method.identifier.name - args = [Argument('*mut JSContext', 'cx'), Argument('JSHandleObject', '_obj'), + args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_obj'), Argument('*const %s' % descriptor.concreteType, 'this'), - Argument('libc::c_uint', 'argc'), Argument('*mut JSVal', 'vp')] - CGAbstractExternMethod.__init__(self, descriptor, name, 'JSBool', args) + Argument('*const JSJitMethodCallArgs', 'args')] + CGAbstractExternMethod.__init__(self, descriptor, name, 'u8', args) def definition_body(self): nativeName = CGSpecializedMethod.makeNativeName(self.descriptor, self.method) return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(), self.descriptor, self.method), - pre="let this = Unrooted::from_raw(this);\n" - "let this = this.root();\n") + pre="let this = &*this;\n" + "let args = &*args;\n" + "let argc = args.argc_;\n") @staticmethod def makeNativeName(descriptor, method): @@ -2661,14 +2821,16 @@ def __init__(self, descriptor, method): def generate_code(self): nativeName = CGSpecializedMethod.makeNativeName(self.descriptor, self.method) - return CGMethodCall(["global.r()"], nativeName, True, self.descriptor, self.method) + setupArgs = CGGeneric("let mut args = CallArgs::from_vp(vp, argc);\n") + call = CGMethodCall(["global.r()"], nativeName, True, self.descriptor, self.method) + return CGList([setupArgs, call]) class CGGenericGetter(CGAbstractBindingMethod): """ A class for generating the C++ code for an IDL attribute getter. """ def __init__(self, descriptor, lenientThis=False): - args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', '_argc'), + args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', 'argc'), Argument('*mut JSVal', 'vp')] if lenientThis: name = "genericLenientGetter" @@ -2685,7 +2847,7 @@ def __init__(self, descriptor, lenientThis=False): def generate_code(self): return CGGeneric( "let info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" - "return CallJitPropertyOp(info, cx, obj, this.unsafe_get() as *mut libc::c_void, vp);") + "return CallJitGetterOp(info, cx, obj.handle(), this.r() as *const _ as *const libc::c_void as *mut libc::c_void, argc, vp);") class CGSpecializedGetter(CGAbstractExternMethod): """ @@ -2696,10 +2858,10 @@ def __init__(self, descriptor, attr): self.attr = attr name = 'get_' + attr.identifier.name args = [ Argument('*mut JSContext', 'cx'), - Argument('JSHandleObject', '_obj'), + Argument('HandleObject', '_obj'), Argument('*const %s' % descriptor.concreteType, 'this'), - Argument('*mut JSVal', 'vp') ] - CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args) + Argument('JSJitGetterCallArgs', 'args') ] + CGAbstractExternMethod.__init__(self, descriptor, name, "u8", args) def definition_body(self): nativeName = CGSpecializedGetter.makeNativeName(self.descriptor, @@ -2707,8 +2869,7 @@ def definition_body(self): return CGWrapper(CGGetterCall([], self.attr.type, nativeName, self.descriptor, self.attr), - pre="let this = Unrooted::from_raw(this);\n" - "let this = this.root();\n") + pre="let this = &*this;\n") @staticmethod def makeNativeName(descriptor, attr): @@ -2734,8 +2895,10 @@ def __init__(self, descriptor, attr): def generate_code(self): nativeName = CGSpecializedGetter.makeNativeName(self.descriptor, self.attr) - return CGGetterCall(["global.r()"], self.attr.type, nativeName, self.descriptor, + setupArgs = CGGeneric("let mut args = CallArgs::from_vp(vp, argc);\n") + call = CGGetterCall(["global.r()"], self.attr.type, nativeName, self.descriptor, self.attr) + return CGList([setupArgs, call]) class CGGenericSetter(CGAbstractBindingMethod): @@ -2758,10 +2921,8 @@ def __init__(self, descriptor, lenientThis=False): def generate_code(self): return CGGeneric( - "let mut undef = UndefinedValue();\n" - "let argv: *mut JSVal = if argc != 0 { JS_ARGV(cx, vp) } else { &mut undef as *mut JSVal };\n" "let info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" - "if CallJitPropertyOp(info, cx, obj, this.unsafe_get() as *mut libc::c_void, argv) == 0 {\n" + "if CallJitSetterOp(info, cx, obj.handle(), this.r() as *const _ as *const libc::c_void as *mut libc::c_void, argc, vp) == 0 {\n" " return 0;\n" "}\n" "*vp = UndefinedValue();\n" @@ -2776,18 +2937,17 @@ def __init__(self, descriptor, attr): self.attr = attr name = 'set_' + attr.identifier.name args = [ Argument('*mut JSContext', 'cx'), - Argument('JSHandleObject', 'obj'), + Argument('HandleObject', 'obj'), Argument('*const %s' % descriptor.concreteType, 'this'), - Argument('*mut JSVal', 'argv')] - CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args) + Argument('JSJitSetterCallArgs', 'args')] + CGAbstractExternMethod.__init__(self, descriptor, name, "u8", args) def definition_body(self): nativeName = CGSpecializedSetter.makeNativeName(self.descriptor, self.attr) return CGWrapper(CGSetterCall([], self.attr.type, nativeName, self.descriptor, self.attr), - pre="let this = Unrooted::from_raw(this);\n" - "let this = this.root();\n") + pre="let this = &*this;\n") @staticmethod def makeNativeName(descriptor, attr): @@ -2808,7 +2968,7 @@ def generate_code(self): nativeName = CGSpecializedSetter.makeNativeName(self.descriptor, self.attr) checkForArg = CGGeneric( - "let argv = JS_ARGV(cx, vp);\n" + "let args = CallArgs::from_vp(vp, argc);\n" "if (argc == 0) {\n" " throw_type_error(cx, \"Not enough arguments to %s setter.\");\n" " return 0;\n" @@ -2831,17 +2991,17 @@ def definition_body(self): assert all(ord(c) < 128 for c in attrName) assert all(ord(c) < 128 for c in forwardToAttrName) return CGGeneric("""\ -let mut v = UndefinedValue(); -if JS_GetProperty(cx, *obj.unnamed_field1, b"%s".as_ptr() as *const i8, &mut v) == 0 { - return 0; +let mut v = RootedValue::new(cx, UndefinedValue()); +if JS_GetProperty(cx, obj, %s as *const u8 as *const i8, v.handle_mut()) == 0 { + return JSFalse; } -if !v.is_object() { +if !v.ptr.is_object() { throw_type_error(cx, "Value.%s is not an object."); - return 0; + return JSFalse; } -let target_obj = v.to_object(); -JS_SetProperty(cx, target_obj, b"%s".as_ptr() as *const i8, argv.offset(0)) -""" % (attrName, attrName, forwardToAttrName)) +let target_obj = RootedObject::new(cx, v.ptr.to_object()); +JS_SetProperty(cx, target_obj.handle(), %s as *const u8 as *const i8, args.get(0)) +""" % (str_to_const_array(attrName), attrName, str_to_const_array(forwardToAttrName))) class CGMemberJITInfo(CGThing): """ @@ -2852,52 +3012,253 @@ def __init__(self, descriptor, member): self.member = member self.descriptor = descriptor - def defineJitInfo(self, infoName, opName, infallible): - protoID = "PrototypeList::ID::%s as u32" % self.descriptor.name - depth = self.descriptor.interface.inheritanceDepth() - failstr = "true" if infallible else "false" - return ("const %s: JSJitInfo = JSJitInfo {\n" - " op: %s as *const u8,\n" - " protoID: %s,\n" - " depth: %s,\n" - " isInfallible: %s, /* False in setters. */\n" - " isConstant: false /* Only relevant for getters. */\n" - "};\n" % (infoName, opName, protoID, depth, failstr)) + def defineJitInfo(self, infoName, opName, opType, infallible, movable, + aliasSet, alwaysInSlot, lazilyInSlot, slotIndex, + returnTypes, args): + """ + aliasSet is a JSJitInfo::AliasSet value, without the "JSJitInfo::" bit. + + args is None if we don't want to output argTypes for some + reason (e.g. we have overloads or we're not a method) and + otherwise an iterable of the arguments for this method. + """ + assert(not movable or aliasSet != "AliasEverything") # Can't move write-aliasing things + assert(not alwaysInSlot or movable) # Things always in slots had better be movable + + def jitInfoInitializer(isTypedMethod): + initializer = fill( + """ + JSJitInfo { + _bindgen_data_1_: ${opName} as *const ::libc::c_void, + protoID: PrototypeList::ID::${name} as u16, + depth: ${depth}, + _bitfield_1: ((JSJitInfo_OpType::${opType} as u32) << 0) | + ((JSJitInfo_AliasSet::${aliasSet} as u32) << 4) | + ((JSValueType::${returnType} as u32) << 8) | + ((${isInfallible} as u32) << 16) | + ((${isMovable} as u32) << 17) | + ((${isAlwaysInSlot} as u32) << 18) | + ((${isLazilyCachedInSlot} as u32) << 19) | + ((${isTypedMethod} as u32) << 20) | + ((${slotIndex} as u32) << 21) + } + """, + opName=opName, + name=self.descriptor.name, + depth=self.descriptor.interface.inheritanceDepth(), + opType=opType, + aliasSet=aliasSet, + returnType=reduce(CGMemberJITInfo.getSingleReturnType, returnTypes, + ""), + isInfallible=toStringBool(infallible), + isMovable=toStringBool(movable), + isAlwaysInSlot=toStringBool(alwaysInSlot), + isLazilyCachedInSlot=toStringBool(lazilyInSlot), + isTypedMethod=toStringBool(isTypedMethod), + slotIndex=slotIndex) + return initializer.rstrip() + + return ("\n" + "const %s: JSJitInfo = %s;\n" + % (infoName, jitInfoInitializer(False))) def define(self): if self.member.isAttr(): getterinfo = ("%s_getterinfo" % self.member.identifier.name) getter = ("get_%s" % self.member.identifier.name) getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True) - result = self.defineJitInfo(getterinfo, getter, getterinfal) - if not self.member.readonly or self.member.getExtendedAttribute("PutForwards"): + + movable = self.mayBeMovable() and getterinfal + aliasSet = self.aliasSet() + + isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot") + if self.member.slotIndex is not None: + assert isAlwaysInSlot or self.member.getExtendedAttribute("Cached") + isLazilyCachedInSlot = not isAlwaysInSlot + slotIndex = memberReservedSlot(self.member) + # We'll statically assert that this is not too big in + # CGUpdateMemberSlotsMethod, in the case when + # isAlwaysInSlot is true. + else: + isLazilyCachedInSlot = False + slotIndex = "0" + + result = self.defineJitInfo(getterinfo, getter, "Getter", + getterinfal, movable, aliasSet, + isAlwaysInSlot, isLazilyCachedInSlot, + slotIndex, + [self.member.type], None) + if (not self.member.readonly or + self.member.getExtendedAttribute("PutForwards")): setterinfo = ("%s_setterinfo" % self.member.identifier.name) setter = ("set_%s" % self.member.identifier.name) # Setters are always fallible, since they have to do a typed unwrap. - result += "\n" + self.defineJitInfo(setterinfo, setter, False) + result += self.defineJitInfo(setterinfo, setter, "Setter", + False, False, "AliasEverything", + False, False, "0", + [BuiltinTypes[IDLBuiltinType.Types.void]], + None) return result if self.member.isMethod(): methodinfo = ("%s_methodinfo" % self.member.identifier.name) - # Actually a JSJitMethodOp, but JSJitPropertyOp by struct definition. method = ("%s" % self.member.identifier.name) # Methods are infallible if they are infallible, have no arguments # to unwrap, and have a return type that's infallible to wrap up for # return. - methodInfal = False sigs = self.member.signatures() - if len(sigs) == 1: + if len(sigs) != 1: # Don't handle overloading. If there's more than one signature, # one of them must take arguments. + methodInfal = False + args = None + movable = False + else: sig = sigs[0] - if len(sig[1]) == 0: - # No arguments and infallible return boxing - methodInfal = True + # For methods that affect nothing, it's OK to set movable to our + # notion of infallible on the C++ side, without considering + # argument conversions, since argument conversions that can + # reliably throw would be effectful anyway and the jit doesn't + # move effectful things. + hasInfallibleImpl = "infallible" in self.descriptor.getExtendedAttributes(self.member) + movable = self.mayBeMovable() and hasInfallibleImpl + # XXXbz can we move the smarts about fallibility due to arg + # conversions into the JIT, using our new args stuff? + if (len(sig[1]) != 0): + # We have arguments or our return-value boxing can fail + methodInfal = False + else: + methodInfal = hasInfallibleImpl + # For now, only bother to output args if we're side-effect-free. + if self.member.affects == "Nothing": + args = sig[1] + else: + args = None - result = self.defineJitInfo(methodinfo, method, methodInfal) + aliasSet = self.aliasSet() + result = self.defineJitInfo(methodinfo, method, "Method", + methodInfal, movable, aliasSet, + False, False, "0", + [s[0] for s in sigs], args) return result raise TypeError("Illegal member type to CGPropertyJITInfo") + def mayBeMovable(self): + """ + Returns whether this attribute or method may be movable, just + based on Affects/DependsOn annotations. + """ + affects = self.member.affects + dependsOn = self.member.dependsOn + assert affects in IDLInterfaceMember.AffectsValues + assert dependsOn in IDLInterfaceMember.DependsOnValues + # Things that are DependsOn=DeviceState are not movable, because we + # don't want them coalesced with each other or loop-hoisted, since + # their return value can change even if nothing is going on from our + # point of view. + return (affects == "Nothing" and + (dependsOn != "Everything" and dependsOn != "DeviceState")) + + def aliasSet(self): + """Returns the alias set to store in the jitinfo. This may not be the + effective alias set the JIT uses, depending on whether we have enough + information about our args to allow the JIT to prove that effectful + argument conversions won't happen. + + """ + dependsOn = self.member.dependsOn + assert dependsOn in IDLInterfaceMember.DependsOnValues + + if dependsOn == "Nothing" or dependsOn == "DeviceState": + assert self.member.affects == "Nothing" + return "AliasNone" + + if dependsOn == "DOMState": + assert self.member.affects == "Nothing" + return "AliasDOMSets" + + return "AliasEverything" + + @staticmethod + def getJSReturnTypeTag(t): + if t.nullable(): + # Sometimes it might return null, sometimes not + return "JSVAL_TYPE_UNKNOWN" + if t.isVoid(): + # No return, every time + return "JSVAL_TYPE_UNDEFINED" + if t.isArray(): + # No idea yet + assert False + if t.isSequence(): + return "JSVAL_TYPE_OBJECT" + if t.isMozMap(): + return "JSVAL_TYPE_OBJECT" + if t.isGeckoInterface(): + return "JSVAL_TYPE_OBJECT" + if t.isString(): + return "JSVAL_TYPE_STRING" + if t.isEnum(): + return "JSVAL_TYPE_STRING" + if t.isCallback(): + return "JSVAL_TYPE_OBJECT" + if t.isAny(): + # The whole point is to return various stuff + return "JSVAL_TYPE_UNKNOWN" + if t.isObject(): + return "JSVAL_TYPE_OBJECT" + if t.isSpiderMonkeyInterface(): + return "JSVAL_TYPE_OBJECT" + if t.isUnion(): + u = t.unroll() + if u.hasNullableType: + # Might be null or not + return "JSVAL_TYPE_UNKNOWN" + return reduce(CGMemberJITInfo.getSingleReturnType, + u.flatMemberTypes, "") + if t.isDictionary(): + return "JSVAL_TYPE_OBJECT" + if t.isDate(): + return "JSVAL_TYPE_OBJECT" + if not t.isPrimitive(): + raise TypeError("No idea what type " + str(t) + " is.") + tag = t.tag() + if tag == IDLType.Tags.bool: + return "JSVAL_TYPE_BOOLEAN" + if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, + IDLType.Tags.int16, IDLType.Tags.uint16, + IDLType.Tags.int32]: + return "JSVAL_TYPE_INT32" + if tag in [IDLType.Tags.int64, IDLType.Tags.uint64, + IDLType.Tags.unrestricted_float, IDLType.Tags.float, + IDLType.Tags.unrestricted_double, IDLType.Tags.double]: + # These all use JS_NumberValue, which can return int or double. + # But TI treats "double" as meaning "int or double", so we're + # good to return JSVAL_TYPE_DOUBLE here. + return "JSVAL_TYPE_DOUBLE" + if tag != IDLType.Tags.uint32: + raise TypeError("No idea what type " + str(t) + " is.") + # uint32 is sometimes int and sometimes double. + return "JSVAL_TYPE_DOUBLE" + + @staticmethod + def getSingleReturnType(existingType, t): + type = CGMemberJITInfo.getJSReturnTypeTag(t) + if existingType == "": + # First element of the list; just return its type + return type + + if type == existingType: + return existingType + if ((type == "JSVAL_TYPE_DOUBLE" and + existingType == "JSVAL_TYPE_INT32") or + (existingType == "JSVAL_TYPE_DOUBLE" and + type == "JSVAL_TYPE_INT32")): + # Promote INT32 to DOUBLE as needed + return "JSVAL_TYPE_DOUBLE" + # Different types + return "JSVAL_TYPE_UNKNOWN" + def getEnumValueName(value): # Some enum values can be empty strings. Others might have weird # characters in them. Deal with the former by returning "_empty", @@ -2933,7 +3294,7 @@ def __init__(self, enum): inner = """\ use dom::bindings::conversions::ToJSValConvertible; -use js::jsapi::JSContext; +use js::jsapi::{JSContext, MutableHandleValue}; use js::jsval::JSVal; pub const strings: &'static [&'static str] = &[ @@ -2941,8 +3302,8 @@ def __init__(self, enum): ]; impl ToJSValConvertible for super::%s { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { - strings[*self as usize].to_jsval(cx) + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { + strings[*self as usize].to_jsval(cx, rval); } } """ % (",\n ".join(['"%s"' % val for val in enum.values()]), enum.identifier.name) @@ -3047,7 +3408,7 @@ def define(self): " e%s(%s)," % (v["name"], v["typeName"]) for v in templateVars ] enumConversions = [ - " %s::e%s(ref inner) => inner.to_jsval(cx)," % (self.type, v["name"]) for v in templateVars + " %s::e%s(ref inner) => inner.to_jsval(cx, rval)," % (self.type, v["name"]) for v in templateVars ] # XXXManishearth The following should be #[must_root], # however we currently allow it till #2661 is fixed @@ -3058,7 +3419,7 @@ def define(self): } impl ToJSValConvertible for %s { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { match *self { %s } @@ -3147,7 +3508,7 @@ def get_match(name): if hasObjectTypes: assert interfaceObject templateBody = CGList([interfaceObject], "\n") - conversions.append(CGIfWrapper(templateBody, "value.is_object()")) + conversions.append(CGIfWrapper(templateBody, "value.get().is_object()")) otherMemberTypes = [ t for t in memberTypes if t.isPrimitive() or t.isString() or t.isEnum() @@ -3173,7 +3534,7 @@ def get_match(name): "Err(())" % ", ".join(names))) method = CGWrapper( CGIndenter(CGList(conversions, "\n\n")), - pre="fn from_jsval(cx: *mut JSContext, value: JSVal, _option: ()) -> Result<%s, ()> {\n" % self.type, + pre="fn from_jsval(cx: *mut JSContext, value: HandleValue, _option: ()) -> Result<%s, ()> {\n" % self.type, post="\n}") return CGWrapper( CGIndenter(CGList([ @@ -3190,7 +3551,7 @@ def try_method(self, t): return CGWrapper( CGIndenter(jsConversion, 4), - pre="fn TryConvertTo%s(cx: *mut JSContext, value: JSVal) -> %s {\n" % (t.name, returnType), + pre="fn TryConvertTo%s(cx: *mut JSContext, value: HandleValue) -> %s {\n" % (t.name, returnType), post="\n}") def define(self): @@ -3236,6 +3597,7 @@ def __init__(self, name, returnType, args, inline=False, static=False, override indicates whether to flag the method as MOZ_OVERRIDE """ assert not override or virtual + assert not (override and static) self.returnType = returnType self.args = args self.inline = False @@ -3378,9 +3740,14 @@ def getInitializationList(self, cgClass): def getBody(self, cgClass): initializers = [" parent: %s" % str(self.baseConstructors[0])] return (self.body + ( - "%s {\n" + "let mut ret = Rc::new(%s {\n" "%s\n" - "}") % (cgClass.name, '\n'.join(initializers))) + "});\n" + "match rc::get_mut(&mut ret) {\n" + " Some(ref mut callback) => callback.parent.init(%s),\n" + " None => unreachable!(),\n" + "};\n" + "ret") % (cgClass.name, '\n'.join(initializers), self.args[0].name)) def declare(self, cgClass): args = ', '.join([a.declare() for a in self.args]) @@ -3391,7 +3758,7 @@ def declare(self, cgClass): body = ' {\n' + body + '}' return string.Template("""\ -pub fn ${decorators}new(${args}) -> ${className}${body} +pub fn ${decorators}new(${args}) -> Rc<${className}>${body} """).substitute({ 'decorators': self.getDecorators(True), 'className': cgClass.getNameString(), 'args': args, @@ -3692,17 +4059,18 @@ def __init__(self, descriptor, operation): argument = arguments[1] info = getJSToNativeConversionInfo( argument.type, descriptor, treatNullAs=argument.treatNullAs, - exceptionCode="return false;") + exceptionCode="return JSFalse;") template = info.template declType = info.declType needsRooting = info.needsRooting templateValues = { - "val": "(*desc).value", + "val": "value.handle()", } self.cgRoot.prepend(instantiateJSToNativeConversionTemplate( template, templateValues, declType, argument.identifier.name, needsRooting)) + self.cgRoot.prepend(CGGeneric("let value = RootedValue::new(cx, desc.get().value);")) elif operation.isGetter(): self.cgRoot.prepend(CGGeneric("let mut found = false;")) @@ -3777,7 +4145,7 @@ def __init__(self, descriptor): class CGProxyUnwrap(CGAbstractMethod): def __init__(self, descriptor): - args = [Argument('*mut JSObject', 'obj')] + args = [Argument('HandleObject', 'obj')] CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", '*const ' + descriptor.concreteType, args, alwaysInline=True) def definition_body(self): @@ -3786,103 +4154,78 @@ def definition_body(self): obj = js::UnwrapObject(obj); }*/ //MOZ_ASSERT(IsProxy(obj)); -let box_ = GetProxyPrivate(obj).to_private() as *const %s; +let box_ = GetProxyPrivate(*obj.ptr).to_private() as *const %s; return box_;""" % self.descriptor.concreteType) class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'), - Argument('jsid', 'id'), Argument('bool', 'set'), - Argument('*mut JSPropertyDescriptor', 'desc')] + args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'), + Argument('HandleId', 'id'), + Argument('MutableHandle', 'desc')] CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor", - "bool", args) + "u8", args) self.descriptor = descriptor def getBody(self): indexedGetter = self.descriptor.operations['IndexedGetter'] indexedSetter = self.descriptor.operations['IndexedSetter'] - setOrIndexedGet = "" + get = "" if indexedGetter or indexedSetter: - setOrIndexedGet += "let index = get_array_index_from_id(cx, id);\n" + get = "let index = get_array_index_from_id(cx, id);\n" if indexedGetter: readonly = toStringBool(self.descriptor.operations['IndexedSetter'] is None) - fillDescriptor = "fill_property_descriptor(&mut *desc, proxy, %s);\nreturn true;" % readonly - templateValues = {'jsvalRef': '(*desc).value', 'successCode': fillDescriptor} - get = ("if index.is_some() {\n" + - " let index = index.unwrap();\n" + - " let this = UnwrapProxy(proxy);\n" + - " let this = Unrooted::from_raw(this);\n" + - " let this = this.root();\n" + - CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" + - "}\n") - - if indexedSetter or self.descriptor.operations['NamedSetter']: - setOrIndexedGet += "if set {\n" - if indexedSetter: - setOrIndexedGet += (" if index.is_some() {\n" + - " let index = index.unwrap();\n") - if not 'IndexedCreator' in self.descriptor.operations: - # FIXME need to check that this is a 'supported property index' - assert False - setOrIndexedGet += (" fill_property_descriptor(&mut *desc, proxy, false);\n" + - " return true;\n" + - " }\n") - if self.descriptor.operations['NamedSetter']: - setOrIndexedGet += " if RUST_JSID_IS_STRING(id) != 0 {\n" - if not 'NamedCreator' in self.descriptor.operations: - # FIXME need to check that this is a 'supported property name' - assert False - setOrIndexedGet += (" fill_property_descriptor(&mut *desc, proxy, false);\n" + - " return true;\n" + - " }\n") - setOrIndexedGet += "}" - if indexedGetter: - setOrIndexedGet += (" else {\n" + - CGIndenter(CGGeneric(get)).define() + - "}") - setOrIndexedGet += "\n\n" - elif indexedGetter: - setOrIndexedGet += ("if !set {\n" + - CGIndenter(CGGeneric(get)).define() + - "}\n\n") + fillDescriptor = "desc.get().value = result_root.ptr;\nfill_property_descriptor(&mut *desc.ptr, *proxy.ptr, %s);\nreturn JSTrue;" % readonly + templateValues = { + 'jsvalRef': 'result_root.handle_mut()', + 'successCode': fillDescriptor, + 'pre': 'let mut result_root = RootedValue::new(cx, UndefinedValue());' + } + get += ("if index.is_some() {\n" + + " let index = index.unwrap();\n" + + " let this = UnwrapProxy(proxy);\n" + + " let this = &*this;\n" + + CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" + + "}\n") namedGetter = self.descriptor.operations['NamedGetter'] if namedGetter: readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None) - fillDescriptor = "fill_property_descriptor(&mut *desc, proxy, %s);\nreturn true;" % readonly - templateValues = {'jsvalRef': '(*desc).value', 'successCode': fillDescriptor} + fillDescriptor = "desc.get().value = result_root.ptr;\nfill_property_descriptor(&mut *desc.ptr, *proxy.ptr, %s);\nreturn JSTrue;" % readonly + templateValues = { + 'jsvalRef': 'result_root.handle_mut()', + 'successCode': fillDescriptor, + 'pre': 'let mut result_root = RootedValue::new(cx, UndefinedValue());' + } # Once we start supporting OverrideBuiltins we need to make # ResolveOwnProperty or EnumerateOwnProperties filter out named # properties that shadow prototype properties. namedGet = ("\n" + - "if !set && RUST_JSID_IS_STRING(id) != 0 && !has_property_on_prototype(cx, proxy, id) {\n" + + "if RUST_JSID_IS_STRING(id) != 0 && !has_property_on_prototype(cx, proxy, id) {\n" + " let name = jsid_to_str(cx, id);\n" + " let this = UnwrapProxy(proxy);\n" + - " let this = Unrooted::from_raw(this);\n" + - " let this = this.root();\n" + + " let this = &*this;\n" + CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" + "}\n") else: namedGet = "" - return setOrIndexedGet + """\ -let expando: *mut JSObject = get_expando_object(proxy); + return get + """\ +let expando = RootedObject::new(cx, get_expando_object(proxy)); //if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) { -if !expando.is_null() { - let flags = if set { JSRESOLVE_ASSIGNING } else { 0 } | JSRESOLVE_QUALIFIED; - if JS_GetPropertyDescriptorById(cx, expando, id, flags, desc) == 0 { - return false; +if !expando.ptr.is_null() { + if JS_GetPropertyDescriptorById(cx, expando.handle(), id, desc) == 0 { + return JSFalse; } - if !(*desc).obj.is_null() { + if !desc.get().obj.is_null() { // Pretend the property lives on the wrapper. - (*desc).obj = proxy; - return true; + desc.get().obj = *proxy.ptr; + return JSTrue; } } """ + namedGet + """\ -(*desc).obj = ptr::null_mut(); -return true;""" +desc.get().obj = ptr::null_mut(); +return JSTrue;""" def definition_body(self): return CGGeneric(self.getBody()) @@ -3890,10 +4233,11 @@ def definition_body(self): # TODO(Issue 5876) class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'), - Argument('jsid', 'id'), - Argument('*mut JSPropertyDescriptor', 'desc')] - CGAbstractExternMethod.__init__(self, descriptor, "defineProperty", "bool", args) + args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'), + Argument('HandleId', 'id'), + Argument('Handle', 'desc'), + Argument('*mut ObjectOpResult', 'opresult')] + CGAbstractExternMethod.__init__(self, descriptor, "defineProperty", "u8", args) self.descriptor = descriptor def getBody(self): set = "" @@ -3906,14 +4250,13 @@ def getBody(self): "if index.is_some() {\n" + " let index = index.unwrap();\n" + " let this = UnwrapProxy(proxy);\n" + - " let this = Unrooted::from_raw(this);\n" + - " let this = this.root();\n" + + " let this = &*this;\n" + CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() + - " return true;\n" + + " return JSTrue;\n" + "}\n") elif self.descriptor.operations['IndexedGetter']: set += ("if get_array_index_from_id(cx, id).is_some() {\n" + - " return false;\n" + + " return JSFalse;\n" + " //return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" + "}\n") % self.descriptor.name @@ -3924,30 +4267,30 @@ def getBody(self): set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" + " let name = jsid_to_str(cx, id);\n" + " let this = UnwrapProxy(proxy);\n" + - " let this = Unrooted::from_raw(this);\n" + - " let this = this.root();\n" + + " let this = &*this;\n" + CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + - " return true;\n" + + " (*opresult).code_ = 0; /* SpecialCodes::OkCode */\n" + + " return JSTrue;\n" + "} else {\n" + - " return false;\n" + + " return JSFalse;\n" + "}\n") else: - if self.descriptor.operations['NamedGetter']: - set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" + - " let name = jsid_to_str(cx, id);\n" + - " let this = UnwrapProxy(proxy);\n" + - " let this = Unrooted::from_raw(this);\n" + - " let this = this.root();\n" + - CGProxyNamedPresenceChecker(self.descriptor).define() + - " if (found) {\n" + - # TODO(Issue 5876) - " //return js::IsInNonStrictPropertySet(cx)\n" + - " // ? opresult.succeed()\n" + - " // : ThrowErrorMessage(cx, MSG_NO_NAMED_SETTER, \"${name}\");\n" + - " return true;\n" + - " }\n" + - "}" - ) % (self.descriptor.name, self.descriptor.name) + set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" + + " let name = jsid_to_str(cx, id);\n" + + " let this = UnwrapProxy(proxy);\n" + + " let this = &*this;\n" + + CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + + " if (found) {\n" + # TODO(Issue 5876) + " //return js::IsInNonStrictPropertySet(cx)\n" + + " // ? opresult.succeed()\n" + + " // : ThrowErrorMessage(cx, MSG_NO_NAMED_SETTER, \"${name}\");\n" + + " (*opresult).code_ = 0; /* SpecialCodes::OkCode */\n" + + " return JSTrue;\n" + + " }\n" + + " (*opresult).code_ = 0; /* SpecialCodes::OkCode */\n" + + " return JSTrue;\n" + "}\n") % (self.descriptor.name, self.descriptor.name) set += "return proxyhandler::define_property(%s);" % ", ".join(a.name for a in self.args) return set @@ -3956,10 +4299,10 @@ def definition_body(self): class CGDOMJSProxyHandler_delete(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'), - Argument('jsid', 'id'), - Argument('*mut bool', 'bp')] - CGAbstractExternMethod.__init__(self, descriptor, "delete", "bool", args) + args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'), + Argument('HandleId', 'id'), + Argument('*mut ObjectOpResult', 'res')] + CGAbstractExternMethod.__init__(self, descriptor, "delete", "u8", args) self.descriptor = descriptor def getBody(self): @@ -3967,10 +4310,9 @@ def getBody(self): if self.descriptor.operations['NamedDeleter']: set += ("let name = jsid_to_str(cx, id);\n" + "let this = UnwrapProxy(proxy);\n" + - "let this = Unrooted::from_raw(this);\n" + - "let this = this.root();\n" + + "let this = &*this;\n" + "%s") % (CGProxyNamedDeleter(self.descriptor).define()) - set += "return proxyhandler::delete(%s);" % ", ".join(a.name for a in self.args) + set += "return proxyhandler::delete(%s) as u8;" % ", ".join(a.name for a in self.args) return set def definition_body(self): @@ -3978,9 +4320,9 @@ def definition_body(self): class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'), - Argument('jsid', 'id'), Argument('*mut bool', 'bp')] - CGAbstractExternMethod.__init__(self, descriptor, "hasOwn", "bool", args) + args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'), + Argument('HandleId', 'id'), Argument('*mut u8', 'bp')] + CGAbstractExternMethod.__init__(self, descriptor, "hasOwn", "u8", args) self.descriptor = descriptor def getBody(self): indexedGetter = self.descriptor.operations['IndexedGetter'] @@ -3989,11 +4331,10 @@ def getBody(self): "if index.is_some() {\n" + " let index = index.unwrap();\n" + " let this = UnwrapProxy(proxy);\n" + - " let this = Unrooted::from_raw(this);\n" + - " let this = this.root();\n" + + " let this = &*this;\n" + CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" + - " *bp = found;\n" + - " return true;\n" + + " *bp = found as u8;\n" + + " return JSTrue;\n" + "}\n\n") else: indexed = "" @@ -4003,57 +4344,56 @@ def getBody(self): named = ("if RUST_JSID_IS_STRING(id) != 0 && !has_property_on_prototype(cx, proxy, id) {\n" + " let name = jsid_to_str(cx, id);\n" + " let this = UnwrapProxy(proxy);\n" + - " let this = Unrooted::from_raw(this);\n" + - " let this = this.root();\n" + + " let this = &*this;\n" + CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + "\n" + - " *bp = found;\n" - " return true;\n" + " *bp = found as u8;\n" + " return JSTrue;\n" "}\n" + "\n") else: named = "" return indexed + """\ -let expando: *mut JSObject = get_expando_object(proxy); -if !expando.is_null() { - let mut b: JSBool = 1; - let ok = JS_HasPropertyById(cx, expando, id, &mut b) != 0; - *bp = b != 0; - if !ok || *bp { - return ok; +let expando = RootedObject::new(cx, get_expando_object(proxy)); +if !expando.ptr.is_null() { + let mut b: u8 = 1; + let ok = JS_HasPropertyById(cx, expando.handle(), id, &mut b) != 0; + *bp = (b != 0) as u8; + if !ok || *bp != 0 { + return ok as u8; } } """ + named + """\ -*bp = false; -return true;""" +*bp = JSFalse; +return JSTrue;""" def definition_body(self): return CGGeneric(self.getBody()) class CGDOMJSProxyHandler_get(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'), - Argument('*mut JSObject', '_receiver'), Argument('jsid', 'id'), - Argument('*mut JSVal', 'vp')] - CGAbstractExternMethod.__init__(self, descriptor, "get", "bool", args) + args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'), + Argument('HandleObject', '_receiver'), Argument('HandleId', 'id'), + Argument('MutableHandleValue', 'vp')] + CGAbstractExternMethod.__init__(self, descriptor, "get", "u8", args) self.descriptor = descriptor def getBody(self): getFromExpando = """\ -let expando = get_expando_object(proxy); -if !expando.is_null() { +let expando = RootedObject::new(cx, get_expando_object(proxy)); +if !expando.ptr.is_null() { let mut hasProp = 0; - if JS_HasPropertyById(cx, expando, id, &mut hasProp) == 0 { - return false; + if JS_HasPropertyById(cx, expando.handle(), id, &mut hasProp) == 0 { + return JSFalse; } if hasProp != 0 { - return JS_GetPropertyById(cx, expando, id, vp) != 0; + return (JS_GetPropertyById(cx, expando.handle(), id, vp) != 0) as u8; } }""" templateValues = { - 'jsvalRef': '*vp', - 'successCode': 'return true;', + 'jsvalRef': 'vp', + 'successCode': 'return JSTrue;', } indexedGetter = self.descriptor.operations['IndexedGetter'] @@ -4062,8 +4402,7 @@ def getBody(self): "if index.is_some() {\n" + " let index = index.unwrap();\n" + " let this = UnwrapProxy(proxy);\n" + - " let this = Unrooted::from_raw(this);\n" + - " let this = this.root();\n" + + " let this = &*this;\n" + CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define()) getIndexedOrExpando += """\ // Even if we don't have this index, we don't forward the @@ -4080,8 +4419,7 @@ def getBody(self): getNamed = ("if (RUST_JSID_IS_STRING(id) != 0) {\n" + " let name = jsid_to_str(cx, id);\n" + " let this = UnwrapProxy(proxy);\n" + - " let this = Unrooted::from_raw(this);\n" + - " let this = this.root();\n" + + " let this = &*this;\n" + CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "}\n") else: @@ -4094,26 +4432,26 @@ def getBody(self): %s let mut found = false; if !get_property_on_prototype(cx, proxy, id, &mut found, vp) { - return false; + return JSFalse; } if found { - return true; + return JSTrue; } %s -*vp = UndefinedValue(); -return true;""" % (getIndexedOrExpando, getNamed) +*vp.ptr = UndefinedValue(); +return JSTrue;""" % (getIndexedOrExpando, getNamed) def definition_body(self): return CGGeneric(self.getBody()) -class CGDOMJSProxyHandler_obj_toString(CGAbstractExternMethod): +class CGDOMJSProxyHandler_className(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', '_proxy')] - CGAbstractExternMethod.__init__(self, descriptor, "obj_toString", "*mut JSString", args) + args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_proxy')] + CGAbstractExternMethod.__init__(self, descriptor, "className", "*const i8", args) self.descriptor = descriptor def getBody(self): - return """proxyhandler::object_to_string(cx, "%s")""" % self.descriptor.name + return '%s as *const u8 as *const i8' % str_to_const_array(self.descriptor.name) def definition_body(self): return CGGeneric(self.getBody()) @@ -4165,7 +4503,8 @@ def __init__(self, descriptor): self.traceGlobal = descriptor.isGlobal() def generate_code(self): - body = [CGGeneric("(*this).trace(%s);" % self.args[0].name)] + body = [CGGeneric("if this.is_null() { return; } // GC during obj creation\n" + "(*this).trace(%s);" % self.args[0].name)] if self.traceGlobal: body += [CGGeneric("trace_global(trc, obj);")] return CGList(body, "\n") @@ -4177,7 +4516,7 @@ class CGClassConstructHook(CGAbstractExternMethod): def __init__(self, descriptor): args = [Argument('*mut JSContext', 'cx'), Argument('u32', 'argc'), Argument('*mut JSVal', 'vp')] CGAbstractExternMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME, - 'JSBool', args) + 'u8', args) self._ctor = self.descriptor.interface.ctor() def define(self): @@ -4188,7 +4527,7 @@ def define(self): def definition_body(self): preamble = CGGeneric("""\ let global = global_object_for_js_object(JS_CALLEE(cx, vp).to_object()); -let global = global.root(); +let args = CallArgs::from_vp(vp, argc); """) name = self._ctor.identifier.name nativeName = MakeNativeName(self.descriptor.binaryNameFor(name)) @@ -4201,7 +4540,7 @@ class CGClassFinalizeHook(CGAbstractClassHook): A hook for finalize, used to release our native object. """ def __init__(self, descriptor): - args = [Argument('*mut JSFreeOp', '_fop'), Argument('*mut JSObject', 'obj')] + args = [Argument('*mut FreeOp', '_fop'), Argument('*mut JSObject', 'obj')] CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME, 'void', args) @@ -4391,7 +4730,7 @@ def __init__(self, descriptor): cgThings.append(CGProxyUnwrap(descriptor)) cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor)) cgThings.append(CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor)) - cgThings.append(CGDOMJSProxyHandler_obj_toString(descriptor)) + cgThings.append(CGDOMJSProxyHandler_className(descriptor)) cgThings.append(CGDOMJSProxyHandler_get(descriptor)) cgThings.append(CGDOMJSProxyHandler_hasOwn(descriptor)) @@ -4427,7 +4766,7 @@ def define(self): return self.cgRoot.define() class CGNonNamespacedEnum(CGThing): - def __init__(self, enumName, names, values, comment="", deriving=""): + def __init__(self, enumName, names, values, comment="", deriving="", repr=""): if not values: values = [] @@ -4449,6 +4788,8 @@ def __init__(self, enumName, names, values, comment="", deriving=""): # Build the enum body. enumstr = comment + 'pub enum %s {\n%s\n}\n' % (enumName, ',\n'.join(entries)) + if repr: + enumstr = ('#[repr(%s)]\n' % repr) + enumstr if deriving: enumstr = ('#[derive(%s)]\n' % deriving) + enumstr curr = CGGeneric(enumstr) @@ -4523,13 +4864,13 @@ def impl(self): def memberInit(memberInfo): member, _ = memberInfo name = self.makeMemberName(member.identifier.name) - conversion = self.getMemberConversion(memberInfo) + conversion = self.getMemberConversion(memberInfo, member.type) return CGGeneric("%s: %s,\n" % (name, conversion.define())) def memberInsert(memberInfo): member, _ = memberInfo name = self.makeMemberName(member.identifier.name) - insertion = ("set_dictionary_property(cx, obj, \"%s\", &mut self.%s.to_jsval(cx)).unwrap();" % (name, name)) + insertion = ("let mut %s = RootedValue::new(cx, UndefinedValue());\nself.%s.to_jsval(cx, %s.handle_mut());\nset_dictionary_property(cx, obj.handle(), \"%s\", %s.handle()).unwrap();" % (name, name, name, name, name)) return CGGeneric("%s\n" % insertion) memberInits = CGList([memberInit(m) for m in self.memberInfo]) @@ -4537,14 +4878,14 @@ def memberInsert(memberInfo): return string.Template( "impl ${selfName} {\n" - " pub fn empty() -> ${selfName} {\n" - " ${selfName}::new(ptr::null_mut(), NullValue()).unwrap()\n" + " pub fn empty(cx: *mut JSContext) -> ${selfName} {\n" + " ${selfName}::new(cx, HandleValue::null()).unwrap()\n" " }\n" - " pub fn new(cx: *mut JSContext, val: JSVal) -> Result<${selfName}, ()> {\n" - " let object = if val.is_null_or_undefined() {\n" - " ptr::null_mut()\n" - " } else if val.is_object() {\n" - " val.to_object()\n" + " pub fn new(cx: *mut JSContext, val: HandleValue) -> Result<${selfName}, ()> {\n" + " let object = if val.get().is_null_or_undefined() {\n" + " RootedObject::new(cx, ptr::null_mut())\n" + " } else if val.get().is_object() {\n" + " RootedObject::new(cx, val.get().to_object())\n" " } else {\n" " throw_type_error(cx, \"Value not an object.\");\n" " return Err(());\n" @@ -4557,10 +4898,10 @@ def memberInsert(memberInfo): "}\n" "\n" "impl ToJSValConvertible for ${selfName} {\n" - " fn to_jsval(&self, cx: *mut JSContext) -> JSVal {\n" - " let obj = unsafe { JS_NewObject(cx, 0 as *const JSClass, 0 as *const JSObject, 0 as *const JSObject) };\n" + " fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {\n" + " let obj = unsafe { RootedObject::new(cx, JS_NewObject(cx, ptr::null())) };\n" "${insertMembers}" - " ObjectOrNullValue(obj)\n" + " rval.set(ObjectOrNullValue(obj.ptr))\n" " }\n" "}\n").substitute({ "selfName": self.makeClassName(d), @@ -4587,7 +4928,7 @@ def getMemberType(self, memberInfo): declType = CGWrapper(info.declType, pre="Option<", post=">") return declType.define() - def getMemberConversion(self, memberInfo): + def getMemberConversion(self, memberInfo, memberType): def indent(s): return CGIndenter(CGGeneric(s), 8).define() @@ -4595,8 +4936,10 @@ def indent(s): templateBody = info.template default = info.default declType = info.declType - replacements = { "val": "value" } + replacements = { "val": "rval.handle()" } conversion = string.Template(templateBody).substitute(replacements) + if memberType.isAny(): + conversion = "%s.get()" % conversion assert (member.defaultValue is None) == (default is None) if not default: @@ -4604,14 +4947,16 @@ def indent(s): conversion = "Some(%s)" % conversion conversion = ( - "match try!(get_dictionary_property(cx, object, \"%s\")) {\n" - " Some(value) => {\n" + "{\n" + "let mut rval = RootedValue::new(cx, UndefinedValue());\n" + "match try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut())) {\n" + " true => {\n" "%s\n" " },\n" - " None => {\n" + " false => {\n" "%s\n" " },\n" - "}") % (member.identifier.name, indent(conversion), indent(default)) + "}\n}") % (member.identifier.name, indent(conversion), indent(default)) return CGGeneric(conversion) @@ -4641,7 +4986,7 @@ class CGRegisterProtos(CGAbstractMethod): def __init__(self, config): arguments = [ Argument('*mut JSContext', 'cx'), - Argument('*mut JSObject', 'global'), + Argument('HandleObject', 'global'), ] CGAbstractMethod.__init__(self, None, 'Register', 'void', arguments, unsafe=False, pub=True) @@ -4732,38 +5077,41 @@ def __init__(self, config, prefix, webIDLFile): # Add imports curr = CGImports(curr, descriptors + callbackDescriptors, mainCallbacks, [ 'js', - 'js::{JS_ARGV, JS_CALLEE, JS_THIS_OBJECT}', - 'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS}', + 'js::JS_CALLEE', + 'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS, JSCLASS_IMPLEMENTS_BARRIERS}', 'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}', - 'js::{JSCLASS_RESERVED_SLOTS_MASK, JSID_VOID, JSJitInfo}', - 'js::{JSPROP_ENUMERATE, JSPROP_NATIVE_ACCESSORS, JSPROP_SHARED}', - 'js::{JSRESOLVE_ASSIGNING, JSRESOLVE_QUALIFIED}', + 'js::{JSCLASS_RESERVED_SLOTS_MASK}', + 'js::{JSPROP_ENUMERATE, JSPROP_SHARED}', 'js::jsapi::{JS_CallFunctionValue, JS_GetClass, JS_GetGlobalForObject}', 'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}', 'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot}', 'js::jsapi::{JS_HasProperty, JS_HasPropertyById, JS_IsExceptionPending}', - 'js::jsapi::{JS_NewObject, JS_ObjectIsCallable, JS_SetProperty, JS_SetPrototype}', - 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSBool, JSContext}', - 'js::jsapi::{JSClass, JSFreeOp, JSFunctionSpec, JSHandleObject, jsid}', - 'js::jsapi::{JSNativeWrapper, JSObject, JSPropertyDescriptor, JS_ArrayIterator}', - 'js::jsapi::{JSPropertyOpWrapper, JSPropertySpec, JS_PropertyStub}', - 'js::jsapi::{JSStrictPropertyOpWrapper, JSString, JSTracer, JS_ConvertStub}', - 'js::jsapi::{JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub}', - 'js::jsapi::{JSMutableHandleValue, JSHandleId, JSType}', + 'js::jsapi::{JS_NewObjectWithGivenProto, JS_NewObject, IsCallable, JS_SetProperty, JS_SetPrototype}', + 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSContext}', + 'js::jsapi::{JSClass, FreeOp, JSFreeOp, JSFunctionSpec, jsid}', + 'js::jsapi::{MutableHandleValue, MutableHandleObject, HandleObject, HandleValue, RootedObject, RootedValue}', + 'js::jsapi::{JSNativeWrapper, JSNative, JSObject, JSPropertyDescriptor}', + 'js::jsapi::{JSPropertySpec}', + 'js::jsapi::{JSString, JSTracer, JSJitInfo, JSJitInfo_OpType, JSJitInfo_AliasSet}', + 'js::jsapi::{MutableHandle, Handle, HandleId, JSType, JSValueType}', + 'js::jsapi::{SymbolCode, ObjectOpResult, HandleValueArray}', + 'js::jsapi::{JSJitGetterCallArgs, JSJitSetterCallArgs, JSJitMethodCallArgs, CallArgs}', + 'js::jsapi::{JSAutoCompartment, JSAutoRequest, JS_ComputeThis}', + 'js::jsapi::GetGlobalForObjectCrossCompartment', 'js::jsval::JSVal', 'js::jsval::{ObjectValue, ObjectOrNullValue, PrivateValue}', 'js::jsval::{NullValue, UndefinedValue}', - 'js::glue::{CallJitMethodOp, CallJitPropertyOp, CreateProxyHandler}', - 'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps, AutoIdVector}', + 'js::glue::{CallJitMethodOp, CallJitGetterOp, CallJitSetterOp, CreateProxyHandler}', + 'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps}', 'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}', 'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING}', - 'js::rust::with_compartment', + 'js::rust::GCMethods', + 'js::{JSTrue, JSFalse}', 'dom::bindings', 'dom::bindings::global::GlobalRef', 'dom::bindings::global::global_object_for_js_object', - 'dom::bindings::js::{JS, JSRef, Root, RootedReference, Temporary, Unrooted}', - 'dom::bindings::js::{OptionalOptionalRootable, OptionalRootable}', - 'dom::bindings::js::{OptionalRootedReference, ResultRootable, Rootable}', + 'dom::bindings::js::{JS, Root, RootedReference}', + 'dom::bindings::js::{OptionalRootedReference}', 'dom::bindings::utils::{create_dom_global, do_create_interface_objects}', 'dom::bindings::utils::ConstantSpec', 'dom::bindings::utils::{DOMClass}', @@ -4780,16 +5128,16 @@ def __init__(self, config, prefix, webIDLFile): 'dom::bindings::utils::{NativeProperties, NativePropertyHooks}', 'dom::bindings::utils::ConstantVal::{IntVal, UintVal}', 'dom::bindings::utils::NonNullJSNative', - 'dom::bindings::trace::JSTraceable', + 'dom::bindings::trace::{JSTraceable, RootedTraceable}', 'dom::bindings::callback::{CallbackContainer,CallbackInterface,CallbackFunction}', 'dom::bindings::callback::{CallSetup,ExceptionHandling}', 'dom::bindings::callback::wrap_call_this_object', 'dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}', - 'dom::bindings::conversions::{native_from_reflector, native_from_reflector_jsmanaged}', + 'dom::bindings::conversions::{native_from_reflector, native_from_handlevalue, native_from_handleobject}', 'dom::bindings::conversions::DOM_OBJECT_SLOT', 'dom::bindings::conversions::IDLInterface', 'dom::bindings::conversions::jsid_to_str', - 'dom::bindings::conversions::StringificationBehavior::{Default, Empty}', + 'dom::bindings::conversions::StringificationBehavior', 'dom::bindings::codegen::{PrototypeList, RegisterBindings, UnionTypes}', 'dom::bindings::codegen::Bindings::*', 'dom::bindings::error::{Fallible, Error, ErrorResult}', @@ -4812,6 +5160,10 @@ def __init__(self, config, prefix, webIDLFile): 'std::num', 'std::ptr', 'std::str', + 'std::rc', + 'std::rc::Rc', + 'std::default::Default', + 'std::ffi::CString', ]) # Add the auto-generated comment. @@ -4918,7 +5270,7 @@ def __init__(self, idlObject, descriptorProvider, baseName, methods, bases=[ClassBase(baseName)], constructors=self.getConstructors(), methods=realMethods+getters+setters, - decorators="#[derive(PartialEq,Copy,Clone)]#[jstraceable]") + decorators="#[derive(PartialEq)]#[jstraceable]") def getConstructors(self): return [ClassConstructor( @@ -4927,7 +5279,7 @@ def getConstructors(self): visibility="pub", explicit=False, baseConstructors=[ - "%s::new(aCallback)" % self.baseName + "%s::new()" % self.baseName ])] def getMethodImpls(self, method): @@ -4936,13 +5288,13 @@ def getMethodImpls(self, method): # Strip out the JSContext*/JSObject* args # that got added. assert args[0].name == "cx" and args[0].argType == "*mut JSContext" - assert args[1].name == "aThisObj" and args[1].argType == "*mut JSObject" + assert args[1].name == "aThisObj" and args[1].argType == "HandleObject" args = args[2:] # Record the names of all the arguments, so we can use them when we call # the private method. argnames = [arg.name for arg in args] - argnamesWithThis = ["s.get_context()", "thisObjJS"] + argnames - argnamesWithoutThis = ["s.get_context()", "ptr::null_mut()"] + argnames + argnamesWithThis = ["s.get_context()", "thisObjJS.handle()"] + argnames + argnamesWithoutThis = ["s.get_context()", "thisObjJS.handle()"] + argnames # Now that we've recorded the argnames for our call to our private # method, insert our optional argument for deciding whether the # CallSetup should re-throw exceptions on aRv. @@ -4951,12 +5303,12 @@ def getMethodImpls(self, method): # And now insert our template argument. argsWithoutThis = list(args) - args.insert(0, Argument("JSRef", "thisObj")) + args.insert(0, Argument("&T", "thisObj")) # And the self argument - method.args.insert(0, Argument(None, "self")) - args.insert(0, Argument(None, "self")) - argsWithoutThis.insert(0, Argument(None, "self")) + method.args.insert(0, Argument(None, "&self")) + args.insert(0, Argument(None, "&self")) + argsWithoutThis.insert(0, Argument(None, "&self")) setupCall = ("let s = CallSetup::new(self, aExceptionHandling);\n" "if s.get_context().is_null() {\n" @@ -4965,8 +5317,9 @@ def getMethodImpls(self, method): bodyWithThis = string.Template( setupCall+ - "let thisObjJS = wrap_call_this_object(s.get_context(), thisObj);\n" - "if thisObjJS.is_null() {\n" + "let mut thisObjJS = RootedObject::new(s.get_context(), ptr::null_mut());\n" + "wrap_call_this_object(s.get_context(), thisObj, thisObjJS.handle_mut());\n" + "if thisObjJS.ptr.is_null() {\n" " return Err(JSFailed);\n" "}\n" "return ${methodName}(${callArgs});").substitute({ @@ -4975,6 +5328,7 @@ def getMethodImpls(self, method): }) bodyWithoutThis = string.Template( setupCall + + "let thisObjJS = RootedObject::new(s.get_context(), ptr::null_mut());" "return ${methodName}(${callArgs});").substitute({ "callArgs" : ", ".join(argnamesWithoutThis), "methodName": 'self.' + method.name, @@ -5017,7 +5371,7 @@ class CGCallbackFunctionImpl(CGGeneric): def __init__(self, callback): impl = string.Template("""\ impl CallbackContainer for ${type} { - fn new(callback: *mut JSObject) -> ${type} { + fn new(callback: *mut JSObject) -> Rc<${type}> { ${type}::new(callback) } @@ -5027,8 +5381,8 @@ def __init__(self, callback): } impl ToJSValConvertible for ${type} { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { - self.callback().to_jsval(cx) + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { + self.callback().to_jsval(cx, rval); } }\ """).substitute({"type": callback.name}) @@ -5127,14 +5481,12 @@ def getImpl(self): "${returnResult}").substitute(replacements) return CGList([ CGGeneric(pre), - CGWrapper(CGIndenter(CGGeneric(body)), - pre="with_compartment(cx, self.parent.callback(), || {\n", - post="})") + CGGeneric(body), ], "\n").define() def getResultConversion(self): replacements = { - "val": "rval", + "val": "rval.handle()", } info = getJSToNativeConversionInfo( @@ -5153,6 +5505,8 @@ def getResultConversion(self): if self.retvalType is None or self.retvalType.isVoid(): retval = "()" + elif self.retvalType.isAny(): + retval = "rvalDecl.get()" else: retval = "rvalDecl" @@ -5177,16 +5531,17 @@ def getArgConversion(self, i, arg): argval = arg.identifier.name if arg.variadic: - argval = argval + "[idx]" + argval = argval + "[idx].get()" jsvalIndex = "%d + idx" % i else: jsvalIndex = "%d" % i if arg.optional and not arg.defaultValue: argval += ".clone().unwrap()" - conversion = wrapForType("argv[%s]" % jsvalIndex, - result=argval, - successCode="") + conversion = wrapForType( + "argv_root.handle_mut()", result=argval, + successCode="argv[%s] = argv_root.ptr;" % jsvalIndex, + pre="let mut argv_root = RootedValue::new(cx, UndefinedValue());") if arg.variadic: conversion = string.Template( "for idx in 0..${arg}.len() {\n" + @@ -5216,7 +5571,7 @@ def getArgs(self, returnType, argList): # We want to allow the caller to pass in a "this" object, as # well as a JSContext. return [Argument("*mut JSContext", "cx"), - Argument("*mut JSObject", "aThisObj")] + args + Argument("HandleObject", "aThisObj")] + args def getCallSetup(self): if self.needThisHandling: @@ -5230,7 +5585,7 @@ def getCallSetup(self): "}\n") def getArgcDecl(self): - return CGGeneric("let mut argc = %s as u32;" % self.argCountStr); + return CGGeneric("let mut argc = %s;" % self.argCountStr); @staticmethod def ensureASCIIName(idlObject): @@ -5252,7 +5607,7 @@ def __init__(self, sig, name, descriptorProvider, needThisHandling): CallbackMember.__init__(self, sig, name, descriptorProvider, needThisHandling) def getRvalDecl(self): - return "let mut rval = UndefinedValue();\n" + return "let mut rval = RootedValue::new(cx, UndefinedValue());\n" def getCall(self): replacements = { @@ -5260,15 +5615,16 @@ def getCall(self): "getCallable": self.getCallableDecl() } if self.argCount > 0: - replacements["argv"] = "argv.as_mut_ptr()" + replacements["argv"] = "argv.as_ptr()" replacements["argc"] = "argc" else: replacements["argv"] = "ptr::null_mut()" replacements["argc"] = "0" return string.Template("${getCallable}" "let ok = unsafe {\n" - " JS_CallFunctionValue(cx, ${thisObj}, callable,\n" - " ${argc}, ${argv}, &mut rval)\n" + " let rootedThis = RootedObject::new(cx, ${thisObj});\n" + " JS_CallFunctionValue(cx, rootedThis.handle(), callable.handle(),\n" + " &HandleValueArray { length_: ${argc} as ::libc::size_t, elements_: ${argv} }, rval.handle_mut())\n" "};\n" "if ok == 0 {\n" " return Err(JSFailed);\n" @@ -5280,10 +5636,10 @@ def __init__(self, callback, descriptorProvider): descriptorProvider, needThisHandling=True) def getThisObj(self): - return "aThisObj" + return "aThisObj.get()" def getCallableDecl(self): - return "let callable = ObjectValue(unsafe {&*self.parent.callback()});\n" + return "let callable = RootedValue::new(cx, ObjectValue(unsafe {&*self.parent.callback()}));\n" class CallbackOperationBase(CallbackMethod): """ @@ -5300,23 +5656,23 @@ def getThisObj(self): # This relies on getCallableDecl declaring a boolean # isCallable in the case when we're a single-operation # interface. - return "if isCallable { aThisObj } else { self.parent.callback() }" + return "if isCallable { aThisObj.get() } else { self.parent.callback() }" def getCallableDecl(self): replacements = { "methodName": self.methodName } getCallableFromProp = string.Template( - 'try!(self.parent.get_callable_property(cx, "${methodName}"))' + 'RootedValue::new(cx, try!(self.parent.get_callable_property(cx, "${methodName}")))' ).substitute(replacements) if not self.singleOperation: return 'JS::Rooted callable(cx);\n' + getCallableFromProp return ( - 'let isCallable = unsafe { JS_ObjectIsCallable(cx, self.parent.callback()) != 0 };\n' + 'let isCallable = unsafe { IsCallable(self.parent.callback()) != 0 };\n' 'let callable =\n' + CGIndenter( CGIfElseWrapper('isCallable', - CGGeneric('unsafe { ObjectValue(&*self.parent.callback()) }'), + CGGeneric('unsafe { RootedValue::new(cx, ObjectValue(&*self.parent.callback())) }'), CGGeneric(getCallableFromProp))).define() + ';\n') class CallbackOperation(CallbackOperationBase): @@ -5399,7 +5755,7 @@ def PrototypeList(config): return CGList([ CGGeneric(AUTOGENERATED_WARNING_COMMENT), CGGeneric("pub const MAX_PROTO_CHAIN_LENGTH: usize = %d;\n\n" % config.maxProtoChainLength), - CGNonNamespacedEnum('ID', protos, [0], deriving="PartialEq, Copy, Clone"), + CGNonNamespacedEnum('ID', protos, [0], deriving="PartialEq, Copy, Clone", repr="u16"), CGNonNamespacedEnum('Proxies', proxies, [0], deriving="PartialEq, Copy, Clone"), ]) @@ -5416,7 +5772,7 @@ def RegisterBindings(config): 'dom::bindings::codegen', 'dom::bindings::codegen::PrototypeList::Proxies', 'js::jsapi::JSContext', - 'js::jsapi::JSObject', + 'js::jsapi::HandleObject', 'libc', ], ignored_warnings=[]) @@ -5442,7 +5798,7 @@ def InheritTypes(config): descriptors = config.getDescriptors(register=True, isCallback=False) allprotos = [CGGeneric("use dom::types::*;\n"), - CGGeneric("use dom::bindings::js::{JS, JSRef, LayoutJS, Rootable, Temporary};\n"), + CGGeneric("use dom::bindings::js::{JS, LayoutJS, Root};\n"), CGGeneric("use dom::bindings::trace::JSTraceable;\n"), CGGeneric("use dom::bindings::utils::Reflectable;\n"), CGGeneric("use js::jsapi::JSTracer;\n\n"), @@ -5476,7 +5832,7 @@ def InheritTypes(config): pub struct ${name}Cast; impl ${name}Cast { #[inline] - pub fn to_ref<'a, T: ${toBound}+Reflectable>(base: JSRef<'a, T>) -> Option> { + pub fn to_ref<'a, T: ${toBound}+Reflectable>(base: &'a T) -> Option<&'a ${name}> { match base.${checkFn}() { true => Some(unsafe { mem::transmute(base) }), false => None @@ -5484,7 +5840,7 @@ def InheritTypes(config): } #[inline] - pub fn to_borrowed_ref<'a, 'b, T: ${toBound}+Reflectable>(base: &'a JSRef<'b, T>) -> Option<&'a JSRef<'b, ${name}>> { + pub fn to_borrowed_ref<'a, 'b, T: ${toBound}+Reflectable>(base: &'a &'b T) -> Option<&'a &'b ${name}> { match base.${checkFn}() { true => Some(unsafe { mem::transmute(base) }), false => None @@ -5503,20 +5859,20 @@ def InheritTypes(config): } #[inline] - pub fn to_temporary(base: Temporary) -> Option> { - match base.root().r().${checkFn}() { + pub fn to_root(base: Root) -> Option> { + match base.r().${checkFn}() { true => Some(unsafe { mem::transmute(base) }), false => None } } #[inline] - pub fn from_ref<'a, T: ${fromBound}+Reflectable>(derived: JSRef<'a, T>) -> JSRef<'a, ${name}> { + pub fn from_ref<'a, T: ${fromBound}+Reflectable>(derived: &'a T) -> &'a ${name} { unsafe { mem::transmute(derived) } } #[inline] - pub fn from_borrowed_ref<'a, 'b, T: ${fromBound}+Reflectable>(derived: &'a JSRef<'b, T>) -> &'a JSRef<'b, ${name}> { + pub fn from_borrowed_ref<'a, 'b, T: ${fromBound}+Reflectable>(derived: &'a &'b T) -> &'a &'b ${name} { unsafe { mem::transmute(derived) } } @@ -5527,7 +5883,7 @@ def InheritTypes(config): } #[inline] - pub fn from_temporary(derived: Temporary) -> Temporary<${name}> { + pub fn from_root(derived: Root) -> Root<${name}> { unsafe { mem::transmute(derived) } } diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 8741cb9eacf0..6e4bcbed34c9 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -148,16 +148,16 @@ def __init__(self, config, interface, desc): if self.interface.isCallback(): self.needsRooting = False ty = "%sBinding::%s" % (ifaceName, ifaceName) - self.returnType = ty + self.returnType = "Rc<%s>"% ty self.argumentType = "???" self.memberType = "???" self.nativeType = ty else: self.needsRooting = True - self.returnType = "Temporary<%s>" % ifaceName - self.argumentType = "JSRef<%s>" % ifaceName + self.returnType = "Root<%s>" % ifaceName + self.argumentType = "&%s" % ifaceName self.memberType = "Root<%s>" % ifaceName - self.nativeType = "Unrooted<%s>" % ifaceName + self.nativeType = "Root<%s>" % ifaceName self.concreteType = ifaceName self.register = desc.get('register', True) diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs index 089193cca43d..317744907c7f 100644 --- a/components/script/dom/bindings/conversions.rs +++ b/components/script/dom/bindings/conversions.rs @@ -24,17 +24,17 @@ //! | USVString | `USVString` | //! | ByteString | `ByteString` | //! | object | `*mut JSObject` | -//! | interface types | `JSRef` | `Temporary` | +//! | interface types | `&T` | `Root` | //! | dictionary types | `&T` | *unsupported* | //! | enumeration types | `T` | -//! | callback function types | `T` | +//! | callback function types | `Rc` | //! | nullable types | `Option` | //! | sequences | `Vec` | //! | union types | `T` | use dom::bindings::codegen::PrototypeList; use dom::bindings::error::throw_type_error; -use dom::bindings::js::{JSRef, Root, Unrooted}; +use dom::bindings::js::Root; use dom::bindings::num::Finite; use dom::bindings::str::{ByteString, USVString}; use dom::bindings::utils::{Reflectable, Reflector, DOMClass}; @@ -43,14 +43,15 @@ use util::str::DOMString; use js; use js::glue::{RUST_JSID_TO_STRING, RUST_JSID_IS_STRING}; use js::glue::RUST_JS_NumberValue; -use js::jsapi::{JSBool, JSContext, JSObject, JSString, jsid}; -use js::jsapi::{JS_ValueToUint64, JS_ValueToInt64}; -use js::jsapi::{JS_ValueToECMAUint32, JS_ValueToECMAInt32}; -use js::jsapi::{JS_ValueToUint16, JS_ValueToNumber, JS_ValueToBoolean}; -use js::jsapi::{JS_ValueToString, JS_GetStringCharsAndLength}; +use js::rust::{ToUint64, ToInt64}; +use js::rust::{ToUint32, ToInt32}; +use js::rust::{ToUint16, ToNumber, ToBoolean, ToString}; +use js::jsapi::{JSContext, JSObject, JSString}; +use js::jsapi::{JS_StringHasLatin1Chars, JS_GetLatin1StringCharsAndLength, JS_GetTwoByteStringCharsAndLength}; use js::jsapi::{JS_NewUCStringCopyN, JS_NewStringCopyN}; use js::jsapi::{JS_WrapValue}; use js::jsapi::{JSClass, JS_GetClass}; +use js::jsapi::{HandleId, HandleValue, HandleObject, MutableHandleValue}; use js::jsval::JSVal; use js::jsval::{UndefinedValue, NullValue, BooleanValue, Int32Value, UInt32Value}; use js::jsval::{StringValue, ObjectValue, ObjectOrNullValue}; @@ -60,6 +61,9 @@ use num::Float; use std::borrow::ToOwned; use std::default; use std::slice; +use std::ptr; +use std::rc::Rc; +use core::nonzero::NonZero; /// A trait to retrieve the constants necessary to check if a `JSObject` /// implements a given interface. @@ -74,7 +78,7 @@ pub trait IDLInterface { /// A trait to convert Rust types to `JSVal`s. pub trait ToJSValConvertible { /// Convert `self` to a `JSVal`. JSAPI failure causes a task failure. - fn to_jsval(&self, cx: *mut JSContext) -> JSVal; + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue); } /// A trait to convert `JSVal`s to Rust types. @@ -85,206 +89,201 @@ pub trait FromJSValConvertible { /// Optional configuration of type `T` can be passed as the `option` /// argument. /// If it returns `Err(())`, a JSAPI exception is pending. - fn from_jsval(cx: *mut JSContext, val: JSVal, option: Self::Config) -> Result; + fn from_jsval(cx: *mut JSContext, val: HandleValue, option: Self::Config) -> Result; } impl ToJSValConvertible for () { - fn to_jsval(&self, _cx: *mut JSContext) -> JSVal { - UndefinedValue() + fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) { + rval.set(UndefinedValue()); } } impl ToJSValConvertible for JSVal { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { - let mut value = *self; - if unsafe { JS_WrapValue(cx, &mut value) } == 0 { + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { + rval.set(*self); + if unsafe { JS_WrapValue(cx, rval) } == 0 { panic!("JS_WrapValue failed."); } - value } } -unsafe fn convert_from_jsval( - cx: *mut JSContext, value: JSVal, - convert_fn: unsafe extern "C" fn(*mut JSContext, JSVal, *mut T) -> JSBool) -> Result { - let mut ret = default::Default::default(); - if convert_fn(cx, value, &mut ret) == 0 { - Err(()) - } else { - Ok(ret) +impl ToJSValConvertible for HandleValue { + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { + rval.set(self.get()); + if unsafe { JS_WrapValue(cx, rval) } == 0 { + panic!("JS_WrapValue failed."); + } } } - impl ToJSValConvertible for bool { - fn to_jsval(&self, _cx: *mut JSContext) -> JSVal { - BooleanValue(*self) + fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) { + rval.set(BooleanValue(*self)); } } impl FromJSValConvertible for bool { type Config = (); - fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - let result = unsafe { convert_from_jsval(cx, val, JS_ValueToBoolean) }; - result.map(|b| b != 0) + fn from_jsval(_cx: *mut JSContext, val: HandleValue, _option: ()) -> Result { + Ok(ToBoolean(val)) } } impl ToJSValConvertible for i8 { - fn to_jsval(&self, _cx: *mut JSContext) -> JSVal { - Int32Value(*self as i32) + fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) { + rval.set(Int32Value(*self as i32)); } } impl FromJSValConvertible for i8 { type Config = (); - fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) }; + fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result { + let result = ToInt32(cx, val); result.map(|v| v as i8) } } impl ToJSValConvertible for u8 { - fn to_jsval(&self, _cx: *mut JSContext) -> JSVal { - Int32Value(*self as i32) + fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) { + rval.set(Int32Value(*self as i32)); } } impl FromJSValConvertible for u8 { type Config = (); - fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) }; + fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result { + let result = ToInt32(cx, val); result.map(|v| v as u8) } } impl ToJSValConvertible for i16 { - fn to_jsval(&self, _cx: *mut JSContext) -> JSVal { - Int32Value(*self as i32) + fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) { + rval.set(Int32Value(*self as i32)); } } impl FromJSValConvertible for i16 { type Config = (); - fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) }; + fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result { + let result = ToInt32(cx, val); result.map(|v| v as i16) } } impl ToJSValConvertible for u16 { - fn to_jsval(&self, _cx: *mut JSContext) -> JSVal { - Int32Value(*self as i32) + fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) { + rval.set(Int32Value(*self as i32)); } } impl FromJSValConvertible for u16 { type Config = (); - fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - unsafe { convert_from_jsval(cx, val, JS_ValueToUint16) } + fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result { + ToUint16(cx, val) } } impl ToJSValConvertible for i32 { - fn to_jsval(&self, _cx: *mut JSContext) -> JSVal { - Int32Value(*self) + fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) { + rval.set(Int32Value(*self)); } } impl FromJSValConvertible for i32 { type Config = (); - fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) } + fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result { + ToInt32(cx, val) } } impl ToJSValConvertible for u32 { - fn to_jsval(&self, _cx: *mut JSContext) -> JSVal { - UInt32Value(*self) + fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) { + rval.set(UInt32Value(*self)); } } impl FromJSValConvertible for u32 { type Config = (); - fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - unsafe { convert_from_jsval(cx, val, JS_ValueToECMAUint32) } + fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result { + ToUint32(cx, val) } } impl ToJSValConvertible for i64 { - fn to_jsval(&self, _cx: *mut JSContext) -> JSVal { + fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) { unsafe { - RUST_JS_NumberValue(*self as f64) + rval.set(RUST_JS_NumberValue(*self as f64)); } } } impl FromJSValConvertible for i64 { type Config = (); - fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - unsafe { convert_from_jsval(cx, val, JS_ValueToInt64) } + fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result { + ToInt64(cx, val) } } impl ToJSValConvertible for u64 { - fn to_jsval(&self, _cx: *mut JSContext) -> JSVal { + fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) { unsafe { - RUST_JS_NumberValue(*self as f64) + rval.set(RUST_JS_NumberValue(*self as f64)); } } } impl FromJSValConvertible for u64 { type Config = (); - fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - unsafe { convert_from_jsval(cx, val, JS_ValueToUint64) } + fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result { + ToUint64(cx, val) } } impl ToJSValConvertible for f32 { - fn to_jsval(&self, _cx: *mut JSContext) -> JSVal { + fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) { unsafe { - RUST_JS_NumberValue(*self as f64) + rval.set(RUST_JS_NumberValue(*self as f64)); } } } impl FromJSValConvertible for f32 { type Config = (); - fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - let result = unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) }; + fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result { + let result = ToNumber(cx, val); result.map(|f| f as f32) } } impl ToJSValConvertible for f64 { - fn to_jsval(&self, _cx: *mut JSContext) -> JSVal { + fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) { unsafe { - RUST_JS_NumberValue(*self) + rval.set(RUST_JS_NumberValue(*self)); } } } impl FromJSValConvertible for f64 { type Config = (); - fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) } + fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result { + ToNumber(cx, val) } } impl ToJSValConvertible for Finite { #[inline] - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { let value = **self; - value.to_jsval(cx) + value.to_jsval(cx, rval); } } impl> FromJSValConvertible for Finite { type Config = (); - fn from_jsval(cx: *mut JSContext, value: JSVal, option: ()) -> Result, ()> { + fn from_jsval(cx: *mut JSContext, value: HandleValue, option: ()) -> Result, ()> { let result = try!(FromJSValConvertible::from_jsval(cx, value, option)); match Finite::new(result) { Some(v) => Ok(v), @@ -297,21 +296,22 @@ impl> FromJSValConvertible for Finite } impl ToJSValConvertible for str { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { unsafe { let string_utf16: Vec = self.utf16_units().collect(); - let jsstr = JS_NewUCStringCopyN(cx, string_utf16.as_ptr(), string_utf16.len() as libc::size_t); + let jsstr = JS_NewUCStringCopyN(cx, string_utf16.as_ptr() as *const i16, + string_utf16.len() as libc::size_t); if jsstr.is_null() { panic!("JS_NewUCStringCopyN failed"); } - StringValue(&*jsstr) + rval.set(StringValue(&*jsstr)); } } } impl ToJSValConvertible for DOMString { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { - (**self).to_jsval(cx) + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { + (**self).to_jsval(cx, rval); } } @@ -333,18 +333,36 @@ impl default::Default for StringificationBehavior { /// Convert the given `JSString` to a `DOMString`. Fails if the string does not /// contain valid UTF-16. pub fn jsstring_to_str(cx: *mut JSContext, s: *mut JSString) -> DOMString { - unsafe { - let mut length = 0; - let chars = JS_GetStringCharsAndLength(cx, s, &mut length); + let mut length = 0; + let latin1 = unsafe { JS_StringHasLatin1Chars(s) != 0 }; + if latin1 { + let chars = unsafe { + JS_GetLatin1StringCharsAndLength(cx, ptr::null(), s, &mut length) + }; + assert!(!chars.is_null()); + + let mut buf = String::with_capacity(length as usize); + for i in 0..(length as isize) { + unsafe { + buf.push(*chars.offset(i) as char); + } + } + buf + } else { + let chars = unsafe { + JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), s, &mut length) + }; assert!(!chars.is_null()); - let char_vec = slice::from_raw_parts(chars, length as usize); + let char_vec = unsafe { + slice::from_raw_parts(chars as *const u16, length as usize) + }; String::from_utf16(char_vec).unwrap() } } /// Convert the given `jsid` to a `DOMString`. Fails if the `jsid` is not a /// string, or if the string does not contain valid UTF-16. -pub fn jsid_to_str(cx: *mut JSContext, id: jsid) -> DOMString { +pub fn jsid_to_str(cx: *mut JSContext, id: HandleId) -> DOMString { unsafe { assert!(RUST_JSID_IS_STRING(id) != 0); jsstring_to_str(cx, RUST_JSID_TO_STRING(id)) @@ -353,15 +371,16 @@ pub fn jsid_to_str(cx: *mut JSContext, id: jsid) -> DOMString { impl FromJSValConvertible for DOMString { type Config = StringificationBehavior; - fn from_jsval(cx: *mut JSContext, value: JSVal, + fn from_jsval(cx: *mut JSContext, value: HandleValue, null_behavior: StringificationBehavior) -> Result { - if null_behavior == StringificationBehavior::Empty && value.is_null() { + if null_behavior == StringificationBehavior::Empty && + value.get().is_null() { Ok("".to_owned()) } else { - let jsstr = unsafe { JS_ValueToString(cx, value) }; + let jsstr = ToString(cx, value); if jsstr.is_null() { - debug!("JS_ValueToString failed"); + debug!("ToString failed"); Err(()) } else { Ok(jsstring_to_str(cx, jsstr)) @@ -371,56 +390,75 @@ impl FromJSValConvertible for DOMString { } impl ToJSValConvertible for USVString { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { - self.0.to_jsval(cx) + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { + self.0.to_jsval(cx, rval); } } impl FromJSValConvertible for USVString { type Config = (); - fn from_jsval(cx: *mut JSContext, value: JSVal, _: ()) + fn from_jsval(cx: *mut JSContext, value: HandleValue, _: ()) -> Result { - let jsstr = unsafe { JS_ValueToString(cx, value) }; + let jsstr = ToString(cx, value); if jsstr.is_null() { - debug!("JS_ValueToString failed"); - Err(()) - } else { - unsafe { - let mut length = 0; - let chars = JS_GetStringCharsAndLength(cx, jsstr, &mut length); - assert!(!chars.is_null()); - let char_vec = slice::from_raw_parts(chars, length as usize); - Ok(USVString(String::from_utf16_lossy(char_vec))) - } + debug!("ToString failed"); + return Err(()); + } + let latin1 = unsafe { JS_StringHasLatin1Chars(jsstr) != 0 }; + if latin1 { + return Ok(USVString(jsstring_to_str(cx, jsstr))); + } + unsafe { + let mut length = 0; + let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), jsstr, &mut length); + assert!(!chars.is_null()); + let char_vec = slice::from_raw_parts(chars as *const u16, length as usize); + Ok(USVString(String::from_utf16_lossy(char_vec))) } } } impl ToJSValConvertible for ByteString { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { unsafe { let jsstr = JS_NewStringCopyN(cx, self.as_ptr() as *const libc::c_char, self.len() as libc::size_t); if jsstr.is_null() { panic!("JS_NewStringCopyN failed"); } - StringValue(&*jsstr) + rval.set(StringValue(&*jsstr)); } } } impl FromJSValConvertible for ByteString { type Config = (); - fn from_jsval(cx: *mut JSContext, value: JSVal, _option: ()) -> Result { - unsafe { - let string = JS_ValueToString(cx, value); - if string.is_null() { - debug!("JS_ValueToString failed"); - return Err(()); - } + fn from_jsval(cx: *mut JSContext, value: HandleValue, _option: ()) -> Result { + let string = ToString(cx, value); + if string.is_null() { + debug!("ToString failed"); + return Err(()); + } + + let latin1 = unsafe { JS_StringHasLatin1Chars(string) != 0 }; + if latin1 { + let mut length = 0; + let chars = unsafe { + JS_GetLatin1StringCharsAndLength(cx, ptr::null(), + string, &mut length) + }; + assert!(!chars.is_null()); + + let char_vec = unsafe { + Vec::from_raw_buf(chars as *mut u8, length as usize) + }; + + return Ok(ByteString::new(char_vec)); + } + unsafe { let mut length = 0; - let chars = JS_GetStringCharsAndLength(cx, string, &mut length); + let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), string, &mut length); let char_vec = slice::from_raw_parts(chars, length as usize); if char_vec.iter().any(|&c| c > 0xFF) { @@ -434,14 +472,13 @@ impl FromJSValConvertible for ByteString { } impl ToJSValConvertible for Reflector { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { - let obj = self.get_jsobject(); + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { + let obj = self.get_jsobject().get(); assert!(!obj.is_null()); - let mut value = ObjectValue(unsafe { &*obj }); - if unsafe { JS_WrapValue(cx, &mut value) } == 0 { + rval.set(ObjectValue(unsafe { &*obj })); + if unsafe { JS_WrapValue(cx, rval) } == 0 { panic!("JS_WrapValue failed."); } - value } } @@ -454,11 +491,10 @@ pub fn is_dom_class(clasp: *const JSClass) -> bool { /// Returns whether `obj` is a DOM object implemented as a proxy. pub fn is_dom_proxy(obj: *mut JSObject) -> bool { - use js::glue::{js_IsObjectProxyClass, js_IsFunctionProxyClass, IsProxyHandlerFamily}; - + use js::glue::IsProxyHandlerFamily; unsafe { - (js_IsObjectProxyClass(obj) || js_IsFunctionProxyClass(obj)) && - IsProxyHandlerFamily(obj) + let clasp = JS_GetClass(obj); + ((*clasp).flags & js::JSCLASS_IS_PROXY) != 0 && IsProxyHandlerFamily(obj) != 0 } } @@ -467,29 +503,24 @@ pub fn is_dom_proxy(obj: *mut JSObject) -> bool { // We use slot 0 for holding the raw object. This is safe for both // globals and non-globals. pub const DOM_OBJECT_SLOT: u32 = 0; -const DOM_PROXY_OBJECT_SLOT: u32 = js::JSSLOT_PROXY_PRIVATE; - -/// Returns the index of the slot wherein a pointer to the reflected DOM object -/// is stored. -/// -/// Fails if `obj` is not a DOM object. -pub unsafe fn dom_object_slot(obj: *mut JSObject) -> u32 { - let clasp = JS_GetClass(obj); - if is_dom_class(&*clasp) { - DOM_OBJECT_SLOT - } else { - assert!(is_dom_proxy(obj)); - DOM_PROXY_OBJECT_SLOT - } -} /// Get the DOM object from the given reflector. pub unsafe fn native_from_reflector(obj: *mut JSObject) -> *const T { use js::jsapi::JS_GetReservedSlot; + use js::glue::GetProxyPrivate; - let slot = dom_object_slot(obj); - let value = JS_GetReservedSlot(obj, slot); - value.to_private() as *const T + let clasp = JS_GetClass(obj); + let value = if is_dom_class(clasp) { + JS_GetReservedSlot(obj, DOM_OBJECT_SLOT) + } else { + assert!(is_dom_proxy(obj)); + GetProxyPrivate(obj) + }; + if value.is_undefined() { + ptr::null() + } else { + value.to_private() as *const T + } } /// Get the `DOMClass` from `obj`, or `Err(())` if `obj` is not a DOM object. @@ -518,17 +549,16 @@ unsafe fn get_dom_class(obj: *mut JSObject) -> Result { /// Returns Err(()) if `obj` is an opaque security wrapper or if the object is /// not a reflector for a DOM object of the given type (as defined by the /// proto_id and proto_depth). -pub fn native_from_reflector_jsmanaged(mut obj: *mut JSObject) -> Result, ()> +pub fn native_from_reflector_jsmanaged(mut obj: *mut JSObject) -> Result, ()> where T: Reflectable + IDLInterface { use js::glue::{IsWrapper, UnwrapObject}; - use std::ptr; unsafe { let dom_class = try!(get_dom_class(obj).or_else(|_| { if IsWrapper(obj) == 1 { debug!("found wrapper"); - obj = UnwrapObject(obj, /* stopAtOuter = */ 0, ptr::null_mut()); + obj = UnwrapObject(obj, /* stopAtOuter = */ 0); if obj.is_null() { debug!("unwrapping security wrapper failed"); Err(()) @@ -547,7 +577,9 @@ pub fn native_from_reflector_jsmanaged(mut obj: *mut JSObject) -> Result::get_prototype_depth(); if dom_class.interface_chain[proto_depth] == proto_id { debug!("good prototype"); - Ok(Unrooted::from_raw(native_from_reflector(obj))) + let native = native_from_reflector(obj); + assert!(!native.is_null()); + Ok(Root::new(NonZero::new(native))) } else { debug!("bad prototype"); Err(()) @@ -555,37 +587,54 @@ pub fn native_from_reflector_jsmanaged(mut obj: *mut JSObject) -> Result for a DOM object accessible from a HandleValue +pub fn native_from_handlevalue(v: HandleValue) -> Result, ()> + where T: Reflectable + IDLInterface +{ + native_from_reflector_jsmanaged(v.get().to_object()) +} + +/// Get a Rooted for a DOM object accessible from a HandleObject +pub fn native_from_handleobject(obj: HandleObject) -> Result, ()> + where T: Reflectable + IDLInterface +{ + native_from_reflector_jsmanaged(obj.get()) +} + impl ToJSValConvertible for Root { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { - self.r().reflector().to_jsval(cx) + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { + self.r().reflector().to_jsval(cx, rval); } } -impl<'a, T: Reflectable> ToJSValConvertible for JSRef<'a, T> { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { - self.reflector().to_jsval(cx) +impl<'a, T: Reflectable> ToJSValConvertible for &'a T { + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { + self.reflector().to_jsval(cx, rval); } } -impl<'a, T: Reflectable> ToJSValConvertible for Unrooted { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { - self.reflector().to_jsval(cx) +impl ToJSValConvertible for Option { + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { + match self { + &Some(ref value) => value.to_jsval(cx, rval), + &None => rval.set(NullValue()), + } } } -impl ToJSValConvertible for Option { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { +impl ToJSValConvertible for Option> { + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { match self { - &Some(ref value) => value.to_jsval(cx), - &None => NullValue(), + &Some(ref value) => (**value).to_jsval(cx, rval), + &None => rval.set(NullValue()), } } } impl> FromJSValConvertible for Option { type Config = (); - fn from_jsval(cx: *mut JSContext, value: JSVal, _: ()) -> Result, ()> { - if value.is_null_or_undefined() { + fn from_jsval(cx: *mut JSContext, value: HandleValue, _: ()) -> Result, ()> { + if value.get().is_null_or_undefined() { Ok(None) } else { let option: X = default::Default::default(); @@ -596,11 +645,10 @@ impl> FromJSValConvertibl } impl ToJSValConvertible for *mut JSObject { - fn to_jsval(&self, cx: *mut JSContext) -> JSVal { - let mut wrapped = ObjectOrNullValue(*self); + fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) { + rval.set(ObjectOrNullValue(*self)); unsafe { - assert!(JS_WrapValue(cx, &mut wrapped) != 0); + assert!(JS_WrapValue(cx, rval) != 0); } - wrapped } } diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index 7d1e7ecbdd69..d228679631a5 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -6,20 +6,22 @@ use dom::bindings::conversions::ToJSValConvertible; use dom::bindings::global::GlobalRef; -use dom::bindings::js::Rootable; use dom::domexception::{DOMException, DOMErrorName}; use util::str::DOMString; -use js::jsapi::{JSContext, JSObject}; +use js::jsapi::{JSContext, JSObject, RootedValue}; use js::jsapi::{JS_IsExceptionPending, JS_SetPendingException, JS_ReportPendingException}; -use js::jsapi::{JS_ReportErrorNumber, JSErrorFormatString, JSEXN_TYPEERR, JSEXN_RANGEERR}; +use js::jsapi::{JS_ReportErrorNumber1, JSErrorFormatString, JSExnType}; use js::jsapi::{JS_SaveFrameChain, JS_RestoreFrameChain}; -use js::rust::with_compartment; +use js::jsapi::JSAutoCompartment; +use js::jsval::UndefinedValue; +use js::JSFalse; use libc; use std::ffi::CString; use std::ptr; +use std::mem; /// DOM exceptions that can be thrown by a native DOM method. #[derive(Debug, Clone)] @@ -116,10 +118,11 @@ pub fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef, }; assert!(unsafe { JS_IsExceptionPending(cx) } == 0); - let exception = DOMException::new(global, code).root(); - let thrown = exception.to_jsval(cx); + let exception = DOMException::new(global, code); + let mut thrown = RootedValue::new(cx, UndefinedValue()); + exception.to_jsval(cx, thrown.handle_mut()); unsafe { - JS_SetPendingException(cx, thrown); + JS_SetPendingException(cx, thrown.handle()); } } @@ -128,9 +131,10 @@ pub fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) { unsafe { if JS_IsExceptionPending(cx) != 0 { let saved = JS_SaveFrameChain(cx); - with_compartment(cx, obj, || { + { + let _ac = JSAutoCompartment::new(cx, obj); JS_ReportPendingException(cx); - }); + } if saved != 0 { JS_RestoreFrameChain(cx); } @@ -158,25 +162,26 @@ static ERROR_FORMAT_STRING_STRING: [libc::c_char; 4] = [ static mut TYPE_ERROR_FORMAT_STRING: JSErrorFormatString = JSErrorFormatString { format: &ERROR_FORMAT_STRING_STRING as *const libc::c_char, argCount: 1, - exnType: JSEXN_TYPEERR as i16, + exnType: JSExnType::JSEXN_TYPEERR as i16, }; /// Format string struct used to throw `RangeError`s. static mut RANGE_ERROR_FORMAT_STRING: JSErrorFormatString = JSErrorFormatString { format: &ERROR_FORMAT_STRING_STRING as *const libc::c_char, argCount: 1, - exnType: JSEXN_RANGEERR as i16, + exnType: JSExnType::JSEXN_RANGEERR as i16, }; /// Callback used to throw javascript errors. /// See throw_js_error for info about error_number. unsafe extern fn get_error_message(_user_ref: *mut libc::c_void, - _locale: *const libc::c_char, - error_number: libc::c_uint) -> *const JSErrorFormatString + error_number: libc::c_uint) + -> *const JSErrorFormatString { - match error_number as i32 { - JSEXN_TYPEERR => &TYPE_ERROR_FORMAT_STRING as *const JSErrorFormatString, - JSEXN_RANGEERR => &RANGE_ERROR_FORMAT_STRING as *const JSErrorFormatString, + let num: JSExnType = mem::transmute(error_number); + match num { + JSExnType::JSEXN_TYPEERR => &TYPE_ERROR_FORMAT_STRING as *const JSErrorFormatString, + JSExnType::JSEXN_RANGEERR => &RANGE_ERROR_FORMAT_STRING as *const JSErrorFormatString, _ => panic!("Bad js error number given to get_error_message: {}", error_number) } } @@ -188,20 +193,18 @@ unsafe extern fn get_error_message(_user_ref: *mut libc::c_void, fn throw_js_error(cx: *mut JSContext, error: &str, error_number: u32) { let error = CString::new(error).unwrap(); unsafe { - JS_ReportErrorNumber(cx, - Some(get_error_message as - unsafe extern "C" fn(*mut libc::c_void, *const libc::c_char, - libc::c_uint) -> *const JSErrorFormatString), + JS_ReportErrorNumber1(cx, + Some(get_error_message), ptr::null_mut(), error_number, error.as_ptr()); } } /// Throw a `TypeError` with the given message. pub fn throw_type_error(cx: *mut JSContext, error: &str) { - throw_js_error(cx, error, JSEXN_TYPEERR as u32); + throw_js_error(cx, error, JSExnType::JSEXN_TYPEERR as u32); } /// Throw a `RangeError` with the given message. pub fn throw_range_error(cx: *mut JSContext, error: &str) { - throw_js_error(cx, error, JSEXN_RANGEERR as u32); + throw_js_error(cx, error, JSExnType::JSEXN_RANGEERR as u32); } diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index d1294173dd14..a6924fbb2815 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -9,7 +9,7 @@ use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::conversions::native_from_reflector_jsmanaged; -use dom::bindings::js::{JS, JSRef, Rootable, Root, Unrooted}; +use dom::bindings::js::{JS, Root}; use dom::bindings::utils::{Reflectable, Reflector}; use dom::document::DocumentHelpers; use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers}; @@ -21,7 +21,7 @@ use msg::constellation_msg::{PipelineId, WorkerId}; use net_traits::ResourceTask; use js::{JSCLASS_IS_GLOBAL, JSCLASS_IS_DOMJSCLASS}; -use js::glue::{GetGlobalForObjectCrossCompartment}; +use js::jsapi::{GetGlobalForObjectCrossCompartment}; use js::jsapi::{JSContext, JSObject}; use js::jsapi::{JS_GetClass}; use url::Url; @@ -30,9 +30,9 @@ use url::Url; #[derive(Copy, Clone)] pub enum GlobalRef<'a> { /// A reference to a `Window` object. - Window(JSRef<'a, window::Window>), + Window(&'a window::Window), /// A reference to a `WorkerGlobalScope` object. - Worker(JSRef<'a, WorkerGlobalScope>), + Worker(&'a WorkerGlobalScope), } /// A stack-based rooted reference to a global object. @@ -55,15 +55,6 @@ pub enum GlobalField { Worker(JS), } -/// An unrooted reference to a global object. -#[must_root] -pub enum GlobalUnrooted { - /// An unrooted reference to a `Window` object. - Window(Unrooted), - /// An unrooted reference to a `WorkerGlobalScope` object. - Worker(Unrooted), -} - impl<'a> GlobalRef<'a> { /// Get the `JSContext` for the `JSRuntime` associated with the thread /// this global object is on. @@ -76,7 +67,7 @@ impl<'a> GlobalRef<'a> { /// Extract a `Window`, causing task failure if the global object is not /// a `Window`. - pub fn as_window<'b>(&'b self) -> JSRef<'b, window::Window> { + pub fn as_window<'b>(&'b self) -> &'b window::Window { match *self { GlobalRef::Window(window) => window, GlobalRef::Worker(_) => panic!("expected a Window scope"), @@ -104,7 +95,7 @@ impl<'a> GlobalRef<'a> { pub fn resource_task(&self) -> ResourceTask { match *self { GlobalRef::Window(ref window) => { - let doc = window.Document().root(); + let doc = window.Document(); let doc = doc.r(); let loader = doc.loader(); loader.resource_task.clone() @@ -182,8 +173,8 @@ impl GlobalField { /// Create a new `GlobalField` from a rooted reference. pub fn from_rooted(global: &GlobalRef) -> GlobalField { match *global { - GlobalRef::Window(window) => GlobalField::Window(JS::from_rooted(window)), - GlobalRef::Worker(worker) => GlobalField::Worker(JS::from_rooted(worker)), + GlobalRef::Window(window) => GlobalField::Window(JS::from_ref(window)), + GlobalRef::Worker(worker) => GlobalField::Worker(JS::from_ref(worker)), } } @@ -196,30 +187,20 @@ impl GlobalField { } } -impl GlobalUnrooted { - /// Create a stack-bounded root for this reference. - pub fn root(&self) -> GlobalRoot { - match *self { - GlobalUnrooted::Window(ref window) => GlobalRoot::Window(window.root()), - GlobalUnrooted::Worker(ref worker) => GlobalRoot::Worker(worker.root()), - } - } -} - /// Returns the global object of the realm that the given JS object was created in. #[allow(unrooted_must_root)] -pub fn global_object_for_js_object(obj: *mut JSObject) -> GlobalUnrooted { +pub fn global_object_for_js_object(obj: *mut JSObject) -> GlobalRoot { unsafe { let global = GetGlobalForObjectCrossCompartment(obj); let clasp = JS_GetClass(global); assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0); match native_from_reflector_jsmanaged(global) { - Ok(window) => return GlobalUnrooted::Window(window), + Ok(window) => return GlobalRoot::Window(window), Err(_) => (), } match native_from_reflector_jsmanaged(global) { - Ok(worker) => return GlobalUnrooted::Worker(worker), + Ok(worker) => return GlobalRoot::Worker(worker), Err(_) => (), } diff --git a/components/script/dom/bindings/js.rs b/components/script/dom/bindings/js.rs index fc22078360f2..400200c3df3f 100644 --- a/components/script/dom/bindings/js.rs +++ b/components/script/dom/bindings/js.rs @@ -11,178 +11,32 @@ //! //! Here is a brief overview of the important types: //! -//! - `JSRef`: a freely-copyable reference to a rooted DOM object. //! - `Root`: a stack-based reference to a rooted DOM object. //! - `JS`: a reference to a DOM object that can automatically be traced by //! the GC when encountered as a field of a Rust structure. -//! - `Temporary`: a reference to a DOM object that will remain rooted for -//! the duration of its lifetime. //! -//! The rule of thumb is as follows: +//! `JS` does not allow access to their inner value without explicitly +//! creating a stack-based root via the `root` method. This returns a `Root`, +//! which causes the JS-owned value to be uncollectable for the duration of the +//! `Root` object's lifetime. A reference to the object can then be obtained +//! from the `Root` object. These references are not allowed to outlive their +//! originating `Root`. //! -//! - All methods return `Temporary`, to ensure the value remains alive -//! until it is stored somewhere that is reachable by the GC. -//! - All functions take `JSRef` arguments, to ensure that they will remain -//! uncollected for the duration of their usage. -//! - All DOM structs contain `JS` fields and derive the `JSTraceable` -//! trait, to ensure that they are transitively marked as reachable by the GC -//! if the enclosing value is reachable. -//! - All methods for type `T` are implemented for `JSRef`, to ensure that -//! the self value will not be collected for the duration of the method call. -//! -//! Both `Temporary` and `JS` do not allow access to their inner value -//! without explicitly creating a stack-based root via the `root` method -//! through the `Rootable` trait. This returns a `Root`, which causes the -//! JS-owned value to be uncollectable for the duration of the `Root` object's -//! lifetime. A `JSRef` can be obtained from a `Root` by calling the `r` -//! method. These `JSRef` values are not allowed to outlive their -//! originating `Root`, to ensure that all interactions with the enclosed -//! value only occur when said value is uncollectable, and will cause static -//! lifetime errors if misused. -//! -//! Other miscellaneous helper traits: -//! -//! - `OptionalRootable` and `OptionalOptionalRootable`: make rooting `Option` -//! values easy via a `root` method -//! - `ResultRootable`: make rooting successful `Result` values easy -//! - `TemporaryPushable`: allows mutating vectors of `JS` with new elements -//! of `JSRef`/`Temporary` -//! - `RootedReference`: makes obtaining an `Option>` from an -//! `Option>` easy use dom::bindings::trace::JSTraceable; -use dom::bindings::trace::RootedVec; +use dom::bindings::trace::trace_reflector; use dom::bindings::utils::{Reflector, Reflectable}; use dom::node::Node; -use js::jsapi::JSObject; -use js::jsval::JSVal; +use js::jsapi::{JSObject, Heap, JSTracer}; +use js::jsval::{JSVal, UndefinedValue}; use layout_interface::TrustedNodeAddress; use script_task::STACK_ROOTS; use core::nonzero::NonZero; -use libc; use std::cell::{Cell, UnsafeCell}; use std::default::Default; -use std::intrinsics::return_address; -use std::marker::PhantomData; use std::ops::Deref; -/// An unrooted, JS-owned value. Must not be held across a GC. -/// -/// This is used in particular to wrap pointers extracted from a reflector. -#[must_root] -pub struct Unrooted { - ptr: NonZero<*const T> -} - -impl Unrooted { - /// Create a new JS-owned value wrapped from a raw Rust pointer. - pub unsafe fn from_raw(raw: *const T) -> Unrooted { - assert!(!raw.is_null()); - Unrooted { - ptr: NonZero::new(raw) - } - } - - /// Create a new unrooted value from a `JS`. - #[allow(unrooted_must_root)] - pub fn from_js(ptr: JS) -> Unrooted { - Unrooted { - ptr: ptr.ptr - } - } - - /// Create a new unrooted value from a `Temporary`. - #[allow(unrooted_must_root)] - pub fn from_temporary(ptr: Temporary) -> Unrooted { - Unrooted::from_js(ptr.inner) - } - - /// Get the `Reflector` for this pointer. - pub fn reflector<'a>(&'a self) -> &'a Reflector { - unsafe { - (**self.ptr).reflector() - } - } - - /// Returns an unsafe pointer to the interior of this object. - pub unsafe fn unsafe_get(&self) -> *const T { - *self.ptr - } -} - -impl Rootable for Unrooted { - /// Create a stack-bounded root for this value. - fn root(&self) -> Root { - STACK_ROOTS.with(|ref collection| { - let RootCollectionPtr(collection) = collection.get().unwrap(); - unsafe { - Root::new(&*collection, self.ptr) - } - }) - } -} - -impl Copy for Unrooted {} -impl Clone for Unrooted { - fn clone(&self) -> Unrooted { *self } -} - -/// A type that represents a JS-owned value that is rooted for the lifetime of -/// this value. Importantly, it requires explicit rooting in order to interact -/// with the inner value. Can be assigned into JS-owned member fields (i.e. -/// `JS` types) safely via the `JS::assign` method or -/// `OptionalSettable::assign` (for `Option>` fields). -#[allow(unrooted_must_root)] -pub struct Temporary { - inner: JS, - /// On-stack JS pointer to assuage conservative stack scanner - _js_ptr: *mut JSObject, -} - -impl Clone for Temporary { - fn clone(&self) -> Temporary { - Temporary { - inner: self.inner, - _js_ptr: self._js_ptr, - } - } -} - -impl PartialEq for Temporary { - fn eq(&self, other: &Temporary) -> bool { - self.inner == other.inner - } -} - -impl Temporary { - /// Create a new `Temporary` value from an unrooted value. - #[allow(unrooted_must_root)] - pub fn from_unrooted(unrooted: Unrooted) -> Temporary { - Temporary { - inner: JS { ptr: unrooted.ptr }, - _js_ptr: unrooted.reflector().get_jsobject(), - } - } - - /// Create a new `Temporary` value from a rooted value. - #[allow(unrooted_must_root)] - pub fn from_rooted>(root: U) -> Temporary { - let inner = JS::from_rooted(root); - Temporary { - inner: inner, - _js_ptr: inner.reflector().get_jsobject(), - } - } -} - -impl Rootable for Temporary { - /// Create a stack-bounded root for this value. - fn root(&self) -> Root { - self.inner.root() - } -} - /// A traced reference to a DOM object. Must only be used as a field in other /// DOM objects. #[must_root] @@ -198,6 +52,32 @@ impl JS { } } } +impl JS { + /// Root this JS-owned value to prevent its collection as garbage. + pub fn root(&self) -> Root { + Root::new(self.ptr) + } + /// Create a JS from a Root + /// XXX Not a great API. Should be a call on Root instead + pub fn from_rooted(root: &Root) -> JS { + JS { + ptr: unsafe { NonZero::new(&**root) } + } + } + /// Create a JS from a &T + pub fn from_ref(obj: &T) -> JS { + JS { + ptr: unsafe { NonZero::new(&*obj) } + } + } + /// Store an rooted value in this field. This is safe under the + /// assumption that JS values are only used as fields in DOM types that + /// are reachable in the GC graph, so this unrooted value becomes + /// transitively rooted for the lifetime of its new owner. + pub fn assign(&mut self, val: Root) { + self.ptr = val.ptr.clone(); + } +} /// An unrooted reference to a DOM object for use in layout. `Layout*Helpers` /// traits must be implemented on this. @@ -208,7 +88,7 @@ pub struct LayoutJS { impl LayoutJS { /// Get the reflector. pub unsafe fn get_jsobject(&self) -> *mut JSObject { - (**self.ptr).reflector().get_jsobject() + (**self.ptr).reflector().get_jsobject().get() } } @@ -217,14 +97,12 @@ impl Copy for JS {} impl Copy for LayoutJS {} impl PartialEq for JS { - #[allow(unrooted_must_root)] fn eq(&self, other: &JS) -> bool { self.ptr == other.ptr } } impl PartialEq for LayoutJS { - #[allow(unrooted_must_root)] fn eq(&self, other: &LayoutJS) -> bool { self.ptr == other.ptr } @@ -260,29 +138,6 @@ impl LayoutJS { } } -impl Rootable for JS { - /// Root this JS-owned value to prevent its collection as garbage. - fn root(&self) -> Root { - STACK_ROOTS.with(|ref collection| { - let RootCollectionPtr(collection) = collection.get().unwrap(); - unsafe { - Root::new(&*collection, self.ptr) - } - }) - } -} - -impl JS { - /// Create a `JS` from any JS-managed pointer. - pub fn from_rooted>(root: T) -> JS { - unsafe { - root.get_js() - } - } -} - -//XXXjdm This is disappointing. This only gets called from trace hooks, in theory, -// so it's safe to assume that self is rooted and thereby safe to access. impl Reflectable for JS { fn reflector<'a>(&'a self) -> &'a Reflector { unsafe { @@ -298,19 +153,50 @@ impl Reflectable for JS { pub trait HeapGCValue: JSTraceable { } -impl HeapGCValue for JSVal { +impl HeapGCValue for Heap { } impl HeapGCValue for JS { } -/// A holder that provides interior mutability for GC-managed values such as -/// `JSVal` and `JS`. +/// A holder that provides interior mutability for GC-managed JSVals. /// /// Must be used in place of traditional interior mutability to ensure proper /// GC barriers are enforced. #[must_root] #[jstraceable] +pub struct MutHeapJSVal { + val: UnsafeCell>, +} + +impl MutHeapJSVal { + /// Create a new `MutHeapJSVal`. + pub fn new() -> MutHeapJSVal { + MutHeapJSVal { + val: UnsafeCell::new(Heap::default()), + } + } + + /// Set this `MutHeapJSVal` to the given value, calling write barriers as + /// appropriate. + pub fn set(&self, val: JSVal) { + unsafe { + let cell = self.val.get(); + (*cell).set(val); + } + } + + /// Set the value in this `MutHeapJSVal`, calling read barriers as appropriate. + pub fn get(&self) -> JSVal { + unsafe { (*self.val.get()).get() } + } +} + + +/// A holder that provides interior mutability for GC-managed values such as +/// `JS`. +#[must_root] +#[jstraceable] pub struct MutHeap { val: Cell, } @@ -323,13 +209,12 @@ impl MutHeap { } } - /// Set this `MutHeap` to the given value, calling write barriers as - /// appropriate. + /// Set this `MutHeap` to the given value. pub fn set(&self, val: T) { self.val.set(val) } - /// Set the value in this `MutHeap`, calling read barriers as appropriate. + /// Set the value in this `MutHeap`. pub fn get(&self) -> T { self.val.get() } @@ -353,8 +238,7 @@ impl MutNullableHeap { } } - /// Set this `MutNullableHeap` to the given value, calling write barriers - /// as appropriate. + /// Set this `MutNullableHeap` to the given value. pub fn set(&self, val: Option) { self.ptr.set(val); } @@ -368,14 +252,14 @@ impl MutNullableHeap { impl MutNullableHeap> { /// Retrieve a copy of the current inner value. If it is `None`, it is /// initialized with the result of `cb` first. - pub fn or_init(&self, cb: F) -> Temporary - where F: FnOnce() -> Temporary + pub fn or_init(&self, cb: F) -> Root + where F: FnOnce() -> Root { match self.get() { - Some(inner) => Temporary::from_rooted(inner), + Some(inner) => Root::from_rooted(inner), None => { let inner = cb(); - self.set(Some(JS::from_rooted(inner.clone()))); + self.set(Some(JS::from_rooted(&inner))); inner }, } @@ -396,16 +280,6 @@ impl Default for MutNullableHeap { } } -impl JS { - /// Store an unrooted value in this field. This is safe under the - /// assumption that JS values are only used as fields in DOM types that - /// are reachable in the GC graph, so this unrooted value becomes - /// transitively rooted for the lifetime of its new owner. - pub fn assign(&mut self, val: Temporary) { - *self = val.inner.clone(); - } -} - impl LayoutJS { /// Returns an unsafe pointer to the interior of this JS object. This is /// the only method that be safely accessed from layout. (The fact that @@ -419,129 +293,36 @@ impl LayoutJS { pub trait RootedReference { /// Obtain a safe optional reference to the wrapped JS owned-value that /// cannot outlive the lifetime of this root. - fn r<'a>(&'a self) -> Option>; + fn r<'a>(&'a self) -> Option<&'a T>; } impl RootedReference for Option> { - fn r<'a>(&'a self) -> Option> { + fn r<'a>(&'a self) -> Option<&'a T> { self.as_ref().map(|root| root.r()) } } -/// Get an `Option>>` out of an `Option>>` +/// Get an `Option>` out of an `Option>>` pub trait OptionalRootedReference { /// Obtain a safe optional optional reference to the wrapped JS owned-value /// that cannot outlive the lifetime of this root. - fn r<'a>(&'a self) -> Option>>; + fn r<'a>(&'a self) -> Option>; } impl OptionalRootedReference for Option>> { - fn r<'a>(&'a self) -> Option>> { + fn r<'a>(&'a self) -> Option> { self.as_ref().map(|inner| inner.r()) } } -/// Trait that allows extracting a `JS` value from a variety of -/// rooting-related containers, which in general is an unsafe operation since -/// they can outlive the rooted lifetime of the original value. -pub trait Assignable { - /// Extract an unrooted `JS`. - unsafe fn get_js(&self) -> JS; -} - -impl Assignable for JS { - unsafe fn get_js(&self) -> JS { - self.clone() - } -} - -impl<'a, T: Reflectable> Assignable for JSRef<'a, T> { - unsafe fn get_js(&self) -> JS { - JS { - ptr: self.ptr - } - } -} - -impl Assignable for Temporary { - unsafe fn get_js(&self) -> JS { - self.inner.clone() - } -} - - -/// Root a rootable `Option` type (used for `Option>`) -pub trait OptionalRootable { - /// Root the inner value, if it exists. - fn root(&self) -> Option>; -} - -impl> OptionalRootable for Option { - fn root(&self) -> Option> { - self.as_ref().map(|inner| inner.root()) - } -} - -/// Root a rootable `Option