From 1bec1934153479de7ef3ebd17d78562c048356ba Mon Sep 17 00:00:00 2001 From: Jack Moffitt Date: Wed, 6 Apr 2016 17:00:48 -0600 Subject: [PATCH] Use better JS engine defaults 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. This also adds back in the options that were accidentally deleted when \#10342 was rebased, which moved things from script_thread.rs to script_runtime.rs. --- components/script/script_runtime.rs | 177 ++++++++++++++++++++++++++++ components/script/script_thread.rs | 3 +- components/util/prefs.rs | 18 ++- resources/prefs.json | 35 ++++++ 4 files changed, 230 insertions(+), 3 deletions(-) diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs index 509a7e93e71..6147fc8bd2b 100644 --- a/components/script/script_runtime.rs +++ b/components/script/script_runtime.rs @@ -13,6 +13,8 @@ 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; @@ -130,6 +132,181 @@ pub fn new_rt_and_cx() -> Runtime { 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 } diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index b9027c96390..7cb24e110bc 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -52,7 +52,8 @@ 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}; diff --git a/components/util/prefs.rs b/components/util/prefs.rs index ff7fbbe5a7e..5679233a41f 100644 --- a/components/util/prefs.rs +++ b/components/util/prefs.rs @@ -23,6 +23,7 @@ lazy_static! { pub enum PrefValue { Boolean(bool), String(String), + Number(f64), Missing } @@ -31,6 +32,9 @@ impl 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) @@ -53,6 +57,13 @@ impl PrefValue { _ => None } } + + pub fn as_i64(&self) -> Option { + match *self { + PrefValue::Number(x) => Some(x as i64), + _ => None, + } + } } impl ToJson for PrefValue { @@ -63,7 +74,10 @@ impl ToJson for PrefValue { }, PrefValue::String(ref x) => { Json::String(x.clone()) - } + }, + PrefValue::Number(x) => { + Json::F64(x) + }, PrefValue::Missing => Json::Null } } @@ -136,7 +150,7 @@ pub fn read_prefs_from_file(mut file: T) 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), } } } diff --git a/resources/prefs.json b/resources/prefs.json index 5a9b084a675..cf7cf17ee06 100644 --- a/resources/prefs.json +++ b/resources/prefs.json @@ -5,6 +5,41 @@ "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,