servo: Merge #2633 - Use more internal mutability for DOM objects (from Ms2ger:derefmut); r=jdm
authorMs2ger <ms2ger@gmail.com>
Wed, 11 Jun 2014 13:59:01 -0400
changeset 334512 31ec9f20fa96096d4a29538def77a67fae9cd61c
parent 334511 2acf0874f9ec860d41c877f72f189ff1a8a5fb64
child 334513 fcc8f262c8789b316c17fafcfdd50d7477f9fabd
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdm
servo: Merge #2633 - Use more internal mutability for DOM objects (from Ms2ger:derefmut); r=jdm Part of #1854. Source-Repo: https://github.com/servo/servo Source-Revision: cc23f3c4360a37e4dc763d4eade779a411a6d97a
servo/src/components/main/layout/wrapper.rs
servo/src/components/script/dom/bindings/utils.rs
servo/src/components/script/dom/characterdata.rs
servo/src/components/script/dom/customevent.rs
servo/src/components/script/dom/document.rs
servo/src/components/script/dom/event.rs
servo/src/components/script/dom/eventdispatcher.rs
servo/src/components/script/dom/eventtarget.rs
servo/src/components/script/dom/formdata.rs
servo/src/components/script/dom/htmlbodyelement.rs
servo/src/components/script/dom/htmlelement.rs
servo/src/components/script/dom/htmliframeelement.rs
servo/src/components/script/dom/htmlimageelement.rs
servo/src/components/script/dom/htmlserializer.rs
servo/src/components/script/dom/node.rs
servo/src/components/script/dom/progressevent.rs
servo/src/components/script/dom/uievent.rs
servo/src/components/script/dom/window.rs
servo/src/components/script/dom/xmlhttprequest.rs
servo/src/components/script/dom/xmlhttprequesteventtarget.rs
servo/src/components/script/html/hubbub_html_parser.rs
servo/src/components/script/script_task.rs
--- a/servo/src/components/main/layout/wrapper.rs
+++ b/servo/src/components/main/layout/wrapper.rs
@@ -107,17 +107,17 @@ pub trait TLayoutNode {
     /// If this node is an iframe element, returns its pipeline and subpage IDs. If this node is
     /// not an iframe element, fails.
     fn iframe_pipeline_and_subpage_ids(&self) -> (PipelineId, SubpageId) {
         unsafe {
             if !self.get().is_htmliframeelement() {
                 fail!("not an iframe element!")
             }
             let iframe_element: JS<HTMLIFrameElement> = self.get_jsmanaged().transmute_copy();
-            let size = (*iframe_element.unsafe_get()).size.unwrap();
+            let size = (*iframe_element.unsafe_get()).size.deref().get().unwrap();
             (size.pipeline_id, size.subpage_id)
         }
     }
 
     /// If this is a text node, copies out the text. If this is not a text node, fails.
     ///
     /// FIXME(pcwalton): Don't copy text. Atomically reference count instead.
     fn text(&self) -> String;
@@ -183,17 +183,17 @@ impl<'ln> TLayoutNode for LayoutNode<'ln
     }
 
     fn text(&self) -> String {
         unsafe {
             if !self.get().is_text() {
                 fail!("not text!")
             }
             let text: JS<Text> = self.get_jsmanaged().transmute_copy();
-            (*text.unsafe_get()).characterdata.data.to_str()
+            (*text.unsafe_get()).characterdata.data.deref().borrow().clone()
         }
     }
 }
 
 impl<'ln> LayoutNode<'ln> {
     /// Creates a new layout node, scoped to the given closure.
     pub unsafe fn with_layout_node<R>(node: JS<Node>, f: <'a> |LayoutNode<'a>| -> R) -> R {
         f(LayoutNode {
@@ -489,17 +489,17 @@ impl<'ln> TLayoutNode for ThreadSafeLayo
             }
         }
 
         unsafe {
             if !self.get().is_text() {
                 fail!("not text!")
             }
             let text: JS<Text> = self.get_jsmanaged().transmute_copy();
-            (*text.unsafe_get()).characterdata.data.to_str()
+            (*text.unsafe_get()).characterdata.data.deref().borrow().clone()
         }
     }
 }
 
 
 impl<'ln> ThreadSafeLayoutNode<'ln> {
     /// Creates a new `ThreadSafeLayoutNode` from the given `LayoutNode`.
     pub fn new<'a>(node: &LayoutNode<'a>) -> ThreadSafeLayoutNode<'a> {
