diff --git a/components/script/cors.rs b/components/script/cors.rs index b9794a3f1fa..da8c3db68ca 100644 --- a/components/script/cors.rs +++ b/components/script/cors.rs @@ -20,7 +20,7 @@ use hyper::mime::{Mime, SubLevel, TopLevel}; use hyper::status::StatusClass::Success; use net_traits::{AsyncResponseListener, Metadata, ResponseAction}; use network_listener::{NetworkListener, PreInvoke}; -use script_thread::ScriptChan; +use script_runtime::ScriptChan; use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::sync::{Arc, Mutex}; diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs index dab74fd5850..8cb8c54b426 100644 --- a/components/script/dom/bindings/global.rs +++ b/components/script/dom/bindings/global.rs @@ -21,7 +21,8 @@ use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL}; use msg::constellation_msg::{ConstellationChan, PipelineId}; use net_traits::ResourceThread; use profile_traits::mem; -use script_thread::{CommonScriptMsg, MainThreadScriptChan, ScriptChan, ScriptPort, ScriptThread}; +use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort}; +use script_thread::{MainThreadScriptChan, ScriptThread}; use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEventRequest}; use task_source::TaskSource; use task_source::dom_manipulation::DOMManipulationTask; diff --git a/components/script/dom/bindings/refcounted.rs b/components/script/dom/bindings/refcounted.rs index c7d67cba5fd..c01136cc735 100644 --- a/components/script/dom/bindings/refcounted.rs +++ b/components/script/dom/bindings/refcounted.rs @@ -28,7 +28,7 @@ use dom::bindings::reflector::{Reflectable, Reflector}; use dom::bindings::trace::trace_reflector; use js::jsapi::JSTracer; use libc; -use script_thread::{CommonScriptMsg, ScriptChan}; +use script_runtime::{CommonScriptMsg, ScriptChan}; use std::cell::RefCell; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::hash_map::HashMap; diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index a23a5452f1c..cf831f2a226 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -63,7 +63,7 @@ use net_traits::response::HttpsState; use net_traits::storage_thread::StorageType; use profile_traits::mem::ProfilerChan as MemProfilerChan; use profile_traits::time::ProfilerChan as TimeProfilerChan; -use script_thread::ScriptChan; +use script_runtime::ScriptChan; use script_traits::{LayoutMsg, ScriptMsg, TimerEventId, TimerSource, TouchpadPressurePhase, UntrustedNodeAddress}; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; diff --git a/components/script/dom/closeevent.rs b/components/script/dom/closeevent.rs index b7181baa2ea..141902b88c1 100644 --- a/components/script/dom/closeevent.rs +++ b/components/script/dom/closeevent.rs @@ -11,7 +11,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; use dom::bindings::reflector::reflect_dom_object; use dom::event::{Event, EventBubbles, EventCancelable}; -use script_thread::ScriptChan; +use script_runtime::ScriptChan; use string_cache::Atom; use util::str::DOMString; diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index d04ea7f11de..32ec841fc08 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -28,8 +28,8 @@ use js::rust::Runtime; use msg::constellation_msg::PipelineId; use net_traits::{LoadContext, load_whole_resource}; use rand::random; -use script_thread::ScriptThreadEventCategory::WorkerEvent; -use script_thread::{ScriptThread, ScriptChan, ScriptPort, StackRootTLS, CommonScriptMsg}; +use script_runtime::ScriptThreadEventCategory::WorkerEvent; +use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx}; use script_traits::{TimerEvent, TimerSource}; use std::mem::replace; use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel}; @@ -236,7 +236,7 @@ impl DedicatedWorkerGlobalScope { } }; - let runtime = ScriptThread::new_rt_and_cx(); + let runtime = new_rt_and_cx(); let (devtools_mpsc_chan, devtools_mpsc_port) = channel(); ROUTER.route_ipc_receiver_to_mpsc_sender(from_devtools_receiver, devtools_mpsc_chan); @@ -347,7 +347,7 @@ impl DedicatedWorkerGlobalScope { let scope = self.upcast::(); let cx = scope.get_cx(); let path_seg = format!("url({})", scope.get_url()); - let reports = ScriptThread::get_reports(cx, path_seg); + let reports = get_reports(cx, path_seg); reports_chan.send(reports); }, } diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index c99099e04f9..367ffb11d0c 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -94,7 +94,8 @@ use net_traits::CookieSource::NonHTTP; use net_traits::response::HttpsState; use net_traits::{AsyncResponseTarget, PendingAsyncLoad}; use num::ToPrimitive; -use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, ScriptChan}; +use script_runtime::ScriptChan; +use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable}; use script_traits::UntrustedNodeAddress; use script_traits::{AnimationState, MouseButton, MouseEventType, MozBrowserEvent}; use script_traits::{ScriptMsg as ConstellationMsg, ScriptToCompositorMsg}; diff --git a/components/script/dom/filereader.rs b/components/script/dom/filereader.rs index e62e556f357..af9fe864246 100644 --- a/components/script/dom/filereader.rs +++ b/components/script/dom/filereader.rs @@ -22,8 +22,9 @@ use encoding::label::encoding_from_whatwg_label; use encoding::types::{DecoderTrap, EncodingRef}; use hyper::mime::{Attr, Mime}; use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64}; -use script_thread::ScriptThreadEventCategory::FileRead; -use script_thread::{CommonScriptMsg, Runnable, ScriptChan}; +use script_runtime::ScriptThreadEventCategory::FileRead; +use script_runtime::{ScriptChan, CommonScriptMsg}; +use script_thread::Runnable; use std::cell::Cell; use string_cache::Atom; use util::str::DOMString; diff --git a/components/script/dom/htmldetailselement.rs b/components/script/dom/htmldetailselement.rs index 01286dd2265..921a3f7736f 100644 --- a/components/script/dom/htmldetailselement.rs +++ b/components/script/dom/htmldetailselement.rs @@ -14,7 +14,8 @@ use dom::eventtarget::EventTarget; use dom::htmlelement::HTMLElement; use dom::node::{Node, window_from_node}; use dom::virtualmethods::VirtualMethods; -use script_thread::{MainThreadScriptChan, Runnable, ScriptChan}; +use script_runtime::ScriptChan; +use script_thread::{MainThreadScriptChan, Runnable}; use std::cell::Cell; use string_cache::Atom; use task_source::dom_manipulation::DOMManipulationTask; diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 1d84c78f78b..f46b69b9e89 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -37,7 +37,8 @@ use hyper::header::ContentType; use hyper::method::Method; use hyper::mime; use msg::constellation_msg::{LoadData, PipelineId}; -use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, ScriptChan}; +use script_runtime::ScriptChan; +use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable}; use std::borrow::ToOwned; use std::cell::Cell; use std::sync::mpsc::Sender; diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 2de6963a526..c36bcb02651 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -25,8 +25,9 @@ use ipc_channel::ipc; use ipc_channel::router::ROUTER; use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image_cache_thread::{ImageResponder, ImageResponse}; -use script_thread::ScriptThreadEventCategory::UpdateReplacedElement; -use script_thread::{CommonScriptMsg, Runnable, ScriptChan}; +use script_runtime::ScriptThreadEventCategory::UpdateReplacedElement; +use script_runtime::{CommonScriptMsg, ScriptChan}; +use script_thread::Runnable; use std::sync::Arc; use string_cache::Atom; use url::Url; diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index e2434d60759..65cc0e0767b 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -32,8 +32,9 @@ use dom::validation::Validatable; use dom::virtualmethods::VirtualMethods; use msg::constellation_msg::ConstellationChan; use range::Range; -use script_thread::ScriptThreadEventCategory::InputEvent; -use script_thread::{CommonScriptMsg, Runnable}; +use script_runtime::CommonScriptMsg; +use script_runtime::ScriptThreadEventCategory::InputEvent; +use script_thread::Runnable; use script_traits::ScriptMsg as ConstellationMsg; use std::borrow::ToOwned; use std::cell::Cell; diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 70d96f25fe7..3a609a0977f 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -34,7 +34,8 @@ use js::jsapi::RootedValue; use js::jsval::UndefinedValue; use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata}; use network_listener::{NetworkListener, PreInvoke}; -use script_thread::{MainThreadScriptChan, ScriptChan}; +use script_runtime::ScriptChan; +use script_thread::MainThreadScriptChan; use std::ascii::AsciiExt; use std::cell::Cell; use std::mem; diff --git a/components/script/dom/servohtmlparser.rs b/components/script/dom/servohtmlparser.rs index dea7c2a44bd..2312ac96795 100644 --- a/components/script/dom/servohtmlparser.rs +++ b/components/script/dom/servohtmlparser.rs @@ -29,7 +29,8 @@ use msg::constellation_msg::{PipelineId, SubpageId}; use net_traits::{AsyncResponseListener, Metadata}; use network_listener::PreInvoke; use parse::Parser; -use script_thread::{ScriptChan, ScriptThread}; +use script_runtime::ScriptChan; +use script_thread::ScriptThread; use std::cell::Cell; use std::cell::UnsafeCell; use std::default::Default; diff --git a/components/script/dom/storage.rs b/components/script/dom/storage.rs index b264580495a..dae8d73e7a3 100644 --- a/components/script/dom/storage.rs +++ b/components/script/dom/storage.rs @@ -16,7 +16,8 @@ use dom::urlhelper::UrlHelper; use ipc_channel::ipc; use net_traits::storage_thread::{StorageThread, StorageThreadMsg, StorageType}; use page::IterablePage; -use script_thread::{MainThreadRunnable, MainThreadScriptChan, ScriptChan, ScriptThread}; +use script_runtime::ScriptChan; +use script_thread::{MainThreadRunnable, MainThreadScriptChan, ScriptThread}; use task_source::dom_manipulation::DOMManipulationTask; use url::Url; use util::str::DOMString; diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index e2a29229efc..59ec9db7b4b 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -35,8 +35,9 @@ use net_traits::MessageData; use net_traits::hosts::replace_hosts; use net_traits::unwrap_websocket_protocol; use net_traits::{WebSocketCommunicate, WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent}; -use script_thread::ScriptThreadEventCategory::WebSocketEvent; -use script_thread::{CommonScriptMsg, Runnable, ScriptChan}; +use script_runtime::ScriptThreadEventCategory::WebSocketEvent; +use script_runtime::{CommonScriptMsg, ScriptChan}; +use script_thread::Runnable; use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::cell::Cell; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 3884a42b8b7..bd8ae5b9f39 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -53,8 +53,9 @@ use page::Page; use profile_traits::mem; use reporter::CSSErrorReporter; use rustc_serialize::base64::{FromBase64, STANDARD, ToBase64}; +use script_runtime::{ScriptChan, ScriptPort}; +use script_thread::SendableMainThreadScriptChan; use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, RunnableWrapper}; -use script_thread::{SendableMainThreadScriptChan, ScriptChan, ScriptPort}; use script_traits::{ConstellationControlMsg, UntrustedNodeAddress}; use script_traits::{DocumentState, MsDuration, ScriptToCompositorMsg, TimerEvent, TimerEventId}; use script_traits::{MozBrowserEvent, ScriptMsg as ConstellationMsg, TimerEventRequest, TimerSource}; diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index dfa8d1363f3..f1f15c3c8f9 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -24,7 +24,8 @@ use ipc_channel::ipc; use js::jsapi::{HandleValue, JSContext, RootedValue}; use js::jsapi::{JSAutoCompartment, JSAutoRequest}; use js::jsval::UndefinedValue; -use script_thread::{Runnable, ScriptChan}; +use script_runtime::ScriptChan; +use script_thread::Runnable; use std::sync::mpsc::{Sender, channel}; use util::str::DOMString; diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index fcc6bbdd151..51180fe10c2 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -23,7 +23,7 @@ use js::rust::Runtime; use msg::constellation_msg::{ConstellationChan, PipelineId}; use net_traits::{LoadContext, ResourceThread, load_whole_resource}; use profile_traits::mem; -use script_thread::{CommonScriptMsg, ScriptChan, ScriptPort}; +use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort}; use script_traits::ScriptMsg as ConstellationMsg; use script_traits::{MsDuration, TimerEvent, TimerEventId, TimerEventRequest, TimerSource}; use std::cell::Cell; diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 6d3ea932099..4569a9e7d4a 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -50,7 +50,7 @@ use net_traits::{LoadConsumer, LoadContext, LoadData, ResourceCORSData, Resource use network_listener::{NetworkListener, PreInvoke}; use parse::html::{ParseContext, parse_html}; use parse::xml::{self, parse_xml}; -use script_thread::{ScriptChan, ScriptPort}; +use script_runtime::{ScriptChan, ScriptPort}; use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::cell::{Cell, RefCell}; diff --git a/components/script/lib.rs b/components/script/lib.rs index 3ab51fc954e..d3913865070 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -93,6 +93,7 @@ mod network_listener; pub mod page; pub mod parse; pub mod reporter; +pub mod script_runtime; #[allow(unsafe_code)] pub mod script_thread; mod task_source; diff --git a/components/script/network_listener.rs b/components/script/network_listener.rs index 448befa0f51..cff0723d277 100644 --- a/components/script/network_listener.rs +++ b/components/script/network_listener.rs @@ -3,8 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use net_traits::{AsyncResponseListener, ResponseAction}; -use script_thread::ScriptThreadEventCategory::NetworkEvent; -use script_thread::{CommonScriptMsg, Runnable, ScriptChan}; +use script_runtime::ScriptThreadEventCategory::NetworkEvent; +use script_runtime::{CommonScriptMsg, ScriptChan}; +use script_thread::Runnable; use std::sync::{Arc, Mutex}; /// An off-thread sink for async network event runnables. All such events are forwarded to diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs new file mode 100644 index 00000000000..35c0bdd618f --- /dev/null +++ b/components/script/script_runtime.rs @@ -0,0 +1,235 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! The script runtime contains common traits and structs commonly used by the +//! script thread, the dom, and the worker threads. + +use dom::bindings::js::{RootCollection, RootCollectionPtr, trace_roots}; +use dom::bindings::refcounted::{LiveDOMReferences, TrustedReference, trace_refcounted_objects}; +use dom::bindings::trace::trace_traceables; +use dom::bindings::utils::DOM_CALLBACKS; +use js::glue::CollectServoSizes; +use js::jsapi::{DisableIncrementalGC, GCDescription, GCProgress}; +use js::jsapi::{JSContext, JS_GetRuntime, JSRuntime, JSTracer, SetDOMCallbacks, SetGCSliceCallback}; +use js::jsapi::{JSGCInvocationKind, JSGCStatus, JS_AddExtraGCRootsTracer, JS_SetGCCallback}; +use js::jsapi::{JSObject, SetPreserveWrapperCallback}; +use js::rust::Runtime; +use libc; +use profile_traits::mem::{Report, ReportKind, ReportsChan}; +use script_thread::{Runnable, STACK_ROOTS, trace_thread}; +use std::cell::Cell; +use std::io::{Write, stdout}; +use std::marker::PhantomData; +use std::ptr; +use time::{Tm, now}; +use util::opts; +use util::thread_state; + +/// Common messages used to control the event loops in both the script and the worker +pub enum CommonScriptMsg { + /// Requests that the script thread measure its memory usage. The results are sent back via the + /// supplied channel. + CollectReports(ReportsChan), + /// A DOM object's last pinned reference was removed (dispatched to all threads). + RefcountCleanup(TrustedReference), + /// Generic message that encapsulates event handling. + RunnableMsg(ScriptThreadEventCategory, Box), +} + +/// A cloneable interface for communicating with an event loop. +pub trait ScriptChan { + /// Send a message to the associated event loop. + fn send(&self, msg: CommonScriptMsg) -> Result<(), ()>; + /// Clone this handle. + fn clone(&self) -> Box; +} + +#[derive(Clone, Copy, Debug, Eq, Hash, JSTraceable, PartialEq)] +pub enum ScriptThreadEventCategory { + AttachLayout, + ConstellationMsg, + DevtoolsMsg, + DocumentEvent, + DomEvent, + FileRead, + FormPlannedNavigation, + ImageCacheMsg, + InputEvent, + NetworkEvent, + Resize, + ScriptEvent, + SetViewport, + StylesheetLoad, + TimerEvent, + UpdateReplacedElement, + WebSocketEvent, + WorkerEvent, +} + +/// An interface for receiving ScriptMsg values in an event loop. Used for synchronous DOM +/// APIs that need to abstract over multiple kinds of event loops (worker/main thread) with +/// different Receiver interfaces. +pub trait ScriptPort { + fn recv(&self) -> Result; +} + +pub struct StackRootTLS<'a>(PhantomData<&'a u32>); + +impl<'a> StackRootTLS<'a> { + pub fn new(roots: &'a RootCollection) -> StackRootTLS<'a> { + STACK_ROOTS.with(|ref r| { + r.set(Some(RootCollectionPtr(roots as *const _))) + }); + StackRootTLS(PhantomData) + } +} + +impl<'a> Drop for StackRootTLS<'a> { + fn drop(&mut self) { + STACK_ROOTS.with(|ref r| r.set(None)); + } +} + +#[allow(unsafe_code)] +pub fn new_rt_and_cx() -> Runtime { + LiveDOMReferences::initialize(); + let runtime = Runtime::new(); + + unsafe { + JS_AddExtraGCRootsTracer(runtime.rt(), Some(trace_rust_roots), ptr::null_mut()); + JS_AddExtraGCRootsTracer(runtime.rt(), Some(trace_refcounted_objects), ptr::null_mut()); + } + + // Needed for debug assertions about whether GC is running. + if cfg!(debug_assertions) { + unsafe { + JS_SetGCCallback(runtime.rt(), Some(debug_gc_callback), ptr::null_mut()); + } + } + if opts::get().gc_profile { + unsafe { + SetGCSliceCallback(runtime.rt(), Some(gc_slice_callback)); + } + } + + unsafe { + unsafe extern "C" fn empty_wrapper_callback(_: *mut JSContext, _: *mut JSObject) -> bool { true } + SetDOMCallbacks(runtime.rt(), &DOM_CALLBACKS); + SetPreserveWrapperCallback(runtime.rt(), Some(empty_wrapper_callback)); + // Pre barriers aren't working correctly at the moment + DisableIncrementalGC(runtime.rt()); + } + + runtime +} + +#[allow(unsafe_code)] +pub fn get_reports(cx: *mut JSContext, path_seg: String) -> Vec { + let mut reports = vec![]; + + unsafe { + let rt = JS_GetRuntime(cx); + let mut stats = ::std::mem::zeroed(); + if CollectServoSizes(rt, &mut stats) { + let mut report = |mut path_suffix, kind, size| { + let mut path = path![path_seg, "js"]; + path.append(&mut path_suffix); + reports.push(Report { + path: path, + kind: kind, + size: size as usize, + }) + }; + + // A note about possibly confusing terminology: the JS GC "heap" is allocated via + // mmap/VirtualAlloc, which means it's not on the malloc "heap", so we use + // `ExplicitNonHeapSize` as its kind. + + report(path!["gc-heap", "used"], + ReportKind::ExplicitNonHeapSize, + stats.gcHeapUsed); + + report(path!["gc-heap", "unused"], + ReportKind::ExplicitNonHeapSize, + stats.gcHeapUnused); + + report(path!["gc-heap", "admin"], + ReportKind::ExplicitNonHeapSize, + stats.gcHeapAdmin); + + report(path!["gc-heap", "decommitted"], + ReportKind::ExplicitNonHeapSize, + stats.gcHeapDecommitted); + + // SpiderMonkey uses the system heap, not jemalloc. + report(path!["malloc-heap"], + ReportKind::ExplicitSystemHeapSize, + stats.mallocHeap); + + report(path!["non-heap"], + ReportKind::ExplicitNonHeapSize, + stats.nonHeap); + } + } + reports +} + +thread_local!(static GC_CYCLE_START: Cell> = Cell::new(None)); +thread_local!(static GC_SLICE_START: Cell> = Cell::new(None)); + +#[allow(unsafe_code)] +unsafe extern "C" fn gc_slice_callback(_rt: *mut JSRuntime, progress: GCProgress, desc: *const GCDescription) { + match progress { + GCProgress::GC_CYCLE_BEGIN => { + GC_CYCLE_START.with(|start| { + start.set(Some(now())); + println!("GC cycle began"); + }) + }, + GCProgress::GC_SLICE_BEGIN => { + GC_SLICE_START.with(|start| { + start.set(Some(now())); + println!("GC slice began"); + }) + }, + GCProgress::GC_SLICE_END => { + GC_SLICE_START.with(|start| { + let dur = now() - start.get().unwrap(); + start.set(None); + println!("GC slice ended: duration={}", dur); + }) + }, + GCProgress::GC_CYCLE_END => { + GC_CYCLE_START.with(|start| { + let dur = now() - start.get().unwrap(); + start.set(None); + println!("GC cycle ended: duration={}", dur); + }) + }, + }; + if !desc.is_null() { + let desc: &GCDescription = &*desc; + let invocationKind = match desc.invocationKind_ { + JSGCInvocationKind::GC_NORMAL => "GC_NORMAL", + JSGCInvocationKind::GC_SHRINK => "GC_SHRINK", + }; + println!(" isCompartment={}, invocationKind={}", desc.isCompartment_, invocationKind); + } + let _ = stdout().flush(); +} + +#[allow(unsafe_code)] +unsafe extern "C" fn debug_gc_callback(_rt: *mut JSRuntime, status: JSGCStatus, _data: *mut libc::c_void) { + match status { + JSGCStatus::JSGC_BEGIN => thread_state::enter(thread_state::IN_GC), + JSGCStatus::JSGC_END => thread_state::exit(thread_state::IN_GC), + } +} + +#[allow(unsafe_code)] +unsafe extern fn trace_rust_roots(tr: *mut JSTracer, _data: *mut libc::c_void) { + trace_thread(tr); + trace_traceables(tr); + trace_roots(tr); +} diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 6726a6ca4e2..99c5d25169f 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -27,11 +27,11 @@ use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, Documen use dom::bindings::conversions::{FromJSValConvertible, StringificationBehavior}; use dom::bindings::global::GlobalRef; use dom::bindings::inheritance::Castable; -use dom::bindings::js::{JS, MutNullableHeap, Root, RootCollection, trace_roots}; +use dom::bindings::js::{JS, MutNullableHeap, Root, RootCollection}; use dom::bindings::js::{RootCollectionPtr, RootedReference}; -use dom::bindings::refcounted::{LiveDOMReferences, Trusted, TrustedReference, trace_refcounted_objects}; -use dom::bindings::trace::{JSTraceable, trace_traceables}; -use dom::bindings::utils::{DOM_CALLBACKS, WRAP_CALLBACKS}; +use dom::bindings::refcounted::{LiveDOMReferences, Trusted}; +use dom::bindings::trace::JSTraceable; +use dom::bindings::utils::WRAP_CALLBACKS; use dom::browsingcontext::BrowsingContext; use dom::document::{Document, DocumentProgressHandler, DocumentSource, FocusType, IsHTMLDocument}; use dom::element::Element; @@ -51,18 +51,12 @@ use hyper::method::Method; use hyper::mime::{Mime, SubLevel, TopLevel}; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; -use js::glue::CollectServoSizes; use js::jsapi::{DOMProxyShadowsResult, HandleId, HandleObject, RootedValue}; -use js::jsapi::{DisableIncrementalGC, JS_AddExtraGCRootsTracer, JS_SetWrapObjectCallbacks}; -use js::jsapi::{GCDescription, GCProgress, JSGCInvocationKind, SetGCSliceCallback}; -use js::jsapi::{JSAutoRequest, JSGCStatus, JS_GetRuntime, JS_SetGCCallback, SetDOMCallbacks}; -use js::jsapi::{JSContext, JSRuntime, JSTracer}; -use js::jsapi::{JSObject, RuntimeOptionsRef, SetPreserveWrapperCallback}; +use js::jsapi::{JSAutoRequest, JSContext, JS_SetWrapObjectCallbacks, JSTracer}; use js::jsval::UndefinedValue; use js::rust::Runtime; use layout_interface::{ReflowQueryType}; use layout_interface::{self, LayoutChan, NewLayoutThreadInfo, ScriptLayoutChan}; -use libc; use mem::heap_size_of_self_and_children; use msg::constellation_msg::{ConstellationChan, LoadData}; use msg::constellation_msg::{PipelineId, PipelineNamespace}; @@ -78,6 +72,8 @@ use parse::html::{ParseContext, parse_html}; use parse::xml::{self, parse_xml}; use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan}; use profile_traits::time::{self, ProfilerCategory, profile}; +use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory}; +use script_runtime::{ScriptPort, StackRootTLS, new_rt_and_cx, get_reports}; use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent}; use script_traits::CompositorEvent::{TouchEvent, TouchpadPressureEvent}; use script_traits::{CompositorEvent, ConstellationControlMsg, EventResult}; @@ -89,10 +85,7 @@ use std::any::Any; use std::borrow::ToOwned; use std::cell::{Cell, RefCell}; use std::collections::HashSet; -use std::io::{Write, stdout}; -use std::marker::PhantomData; use std::option::Option; -use std::ptr; use std::rc::Rc; use std::result::Result; use std::sync::atomic::{Ordering, AtomicBool}; @@ -105,7 +98,7 @@ use task_source::file_reading::FileReadingTaskSource; use task_source::history_traversal::HistoryTraversalTaskSource; use task_source::networking::NetworkingTaskSource; use task_source::user_interaction::UserInteractionTaskSource; -use time::{Tm, now}; +use time::Tm; use url::Url; use util::opts; use util::prefs::get_pref; @@ -117,15 +110,12 @@ use webdriver_handlers; thread_local!(pub static STACK_ROOTS: Cell> = Cell::new(None)); thread_local!(static SCRIPT_THREAD_ROOT: RefCell> = RefCell::new(None)); -unsafe extern fn trace_rust_roots(tr: *mut JSTracer, _data: *mut libc::c_void) { +pub unsafe fn trace_thread(tr: *mut JSTracer) { SCRIPT_THREAD_ROOT.with(|root| { if let Some(script_thread) = *root.borrow() { (*script_thread).trace(tr); } }); - - trace_traceables(tr); - trace_roots(tr); } /// A document load that is in the process of fetching the requested resource. Contains @@ -216,39 +206,6 @@ enum MixedMessage { FromScheduler(TimerEvent), } -/// Common messages used to control the event loops in both the script and the worker -pub enum CommonScriptMsg { - /// Requests that the script thread measure its memory usage. The results are sent back via the - /// supplied channel. - CollectReports(ReportsChan), - /// A DOM object's last pinned reference was removed (dispatched to all threads). - RefcountCleanup(TrustedReference), - /// Generic message that encapsulates event handling. - RunnableMsg(ScriptThreadEventCategory, Box), -} - -#[derive(Clone, Copy, Debug, Eq, Hash, JSTraceable, PartialEq)] -pub enum ScriptThreadEventCategory { - AttachLayout, - ConstellationMsg, - DevtoolsMsg, - DocumentEvent, - DomEvent, - FileRead, - FormPlannedNavigation, - ImageCacheMsg, - InputEvent, - NetworkEvent, - Resize, - ScriptEvent, - SetViewport, - StylesheetLoad, - TimerEvent, - UpdateReplacedElement, - WebSocketEvent, - WorkerEvent, -} - /// Messages used to control the script event loop pub enum MainThreadScriptMsg { /// Common variants associated with the script messages @@ -265,27 +222,12 @@ pub enum MainThreadScriptMsg { DOMManipulation(DOMManipulationTask), } -/// A cloneable interface for communicating with an event loop. -pub trait ScriptChan { - /// Send a message to the associated event loop. - fn send(&self, msg: CommonScriptMsg) -> Result<(), ()>; - /// Clone this handle. - fn clone(&self) -> Box; -} - impl OpaqueSender for Box { fn send(&self, msg: CommonScriptMsg) { ScriptChan::send(&**self, msg).unwrap(); } } -/// An interface for receiving ScriptMsg values in an event loop. Used for synchronous DOM -/// APIs that need to abstract over multiple kinds of event loops (worker/main thread) with -/// different Receiver interfaces. -pub trait ScriptPort { - fn recv(&self) -> Result; -} - impl ScriptPort for Receiver { fn recv(&self) -> Result { self.recv().map_err(|_| ()) @@ -362,24 +304,6 @@ impl MainThreadScriptChan { } } -pub struct StackRootTLS<'a>(PhantomData<&'a u32>); - -impl<'a> StackRootTLS<'a> { - pub fn new(roots: &'a RootCollection) -> StackRootTLS<'a> { - STACK_ROOTS.with(|ref r| { - r.set(Some(RootCollectionPtr(roots as *const _))) - }); - StackRootTLS(PhantomData) - } -} - -impl<'a> Drop for StackRootTLS<'a> { - fn drop(&mut self) { - STACK_ROOTS.with(|ref r| r.set(None)); - } -} - - /// Information for an entire page. Pages are top-level browsing contexts and can contain multiple /// frames. #[derive(JSTraceable)] @@ -561,56 +485,6 @@ impl ScriptThreadFactory for ScriptThread { } } -thread_local!(static GC_CYCLE_START: Cell> = Cell::new(None)); -thread_local!(static GC_SLICE_START: Cell> = Cell::new(None)); - -unsafe extern "C" fn gc_slice_callback(_rt: *mut JSRuntime, progress: GCProgress, desc: *const GCDescription) { - match progress { - GCProgress::GC_CYCLE_BEGIN => { - GC_CYCLE_START.with(|start| { - start.set(Some(now())); - println!("GC cycle began"); - }) - }, - GCProgress::GC_SLICE_BEGIN => { - GC_SLICE_START.with(|start| { - start.set(Some(now())); - println!("GC slice began"); - }) - }, - GCProgress::GC_SLICE_END => { - GC_SLICE_START.with(|start| { - let dur = now() - start.get().unwrap(); - start.set(None); - println!("GC slice ended: duration={}", dur); - }) - }, - GCProgress::GC_CYCLE_END => { - GC_CYCLE_START.with(|start| { - let dur = now() - start.get().unwrap(); - start.set(None); - println!("GC cycle ended: duration={}", dur); - }) - }, - }; - if !desc.is_null() { - let desc: &GCDescription = &*desc; - let invocationKind = match desc.invocationKind_ { - JSGCInvocationKind::GC_NORMAL => "GC_NORMAL", - JSGCInvocationKind::GC_SHRINK => "GC_SHRINK", - }; - println!(" isCompartment={}, invocationKind={}", desc.isCompartment_, invocationKind); - } - let _ = stdout().flush(); -} - -unsafe extern "C" fn debug_gc_callback(_rt: *mut JSRuntime, status: JSGCStatus, _data: *mut libc::c_void) { - match status { - JSGCStatus::JSGC_BEGIN => thread_state::enter(thread_state::IN_GC), - JSGCStatus::JSGC_END => thread_state::exit(thread_state::IN_GC), - } -} - pub unsafe extern "C" fn shadow_check_callback(_cx: *mut JSContext, _object: HandleObject, _id: HandleId) -> DOMProxyShadowsResult { // XXX implement me @@ -647,7 +521,7 @@ impl ScriptThread { port: Receiver, chan: Sender) -> ScriptThread { - let runtime = ScriptThread::new_rt_and_cx(); + let runtime = new_rt_and_cx(); unsafe { JS_SetWrapObjectCallbacks(runtime.rt(), @@ -711,47 +585,6 @@ impl ScriptThread { } } - pub fn new_rt_and_cx() -> Runtime { - LiveDOMReferences::initialize(); - let runtime = Runtime::new(); - - unsafe { - JS_AddExtraGCRootsTracer(runtime.rt(), Some(trace_rust_roots), ptr::null_mut()); - JS_AddExtraGCRootsTracer(runtime.rt(), Some(trace_refcounted_objects), ptr::null_mut()); - } - - // Needed for debug assertions about whether GC is running. - if cfg!(debug_assertions) { - unsafe { - JS_SetGCCallback(runtime.rt(), Some(debug_gc_callback), ptr::null_mut()); - } - } - if opts::get().gc_profile { - unsafe { - SetGCSliceCallback(runtime.rt(), Some(gc_slice_callback)); - } - } - - unsafe { - unsafe extern "C" fn empty_wrapper_callback(_: *mut JSContext, _: *mut JSObject) -> bool { true } - SetDOMCallbacks(runtime.rt(), &DOM_CALLBACKS); - SetPreserveWrapperCallback(runtime.rt(), Some(empty_wrapper_callback)); - // Pre barriers aren't working correctly at the moment - DisableIncrementalGC(runtime.rt()); - } - - // Enable or disable the JITs. - let rt_opts = unsafe { &mut *RuntimeOptionsRef(runtime.rt()) }; - if let Some(val) = get_pref("js.baseline.enabled").as_boolean() { - rt_opts.set_baseline_(val); - } - if let Some(val) = get_pref("js.ion.enabled").as_boolean() { - rt_opts.set_ion_(val); - } - - runtime - } - // Return the root page in the frame tree. Panics if it doesn't exist. pub fn root_page(&self) -> Rc { self.page.borrow().as_ref().unwrap().clone() @@ -1292,56 +1125,6 @@ impl ScriptThread { chan.send(ConstellationMsg::LoadComplete(pipeline)).unwrap(); } - pub fn get_reports(cx: *mut JSContext, path_seg: String) -> Vec { - let mut reports = vec![]; - - unsafe { - let rt = JS_GetRuntime(cx); - let mut stats = ::std::mem::zeroed(); - if CollectServoSizes(rt, &mut stats) { - let mut report = |mut path_suffix, kind, size| { - let mut path = path![path_seg, "js"]; - path.append(&mut path_suffix); - reports.push(Report { - path: path, - kind: kind, - size: size as usize, - }) - }; - - // A note about possibly confusing terminology: the JS GC "heap" is allocated via - // mmap/VirtualAlloc, which means it's not on the malloc "heap", so we use - // `ExplicitNonHeapSize` as its kind. - - report(path!["gc-heap", "used"], - ReportKind::ExplicitNonHeapSize, - stats.gcHeapUsed); - - report(path!["gc-heap", "unused"], - ReportKind::ExplicitNonHeapSize, - stats.gcHeapUnused); - - report(path!["gc-heap", "admin"], - ReportKind::ExplicitNonHeapSize, - stats.gcHeapAdmin); - - report(path!["gc-heap", "decommitted"], - ReportKind::ExplicitNonHeapSize, - stats.gcHeapDecommitted); - - // SpiderMonkey uses the system heap, not jemalloc. - report(path!["malloc-heap"], - ReportKind::ExplicitSystemHeapSize, - stats.mallocHeap); - - report(path!["non-heap"], - ReportKind::ExplicitNonHeapSize, - stats.nonHeap); - } - } - reports - } - fn collect_reports(&self, reports_chan: ReportsChan) { let mut urls = vec![]; let mut dom_tree_size = 0; @@ -1366,7 +1149,7 @@ impl ScriptThread { } } let path_seg = format!("url({})", urls.join(", ")); - reports.extend(ScriptThread::get_reports(self.get_cx(), path_seg)); + reports.extend(get_reports(self.get_cx(), path_seg)); reports_chan.send(reports); } diff --git a/components/script/task_source/file_reading.rs b/components/script/task_source/file_reading.rs index 30e9530a76d..7eda4d73ff6 100644 --- a/components/script/task_source/file_reading.rs +++ b/components/script/task_source/file_reading.rs @@ -2,7 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use script_thread::{CommonScriptMsg, MainThreadScriptMsg, ScriptChan}; +use script_runtime::{CommonScriptMsg, ScriptChan}; +use script_thread::MainThreadScriptMsg; use std::sync::mpsc::Sender; #[derive(JSTraceable)] diff --git a/components/script/task_source/history_traversal.rs b/components/script/task_source/history_traversal.rs index c2d276e6eec..e5887264cf6 100644 --- a/components/script/task_source/history_traversal.rs +++ b/components/script/task_source/history_traversal.rs @@ -2,7 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use script_thread::{CommonScriptMsg, MainThreadScriptMsg, ScriptChan}; +use script_runtime::{ScriptChan, CommonScriptMsg}; +use script_thread::MainThreadScriptMsg; use std::sync::mpsc::Sender; #[derive(JSTraceable)] diff --git a/components/script/task_source/networking.rs b/components/script/task_source/networking.rs index 83160468395..4f85ac6c3e6 100644 --- a/components/script/task_source/networking.rs +++ b/components/script/task_source/networking.rs @@ -2,7 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use script_thread::{CommonScriptMsg, MainThreadScriptMsg, ScriptChan}; +use script_runtime::{CommonScriptMsg, ScriptChan}; +use script_thread::MainThreadScriptMsg; use std::sync::mpsc::Sender; #[derive(JSTraceable)] diff --git a/components/script/task_source/user_interaction.rs b/components/script/task_source/user_interaction.rs index 254b0d008d1..8f79b8ddaed 100644 --- a/components/script/task_source/user_interaction.rs +++ b/components/script/task_source/user_interaction.rs @@ -2,7 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use script_thread::{CommonScriptMsg, MainThreadScriptMsg, ScriptChan}; +use script_runtime::{CommonScriptMsg, ScriptChan}; +use script_thread::MainThreadScriptMsg; use std::sync::mpsc::Sender; #[derive(JSTraceable)]