diff --git a/src/browser/print_stats.js b/src/browser/print_stats.js index f4ea525d..d8f72a73 100644 --- a/src/browser/print_stats.js +++ b/src/browser/print_stats.js @@ -152,9 +152,9 @@ const print_stats = { text += "wasm memory size: " + (cpu.wasm_memory.buffer.byteLength >> 20) + "m\n"; text += "Config:\n"; - text += "MAX_PAGES=" + cpu.wm.exports["get_config"](0) + "\n"; - text += "JIT_USE_LOOP_SAFETY=" + cpu.wm.exports["get_config"](1) + "\n"; - text += "MAX_EXTRA_BASIC_BLOCKS=" + cpu.wm.exports["get_config"](2) + "\n"; + text += "MAX_PAGES=" + cpu.wm.exports["get_jit_config"](0) + "\n"; + text += "JIT_USE_LOOP_SAFETY=" + Boolean(cpu.wm.exports["get_jit_config"](1)) + "\n"; + text += "MAX_EXTRA_BASIC_BLOCKS=" + cpu.wm.exports["get_jit_config"](2) + "\n"; return text; }, diff --git a/src/rust/control_flow.rs b/src/rust/control_flow.rs index a1acc5b9..ae43116b 100644 --- a/src/rust/control_flow.rs +++ b/src/rust/control_flow.rs @@ -276,7 +276,9 @@ pub fn loopify(nodes: &Graph) -> Vec { //); } - if entries_to_group.len() * group.len() > MAX_EXTRA_BASIC_BLOCKS { + let max_extra_basic_blocks = unsafe { MAX_EXTRA_BASIC_BLOCKS } as usize; + + if entries_to_group.len() * group.len() > max_extra_basic_blocks { let mut subgroup_edges: Graph = Graph::new(); for elem in group { subgroup_edges.insert( diff --git a/src/rust/jit.rs b/src/rust/jit.rs index 9a9aec24..9981322b 100644 --- a/src/rust/jit.rs +++ b/src/rust/jit.rs @@ -56,18 +56,27 @@ pub fn jit_clear_func(wasm_table_index: WasmTableIndex) { unsafe { unsafe_jit::jit_clear_func(wasm_table_index) } } -// less branches will generate if-else, more will generate brtable -pub const BRTABLE_CUTOFF: usize = 10; +// Maximum number of pages per wasm module. Necessary for the following reasons: +// - There is an upper limit on the size of a single function in wasm (currently ~7MB in all browsers) +// See https://github.com/WebAssembly/design/issues/1138 +// - v8 poorly handles large br_table elements and OOMs on modules much smaller than the above limit +// See https://bugs.chromium.org/p/v8/issues/detail?id=9697 and https://bugs.chromium.org/p/v8/issues/detail?id=9141 +// Will hopefully be fixed in the near future by generating direct control flow +static mut MAX_PAGES: u32 = 3; -pub const WASM_TABLE_SIZE: u32 = 900; +static mut JIT_USE_LOOP_SAFETY: bool = true; -pub const CHECK_JIT_STATE_INVARIANTS: bool = false; - -pub const JIT_USE_LOOP_SAFETY: bool = true; +pub static mut MAX_EXTRA_BASIC_BLOCKS: u32 = 250; pub const JIT_THRESHOLD: u32 = 200 * 1000; -pub const MAX_EXTRA_BASIC_BLOCKS: usize = 250; +// less branches will generate if-else, more will generate brtable +pub const BRTABLE_CUTOFF: usize = 10; + +// needs to be synced to const.js +pub const WASM_TABLE_SIZE: u32 = 900; + +pub const CHECK_JIT_STATE_INVARIANTS: bool = false; const MAX_INSTRUCTION_LENGTH: u32 = 16; @@ -372,14 +381,6 @@ pub fn jit_find_cache_entry_in_page( return -1; } -// Maximum number of pages per wasm module. Necessary for the following reasons: -// - There is an upper limit on the size of a single function in wasm (currently ~7MB in all browsers) -// See https://github.com/WebAssembly/design/issues/1138 -// - v8 poorly handles large br_table elements and OOMs on modules much smaller than the above limit -// See https://bugs.chromium.org/p/v8/issues/detail?id=9697 and https://bugs.chromium.org/p/v8/issues/detail?id=9141 -// Will hopefully be fixed in the near future by generating direct control flow -const MAX_PAGES: usize = 3; - fn jit_find_basic_blocks( ctx: &mut JitState, entry_points: HashSet, @@ -390,7 +391,7 @@ fn jit_find_basic_blocks( ctx: &mut JitState, pages: &mut HashSet, page_blacklist: &mut HashSet, - max_pages: usize, + max_pages: u32, marked_as_entry: &mut HashSet, to_visit_stack: &mut Vec, ) -> Option { @@ -407,7 +408,7 @@ fn jit_find_basic_blocks( let phys_page = Page::page_of(phys_target); - if !pages.contains(&phys_page) && pages.len() == max_pages + if !pages.contains(&phys_page) && pages.len() as u32 == max_pages || page_blacklist.contains(&phys_page) { return None; @@ -453,7 +454,7 @@ fn jit_find_basic_blocks( } pages.insert(phys_page); - dbg_assert!(pages.len() <= max_pages); + dbg_assert!(pages.len() as u32 <= max_pages); } to_visit_stack.push(virt_target); @@ -467,7 +468,12 @@ fn jit_find_basic_blocks( let mut page_blacklist = HashSet::new(); // 16-bit doesn't not work correctly, most likely due to instruction pointer wrap-around - let max_pages = if cpu.state_flags.is_32() { MAX_PAGES } else { 1 }; + let max_pages = if cpu.state_flags.is_32() { + unsafe { MAX_PAGES } + } + else { + 1 + }; for virt_addr in entry_points { let ok = follow_jump( @@ -712,7 +718,7 @@ fn jit_find_basic_blocks( basic_blocks.insert(current_block.addr, current_block); } - dbg_assert!(pages.len() <= max_pages); + dbg_assert!(pages.len() as u32 <= max_pages); for block in basic_blocks.values_mut() { if marked_as_entry.contains(&block.virt_addr) { @@ -935,7 +941,7 @@ fn jit_analyze_and_generate( dbg_assert!(wasm_table_index != WasmTableIndex(0)); dbg_assert!(!pages.is_empty()); - dbg_assert!(pages.len() <= MAX_PAGES); + dbg_assert!(pages.len() <= unsafe { MAX_PAGES } as usize); let basic_block_by_addr: HashMap = basic_blocks.into_iter().map(|b| (b.addr, b)).collect(); @@ -1152,7 +1158,7 @@ fn jit_generate_module( let exit_label = builder.block_void(); let exit_with_fault_label = builder.block_void(); let main_loop_label = builder.loop_void(); - if JIT_USE_LOOP_SAFETY { + if unsafe { JIT_USE_LOOP_SAFETY } { builder.get_local(&instruction_counter); builder.const_i32(cpu::LOOP_COUNTER); builder.geu_i32(); @@ -1822,7 +1828,7 @@ fn jit_generate_module( codegen::gen_set_eip_low_bits(ctx.builder, addr as i32 & 0xFFF); profiler::stat_increment(stat::COMPILE_WITH_LOOP_SAFETY); codegen::gen_profiler_stat_increment(ctx.builder, stat::LOOP_SAFETY); - if JIT_USE_LOOP_SAFETY { + if unsafe { JIT_USE_LOOP_SAFETY } { ctx.builder.get_local(&ctx.instruction_counter); ctx.builder.const_i32(cpu::LOOP_COUNTER); ctx.builder.geu_i32(); @@ -2393,8 +2399,17 @@ pub fn enter_basic_block(phys_eip: u32) { } #[no_mangle] -#[cfg(feature = "profiler")] -pub fn get_config(index: u32) -> u32 { +pub unsafe fn set_jit_config(index: u32, value: u32) { + match index { + 0 => MAX_PAGES = value, + 1 => JIT_USE_LOOP_SAFETY = value != 0, + 2 => MAX_EXTRA_BASIC_BLOCKS = value, + _ => dbg_assert!(false), + } +} + +#[no_mangle] +pub unsafe fn get_jit_config(index: u32) -> u32 { match index { 0 => MAX_PAGES as u32, 1 => JIT_USE_LOOP_SAFETY as u32,