@@ -631,17 +631,17 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
         traversal.process(self)
     }
 
     pub fn is_ignorable_whitespace(&self) -> bool {
         match self.type_id() {
             Some(TextNodeTypeId) => {
                 unsafe {
                     let text: JS<Text> = self.get_jsmanaged().transmute_copy();
-                    if !is_whitespace((*text.unsafe_get()).characterdata.data.as_slice()) {
+                    if !is_whitespace((*text.unsafe_get()).characterdata.data.deref().borrow().as_slice()) {
                         return false
                     }
 
                     // NB: See the rules for `white-space` here:
                     //
                     //    http://www.w3.org/TR/CSS21/text.html#propdef-white-space
                     //
                     // If you implement other values for this property, you will almost certainly
--- a/servo/src/components/script/dom/bindings/utils.rs
+++ b/servo/src/components/script/dom/bindings/utils.rs
@@ -601,17 +601,17 @@ pub extern fn outerize_global(_cx: *mut 
         debug!("outerizing");
         let obj = *obj.unnamed_field1;
         let win: Root<window::Window> =
             unwrap_jsmanaged(obj,
                              IDLInterface::get_prototype_id(None::<window::Window>),
                              IDLInterface::get_prototype_depth(None::<window::Window>))
             .unwrap()
             .root();
-        win.deref().browser_context.get_ref().window_proxy()
+        win.deref().browser_context.deref().borrow().get_ref().window_proxy()
     }
 }
 
 /// Returns the global object of the realm that the given JS object was created in.
 pub fn global_object_for_js_object(obj: *mut JSObject) -> JS<window::Window> {
     unsafe {
         let global = GetGlobalForObjectCrossCompartment(obj);
         let clasp = JS_GetClass(global);
--- a/servo/src/components/script/dom/characterdata.rs
+++ b/servo/src/components/script/dom/characterdata.rs
@@ -1,27 +1,30 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! DOM bindings for `CharacterData`.
 
 use dom::bindings::codegen::InheritTypes::{CharacterDataDerived, NodeCast};
+use dom::bindings::error::{Fallible, ErrorResult, IndexSize};
 use dom::bindings::js::JSRef;
-use dom::bindings::error::{Fallible, ErrorResult, IndexSize};
+use dom::bindings::trace::Untraceable;
 use dom::bindings::utils::{Reflectable, Reflector};
 use dom::document::Document;
 use dom::eventtarget::{EventTarget, NodeTargetTypeId};
 use dom::node::{CommentNodeTypeId, Node, NodeTypeId, TextNodeTypeId, ProcessingInstructionNodeTypeId, NodeHelpers};
 use servo_util::str::DOMString;
 
+use std::cell::RefCell;
+
 #[deriving(Encodable)]
 pub struct CharacterData {
     pub node: Node,
-    pub data: DOMString,
+    pub data: Untraceable<RefCell<DOMString>>,
 }
 
 impl CharacterDataDerived for EventTarget {
     fn is_characterdata(&self) -> bool {
         match self.type_id {
             NodeTargetTypeId(TextNodeTypeId) |
             NodeTargetTypeId(CommentNodeTypeId) |
             NodeTargetTypeId(ProcessingInstructionNodeTypeId) => true,
@@ -29,78 +32,78 @@ impl CharacterDataDerived for EventTarge
         }
     }
 }
 
 impl CharacterData {
     pub fn new_inherited(id: NodeTypeId, data: DOMString, document: &JSRef<Document>) -> CharacterData {
         CharacterData {
             node: Node::new_inherited(id, document),
-            data: data
+            data: Untraceable::new(RefCell::new(data)),
         }
     }
 }
 
 pub trait CharacterDataMethods {
     fn Data(&self) -> DOMString;
-    fn SetData(&mut self, arg: DOMString) -> ErrorResult;
+    fn SetData(&self, arg: DOMString) -> ErrorResult;
     fn Length(&self) -> u32;
     fn SubstringData(&self, offset: u32, count: u32) -> Fallible<DOMString>;
-    fn AppendData(&mut self, arg: DOMString) -> ErrorResult;
-    fn InsertData(&mut self, _offset: u32, _arg: DOMString) -> ErrorResult;
-    fn DeleteData(&mut self, _offset: u32, _count: u32) -> ErrorResult;
-    fn ReplaceData(&mut self, _offset: u32, _count: u32, _arg: DOMString) -> ErrorResult;
+    fn AppendData(&self, arg: DOMString) -> ErrorResult;
+    fn InsertData(&self, _offset: u32, _arg: DOMString) -> ErrorResult;
+    fn DeleteData(&self, _offset: u32, _count: u32) -> ErrorResult;
+    fn ReplaceData(&self, _offset: u32, _count: u32, _arg: DOMString) -> ErrorResult;
     fn Remove(&self);
 }
 
 impl<'a> CharacterDataMethods for JSRef<'a, CharacterData> {
     fn Data(&self) -> DOMString {
-        self.data.clone()
+        self.data.deref().borrow().clone()
     }
 
-    fn SetData(&mut self, arg: DOMString) -> ErrorResult {
-        self.data = arg;
+    fn SetData(&self, arg: DOMString) -> ErrorResult {
+        *self.data.deref().borrow_mut() = arg;
         Ok(())
     }
 
     fn Length(&self) -> u32 {
-        self.data.len() as u32
+        self.data.deref().borrow().len() as u32
     }
 
     fn SubstringData(&self, offset: u32, count: u32) -> Fallible<DOMString> {
-        Ok(self.data.as_slice().slice(offset as uint, count as uint).to_str())
+        Ok(self.data.deref().borrow().as_slice().slice(offset as uint, count as uint).to_string())
     }
 
-    fn AppendData(&mut self, arg: DOMString) -> ErrorResult {
-        self.data.push_str(arg.as_slice());
+    fn AppendData(&self, arg: DOMString) -> ErrorResult {
+        self.data.deref().borrow_mut().push_str(arg.as_slice());
         Ok(())
     }
 
-    fn InsertData(&mut self, offset: u32, arg: DOMString) -> ErrorResult {
+    fn InsertData(&self, offset: u32, arg: DOMString) -> ErrorResult {
         self.ReplaceData(offset, 0, arg)
     }
 
-    fn DeleteData(&mut self, offset: u32, count: u32) -> ErrorResult {
+    fn DeleteData(&self, offset: u32, count: u32) -> ErrorResult {
         self.ReplaceData(offset, count, "".to_string())
     }
 
-    fn ReplaceData(&mut self, offset: u32, count: u32, arg: DOMString) -> ErrorResult {
-        let length = self.data.len() as u32;
+    fn ReplaceData(&self, offset: u32, count: u32, arg: DOMString) -> ErrorResult {
+        let length = self.data.deref().borrow().len() as u32;
         if offset > length {
             return Err(IndexSize);
         }
         let count = if offset + count > length {
             length - offset
         } else {
             count
         };
-        let mut data = self.data.as_slice().slice(0, offset as uint).to_string();
+        let mut data = self.data.deref().borrow().as_slice().slice(0, offset as uint).to_string();
         data.push_str(arg.as_slice());
-        data.push_str(self.data.as_slice().slice((offset + count) as uint, length as uint));
-        self.data = data.into_owned();
+        data.push_str(self.data.deref().borrow().as_slice().slice((offset + count) as uint, length as uint));
+        *self.data.deref().borrow_mut() = data.into_owned();
         // FIXME: Once we have `Range`, we should implement step7 to step11
         Ok(())
     }
 
     // http://dom.spec.whatwg.org/#dom-childnode-remove
     fn Remove(&self) {
         let node: &JSRef<Node> = NodeCast::from_ref(self);
         node.remove_self();
--- a/servo/src/components/script/dom/customevent.rs
+++ b/servo/src/components/script/dom/customevent.rs
@@ -9,73 +9,75 @@ use dom::bindings::error::Fallible;
 use dom::bindings::trace::Traceable;
 use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
 use dom::event::{Event, EventMethods, EventTypeId, CustomEventTypeId};
 use dom::window::Window;
 use js::jsapi::JSContext;
 use js::jsval::{JSVal, NullValue};
 use servo_util::str::DOMString;
 
+use std::cell::Cell;
+
 #[deriving(Encodable)]
 pub struct CustomEvent {
     event: Event,
-    detail: Traceable<JSVal>
+    detail: Traceable<Cell<Traceable<JSVal>>>,
 }
 
 impl CustomEventDerived for Event {
     fn is_customevent(&self) -> bool {
         self.type_id == CustomEventTypeId
     }
 }
 
 pub trait CustomEventMethods {
     fn Detail(&self, _cx: *mut JSContext) -> JSVal;
-    fn InitCustomEvent(&mut self, _cx: *mut JSContext,
+    fn InitCustomEvent(&self, _cx: *mut JSContext,
                        type_: DOMString, can_bubble: bool,
                        cancelable: bool, detail: JSVal);
 }
 
 impl CustomEvent {
     pub fn new_inherited(type_id: EventTypeId) -> CustomEvent {
         CustomEvent {
             event: Event::new_inherited(type_id),
-            detail: Traceable::new(NullValue())
+            detail: Traceable::new(Cell::new(Traceable::new(NullValue()))),
         }
     }
 
     pub fn new_uninitialized(window: &JSRef<Window>) -> Temporary<CustomEvent> {
         reflect_dom_object(box CustomEvent::new_inherited(CustomEventTypeId),
                            window,
                            CustomEventBinding::Wrap)
     }
     pub fn new(window: &JSRef<Window>, type_: DOMString, bubbles: bool, cancelable: bool, detail: JSVal) -> Temporary<CustomEvent> {
-        let mut ev = CustomEvent::new_uninitialized(window).root();
-        ev.InitCustomEvent(window.deref().get_cx(), type_, bubbles, cancelable, detail);
+        let ev = CustomEvent::new_uninitialized(window).root();
+        ev.deref().InitCustomEvent(window.deref().get_cx(), type_, bubbles, cancelable, detail);
         Temporary::from_rooted(&*ev)
     }
     pub fn Constructor(owner: &JSRef<Window>,
                        type_: DOMString,
                        init: &CustomEventBinding::CustomEventInit) -> Fallible<Temporary<CustomEvent>>{
         Ok(CustomEvent::new(owner, type_, init.parent.bubbles, init.parent.cancelable, init.detail))
     }
 }
 
 impl<'a> CustomEventMethods for JSRef<'a, CustomEvent> {
     fn Detail(&self, _cx: *mut JSContext) -> JSVal {
-        self.detail.deref().clone()
+        *self.detail.deref().get()
     }
 
-    fn InitCustomEvent(&mut self,
-                        _cx: *mut JSContext,
+    fn InitCustomEvent(&self,
+                       _cx: *mut JSContext,
                        type_: DOMString,
                        can_bubble: bool,
                        cancelable: bool,
                        detail: JSVal) {
-        self.detail = Traceable::new(detail);
-        let event: &mut JSRef<Event> = EventCast::from_mut_ref(self);
+        self.detail.deref().set(Traceable::new(detail));
+        let event: &JSRef<Event> = EventCast::from_ref(self);
         event.InitEvent(type_, can_bubble, cancelable);
     }
 }
 
 impl Reflectable for CustomEvent {
     fn reflector<'a>(&'a self) -> &'a Reflector {
         self.event.reflector()
     }
--- a/servo/src/components/script/dom/document.rs
+++ b/servo/src/components/script/dom/document.rs
@@ -44,73 +44,73 @@ use hubbub::hubbub::{QuirksMode, NoQuirk
 use layout_interface::{DocumentDamageLevel, ContentChangedDocumentDamage};
 use servo_util::namespace;
 use servo_util::namespace::{Namespace, Null};
 use servo_util::str::{DOMString, null_str_as_empty_ref};
 
 use collections::hashmap::HashMap;
 use js::jsapi::JSContext;
 use std::ascii::StrAsciiExt;
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
 use url::{Url, from_str};
 
 #[deriving(Eq,Encodable)]
 pub enum IsHTMLDocument {
     HTMLDocument,
     NonHTMLDocument,
 }
 
 #[deriving(Encodable)]
 pub struct Document {
     pub node: Node,
     pub reflector_: Reflector,
     pub window: JS<Window>,
     pub idmap: HashMap<DOMString, Vec<JS<Element>>>,
     pub implementation: Cell<Option<JS<DOMImplementation>>>,
     pub content_type: DOMString,
-    pub encoding_name: DOMString,
+    pub encoding_name: Untraceable<RefCell<DOMString>>,
     pub is_html_document: bool,
     pub url: Untraceable<Url>,
-    pub quirks_mode: Untraceable<QuirksMode>,
+    pub quirks_mode: Untraceable<Cell<QuirksMode>>,
 }
 
 impl DocumentDerived for EventTarget {
     fn is_document(&self) -> bool {
         self.type_id == NodeTargetTypeId(DocumentNodeTypeId)
     }
 }
 
 pub trait DocumentHelpers {
     fn url<'a>(&'a self) -> &'a Url;
     fn quirks_mode(&self) -> QuirksMode;
-    fn set_quirks_mode(&mut self, mode: QuirksMode);
-    fn set_encoding_name(&mut self, name: DOMString);
+    fn set_quirks_mode(&self, mode: QuirksMode);
+    fn set_encoding_name(&self, name: DOMString);
     fn content_changed(&self);
     fn damage_and_reflow(&self, damage: DocumentDamageLevel);
     fn wait_until_safe_to_modify_dom(&self);
     fn unregister_named_element(&mut self, to_unregister: &JSRef<Element>, id: DOMString);
     fn register_named_element(&mut self, element: &JSRef<Element>, id: DOMString);
     fn load_anchor_href(&self, href: DOMString);
 }
 
 impl<'a> DocumentHelpers for JSRef<'a, Document> {
     fn url<'a>(&'a self) -> &'a Url {
         &*self.url
     }
 
     fn quirks_mode(&self) -> QuirksMode {
-        *self.quirks_mode
+        self.quirks_mode.deref().get()
     }
 
-    fn set_quirks_mode(&mut self, mode: QuirksMode) {
-        *self.quirks_mode = mode;
+    fn set_quirks_mode(&self, mode: QuirksMode) {
+        self.quirks_mode.deref().set(mode);
     }
 
-    fn set_encoding_name(&mut self, name: DOMString) {
-        self.encoding_name = name;
+    fn set_encoding_name(&self, name: DOMString) {
+        *self.encoding_name.deref().borrow_mut() = name;
     }
 
     fn content_changed(&self) {
         self.damage_and_reflow(ContentChangedDocumentDamage);
     }
 
     fn damage_and_reflow(&self, damage: DocumentDamageLevel) {
         self.window.root().damage_and_reflow(damage);
@@ -222,19 +222,19 @@ impl Document {
                     // http://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument
                     HTMLDocument => "text/html".to_string(),
                     // http://dom.spec.whatwg.org/#concept-document-content-type
                     NonHTMLDocument => "application/xml".to_string()
                 }
             },
             url: Untraceable::new(url),
             // http://dom.spec.whatwg.org/#concept-document-quirks
-            quirks_mode: Untraceable::new(NoQuirks),
+            quirks_mode: Untraceable::new(Cell::new(NoQuirks)),
             // http://dom.spec.whatwg.org/#concept-document-encoding
-            encoding_name: "utf-8".to_string(),
+            encoding_name: Untraceable::new(RefCell::new("utf-8".to_string())),
             is_html_document: is_html_document == HTMLDocument,
         }
     }
 
     // http://dom.spec.whatwg.org/#dom-document
     pub fn Constructor(owner: &JSRef<Window>) -> Fallible<Temporary<Document>> {
         Ok(Document::new(owner, None, NonHTMLDocument, None))
     }
@@ -326,19 +326,19 @@ pub trait DocumentMethods {
     fn Forms(&self) -> Temporary<HTMLCollection>;
     fn Scripts(&self) -> Temporary<HTMLCollection>;
     fn Anchors(&self) -> Temporary<HTMLCollection>;
     fn Applets(&self) -> Temporary<HTMLCollection>;
     fn Location(&self) -> Temporary<Location>;
     fn Children(&self) -> Temporary<HTMLCollection>;
     fn QuerySelector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>>;
     fn GetOnclick(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnclick(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnclick(&self, listener: Option<EventHandlerNonNull>);
     fn GetOnload(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnload(&self, listener: Option<EventHandlerNonNull>);
 }
 
 impl<'a> DocumentMethods for JSRef<'a, Document> {
     // http://dom.spec.whatwg.org/#dom-document-implementation
     fn Implementation(&self) -> Temporary<DOMImplementation> {
         if self.implementation.get().is_none() {
             let window = self.window.root();
             self.implementation.assign(Some(DOMImplementation::new(&*window)));
@@ -353,25 +353,25 @@ impl<'a> DocumentMethods for JSRef<'a, D
 
     // http://dom.spec.whatwg.org/#dom-document-documenturi
     fn DocumentURI(&self) -> DOMString {
         self.URL()
     }
 
     // http://dom.spec.whatwg.org/#dom-document-compatmode
     fn CompatMode(&self) -> DOMString {
-        match *self.quirks_mode {
+        match self.quirks_mode.deref().get() {
             NoQuirks => "CSS1Compat".to_string(),
             LimitedQuirks | FullQuirks => "BackCompat".to_string()
         }
     }
 
     // http://dom.spec.whatwg.org/#dom-document-characterset
     fn CharacterSet(&self) -> DOMString {
-        self.encoding_name.as_slice().to_ascii_lower()
+        self.encoding_name.deref().borrow().as_slice().to_ascii_lower()
     }
 
     // http://dom.spec.whatwg.org/#dom-document-content_type
     fn ContentType(&self) -> DOMString {
         self.content_type.clone()
     }
 
     // http://dom.spec.whatwg.org/#dom-document-doctype
@@ -425,17 +425,17 @@ impl<'a> DocumentMethods for JSRef<'a, D
 
     // http://dom.spec.whatwg.org/#dom-document-createelement
     fn CreateElement(&self, local_name: DOMString) -> Fallible<Temporary<Element>> {
         if xml_name_type(local_name.as_slice()) == InvalidXMLName {
             debug!("Not a valid element name");
             return Err(InvalidCharacter);
         }
         let local_name = local_name.as_slice().to_ascii_lower();
-        Ok(build_element_from_tag(local_name, self))
+        Ok(build_element_from_tag(local_name, namespace::HTML, self))
     }
 
     // http://dom.spec.whatwg.org/#dom-document-createelementns
     fn CreateElementNS(&self,
                        namespace: Option<DOMString>,
                        qualified_name: DOMString) -> Fallible<Temporary<Element>> {
         let ns = Namespace::from_str(null_str_as_empty_ref(&namespace));
         match xml_name_type(qualified_name.as_slice()) {
@@ -468,17 +468,17 @@ impl<'a> DocumentMethods for JSRef<'a, D
             (&namespace::XMLNS, _, _) => {
                 debug!("The prefix or the qualified name must be 'xmlns' if namespace is the XMLNS namespace ");
                 return Err(NamespaceError);
             },
             _ => {}
         }
 
         if ns == namespace::HTML {
-            Ok(build_element_from_tag(local_name_from_qname, self))
+            Ok(build_element_from_tag(local_name_from_qname, ns, self))
         } else {
             Ok(Element::new(local_name_from_qname, ns, prefix_from_qname, self))
         }
     }
 
     // http://dom.spec.whatwg.org/#dom-document-createdocumentfragment
     fn CreateDocumentFragment(&self) -> Temporary<DocumentFragment> {
         DocumentFragment::new(self)
@@ -562,17 +562,17 @@ impl<'a> DocumentMethods for JSRef<'a, D
         self.GetDocumentElement().root().map(|root| {
             let root: &JSRef<Node> = NodeCast::from_ref(&*root);
             root.traverse_preorder()
                 .find(|node| node.type_id() == ElementNodeTypeId(HTMLTitleElementTypeId))
                 .map(|title_elem| {
                     for child in title_elem.children() {
                         if child.is_text() {
                             let text: &JSRef<Text> = TextCast::to_ref(&child).unwrap();
-                            title.push_str(text.deref().characterdata.data.as_slice());
+                            title.push_str(text.deref().characterdata.data.deref().borrow().as_slice());
                         }
                     }
                 });
         });
         let v: Vec<&str> = title.as_slice().words().collect();
         let title = v.connect(" ");
         title.as_slice().trim().to_string()
     }
@@ -821,23 +821,23 @@ impl<'a> DocumentMethods for JSRef<'a, D
         root.query_selector(selectors)
     }
 
     fn GetOnclick(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("click")
     }
 
-    fn SetOnclick(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnclick(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("click", listener)
     }
 
     fn GetOnload(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("load")
     }
 
-    fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnload(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("load", listener)
     }
 }
--- a/servo/src/components/script/dom/event.rs
+++ b/servo/src/components/script/dom/event.rs
@@ -1,22 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use dom::bindings::codegen::Bindings::EventBinding;
 use dom::bindings::codegen::Bindings::EventBinding::EventConstants;
+use dom::bindings::error::Fallible;
 use dom::bindings::js::{JS, JSRef, Temporary};
+use dom::bindings::trace::Untraceable;
 use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
-use dom::bindings::error::Fallible;
 use dom::eventtarget::EventTarget;
 use dom::window::Window;
 use servo_util::str::DOMString;
 use servo_util::geometry::PagePx;
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
 
 use geom::point::Point2D;
 use geom::size::TypedSize2D;
 
 use time;
 
 pub enum Event_ {
     ResizeEvent(TypedSize2D<PagePx, f32>),
@@ -46,156 +47,156 @@ pub enum EventTypeId {
 }
 
 #[deriving(Encodable)]
 pub struct Event {
     pub type_id: EventTypeId,
     pub reflector_: Reflector,
     pub current_target: Cell<Option<JS<EventTarget>>>,
     pub target: Cell<Option<JS<EventTarget>>>,
-    pub type_: DOMString,
-    pub phase: EventPhase,
-    pub canceled: bool,
-    pub stop_propagation: bool,
-    pub stop_immediate: bool,
-    pub cancelable: bool,
-    pub bubbles: bool,
-    pub trusted: bool,
-    pub dispatching: bool,
-    pub initialized: bool,
+    type_: Untraceable<RefCell<DOMString>>,
+    pub phase: Untraceable<Cell<EventPhase>>,
+    pub canceled: Untraceable<Cell<bool>>,
+    pub stop_propagation: Untraceable<Cell<bool>>,
+    pub stop_immediate: Untraceable<Cell<bool>>,
+    pub cancelable: Untraceable<Cell<bool>>,
+    pub bubbles: Untraceable<Cell<bool>>,
+    pub trusted: Untraceable<Cell<bool>>,
+    pub dispatching: Untraceable<Cell<bool>>,
+    pub initialized: Untraceable<Cell<bool>>,
     pub timestamp: u64,
 }
 
 impl Event {
     pub fn new_inherited(type_id: EventTypeId) -> Event {
         Event {
             type_id: type_id,
             reflector_: Reflector::new(),
             current_target: Cell::new(None),
             target: Cell::new(None),
-            phase: PhaseNone,
-            type_: "".to_string(),
-            canceled: false,
-            cancelable: true,
-            bubbles: false,
-            trusted: false,
-            dispatching: false,
-            stop_propagation: false,
-            stop_immediate: false,
-            initialized: false,
+            phase: Untraceable::new(Cell::new(PhaseNone)),
+            type_: Untraceable::new(RefCell::new("".to_string())),
+            canceled: Untraceable::new(Cell::new(false)),
+            cancelable: Untraceable::new(Cell::new(true)),
+            bubbles: Untraceable::new(Cell::new(false)),
+            trusted: Untraceable::new(Cell::new(false)),
+            dispatching: Untraceable::new(Cell::new(false)),
+            stop_propagation: Untraceable::new(Cell::new(false)),
+            stop_immediate: Untraceable::new(Cell::new(false)),
+            initialized: Untraceable::new(Cell::new(false)),
             timestamp: time::get_time().sec as u64,
         }
     }
 
     pub fn new_uninitialized(window: &JSRef<Window>) -> Temporary<Event> {
         reflect_dom_object(box Event::new_inherited(HTMLEventTypeId),
                            window,
                            EventBinding::Wrap)
     }
 
     pub fn new(window: &JSRef<Window>,
                type_: DOMString,
                can_bubble: bool,
                cancelable: bool) -> Temporary<Event> {
-        let mut event = Event::new_uninitialized(window).root();
-        event.InitEvent(type_, can_bubble, cancelable);
+        let event = Event::new_uninitialized(window).root();
+        event.deref().InitEvent(type_, can_bubble, cancelable);
         Temporary::from_rooted(&*event)
     }
 
     pub fn Constructor(global: &JSRef<Window>,
                        type_: DOMString,
                        init: &EventBinding::EventInit) -> Fallible<Temporary<Event>> {
         Ok(Event::new(global, type_, init.bubbles, init.cancelable))
     }
 }
 
 pub trait EventMethods {
     fn EventPhase(&self) -> u16;
     fn Type(&self) -> DOMString;
     fn GetTarget(&self) -> Option<Temporary<EventTarget>>;
     fn GetCurrentTarget(&self) -> Option<Temporary<EventTarget>>;
     fn DefaultPrevented(&self) -> bool;
-    fn PreventDefault(&mut self);
-    fn StopPropagation(&mut self);
-    fn StopImmediatePropagation(&mut self);
+    fn PreventDefault(&self);
+    fn StopPropagation(&self);
+    fn StopImmediatePropagation(&self);
     fn Bubbles(&self) -> bool;
     fn Cancelable(&self) -> bool;
     fn TimeStamp(&self) -> u64;
-    fn InitEvent(&mut self, type_: DOMString, bubbles: bool, cancelable: bool);
+    fn InitEvent(&self, type_: DOMString, bubbles: bool, cancelable: bool);
     fn IsTrusted(&self) -> bool;
 }
 
 impl<'a> EventMethods for JSRef<'a, Event> {
     fn EventPhase(&self) -> u16 {
-        self.phase as u16
+        self.phase.deref().get() as u16
     }
 
     fn Type(&self) -> DOMString {
-        self.type_.clone()
+        self.type_.deref().borrow().clone()
     }
 
     fn GetTarget(&self) -> Option<Temporary<EventTarget>> {
         self.target.get().as_ref().map(|target| Temporary::new(target.clone()))
     }
 
     fn GetCurrentTarget(&self) -> Option<Temporary<EventTarget>> {
         self.current_target.get().as_ref().map(|target| Temporary::new(target.clone()))
     }
 
     fn DefaultPrevented(&self) -> bool {
-        self.canceled
+        self.canceled.deref().get()
     }
 
-    fn PreventDefault(&mut self) {
-        if self.cancelable {
-            self.canceled = true
+    fn PreventDefault(&self) {
+        if self.cancelable.deref().get() {
+            self.canceled.deref().set(true)
         }
     }
 
-    fn StopPropagation(&mut self) {
-        self.stop_propagation = true;
+    fn StopPropagation(&self) {
+        self.stop_propagation.deref().set(true);
     }
 
-    fn StopImmediatePropagation(&mut self) {
-        self.stop_immediate = true;
-        self.stop_propagation = true;
+    fn StopImmediatePropagation(&self) {
+        self.stop_immediate.deref().set(true);
+        self.stop_propagation.deref().set(true);
     }
 
     fn Bubbles(&self) -> bool {
-        self.bubbles
+        self.bubbles.deref().get()
     }
 
     fn Cancelable(&self) -> bool {
-        self.cancelable
+        self.cancelable.deref().get()
     }
 
     fn TimeStamp(&self) -> u64 {
         self.timestamp
     }
 
-    fn InitEvent(&mut self,
+    fn InitEvent(&self,
                  type_: DOMString,
                  bubbles: bool,
                  cancelable: bool) {
-        self.initialized = true;
-        if self.dispatching {
+        self.initialized.deref().set(true);
+        if self.dispatching.deref().get() {
             return;
         }
-        self.stop_propagation = false;
-        self.stop_immediate = false;
-        self.canceled = false;
-        self.trusted = false;
+        self.stop_propagation.deref().set(false);
+        self.stop_immediate.deref().set(false);
+        self.canceled.deref().set(false);
+        self.trusted.deref().set(false);
         self.target.set(None);
-        self.type_ = type_;
-        self.bubbles = bubbles;
-        self.cancelable = cancelable;
+        *self.type_.deref().borrow_mut() = type_;
+        self.bubbles.deref().set(bubbles);
+        self.cancelable.deref().set(cancelable);
     }
 
     fn IsTrusted(&self) -> bool {
-        self.trusted
+        self.trusted.deref().get()
     }
 }
 
 impl Reflectable for Event {
     fn reflector<'a>(&'a self) -> &'a Reflector {
         &self.reflector_
     }
 
--- a/servo/src/components/script/dom/eventdispatcher.rs
+++ b/servo/src/components/script/dom/eventdispatcher.rs
@@ -8,108 +8,102 @@ use dom::bindings::js::{JSRef, OptionalS
 use dom::eventtarget::{Capturing, Bubbling, EventTarget};
 use dom::event::{Event, PhaseAtTarget, PhaseNone, PhaseBubbling, PhaseCapturing, EventMethods};
 use dom::node::{Node, NodeHelpers};
 use dom::virtualmethods::vtable_for;
 
 // See http://dom.spec.whatwg.org/#concept-event-dispatch for the full dispatch algorithm
 pub fn dispatch_event<'a, 'b>(target: &JSRef<'a, EventTarget>,
                               pseudo_target: Option<JSRef<'b, EventTarget>>,
-                              event: &mut JSRef<Event>) -> bool {
-    assert!(!event.deref().dispatching);
+                              event: &JSRef<Event>) -> bool {
+    assert!(!event.deref().dispatching.deref().get());
 
-    {
-        let event = event.deref_mut();
-        event.target.assign(Some(match pseudo_target {
-            Some(pseudo_target) => pseudo_target,
-            None => target.clone(),
-        }));
-        event.dispatching = true;
-    }
+    event.target.assign(Some(match pseudo_target {
+        Some(pseudo_target) => pseudo_target,
+        None => target.clone(),
+    }));
+    event.dispatching.deref().set(true);
 
-    let type_ = event.deref().type_.clone();
+    let type_ = event.Type();
 
     //TODO: no chain if not participating in a tree
     let mut chain: Vec<Root<EventTarget>> = if target.deref().is_node() {
         let target_node: &JSRef<Node> = NodeCast::to_ref(target).unwrap();
         target_node.ancestors().map(|ancestor| {
             let ancestor_target: &JSRef<EventTarget> = EventTargetCast::from_ref(&ancestor);
             ancestor_target.unrooted().root()
         }).collect()
     } else {
         vec!()
     };
 
-    event.deref_mut().phase = PhaseCapturing;
+    event.deref().phase.deref().set(PhaseCapturing);
 
     //FIXME: The "callback this value" should be currentTarget
 
     /* capturing */
     for cur_target in chain.as_slice().iter().rev() {
         let stopped = match cur_target.get_listeners_for(type_.as_slice(), Capturing) {
             Some(listeners) => {
                 event.current_target.assign(Some(cur_target.deref().clone()));
                 for listener in listeners.iter() {
                     // Explicitly drop any exception on the floor.
                     let _ = listener.HandleEvent_(&**cur_target, event, ReportExceptions);
 
-                    if event.deref().stop_immediate {
+                    if event.deref().stop_immediate.deref().get() {
                         break;
                     }
                 }
 
-                event.deref().stop_propagation
+                event.deref().stop_propagation.deref().get()
             }
             None => false
         };
 
         if stopped {
             break;
         }
     }
 
     /* at target */
-    if !event.deref().stop_propagation {
-        {
-            let event = event.deref_mut();
-            event.phase = PhaseAtTarget;
-            event.current_target.assign(Some(target.clone()));
-        }
+    if !event.deref().stop_propagation.deref().get() {
+        event.phase.deref().set(PhaseAtTarget);
+        event.current_target.assign(Some(target.clone()));
 
         let opt_listeners = target.deref().get_listeners(type_.as_slice());
         for listeners in opt_listeners.iter() {
             for listener in listeners.iter() {
                 // Explicitly drop any exception on the floor.
                 let _ = listener.HandleEvent_(target, event, ReportExceptions);
 
-                if event.deref().stop_immediate {
+                if event.deref().stop_immediate.deref().get() {
                     break;
                 }
             }
         }
     }
 
     /* bubbling */
-    if event.deref().bubbles && !event.deref().stop_propagation {
-        event.deref_mut().phase = PhaseBubbling;
+    if event.deref().bubbles.deref().get() && !event.deref().stop_propagation.deref().get() {
+        event.deref().phase.deref().set(PhaseBubbling);
 
         for cur_target in chain.iter() {
             let stopped = match cur_target.deref().get_listeners_for(type_.as_slice(), Bubbling) {
                 Some(listeners) => {
-                    event.deref_mut().current_target.assign(Some(cur_target.deref().clone()));
+                    event.deref().current_target.assign(Some(cur_target.deref().clone()));
                     for listener in listeners.iter() {
                         // Explicitly drop any exception on the floor.
                         let _ = listener.HandleEvent_(&**cur_target, event, ReportExceptions);
 
-                        if event.deref().stop_immediate {
+                        if event.deref().stop_immediate.deref().get() {
                             break;
                         }
                     }
 
-                    event.deref().stop_propagation
+                    event.deref().stop_propagation.deref().get()
                 }
                 None => false
             };
             if stopped {
                 break;
             }
         }
     }
@@ -131,14 +125,14 @@ pub fn dispatch_event<'a, 'b>(target: &J
     }
 
     // Root ordering restrictions mean we need to unroot the chain entries
     // in the same order they were rooted.
     while chain.len() > 0 {
         let _ = chain.pop();
     }
 
-    event.dispatching = false;
-    event.phase = PhaseNone;
+    event.dispatching.deref().set(false);
+    event.phase.deref().set(PhaseNone);
     event.current_target.set(None);
 
     !event.DefaultPrevented()
 }
--- a/servo/src/components/script/dom/eventtarget.rs
+++ b/servo/src/components/script/dom/eventtarget.rs
@@ -2,26 +2,28 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use dom::bindings::callback::CallbackContainer;
 use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
 use dom::bindings::codegen::Bindings::EventListenerBinding::EventListener;
 use dom::bindings::error::{Fallible, InvalidState};
 use dom::bindings::js::JSRef;
+use dom::bindings::trace::Traceable;
 use dom::bindings::utils::{Reflectable, Reflector};
 use dom::event::Event;
 use dom::eventdispatcher::dispatch_event;
 use dom::node::NodeTypeId;
 use dom::xmlhttprequest::XMLHttpRequestId;
 use dom::virtualmethods::VirtualMethods;
 use js::jsapi::{JS_CompileUCFunction, JS_GetFunctionObject, JS_CloneFunctionObject};
 use js::jsapi::{JSContext, JSObject};
 use servo_util::str::DOMString;
 use libc::{c_char, size_t};
+use std::cell::RefCell;
 use std::ptr;
 use url::Url;
 
 use collections::hashmap::HashMap;
 
 #[deriving(Eq,Encodable)]
 pub enum ListenerPhase {
     Capturing,
@@ -54,76 +56,79 @@ pub struct EventListenerEntry {
     pub phase: ListenerPhase,
     pub listener: EventListenerType
 }
 
 #[deriving(Encodable)]
 pub struct EventTarget {
     pub type_id: EventTargetTypeId,
     pub reflector_: Reflector,
-    pub handlers: HashMap<DOMString, Vec<EventListenerEntry>>,
+    handlers: Traceable<RefCell<HashMap<DOMString, Vec<EventListenerEntry>>>>,
 }
 
 impl EventTarget {
     pub fn new_inherited(type_id: EventTargetTypeId) -> EventTarget {
         EventTarget {
             type_id: type_id,
             reflector_: Reflector::new(),
-            handlers: HashMap::new(),
+            handlers: Traceable::new(RefCell::new(HashMap::new())),
         }
     }
 
     pub fn get_listeners(&self, type_: &str) -> Option<Vec<EventListener>> {
-        self.handlers.find_equiv(&type_).map(|listeners| {
+        self.handlers.deref().borrow().find_equiv(&type_).map(|listeners| {
             listeners.iter().map(|entry| entry.listener.get_listener()).collect()
         })
     }
 
     pub fn get_listeners_for(&self, type_: &str, desired_phase: ListenerPhase)
         -> Option<Vec<EventListener>> {
-        self.handlers.find_equiv(&type_).map(|listeners| {
+        self.handlers.deref().borrow().find_equiv(&type_).map(|listeners| {
             let filtered = listeners.iter().filter(|entry| entry.phase == desired_phase);
             filtered.map(|entry| entry.listener.get_listener()).collect()
         })
     }
 }
 
 pub trait EventTargetHelpers {
     fn dispatch_event_with_target<'a>(&self,
                                       target: Option<JSRef<'a, EventTarget>>,
-                                      event: &mut JSRef<Event>) -> Fallible<bool>;
-    fn set_inline_event_listener(&mut self,
+                                      event: &JSRef<Event>) -> Fallible<bool>;
+    fn set_inline_event_listener(&self,
                                  ty: DOMString,
                                  listener: Option<EventListener>);
     fn get_inline_event_listener(&self, ty: DOMString) -> Option<EventListener>;
-    fn set_event_handler_uncompiled(&mut self,
+    fn set_event_handler_uncompiled(&self,
                                     cx: *mut JSContext,
                                     url: Url,
                                     scope: *mut JSObject,
                                     ty: &str,
                                     source: DOMString);
-    fn set_event_handler_common<T: CallbackContainer>(&mut self, ty: &str,
+    fn set_event_handler_common<T: CallbackContainer>(&self, ty: &str,
                                                       listener: Option<T>);
     fn get_event_handler_common<T: CallbackContainer>(&self, ty: &str) -> Option<T>;
+
+    fn has_handlers(&self) -> bool;
 }
 
 impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> {
     fn dispatch_event_with_target<'b>(&self,
                                       target: Option<JSRef<'b, EventTarget>>,
-                                      event: &mut JSRef<Event>) -> Fallible<bool> {
-        if event.deref().dispatching || !event.deref().initialized {
+                                      event: &JSRef<Event>) -> Fallible<bool> {
+        if event.deref().dispatching.deref().get() || !event.deref().initialized.deref().get() {
             return Err(InvalidState);
         }
         Ok(dispatch_event(self, target, event))
     }
 
-    fn set_inline_event_listener(&mut self,
+    fn set_inline_event_listener(&self,
                                  ty: DOMString,
                                  listener: Option<EventListener>) {
-        let entries = self.handlers.find_or_insert_with(ty, |_| vec!());
+        let mut handlers = self.handlers.deref().borrow_mut();
+        let entries = handlers.find_or_insert_with(ty, |_| vec!());
         let idx = entries.iter().position(|&entry| {
             match entry.listener {
                 Inline(_) => true,
                 _ => false,
             }
         });
 
         match idx {
@@ -142,26 +147,27 @@ impl<'a> EventTargetHelpers for JSRef<'a
                         listener: Inline(listener.unwrap()),
                     });
                 }
             }
         }
     }
 
     fn get_inline_event_listener(&self, ty: DOMString) -> Option<EventListener> {
-        let entries = self.handlers.find(&ty);
+        let handlers = self.handlers.deref().borrow();
+        let entries = handlers.find(&ty);
         entries.and_then(|entries| entries.iter().find(|entry| {
             match entry.listener {
                 Inline(_) => true,
                 _ => false,
             }
         }).map(|entry| entry.listener.get_listener()))
     }
 
-    fn set_event_handler_uncompiled(&mut self,
+    fn set_event_handler_uncompiled(&self,
                                     cx: *mut JSContext,
                                     url: Url,
                                     scope: *mut JSObject,
                                     ty: &str,
                                     source: DOMString) {
         let url = url.to_str().to_c_str();
         let name = ty.to_c_str();
         let lineno = 0; //XXXjdm need to get a real number here
@@ -183,80 +189,92 @@ impl<'a> EventTargetHelpers for JSRef<'a
                 JS_GetFunctionObject(fun)
             }})});
         let funobj = unsafe { JS_CloneFunctionObject(cx, handler, scope) };
         assert!(funobj.is_not_null());
         self.set_event_handler_common(ty, Some(EventHandlerNonNull::new(funobj)))
     }
 
     fn set_event_handler_common<T: CallbackContainer>(
-        &mut self, ty: &str, listener: Option<T>)
+        &self, ty: &str, listener: Option<T>)
     {
         let event_listener = listener.map(|listener|
                                           EventListener::new(listener.callback()));
         self.set_inline_event_listener(ty.to_string(), event_listener);
     }
 
     fn get_event_handler_common<T: CallbackContainer>(&self, ty: &str) -> Option<T> {
         let listener = self.get_inline_event_listener(ty.to_string());
         listener.map(|listener| CallbackContainer::new(listener.parent.callback()))
     }
+
+    fn has_handlers(&self) -> bool {
+        !self.handlers.deref().borrow().is_empty()
+    }
 }
 
 pub trait EventTargetMethods {
-    fn AddEventListener(&mut self,
+    fn AddEventListener(&self,
                         ty: DOMString,
                         listener: Option<EventListener>,
                         capture: bool);
-    fn RemoveEventListener(&mut self,
+    fn RemoveEventListener(&self,
                            ty: DOMString,
                            listener: Option<EventListener>,
                            capture: bool);
-    fn DispatchEvent(&self, event: &mut JSRef<Event>) -> Fallible<bool>;
+    fn DispatchEvent(&self, event: &JSRef<Event>) -> Fallible<bool>;
 }
 
 impl<'a> EventTargetMethods for JSRef<'a, EventTarget> {
-    fn AddEventListener(&mut self,
+    fn AddEventListener(&self,
                         ty: DOMString,
                         listener: Option<EventListener>,
                         capture: bool) {
-        for &listener in listener.iter() {
-            let entry = self.handlers.find_or_insert_with(ty.clone(), |_| vec!());
-            let phase = if capture { Capturing } else { Bubbling };
-            let new_entry = EventListenerEntry {
-                phase: phase,
-                listener: Additive(listener)
-            };
-            if entry.as_slice().position_elem(&new_entry).is_none() {
-                entry.push(new_entry);
-            }
+        match listener {
+            Some(listener) => {
+                let mut handlers = self.handlers.deref().borrow_mut();
+                let entry = handlers.find_or_insert_with(ty, |_| vec!());
+                let phase = if capture { Capturing } else { Bubbling };
+                let new_entry = EventListenerEntry {
+                    phase: phase,
+                    listener: Additive(listener)
+                };
+                if entry.as_slice().position_elem(&new_entry).is_none() {
+                    entry.push(new_entry);
+                }
+            },
+            _ => (),
         }
     }
 
-    fn RemoveEventListener(&mut self,
+    fn RemoveEventListener(&self,
                            ty: DOMString,
                            listener: Option<EventListener>,
                            capture: bool) {
-        for &listener in listener.iter() {
-            let mut entry = self.handlers.find_mut(&ty);
-            for entry in entry.mut_iter() {
-                let phase = if capture { Capturing } else { Bubbling };
-                let old_entry = EventListenerEntry {
-                    phase: phase,
-                    listener: Additive(listener)
-                };
-                let position = entry.as_slice().position_elem(&old_entry);
-                for &position in position.iter() {
-                    entry.remove(position);
+        match listener {
+            Some(listener) => {
+                let mut handlers = self.handlers.deref().borrow_mut();
+                let mut entry = handlers.find_mut(&ty);
+                for entry in entry.mut_iter() {
+                    let phase = if capture { Capturing } else { Bubbling };
+                    let old_entry = EventListenerEntry {
+                        phase: phase,
+                        listener: Additive(listener)
+                    };
+                    let position = entry.as_slice().position_elem(&old_entry);
+                    for &position in position.iter() {
+                        entry.remove(position);
+                    }
                 }
-            }
+            },
+            _ => (),
         }
     }
 
-    fn DispatchEvent(&self, event: &mut JSRef<Event>) -> Fallible<bool> {
+    fn DispatchEvent(&self, event: &JSRef<Event>) -> Fallible<bool> {
         self.dispatch_event_with_target(None, event)
     }
 }
 
 impl Reflectable for EventTarget {
     fn reflector<'a>(&'a self) -> &'a Reflector {
         &self.reflector_
     }
--- a/servo/src/components/script/dom/formdata.rs
+++ b/servo/src/components/script/dom/formdata.rs
@@ -1,71 +1,73 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
+use dom::bindings::codegen::Bindings::FormDataBinding;
 use dom::bindings::error::{Fallible};
-use dom::bindings::codegen::Bindings::FormDataBinding;
 use dom::bindings::js::{JS, JSRef, Temporary, OptionalUnrootable};
+use dom::bindings::trace::Traceable;
+use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
 use dom::blob::Blob;
 use dom::htmlformelement::HTMLFormElement;
 use dom::window::Window;
 use servo_util::str::DOMString;
 use collections::hashmap::HashMap;
+use std::cell::RefCell;
 
 #[deriving(Encodable)]
 pub enum FormDatum {
     StringData(DOMString),
     BlobData { blob: JS<Blob>, name: DOMString }
 }
 
 #[deriving(Encodable)]
 pub struct FormData {
-    pub data: HashMap<DOMString, FormDatum>,
+    pub data: Traceable<RefCell<HashMap<DOMString, FormDatum>>>,
     pub reflector_: Reflector,
     pub window: JS<Window>,
     pub form: Option<JS<HTMLFormElement>>
 }
 
 impl FormData {
     pub fn new_inherited(form: Option<JSRef<HTMLFormElement>>, window: &JSRef<Window>) -> FormData {
         FormData {
-            data: HashMap::new(),
+            data: Traceable::new(RefCell::new(HashMap::new())),
             reflector_: Reflector::new(),
             window: window.unrooted(),
             form: form.unrooted(),
         }
     }
 
     pub fn new(form: Option<JSRef<HTMLFormElement>>, window: &JSRef<Window>) -> Temporary<FormData> {
         reflect_dom_object(box FormData::new_inherited(form, window), window, FormDataBinding::Wrap)
     }
 
     pub fn Constructor(window: &JSRef<Window>, form: Option<JSRef<HTMLFormElement>>) -> Fallible<Temporary<FormData>> {
         Ok(FormData::new(form, window))
     }
 }
 
 pub trait FormDataMethods {
-    fn Append(&mut self, name: DOMString, value: &JSRef<Blob>, filename: Option<DOMString>);
-    fn Append_(&mut self, name: DOMString, value: DOMString);
+    fn Append(&self, name: DOMString, value: &JSRef<Blob>, filename: Option<DOMString>);
+    fn Append_(&self, name: DOMString, value: DOMString);
 }
 
 impl<'a> FormDataMethods for JSRef<'a, FormData> {
-    fn Append(&mut self, name: DOMString, value: &JSRef<Blob>, filename: Option<DOMString>) {
+    fn Append(&self, name: DOMString, value: &JSRef<Blob>, filename: Option<DOMString>) {
         let blob = BlobData {
             blob: value.unrooted(),
             name: filename.unwrap_or("default".to_string())
         };
-        self.data.insert(name.clone(), blob);
+        self.data.deref().borrow_mut().insert(name.clone(), blob);
     }
 
-    fn Append_(&mut self, name: DOMString, value: DOMString) {
-        self.data.insert(name, StringData(value));
+    fn Append_(&self, name: DOMString, value: DOMString) {
+        self.data.deref().borrow_mut().insert(name, StringData(value));
     }
 }
 
 impl Reflectable for FormData {
     fn reflector<'a>(&'a self) -> &'a Reflector {
         &self.reflector_
     }
 
--- a/servo/src/components/script/dom/htmlbodyelement.rs
+++ b/servo/src/components/script/dom/htmlbodyelement.rs
@@ -75,21 +75,20 @@ impl<'a> VirtualMethods for JSRef<'a, HT
                 &["onfocus", "onload", "onscroll", "onafterprint", "onbeforeprint",
                   "onbeforeunload", "onhashchange", "onlanguagechange", "onmessage",
                   "onoffline", "ononline", "onpagehide", "onpageshow", "onpopstate",
                   "onstorage", "onresize", "onunload", "onerror"];
             let mut window = window_from_node(self).root();
             let (cx, url, reflector) = (window.get_cx(),
                                         window.get_url(),
                                         window.reflector().get_jsobject());
-            let mut self_alias = self.clone();
-            let evtarget: &mut JSRef<EventTarget> =
+            let evtarget: &JSRef<EventTarget> =
                 if forwarded_events.iter().any(|&event| name.as_slice() == event) {
-                    EventTargetCast::from_mut_ref(&mut *window)
+                    EventTargetCast::from_ref(&*window)
                 } else {
-                    EventTargetCast::from_mut_ref(&mut self_alias)
+                    EventTargetCast::from_ref(self)
                 };
             evtarget.set_event_handler_uncompiled(cx, url, reflector,
                                                   name.as_slice().slice_from(2),
                                                   value);
         }
     }
 }
--- a/servo/src/components/script/dom/htmlelement.rs
+++ b/servo/src/components/script/dom/htmlelement.rs
@@ -54,45 +54,45 @@ impl<'a> PrivateHTMLElementHelpers for J
     fn is_body_or_frameset(&self) -> bool {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.is_htmlbodyelement() || eventtarget.is_htmlframesetelement()
     }
 }
 
 pub trait HTMLElementMethods {
     fn GetOnclick(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnclick(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnclick(&self, listener: Option<EventHandlerNonNull>);
     fn GetOnload(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnload(&self, listener: Option<EventHandlerNonNull>);
 }
 
 impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> {
     fn GetOnclick(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("click")
     }
 
-    fn SetOnclick(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnclick(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("click", listener)
     }
 
     fn GetOnload(&self) -> Option<EventHandlerNonNull> {
         if self.is_body_or_frameset() {
             let win = window_from_node(self).root();
             win.deref().GetOnload()
         } else {
             None
         }
     }
 
-    fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>) {
+    fn SetOnload(&self, listener: Option<EventHandlerNonNull>) {
         if self.is_body_or_frameset() {
-            let mut win = window_from_node(self).root();
-            win.SetOnload(listener)
+            let win = window_from_node(self).root();
+            win.deref().SetOnload(listener)
         }
     }
 }
 
 impl<'a> VirtualMethods for JSRef<'a, HTMLElement> {
     fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods:> {
         let element: &JSRef<Element> = ElementCast::from_ref(self);
         Some(element as &VirtualMethods:)
@@ -104,17 +104,15 @@ impl<'a> VirtualMethods for JSRef<'a, HT
             _ => (),
         }
 
         if name.as_slice().starts_with("on") {
             let mut window = window_from_node(self).root();
             let (cx, url, reflector) = (window.get_cx(),
                                         window.get_url(),
                                         window.reflector().get_jsobject());
-            let mut self_alias = self.clone();
-            let evtarget: &mut JSRef<EventTarget> =
-                EventTargetCast::from_mut_ref(&mut self_alias);
+            let evtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
             evtarget.set_event_handler_uncompiled(cx, url, reflector,
                                                   name.as_slice().slice_from(2),
                                                   value);
         }
     }
 }
--- a/servo/src/components/script/dom/htmliframeelement.rs
+++ b/servo/src/components/script/dom/htmliframeelement.rs
@@ -34,17 +34,17 @@ enum SandboxAllowance {
     AllowScripts = 0x08,
     AllowPointerLock = 0x10,
     AllowPopups = 0x20
 }
 
 #[deriving(Encodable)]
 pub struct HTMLIFrameElement {
     pub htmlelement: HTMLElement,
-    pub size: Option<IFrameSize>,
+    pub size: Traceable<Cell<Option<IFrameSize>>>,
     pub sandbox: Traceable<Cell<Option<u8>>>,
 }
 
 impl HTMLIFrameElementDerived for EventTarget {
     fn is_htmliframeelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLIFrameElementTypeId))
     }
 }
@@ -74,17 +74,17 @@ impl<'a> HTMLIFrameElementHelpers for JS
         })
     }
 }
 
 impl HTMLIFrameElement {
     pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLIFrameElement {
         HTMLIFrameElement {
             htmlelement: HTMLElement::new_inherited(HTMLIFrameElementTypeId, localName, document),
-            size: None,
+            size: Traceable::new(Cell::new(None)),
             sandbox: Traceable::new(Cell::new(None)),
         }
     }
 
     pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLIFrameElement> {
         let element = HTMLIFrameElement::new_inherited(localName, document);
         Node::reflect_node(box element, document, HTMLIFrameElementBinding::Wrap)
     }
@@ -115,17 +115,17 @@ impl<'a> HTMLIFrameElementMethods for JS
     }
 
     fn SetSandbox(&self, sandbox: DOMString) {
         let element: &JSRef<Element> = ElementCast::from_ref(self);
         element.set_string_attribute("sandbox", sandbox);
     }
 
     fn GetContentWindow(&self) -> Option<Temporary<Window>> {
-        self.size.and_then(|size| {
+        self.size.deref().get().and_then(|size| {
             let window = window_from_node(self).root();
             let children = &*window.deref().page.children.deref().borrow();
             let child = children.iter().find(|child| {
                 child.subpage_id.unwrap() == size.subpage_id
             });
             child.and_then(|page| {
                 page.frame.deref().borrow().as_ref().map(|frame| {
                     Temporary::new(frame.window.clone())
@@ -189,21 +189,20 @@ impl<'a> VirtualMethods for JSRef<'a, HT
                     IFrameUnsandboxed
                 };
 
                 // Subpage Id
                 let window = window_from_node(self).root();
                 let page = window.deref().page();
                 let subpage_id = page.get_next_subpage_id();
 
-                let mut self_alias = self.clone();
-                self_alias.deref_mut().size = Some(IFrameSize {
+                self.deref().size.deref().set(Some(IFrameSize {
                     pipeline_id: page.id,
                     subpage_id: subpage_id,
-                });
+                }));
 
                 let ConstellationChan(ref chan) = *page.constellation_chan.deref();
                 chan.send(LoadIframeUrlMsg(url, page.id, subpage_id, sandboxed));
             }
             _ => ()
         }
     }
 }
--- a/servo/src/components/script/dom/htmlimageelement.rs
+++ b/servo/src/components/script/dom/htmlimageelement.rs
@@ -12,83 +12,83 @@ use dom::element::AttributeHandlers;
 use dom::eventtarget::{EventTarget, NodeTargetTypeId};
 use dom::htmlelement::HTMLElement;
 use dom::node::{Node, ElementNodeTypeId, NodeHelpers, window_from_node};
 use dom::virtualmethods::VirtualMethods;
 use servo_util::geometry::to_px;
 use servo_net::image_cache_task;
 use servo_util::url::parse_url;
 use servo_util::str::DOMString;
+use std::cell::RefCell;
 use url::Url;
 
 #[deriving(Encodable)]
 pub struct HTMLImageElement {
     pub htmlelement: HTMLElement,
-    image: Untraceable<Option<Url>>,
+    image: Untraceable<RefCell<Option<Url>>>,
 }
 
 impl HTMLImageElementDerived for EventTarget {
     fn is_htmlimageelement(&self) -> bool {
         self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLImageElementTypeId))
     }
 }
 
 trait PrivateHTMLImageElementHelpers {
-    fn update_image(&mut self, value: Option<DOMString>, url: Option<Url>);
+    fn update_image(&self, value: Option<DOMString>, url: Option<Url>);
 }
 
 impl<'a> PrivateHTMLImageElementHelpers for JSRef<'a, HTMLImageElement> {
     /// Makes the local `image` member match the status of the `src` attribute and starts
     /// prefetching the image. This method must be called after `src` is changed.
-    fn update_image(&mut self, value: Option<DOMString>, url: Option<Url>) {
-        let self_alias = self.clone();
-        let node_alias: &JSRef<Node> = NodeCast::from_ref(&self_alias);
-        let document = node_alias.owner_doc().root();
+    fn update_image(&self, value: Option<DOMString>, url: Option<Url>) {
+        let node: &JSRef<Node> = NodeCast::from_ref(self);
+        let document = node.owner_doc().root();
         let window = document.deref().window.root();
         let image_cache = &window.image_cache_task;
         match value {
             None => {
-                *self.image = None;
+                *self.image.deref().borrow_mut() = None;
             }
             Some(src) => {
                 let img_url = parse_url(src.as_slice(), url);
-                *self.image = Some(img_url.clone());
+                *self.image.deref().borrow_mut() = Some(img_url.clone());
 
                 // inform the image cache to load this, but don't store a
                 // handle.
                 //
                 // TODO (Issue #84): don't prefetch if we are within a
                 // <noscript> tag.
                 image_cache.send(image_cache_task::Prefetch(img_url));
             }
         }
     }
 }
 
 impl HTMLImageElement {
     pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLImageElement {
         HTMLImageElement {
             htmlelement: HTMLElement::new_inherited(HTMLImageElementTypeId, localName, document),
-            image: Untraceable::new(None),
+            image: Untraceable::new(RefCell::new(None)),
         }
     }
 
     pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLImageElement> {
         let element = HTMLImageElement::new_inherited(localName, document);
         Node::reflect_node(box element, document, HTMLImageElementBinding::Wrap)
     }
 }
 
 pub trait LayoutHTMLImageElementHelpers {
-    unsafe fn image<'a>(&'a self) -> &'a Option<Url>;
+    unsafe fn image(&self) -> Option<Url>;
 }
 
 impl LayoutHTMLImageElementHelpers for JS<HTMLImageElement> {
-    unsafe fn image<'a>(&'a self) -> &'a Option<Url> {
-        &*(*self.unsafe_get()).image
+    unsafe fn image(&self) -> Option<Url> {
+        (*self.unsafe_get()).image.borrow().clone()
     }
 }
 
 pub trait HTMLImageElementMethods {
     fn Alt(&self) -> DOMString;
     fn SetAlt(&self, alt: DOMString);
     fn Src(&self) -> DOMString;
     fn SetSrc(&self, src: DOMString);
@@ -248,25 +248,23 @@ impl<'a> VirtualMethods for JSRef<'a, HT
         match self.super_type() {
             Some(ref s) => s.after_set_attr(name.clone(), value.clone()),
             _ => (),
         }
 
         if "src" == name.as_slice() {
             let window = window_from_node(self).root();
             let url = Some(window.deref().get_url());
-            let mut self_alias = self.clone();
-            self_alias.update_image(Some(value), url);
+            self.update_image(Some(value), url);
         }
     }
 
     fn before_remove_attr(&self, name: DOMString, value: DOMString) {
         match self.super_type() {
             Some(ref s) => s.before_remove_attr(name.clone(), value.clone()),
             _ => (),
         }
 
         if "src" == name.as_slice() {
-            let mut self_alias = self.clone();
-            self_alias.update_image(None, None);
+            self.update_image(None, None);
         }
     }
 }
--- a/servo/src/components/script/dom/htmlserializer.rs
+++ b/servo/src/components/script/dom/htmlserializer.rs
@@ -62,43 +62,43 @@ pub fn serialize(iterator: &mut NodeIter
         html.push_str(open_elements.pop().unwrap().as_slice());
         html.push_str(">");
     }
     html.into_owned()
 }
 
 fn serialize_comment(comment: &JSRef<Comment>, html: &mut String) {
     html.push_str("<!--");
-    html.push_str(comment.deref().characterdata.data.as_slice());
+    html.push_str(comment.deref().characterdata.data.deref().borrow().as_slice());
     html.push_str("-->");
 }
 
 fn serialize_text(text: &JSRef<Text>, html: &mut String) {
     let text_node: &JSRef<Node> = NodeCast::from_ref(text);
     match text_node.parent_node().map(|node| node.root()) {
         Some(ref parent) if parent.is_element() => {
             let elem: &JSRef<Element> = ElementCast::to_ref(&**parent).unwrap();
             match elem.deref().local_name.as_slice() {
                 "style" | "script" | "xmp" | "iframe" |
                 "noembed" | "noframes" | "plaintext" |
                 "noscript" if elem.deref().namespace == namespace::HTML
-                => html.push_str(text.deref().characterdata.data.as_slice()),
-                _ => escape(text.deref().characterdata.data.as_slice(), false, html)
+                => html.push_str(text.deref().characterdata.data.deref().borrow().as_slice()),
+                _ => escape(text.deref().characterdata.data.deref().borrow().as_slice(), false, html)
             }
         }
-        _ => escape(text.deref().characterdata.data.as_slice(), false, html)
+        _ => escape(text.deref().characterdata.data.deref().borrow().as_slice(), false, html)
     }
 }
 
 fn serialize_processing_instruction(processing_instruction: &JSRef<ProcessingInstruction>,
                                     html: &mut String) {
     html.push_str("<?");
     html.push_str(processing_instruction.deref().target.as_slice());
     html.push_char(' ');
-    html.push_str(processing_instruction.deref().characterdata.data.as_slice());
+    html.push_str(processing_instruction.deref().characterdata.data.deref().borrow().as_slice());
     html.push_str("?>");
 }
 
 fn serialize_doctype(doctype: &JSRef<DocumentType>, html: &mut String) {
     html.push_str("<!DOCTYPE");
     html.push_str(doctype.deref().name.as_slice());
     html.push_char('>');
 }
@@ -113,17 +113,17 @@ fn serialize_elem(elem: &JSRef<Element>,
     html.push_char('>');
 
     match elem.deref().local_name.as_slice() {
         "pre" | "listing" | "textarea" if elem.deref().namespace == namespace::HTML => {
             let node: &JSRef<Node> = NodeCast::from_ref(elem);
             match node.first_child().map(|child| child.root()) {
                 Some(ref child) if child.is_text() => {
                     let text: &JSRef<CharacterData> = CharacterDataCast::to_ref(&**child).unwrap();
-                    if text.deref().data.len() > 0 && text.deref().data.as_slice().char_at(0) == '\n' {
+                    if text.deref().data.deref().borrow().len() > 0 && text.deref().data.deref().borrow().as_slice().char_at(0) == '\n' {
                         html.push_char('\x0A');
                     }
                 },
                 _ => {}
             }
         },
         _ => {}
     }
--- a/servo/src/components/script/dom/node.rs
+++ b/servo/src/components/script/dom/node.rs
@@ -6,22 +6,23 @@
 
 use cssparser::tokenize;
 use dom::attr::{Attr, AttrMethods};
 use dom::bindings::codegen::InheritTypes::{CommentCast, DocumentCast, DocumentTypeCast};
 use dom::bindings::codegen::InheritTypes::{ElementCast, TextCast, NodeCast, ElementDerived};
 use dom::bindings::codegen::InheritTypes::{CharacterDataCast, NodeBase, NodeDerived};
 use dom::bindings::codegen::InheritTypes::{ProcessingInstructionCast, EventTargetCast};
 use dom::bindings::codegen::Bindings::NodeBinding::NodeConstants;
+use dom::bindings::error::{ErrorResult, Fallible, NotFound, HierarchyRequest, Syntax};
 use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, Root, OptionalUnrootable};
 use dom::bindings::js::{OptionalSettable, TemporaryPushable, OptionalRootedRootable};
 use dom::bindings::js::{ResultRootable, OptionalRootable};
+use dom::bindings::trace::Untraceable;
+use dom::bindings::utils;
 use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
-use dom::bindings::error::{ErrorResult, Fallible, NotFound, HierarchyRequest, Syntax};
-use dom::bindings::utils;
 use dom::characterdata::{CharacterData, CharacterDataMethods};
 use dom::comment::Comment;
 use dom::document::{Document, DocumentMethods, DocumentHelpers, HTMLDocument, NonHTMLDocument};
 use dom::documentfragment::DocumentFragment;
 use dom::documenttype::DocumentType;
 use dom::element::{AttributeHandlers, Element, ElementMethods, ElementTypeId};
 use dom::element::{HTMLAnchorElementTypeId, ElementHelpers};
 use dom::eventtarget::{EventTarget, NodeTargetTypeId};
@@ -81,17 +82,17 @@ pub struct Node {
 
     /// The document that this node belongs to.
     owner_doc: Cell<Option<JS<Document>>>,
 
     /// The live list of children return by .childNodes.
     pub child_list: Cell<Option<JS<NodeList>>>,
 
     /// A bitfield of flags for node items.
-    flags: NodeFlags,
+    flags: Untraceable<RefCell<NodeFlags>>,
 
     /// Layout information. Only the layout task may touch this data.
     ///
     /// FIXME(pcwalton): We need to send these back to the layout task to be destroyed when this
     /// node is finalized.
     pub layout_data: LayoutDataRef,
 }
 
@@ -377,17 +378,17 @@ pub trait NodeHelpers {
 
     fn is_element(&self) -> bool;
     fn is_document(&self) -> bool;
     fn is_doctype(&self) -> bool;
     fn is_text(&self) -> bool;
     fn is_anchor_element(&self) -> bool;
 
     fn get_hover_state(&self) -> bool;
-    fn set_hover_state(&mut self, state: bool);
+    fn set_hover_state(&self, state: bool);
 
     fn dump(&self);
     fn dump_indent(&self, indent: uint);
     fn debug_str(&self) -> String;
 
     fn traverse_preorder<'a>(&'a self) -> TreeIterator<'a>;
     fn sequential_traverse_postorder<'a>(&'a self) -> TreeIterator<'a>;
     fn inclusively_following_siblings<'a>(&'a self) -> AbstractNodeChildrenIterator<'a>;
@@ -425,17 +426,17 @@ impl<'a> NodeHelpers for JSRef<'a, Node>
     }
 
     /// Returns a string that describes this node.
     fn debug_str(&self) -> String {
         format!("{:?}", self.type_id())
     }
 
     fn is_in_doc(&self) -> bool {
-        self.deref().flags.contains(IsInDoc)
+        self.deref().flags.deref().borrow().contains(IsInDoc)
     }
 
     /// Returns the type ID of this node. Fails if this node is borrowed mutably.
     fn type_id(&self) -> NodeTypeId {
         self.deref().type_id
     }
 
     fn parent_node(&self) -> Option<Temporary<Node>> {
@@ -484,24 +485,24 @@ impl<'a> NodeHelpers for JSRef<'a, Node>
     }
 
     #[inline]
     fn is_text(&self) -> bool {
         self.type_id() == TextNodeTypeId
     }
 
     fn get_hover_state(&self) -> bool {
-        self.flags.contains(InHoverState)
+        self.flags.deref().borrow().contains(InHoverState)
     }
 
-    fn set_hover_state(&mut self, state: bool) {
+    fn set_hover_state(&self, state: bool) {
         if state {
-            self.flags.insert(InHoverState);
+            self.flags.deref().borrow_mut().insert(InHoverState);
         } else {
-            self.flags.remove(InHoverState);
+            self.flags.deref().borrow_mut().remove(InHoverState);
         }
     }
 
     /// Iterates over this node and all its descendants, in preorder.
     fn traverse_preorder<'a>(&'a self) -> TreeIterator<'a> {
         let mut nodes = vec!();
         gather_abstract_nodes(self, &mut nodes, false);
         TreeIterator::new(nodes)
@@ -701,17 +702,17 @@ impl LayoutNodeHelpers for JS<Node> {
 }
 
 pub trait RawLayoutNodeHelpers {
     unsafe fn get_hover_state_for_layout(&self) -> bool;
 }
 
 impl RawLayoutNodeHelpers for Node {
     unsafe fn get_hover_state_for_layout(&self) -> bool {
-        self.flags.contains(InHoverState)
+        self.flags.deref().borrow().contains(InHoverState)
     }
 }
 
 
 //
 // Iteration and traversal
 //
 
@@ -911,17 +912,17 @@ impl Node {
             first_child: Cell::new(None),
             last_child: Cell::new(None),
             next_sibling: Cell::new(None),
             prev_sibling: Cell::new(None),
 
             owner_doc: Cell::new(doc.unrooted()),
             child_list: Cell::new(None),
 
-            flags: NodeFlags::new(type_id),
+            flags: Untraceable::new(RefCell::new(NodeFlags::new(type_id))),
 
             layout_data: LayoutDataRef::new(),
         }
     }
 
     // http://dom.spec.whatwg.org/#concept-node-adopt
     pub fn adopt(node: &JSRef<Node>, document: &JSRef<Document>) {
         // Step 1.
@@ -1105,19 +1106,19 @@ impl Node {
             _ => (),
         }
 
         // Step 7: mutation records.
         // Step 8.
         for node in nodes.mut_iter() {
             parent.add_child(node, child);
             if parent.is_in_doc() {
-                node.flags.insert(IsInDoc);
+                node.flags.deref().borrow_mut().insert(IsInDoc);
             } else {
-                node.flags.remove(IsInDoc);
+                node.flags.deref().borrow_mut().remove(IsInDoc);
             }
         }
 
         // Step 9.
         match suppress_observers {
             Unsuppressed => {
                 for node in nodes.iter() {
                     node.node_inserted();
@@ -1192,19 +1193,17 @@ impl Node {
     fn remove(node: &JSRef<Node>, parent: &JSRef<Node>, suppress_observers: SuppressObserver) {
         assert!(node.parent_node().map_or(false, |node_parent| node_parent == Temporary::from_rooted(parent)));
 
         // Step 1-5: ranges.
         // Step 6-7: mutation observers.
         // Step 8.
         parent.remove_child(node);
 
-        // FIXME(2513): remove this `node_alias` when in fix mozilla#2513
-        let mut node_alias = node.clone();
-        node_alias.deref_mut().flags.remove(IsInDoc);
+        node.deref().flags.deref().borrow_mut().remove(IsInDoc);
 
         // Step 9.
         match suppress_observers {
             Suppressed => (),
             Unsuppressed => node.node_removed(),
         }
     }
 
@@ -1231,47 +1230,48 @@ impl Node {
             },
             DocumentFragmentNodeTypeId => {
                 let doc_fragment = DocumentFragment::new(&*document);
                 NodeCast::from_temporary(doc_fragment)
             },
             CommentNodeTypeId => {
                 let comment: &JSRef<Comment> = CommentCast::to_ref(node).unwrap();
                 let comment = comment.deref();
-                let comment = Comment::new(comment.characterdata.data.clone(), &*document);
+                let comment = Comment::new(comment.characterdata.data.deref().borrow().clone(), &*document);
                 NodeCast::from_temporary(comment)
             },
             DocumentNodeTypeId => {
                 let document: &JSRef<Document> = DocumentCast::to_ref(node).unwrap();
                 let is_html_doc = match document.is_html_document {
                     true => HTMLDocument,
                     false => NonHTMLDocument
                 };
                 let window = document.window.root();
                 let document = Document::new(&*window, Some(document.url().clone()),
                                              is_html_doc, None);
                 NodeCast::from_temporary(document)
             },
             ElementNodeTypeId(..) => {
                 let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap();
                 let element = element.deref();
-                let element = build_element_from_tag(element.local_name.clone(), &*document);
+                let element = build_element_from_tag(element.local_name.clone(),
+                    element.namespace.clone(), &*document);
                 NodeCast::from_temporary(element)
             },
             TextNodeTypeId => {
                 let text: &JSRef<Text> = TextCast::to_ref(node).unwrap();
                 let text = text.deref();
-                let text = Text::new(text.characterdata.data.clone(), &*document);
+                let text = Text::new(text.characterdata.data.deref().borrow().clone(), &*document);
                 NodeCast::from_temporary(text)
             },
             ProcessingInstructionNodeTypeId => {
                 let pi: &JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(node).unwrap();
                 let pi = pi.deref();
                 let pi = ProcessingInstruction::new(pi.target.clone(),
-                                                    pi.characterdata.data.clone(), &*document);
+                                                    pi.characterdata.data.deref().borrow().clone(), &*document);
                 NodeCast::from_temporary(pi)
             },
         }.root();
 
         // Step 3.
         let document = if copy.is_document() {
             let doc: &JSRef<Document> = DocumentCast::to_ref(&*copy).unwrap();
             doc.unrooted().root()
@@ -1279,38 +1279,32 @@ impl Node {
             document.unrooted().root()
         };
         assert!(&*copy.owner_doc().root() == &*document);
 
         // Step 4 (some data already copied in step 2).
         match node.type_id() {
             DocumentNodeTypeId => {
                 let node_doc: &JSRef<Document> = DocumentCast::to_ref(node).unwrap();
-                let copy_doc: &mut JSRef<Document> = DocumentCast::to_mut_ref(&mut *copy).unwrap();
-                copy_doc.set_encoding_name(node_doc.encoding_name.clone());
+                let copy_doc: &JSRef<Document> = DocumentCast::to_ref(&*copy).unwrap();
+                copy_doc.set_encoding_name(node_doc.encoding_name.deref().borrow().clone());
                 copy_doc.set_quirks_mode(node_doc.quirks_mode());
             },
             ElementNodeTypeId(..) => {
                 let node_elem: &JSRef<Element> = ElementCast::to_ref(node).unwrap();
-                let node_elem = node_elem.deref();
-                let copy_elem: &mut JSRef<Element> = ElementCast::to_mut_ref(&mut *copy).unwrap();
-
-                // XXX: to avoid double borrowing compile error. we might be able to fix this after #1854
-                let copy_elem_alias = copy_elem.clone();
+                let copy_elem: &JSRef<Element> = ElementCast::to_ref(&*copy).unwrap();
 
-                let copy_elem = copy_elem.deref_mut();
                 // FIXME: https://github.com/mozilla/servo/issues/1737
-                copy_elem.namespace = node_elem.namespace.clone();
                 let window = document.deref().window.root();
-                for attr in node_elem.attrs.borrow().iter().map(|attr| attr.root()) {
-                    copy_elem.attrs.borrow_mut().push_unrooted(
+                for attr in node_elem.deref().attrs.borrow().iter().map(|attr| attr.root()) {
+                    copy_elem.deref().attrs.borrow_mut().push_unrooted(
                         &Attr::new(&*window,
                                    attr.deref().local_name.clone(), attr.deref().value.clone(),
                                    attr.deref().name.clone(), attr.deref().namespace.clone(),
-                                   attr.deref().prefix.clone(), &copy_elem_alias));
+                                   attr.deref().prefix.clone(), copy_elem));
                 }
             },
             _ => ()
         }
 
         // Step 5: cloning steps.
 
         // Step 6.
@@ -1515,17 +1509,17 @@ impl<'a> NodeMethods for JSRef<'a, Node>
     fn GetTextContent(&self) -> Option<DOMString> {
         match self.type_id {
             DocumentFragmentNodeTypeId |
             ElementNodeTypeId(..) => {
                 let mut content = String::new();
                 for node in self.traverse_preorder() {
                     if node.is_text() {
                         let text: &JSRef<Text> = TextCast::to_ref(&node).unwrap();
-                        content.push_str(text.deref().characterdata.data.as_slice());
+                        content.push_str(text.deref().characterdata.data.deref().borrow().as_slice());
                     }
                 }
                 Some(content.into_owned())
             }
             CommentNodeTypeId |
             TextNodeTypeId |
             ProcessingInstructionNodeTypeId => {
                 let characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(self).unwrap();
@@ -1556,20 +1550,18 @@ impl<'a> NodeMethods for JSRef<'a, Node>
                 // Step 3.
                 Node::replace_all(node.root_ref(), self);
             }
             CommentNodeTypeId |
             TextNodeTypeId |
             ProcessingInstructionNodeTypeId => {
                 self.wait_until_safe_to_modify_dom();
 
-                {
-                    let characterdata: &mut JSRef<CharacterData> = CharacterDataCast::to_mut_ref(self).unwrap();
-                    characterdata.deref_mut().data = value;
-                }
+                let characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(self).unwrap();
+                *characterdata.data.deref().borrow_mut() = value;
 
                 // Notify the document that the content of this node is different
                 let document = self.owner_doc().root();
                 document.deref().content_changed();
             }
             DoctypeNodeTypeId |
             DocumentNodeTypeId => {}
         }
@@ -1773,22 +1765,22 @@ impl<'a> NodeMethods for JSRef<'a, Node>
             (element.namespace == other_element.namespace) &&
             (element.local_name == other_element.local_name) &&
             (element.attrs.borrow().len() == other_element.attrs.borrow().len())
         }
         fn is_equal_processinginstruction(node: &JSRef<Node>, other: &JSRef<Node>) -> bool {
             let pi: &JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(node).unwrap();
             let other_pi: &JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(other).unwrap();
             (pi.deref().target == other_pi.deref().target) &&
-            (pi.deref().characterdata.data == other_pi.deref().characterdata.data)
+            (*pi.deref().characterdata.data.deref().borrow() == *other_pi.deref().characterdata.data.deref().borrow())
         }
         fn is_equal_characterdata(node: &JSRef<Node>, other: &JSRef<Node>) -> bool {
             let characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(node).unwrap();
             let other_characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(other).unwrap();
-            characterdata.deref().data == other_characterdata.deref().data
+            *characterdata.deref().data.deref().borrow() == *other_characterdata.deref().data.deref().borrow()
         }
         fn is_equal_element_attrs(node: &JSRef<Node>, other: &JSRef<Node>) -> bool {
             let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap();
             let other_element: &JSRef<Element> = ElementCast::to_ref(other).unwrap();
             let element = element.deref();
             let other_element = other_element.deref();
             assert!(element.attrs.borrow().len() == other_element.attrs.borrow().len());
             element.attrs.borrow().iter().map(|attr| attr.root()).all(|attr| {
--- a/servo/src/components/script/dom/progressevent.rs
+++ b/servo/src/components/script/dom/progressevent.rs
@@ -32,23 +32,21 @@ impl ProgressEvent {
             length_computable: length_computable,
             loaded: loaded,
             total: total
         }
     }
     pub fn new(window: &JSRef<Window>, type_: DOMString,
                can_bubble: bool, cancelable: bool,
                length_computable: bool, loaded: u64, total: u64) -> Temporary<ProgressEvent> {
-        let mut ev = reflect_dom_object(box ProgressEvent::new_inherited(length_computable, loaded, total),
-                                        window,
-                                        ProgressEventBinding::Wrap).root();
-        {
-            let event: &mut JSRef<Event> = EventCast::from_mut_ref(&mut *ev);
-            event.InitEvent(type_, can_bubble, cancelable);
-        }
+        let ev = reflect_dom_object(box ProgressEvent::new_inherited(length_computable, loaded, total),
+                                    window,
+                                    ProgressEventBinding::Wrap).root();
+        let event: &JSRef<Event> = EventCast::from_ref(&*ev);
+        event.InitEvent(type_, can_bubble, cancelable);
         Temporary::from_rooted(&*ev)
     }
     pub fn Constructor(owner: &JSRef<Window>,
                        type_: DOMString,
                        init: &ProgressEventBinding::ProgressEventInit)
                        -> Fallible<Temporary<ProgressEvent>> {
         let ev = ProgressEvent::new(owner, type_, init.parent.bubbles, init.parent.cancelable,
                                     init.lengthComputable, init.loaded, init.total);
--- a/servo/src/components/script/dom/uievent.rs
+++ b/servo/src/components/script/dom/uievent.rs
@@ -1,105 +1,104 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use dom::bindings::codegen::Bindings::UIEventBinding;
 use dom::bindings::codegen::InheritTypes::{EventCast, UIEventDerived};
+use dom::bindings::error::Fallible;
 use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, OptionalSettable};
-use dom::bindings::error::Fallible;
+use dom::bindings::trace::Untraceable;
 use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
 use dom::event::{Event, EventMethods, EventTypeId, UIEventTypeId};
 use dom::window::Window;
 use servo_util::str::DOMString;
 
 use serialize::{Encoder, Encodable};
 use std::cell::Cell;
 
 #[deriving(Encodable)]
 pub struct UIEvent {
     pub event: Event,
     pub view: Cell<Option<JS<Window>>>,
-    pub detail: i32
+    pub detail: Untraceable<Cell<i32>>
 }
 
 impl UIEventDerived for Event {
     fn is_uievent(&self) -> bool {
         self.type_id == UIEventTypeId
     }
 }
 
 impl UIEvent {
     pub fn new_inherited(type_id: EventTypeId) -> UIEvent {
         UIEvent {
             event: Event::new_inherited(type_id),
             view: Cell::new(None),
-            detail: 0
+            detail: Untraceable::new(Cell::new(0)),
         }
     }
 
     pub fn new_uninitialized(window: &JSRef<Window>) -> Temporary<UIEvent> {
         reflect_dom_object(box UIEvent::new_inherited(UIEventTypeId),
                            window,
                            UIEventBinding::Wrap)
     }
 
     pub fn new(window: &JSRef<Window>,
                type_: DOMString,
                can_bubble: bool,
                cancelable: bool,
                view: Option<JSRef<Window>>,
                detail: i32) -> Temporary<UIEvent> {
-        let mut ev = UIEvent::new_uninitialized(window).root();
-        ev.InitUIEvent(type_, can_bubble, cancelable, view, detail);
+        let ev = UIEvent::new_uninitialized(window).root();
+        ev.deref().InitUIEvent(type_, can_bubble, cancelable, view, detail);
         Temporary::from_rooted(&*ev)
     }
 
     pub fn Constructor(owner: &JSRef<Window>,
                        type_: DOMString,
                        init: &UIEventBinding::UIEventInit) -> Fallible<Temporary<UIEvent>> {
         let event = UIEvent::new(owner, type_,
                                  init.parent.bubbles, init.parent.cancelable,
                                  init.view.root_ref(), init.detail);
         Ok(event)
     }
 }
 
 pub trait UIEventMethods {
     fn GetView(&self) -> Option<Temporary<Window>>;
     fn Detail(&self) -> i32;
-    fn InitUIEvent(&mut self,
+    fn InitUIEvent(&self,
                    type_: DOMString,
                    can_bubble: bool,
                    cancelable: bool,
                    view: Option<JSRef<Window>>,
                    detail: i32);
 }
 
 impl<'a> UIEventMethods for JSRef<'a, UIEvent> {
     fn GetView(&self) -> Option<Temporary<Window>> {
         self.view.get().map(|view| Temporary::new(view))
     }
 
     fn Detail(&self) -> i32 {
-        self.detail
+        self.detail.deref().get()
     }
 
-    fn InitUIEvent(&mut self,
+    fn InitUIEvent(&self,
                    type_: DOMString,
                    can_bubble: bool,
                    cancelable: bool,
                    view: Option<JSRef<Window>>,
                    detail: i32) {
-        {
-            let event: &mut JSRef<Event> = EventCast::from_mut_ref(self);
-            event.InitEvent(type_, can_bubble, cancelable);
-        }
+        let event: &JSRef<Event> = EventCast::from_ref(self);
+        event.InitEvent(type_, can_bubble, cancelable);
         self.view.assign(view);
-        self.detail = detail;
+        self.detail.deref().set(detail);
     }
 }
 
 impl Reflectable for UIEvent {
     fn reflector<'a>(&'a self) -> &'a Reflector {
         self.event.reflector()
     }
 
--- a/servo/src/components/script/dom/window.rs
+++ b/servo/src/components/script/dom/window.rs
@@ -24,17 +24,17 @@ use servo_util::str::DOMString;
 use servo_util::task::{spawn_named};
 use servo_util::url::parse_url;
 
 use js::jsapi::JSContext;
 use js::jsapi::{JS_GC, JS_GetRuntime};
 use js::jsval::JSVal;
 
 use collections::hashmap::HashMap;
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
 use std::cmp;
 use std::comm::{channel, Sender};
 use std::comm::Select;
 use std::hash::{Hash, sip};
 use std::io::timer::Timer;
 use std::rc::Rc;
 
 use time;
@@ -68,20 +68,20 @@ impl TimerHandle {
 #[deriving(Encodable)]
 pub struct Window {
     pub eventtarget: EventTarget,
     pub script_chan: ScriptChan,
     pub console: Cell<Option<JS<Console>>>,
     pub location: Cell<Option<JS<Location>>>,
     pub navigator: Cell<Option<JS<Navigator>>>,
     pub image_cache_task: ImageCacheTask,
-    pub active_timers: Box<HashMap<TimerId, TimerHandle>>,
-    pub next_timer_handle: i32,
+    pub active_timers: Traceable<RefCell<HashMap<TimerId, TimerHandle>>>,
+    pub next_timer_handle: Untraceable<Cell<i32>>,
     pub compositor: Untraceable<Box<ScriptListener>>,
-    pub browser_context: Option<BrowserContext>,
+    pub browser_context: Traceable<RefCell<Option<BrowserContext>>>,
     pub page: Rc<Page>,
     pub performance: Cell<Option<JS<Performance>>>,
     pub navigationStart: u64,
     pub navigationStartPrecise: f64,
 }
 
 impl Window {
     pub fn get_cx(&self) -> *mut JSContext {
@@ -95,17 +95,17 @@ impl Window {
     pub fn get_url(&self) -> Url {
         self.page().get_url()
     }
 }
 
 #[unsafe_destructor]
 impl Drop for Window {
     fn drop(&mut self) {
-        for (_, timer_handle) in self.active_timers.mut_iter() {
+        for (_, timer_handle) in self.active_timers.borrow_mut().mut_iter() {
             timer_handle.cancel();
         }
     }
 }
 
 // Holder for the various JS values associated with setTimeout
 // (ie. function value to invoke and all arguments to pass
 //      to the function when calling it)
@@ -117,31 +117,31 @@ pub struct TimerData {
 
 pub trait WindowMethods {
     fn Alert(&self, s: DOMString);
     fn Close(&self);
     fn Document(&self) -> Temporary<Document>;
     fn Location(&self) -> Temporary<Location>;
     fn Console(&self) -> Temporary<Console>;
     fn Navigator(&self) -> Temporary<Navigator>;
-    fn SetTimeout(&mut self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32;
-    fn ClearTimeout(&mut self, handle: i32);
-    fn SetInterval(&mut self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32;
-    fn ClearInterval(&mut self, handle: i32);
+    fn SetTimeout(&self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32;
+    fn ClearTimeout(&self, handle: i32);
+    fn SetInterval(&self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32;
+    fn ClearInterval(&self, handle: i32);
     fn Window(&self) -> Temporary<Window>;
     fn Self(&self) -> Temporary<Window>;
     fn Performance(&self) -> Temporary<Performance>;
     fn GetOnclick(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnclick(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnclick(&self, listener: Option<EventHandlerNonNull>);
     fn GetOnload(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnload(&self, listener: Option<EventHandlerNonNull>);
     fn GetOnunload(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnunload(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnunload(&self, listener: Option<EventHandlerNonNull>);
     fn GetOnerror(&self) -> Option<OnErrorEventHandlerNonNull>;
-    fn SetOnerror(&mut self, listener: Option<OnErrorEventHandlerNonNull>);
+    fn SetOnerror(&self, listener: Option<OnErrorEventHandlerNonNull>);
     fn Debug(&self, message: DOMString);
     fn Gc(&self);
 }
 
 impl<'a> WindowMethods for JSRef<'a, Window> {
     fn Alert(&self, s: DOMString) {
         // Right now, just print to the console
         println!("ALERT: {:s}", s);
@@ -177,34 +177,35 @@ impl<'a> WindowMethods for JSRef<'a, Win
     fn Navigator(&self) -> Temporary<Navigator> {
         if self.navigator.get().is_none() {
             let navigator = Navigator::new(self);
             self.navigator.assign(Some(navigator));
         }
         Temporary::new(self.navigator.get().get_ref().clone())
     }
 
-    fn SetTimeout(&mut self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32 {
+    fn SetTimeout(&self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32 {
         self.set_timeout_or_interval(callback, timeout, false)
     }
 
-    fn ClearTimeout(&mut self, handle: i32) {
-        let mut timer_handle = self.active_timers.pop(&TimerId(handle));
+    fn ClearTimeout(&self, handle: i32) {
+        let mut timers = self.active_timers.deref().borrow_mut();
+        let mut timer_handle = timers.pop(&TimerId(handle));
         match timer_handle {
             Some(ref mut handle) => handle.cancel(),
             None => { }
         }
-        self.active_timers.remove(&TimerId(handle));
+        timers.remove(&TimerId(handle));
     }
 
-    fn SetInterval(&mut self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32 {
+    fn SetInterval(&self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32 {
         self.set_timeout_or_interval(callback, timeout, true)
     }
 
-    fn ClearInterval(&mut self, handle: i32) {
+    fn ClearInterval(&self, handle: i32) {
         self.ClearTimeout(handle);
     }
 
     fn Window(&self) -> Temporary<Window> {
         Temporary::from_rooted(self)
     }
 
     fn Self(&self) -> Temporary<Window> {
@@ -219,48 +220,48 @@ impl<'a> WindowMethods for JSRef<'a, Win
         Temporary::new(self.performance.get().get_ref().clone())
     }
 
     fn GetOnclick(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("click")
     }
 
-    fn SetOnclick(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnclick(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("click", listener)
     }
 
     fn GetOnload(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("load")
     }
 
-    fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnload(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("load", listener)
     }
 
     fn GetOnunload(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("unload")
     }
 
-    fn SetOnunload(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnunload(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("unload", listener)
     }
 
     fn GetOnerror(&self) -> Option<OnErrorEventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("error")
     }
 
-    fn SetOnerror(&mut self, listener: Option<OnErrorEventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnerror(&self, listener: Option<OnErrorEventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("error", listener)
     }
 
     fn Debug(&self, message: DOMString) {
         debug!("{:s}", message);
     }
 
     fn Gc(&self) {
@@ -278,22 +279,22 @@ impl Reflectable for Window {
     fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
         self.eventtarget.mut_reflector()
     }
 }
 
 pub trait WindowHelpers {
     fn damage_and_reflow(&self, damage: DocumentDamageLevel);
     fn wait_until_safe_to_modify_dom(&self);
-    fn init_browser_context(&mut self, doc: &JSRef<Document>);
+    fn init_browser_context(&self, doc: &JSRef<Document>);
     fn load_url(&self, href: DOMString);
 }
 
 trait PrivateWindowHelpers {
-    fn set_timeout_or_interval(&mut self, callback: JSVal, timeout: i32, is_interval: bool) -> i32;
+    fn set_timeout_or_interval(&self, callback: JSVal, timeout: i32, is_interval: bool) -> i32;
 }
 
 impl<'a> WindowHelpers for JSRef<'a, Window> {
     fn damage_and_reflow(&self, damage: DocumentDamageLevel) {
         // FIXME This should probably be ReflowForQuery, not Display. All queries currently
         // currently rely on the display list, which means we can't destroy it by
         // doing a query reflow.
         self.page().damage(damage);
@@ -301,18 +302,18 @@ impl<'a> WindowHelpers for JSRef<'a, Win
     }
 
     fn wait_until_safe_to_modify_dom(&self) {
         // FIXME: This disables concurrent layout while we are modifying the DOM, since
         //        our current architecture is entirely unsafe in the presence of races.
         self.page().join_layout();
     }
 
-    fn init_browser_context(&mut self, doc: &JSRef<Document>) {
-        self.browser_context = Some(BrowserContext::new(doc));
+    fn init_browser_context(&self, doc: &JSRef<Document>) {
+        *self.browser_context.deref().borrow_mut() = Some(BrowserContext::new(doc));
     }
 
     /// Commence a new URL load which will either replace this window or scroll to a fragment.
     fn load_url(&self, href: DOMString) {
         let base_url = Some(self.page().get_url());
         debug!("current page url is {:?}", base_url);
         let url = parse_url(href.as_slice(), base_url);
         let ScriptChan(ref script_chan) = self.script_chan;
@@ -320,20 +321,20 @@ impl<'a> WindowHelpers for JSRef<'a, Win
             script_chan.send(TriggerFragmentMsg(self.page.id, url));
         } else {
             script_chan.send(TriggerLoadMsg(self.page.id, url));
         }
     }
 }
 
 impl<'a> PrivateWindowHelpers for JSRef<'a, Window> {
-    fn set_timeout_or_interval(&mut self, callback: JSVal, timeout: i32, is_interval: bool) -> i32 {
+    fn set_timeout_or_interval(&self, callback: JSVal, timeout: i32, is_interval: bool) -> i32 {
         let timeout = cmp::max(0, timeout) as u64;
-        let handle = self.next_timer_handle;
-        self.next_timer_handle += 1;
+        let handle = self.next_timer_handle.deref().get();
+        self.next_timer_handle.deref().set(handle + 1);
 
         // Post a delayed message to the per-window timer task; it will dispatch it
         // to the relevant script handler that will deal with it.
         let tm = Timer::new().unwrap();
         let (cancel_chan, cancel_port) = channel();
         let chan = self.script_chan.clone();
         let page_id = self.page.id.clone();
         let spawn_name = if is_interval {
@@ -374,17 +375,17 @@ impl<'a> PrivateWindowHelpers for JSRef<
         let timer = TimerHandle {
             handle: timer_id,
             cancel_chan: Untraceable::new(Some(cancel_chan)),
             data: TimerData {
                 is_interval: is_interval,
                 funval: Traceable::new(callback),
             }
         };
-        self.active_timers.insert(timer_id, timer);
+        self.active_timers.deref().borrow_mut().insert(timer_id, timer);
         handle
     }
 }
 
 impl Window {
     pub fn new(cx: *mut JSContext,
                page: Rc<Page>,
                script_chan: ScriptChan,
@@ -395,19 +396,19 @@ impl Window {
             eventtarget: EventTarget::new_inherited(WindowTypeId),
             script_chan: script_chan,
             console: Cell::new(None),
             compositor: Untraceable::new(compositor),
             page: page,
             location: Cell::new(None),
             navigator: Cell::new(None),
             image_cache_task: image_cache_task,
-            active_timers: box HashMap::new(),
-            next_timer_handle: 0,
-            browser_context: None,
+            active_timers: Traceable::new(RefCell::new(HashMap::new())),
+            next_timer_handle: Untraceable::new(Cell::new(0)),
+            browser_context: Traceable::new(RefCell::new(None)),
             performance: Cell::new(None),
             navigationStart: time::get_time().sec as u64,
             navigationStartPrecise: time::precise_time_s(),
         };
 
         WindowBinding::Wrap(cx, win)
     }
 }
--- a/servo/src/components/script/dom/xmlhttprequest.rs
+++ b/servo/src/components/script/dom/xmlhttprequest.rs
@@ -220,17 +220,17 @@ impl XMLHttpRequest {
                 }
             }
         }
     }
 }
 
 pub trait XMLHttpRequestMethods<'a> {
     fn GetOnreadystatechange(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnreadystatechange(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnreadystatechange(&self, listener: Option<EventHandlerNonNull>);
     fn ReadyState(&self) -> u16;
     fn Open(&mut self, _method: ByteString, _url: DOMString) -> ErrorResult;
     fn Open_(&mut self, _method: ByteString, _url: DOMString, _async: bool,
              _username: Option<DOMString>, _password: Option<DOMString>) -> ErrorResult;
     fn SetRequestHeader(&mut self, name: ByteString, mut value: ByteString) -> ErrorResult;
     fn Timeout(&self) -> u32;
     fn SetTimeout(&mut self, timeout: u32);
     fn WithCredentials(&self) -> bool;
@@ -252,18 +252,18 @@ pub trait XMLHttpRequestMethods<'a> {
 }
 
 impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> {
     fn GetOnreadystatechange(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("readystatechange")
     }
 
-    fn SetOnreadystatechange(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnreadystatechange(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("readystatechange", listener)
     }
 
     fn ReadyState(&self) -> u16 {
         self.ready_state as u16
     }
 
     fn Open(&mut self, method: ByteString, url: DOMString) -> ErrorResult {
@@ -426,17 +426,17 @@ impl<'a> XMLHttpRequestMethods<'a> for J
             None => true,
             Some (ref s) if s.len() == 0 => true,
             _ => false
         };
         if !self.sync {
             // Step 8
             let upload_target = &*self.upload.get().root().unwrap();
             let event_target: &JSRef<EventTarget> = EventTargetCast::from_ref(upload_target);
-            if  event_target.handlers.iter().len() > 0 {
+            if event_target.has_handlers() {
                 self.upload_events = true;
             }
 
             // Step 9
             self.send_flag = true;
             self.dispatch_response_progress_event("loadstart".to_string());
             if !self.upload_complete {
                 self.dispatch_upload_progress_event("loadstart".to_string(), Some(0));
@@ -633,20 +633,20 @@ impl<'a> PrivateXMLHttpRequestHelpers fo
         }
         self.pinned = false;
     }
 
     fn change_ready_state(&mut self, rs: XMLHttpRequestState) {
         assert!(self.ready_state != rs)
         self.ready_state = rs;
         let win = &*self.global.root();
-        let mut event =
+        let event =
             Event::new(win, "readystatechange".to_string(), false, true).root();
         let target: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
-        target.dispatch_event_with_target(None, &mut *event).ok();
+        target.dispatch_event_with_target(None, &*event).ok();
     }
 
     fn process_partial_response(&mut self, progress: XHRProgress) {
         match progress {
             HeadersReceivedMsg(headers, status) => {
                 // XXXManishearth Find a way to track partial progress of the send (onprogresss for XHRUpload)
 
                 // Part of step 13, send() (processing request end of file)
@@ -734,26 +734,26 @@ impl<'a> PrivateXMLHttpRequestHelpers fo
                                                                 String::from_str(name.as_slice()),
                                                                 &mut HeaderValueByteIterator::new(&mut reader));
         collection.insert(maybe_header.unwrap());
     }
 
     fn dispatch_progress_event(&self, upload: bool, type_: DOMString, loaded: u64, total: Option<u64>) {
         let win = &*self.global.root();
         let upload_target = &*self.upload.get().root().unwrap();
-        let mut progressevent = ProgressEvent::new(win, type_, false, false,
-                                                   total.is_some(), loaded,
-                                                   total.unwrap_or(0)).root();
+        let progressevent = ProgressEvent::new(win, type_, false, false,
+                                               total.is_some(), loaded,
+                                               total.unwrap_or(0)).root();
         let target: &JSRef<EventTarget> = if upload {
             EventTargetCast::from_ref(upload_target)
         } else {
             EventTargetCast::from_ref(self)
         };
-        let event: &mut JSRef<Event> = EventCast::from_mut_ref(&mut *progressevent);
-        target.dispatch_event_with_target(None, &mut *event).ok();
+        let event: &JSRef<Event> = EventCast::from_ref(&*progressevent);
+        target.dispatch_event_with_target(None, event).ok();
     }
 
     fn dispatch_upload_progress_event(&self, type_: DOMString, partial_load: Option<u64>) {
         // If partial_load is None, loading has completed and we can just use the value from the request body
 
         let total = self.request_body.len() as u64;
         self.dispatch_progress_event(true, type_, partial_load.unwrap_or(total), Some(total));
     }
--- a/servo/src/components/script/dom/xmlhttprequesteventtarget.rs
+++ b/servo/src/components/script/dom/xmlhttprequesteventtarget.rs
@@ -39,94 +39,94 @@ impl Reflectable for XMLHttpRequestEvent
 
     fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
         self.eventtarget.mut_reflector()
     }
 }
 
 pub trait XMLHttpRequestEventTargetMethods {
     fn GetOnloadstart(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnloadstart(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnloadstart(&self, listener: Option<EventHandlerNonNull>);
     fn GetOnprogress(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnprogress(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnprogress(&self, listener: Option<EventHandlerNonNull>);
     fn GetOnabort(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnabort(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnabort(&self, listener: Option<EventHandlerNonNull>);
     fn GetOnerror(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnerror(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnerror(&self, listener: Option<EventHandlerNonNull>);
     fn GetOnload(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnload(&self, listener: Option<EventHandlerNonNull>);
     fn GetOntimeout(&self) -> Option<EventHandlerNonNull>;
-    fn SetOntimeout(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOntimeout(&self, listener: Option<EventHandlerNonNull>);
     fn GetOnloadend(&self) -> Option<EventHandlerNonNull>;
-    fn SetOnloadend(&mut self, listener: Option<EventHandlerNonNull>);
+    fn SetOnloadend(&self, listener: Option<EventHandlerNonNull>);
 }
 
 impl<'a> XMLHttpRequestEventTargetMethods for JSRef<'a, XMLHttpRequestEventTarget> {
     fn GetOnloadstart(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("loadstart")
     }
 
-    fn SetOnloadstart(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnloadstart(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("loadstart", listener)
     }
 
     fn GetOnprogress(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("progress")
     }
 
-    fn SetOnprogress(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnprogress(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("progress", listener)
     }
 
     fn GetOnabort(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("abort")
     }
 
-    fn SetOnabort(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnabort(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("abort", listener)
     }
 
     fn GetOnerror(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("error")
     }
 
-    fn SetOnerror(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnerror(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("error", listener)
     }
 
     fn GetOnload(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("load")
     }
 
-    fn SetOnload(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnload(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("load", listener)
     }
 
     fn GetOntimeout(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("timeout")
     }
 
-    fn SetOntimeout(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOntimeout(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("timeout", listener)
     }
 
     fn GetOnloadend(&self) -> Option<EventHandlerNonNull> {
         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.get_event_handler_common("loadend")
     }
 
-    fn SetOnloadend(&mut self, listener: Option<EventHandlerNonNull>) {
-        let eventtarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(self);
+    fn SetOnloadend(&self, listener: Option<EventHandlerNonNull>) {
+        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
         eventtarget.set_event_handler_common("loadend", listener)
     }
 }
--- a/servo/src/components/script/html/hubbub_html_parser.rs
+++ b/servo/src/components/script/html/hubbub_html_parser.rs
@@ -12,20 +12,20 @@ use dom::htmlelement::HTMLElement;
 use dom::htmlheadingelement::{Heading1, Heading2, Heading3, Heading4, Heading5, Heading6};
 use dom::htmlformelement::HTMLFormElement;
 use dom::node::{ElementNodeTypeId, NodeHelpers, NodeMethods};
 use dom::types::*;
 use html::cssparse::{StylesheetProvenance, UrlProvenance, spawn_css_parser};
 use script_task::Page;
 
 use hubbub::hubbub;
-use hubbub::hubbub::{NullNs, XLinkNs, XmlNs, XmlNsNs};
+use hubbub::hubbub::{NullNs, HtmlNs, MathMlNs, SvgNs, XLinkNs, XmlNs, XmlNsNs};
 use servo_net::resource_task::{Load, LoadData, Payload, Done, ResourceTask, load_whole_resource};
 use servo_util::namespace;
-use servo_util::namespace::Null;
+use servo_util::namespace::{Namespace, Null};
 use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS};
 use servo_util::task::spawn_named;
 use servo_util::url::parse_url;
 use std::ascii::StrAsciiExt;
 use std::mem;
 use std::cell::RefCell;
 use std::comm::{channel, Sender, Receiver};
 use style::Stylesheet;
@@ -153,17 +153,21 @@ fn js_script_listener(to_parent: Sender<
     }
 
     assert!(to_parent.send_opt(HtmlDiscoveredScript(result_vec)).is_ok());
 }
 
 // Silly macros to handle constructing      DOM nodes. This produces bad code and should be optimized
 // via atomization (issue #85).
 
-pub fn build_element_from_tag(tag: DOMString, document: &JSRef<Document>) -> Temporary<Element> {
+pub fn build_element_from_tag(tag: DOMString, ns: Namespace, document: &JSRef<Document>) -> Temporary<Element> {
+    if ns != namespace::HTML {
+        return Element::new(tag, ns, None, document);
+    }
+
     // TODO (Issue #85): use atoms
     handle_element!(document, tag, "a",         HTMLAnchorElement);
     handle_element!(document, tag, "abbr",      HTMLElement);
     handle_element!(document, tag, "acronym",   HTMLElement);
     handle_element!(document, tag, "address",   HTMLElement);
     handle_element!(document, tag, "applet",    HTMLAppletElement);
     handle_element!(document, tag, "area",      HTMLAreaElement);
     handle_element!(document, tag, "article",   HTMLElement);
@@ -364,17 +368,23 @@ pub fn parse_html(page: &Page,
                 doctype_node.deref().to_hubbub_node()
             }
         },
         create_element: |tag: Box<hubbub::Tag>| {
             debug!("create element {:?}", tag.name.clone());
             // NOTE: tmp vars are workaround for lifetime issues. Both required.
             let tmp_borrow = doc_cell.borrow();
             let tmp = &*tmp_borrow;
-            let mut element: Root<Element> = build_element_from_tag(tag.name.clone(), *tmp).root();
+            let namespace = match tag.ns {
+                HtmlNs => namespace::HTML,
+                MathMlNs => namespace::MathML,
+                SvgNs => namespace::SVG,
+                ns => fail!("Not expecting namespace {:?}", ns),
+            };
+            let mut element: Root<Element> = build_element_from_tag(tag.name.clone(), namespace, *tmp).root();
 
             debug!("-- attach attrs");
             for attr in tag.attributes.iter() {
                 let (namespace, prefix) = match attr.ns {
                     NullNs => (namespace::Null, None),
                     XLinkNs => (namespace::XLink, Some("xlink")),
                     XmlNs => (namespace::XML, Some("xml")),
                     XmlNsNs => (namespace::XMLNS, Some("xmlns")),
@@ -491,27 +501,27 @@ pub fn parse_html(page: &Page,
                 let script: &JSRef<Element> = &*from_hubbub_node(script).root();
                 match script.get_attribute(Null, "src").root() {
                     Some(src) => {
                         debug!("found script: {:s}", src.deref().Value());
                         let new_url = parse_url(src.deref().value_ref(), Some(url3.clone()));
                         js_chan2.send(JSTaskNewFile(new_url));
                     }
                     None => {
-                        let mut data = vec!();
+                        let mut data = String::new();
                         let scriptnode: &JSRef<Node> = NodeCast::from_ref(script);
                         debug!("iterating over children {:?}", scriptnode.first_child());
                         for child in scriptnode.children() {
                             debug!("child = {:?}", child);
                             let text: &JSRef<Text> = TextCast::to_ref(&child).unwrap();
-                            data.push(text.deref().characterdata.data.to_str());  // FIXME: Bad copy.
+                            data.push_str(text.deref().characterdata.data.deref().borrow().as_slice());
                         }
 
                         debug!("script data = {:?}", data);
-                        js_chan2.send(JSTaskNewInlineScript(data.concat(), url3.clone()));
+                        js_chan2.send(JSTaskNewInlineScript(data, url3.clone()));
                     }
                 }
             }
             debug!("complete script");
         },
         complete_style: |_| {
             // style parsing is handled in element::notify_child_list_changed.
         },
--- a/servo/src/components/script/script_task.rs
+++ b/servo/src/components/script/script_task.rs
@@ -812,41 +812,37 @@ impl ScriptTask {
     }
 
     /// Handles a timer that fired.
     fn handle_fire_timer_msg(&self, id: PipelineId, timer_id: TimerId) {
         let mut page = self.page.borrow_mut();
         let page = page.find(id).expect("ScriptTask: received fire timer msg for a
             pipeline ID not associated with this script task. This is a bug.");
         let frame = page.frame();
-        let mut window = frame.get_ref().window.root();
+        let window = frame.get_ref().window.root();
 
         let this_value = window.deref().reflector().get_jsobject();
 
-        let is_interval;
-        match window.deref().active_timers.find(&timer_id) {
+        let data = match window.deref().active_timers.deref().borrow().find(&timer_id) {
             None => return,
-            Some(timer_handle) => {
-                // TODO: Support extra arguments. This requires passing a `*JSVal` array as `argv`.
-                let cx = self.get_cx();
-                with_compartment(cx, this_value, || {
-                    let mut rval = NullValue();
-                    unsafe {
-                        JS_CallFunctionValue(cx, this_value,
-                                             *timer_handle.data.funval,
-                                             0, ptr::mut_null(), &mut rval);
-                    }
-                });
+            Some(timer_handle) => timer_handle.data,
+        };
 
-                is_interval = timer_handle.data.is_interval;
+        // TODO: Support extra arguments. This requires passing a `*JSVal` array as `argv`.
+        let cx = self.get_cx();
+        with_compartment(cx, this_value, || {
+            let mut rval = NullValue();
+            unsafe {
+                JS_CallFunctionValue(cx, this_value, *data.funval,
+                                     0, ptr::mut_null(), &mut rval);
             }
-        }
+        });
 
-        if !is_interval {
-            window.deref_mut().active_timers.remove(&timer_id);
+        if !data.is_interval {
+            window.deref().active_timers.deref().borrow_mut().remove(&timer_id);
         }
     }
 
     /// Handles a notification that reflow completed.
     fn handle_reflow_complete_msg(&self, pipeline_id: PipelineId, reflow_id: uint) {
         debug!("Script: Reflow {:?} complete for {:?}", reflow_id, pipeline_id);
         let mut page = self.page.borrow_mut();
         let page = page.find(pipeline_id).expect(
@@ -947,17 +943,17 @@ impl ScriptTask {
         let cx = cx.get_ref();
         // Create the window and document objects.
         let mut window = Window::new(cx.deref().ptr,
                                      page.clone(),
                                      self.chan.clone(),
                                      self.compositor.dup(),
                                      self.image_cache_task.clone()).root();
         let mut document = Document::new(&*window, Some(url.clone()), HTMLDocument, None).root();
-        window.deref_mut().init_browser_context(&*document);
+        window.deref().init_browser_context(&*document);
 
         with_compartment((**cx).ptr, window.reflector().get_jsobject(), || {
             let mut js_info = page.mut_js_info();
             RegisterBindings::Register(&*window, js_info.get_mut_ref());
         });
 
         self.compositor.set_ready_state(Loading);
         // Parse HTML.
@@ -1028,22 +1024,21 @@ impl ScriptTask {
                     Err(_) => println!("evaluate_script failed")
                 }
             }
         });
 
         // We have no concept of a document loader right now, so just dispatch the
         // "load" event as soon as we've finished executing all scripts parsed during
         // the initial load.
-        let mut event =
-            Event::new(&*window, "load".to_string(), false, false).root();
+        let event = Event::new(&*window, "load".to_string(), false, false).root();
         let doctarget: &JSRef<EventTarget> = EventTargetCast::from_ref(&*document);
         let wintarget: &JSRef<EventTarget> = EventTargetCast::from_ref(&*window);
         let _ = wintarget.dispatch_event_with_target(Some((*doctarget).clone()),
-                                                     &mut *event);
+                                                     &*event);
 
         page.fragment_node.assign(fragment.map_or(None, |fragid| page.find_fragment_node(fragid)));
 
         let ConstellationChan(ref chan) = self.constellation_chan;
         chan.send(LoadCompleteMsg(page.id, url));
     }
 
     fn scroll_fragment_point(&self, pipeline_id: PipelineId, node: &JSRef<Element>) {
@@ -1084,22 +1079,24 @@ impl ScriptTask {
 
                     frame.as_ref().map(|frame| Temporary::new(frame.window.clone()))
                 };
 
                 match window.root() {
                     Some(mut window) => {
                         // http://dev.w3.org/csswg/cssom-view/#resizing-viewports
                         // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#event-type-resize
-                        let mut uievent = UIEvent::new(&window.clone(), "resize".to_string(), false, false,
-                                                       Some((*window).clone()), 0i32).root();
-                        let event: &mut JSRef<Event> = EventCast::from_mut_ref(&mut *uievent);
+                        let uievent = UIEvent::new(&window.clone(),
+                                                   "resize".to_string(), false,
+                                                   false, Some(window.clone()),
+                                                   0i32).root();
+                        let event: &JSRef<Event> = EventCast::from_ref(&*uievent);
 
-                        let wintarget: &mut JSRef<EventTarget> = EventTargetCast::from_mut_ref(&mut *window);
-                        let _ = wintarget.dispatch_event_with_target(None, &mut *event);
+                        let wintarget: &JSRef<EventTarget> = EventTargetCast::from_ref(&*window);
+                        let _ = wintarget.dispatch_event_with_target(None, event);
                     }
                     None => ()
                 }
             }
 
             // FIXME(pcwalton): This reflows the entire document and is not incremental-y.
             ReflowEvent => {
                 debug!("script got reflow event");
@@ -1124,22 +1121,22 @@ impl ScriptTask {
 
                         let maybe_node = temp_node.root().ancestors().find(|node| node.is_element());
                         match maybe_node {
                             Some(node) => {
                                 debug!("clicked on {:s}", node.debug_str());
                                 match *page.frame() {
                                     Some(ref frame) => {
                                         let window = frame.window.root();
-                                        let mut event =
+                                        let event =
                                             Event::new(&*window,
                                                        "click".to_string(),
                                                        true, true).root();
                                         let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(&node);
-                                        let _ = eventtarget.dispatch_event_with_target(None, &mut *event);
+                                        let _ = eventtarget.dispatch_event_with_target(None, &*event);
                                     }
                                     None => {}
                                 }
                             }
                             None => {}
                         }
                     }
 
@@ -1155,32 +1152,32 @@ impl ScriptTask {
 
                         let mut target_list = vec!();
                         let mut target_compare = false;
 
                         let mouse_over_targets = &mut *self.mouse_over_targets.borrow_mut();
                         match *mouse_over_targets {
                             Some(ref mut mouse_over_targets) => {
                                 for node in mouse_over_targets.mut_iter() {
-                                    let mut node = node.root();
-                                    node.set_hover_state(false);
+                                    let node = node.root();
+                                    node.deref().set_hover_state(false);
                                 }
                             }
                             None => {}
                         }
 
                         for node_address in node_address.iter() {
 
                             let temp_node =
                                 node::from_untrusted_node_address(
                                     self.js_runtime.deref().ptr, *node_address);
 
                             let maybe_node = temp_node.root().ancestors().find(|node| node.is_element());
                             match maybe_node {
-                                Some(mut node) => {
+                                Some(node) => {
                                     node.set_hover_state(true);
 
                                     match *mouse_over_targets {
                                         Some(ref mouse_over_targets) => {
                                             if !target_compare {
                                                 target_compare = !mouse_over_targets.contains(&node.unrooted());
                                             }
                                         }