diff options
-rw-r--r-- | components/script/dom/bindings/global.rs | 4 | ||||
-rw-r--r-- | components/script/dom/bindings/js.rs | 20 | ||||
-rw-r--r-- | components/script/dom/bindings/refcounted.rs | 178 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 10 | ||||
-rw-r--r-- | components/script/dom/dedicatedworkerglobalscope.rs | 201 | ||||
-rw-r--r-- | components/script/dom/htmlformelement.rs | 3 | ||||
-rw-r--r-- | components/script/dom/window.rs | 16 | ||||
-rw-r--r-- | components/script/dom/worker.rs | 61 | ||||
-rw-r--r-- | components/script/dom/workerglobalscope.rs | 32 | ||||
-rw-r--r-- | components/script/dom/xmlhttprequest.rs | 95 | ||||
-rw-r--r-- | components/script/lib.rs | 1 | ||||
-rw-r--r-- | components/script/script_task.rs | 49 | ||||
-rw-r--r-- | components/script/timers.rs | 5 |
13 files changed, 422 insertions, 253 deletions
diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index 4efeb7aaf67..38e018fe24f 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -10,7 +10,7 @@ use dom::bindings::conversions::FromJSValConvertible; use dom::bindings::js::{JS, JSRef, Root}; use dom::bindings::utils::{Reflectable, Reflector}; -use dom::workerglobalscope::WorkerGlobalScope; +use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers}; use dom::window; use script_task::ScriptChan; @@ -81,7 +81,7 @@ impl<'a> GlobalRef<'a> { /// `ScriptChan` used to send messages to the event loop of this global's /// thread. - pub fn script_chan<'b>(&'b self) -> &'b ScriptChan { + pub fn script_chan(&self) -> Box<ScriptChan+Send> { match *self { GlobalRef::Window(ref window) => window.script_chan(), GlobalRef::Worker(ref worker) => worker.script_chan(), diff --git a/components/script/dom/bindings/js.rs b/components/script/dom/bindings/js.rs index 1f3cb7814e0..a1957f6797a 100644 --- a/components/script/dom/bindings/js.rs +++ b/components/script/dom/bindings/js.rs @@ -48,8 +48,6 @@ use dom::bindings::trace::JSTraceable; use dom::bindings::utils::{Reflector, Reflectable}; use dom::node::Node; -use dom::xmlhttprequest::{XMLHttpRequest, TrustedXHRAddress}; -use dom::worker::{Worker, TrustedWorkerAddress}; use js::jsapi::JSObject; use js::jsval::JSVal; use layout_interface::TrustedNodeAddress; @@ -142,24 +140,6 @@ impl JS<Node> { } } -impl JS<XMLHttpRequest> { - pub unsafe fn from_trusted_xhr_address(inner: TrustedXHRAddress) -> JS<XMLHttpRequest> { - let TrustedXHRAddress(addr) = inner; - JS { - ptr: addr as *const XMLHttpRequest - } - } -} - -impl JS<Worker> { - pub unsafe fn from_trusted_worker_address(inner: TrustedWorkerAddress) -> JS<Worker> { - let TrustedWorkerAddress(addr) = inner; - JS { - ptr: addr as *const Worker - } - } -} - impl<T: Reflectable> JS<T> { /// Create a new JS-owned value wrapped from a raw Rust pointer. pub unsafe fn from_raw(raw: *const T) -> JS<T> { diff --git a/components/script/dom/bindings/refcounted.rs b/components/script/dom/bindings/refcounted.rs new file mode 100644 index 00000000000..7bffda2153d --- /dev/null +++ b/components/script/dom/bindings/refcounted.rs @@ -0,0 +1,178 @@ +/* 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/. */ + +#![deny(missing_docs)] + +//! A generic, safe mechnanism by which DOM objects can be pinned and transferred +//! between tasks (or intra-task for asynchronous events). Akin to Gecko's +//! nsMainThreadPtrHandle, this uses thread-safe reference counting and ensures +//! that the actual SpiderMonkey GC integration occurs on the script task via +//! message passing. Ownership of a `Trusted<T>` object means the DOM object of +//! type T to which it points remains alive. Any other behaviour is undefined. +//! To guarantee the lifetime of a DOM object when performing asynchronous operations, +//! obtain a `Trusted<T>` from that object and pass it along with each operation. +//! A usable pointer to the original DOM object can be obtained on the script task +//! from a `Trusted<T>` via the `to_temporary` method. +//! +//! The implementation of Trusted<T> is as follows: +//! A hashtable resides in the script task, keyed on the pointer to the Rust DOM object. +//! The values in this hashtable are atomic reference counts. When a Trusted<T> object is +//! created or cloned, this count is increased. When a Trusted<T> is dropped, the count +//! decreases. If the count hits zero, a message is dispatched to the script task to remove +//! the entry from the hashmap if the count is still zero. The JS reflector for the DOM object +//! is rooted when a hashmap entry is first created, and unrooted when the hashmap entry +//! is removed. + +use dom::bindings::js::{Temporary, JS, JSRef}; +use dom::bindings::utils::{Reflector, Reflectable}; +use script_task::{ScriptMsg, ScriptChan}; + +use js::jsapi::{JS_AddObjectRoot, JS_RemoveObjectRoot, JSContext}; + +use libc; +use std::cell::RefCell; +use std::collections::hash_map::{HashMap, Vacant, Occupied}; +use std::sync::{Arc, Mutex}; + +local_data_key!(pub LiveReferences: LiveDOMReferences) + +/// A safe wrapper around a raw pointer to a DOM object that can be +/// shared among tasks for use in asynchronous operations. The underlying +/// DOM object is guaranteed to live at least as long as the last outstanding +/// `Trusted<T>` instance. +pub struct Trusted<T> { + /// A pointer to the Rust DOM object of type T, but void to allow + /// sending `Trusted<T>` between tasks, regardless of T's sendability. + ptr: *const libc::c_void, + refcount: Arc<Mutex<uint>>, + script_chan: Box<ScriptChan + Send>, + owner_thread: *const libc::c_void, +} + +impl<T: Reflectable> Trusted<T> { + /// Create a new `Trusted<T>` instance from an existing DOM pointer. The DOM object will + /// be prevented from being GCed for the duration of the resulting `Trusted<T>` object's + /// lifetime. + pub fn new(cx: *mut JSContext, ptr: JSRef<T>, script_chan: Box<ScriptChan + Send>) -> Trusted<T> { + let live_references = LiveReferences.get().unwrap(); + let refcount = live_references.addref(cx, &*ptr as *const T); + Trusted { + ptr: &*ptr as *const T as *const libc::c_void, + refcount: refcount, + script_chan: script_chan, + owner_thread: (&*live_references) as *const _ as *const libc::c_void, + } + } + + /// Obtain a usable DOM pointer from a pinned `Trusted<T>` value. Fails if used on + /// a different thread than the original value from which this `Trusted<T>` was + /// obtained. + pub fn to_temporary(&self) -> Temporary<T> { + assert!({ + let live_references = LiveReferences.get().unwrap(); + self.owner_thread == (&*live_references) as *const _ as *const libc::c_void + }); + unsafe { + Temporary::new(JS::from_raw(self.ptr as *const T)) + } + } +} + +impl<T: Reflectable> Clone for Trusted<T> { + fn clone(&self) -> Trusted<T> { + { + let mut refcount = self.refcount.lock(); + *refcount += 1; + } + + Trusted { + ptr: self.ptr, + refcount: self.refcount.clone(), + script_chan: self.script_chan.clone(), + owner_thread: self.owner_thread, + } + } +} + +#[unsafe_destructor] +impl<T: Reflectable> Drop for Trusted<T> { + fn drop(&mut self) { + let mut refcount = self.refcount.lock(); + assert!(*refcount > 0); + *refcount -= 1; + if *refcount == 0 { + self.script_chan.send(ScriptMsg::RefcountCleanup(self.ptr)); + } + } +} + +/// The set of live, pinned DOM objects that are currently prevented +/// from being garbage collected due to outstanding references. +pub struct LiveDOMReferences { + // keyed on pointer to Rust DOM object + table: RefCell<HashMap<*const libc::c_void, Arc<Mutex<uint>>>> +} + +impl LiveDOMReferences { + /// Set up the task-local data required for storing the outstanding DOM references. + pub fn initialize() { + LiveReferences.replace(Some(LiveDOMReferences { + table: RefCell::new(HashMap::new()), + })); + } + + fn addref<T: Reflectable>(&self, cx: *mut JSContext, ptr: *const T) -> Arc<Mutex<uint>> { + let mut table = self.table.borrow_mut(); + match table.entry(ptr as *const libc::c_void) { + Occupied(mut entry) => { + let refcount = entry.get_mut(); + *refcount.lock() += 1; + refcount.clone() + } + Vacant(entry) => { + unsafe { + let rootable = (*ptr).reflector().rootable(); + JS_AddObjectRoot(cx, rootable); + } + let refcount = Arc::new(Mutex::new(1)); + entry.set(refcount.clone()); + refcount + } + } + } + + /// Unpin the given DOM object if its refcount is 0. + pub fn cleanup(cx: *mut JSContext, raw_reflectable: *const libc::c_void) { + let live_references = LiveReferences.get().unwrap(); + let reflectable = raw_reflectable as *const Reflector; + let mut table = live_references.table.borrow_mut(); + match table.entry(raw_reflectable) { + Occupied(entry) => { + if *entry.get().lock() != 0 { + // there could have been a new reference taken since + // this message was dispatched. + return; + } + + unsafe { + JS_RemoveObjectRoot(cx, (*reflectable).rootable()); + } + let _ = entry.take(); + } + Vacant(_) => { + // there could be a cleanup message dispatched, then a new + // pinned reference obtained and released before the message + // is processed, at which point there would be no matching + // hashtable entry. + info!("attempt to cleanup an unrecognized reflector"); + } + } + } +} + +impl Drop for LiveDOMReferences { + fn drop(&mut self) { + assert!(self.table.borrow().keys().count() == 0); + } +} diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index b877d022c2e..955638a7f7d 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -28,8 +28,10 @@ //! a datatype. use dom::bindings::js::JS; +use dom::bindings::refcounted::Trusted; use dom::bindings::utils::{Reflectable, Reflector, WindowProxyHandler}; use dom::node::{Node, TrustedNodeAddress}; +use script_task::ScriptChan; use collections::hash::{Hash, Hasher}; use cssparser::RGBA; @@ -203,6 +205,7 @@ no_jsmanaged_fields!(Receiver<T>) no_jsmanaged_fields!(Rect<T>) no_jsmanaged_fields!(ImageCacheTask, ScriptControlChan) no_jsmanaged_fields!(Atom, Namespace, Timer) +no_jsmanaged_fields!(Trusted<T>) no_jsmanaged_fields!(PropertyDeclarationBlock) // These three are interdependent, if you plan to put jsmanaged data // in one of these make sure it is propagated properly to containing structs @@ -217,6 +220,13 @@ no_jsmanaged_fields!(UntrustedNodeAddress) no_jsmanaged_fields!(LengthOrPercentageOrAuto) no_jsmanaged_fields!(RGBA) +impl JSTraceable for Box<ScriptChan+Send> { + #[inline] + fn trace(&self, _trc: *mut JSTracer) { + // Do nothing + } +} + impl<'a> JSTraceable for &'a str { #[inline] fn trace(&self, _: *mut JSTracer) { diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index ae0bee5c670..0044bd56254 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -2,6 +2,7 @@ * 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::cell::DOMRefCell; use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding; use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding::DedicatedWorkerGlobalScopeMethods; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; @@ -11,6 +12,7 @@ use dom::bindings::error::ErrorResult; use dom::bindings::error::Error::DataClone; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JSRef, Temporary, RootCollection}; +use dom::bindings::refcounted::LiveDOMReferences; use dom::bindings::utils::Reflectable; use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; use dom::messageevent::MessageEvent; @@ -34,44 +36,93 @@ use std::rc::Rc; use std::ptr; use url::Url; +/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with +/// every message. While this SendableWorkerScriptChan is alive, the associated Worker object +/// will remain alive. +#[deriving(Clone)] +#[jstraceable] +pub struct SendableWorkerScriptChan { + sender: Sender<(TrustedWorkerAddress, ScriptMsg)>, + worker: TrustedWorkerAddress, +} + +impl ScriptChan for SendableWorkerScriptChan { + fn send(&self, msg: ScriptMsg) { + self.sender.send((self.worker.clone(), msg)); + } + + fn clone(&self) -> Box<ScriptChan + Send> { + box SendableWorkerScriptChan { + sender: self.sender.clone(), + worker: self.worker.clone(), + } + } +} + +/// Set the `worker` field of a related DedicatedWorkerGlobalScope object to a particular +/// value for the duration of this object's lifetime. This ensures that the related Worker +/// object only lives as long as necessary (ie. while events are being executed), while +/// providing a reference that can be cloned freely. +struct AutoWorkerReset<'a> { + workerscope: JSRef<'a, DedicatedWorkerGlobalScope>, + old_worker: Option<TrustedWorkerAddress>, +} + +impl<'a> AutoWorkerReset<'a> { + fn new(workerscope: JSRef<'a, DedicatedWorkerGlobalScope>, worker: TrustedWorkerAddress) -> AutoWorkerReset<'a> { + let reset = AutoWorkerReset { + workerscope: workerscope, + old_worker: workerscope.worker.borrow().clone() + }; + *workerscope.worker.borrow_mut() = Some(worker); + reset + } +} + +#[unsafe_destructor] +impl<'a> Drop for AutoWorkerReset<'a> { + fn drop(&mut self) { + *self.workerscope.worker.borrow_mut() = self.old_worker.clone(); + } +} + #[dom_struct] pub struct DedicatedWorkerGlobalScope { workerglobalscope: WorkerGlobalScope, - receiver: Receiver<ScriptMsg>, + receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>, + own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>, + worker: DOMRefCell<Option<TrustedWorkerAddress>>, /// Sender to the parent thread. - parent_sender: ScriptChan, - worker: TrustedWorkerAddress, + parent_sender: Box<ScriptChan+Send>, } impl DedicatedWorkerGlobalScope { fn new_inherited(worker_url: Url, - worker: TrustedWorkerAddress, cx: Rc<Cx>, resource_task: ResourceTask, - parent_sender: ScriptChan, - own_sender: ScriptChan, - receiver: Receiver<ScriptMsg>) + parent_sender: Box<ScriptChan+Send>, + own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>, + receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>) -> DedicatedWorkerGlobalScope { DedicatedWorkerGlobalScope { workerglobalscope: WorkerGlobalScope::new_inherited( - WorkerGlobalScopeTypeId::DedicatedGlobalScope, worker_url, cx, - resource_task, own_sender), + WorkerGlobalScopeTypeId::DedicatedGlobalScope, worker_url, cx, resource_task), receiver: receiver, + own_sender: own_sender, parent_sender: parent_sender, - worker: worker, + worker: DOMRefCell::new(None), } } pub fn new(worker_url: Url, - worker: TrustedWorkerAddress, cx: Rc<Cx>, resource_task: ResourceTask, - parent_sender: ScriptChan, - own_sender: ScriptChan, - receiver: Receiver<ScriptMsg>) + parent_sender: Box<ScriptChan+Send>, + own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>, + receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>) -> Temporary<DedicatedWorkerGlobalScope> { let scope = box DedicatedWorkerGlobalScope::new_inherited( - worker_url, worker, cx.clone(), resource_task, parent_sender, + worker_url, cx.clone(), resource_task, parent_sender, own_sender, receiver); DedicatedWorkerGlobalScopeBinding::Wrap(cx.ptr, scope) } @@ -81,9 +132,9 @@ impl DedicatedWorkerGlobalScope { pub fn run_worker_scope(worker_url: Url, worker: TrustedWorkerAddress, resource_task: ResourceTask, - parent_sender: ScriptChan, - own_sender: ScriptChan, - receiver: Receiver<ScriptMsg>) { + parent_sender: Box<ScriptChan+Send>, + own_sender: Sender<(TrustedWorkerAddress, ScriptMsg)>, + receiver: Receiver<(TrustedWorkerAddress, ScriptMsg)>) { spawn_named_native(format!("WebWorker for {}", worker_url.serialize()), proc() { task_state::initialize(SCRIPT | IN_WORKER); @@ -103,46 +154,25 @@ impl DedicatedWorkerGlobalScope { let (_js_runtime, js_context) = ScriptTask::new_rt_and_cx(); let global = DedicatedWorkerGlobalScope::new( - worker_url, worker, js_context.clone(), resource_task, + worker_url, js_context.clone(), resource_task, parent_sender, own_sender, receiver).root(); - match js_context.evaluate_script( - global.reflector().get_jsobject(), source, url.serialize(), 1) { - Ok(_) => (), - Err(_) => println!("evaluate_script failed") + + { + let _ar = AutoWorkerReset::new(*global, worker); + + match js_context.evaluate_script( + global.reflector().get_jsobject(), source, url.serialize(), 1) { + Ok(_) => (), + Err(_) => println!("evaluate_script failed") + } } - global.delayed_release_worker(); - let scope: JSRef<WorkerGlobalScope> = - WorkerGlobalScopeCast::from_ref(*global); - let target: JSRef<EventTarget> = - EventTargetCast::from_ref(*global); loop { match global.receiver.recv_opt() { - Ok(ScriptMsg::DOMMessage(data, nbytes)) => { - let mut message = UndefinedValue(); - unsafe { - assert!(JS_ReadStructuredClone( - js_context.ptr, data as *const u64, nbytes, - JS_STRUCTURED_CLONE_VERSION, &mut message, - ptr::null(), ptr::null_mut()) != 0); - } - - MessageEvent::dispatch_jsval(target, GlobalRef::Worker(scope), message); - global.delayed_release_worker(); - }, - Ok(ScriptMsg::RunnableMsg(runnable)) => { - runnable.handler() - }, - Ok(ScriptMsg::WorkerPostMessage(addr, data, nbytes)) => { - Worker::handle_message(addr, data, nbytes); - }, - Ok(ScriptMsg::WorkerRelease(addr)) => { - Worker::handle_release(addr) - }, - Ok(ScriptMsg::FireTimer(TimerSource::FromWorker, timer_id)) => { - scope.handle_fire_timer(timer_id); + Ok((linked_worker, msg)) => { + let _ar = AutoWorkerReset::new(*global, linked_worker); + global.handle_event(msg); } - Ok(_) => panic!("Unexpected message"), Err(_) => break, } } @@ -150,6 +180,58 @@ impl DedicatedWorkerGlobalScope { } } +pub trait DedicatedWorkerGlobalScopeHelpers { + fn script_chan(self) -> Box<ScriptChan+Send>; +} + +impl<'a> DedicatedWorkerGlobalScopeHelpers for JSRef<'a, DedicatedWorkerGlobalScope> { + fn script_chan(self) -> Box<ScriptChan+Send> { + box SendableWorkerScriptChan { + sender: self.own_sender.clone(), + worker: self.worker.borrow().as_ref().unwrap().clone(), + } + } +} + +trait PrivateDedicatedWorkerGlobalScopeHelpers { + fn handle_event(self, msg: ScriptMsg); +} + +impl<'a> PrivateDedicatedWorkerGlobalScopeHelpers for JSRef<'a, DedicatedWorkerGlobalScope> { + fn handle_event(self, msg: ScriptMsg) { + match msg { + ScriptMsg::DOMMessage(data, nbytes) => { + let mut message = UndefinedValue(); + let scope: JSRef<WorkerGlobalScope> = WorkerGlobalScopeCast::from_ref(self); + unsafe { + assert!(JS_ReadStructuredClone( + scope.get_cx(), data as *const u64, nbytes, + JS_STRUCTURED_CLONE_VERSION, &mut message, + ptr::null(), ptr::null_mut()) != 0); + } + + let target: JSRef<EventTarget> = EventTargetCast::from_ref(self); + MessageEvent::dispatch_jsval(target, GlobalRef::Worker(scope), message); + }, + ScriptMsg::RunnableMsg(runnable) => { + runnable.handler() + }, + ScriptMsg::WorkerPostMessage(addr, data, nbytes) => { + Worker::handle_message(addr, data, nbytes); + }, + ScriptMsg::RefcountCleanup(addr) => { + let scope: JSRef<WorkerGlobalScope> = WorkerGlobalScopeCast::from_ref(self); + LiveDOMReferences::cleanup(scope.get_cx(), addr); + } + ScriptMsg::FireTimer(TimerSource::FromWorker, timer_id) => { + let scope: JSRef<WorkerGlobalScope> = WorkerGlobalScopeCast::from_ref(self); + scope.handle_fire_timer(timer_id); + } + _ => panic!("Unexpected message"), + } + } +} + impl<'a> DedicatedWorkerGlobalScopeMethods for JSRef<'a, DedicatedWorkerGlobalScope> { fn PostMessage(self, cx: *mut JSContext, message: JSVal) -> ErrorResult { let mut data = ptr::null_mut(); @@ -163,25 +245,14 @@ impl<'a> DedicatedWorkerGlobalScopeMethods for JSRef<'a, DedicatedWorkerGlobalSc return Err(DataClone); } - let ScriptChan(ref sender) = self.parent_sender; - sender.send(ScriptMsg::WorkerPostMessage(self.worker, data, nbytes)); + let worker = self.worker.borrow().as_ref().unwrap().clone(); + self.parent_sender.send(ScriptMsg::WorkerPostMessage(worker, data, nbytes)); Ok(()) } event_handler!(message, GetOnmessage, SetOnmessage) } -trait PrivateDedicatedWorkerGlobalScopeHelpers { - fn delayed_release_worker(self); -} - -impl<'a> PrivateDedicatedWorkerGlobalScopeHelpers for JSRef<'a, DedicatedWorkerGlobalScope> { - fn delayed_release_worker(self) { - let ScriptChan(ref sender) = self.parent_sender; - sender.send(ScriptMsg::WorkerRelease(self.worker)); - } -} - impl DedicatedWorkerGlobalScopeDerived for EventTarget { fn is_dedicatedworkerglobalscope(&self) -> bool { match *self.type_id() { diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index dbc67347596..e58aaed0650 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -204,8 +204,7 @@ impl<'a> HTMLFormElementHelpers for JSRef<'a, HTMLFormElement> { } // This is wrong. https://html.spec.whatwg.org/multipage/forms.html#planned-navigation - let ScriptChan(ref script_chan) = *win.script_chan(); - script_chan.send(ScriptMsg::TriggerLoad(win.page().id, load_data)); + win.script_chan().send(ScriptMsg::TriggerLoad(win.page().id, load_data)); } fn get_form_dataset<'b>(self, submitter: Option<FormSubmitter<'b>>) -> Vec<FormDatum> { diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 21afb9e59af..7b7cc679461 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -52,7 +52,7 @@ use time; #[dom_struct] pub struct Window { eventtarget: EventTarget, - script_chan: ScriptChan, + script_chan: Box<ScriptChan+Send>, control_chan: ScriptControlChan, console: MutNullableJS<Console>, location: MutNullableJS<Location>, @@ -75,8 +75,8 @@ impl Window { (*js_info.as_ref().unwrap().js_context).ptr } - pub fn script_chan<'a>(&'a self) -> &'a ScriptChan { - &self.script_chan + pub fn script_chan(&self) -> Box<ScriptChan+Send> { + self.script_chan.clone() } pub fn control_chan<'a>(&'a self) -> &'a ScriptControlChan { @@ -189,8 +189,7 @@ impl<'a> WindowMethods for JSRef<'a, Window> { } fn Close(self) { - let ScriptChan(ref chan) = self.script_chan; - chan.send(ScriptMsg::ExitWindow(self.page.id.clone())); + self.script_chan.send(ScriptMsg::ExitWindow(self.page.id.clone())); } fn Document(self) -> Temporary<Document> { @@ -342,11 +341,10 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { let url = UrlParser::new().base_url(&base_url).parse(href.as_slice()); // FIXME: handle URL parse errors more gracefully. let url = url.unwrap(); - let ScriptChan(ref script_chan) = self.script_chan; if href.as_slice().starts_with("#") { - script_chan.send(ScriptMsg::TriggerFragment(self.page.id, url)); + self.script_chan.send(ScriptMsg::TriggerFragment(self.page.id, url)); } else { - script_chan.send(ScriptMsg::TriggerLoad(self.page.id, LoadData::new(url))); + self.script_chan.send(ScriptMsg::TriggerLoad(self.page.id, LoadData::new(url))); } } @@ -359,7 +357,7 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { impl Window { pub fn new(cx: *mut JSContext, page: Rc<Page>, - script_chan: ScriptChan, + script_chan: Box<ScriptChan+Send>, control_chan: ScriptControlChan, compositor: Box<ScriptListener+'static>, image_cache_task: ImageCacheTask) diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index 4d03d312223..d6e4391cbfd 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -9,7 +9,8 @@ use dom::bindings::codegen::InheritTypes::EventTargetCast; use dom::bindings::error::{Fallible, ErrorResult}; use dom::bindings::error::Error::{Syntax, DataClone}; use dom::bindings::global::{GlobalRef, GlobalField}; -use dom::bindings::js::{JS, JSRef, Temporary}; +use dom::bindings::js::{JSRef, Temporary}; +use dom::bindings::refcounted::Trusted; use dom::bindings::trace::JSTraceable; use dom::bindings::utils::{Reflectable, reflect_dom_object}; use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope; @@ -20,17 +21,16 @@ use script_task::{ScriptChan, ScriptMsg}; use servo_util::str::DOMString; use js::glue::JS_STRUCTURED_CLONE_VERSION; -use js::jsapi::{JSContext, JS_AddObjectRoot, JS_RemoveObjectRoot, JSTracer}; +use js::jsapi::JSContext; use js::jsapi::{JS_ReadStructuredClone, JS_WriteStructuredClone, JS_ClearPendingException}; use js::jsval::{JSVal, UndefinedValue}; use url::UrlParser; -use libc::{c_void, size_t}; +use libc::size_t; use std::cell::Cell; use std::ptr; -pub struct TrustedWorkerAddress(pub *const c_void); -no_jsmanaged_fields!(TrustedWorkerAddress) +pub type TrustedWorkerAddress = Trusted<Worker>; #[dom_struct] pub struct Worker { @@ -39,11 +39,11 @@ pub struct Worker { global: GlobalField, /// Sender to the Receiver associated with the DedicatedWorkerGlobalScope /// this Worker created. - sender: ScriptChan, + sender: Sender<(TrustedWorkerAddress, ScriptMsg)>, } impl Worker { - fn new_inherited(global: &GlobalRef, sender: ScriptChan) -> Worker { + fn new_inherited(global: &GlobalRef, sender: Sender<(TrustedWorkerAddress, ScriptMsg)>) -> Worker { Worker { eventtarget: EventTarget::new_inherited(EventTargetTypeId::Worker), refcount: Cell::new(0), @@ -52,7 +52,7 @@ impl Worker { } } - pub fn new(global: &GlobalRef, sender: ScriptChan) -> Temporary<Worker> { + pub fn new(global: &GlobalRef, sender: Sender<(TrustedWorkerAddress, ScriptMsg)>) -> Temporary<Worker> { reflect_dom_object(box Worker::new_inherited(global, sender), *global, WorkerBinding::Wrap) @@ -68,13 +68,13 @@ impl Worker { }; let resource_task = global.resource_task(); - let (receiver, sender) = ScriptChan::new(); + let (sender, receiver) = channel(); let worker = Worker::new(global, sender.clone()).root(); - let worker_ref = worker.addref(); + let worker_ref = Trusted::new(global.get_cx(), *worker, global.script_chan()); DedicatedWorkerGlobalScope::run_worker_scope( - worker_url, worker_ref, resource_task, global.script_chan().clone(), + worker_url, worker_ref, resource_task, global.script_chan(), sender, receiver); Ok(Temporary::from_rooted(*worker)) @@ -82,7 +82,7 @@ impl Worker { pub fn handle_message(address: TrustedWorkerAddress, data: *mut u64, nbytes: size_t) { - let worker = unsafe { JS::from_trusted_worker_address(address).root() }; + let worker = address.to_temporary().root(); let global = worker.global.root(); @@ -99,38 +99,6 @@ impl Worker { } } -impl Worker { - // Creates a trusted address to the object, and roots it. Always pair this with a release() - pub fn addref(&self) -> TrustedWorkerAddress { - let refcount = self.refcount.get(); - if refcount == 0 { - let cx = self.global.root().root_ref().get_cx(); - unsafe { - JS_AddObjectRoot(cx, self.reflector().rootable()); - } - } - self.refcount.set(refcount + 1); - TrustedWorkerAddress(self as *const Worker as *const c_void) - } - - pub fn release(&self) { - let refcount = self.refcount.get(); - assert!(refcount > 0) - self.refcount.set(refcount - 1); - if refcount == 1 { - let cx = self.global.root().root_ref().get_cx(); - unsafe { - JS_RemoveObjectRoot(cx, self.reflector().rootable()); - } - } - } - - pub fn handle_release(address: TrustedWorkerAddress) { - let worker = unsafe { JS::from_trusted_worker_address(address).root() }; - worker.release(); - } -} - impl<'a> WorkerMethods for JSRef<'a, Worker> { fn PostMessage(self, cx: *mut JSContext, message: JSVal) -> ErrorResult { let mut data = ptr::null_mut(); @@ -144,9 +112,8 @@ impl<'a> WorkerMethods for JSRef<'a, Worker> { return Err(DataClone); } - self.addref(); - let ScriptChan(ref sender) = self.sender; - sender.send(ScriptMsg::DOMMessage(data, nbytes)); + let address = Trusted::new(cx, self, self.global.root().root_ref().script_chan().clone()); + self.sender.send((address, ScriptMsg::DOMMessage(data, nbytes))); Ok(()) } diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index b9e1709ca44..3cec2779de9 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -2,14 +2,16 @@ * 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::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods; use dom::bindings::codegen::Bindings::FunctionBinding::Function; +use dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods; +use dom::bindings::codegen::InheritTypes::DedicatedWorkerGlobalScopeCast; use dom::bindings::error::{ErrorResult, Fallible}; use dom::bindings::error::Error::{Syntax, Network, FailureUnknown}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{MutNullableJS, JSRef, Temporary}; use dom::bindings::utils::Reflectable; use dom::console::Console; +use dom::dedicatedworkerglobalscope::{DedicatedWorkerGlobalScope, DedicatedWorkerGlobalScopeHelpers}; use dom::eventtarget::{EventTarget, EventTargetTypeId}; use dom::workerlocation::WorkerLocation; use dom::workernavigator::WorkerNavigator; @@ -40,7 +42,6 @@ pub struct WorkerGlobalScope { worker_url: Url, js_context: Rc<Cx>, resource_task: ResourceTask, - script_chan: ScriptChan, location: MutNullableJS<WorkerLocation>, navigator: MutNullableJS<WorkerNavigator>, console: MutNullableJS<Console>, @@ -51,18 +52,16 @@ impl WorkerGlobalScope { pub fn new_inherited(type_id: WorkerGlobalScopeTypeId, worker_url: Url, cx: Rc<Cx>, - resource_task: ResourceTask, - script_chan: ScriptChan) -> WorkerGlobalScope { + resource_task: ResourceTask) -> WorkerGlobalScope { WorkerGlobalScope { eventtarget: EventTarget::new_inherited(EventTargetTypeId::WorkerGlobalScope(type_id)), worker_url: worker_url, js_context: cx, resource_task: resource_task, - script_chan: script_chan, location: Default::default(), navigator: Default::default(), console: Default::default(), - timers: TimerManager::new() + timers: TimerManager::new(), } } @@ -82,10 +81,6 @@ impl WorkerGlobalScope { pub fn get_url<'a>(&'a self) -> &'a Url { &self.worker_url } - - pub fn script_chan<'a>(&'a self) -> &'a ScriptChan { - &self.script_chan - } } impl<'a> WorkerGlobalScopeMethods for JSRef<'a, WorkerGlobalScope> { @@ -153,7 +148,7 @@ impl<'a> WorkerGlobalScopeMethods for JSRef<'a, WorkerGlobalScope> { timeout, IsInterval::NonInterval, TimerSource::FromWorker, - self.script_chan.clone()) + self.script_chan()) } fn ClearTimeout(self, handle: i32) { @@ -166,7 +161,7 @@ impl<'a> WorkerGlobalScopeMethods for JSRef<'a, WorkerGlobalScope> { timeout, IsInterval::Interval, TimerSource::FromWorker, - self.script_chan.clone()) + self.script_chan()) } fn ClearInterval(self, handle: i32) { @@ -176,13 +171,26 @@ impl<'a> WorkerGlobalScopeMethods for JSRef<'a, WorkerGlobalScope> { pub trait WorkerGlobalScopeHelpers { fn handle_fire_timer(self, timer_id: TimerId); + fn script_chan(self) -> Box<ScriptChan+Send>; + fn get_cx(self) -> *mut JSContext; } impl<'a> WorkerGlobalScopeHelpers for JSRef<'a, WorkerGlobalScope> { + fn script_chan(self) -> Box<ScriptChan+Send> { + let dedicated: Option<JSRef<DedicatedWorkerGlobalScope>> = + DedicatedWorkerGlobalScopeCast::to_ref(self); + match dedicated { + Some(dedicated) => dedicated.script_chan(), + None => panic!("need to implement a sender for SharedWorker"), + } + } fn handle_fire_timer(self, timer_id: TimerId) { self.timers.fire_timer(timer_id, self); } + fn get_cx(self) -> *mut JSContext { + self.js_context.ptr + } } diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 9c31ff28d9f..b50a5c4330a 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -15,6 +15,7 @@ use dom::bindings::error::Error::{InvalidState, InvalidAccess}; use dom::bindings::error::Error::{Network, Syntax, Security, Abort, Timeout}; use dom::bindings::global::{GlobalField, GlobalRef, GlobalRoot}; use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, OptionalRootedRootable}; +use dom::bindings::refcounted::Trusted; use dom::bindings::str::ByteString; use dom::bindings::utils::{Reflectable, reflect_dom_object}; use dom::document::Document; @@ -37,13 +38,10 @@ use hyper::http::RawStatus; use hyper::mime::{mod, Mime}; use hyper::method::{Method, Get, Head, Connect, Trace, Extension}; -use js::jsapi::{JS_AddObjectRoot, JS_ParseJSON, JS_RemoveObjectRoot, JSContext}; +use js::jsapi::{JS_ParseJSON, JSContext}; use js::jsapi::JS_ClearPendingException; use js::jsval::{JSVal, NullValue, UndefinedValue}; -use libc; -use libc::c_void; - use net::resource_task::{ResourceTask, ResourceCORSData, Load, LoadData, LoadResponse, Payload, Done}; use cors::{allow_cross_origin_request, CORSRequest, RequestMode}; use servo_util::str::DOMString; @@ -73,15 +71,6 @@ enum XMLHttpRequestState { XHRDone = 4, // So as not to conflict with the ProgressMsg `Done` } -struct XHRReleaseHandler(TrustedXHRAddress); - -impl Runnable for XHRReleaseHandler { - fn handler(&self) { - let XHRReleaseHandler(addr) = *self; - XMLHttpRequest::handle_release(addr); - } -} - struct XHRProgressHandler { addr: TrustedXHRAddress, progress: XHRProgress, @@ -95,7 +84,7 @@ impl XHRProgressHandler { impl Runnable for XHRProgressHandler { fn handler(&self) { - XMLHttpRequest::handle_progress(self.addr, self.progress.clone()); + XMLHttpRequest::handle_progress(self.addr.clone(), self.progress.clone()); } } @@ -128,7 +117,7 @@ impl XHRProgress { enum SyncOrAsync<'a> { Sync(JSRef<'a, XMLHttpRequest>), - Async(TrustedXHRAddress, &'a ScriptChan) + Async(TrustedXHRAddress, Box<ScriptChan+Send>) } enum TerminateReason { @@ -162,7 +151,6 @@ pub struct XMLHttpRequest { send_flag: Cell<bool>, global: GlobalField, - pinned_count: Cell<uint>, timer: DOMRefCell<Timer>, fetch_time: Cell<i64>, terminate_sender: DOMRefCell<Option<Sender<TerminateReason>>>, @@ -196,7 +184,6 @@ impl XMLHttpRequest { upload_events: Cell::new(false), global: GlobalField::from_rooted(global), - pinned_count: Cell::new(0), timer: DOMRefCell::new(Timer::new().unwrap()), fetch_time: Cell::new(0), terminate_sender: DOMRefCell::new(None), @@ -213,14 +200,8 @@ impl XMLHttpRequest { } pub fn handle_progress(addr: TrustedXHRAddress, progress: XHRProgress) { - unsafe { - let xhr = JS::from_trusted_xhr_address(addr).root(); - xhr.process_partial_response(progress); - } - } - - pub fn handle_release(addr: TrustedXHRAddress) { - addr.release_once(); + let xhr = addr.to_temporary().root(); + xhr.process_partial_response(progress); } fn fetch(fetch_type: &SyncOrAsync, resource_task: ResourceTask, @@ -233,9 +214,8 @@ impl XMLHttpRequest { SyncOrAsync::Sync(xhr) => { xhr.process_partial_response(msg); }, - SyncOrAsync::Async(addr, script_chan) => { - let ScriptChan(ref chan) = *script_chan; - chan.send(ScriptMsg::RunnableMsg(box XHRProgressHandler::new(addr, msg))); + SyncOrAsync::Async(ref addr, ref script_chan) => { + script_chan.send(ScriptMsg::RunnableMsg(box XHRProgressHandler::new(addr.clone(), msg))); } } } @@ -633,25 +613,20 @@ impl<'a> XMLHttpRequestMethods for JSRef<'a, XMLHttpRequest> { terminate_receiver, cors_request, gen_id, start_port); } else { self.fetch_time.set(time::now().to_timespec().sec); - let script_chan = global.root_ref().script_chan().clone(); - // Pin the object before launching the fetch task. - // The `ScriptMsg::RunnableMsg` sent when the fetch task completes will - // unpin it. This is to ensure that the object will stay alive - // as long as there are (possibly cancelled) inflight events queued up - // in the script task's port - let addr = unsafe { - self.to_trusted() - }; + let script_chan = global.root_ref().script_chan(); + // Pin the object before launching the fetch task. This is to ensure that + // the object will stay alive as long as there are (possibly cancelled) + // inflight events queued up in the script task's port. + let addr = Trusted::new(self.global.root().root_ref().get_cx(), self, + script_chan.clone()); spawn_named("XHRTask", proc() { - let _ = XMLHttpRequest::fetch(&mut SyncOrAsync::Async(addr, &script_chan), + let _ = XMLHttpRequest::fetch(&mut SyncOrAsync::Async(addr, script_chan), resource_task, load_data, terminate_receiver, cors_request, gen_id, start_port); - let ScriptChan(ref chan) = script_chan; - chan.send(ScriptMsg::RunnableMsg(box XHRReleaseHandler(addr))); }); let timeout = self.timeout.get(); if timeout > 0 { @@ -768,20 +743,9 @@ impl XMLHttpRequestDerived for EventTarget { } } -pub struct TrustedXHRAddress(pub *const c_void); - -impl TrustedXHRAddress { - pub fn release_once(self) { - unsafe { - JS::from_trusted_xhr_address(self).root().release_once(); - } - } -} - +pub type TrustedXHRAddress = Trusted<XMLHttpRequest>; trait PrivateXMLHttpRequestHelpers { - unsafe fn to_trusted(self) -> TrustedXHRAddress; - fn release_once(self); fn change_ready_state(self, XMLHttpRequestState); fn process_partial_response(self, progress: XHRProgress); fn terminate_ongoing_fetch(self); @@ -796,33 +760,6 @@ trait PrivateXMLHttpRequestHelpers { } impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> { - // Creates a trusted address to the object, and roots it. Always pair this with a release() - unsafe fn to_trusted(self) -> TrustedXHRAddress { - if self.pinned_count.get() == 0 { - JS_AddObjectRoot(self.global.root().root_ref().get_cx(), self.reflector().rootable()); - } - let pinned_count = self.pinned_count.get(); - self.pinned_count.set(pinned_count + 1); - TrustedXHRAddress(self.deref() as *const XMLHttpRequest as *const libc::c_void) - } - - fn release_once(self) { - if self.sync.get() { - // Lets us call this at various termination cases without having to - // check self.sync every time, since the pinning mechanism only is - // meaningful during an async fetch - return; - } - assert!(self.pinned_count.get() > 0) - let pinned_count = self.pinned_count.get(); - self.pinned_count.set(pinned_count - 1); - if self.pinned_count.get() == 0 { - unsafe { - JS_RemoveObjectRoot(self.global.root().root_ref().get_cx(), self.reflector().rootable()); - } - } - } - fn change_ready_state(self, rs: XMLHttpRequestState) { assert!(self.ready_state.get() != rs) self.ready_state.set(rs); diff --git a/components/script/lib.rs b/components/script/lib.rs index b62b137a38e..7ad317a1296 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -59,6 +59,7 @@ pub mod dom { pub mod cell; pub mod global; pub mod js; + pub mod refcounted; pub mod utils; pub mod callback; pub mod error; diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 26b5665962e..443bb8c37d6 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -15,6 +15,7 @@ use dom::bindings::conversions::FromJSValConvertible; use dom::bindings::conversions::StringificationBehavior; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, JSRef, RootCollection, Temporary, OptionalRootable}; +use dom::bindings::refcounted::LiveDOMReferences; use dom::bindings::trace::JSTraceable; use dom::bindings::utils::{wrap_for_same_compartment, pre_wrap}; use dom::document::{Document, IsHTMLDocument, DocumentHelpers, DocumentSource}; @@ -63,13 +64,14 @@ use geom::point::Point2D; use hyper::header::{Header, HeaderFormat}; use hyper::header::common::util as header_util; use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC}; -use js::jsapi::{JSContext, JSRuntime, JSTracer}; +use js::jsapi::{JSContext, JSRuntime}; use js::jsapi::{JS_SetGCParameter, JSGC_MAX_BYTES}; use js::jsapi::{JS_SetGCCallback, JSGCStatus, JSGC_BEGIN, JSGC_END}; use js::rust::{Cx, RtUtils}; use js; use url::Url; +use libc; use libc::size_t; use std::any::{Any, AnyRefExt}; use std::comm::{channel, Sender, Receiver, Select}; @@ -114,23 +116,41 @@ pub enum ScriptMsg { DOMMessage(*mut u64, size_t), /// Posts a message to the Worker object (dispatched to all tasks). WorkerPostMessage(TrustedWorkerAddress, *mut u64, size_t), - /// Releases one reference to the Worker object (dispatched to all tasks). - WorkerRelease(TrustedWorkerAddress), /// Generic message that encapsulates event handling. RunnableMsg(Box<Runnable+Send>), + /// A DOM object's last pinned reference was removed (dispatched to all tasks). + RefcountCleanup(*const libc::c_void), +} + +/// A cloneable interface for communicating with an event loop. +pub trait ScriptChan { + /// Send a message to the associated event loop. + fn send(&self, msg: ScriptMsg); + /// Clone this handle. + fn clone(&self) -> Box<ScriptChan+Send>; } /// Encapsulates internal communication within the script task. -#[deriving(Clone)] -pub struct ScriptChan(pub Sender<ScriptMsg>); +#[jstraceable] +pub struct NonWorkerScriptChan(pub Sender<ScriptMsg>); -no_jsmanaged_fields!(ScriptChan) +impl ScriptChan for NonWorkerScriptChan { + fn send(&self, msg: ScriptMsg) { + let NonWorkerScriptChan(ref chan) = *self; + chan.send(msg); + } + + fn clone(&self) -> Box<ScriptChan+Send> { + let NonWorkerScriptChan(ref chan) = *self; + box NonWorkerScriptChan(chan.clone()) + } +} -impl ScriptChan { +impl NonWorkerScriptChan { /// Creates a new script chan. - pub fn new() -> (Receiver<ScriptMsg>, ScriptChan) { + pub fn new() -> (Receiver<ScriptMsg>, Box<NonWorkerScriptChan>) { let (chan, port) = channel(); - (port, ScriptChan(chan)) + (port, box NonWorkerScriptChan(chan)) } } @@ -165,7 +185,7 @@ pub struct ScriptTask { port: Receiver<ScriptMsg>, /// A channel to hand out to script task-based entities that need to be able to enqueue /// events in the event queue. - chan: ScriptChan, + chan: NonWorkerScriptChan, /// A channel to hand out to tasks that need to respond to a message from the script task. control_chan: ScriptControlChan, @@ -280,7 +300,7 @@ impl ScriptTaskFactory for ScriptTask { box compositor as Box<ScriptListener>, layout_chan, script_port, - ScriptChan(script_chan), + NonWorkerScriptChan(script_chan), control_chan, control_port, constellation_chan, @@ -312,7 +332,7 @@ impl ScriptTask { compositor: Box<ScriptListener+'static>, layout_chan: LayoutChan, port: Receiver<ScriptMsg>, - chan: ScriptChan, + chan: NonWorkerScriptChan, control_chan: ScriptControlChan, control_port: Receiver<ConstellationControlMsg>, constellation_chan: ConstellationChan, @@ -368,6 +388,7 @@ impl ScriptTask { } pub fn new_rt_and_cx() -> (js::rust::rt, Rc<Cx>) { + LiveDOMReferences::initialize(); let js_runtime = js::rust::rt(); assert!({ let ptr: *mut JSRuntime = (*js_runtime).ptr; @@ -577,10 +598,10 @@ impl ScriptTask { panic!("unexpected message"), ScriptMsg::WorkerPostMessage(addr, data, nbytes) => Worker::handle_message(addr, data, nbytes), - ScriptMsg::WorkerRelease(addr) => - Worker::handle_release(addr), ScriptMsg::RunnableMsg(runnable) => runnable.handler(), + ScriptMsg::RefcountCleanup(addr) => + LiveDOMReferences::cleanup(self.get_cx(), addr), } } diff --git a/components/script/timers.rs b/components/script/timers.rs index 082ea626790..0502bdfcd38 100644 --- a/components/script/timers.rs +++ b/components/script/timers.rs @@ -100,7 +100,7 @@ impl TimerManager { timeout: i32, is_interval: IsInterval, source: TimerSource, - script_chan: ScriptChan) + script_chan: Box<ScriptChan+Send>) -> i32 { let timeout = cmp::max(0, timeout) as u64; let handle = self.next_timer_handle.get(); @@ -136,8 +136,7 @@ impl TimerManager { let id = select.wait(); if id == timeout_handle.id() { timeout_port.recv(); - let ScriptChan(ref chan) = script_chan; - chan.send(ScriptMsg::FireTimer(source, TimerId(handle))); + script_chan.send(ScriptMsg::FireTimer(source, TimerId(handle))); if is_interval == IsInterval::NonInterval { break; } |