servo: Merge #15136 - Use mitochondria::OnceCell to store ScriptThread in TLS (from nox:mitochondria-finally-makes-it-into-the-tree); r=jdm
authorAnthony Ramine <n.oxyde@gmail.com>
Mon, 23 Jan 2017 03:17:33 -0800
changeset 340631 7163b269559109ccd975be316bd9efd63dd18e18
parent 340630 63aaf3f9acb1a061c87f3572f86539f48013575b
child 340632 85fa98ddb44a0aafee24571152c2c70ab5d1e5f3
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdm
servo: Merge #15136 - Use mitochondria::OnceCell to store ScriptThread in TLS (from nox:mitochondria-finally-makes-it-into-the-tree); r=jdm Source-Repo: https://github.com/servo/servo Source-Revision: ca6376a7142640185f21beca4b11011e8367ec91
servo/Cargo.lock
servo/components/script/Cargo.toml
servo/components/script/lib.rs
servo/components/script/script_thread.rs
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -1618,16 +1618,21 @@ source = "registry+https://github.com/ru
 dependencies = [
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "mitochondria"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "mozjs_sys"
 version = "0.0.0"
 source = "git+https://github.com/servo/mozjs#7cd72d8c8f44f43ba162bdd814ec85e81b79cfb4"
 dependencies = [
  "libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "libz-sys 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -2275,16 +2280,17 @@ dependencies = [
  "image 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "js 0.1.3 (git+https://github.com/servo/rust-mozjs)",
  "jstraceable_derive 0.0.1",
  "libc 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "mime 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mitochondria 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "open 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf_codegen 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3502,16 +3508,17 @@ dependencies = [
 "checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1"
 "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
 "checksum memmap 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f20f72ed93291a72e22e8b16bb18762183bb4943f0f483da5b8be1a9e8192752"
 "checksum mime 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5c93a4bd787ddc6e7833c519b73a50883deb5863d76d9b71eb8216fb7f94e66"
 "checksum mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76da6df85047af8c0edfa53f48eb1073012ce1cc95c8fedc0a374f659a89dd65"
 "checksum miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1f4d337a01c32e1f2122510fed46393d53ca35a7f429cb0450abaedfa3ed54"
 "checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e"
 "checksum miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3e690c5df6b2f60acd45d56378981e827ff8295562fc8d34f573deb267a59cd1"
+"checksum mitochondria 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9de3eca27871df31c33b807f834b94ef7d000956f57aa25c5aed9c5f0aae8f6f"
 "checksum mozjs_sys 0.0.0 (git+https://github.com/servo/mozjs)" = "<none>"
 "checksum mp3-metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2f61cf32f7fc3cec83a15a255ac60bceb6cac59a7ce190cb824ca25c0fce0feb"
 "checksum mp4parse 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1736d06703a9cb5228b5a8151acc79bf5ba7669a810243852bcad4d3a25504"
 "checksum net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "5edf9cb6be97212423aed9413dd4729d62b370b5e1c571750e882cebbbc1e3e2"
 "checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79"
 "checksum nodrop 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbadd3f4c98dea0bd3d9b4be4c0cdaf1ab57035cb2e41fce3983db5add7cc5"
 "checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
 "checksum num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "88b14378471f7c2adc5262f05b4701ef53e8da376453a8d8fee48e51db745e49"
--- a/servo/components/script/Cargo.toml
+++ b/servo/components/script/Cargo.toml
@@ -48,16 +48,17 @@ hyper_serde = "0.1.4"
 image = "0.12"
 ipc-channel = "0.5"
 js = {git = "https://github.com/servo/rust-mozjs", features = ["promises"]}
 jstraceable_derive = {path = "../jstraceable_derive"}
 libc = "0.2"
 log = "0.3.5"
 mime = "0.2.1"
 mime_guess = "1.8.0"
+mitochondria = "1.1.2"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 num-traits = "0.1.32"
 offscreen_gl_context = "0.5.0"
 open = "1.1.1"
 parking_lot = "0.3"
 phf = "0.7.18"
 plugins = {path = "../plugins"}
--- a/servo/components/script/lib.rs
+++ b/servo/components/script/lib.rs
@@ -58,16 +58,17 @@ extern crate js;
 #[macro_use]
 extern crate jstraceable_derive;
 extern crate libc;
 #[macro_use]
 extern crate log;
 #[macro_use]
 extern crate mime;
 extern crate mime_guess;
+extern crate mitochondria;
 extern crate msg;
 extern crate net_traits;
 extern crate num_traits;
 extern crate offscreen_gl_context;
 extern crate open;
 extern crate parking_lot;
 extern crate phf;
 #[macro_use]
--- a/servo/components/script/script_thread.rs
+++ b/servo/components/script/script_thread.rs
@@ -65,16 +65,17 @@ 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::jsval::UndefinedValue;
 use js::rust::Runtime;
 use layout_wrapper::ServoLayoutNode;
 use mem::heap_size_of_self_and_children;
+use mitochondria::OnceCell;
 use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespace};
 use net_traits::{CoreResourceMsg, FetchMetadata, FetchResponseListener};
 use net_traits::{IpcSend, Metadata, ReferrerPolicy, ResourceThreads};
 use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
 use net_traits::request::{CredentialsMode, Destination, RequestInit};
 use net_traits::storage_thread::StorageType;
 use network_listener::NetworkListener;
 use origin::Origin;
@@ -115,23 +116,23 @@ use task_source::history_traversal::Hist
 use task_source::networking::NetworkingTaskSource;
 use task_source::user_interaction::{UserInteractionTask, UserInteractionTaskSource};
 use time::Tm;
 use url::Position;
 use webdriver_handlers;
 use webvr_traits::WebVRMsg;
 
 thread_local!(pub static STACK_ROOTS: Cell<Option<RootCollectionPtr>> = Cell::new(None));
-thread_local!(static SCRIPT_THREAD_ROOT: Cell<Option<*const ScriptThread>> = Cell::new(None));
+thread_local!(static SCRIPT_THREAD_ROOT: OnceCell<ScriptThread> = OnceCell::new());
 
 pub unsafe fn trace_thread(tr: *mut JSTracer) {
     SCRIPT_THREAD_ROOT.with(|root| {
-        if let Some(script_thread) = root.get() {
+        if let Some(script_thread) = root.as_ref() {
             debug!("tracing fields of ScriptThread");
-            (*script_thread).trace(tr);
+            script_thread.trace(tr);
         }
     });
 }
 
 /// A document load that is in the process of fetching the requested resource. Contains
 /// data that will need to be present when the document and frame tree entry are created,
 /// but is only easily available at initiation of the load and on a push basis (so some
 /// data will be updated according to future resize events, viewport changes, etc.)
@@ -529,101 +530,96 @@ impl ScriptThreadFactory for ScriptThrea
             FrameId::install(state.top_level_frame_id);
             let roots = RootCollection::new();
             let _stack_roots_tls = StackRootTLS::new(&roots);
             let id = state.id;
             let frame_id = state.frame_id;
             let parent_info = state.parent_info;
             let mem_profiler_chan = state.mem_profiler_chan.clone();
             let window_size = state.window_size;
-            let script_thread = ScriptThread::new(state,
-                                                  script_port,
-                                                  script_chan.clone());
 
             SCRIPT_THREAD_ROOT.with(|root| {
-                root.set(Some(&script_thread as *const _));
-            });
+                let script_thread = root.init_once(|| ScriptThread::new(state, script_port, script_chan.clone()));
+
+                let mut failsafe = ScriptMemoryFailsafe::new(&script_thread);
 
-            let mut failsafe = ScriptMemoryFailsafe::new(&script_thread);
+                let origin = Origin::new(&load_data.url);
+                let new_load = InProgressLoad::new(id, frame_id, parent_info, layout_chan, window_size,
+                                                   load_data.url.clone(), origin);
+                script_thread.start_page_load(new_load, load_data);
 
-            let origin = Origin::new(&load_data.url);
-            let new_load = InProgressLoad::new(id, frame_id, parent_info, layout_chan, window_size,
-                                               load_data.url.clone(), origin);
-            script_thread.start_page_load(new_load, load_data);
+                let reporter_name = format!("script-reporter-{}", id);
+                mem_profiler_chan.run_with_memory_reporting(|| {
+                    script_thread.start();
+                    let _ = script_thread.content_process_shutdown_chan.send(());
+                }, reporter_name, script_chan, CommonScriptMsg::CollectReports);
 
-            let reporter_name = format!("script-reporter-{}", id);
-            mem_profiler_chan.run_with_memory_reporting(|| {
-                script_thread.start();
-                let _ = script_thread.content_process_shutdown_chan.send(());
-            }, reporter_name, script_chan, CommonScriptMsg::CollectReports);
-
-            // This must always be the very last operation performed before the thread completes
-            failsafe.neuter();
+                // This must always be the very last operation performed before the thread completes
+                failsafe.neuter();
+            });
         }).expect("Thread spawning failed");
 
         (sender, receiver)
     }
 }
 
 impl ScriptThread {
     pub fn page_headers_available(id: &PipelineId, metadata: Option<Metadata>)
                                   -> Option<Root<ServoParser>> {
         SCRIPT_THREAD_ROOT.with(|root| {
-            let script_thread = unsafe { &*root.get().unwrap() };
+            let script_thread = root.as_ref().unwrap();
             script_thread.handle_page_headers_available(id, metadata)
         })
     }
 
     #[allow(unrooted_must_root)]
     pub fn schedule_job(job: Job, global: &GlobalScope) {
         SCRIPT_THREAD_ROOT.with(|root| {
-            let script_thread = unsafe { &*root.get().unwrap() };
+            let script_thread = root.as_ref().unwrap();
             let job_queue = &*script_thread.job_queue_map;
             job_queue.schedule_job(job, global, &script_thread);
         });
     }
 
     pub fn process_event(msg: CommonScriptMsg) {
         SCRIPT_THREAD_ROOT.with(|root| {
-            if let Some(script_thread) = root.get() {
-                let script_thread = unsafe { &*script_thread };
+            if let Some(script_thread) = root.as_ref() {
                 script_thread.handle_msg_from_script(MainThreadScriptMsg::Common(msg));
             }
         });
     }
 
     // https://html.spec.whatwg.org/multipage/#await-a-stable-state
     pub fn await_stable_state<T: Runnable + Send + 'static>(task: T) {
         //TODO use microtasks when they exist
         SCRIPT_THREAD_ROOT.with(|root| {
-            if let Some(script_thread) = root.get() {
-                let script_thread = unsafe { &*script_thread };
+            if let Some(script_thread) = root.as_ref() {
                 let _ = script_thread.chan.send(CommonScriptMsg::RunnableMsg(
                     ScriptThreadEventCategory::DomEvent,
                     box task));
             }
         });
     }
 
     pub fn process_attach_layout(new_layout_info: NewLayoutInfo, origin: Origin) {
         SCRIPT_THREAD_ROOT.with(|root| {
-            if let Some(script_thread) = root.get() {
-                let script_thread = unsafe { &*script_thread };
+            if let Some(script_thread) = root.as_ref() {
                 script_thread.profile_event(ScriptThreadEventCategory::AttachLayout, || {
                     script_thread.handle_new_layout(new_layout_info, origin);
                 })
             }
         });
     }
 
     pub fn find_document(id: PipelineId) -> Option<Root<Document>> {
-        SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| {
-            let script_thread = unsafe { &*script_thread };
-            script_thread.documents.borrow().find_document(id)
-        }))
+        SCRIPT_THREAD_ROOT.with(|root| {
+            root.as_ref().and_then(|script_thread| {
+                script_thread.documents.borrow().find_document(id)
+            })
+        })
     }
 
     /// Creates a new script thread.
     pub fn new(state: InitialScriptState,
                port: Receiver<MainThreadScriptMsg>,
                chan: Sender<MainThreadScriptMsg>)
                -> ScriptThread {
         let runtime = unsafe { new_rt_and_cx() };
@@ -2162,24 +2158,24 @@ impl ScriptThread {
         if let Some(window) = window {
             let navigator = window.Navigator();
             navigator.handle_webvr_event(event);
         }
     }
 
     pub fn enqueue_promise_job(job: EnqueuedPromiseCallback, global: &GlobalScope) {
         SCRIPT_THREAD_ROOT.with(|root| {
-            let script_thread = unsafe { &*root.get().unwrap() };
+            let script_thread = root.as_ref().unwrap();
             script_thread.promise_job_queue.enqueue(job, global);
         });
     }
 
     pub fn flush_promise_jobs(global: &GlobalScope) {
         SCRIPT_THREAD_ROOT.with(|root| {
-            let script_thread = unsafe { &*root.get().unwrap() };
+            let script_thread = root.as_ref().unwrap();
             let _ = script_thread.dom_manipulation_task_source.queue(
                 box FlushPromiseJobs, global);
         })
     }
 
     fn do_flush_promise_jobs(&self) {
         self.promise_job_queue.flush_promise_jobs(|id| self.documents.borrow().find_global(id))
     }
@@ -2187,24 +2183,16 @@ impl ScriptThread {
 
 struct FlushPromiseJobs;
 impl Runnable for FlushPromiseJobs {
     fn main_thread_handler(self: Box<FlushPromiseJobs>, script_thread: &ScriptThread) {
         script_thread.do_flush_promise_jobs();
     }
 }
 
-impl Drop for ScriptThread {
-    fn drop(&mut self) {
-        SCRIPT_THREAD_ROOT.with(|root| {
-            root.set(None);
-        });
-    }
-}
-
 /// Shuts down layout for the given window.
 fn shut_down_layout(window: &Window) {
     // Tell the layout thread to begin shutting down, and wait until it
     // processed this message.
     let (response_chan, response_port) = channel();
     let chan = window.layout_chan().clone();
     if chan.send(message::Msg::PrepareToExit(response_chan)).is_ok() {
         let _ = response_port.recv();