diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index 9699262a874..a605e744ead 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -268,15 +268,12 @@ impl ServiceWorkerGlobalScope { } = scope_things; let serialized_worker_url = script_url.to_string(); - let origin = GlobalScope::current() - .expect("No current global object") - .origin() - .immutable() - .clone(); + let origin = scope_url.origin(); thread::Builder::new() .name(format!("ServiceWorker for {}", serialized_worker_url)) .spawn(move || { thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER); + let runtime = new_rt_and_cx(None); let roots = RootCollection::new(); let _stack_roots = ThreadLocalStackRoots::new(&roots); @@ -298,34 +295,19 @@ impl ServiceWorkerGlobalScope { .referrer_policy(referrer_policy) .origin(origin); - let (url, source) = match load_whole_resource( - request, - &init.resource_threads.sender(), - &GlobalScope::current().expect("No current global object"), - ) { - Err(_) => { - println!("error loading script {}", serialized_worker_url); - return; - }, - Ok((metadata, bytes)) => { - (metadata.final_url, String::from_utf8(bytes).unwrap()) - }, - }; - - let runtime = new_rt_and_cx(None); - - let (devtools_mpsc_chan, devtools_mpsc_port) = unbounded(); - ROUTER - .route_ipc_receiver_to_crossbeam_sender(devtools_receiver, devtools_mpsc_chan); - // Service workers are time limited // https://w3c.github.io/ServiceWorker/#service-worker-lifetime let sw_lifetime_timeout = pref!(dom.serviceworker.timeout_seconds) as u64; let time_out_port = after(Duration::new(sw_lifetime_timeout, 0)); + let (devtools_mpsc_chan, devtools_mpsc_port) = unbounded(); + ROUTER + .route_ipc_receiver_to_crossbeam_sender(devtools_receiver, devtools_mpsc_chan); + + let resource_threads_sender = init.resource_threads.sender(); let global = ServiceWorkerGlobalScope::new( init, - url, + script_url, devtools_mpsc_port, runtime, own_sender, @@ -334,6 +316,19 @@ impl ServiceWorkerGlobalScope { swmanager_sender, scope_url, ); + + let (_url, source) = + match load_whole_resource(request, &resource_threads_sender, &*global.upcast()) + { + Err(_) => { + println!("error loading script {}", serialized_worker_url); + return; + }, + Ok((metadata, bytes)) => { + (metadata.final_url, String::from_utf8(bytes).unwrap()) + }, + }; + let scope = global.upcast::(); unsafe { @@ -356,7 +351,7 @@ impl ServiceWorkerGlobalScope { // until the event loop is destroyed, // which happens after the closing flag is set to true, // or until the worker has run beyond its allocated time. - while !scope.is_closing() || !global.has_timed_out() { + while !scope.is_closing() && !global.has_timed_out() { run_worker_event_loop(&*global, None); } }, @@ -364,6 +359,7 @@ impl ServiceWorkerGlobalScope { scope.script_chan(), CommonScriptMsg::CollectReports, ); + scope.clear_js_runtime(); }) .expect("Thread spawning failed"); } @@ -390,15 +386,10 @@ impl ServiceWorkerGlobalScope { } fn has_timed_out(&self) -> bool { - // Note: this should be included in the `select` inside `run_worker_event_loop`, - // otherwise a block on the select can prevent the timeout. - if self.time_out_port.try_recv().is_ok() { - let _ = self - .swmanager_sender - .send(ServiceWorkerMsg::Timeout(self.scope_url.clone())); - return true; - } - false + // TODO: https://w3c.github.io/ServiceWorker/#service-worker-lifetime + // Since we don't have a shutdown mechanism yet, see #26548 + // immediately stop the event-loop after executing the initial script. + true } fn handle_script_event(&self, msg: ServiceWorkerScriptMsg) { diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 6e9490cb2c7..8d54c3f7da4 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -100,7 +100,7 @@ pub struct WorkerGlobalScope { #[ignore_malloc_size_of = "Arc"] closing: Option>, #[ignore_malloc_size_of = "Defined in js"] - runtime: Runtime, + runtime: DomRefCell>, location: MutNullableDom, navigator: MutNullableDom, @@ -151,7 +151,7 @@ impl WorkerGlobalScope { worker_type, worker_url: DomRefCell::new(worker_url), closing, - runtime, + runtime: DomRefCell::new(Some(runtime)), location: Default::default(), navigator: Default::default(), from_devtools_sender: init.from_devtools_sender, @@ -161,8 +161,17 @@ impl WorkerGlobalScope { } } + pub fn clear_js_runtime(&self) { + let runtime = self.runtime.borrow_mut().take(); + drop(runtime); + } + pub fn runtime_handle(&self) -> ParentRuntime { - self.runtime.prepare_for_new_child() + self.runtime + .borrow() + .as_ref() + .unwrap() + .prepare_for_new_child() } pub fn from_devtools_sender(&self) -> Option> { @@ -175,7 +184,7 @@ impl WorkerGlobalScope { #[allow(unsafe_code)] pub fn get_cx(&self) -> JSContext { - unsafe { JSContext::from_ptr(self.runtime.cx()) } + unsafe { JSContext::from_ptr(self.runtime.borrow().as_ref().unwrap().cx()) } } pub fn is_closing(&self) -> bool { @@ -235,7 +244,7 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope { }; } - rooted!(in(self.runtime.cx()) let mut rval = UndefinedValue()); + rooted!(in(self.runtime.borrow().as_ref().unwrap().cx()) let mut rval = UndefinedValue()); for url in urls { let global_scope = self.upcast::(); let request = NetRequestInit::new(url.clone()) @@ -256,7 +265,7 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope { Ok((metadata, bytes)) => (metadata.final_url, String::from_utf8(bytes).unwrap()), }; - let result = self.runtime.evaluate_script( + let result = self.runtime.borrow().as_ref().unwrap().evaluate_script( self.reflector().get_jsobject(), &source, url.as_str(), @@ -401,8 +410,9 @@ impl WorkerGlobalScope { #[allow(unsafe_code)] pub fn execute_script(&self, source: DOMString) { let _aes = AutoEntryScript::new(self.upcast()); - rooted!(in(self.runtime.cx()) let mut rval = UndefinedValue()); - match self.runtime.evaluate_script( + let cx = self.runtime.borrow().as_ref().unwrap().cx(); + rooted!(in(cx) let mut rval = UndefinedValue()); + match self.runtime.borrow().as_ref().unwrap().evaluate_script( self.reflector().get_jsobject(), &source, self.worker_url.borrow().as_str(), @@ -419,7 +429,7 @@ impl WorkerGlobalScope { println!("evaluate_script failed"); unsafe { let ar = enter_realm(&*self); - report_pending_exception(self.runtime.cx(), true, InRealm::Entered(&ar)); + report_pending_exception(cx, true, InRealm::Entered(&ar)); } } }, diff --git a/components/script/serviceworker_manager.rs b/components/script/serviceworker_manager.rs index ed5766c8445..7c0484144d9 100644 --- a/components/script/serviceworker_manager.rs +++ b/components/script/serviceworker_manager.rs @@ -212,7 +212,9 @@ impl ServiceWorkerManager { fn handle_message_from_constellation(&mut self, msg: ServiceWorkerMsg) -> bool { match msg { - ServiceWorkerMsg::Timeout(scope) => {}, + ServiceWorkerMsg::Timeout(_scope) => { + // TODO: https://w3c.github.io/ServiceWorker/#terminate-service-worker + }, ServiceWorkerMsg::ForwardDOMMessage(msg, scope_url) => { if let Some(registration) = self.registrations.get_mut(&scope_url) { if let Some(ref worker) = registration.active_worker {