diff options
author | Mátyás Mustoha <mmatyas@inf.u-szeged.hu> | 2016-07-20 12:47:55 +0200 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2016-09-22 16:16:49 -0400 |
commit | fd778b424050cc8ef76b9a3679caf366410aac07 (patch) | |
tree | 70dc8e490c8e37d8e14670a862cee8f532adaa39 /components/script/script_thread.rs | |
parent | a1091772ec9258d4e2c4184e07edab730e4d559c (diff) | |
download | servo-fd778b424050cc8ef76b9a3679caf366410aac07.tar.gz servo-fd778b424050cc8ef76b9a3679caf366410aac07.zip |
Enqueue promise jobs from SpiderMonkey callbacks, and execute them in batches. Implement native Promise APIs.
Add SpiderMonkey hooks for enqueuing promise jobs. Start porting various native Promise APIs.
Diffstat (limited to 'components/script/script_thread.rs')
-rw-r--r-- | components/script/script_thread.rs | 70 |
1 files changed, 67 insertions, 3 deletions
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 298323929c1..cf0116edef0 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -22,12 +22,14 @@ use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo}; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use devtools_traits::CSSError; use document_loader::DocumentLoader; +use dom::bindings::callback::ExceptionHandling; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState}; use dom::bindings::codegen::Bindings::LocationBinding::LocationMethods; +use dom::bindings::codegen::Bindings::PromiseBinding::PromiseJobCallback; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::conversions::{ConversionResult, FromJSValConvertible, StringificationBehavior}; -use dom::bindings::global::GlobalRef; +use dom::bindings::global::{GlobalRef, global_root_from_object}; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, MutNullableHeap, Root, RootCollection}; use dom::bindings::js::{RootCollectionPtr, RootedReference}; @@ -59,8 +61,8 @@ use hyper_serde::Serde; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; use js::glue::GetWindowProxyClass; -use js::jsapi::{JSAutoCompartment, JSContext, JS_SetWrapObjectCallbacks}; -use js::jsapi::{JSTracer, SetWindowProxyClass}; +use js::jsapi::{JSAutoCompartment, JSContext, JS_SetWrapObjectCallbacks, HandleObject}; +use js::jsapi::{JSTracer, SetWindowProxyClass, SetEnqueuePromiseJobCallback}; use js::jsval::UndefinedValue; use js::rust::Runtime; use mem::heap_size_of_self_and_children; @@ -91,6 +93,7 @@ use std::borrow::ToOwned; use std::cell::Cell; use std::collections::{HashMap, HashSet}; use std::option::Option; +use std::os::raw::c_void; use std::ptr; use std::rc::Rc; use std::result::Result; @@ -315,6 +318,18 @@ impl OpaqueSender<CommonScriptMsg> for Sender<MainThreadScriptMsg> { } } +#[allow(unsafe_code)] +unsafe extern "C" fn enqueue_job(_cx: *mut JSContext, + job: HandleObject, + _allocation_site: HandleObject, + _data: *mut c_void) -> bool { + SCRIPT_THREAD_ROOT.with(|root| { + let script_thread = &*root.get().unwrap(); + script_thread.enqueue_promise_job(job); + }); + true +} + /// Information for an entire page. Pages are top-level browsing contexts and can contain multiple /// frames. #[derive(JSTraceable)] @@ -394,6 +409,16 @@ pub struct ScriptThread { timer_event_port: Receiver<TimerEvent>, content_process_shutdown_chan: IpcSender<()>, + + flushing_job_queue: DOMRefCell<Vec<EnqueuedPromiseCallback>>, + promise_job_queue: DOMRefCell<Vec<EnqueuedPromiseCallback>>, + pending_promise_job_runnable: Cell<bool>, +} + +#[derive(JSTraceable)] +struct EnqueuedPromiseCallback { + callback: Rc<PromiseJobCallback>, + pipeline: PipelineId, } /// In the event of thread panic, all data on the stack runs its destructor. However, there @@ -541,6 +566,7 @@ impl ScriptThread { JS_SetWrapObjectCallbacks(runtime.rt(), &WRAP_CALLBACKS); SetWindowProxyClass(runtime.rt(), GetWindowProxyClass()); + SetEnqueuePromiseJobCallback(runtime.rt(), Some(enqueue_job), ptr::null_mut()); } // Ask the router to proxy IPC messages from the devtools to us. @@ -599,6 +625,10 @@ impl ScriptThread { timer_event_port: timer_event_port, content_process_shutdown_chan: state.content_process_shutdown_chan, + + promise_job_queue: DOMRefCell::new(vec![]), + flushing_job_queue: DOMRefCell::new(vec![]), + pending_promise_job_runnable: Cell::new(false), } } @@ -2174,6 +2204,40 @@ impl ScriptThread { location.Reload(); } } + + fn enqueue_promise_job(&self, job: HandleObject) { + let global = unsafe { global_root_from_object(job.get()) }; + let pipeline = global.r().pipeline(); + self.promise_job_queue.borrow_mut().push(EnqueuedPromiseCallback { + callback: PromiseJobCallback::new(job.get()), + pipeline: pipeline, + }); + if !self.pending_promise_job_runnable.get() { + self.pending_promise_job_runnable.set(true); + let _ = self.dom_manipulation_task_source.queue(box FlushPromiseJobs, global.r()); + } + } + + fn flush_promise_jobs(&self) { + self.pending_promise_job_runnable.set(false); + { + let mut pending_queue = self.promise_job_queue.borrow_mut(); + *self.flushing_job_queue.borrow_mut() = pending_queue.drain(..).collect(); + } + for job in &*self.flushing_job_queue.borrow() { + if let Some(context) = self.find_child_context(job.pipeline) { + let _ = job.callback.Call_(&*context.active_window(), ExceptionHandling::Report); + } + } + self.flushing_job_queue.borrow_mut().clear(); + } +} + +struct FlushPromiseJobs; +impl Runnable for FlushPromiseJobs { + fn main_thread_handler(self: Box<FlushPromiseJobs>, script_thread: &ScriptThread) { + script_thread.flush_promise_jobs(); + } } impl Drop for ScriptThread { |