servo: Merge #10445 - Use better JS engine defaults (from metajack:enable-asmjs); r=jdm
authorJack Moffitt <jack@metajack.im>
Tue, 12 Apr 2016 02:07:35 +0500
changeset 338478 3f3e57e89169f4fb7fa4766d2462f711fc096b57
parent 338477 f4f278bd0b2020fbcf5164e698a851fbfc43d51b
child 338479 993f348880a66120f717a4cca374614f58a1a625
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 #10445 - Use better JS engine defaults (from metajack:enable-asmjs); r=jdm This adds in preferences for all the SM 39 available options (as retrieved from Gecko), and uses the same defaults as Gecko. A few properties are not supported yet, and incremental GC is still always disabled regardless of the preference setting. Source-Repo: https://github.com/servo/servo Source-Revision: bc2237ea2ba3beac501ca4347b8118f3dccd9629
servo/components/script/script_runtime.rs
servo/components/script/script_thread.rs
servo/components/util/prefs.rs
servo/resources/prefs.json
--- a/servo/components/script/script_runtime.rs
+++ b/servo/components/script/script_runtime.rs
@@ -8,16 +8,18 @@
 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::{JSGCMode, JSGCParamKey, JS_SetGCParameter, JS_SetGlobalJitCompilerOption};
+use js::jsapi::{JSJitCompilerOption, JS_SetOffthreadIonCompilationEnabled, JS_SetParallelParsingEnabled};
 use js::jsapi::{JSObject, RuntimeOptionsRef, 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;
@@ -125,16 +127,191 @@ pub fn new_rt_and_cx() -> Runtime {
     // 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);
     }
+    if let Some(val) = get_pref("js.asmjs.enabled").as_boolean() {
+        rt_opts.set_asmJS_(val);
+    }
+    if let Some(val) = get_pref("js.strict.enabled").as_boolean() {
+        rt_opts.set_extraWarnings_(val);
+    }
+    // TODO: handle js.strict.debug.enabled
+    // TODO: handle js.throw_on_asmjs_validation_failure (needs new Spidermonkey)
+    if let Some(val) = get_pref("js.native_regexp.enabled").as_boolean() {
+        rt_opts.set_nativeRegExp_(val);
+    }
+    if let Some(val) = get_pref("js.parallel_parsing.enabled").as_boolean() {
+        unsafe { JS_SetParallelParsingEnabled(runtime.rt(), val); }
+    }
+    if let Some(val) = get_pref("js.offthread_compilation_enabled").as_boolean() {
+        unsafe { JS_SetOffthreadIonCompilationEnabled(runtime.rt(), val); }
+    }
+    if let Some(val) = get_pref("js.baseline.unsafe_eager_compilation.enabled").as_boolean() {
+        let trigger: i32 = if val {
+            0
+        } else {
+            -1
+        };
+        unsafe {
+            JS_SetGlobalJitCompilerOption(runtime.rt(),
+                                          JSJitCompilerOption::JSJITCOMPILER_BASELINE_WARMUP_TRIGGER,
+                                          trigger as u32);
+        }
+    }
+    if let Some(val) = get_pref("js.ion.unsafe_eager_compilation.enabled").as_boolean() {
+        let trigger: i64 = if val {
+            0
+        } else {
+            -1
+        };
+        unsafe {
+            JS_SetGlobalJitCompilerOption(runtime.rt(),
+                                          JSJitCompilerOption::JSJITCOMPILER_ION_WARMUP_TRIGGER,
+                                          trigger as u32);
+        }
+    }
+    // TODO: handle js.discard_system_source.enabled
+    // TODO: handle js.asyncstack.enabled (needs new Spidermonkey)
+    // TODO: handle js.throw_on_debugee_would_run (needs new Spidermonkey)
+    // TODO: handle js.dump_stack_on_debugee_would_run (needs new Spidermonkey)
+    if let Some(val) = get_pref("js.werror.enabled").as_boolean() {
+        rt_opts.set_werror_(val);
+    }
+    // TODO: handle js.shared_memory.enabled
+    if let Some(val) = get_pref("js.mem.high_water_mark").as_i64() {
+        unsafe {
+            JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_MAX_MALLOC_BYTES, val as u32 * 1024 * 1024);
+        }
+    }
+    if let Some(val) = get_pref("js.mem.max").as_i64() {
+        let max = if val <= 0 || val >= 0x1000 {
+            -1
+        } else {
+            val * 1024 * 1024
+        };
+        unsafe {
+            JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_MAX_BYTES, max as u32);
+        }
+    }
+    // NOTE: This is disabled above, so enabling it here will do nothing for now.
+    if let Some(val) = get_pref("js.mem.gc.incremental.enabled").as_boolean() {
+        let compartment = if let Some(val) = get_pref("js.mem.gc.per_compartment.enabled").as_boolean() {
+            val
+        } else {
+            false
+        };
+        let mode = if val {
+            JSGCMode::JSGC_MODE_INCREMENTAL
+        } else if compartment {
+            JSGCMode::JSGC_MODE_COMPARTMENT
+        } else {
+            JSGCMode::JSGC_MODE_GLOBAL
+        };
+        unsafe {
+            JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_MODE, mode as u32);
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.incremental.slice_ms").as_i64() {
+        if val >= 0 && val < 100000 {
+            unsafe {
+                JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_SLICE_TIME_BUDGET, val as u32);
+            }
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.compacting.enabled").as_boolean() {
+        unsafe {
+            JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_COMPACTING_ENABLED, val as u32);
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.high_frequency_time_limit_ms").as_i64() {
+        if val >= 0 && val < 10000 {
+            unsafe {
+                JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_HIGH_FREQUENCY_TIME_LIMIT, val as u32);
+            }
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.dynamic_mark_slice.enabled").as_boolean() {
+        unsafe {
+            JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_DYNAMIC_MARK_SLICE, val as u32);
+        }
+    }
+    // TODO: handle js.mem.gc.refresh_frame_slices.enabled
+    if let Some(val) = get_pref("js.mem.gc.dynamic_heap_growth.enabled").as_boolean() {
+        unsafe {
+            JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_DYNAMIC_HEAP_GROWTH, val as u32);
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.low_frequency_heap_growth").as_i64() {
+        if val >= 0 && val < 10000 {
+            unsafe {
+                JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_LOW_FREQUENCY_HEAP_GROWTH, val as u32);
+            }
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.high_frequency_heap_growth_min").as_i64() {
+        if val >= 0 && val < 10000 {
+            unsafe {
+                JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, val as u32);
+            }
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.high_frequency_heap_growth_max").as_i64() {
+        if val >= 0 && val < 10000 {
+            unsafe {
+                JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, val as u32);
+            }
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.high_frequency_low_limit_mb").as_i64() {
+        if val >= 0 && val < 10000 {
+            unsafe {
+                JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_HIGH_FREQUENCY_LOW_LIMIT, val as u32);
+            }
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.high_frequency_high_limit_mb").as_i64() {
+        if val >= 0 && val < 10000 {
+            unsafe {
+                JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_HIGH_FREQUENCY_HIGH_LIMIT, val as u32);
+            }
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.allocation_threshold_mb").as_i64() {
+        if val >= 0 && val < 10000 {
+            unsafe {
+                JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_ALLOCATION_THRESHOLD, val as u32);
+            }
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.decommit_threshold_mb").as_i64() {
+        if val >= 0 && val < 10000 {
+            unsafe {
+                JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_DECOMMIT_THRESHOLD, val as u32);
+            }
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.empty_chunk_count_min").as_i64() {
+        if val >= 0 && val < 10000 {
+            unsafe {
+                JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_MIN_EMPTY_CHUNK_COUNT, val as u32);
+            }
+        }
+    }
+    if let Some(val) = get_pref("js.mem.gc.empty_chunk_count_max").as_i64() {
+        if val >= 0 && val < 10000 {
+            unsafe {
+                JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_MAX_EMPTY_CHUNK_COUNT, val as u32);
+            }
+        }
+    }
 
     runtime
 }
 
 #[allow(unsafe_code)]
 pub fn get_reports(cx: *mut JSContext, path_seg: String) -> Vec<Report> {
     let mut reports = vec![];
 
--- a/servo/components/script/script_thread.rs
+++ b/servo/components/script/script_thread.rs
@@ -47,17 +47,18 @@ use euclid::point::Point2D;
 use gfx_traits::LayerId;
 use hyper::header::{ContentType, HttpDate};
 use hyper::header::{Headers, LastModified};
 use hyper::method::Method;
 use hyper::mime::{Mime, SubLevel, TopLevel};
 use ipc_channel::ipc::{self, IpcSender};
 use ipc_channel::router::ROUTER;
 use js::jsapi::{DOMProxyShadowsResult, HandleId, HandleObject, RootedValue};
-use js::jsapi::{JSAutoRequest, JSContext, JS_SetWrapObjectCallbacks, JSTracer};
+use js::jsapi::{JSAutoRequest, JS_SetWrapObjectCallbacks};
+use js::jsapi::{JSContext, JSTracer};
 use js::jsval::UndefinedValue;
 use js::rust::Runtime;
 use layout_interface::{ReflowQueryType};
 use layout_interface::{self, LayoutChan, NewLayoutThreadInfo, ScriptLayoutChan};
 use mem::heap_size_of_self_and_children;
 use msg::constellation_msg::{ConstellationChan, LoadData};
 use msg::constellation_msg::{PipelineId, PipelineNamespace};
 use msg::constellation_msg::{SubpageId, WindowSizeData};
--- a/servo/components/util/prefs.rs
+++ b/servo/components/util/prefs.rs
@@ -18,24 +18,28 @@ lazy_static! {
         Arc::new(Mutex::new(prefs))
     };
 }
 
 #[derive(PartialEq, Clone, Debug)]
 pub enum PrefValue {
     Boolean(bool),
     String(String),
+    Number(f64),
     Missing
 }
 
 impl PrefValue {
     pub fn from_json(data: Json) -> Result<PrefValue, ()> {
         let value = match data {
             Json::Boolean(x) => PrefValue::Boolean(x),
             Json::String(x) => PrefValue::String(x),
+            Json::F64(x) => PrefValue::Number(x),
+            Json::I64(x) => PrefValue::Number(x as f64),
+            Json::U64(x) => PrefValue::Number(x as f64),
             _ => return Err(())
         };
         Ok(value)
     }
 
     pub fn as_boolean(&self) -> Option<bool> {
         match *self {
             PrefValue::Boolean(value) => {
@@ -48,27 +52,37 @@ impl PrefValue {
     pub fn as_string(&self) -> Option<&str> {
         match *self {
             PrefValue::String(ref value) => {
                 Some(&value)
             },
             _ => None
         }
     }
+
+    pub fn as_i64(&self) -> Option<i64> {
+        match *self {
+            PrefValue::Number(x) => Some(x as i64),
+            _ => None,
+        }
+    }
 }
 
 impl ToJson for PrefValue {
     fn to_json(&self) -> Json {
         match *self {
             PrefValue::Boolean(x) => {
                 Json::Boolean(x)
             },
             PrefValue::String(ref x) => {
                 Json::String(x.clone())
-            }
+            },
+            PrefValue::Number(x) => {
+                Json::F64(x)
+            },
             PrefValue::Missing => Json::Null
         }
     }
 }
 
 #[derive(Debug)]
 pub enum Pref {
     NoDefault(Arc<PrefValue>),
@@ -131,17 +145,17 @@ pub fn read_prefs_from_file<T>(mut file:
 
     let mut prefs = HashMap::new();
     if let Json::Object(obj) = json {
         for (name, value) in obj.into_iter() {
             match Pref::from_json(value) {
                 Ok(x) => {
                     prefs.insert(name, x);
                 },
-                Err(_) => println!("Ignoring non-boolean/string preference value for {:?}", name)
+                Err(_) => println!("Ignoring non-boolean/string/i64 preference value for {:?}", name),
             }
         }
     }
     Ok(prefs)
 }
 
 pub fn extend_prefs(extension: HashMap<String, Pref>) {
     PREFS.lock().unwrap().extend(extension);
--- a/servo/resources/prefs.json
+++ b/servo/resources/prefs.json
@@ -1,15 +1,50 @@
 {
   "dom.forcetouch.enabled": false,
   "dom.mouseevent.which.enabled": false,
   "dom.mozbrowser.enabled": false,
   "gfx.webrender.enabled": false,
   "js.baseline.enabled": true,
   "js.ion.enabled": true,
+  "js.asmjs.enabled": true,
+  "js.strict.enabled": false,
+  "js.strict.debug.enabled": false,
+  "js.throw_on_asmjs_validation_failure.enabled": false,
+  "js.native_regexp.enabled": true,
+  "js.parallel_parsing.enabled": true,
+  "js.ion.offthread_compilation.enabled": true,
+  "js.baseline.unsafe_eager_compilation.enabled": false,
+  "js.ion.unsafe_eager_compilation.enabled": false,
+  "js.discard_system_source.enabled": false,
+  "js.asyncstack.enabled": false,
+  "js.throw_on_debuggee_would_run.enabled": false,
+  "js.dump_stack_on_debuggee_would_run.enabled": false,
+  "js.werror.enabled": false,
+  "js.strict.enabled": false,
+  "js.shared_memory.enabled": true,
+  "js.mem.high_water_mark": 128,
+  "js.mem.max": -1,
+  "js.mem.gc.per_compartment.enabled": true,
+  "js.mem.gc.incremental.enabled": true,
+  "js.mem.gc.incremental.slice_ms": 10,
+  "js.mem.gc.compacting.enabled": true,
+  "js.mem.gc.high_frequency_time_limit_ms": 1000,
+  "js.mem.gc.dynamic_mark_slice.enabled": true,
+  "js.mem.gc.refresh_frame_slices.enabled": true,
+  "js.mem.gc.dynamic_heap_growth.enabled": true,
+  "js.mem.gc.low_frequency_heap_growth": 150,
+  "js.mem.gc.high_frequency_heap_growth_min": 150,
+  "js.mem.gc.high_frequency_heap_growth_max": 300,
+  "js.mem.gc.high_frequency_low_limit_mb": 100,
+  "js.mem.gc.high_frequency_high_limit_mb": 500,
+  "js.mem.gc.allocation_threshold_mb": 30,
+  "js.mem.gc.decommit_threshold_mb": 32,
+  "js.mem.gc.empty_chunk_count_min": 1,
+  "js.mem.gc.empty_chunk_count_max": 30,
   "layout.columns.enabled": false,
   "layout.column-width.enabled": false,
   "layout.column-count.enabled": false,
   "layout.column-gap.enabled": false,
   "layout.flex.enabled": false,
   "layout.flex-direction.enabled": false,
   "layout.text-orientation.enabled": false,
   "layout.viewport.enabled": false,