diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/script/dom/bindings/global.rs | 4 | ||||
-rw-r--r-- | components/script/dom/bindings/refcounted.rs | 22 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 8 | ||||
-rw-r--r-- | components/script/dom/dedicatedworkerglobalscope.rs | 187 | ||||
-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 | 17 | ||||
-rw-r--r-- | components/script/dom/workerglobalscope.rs | 32 | ||||
-rw-r--r-- | components/script/dom/xmlhttprequest.rs | 19 | ||||
-rw-r--r-- | components/script/script_task.rs | 42 | ||||
-rw-r--r-- | components/script/timers.rs | 5 |
11 files changed, 234 insertions, 121 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/refcounted.rs b/components/script/dom/bindings/refcounted.rs index 6118408ed4c..7bffda2153d 100644 --- a/components/script/dom/bindings/refcounted.rs +++ b/components/script/dom/bindings/refcounted.rs @@ -42,32 +42,37 @@ local_data_key!(pub LiveReferences: LiveDOMReferences) /// DOM object is guaranteed to live at least as long as the last outstanding /// `Trusted<T>` instance. pub struct Trusted<T> { - cx: *mut JSContext, /// 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: ScriptChan, + 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: ScriptChan) -> Trusted<T> { + 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 { - cx: cx, 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. Attempts to use the - /// resulting `Temporary<T>` off of the script thread will fail. + /// 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)) } @@ -82,10 +87,10 @@ impl<T: Reflectable> Clone for Trusted<T> { } Trusted { - cx: self.cx, ptr: self.ptr, refcount: self.refcount.clone(), script_chan: self.script_chan.clone(), + owner_thread: self.owner_thread, } } } @@ -97,8 +102,7 @@ impl<T: Reflectable> Drop for Trusted<T> { assert!(*refcount > 0); *refcount -= 1; if *refcount == 0 { - let ScriptChan(ref chan) = self.script_chan; - chan.send(ScriptMsg::RefcountCleanup(self.ptr)); + self.script_chan.send(ScriptMsg::RefcountCleanup(self.ptr)); } } } diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 0538e847049..955638a7f7d 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -31,6 +31,7 @@ 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; @@ -219,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 0543e25a4c3..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; @@ -35,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) } @@ -82,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); @@ -104,44 +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") + } } - 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(_addr, 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); - }, - Ok(ScriptMsg::RunnableMsg(runnable)) => { - runnable.handler() - }, - Ok(ScriptMsg::WorkerPostMessage(addr, data, nbytes)) => { - Worker::handle_message(addr, data, nbytes); - }, - Ok(ScriptMsg::RefcountCleanup(addr)) => { - LiveDOMReferences::cleanup(js_context.ptr, 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, } } @@ -149,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(); @@ -162,8 +245,8 @@ impl<'a> DedicatedWorkerGlobalScopeMethods for JSRef<'a, DedicatedWorkerGlobalSc return Err(DataClone); } - let ScriptChan(ref sender) = self.parent_sender; - sender.send(ScriptMsg::WorkerPostMessage(self.worker.clone(), data, nbytes)); + let worker = self.worker.borrow().as_ref().unwrap().clone(); + self.parent_sender.send(ScriptMsg::WorkerPostMessage(worker, data, nbytes)); Ok(()) } 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 e6708954a41..d6e4391cbfd 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -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 = Trusted::new(global.get_cx(), *worker, global.script_chan().clone()); + 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)) @@ -112,9 +112,8 @@ impl<'a> WorkerMethods for JSRef<'a, Worker> { return Err(DataClone); } - let addr = Trusted::new(cx, self, self.global.root().root_ref().script_chan().clone()); - let ScriptChan(ref sender) = self.sender; - sender.send(ScriptMsg::DOMMessage(addr, 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 c69d8e805a8..b50a5c4330a 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -117,7 +117,7 @@ impl XHRProgress { enum SyncOrAsync<'a> { Sync(JSRef<'a, XMLHttpRequest>), - Async(TrustedXHRAddress, &'a ScriptChan) + Async(TrustedXHRAddress, Box<ScriptChan+Send>) } enum TerminateReason { @@ -214,9 +214,8 @@ impl XMLHttpRequest { SyncOrAsync::Sync(xhr) => { xhr.process_partial_response(msg); }, - SyncOrAsync::Async(ref addr, script_chan) => { - let ScriptChan(ref chan) = *script_chan; - chan.send(ScriptMsg::RunnableMsg(box XHRProgressHandler::new(addr.clone(), msg))); + SyncOrAsync::Async(ref addr, ref script_chan) => { + script_chan.send(ScriptMsg::RunnableMsg(box XHRProgressHandler::new(addr.clone(), msg))); } } } @@ -614,16 +613,14 @@ 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 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, diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 0a202752336..ae27dc671c7 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -64,7 +64,7 @@ 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}; @@ -113,7 +113,7 @@ pub enum ScriptMsg { ExitWindow(PipelineId), /// Message sent through Worker.postMessage (only dispatched to /// DedicatedWorkerGlobalScope). - DOMMessage(TrustedWorkerAddress, *mut u64, size_t), + DOMMessage(*mut u64, size_t), /// Posts a message to the Worker object (dispatched to all tasks). WorkerPostMessage(TrustedWorkerAddress, *mut u64, size_t), /// Generic message that encapsulates event handling. @@ -122,17 +122,35 @@ pub enum ScriptMsg { 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)) } } @@ -167,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, @@ -282,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, @@ -314,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, @@ -583,7 +601,7 @@ impl ScriptTask { ScriptMsg::RunnableMsg(runnable) => runnable.handler(), ScriptMsg::RefcountCleanup(addr) => - LiveDOMReferences::cleanup(self.js_context.borrow().as_ref().unwrap().ptr, 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; } |