Auto merge of #18480 - servo:rc-microtask-queue, r=jdm

Store microtask queues directly in GlobalScope

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18480)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-09-13 09:18:41 -05:00 committed by GitHub
commit 2c576e5613
8 changed files with 213 additions and 229 deletions

View file

@ -247,7 +247,7 @@ impl DedicatedWorkerGlobalScope {
global.handle_event(event);
// Step 6
let _ar = AutoWorkerReset::new(&global, worker.clone());
global.upcast::<WorkerGlobalScope>().perform_a_microtask_checkpoint();
global.upcast::<GlobalScope>().perform_a_microtask_checkpoint();
}
}, reporter_name, parent_sender, CommonScriptMsg::CollectReports);
}).expect("Thread spawning failed");

View file

@ -45,12 +45,16 @@ pub struct DissimilarOriginWindow {
impl DissimilarOriginWindow {
#[allow(unsafe_code)]
pub fn new(global_to_clone_from: &GlobalScope, window_proxy: &WindowProxy) -> Root<DissimilarOriginWindow> {
pub fn new(
global_to_clone_from: &GlobalScope,
window_proxy: &WindowProxy,
) -> Root<Self> {
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(),
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(),
@ -58,16 +62,19 @@ impl DissimilarOriginWindow {
global_to_clone_from.scheduler_chan().clone(),
global_to_clone_from.resource_threads().clone(),
timer_event_chan,
global_to_clone_from.origin().clone()),
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::<GlobalScope>().origin()
}
}

View file

@ -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,6 +100,15 @@ 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<T> is hard"]
microtask_queue: Rc<MicrotaskQueue>,
}
impl GlobalScope {
@ -111,24 +121,26 @@ impl GlobalScope {
scheduler_chan: IpcSender<TimerSchedulerMsg>,
resource_threads: ResourceThreads,
timer_event_chan: IpcSender<TimerEvent>,
origin: MutableOrigin)
-> Self {
GlobalScope {
origin: MutableOrigin,
microtask_queue: Rc<MicrotaskQueue>,
) -> 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::<Window>() {
return ScriptThread::invoke_perform_a_microtask_checkpoint();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.perform_a_microtask_checkpoint();
}
if let Some(worker) = self.downcast::<WorkletGlobalScope>() {
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::<Window>() {
return ScriptThread::enqueue_microtask(job);
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.enqueue_microtask(job);
}
if let Some(worker) = self.downcast::<WorkletGlobalScope>() {
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<MicrotaskQueue> {
&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) {

View file

@ -219,7 +219,7 @@ impl ServiceWorkerGlobalScope {
break;
}
// Step 6
global.upcast::<WorkerGlobalScope>().perform_a_microtask_checkpoint();
global.upcast::<GlobalScope>().perform_a_microtask_checkpoint();
}
}, reporter_name, scope.script_chan(), CommonScriptMsg::CollectReports);
}).expect("Thread spawning failed");

View file

@ -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,13 +1790,14 @@ impl Window {
impl Window {
#[allow(unsafe_code)]
pub fn new(runtime: Rc<Runtime>,
pub fn new(
runtime: Rc<Runtime>,
script_chan: MainThreadScriptChan,
dom_task_source: DOMManipulationTaskSource,
user_task_source: UserInteractionTaskSource,
network_task_source: NetworkingTaskSource,
history_task_source: HistoryTraversalTaskSource,
file_task_source: FileReadingTaskSource,
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<ImageCacheMsg>,
image_cache: Arc<ImageCache>,
@ -1809,28 +1811,28 @@ impl Window {
scheduler_chan: IpcSender<TimerSchedulerMsg>,
timer_event_chan: IpcSender<TimerEvent>,
layout_chan: Sender<Msg>,
id: PipelineId,
pipelineid: PipelineId,
parent_info: Option<(PipelineId, FrameType)>,
window_size: Option<WindowSizeData>,
origin: MutableOrigin,
navigation_start: u64,
navigation_start_precise: f64,
webgl_chan: WebGLChan,
webvr_chan: Option<IpcSender<WebVRMsg>>)
-> Root<Window> {
webvr_chan: Option<IpcSender<WebVRMsg>>,
microtask_queue: Rc<MicrotaskQueue>,
) -> Root<Self> {
let layout_rpc: Box<LayoutRPC + Send> = {
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,
let win = box Self {
globalscope: GlobalScope::new_inherited(
pipelineid,
devtools_chan,
mem_profiler_chan,
time_profiler_chan,
@ -1838,16 +1840,18 @@ impl Window {
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,
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(),
};

View file

@ -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,23 +90,21 @@ pub struct WorkerGlobalScope {
/// `IpcSender` doesn't exist
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
microtask_queue: MicrotaskQueue,
navigation_start_precise: f64,
performance: MutNullableJS<Performance>,
}
impl WorkerGlobalScope {
pub fn new_inherited(init: WorkerGlobalScopeInit,
pub fn new_inherited(
init: WorkerGlobalScopeInit,
worker_url: ServoUrl,
runtime: Runtime,
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
timer_event_chan: IpcSender<TimerEvent>,
closing: Option<Arc<AtomicBool>>)
-> WorkerGlobalScope {
WorkerGlobalScope {
globalscope:
GlobalScope::new_inherited(
closing: Option<Arc<AtomicBool>>,
) -> Self {
Self {
globalscope: GlobalScope::new_inherited(
init.pipeline_id,
init.to_devtools_sender,
init.mem_profiler_chan,
@ -116,16 +113,17 @@ impl WorkerGlobalScope {
init.scheduler_chan,
init.resource_threads,
timer_event_chan,
MutableOrigin::new(init.origin)),
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::<GlobalScope>();
assert_eq!(global.pipeline_id(), id);
Some(Root::from_ref(global))
});
}
}
impl WorkerGlobalScopeMethods for WorkerGlobalScope {

View file

@ -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<MainThreadScriptMsg>,
@ -57,19 +53,21 @@ pub struct WorkletGlobalScope {
impl WorkletGlobalScope {
/// Create a new stack-allocated `WorkletGlobalScope`.
pub fn new_inherited(pipeline_id: PipelineId,
pub fn new_inherited(
pipeline_id: PipelineId,
base_url: ServoUrl,
executor: WorkletExecutor,
init: &WorkletGlobalScopeInit)
-> WorkletGlobalScope {
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,
Self {
globalscope: GlobalScope::new_inherited(
pipeline_id,
init.devtools_chan.clone(),
init.mem_profiler_chan.clone(),
init.time_profiler_chan.clone(),
@ -77,11 +75,12 @@ impl WorkletGlobalScope {
init.scheduler_chan.clone(),
init.resource_threads.clone(),
timer_event_chan,
MutableOrigin::new(ImmutableOrigin::new_opaque())),
base_url: base_url,
microtask_queue: MicrotaskQueue::default(),
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::<GlobalScope>();
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 {

View file

@ -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<MicrotaskQueue>,
/// Microtask Queue for adding support for mutation observer microtasks
mutation_observer_compound_microtask_queued: Cell<bool>,
@ -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,7 +2039,8 @@ impl ScriptThread {
};
// Create the window and document objects.
let window = Window::new(self.js_runtime.clone(),
let window = Window::new(
self.js_runtime.clone(),
MainThreadScriptChan(sender.clone()),
DOMManipulationTaskSource(dom_sender.clone()),
UserInteractionTaskSource(user_sender.clone()),
@ -2065,7 +2067,9 @@ impl ScriptThread {
incomplete.navigation_start,
incomplete.navigation_start_precise,
self.webgl_chan.channel(),
self.webvr_chan.clone());
self.webvr_chan.clone(),
self.microtask_queue.clone(),
);
// Initialize the browsing context for the window.
let window_proxy = self.local_window_proxy(&window,