Skip to content

Commit

Permalink
Auto merge of #5862 - nox:mutnullableheap, r=jdm
Browse files Browse the repository at this point in the history
This is useful for union types, in cases where we need MutNullableHeap<NodeOrString>.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/5862)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Apr 27, 2015
2 parents 21c38d0 + afafde5 commit b0ddd81
Show file tree
Hide file tree
Showing 18 changed files with 172 additions and 169 deletions.
10 changes: 5 additions & 5 deletions components/script/dom/attr.rs
Expand Up @@ -6,7 +6,7 @@ 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::{JSRef, MutNullableJS, Temporary};
use dom::bindings::js::{JS, JSRef, MutNullableHeap, Temporary};
use dom::bindings::js::{OptionalRootable, OptionalRootedRootable};
use dom::bindings::js::RootedReference;
use dom::bindings::utils::{Reflector, reflect_dom_object};
Expand Down Expand Up @@ -104,7 +104,7 @@ pub struct Attr {
prefix: Option<DOMString>,

/// the element that owns this attribute.
owner: MutNullableJS<Element>,
owner: MutNullableHeap<JS<Element>>,
}

impl Attr {
Expand All @@ -117,7 +117,7 @@ impl Attr {
name: name,
namespace: namespace,
prefix: prefix,
owner: MutNullableJS::new(owner),
owner: MutNullableHeap::new(owner.map(JS::from_rooted)),
}
}

Expand Down Expand Up @@ -271,11 +271,11 @@ impl<'a> AttrHelpers<'a> for JSRef<'a, Attr> {
}
(old, new) => assert!(old == new)
}
self.owner.assign(owner)
self.owner.set(owner.map(JS::from_rooted))
}

fn owner(self) -> Option<Temporary<Element>> {
self.owner.get()
self.owner.get().map(Temporary::new)
}

fn summarize(self) -> AttrInfo {
Expand Down
81 changes: 35 additions & 46 deletions components/script/dom/bindings/js.rs
Expand Up @@ -339,76 +339,65 @@ impl<T: HeapGCValue+Copy> MutHeap<T> {
}
}

