diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index 9c4949027b9..8ea89562f39 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -247,7 +247,7 @@ impl DedicatedWorkerGlobalScope { global.handle_event(event); // Step 6 let _ar = AutoWorkerReset::new(&global, worker.clone()); - global.upcast::().perform_a_microtask_checkpoint(); + global.upcast::().perform_a_microtask_checkpoint(); } }, reporter_name, parent_sender, CommonScriptMsg::CollectReports); }).expect("Thread spawning failed"); diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs index a0eeb7d4a6e..6b0745a72e5 100644 --- a/components/script/dom/dissimilaroriginwindow.rs +++ b/components/script/dom/dissimilaroriginwindow.rs @@ -45,29 +45,36 @@ pub struct DissimilarOriginWindow { impl DissimilarOriginWindow { #[allow(unsafe_code)] - pub fn new(global_to_clone_from: &GlobalScope, window_proxy: &WindowProxy) -> Root { + pub fn new( + global_to_clone_from: &GlobalScope, + window_proxy: &WindowProxy, + ) -> Root { let cx = global_to_clone_from.get_cx(); // Any timer events fired on this window are ignored. let (timer_event_chan, _) = ipc::channel().unwrap(); - let win = box DissimilarOriginWindow { - globalscope: GlobalScope::new_inherited(PipelineId::new(), - global_to_clone_from.devtools_chan().cloned(), - global_to_clone_from.mem_profiler_chan().clone(), - global_to_clone_from.time_profiler_chan().clone(), - global_to_clone_from.script_to_constellation_chan().clone(), - global_to_clone_from.scheduler_chan().clone(), - global_to_clone_from.resource_threads().clone(), - timer_event_chan, - global_to_clone_from.origin().clone()), + let win = box Self { + globalscope: GlobalScope::new_inherited( + PipelineId::new(), + global_to_clone_from.devtools_chan().cloned(), + global_to_clone_from.mem_profiler_chan().clone(), + global_to_clone_from.time_profiler_chan().clone(), + global_to_clone_from.script_to_constellation_chan().clone(), + global_to_clone_from.scheduler_chan().clone(), + global_to_clone_from.resource_threads().clone(), + timer_event_chan, + global_to_clone_from.origin().clone(), + // FIXME(nox): The microtask queue is probably not important + // here, but this whole DOM interface is a hack anyway. + global_to_clone_from.microtask_queue().clone(), + ), window_proxy: JS::from_ref(window_proxy), - location: MutNullableJS::new(None), + location: Default::default(), }; unsafe { DissimilarOriginWindowBinding::Wrap(cx, win) } } - #[allow(dead_code)] pub fn origin(&self) -> &MutableOrigin { - self.globalscope.origin() + self.upcast::().origin() } } diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index e340b90e67e..681953defdd 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -33,7 +33,7 @@ use js::jsapi::{JS_GetObjectRuntime, MutableHandleValue}; use js::panic::maybe_resume_unwind; use js::rust::{CompileOptionsWrapper, Runtime, get_object_class}; use libc; -use microtask::Microtask; +use microtask::{Microtask, MicrotaskQueue}; use msg::constellation_msg::PipelineId; use net_traits::{CoreResourceThread, ResourceThreads, IpcSend}; use profile_traits::{mem, time}; @@ -46,6 +46,7 @@ use std::cell::Cell; use std::collections::HashMap; use std::collections::hash_map::Entry; use std::ffi::CString; +use std::rc::Rc; use task_source::file_reading::FileReadingTaskSource; use task_source::networking::NetworkingTaskSource; use task_source::performance_timeline::PerformanceTimelineTaskSource; @@ -99,36 +100,47 @@ pub struct GlobalScope { /// The origin of the globalscope origin: MutableOrigin, + + /// The microtask queue associated with this global. + /// + /// It is refcounted because windows in the same script thread share the + /// same microtask queue. + /// + /// https://html.spec.whatwg.org/multipage/#microtask-queue + #[ignore_heap_size_of = "Rc is hard"] + microtask_queue: Rc, } impl GlobalScope { pub fn new_inherited( - pipeline_id: PipelineId, - devtools_chan: Option>, - mem_profiler_chan: mem::ProfilerChan, - time_profiler_chan: time::ProfilerChan, - script_to_constellation_chan: ScriptToConstellationChan, - scheduler_chan: IpcSender, - resource_threads: ResourceThreads, - timer_event_chan: IpcSender, - origin: MutableOrigin) - -> Self { - GlobalScope { + pipeline_id: PipelineId, + devtools_chan: Option>, + mem_profiler_chan: mem::ProfilerChan, + time_profiler_chan: time::ProfilerChan, + script_to_constellation_chan: ScriptToConstellationChan, + scheduler_chan: IpcSender, + resource_threads: ResourceThreads, + timer_event_chan: IpcSender, + origin: MutableOrigin, + microtask_queue: Rc, + ) -> Self { + Self { eventtarget: EventTarget::new_inherited(), crypto: Default::default(), next_worker_id: Cell::new(WorkerId(0)), - pipeline_id: pipeline_id, + pipeline_id, devtools_wants_updates: Default::default(), console_timers: DOMRefCell::new(Default::default()), - devtools_chan: devtools_chan, - mem_profiler_chan: mem_profiler_chan, - time_profiler_chan: time_profiler_chan, - script_to_constellation_chan: script_to_constellation_chan, + devtools_chan, + mem_profiler_chan, + time_profiler_chan, + script_to_constellation_chan, scheduler_chan: scheduler_chan.clone(), in_error_reporting_mode: Default::default(), - resource_threads: resource_threads, + resource_threads, timers: OneshotTimers::new(timer_event_chan, scheduler_chan), - origin: origin, + origin, + microtask_queue, } } @@ -479,30 +491,12 @@ impl GlobalScope { /// Perform a microtask checkpoint. pub fn perform_a_microtask_checkpoint(&self) { - if self.is::() { - return ScriptThread::invoke_perform_a_microtask_checkpoint(); - } - if let Some(worker) = self.downcast::() { - return worker.perform_a_microtask_checkpoint(); - } - if let Some(worker) = self.downcast::() { - return worker.perform_a_microtask_checkpoint(); - } - unreachable!(); + self.microtask_queue.checkpoint(|_| Some(Root::from_ref(self))); } /// Enqueue a microtask for subsequent execution. pub fn enqueue_microtask(&self, job: Microtask) { - if self.is::() { - return ScriptThread::enqueue_microtask(job); - } - if let Some(worker) = self.downcast::() { - return worker.enqueue_microtask(job); - } - if let Some(worker) = self.downcast::() { - return worker.enqueue_microtask(job); - } - unreachable!(); + self.microtask_queue.enqueue(job); } /// Create a new sender/receiver pair that can be used to implement an on-demand @@ -518,6 +512,11 @@ impl GlobalScope { unreachable!(); } + /// Returns the microtask queue of this global. + pub fn microtask_queue(&self) -> &Rc { + &self.microtask_queue + } + /// Process a single event as if it were the next event /// in the thread queue for this global scope. pub fn process_event(&self, msg: CommonScriptMsg) { diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index e16707a77c6..de0cbb2e8af 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -219,7 +219,7 @@ impl ServiceWorkerGlobalScope { break; } // Step 6 - global.upcast::().perform_a_microtask_checkpoint(); + global.upcast::().perform_a_microtask_checkpoint(); } }, reporter_name, scope.script_chan(), CommonScriptMsg::CollectReports); }).expect("Thread spawning failed"); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 114d5ca3a0d..51d58eb77dc 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -59,6 +59,7 @@ use js::jsapi::{JS_GC, JS_GetRuntime}; use js::jsval::UndefinedValue; use js::rust::Runtime; use layout_image::fetch_image_for_layout; +use microtask::MicrotaskQueue; use msg::constellation_msg::{FrameType, PipelineId}; use net_traits::{ResourceThreads, ReferrerPolicy}; use net_traits::image_cache::{ImageCache, ImageResponder, ImageResponse}; @@ -1789,65 +1790,68 @@ impl Window { impl Window { #[allow(unsafe_code)] - pub fn new(runtime: Rc, - script_chan: MainThreadScriptChan, - dom_task_source: DOMManipulationTaskSource, - user_task_source: UserInteractionTaskSource, - network_task_source: NetworkingTaskSource, - history_task_source: HistoryTraversalTaskSource, - file_task_source: FileReadingTaskSource, - performance_timeline_task_source: PerformanceTimelineTaskSource, - image_cache_chan: Sender, - image_cache: Arc, - resource_threads: ResourceThreads, - bluetooth_thread: IpcSender, - mem_profiler_chan: MemProfilerChan, - time_profiler_chan: TimeProfilerChan, - devtools_chan: Option>, - constellation_chan: ScriptToConstellationChan, - control_chan: IpcSender, - scheduler_chan: IpcSender, - timer_event_chan: IpcSender, - layout_chan: Sender, - id: PipelineId, - parent_info: Option<(PipelineId, FrameType)>, - window_size: Option, - origin: MutableOrigin, - navigation_start: u64, - navigation_start_precise: f64, - webgl_chan: WebGLChan, - webvr_chan: Option>) - -> Root { + pub fn new( + runtime: Rc, + script_chan: MainThreadScriptChan, + dom_manipulation_task_source: DOMManipulationTaskSource, + user_interaction_task_source: UserInteractionTaskSource, + networking_task_source: NetworkingTaskSource, + history_traversal_task_source: HistoryTraversalTaskSource, + file_reading_task_source: FileReadingTaskSource, + performance_timeline_task_source: PerformanceTimelineTaskSource, + image_cache_chan: Sender, + image_cache: Arc, + resource_threads: ResourceThreads, + bluetooth_thread: IpcSender, + mem_profiler_chan: MemProfilerChan, + time_profiler_chan: TimeProfilerChan, + devtools_chan: Option>, + constellation_chan: ScriptToConstellationChan, + control_chan: IpcSender, + scheduler_chan: IpcSender, + timer_event_chan: IpcSender, + layout_chan: Sender, + pipelineid: PipelineId, + parent_info: Option<(PipelineId, FrameType)>, + window_size: Option, + origin: MutableOrigin, + navigation_start: u64, + navigation_start_precise: f64, + webgl_chan: WebGLChan, + webvr_chan: Option>, + microtask_queue: Rc, + ) -> Root { let layout_rpc: Box = { let (rpc_send, rpc_recv) = channel(); layout_chan.send(Msg::GetRPC(rpc_send)).unwrap(); rpc_recv.recv().unwrap() }; let error_reporter = CSSErrorReporter { - pipelineid: id, + pipelineid, script_chan: Arc::new(Mutex::new(control_chan)), }; - let win = box Window { - globalscope: - GlobalScope::new_inherited( - id, - devtools_chan, - mem_profiler_chan, - time_profiler_chan, - constellation_chan, - scheduler_chan, - resource_threads, - timer_event_chan, - origin), - script_chan: script_chan, - dom_manipulation_task_source: dom_task_source, - user_interaction_task_source: user_task_source, - networking_task_source: network_task_source, - history_traversal_task_source: history_task_source, - file_reading_task_source: file_task_source, + let win = box Self { + globalscope: GlobalScope::new_inherited( + pipelineid, + devtools_chan, + mem_profiler_chan, + time_profiler_chan, + constellation_chan, + scheduler_chan, + resource_threads, + timer_event_chan, + origin, + microtask_queue, + ), + script_chan, + dom_manipulation_task_source, + user_interaction_task_source, + networking_task_source, + history_traversal_task_source, + file_reading_task_source, performance_timeline_task_source, - image_cache_chan: image_cache_chan, - image_cache: image_cache.clone(), + image_cache_chan, + image_cache, navigator: Default::default(), history: Default::default(), custom_element_registry: Default::default(), @@ -1860,34 +1864,33 @@ impl Window { session_storage: Default::default(), local_storage: Default::default(), status: DOMRefCell::new(DOMString::new()), - parent_info: parent_info, + parent_info, dom_static: GlobalStaticData::new(), js_runtime: DOMRefCell::new(Some(runtime.clone())), - bluetooth_thread: bluetooth_thread, + bluetooth_thread, bluetooth_extra_permission_data: BluetoothExtraPermissionData::new(), page_clip_rect: Cell::new(max_rect()), - resize_event: Cell::new(None), - layout_chan: layout_chan, - layout_rpc: layout_rpc, + resize_event: Default::default(), + layout_chan, + layout_rpc, window_size: Cell::new(window_size), current_viewport: Cell::new(Rect::zero()), suppress_reflow: Cell::new(true), - pending_reflow_count: Cell::new(0), + pending_reflow_count: Default::default(), current_state: Cell::new(WindowState::Alive), - - devtools_marker_sender: DOMRefCell::new(None), - devtools_markers: DOMRefCell::new(HashSet::new()), - webdriver_script_chan: DOMRefCell::new(None), + devtools_marker_sender: Default::default(), + devtools_markers: Default::default(), + webdriver_script_chan: Default::default(), ignore_further_async_events: Default::default(), - error_reporter: error_reporter, - scroll_offsets: DOMRefCell::new(HashMap::new()), + error_reporter, + scroll_offsets: Default::default(), media_query_lists: WeakMediaQueryListVec::new(), test_runner: Default::default(), - webgl_chan: webgl_chan, - webvr_chan: webvr_chan, - permission_state_invocation_results: DOMRefCell::new(HashMap::new()), - pending_layout_images: DOMRefCell::new(HashMap::new()), - unminified_js_dir: DOMRefCell::new(None), + webgl_chan, + webvr_chan, + permission_state_invocation_results: Default::default(), + pending_layout_images: Default::default(), + unminified_js_dir: Default::default(), test_worklet: Default::default(), paint_worklet: Default::default(), }; diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index cb199125d16..ebcebef6c27 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -30,7 +30,6 @@ use js::jsapi::{HandleValue, JSAutoCompartment, JSContext, JSRuntime}; use js::jsval::UndefinedValue; use js::panic::maybe_resume_unwind; use js::rust::Runtime; -use microtask::{MicrotaskQueue, Microtask}; use net_traits::{IpcSend, load_whole_resource}; use net_traits::request::{CredentialsMode, Destination, RequestInit as NetRequestInit, Type as RequestType}; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort}; @@ -91,41 +90,40 @@ pub struct WorkerGlobalScope { /// `IpcSender` doesn't exist from_devtools_receiver: Receiver, - microtask_queue: MicrotaskQueue, - navigation_start_precise: f64, performance: MutNullableJS, } impl WorkerGlobalScope { - pub fn new_inherited(init: WorkerGlobalScopeInit, - worker_url: ServoUrl, - runtime: Runtime, - from_devtools_receiver: Receiver, - timer_event_chan: IpcSender, - closing: Option>) - -> WorkerGlobalScope { - WorkerGlobalScope { - globalscope: - GlobalScope::new_inherited( - init.pipeline_id, - init.to_devtools_sender, - init.mem_profiler_chan, - init.time_profiler_chan, - init.script_to_constellation_chan, - init.scheduler_chan, - init.resource_threads, - timer_event_chan, - MutableOrigin::new(init.origin)), + pub fn new_inherited( + init: WorkerGlobalScopeInit, + worker_url: ServoUrl, + runtime: Runtime, + from_devtools_receiver: Receiver, + timer_event_chan: IpcSender, + closing: Option>, + ) -> Self { + Self { + globalscope: GlobalScope::new_inherited( + init.pipeline_id, + init.to_devtools_sender, + init.mem_profiler_chan, + init.time_profiler_chan, + init.script_to_constellation_chan, + init.scheduler_chan, + init.resource_threads, + timer_event_chan, + MutableOrigin::new(init.origin), + Default::default(), + ), worker_id: init.worker_id, - worker_url: worker_url, - closing: closing, - runtime: runtime, + worker_url, + closing, + runtime, location: Default::default(), navigator: Default::default(), from_devtools_sender: init.from_devtools_sender, - from_devtools_receiver: from_devtools_receiver, - microtask_queue: MicrotaskQueue::default(), + from_devtools_receiver, navigation_start_precise: precise_time_ns() as f64, performance: Default::default(), } @@ -168,18 +166,6 @@ impl WorkerGlobalScope { cancelled: self.closing.clone(), } } - - pub fn enqueue_microtask(&self, job: Microtask) { - self.microtask_queue.enqueue(job); - } - - pub fn perform_a_microtask_checkpoint(&self) { - self.microtask_queue.checkpoint(|id| { - let global = self.upcast::(); - assert_eq!(global.pipeline_id(), id); - Some(Root::from_ref(global)) - }); - } } impl WorkerGlobalScopeMethods for WorkerGlobalScope { diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs index bfefd9d4758..64a2b3199fb 100644 --- a/components/script/dom/workletglobalscope.rs +++ b/components/script/dom/workletglobalscope.rs @@ -17,8 +17,6 @@ use ipc_channel::ipc::IpcSender; use js::jsapi::JSContext; use js::jsval::UndefinedValue; use js::rust::Runtime; -use microtask::Microtask; -use microtask::MicrotaskQueue; use msg::constellation_msg::PipelineId; use net_traits::ResourceThreads; use net_traits::image_cache::ImageCache; @@ -46,8 +44,6 @@ pub struct WorkletGlobalScope { globalscope: GlobalScope, /// The base URL for this worklet. base_url: ServoUrl, - /// The microtask queue for this worklet - microtask_queue: MicrotaskQueue, /// Sender back to the script thread #[ignore_heap_size_of = "channels are hard"] to_script_thread_sender: Sender, @@ -57,31 +53,34 @@ pub struct WorkletGlobalScope { impl WorkletGlobalScope { /// Create a new stack-allocated `WorkletGlobalScope`. - pub fn new_inherited(pipeline_id: PipelineId, - base_url: ServoUrl, - executor: WorkletExecutor, - init: &WorkletGlobalScopeInit) - -> WorkletGlobalScope { + pub fn new_inherited( + pipeline_id: PipelineId, + base_url: ServoUrl, + executor: WorkletExecutor, + init: &WorkletGlobalScopeInit, + ) -> Self { // Any timer events fired on this global are ignored. let (timer_event_chan, _) = ipc::channel().unwrap(); let script_to_constellation_chan = ScriptToConstellationChan { sender: init.to_constellation_sender.clone(), - pipeline_id: pipeline_id, + pipeline_id, }; - WorkletGlobalScope { - globalscope: GlobalScope::new_inherited(pipeline_id, - init.devtools_chan.clone(), - init.mem_profiler_chan.clone(), - init.time_profiler_chan.clone(), - script_to_constellation_chan, - init.scheduler_chan.clone(), - init.resource_threads.clone(), - timer_event_chan, - MutableOrigin::new(ImmutableOrigin::new_opaque())), - base_url: base_url, - microtask_queue: MicrotaskQueue::default(), + Self { + globalscope: GlobalScope::new_inherited( + pipeline_id, + init.devtools_chan.clone(), + init.mem_profiler_chan.clone(), + init.time_profiler_chan.clone(), + script_to_constellation_chan, + init.scheduler_chan.clone(), + init.resource_threads.clone(), + timer_event_chan, + MutableOrigin::new(ImmutableOrigin::new_opaque()), + Default::default(), + ), + base_url, to_script_thread_sender: init.to_script_thread_sender.clone(), - executor: executor, + executor, } } @@ -128,20 +127,6 @@ impl WorkletGlobalScope { self.executor.clone() } - /// Queue up a microtask to be executed in this global. - pub fn enqueue_microtask(&self, job: Microtask) { - self.microtask_queue.enqueue(job); - } - - /// Perform any queued microtasks. - pub fn perform_a_microtask_checkpoint(&self) { - self.microtask_queue.checkpoint(|id| { - let global = self.upcast::(); - assert_eq!(global.pipeline_id(), id); - Some(Root::from_ref(global)) - }); - } - /// Perform a worklet task pub fn perform_a_worklet_task(&self, task: WorkletTask) { match task { diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 12afd67c7c5..b2359c3ea94 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -515,7 +515,8 @@ pub struct ScriptThread { content_process_shutdown_chan: IpcSender<()>, - microtask_queue: MicrotaskQueue, + /// https://html.spec.whatwg.org/multipage/#microtask-queue + microtask_queue: Rc, /// Microtask Queue for adding support for mutation observer microtasks mutation_observer_compound_microtask_queued: Cell, @@ -843,7 +844,7 @@ impl ScriptThread { // Ask the router to proxy IPC messages from the control port to us. let control_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(state.control_port); - let boxed_script_sender = MainThreadScriptChan(chan.clone()).clone(); + let boxed_script_sender = box MainThreadScriptChan(chan.clone()); let (image_cache_channel, image_cache_port) = channel(); @@ -892,7 +893,7 @@ impl ScriptThread { content_process_shutdown_chan: state.content_process_shutdown_chan, - microtask_queue: MicrotaskQueue::default(), + microtask_queue: Default::default(), mutation_observer_compound_microtask_queued: Default::default(), @@ -2038,34 +2039,37 @@ impl ScriptThread { }; // Create the window and document objects. - let window = Window::new(self.js_runtime.clone(), - MainThreadScriptChan(sender.clone()), - DOMManipulationTaskSource(dom_sender.clone()), - UserInteractionTaskSource(user_sender.clone()), - self.networking_task_source.clone(), - HistoryTraversalTaskSource(history_sender.clone()), - self.file_reading_task_source.clone(), - self.performance_timeline_task_source.clone(), - self.image_cache_channel.clone(), - self.image_cache.clone(), - self.resource_threads.clone(), - self.bluetooth_thread.clone(), - self.mem_profiler_chan.clone(), - self.time_profiler_chan.clone(), - self.devtools_chan.clone(), - script_to_constellation_chan, - self.control_chan.clone(), - self.scheduler_chan.clone(), - ipc_timer_event_chan, - incomplete.layout_chan, - incomplete.pipeline_id, - incomplete.parent_info, - incomplete.window_size, - origin, - incomplete.navigation_start, - incomplete.navigation_start_precise, - self.webgl_chan.channel(), - self.webvr_chan.clone()); + let window = Window::new( + self.js_runtime.clone(), + MainThreadScriptChan(sender.clone()), + DOMManipulationTaskSource(dom_sender.clone()), + UserInteractionTaskSource(user_sender.clone()), + self.networking_task_source.clone(), + HistoryTraversalTaskSource(history_sender.clone()), + self.file_reading_task_source.clone(), + self.performance_timeline_task_source.clone(), + self.image_cache_channel.clone(), + self.image_cache.clone(), + self.resource_threads.clone(), + self.bluetooth_thread.clone(), + self.mem_profiler_chan.clone(), + self.time_profiler_chan.clone(), + self.devtools_chan.clone(), + script_to_constellation_chan, + self.control_chan.clone(), + self.scheduler_chan.clone(), + ipc_timer_event_chan, + incomplete.layout_chan, + incomplete.pipeline_id, + incomplete.parent_info, + incomplete.window_size, + origin, + incomplete.navigation_start, + incomplete.navigation_start_precise, + self.webgl_chan.channel(), + self.webvr_chan.clone(), + self.microtask_queue.clone(), + ); // Initialize the browsing context for the window. let window_proxy = self.local_window_proxy(&window,