diff options
Diffstat (limited to 'components/script/dom/worker.rs')
-rw-r--r-- | components/script/dom/worker.rs | 299 |
1 files changed, 159 insertions, 140 deletions
diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index 1fb354189e3..563a04679ea 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -1,37 +1,42 @@ /* 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 devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg}; -use dom::abstractworker::{SharedRt, SimpleWorkerErrorHandler}; -use dom::abstractworker::WorkerScriptMsg; -use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; -use dom::bindings::codegen::Bindings::WorkerBinding; -use dom::bindings::codegen::Bindings::WorkerBinding::WorkerMethods; -use dom::bindings::error::{Error, ErrorResult, Fallible, ErrorInfo}; -use dom::bindings::inheritance::Castable; -use dom::bindings::js::Root; -use dom::bindings::refcounted::Trusted; -use dom::bindings::reflector::{DomObject, reflect_dom_object}; -use dom::bindings::str::DOMString; -use dom::bindings::structuredclone::StructuredCloneData; -use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope; -use dom::errorevent::ErrorEvent; -use dom::event::{Event, EventBubbles, EventCancelable, EventStatus}; -use dom::eventtarget::EventTarget; -use dom::globalscope::GlobalScope; -use dom::messageevent::MessageEvent; -use dom::workerglobalscope::prepare_workerscope_init; + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::abstractworker::SimpleWorkerErrorHandler; +use crate::dom::abstractworker::WorkerScriptMsg; +use crate::dom::bindings::codegen::Bindings::MessagePortBinding::PostMessageOptions; +use crate::dom::bindings::codegen::Bindings::WorkerBinding::{WorkerMethods, WorkerOptions}; +use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::refcounted::Trusted; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::str::USVString; +use crate::dom::bindings::structuredclone; +use crate::dom::bindings::trace::RootedTraceableBox; +use crate::dom::dedicatedworkerglobalscope::{ + DedicatedWorkerGlobalScope, DedicatedWorkerScriptMsg, +}; +use crate::dom::eventtarget::EventTarget; +use crate::dom::globalscope::GlobalScope; +use crate::dom::messageevent::MessageEvent; +use crate::dom::window::Window; +use crate::dom::workerglobalscope::prepare_workerscope_init; +use crate::realms::enter_realm; +use crate::script_runtime::JSContext; +use crate::task::TaskOnce; +use crossbeam_channel::{unbounded, Sender}; +use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg, WorkerId}; use dom_struct::dom_struct; use ipc_channel::ipc; -use js::jsapi::{HandleValue, JSAutoCompartment, JSContext, NullHandleValue}; +use js::jsapi::{Heap, JSObject, JS_RequestInterruptCallback}; use js::jsval::UndefinedValue; -use script_thread::Runnable; -use script_traits::WorkerScriptLoadOrigin; +use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue}; +use script_traits::{StructuredSerializedData, WorkerScriptLoadOrigin}; use std::cell::Cell; -use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::mpsc::{Sender, channel}; +use std::sync::Arc; +use uuid::Uuid; pub type TrustedWorkerAddress = Trusted<Worker>; @@ -39,46 +44,47 @@ pub type TrustedWorkerAddress = Trusted<Worker>; #[dom_struct] pub struct Worker { eventtarget: EventTarget, - #[ignore_heap_size_of = "Defined in std"] + #[ignore_malloc_size_of = "Defined in std"] /// Sender to the Receiver associated with the DedicatedWorkerGlobalScope /// this Worker created. - sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>, + sender: Sender<DedicatedWorkerScriptMsg>, + #[ignore_malloc_size_of = "Arc"] closing: Arc<AtomicBool>, - #[ignore_heap_size_of = "Defined in rust-mozjs"] - runtime: Arc<Mutex<Option<SharedRt>>>, terminated: Cell<bool>, } impl Worker { - fn new_inherited(sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>, - closing: Arc<AtomicBool>) -> Worker { + fn new_inherited(sender: Sender<DedicatedWorkerScriptMsg>, closing: Arc<AtomicBool>) -> Worker { Worker { eventtarget: EventTarget::new_inherited(), sender: sender, closing: closing, - runtime: Arc::new(Mutex::new(None)), terminated: Cell::new(false), } } - pub fn new(global: &GlobalScope, - sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>, - closing: Arc<AtomicBool>) -> Root<Worker> { - reflect_dom_object(box Worker::new_inherited(sender, closing), - global, - WorkerBinding::Wrap) + pub fn new( + global: &GlobalScope, + sender: Sender<DedicatedWorkerScriptMsg>, + closing: Arc<AtomicBool>, + ) -> DomRoot<Worker> { + reflect_dom_object(Box::new(Worker::new_inherited(sender, closing)), global) } // https://html.spec.whatwg.org/multipage/#dom-worker - #[allow(unsafe_code)] - pub fn Constructor(global: &GlobalScope, script_url: DOMString) -> Fallible<Root<Worker>> { + #[allow(unsafe_code, non_snake_case)] + pub fn Constructor( + global: &GlobalScope, + script_url: USVString, + worker_options: &WorkerOptions, + ) -> Fallible<DomRoot<Worker>> { // Step 2-4. let worker_url = match global.api_base_url().join(&script_url) { Ok(url) => url, Err(_) => return Err(Error::Syntax), }; - let (sender, receiver) = channel(); + let (sender, receiver) = unbounded(); let closing = Arc::new(AtomicBool::new(false)); let worker = Worker::new(global, sender.clone(), closing.clone()); let worker_ref = Trusted::new(&*worker); @@ -86,42 +92,74 @@ impl Worker { let worker_load_origin = WorkerScriptLoadOrigin { referrer_url: None, referrer_policy: None, - pipeline_id: Some(global.pipeline_id()), + pipeline_id: global.pipeline_id(), }; + let browsing_context = global + .downcast::<Window>() + .map(|w| w.window_proxy().browsing_context_id()) + .or_else(|| { + global + .downcast::<DedicatedWorkerGlobalScope>() + .and_then(|w| w.browsing_context()) + }); + let (devtools_sender, devtools_receiver) = ipc::channel().unwrap(); - let worker_id = global.get_next_worker_id(); + let worker_id = WorkerId(Uuid::new_v4()); if let Some(ref chan) = global.devtools_chan() { let pipeline_id = global.pipeline_id(); - let title = format!("Worker for {}", worker_url); + let title = format!("Worker for {}", worker_url); + if let Some(browsing_context) = browsing_context { let page_info = DevtoolsPageInfo { title: title, url: worker_url.clone(), }; - let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal((pipeline_id, Some(worker_id)), - devtools_sender.clone(), - page_info)); + let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal( + (browsing_context, pipeline_id, Some(worker_id)), + devtools_sender.clone(), + page_info, + )); + } } - let init = prepare_workerscope_init(global, Some(devtools_sender)); - - DedicatedWorkerGlobalScope::run_worker_scope( - init, worker_url, devtools_receiver, worker.runtime.clone(), worker_ref, - global.script_chan(), sender, receiver, worker_load_origin, closing); + let init = prepare_workerscope_init(global, Some(devtools_sender), Some(worker_id)); + + let (control_sender, control_receiver) = unbounded(); + let (context_sender, context_receiver) = unbounded(); + + let join_handle = DedicatedWorkerGlobalScope::run_worker_scope( + init, + worker_url, + devtools_receiver, + worker_ref, + global.script_chan(), + sender, + receiver, + worker_load_origin, + String::from(&*worker_options.name), + worker_options.type_, + closing.clone(), + global.image_cache(), + browsing_context, + global.wgpu_id_hub(), + control_receiver, + context_sender, + ); + + let context = context_receiver + .recv() + .expect("Couldn't receive a context for worker."); + + global.track_worker(closing, join_handle, control_sender, context); Ok(worker) } - pub fn is_closing(&self) -> bool { - self.closing.load(Ordering::SeqCst) - } - pub fn is_terminated(&self) -> bool { self.terminated.get() } - pub fn handle_message(address: TrustedWorkerAddress, - data: StructuredCloneData) { + pub fn handle_message(address: TrustedWorkerAddress, data: StructuredSerializedData) { let worker = address.root(); if worker.is_terminated() { @@ -130,10 +168,14 @@ impl Worker { let global = worker.global(); let target = worker.upcast(); - let _ac = JSAutoCompartment::new(global.get_cx(), target.reflector().get_jsobject().get()); - rooted!(in(global.get_cx()) let mut message = UndefinedValue()); - data.read(&global, message.handle_mut()); - MessageEvent::dispatch_jsval(target, &global, message.handle()); + let _ac = enter_realm(target); + rooted!(in(*global.get_cx()) let mut message = UndefinedValue()); + if let Ok(ports) = structuredclone::read(&global, data, message.handle_mut()) { + MessageEvent::dispatch_jsval(target, &global, message.handle(), None, None, ports); + } else { + // Step 4 of the "port post message steps" of the implicit messageport, fire messageerror. + MessageEvent::dispatch_error(target, &global); + } } pub fn dispatch_simple_error(address: TrustedWorkerAddress) { @@ -141,41 +183,59 @@ impl Worker { worker.upcast().fire_event(atom!("error")); } - #[allow(unsafe_code)] - fn dispatch_error(&self, error_info: ErrorInfo) { - let global = self.global(); - let event = ErrorEvent::new(&global, - atom!("error"), - EventBubbles::DoesNotBubble, - EventCancelable::Cancelable, - error_info.message.as_str().into(), - error_info.filename.as_str().into(), - error_info.lineno, - error_info.column, - unsafe { NullHandleValue }); - - let event_status = event.upcast::<Event>().fire(self.upcast::<EventTarget>()); - if event_status == EventStatus::Canceled { - return; - } + /// https://html.spec.whatwg.org/multipage/#dom-dedicatedworkerglobalscope-postmessage + fn post_message_impl( + &self, + cx: JSContext, + message: HandleValue, + transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>, + ) -> ErrorResult { + let data = structuredclone::write(cx, message, Some(transfer))?; + let address = Trusted::new(self); - global.report_an_error(error_info, unsafe { NullHandleValue }); + // NOTE: step 9 of https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage + // indicates that a nonexistent communication channel should result in a silent error. + let _ = self.sender.send(DedicatedWorkerScriptMsg::CommonWorker( + address, + WorkerScriptMsg::DOMMessage { + origin: self.global().origin().immutable().clone(), + data, + }, + )); + Ok(()) } } impl WorkerMethods for Worker { - #[allow(unsafe_code)] - // https://html.spec.whatwg.org/multipage/#dom-worker-postmessage - unsafe fn PostMessage(&self, cx: *mut JSContext, message: HandleValue) -> ErrorResult { - let data = try!(StructuredCloneData::write(cx, message)); - let address = Trusted::new(self); + /// https://html.spec.whatwg.org/multipage/#dom-worker-postmessage + fn PostMessage( + &self, + cx: JSContext, + message: HandleValue, + transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>, + ) -> ErrorResult { + self.post_message_impl(cx, message, transfer) + } - // NOTE: step 9 of https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage - // indicates that a nonexistent communication channel should result in a silent error. - let _ = self.sender.send((address, WorkerScriptMsg::DOMMessage(data))); - Ok(()) + /// https://html.spec.whatwg.org/multipage/#dom-worker-postmessage + fn PostMessage_( + &self, + cx: JSContext, + message: HandleValue, + options: RootedTraceableBox<PostMessageOptions>, + ) -> ErrorResult { + let mut rooted = CustomAutoRooter::new( + options + .transfer + .iter() + .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get()) + .collect(), + ); + let guard = CustomAutoRooterGuard::new(*cx, &mut rooted); + self.post_message_impl(cx, message, guard) } + #[allow(unsafe_code)] // https://html.spec.whatwg.org/multipage/#terminate-a-worker fn Terminate(&self) { // Step 1 @@ -187,64 +247,23 @@ impl WorkerMethods for Worker { self.terminated.set(true); // Step 3 - if let Some(runtime) = *self.runtime.lock().unwrap() { - runtime.request_interrupt(); - } + let cx = self.global().get_cx(); + unsafe { JS_RequestInterruptCallback(*cx) }; } // https://html.spec.whatwg.org/multipage/#handler-worker-onmessage event_handler!(message, GetOnmessage, SetOnmessage); + // https://html.spec.whatwg.org/multipage/#handler-worker-onmessageerror + event_handler!(messageerror, GetOnmessageerror, SetOnmessageerror); + // https://html.spec.whatwg.org/multipage/#handler-workerglobalscope-onerror event_handler!(error, GetOnerror, SetOnerror); } -pub struct WorkerMessageHandler { - addr: TrustedWorkerAddress, - data: StructuredCloneData, -} - -impl WorkerMessageHandler { - pub fn new(addr: TrustedWorkerAddress, data: StructuredCloneData) -> WorkerMessageHandler { - WorkerMessageHandler { - addr: addr, - data: data, - } - } -} - -impl Runnable for WorkerMessageHandler { - fn handler(self: Box<WorkerMessageHandler>) { - let this = *self; - Worker::handle_message(this.addr, this.data); - } -} - -impl Runnable for SimpleWorkerErrorHandler<Worker> { +impl TaskOnce for SimpleWorkerErrorHandler<Worker> { #[allow(unrooted_must_root)] - fn handler(self: Box<SimpleWorkerErrorHandler<Worker>>) { - let this = *self; - Worker::dispatch_simple_error(this.addr); - } -} - -pub struct WorkerErrorHandler { - address: Trusted<Worker>, - error_info: ErrorInfo, -} - -impl WorkerErrorHandler { - pub fn new(address: Trusted<Worker>, error_info: ErrorInfo) -> WorkerErrorHandler { - WorkerErrorHandler { - address: address, - error_info: error_info, - } - } -} - -impl Runnable for WorkerErrorHandler { - fn handler(self: Box<Self>) { - let this = *self; - this.address.root().dispatch_error(this.error_info); + fn run_once(self) { + Worker::dispatch_simple_error(self.addr); } } |