/// A mutable `JS<T>` value, with nullability represented by an enclosing
/// Option wrapper. Must be used in place of traditional internal mutability
/// to ensure that the proper GC barriers are enforced.
/// A mutable holder for GC-managed values such as `JSval` and `JS<T>`, with
/// nullability represented by an enclosing Option wrapper. Must be used in
/// place of traditional internal mutability to ensure that the proper GC
/// barriers are enforced.
#[must_root]
#[jstraceable]
pub struct MutNullableJS<T: Reflectable> {
ptr: Cell<Option<JS<T>>>
pub struct MutNullableHeap<T: HeapGCValue+Copy> {
ptr: Cell<Option<T>>
}

impl<U: Reflectable> MutNullableJS<U> {
/// Create a new `MutNullableJS`
pub fn new<T: Assignable<U>>(initial: Option<T>) -> MutNullableJS<U> {
MutNullableJS {
ptr: Cell::new(initial.map(|initial| {
unsafe { initial.get_js() }
}))
impl<T: HeapGCValue+Copy> MutNullableHeap<T> {
/// Create a new `MutNullableHeap`.
pub fn new(initial: Option<T>) -> MutNullableHeap<T> {
MutNullableHeap {
ptr: Cell::new(initial)
}
}
}

impl<T: Reflectable> Default for MutNullableJS<T> {
fn default() -> MutNullableJS<T> {
MutNullableJS {
ptr: Cell::new(None)
}
}
}

impl<T: Reflectable> MutNullableJS<T> {
/// Store an unrooted value in this field. This is safe under the
/// assumption that `MutNullableJS<T>` 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<U: Assignable<T>>(&self, val: Option<U>) {
self.ptr.set(val.map(|val| {
unsafe { val.get_js() }
}));
}

/// Set the inner value to null, without making API users jump through
/// useless type-ascription hoops.
pub fn clear(&self) {
self.assign(None::<JS<T>>);
/// Set this `MutNullableHeap` to the given value, calling write barriers
/// as appropriate.
pub fn set(&self, val: Option<T>) {
self.ptr.set(val);
}

/// Retrieve a copy of the current optional inner value.
pub fn get(&self) -> Option<Temporary<T>> {
self.ptr.get().map(Temporary::new)
}

/// Retrieve a copy of the inner optional `JS<T>` as `LayoutJS<T>`.
/// For use by layout, which can't use safe types like Temporary.
pub unsafe fn get_inner_as_layout(&self) -> Option<LayoutJS<T>> {
self.ptr.get().map(|js| js.to_layout())
pub fn get(&self) -> Option<T> {
self.ptr.get()
}
}

impl<T: Reflectable> MutNullableHeap<JS<T>> {
/// 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<F>(&self, cb: F) -> Temporary<T>
where F: FnOnce() -> Temporary<T>
{
match self.get() {
Some(inner) => inner,
Some(inner) => Temporary::new(inner),
None => {
let inner = cb();
self.assign(Some(inner.clone()));
self.set(Some(JS::from_rooted(inner.clone())));
inner
},
}
}

/// Retrieve a copy of the inner optional `JS<T>` as `LayoutJS<T>`.
/// For use by layout, which can't use safe types like Temporary.
pub unsafe fn get_inner_as_layout(&self) -> Option<LayoutJS<T>> {
self.ptr.get().map(|js| js.to_layout())
}
}

impl<T: HeapGCValue+Copy> Default for MutNullableHeap<T> {
fn default() -> MutNullableHeap<T> {
MutNullableHeap {
ptr: Cell::new(None)
}
}
}

impl<T: Reflectable> JS<T> {
Expand Down
42 changes: 22 additions & 20 deletions components/script/dom/document.rs
Expand Up @@ -24,8 +24,10 @@ use dom::bindings::error::{ErrorResult, Fallible};
use dom::bindings::error::Error::{NotSupported, InvalidCharacter, Security};
use dom::bindings::error::Error::HierarchyRequest;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{MutNullableJS, JS, JSRef, LayoutJS, Temporary, TemporaryPushable};
use dom::bindings::js::{OptionalRootable, RootedReference};
use dom::bindings::js::{JS, JSRef, LayoutJS, MutNullableHeap};
use dom::bindings::js::{OptionalRootable, OptionalRootedRootable};
use dom::bindings::js::{RootedReference, Temporary};
use dom::bindings::js::TemporaryPushable;
use dom::bindings::refcounted::Trusted;
use dom::bindings::trace::RootedVec;
use dom::bindings::utils::reflect_dom_object;
Expand Down Expand Up @@ -102,28 +104,28 @@ pub struct Document {
node: Node,
window: JS<Window>,
idmap: DOMRefCell<HashMap<Atom, Vec<JS<Element>>>>,
implementation: MutNullableJS<DOMImplementation>,
location: MutNullableJS<Location>,
implementation: MutNullableHeap<JS<DOMImplementation>>,
location: MutNullableHeap<JS<Location>>,
content_type: DOMString,
last_modified: Option<DOMString>,
encoding_name: DOMRefCell<DOMString>,
is_html_document: bool,
url: Url,
quirks_mode: Cell<QuirksMode>,
images: MutNullableJS<HTMLCollection>,
embeds: MutNullableJS<HTMLCollection>,
links: MutNullableJS<HTMLCollection>,
forms: MutNullableJS<HTMLCollection>,
scripts: MutNullableJS<HTMLCollection>,
anchors: MutNullableJS<HTMLCollection>,
applets: MutNullableJS<HTMLCollection>,
images: MutNullableHeap<JS<HTMLCollection>>,
embeds: MutNullableHeap<JS<HTMLCollection>>,
links: MutNullableHeap<JS<HTMLCollection>>,
forms: MutNullableHeap<JS<HTMLCollection>>,
scripts: MutNullableHeap<JS<HTMLCollection>>,
anchors: MutNullableHeap<JS<HTMLCollection>>,
applets: MutNullableHeap<JS<HTMLCollection>>,
ready_state: Cell<DocumentReadyState>,
/// The element that has most recently requested focus for itself.
possibly_focused: MutNullableJS<Element>,
possibly_focused: MutNullableHeap<JS<Element>>,
/// The element that currently has the document focus context.
focused: MutNullableJS<Element>,
focused: MutNullableHeap<JS<Element>>,
/// The script element that is currently executing.
current_script: MutNullableJS<HTMLScriptElement>,
current_script: MutNullableHeap<JS<HTMLScriptElement>>,
/// https://html.spec.whatwg.org/multipage/#concept-n-noscript
/// True if scripting is enabled for all scripts in this document
scripting_enabled: Cell<bool>,
Expand Down Expand Up @@ -440,19 +442,19 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
/// Return the element that currently has focus.
// https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#events-focusevent-doc-focus
fn get_focused_element(self) -> Option<Temporary<Element>> {
self.focused.get()
self.focused.get().map(Temporary::new)
}

/// Initiate a new round of checking for elements requesting focus. The last element to call
/// `request_focus` before `commit_focus_transaction` is called will receive focus.
fn begin_focus_transaction(self) {
self.possibly_focused.clear();
self.possibly_focused.set(None);
}

/// Request that the given element receive focus once the current transaction is complete.
fn request_focus(self, elem: JSRef<Element>) {
if elem.is_focusable_area() {
self.possibly_focused.assign(Some(elem))
self.possibly_focused.set(Some(JS::from_rooted(elem)))
}
}

Expand All @@ -466,7 +468,7 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
node.set_focus_state(false);
}

self.focused.assign(self.possibly_focused.get());
self.focused.set(self.possibly_focused.get());

if let Some(ref elem) = self.focused.get().root() {
let node: JSRef<Node> = NodeCast::from_ref(elem.r());
Expand Down Expand Up @@ -741,7 +743,7 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
}

fn set_current_script(self, script: Option<JSRef<HTMLScriptElement>>) {
self.current_script.assign(script);
self.current_script.set(script.map(JS::from_rooted));
}

fn trigger_mozbrowser_event(self, event: MozBrowserEvent) {
Expand Down Expand Up @@ -1250,7 +1252,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {

// https://html.spec.whatwg.org/#dom-document-currentscript
fn GetCurrentScript(self) -> Option<Temporary<HTMLScriptElement>> {
self.current_script.get()
self.current_script.get().map(Temporary::new)
}

// https://html.spec.whatwg.org/#dom-document-body
Expand Down
9 changes: 5 additions & 4 deletions components/script/dom/element.rs
Expand Up @@ -27,8 +27,9 @@ use dom::bindings::codegen::UnionTypes::NodeOrString;
use dom::bindings::error::{ErrorResult, Fallible};
use dom::bindings::error::Error::{InvalidCharacter, Syntax};
use dom::bindings::error::Error::NoModificationAllowed;
use dom::bindings::js::{MutNullableJS, JS, JSRef, LayoutJS, Temporary, TemporaryPushable};
use dom::bindings::js::{OptionalRootable, RootedReference};
use dom::bindings::js::{JS, JSRef, LayoutJS, MutNullableHeap};
use dom::bindings::js::{OptionalRootable, RootedReference, Temporary};
use dom::bindings::js::TemporaryPushable;
use dom::bindings::trace::RootedVec;
use dom::bindings::utils::{xml_name_type, validate_and_extract};
use dom::bindings::utils::XMLName::InvalidXMLName;
Expand Down Expand Up @@ -88,8 +89,8 @@ pub struct Element {
prefix: Option<DOMString>,
attrs: DOMRefCell<Vec<JS<Attr>>>,
style_attribute: DOMRefCell<Option<PropertyDeclarationBlock>>,
attr_list: MutNullableJS<NamedNodeMap>,
class_list: MutNullableJS<DOMTokenList>,
attr_list: MutNullableHeap<JS<NamedNodeMap>>,
class_list: MutNullableHeap<JS<DOMTokenList>>,
}

impl ElementDerived for EventTarget {
Expand Down
18 changes: 9 additions & 9 deletions components/script/dom/event.rs
Expand Up @@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::EventBinding;
use dom::bindings::codegen::Bindings::EventBinding::{EventConstants, EventMethods};
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{MutNullableJS, JSRef, Temporary};
use dom::bindings::js::{JS, JSRef, MutNullableHeap, Temporary};
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::eventtarget::{EventTarget, EventTargetHelpers};
use util::str::DOMString;
Expand Down Expand Up @@ -58,8 +58,8 @@ pub enum EventCancelable {
pub struct Event {
reflector_: Reflector,
type_id: EventTypeId,
current_target: MutNullableJS<EventTarget>,
target: MutNullableJS<EventTarget>,
current_target: MutNullableHeap<JS<EventTarget>>,
target: MutNullableHeap<JS<EventTarget>>,
type_: DOMRefCell<DOMString>,
phase: Cell<EventPhase>,
canceled: Cell<bool>,
Expand Down Expand Up @@ -124,17 +124,17 @@ impl Event {

#[inline]
pub fn clear_current_target(&self) {
self.current_target.clear();
self.current_target.set(None);
}

#[inline]
pub fn set_current_target(&self, val: JSRef<EventTarget>) {
self.current_target.assign(Some(val));
self.current_target.set(Some(JS::from_rooted(val)));
}

#[inline]
pub fn set_target(&self, val: JSRef<EventTarget>) {
self.target.assign(Some(val));
self.target.set(Some(JS::from_rooted(val)));
}

#[inline]
Expand Down Expand Up @@ -188,12 +188,12 @@ impl<'a> EventMethods for JSRef<'a, Event> {

// https://dom.spec.whatwg.org/#dom-event-target
fn GetTarget(self) -> Option<Temporary<EventTarget>> {
self.target.get()
self.target.get().map(Temporary::new)
}

// https://dom.spec.whatwg.org/#dom-event-currenttarget
fn GetCurrentTarget(self) -> Option<Temporary<EventTarget>> {
self.current_target.get()
self.current_target.get().map(Temporary::new)
}

// https://dom.spec.whatwg.org/#dom-event-defaultprevented
Expand Down Expand Up @@ -248,7 +248,7 @@ impl<'a> EventMethods for JSRef<'a, Event> {
self.stop_immediate.set(false);
self.canceled.set(false);
self.trusted.set(false);
self.target.clear();
self.target.set(None);
*self.type_.borrow_mut() = type_;
self.bubbles.set(bubbles);
self.cancelable.set(cancelable);
Expand Down
5 changes: 3 additions & 2 deletions components/script/dom/htmlanchorelement.rs
Expand Up @@ -13,7 +13,8 @@ use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::{HTMLAnchorElementDerived, HTMLImageElementDerived};
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast};
use dom::bindings::codegen::InheritTypes::{MouseEventCast, NodeCast};
use dom::bindings::js::{MutNullableJS, JSRef, Temporary, OptionalRootable};
use dom::bindings::js::{JS, JSRef, MutNullableHeap, Temporary};
use dom::bindings::js::OptionalRootable;
use dom::document::{Document, DocumentHelpers};
use dom::domtokenlist::DOMTokenList;
use dom::element::{Element, AttributeHandlers, ElementTypeId};
Expand All @@ -32,7 +33,7 @@ use util::str::DOMString;
#[dom_struct]
pub struct HTMLAnchorElement {
htmlelement: HTMLElement,
rel_list: MutNullableJS<DOMTokenList>,
rel_list: MutNullableHeap<JS<DOMTokenList>>,
}

impl HTMLAnchorElementDerived for EventTarget {
Expand Down
4 changes: 2 additions & 2 deletions components/script/dom/htmlareaelement.rs
Expand Up @@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::HTMLAreaElementBinding;
use dom::bindings::codegen::Bindings::HTMLAreaElementBinding::HTMLAreaElementMethods;
use dom::bindings::codegen::InheritTypes::{HTMLAreaElementDerived, HTMLElementCast};
use dom::bindings::codegen::InheritTypes::ElementCast;
use dom::bindings::js::{MutNullableJS, JSRef, Temporary};
use dom::bindings::js::{JS, JSRef, MutNullableHeap, Temporary};
use dom::bindings::utils::Reflectable;
use dom::document::Document;
use dom::domtokenlist::DOMTokenList;
Expand All @@ -24,7 +24,7 @@ use util::str::DOMString;
#[dom_struct]
pub struct HTMLAreaElement {
htmlelement: HTMLElement,
rel_list: MutNullableJS<DOMTokenList>,
rel_list: MutNullableHeap<JS<DOMTokenList>>,
}

impl HTMLAreaElementDerived for EventTarget {
Expand Down

0 comments on commit b0ddd81

Please sign in to comment.