Store instruction counter in local, use it for loop limits
This commit is contained in:
parent
28800164cc
commit
a238684de6
|
@ -829,7 +829,7 @@ V86Starter.prototype.get_instruction_counter = function()
|
|||
{
|
||||
if(this.v86)
|
||||
{
|
||||
return this.v86.cpu.timestamp_counter[0] >>> 0;
|
||||
return this.v86.cpu.instruction_counter[0] >>> 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -121,7 +121,7 @@ function CPU(bus, wm)
|
|||
vga: null,
|
||||
};
|
||||
|
||||
this.timestamp_counter = v86util.view(Uint32Array, memory, 664, 1);
|
||||
this.instruction_counter = v86util.view(Uint32Array, memory, 664, 1);
|
||||
|
||||
// registers
|
||||
this.reg32 = v86util.view(Int32Array, memory, 64, 8);
|
||||
|
@ -649,7 +649,7 @@ CPU.prototype.reset = function()
|
|||
|
||||
this.last_virt_eip[0] = -1;
|
||||
|
||||
this.timestamp_counter[0] = 0;
|
||||
this.instruction_counter[0] = 0;
|
||||
this.previous_ip[0] = 0;
|
||||
this.in_hlt[0] = +false;
|
||||
|
||||
|
|
|
@ -113,8 +113,14 @@ pub fn gen_page_switch_check(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn gen_increment_timestamp_counter(builder: &mut WasmBuilder, n: i32) {
|
||||
builder.increment_fixed_i32(global_pointers::timestamp_counter as u32, n)
|
||||
pub fn gen_update_instruction_counter(ctx: &mut JitContext) {
|
||||
ctx.builder
|
||||
.const_i32(global_pointers::instruction_counter as i32);
|
||||
ctx.builder
|
||||
.load_fixed_i32(global_pointers::instruction_counter as u32);
|
||||
ctx.builder.get_local(&ctx.instruction_counter);
|
||||
ctx.builder.add_i32();
|
||||
ctx.builder.store_aligned_i32(0);
|
||||
}
|
||||
|
||||
pub fn gen_get_reg8(ctx: &mut JitContext, r: u32) {
|
||||
|
|
|
@ -2392,7 +2392,7 @@ pub unsafe fn cycle_internal() {
|
|||
|
||||
if entry != jit::CachedCode::NONE {
|
||||
profiler::stat_increment(RUN_FROM_CACHE);
|
||||
let initial_tsc = *timestamp_counter;
|
||||
let initial_instruction_counter = *instruction_counter;
|
||||
let wasm_table_index = entry.wasm_table_index;
|
||||
let initial_state = entry.initial_state;
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -2410,9 +2410,12 @@ pub unsafe fn cycle_internal() {
|
|||
}
|
||||
profiler::stat_increment_by(
|
||||
RUN_FROM_CACHE_STEPS,
|
||||
(*timestamp_counter - initial_tsc) as u64,
|
||||
(*instruction_counter - initial_instruction_counter) as u64,
|
||||
);
|
||||
dbg_assert!(
|
||||
*instruction_counter != initial_instruction_counter,
|
||||
"Instruction counter didn't change"
|
||||
);
|
||||
dbg_assert!(*timestamp_counter != initial_tsc, "TSC didn't change");
|
||||
|
||||
if cfg!(feature = "profiler") {
|
||||
dbg_assert!(match ::cpu::cpu::debug_last_jump {
|
||||
|
@ -2462,7 +2465,7 @@ pub unsafe fn cycle_internal() {
|
|||
dbg_assert!(must_not_fault);
|
||||
must_not_fault = false
|
||||
}
|
||||
let initial_tsc = *timestamp_counter;
|
||||
let initial_instruction_counter = *instruction_counter;
|
||||
jit_run_interpreted(phys_addr as i32);
|
||||
|
||||
jit::jit_increase_hotness_and_maybe_compile(
|
||||
|
@ -2470,21 +2473,24 @@ pub unsafe fn cycle_internal() {
|
|||
phys_addr,
|
||||
get_seg_cs() as u32,
|
||||
state_flags,
|
||||
*timestamp_counter - initial_tsc,
|
||||
*instruction_counter - initial_instruction_counter,
|
||||
);
|
||||
|
||||
profiler::stat_increment_by(
|
||||
RUN_INTERPRETED_STEPS,
|
||||
(*timestamp_counter - initial_tsc) as u64,
|
||||
(*instruction_counter - initial_instruction_counter) as u64,
|
||||
);
|
||||
dbg_assert!(
|
||||
*instruction_counter != initial_instruction_counter,
|
||||
"Instruction counter didn't change"
|
||||
);
|
||||
dbg_assert!(*timestamp_counter != initial_tsc, "TSC didn't change");
|
||||
};
|
||||
}
|
||||
else {
|
||||
*previous_ip = *instruction_pointer;
|
||||
|
||||
let opcode = return_on_pagefault!(read_imm8());
|
||||
*timestamp_counter += 1;
|
||||
*instruction_counter += 1;
|
||||
dbg_assert!(*prefixes == 0);
|
||||
run_instruction(opcode | (*is_32 as i32) << 8);
|
||||
dbg_assert!(*prefixes == 0);
|
||||
|
@ -2515,7 +2521,7 @@ unsafe fn jit_run_interpreted(phys_addr: i32) {
|
|||
jit_block_boundary = false;
|
||||
let opcode = *mem8.offset(phys_addr as isize) as i32;
|
||||
*instruction_pointer += 1;
|
||||
*timestamp_counter += 1;
|
||||
*instruction_counter += 1;
|
||||
dbg_assert!(*prefixes == 0);
|
||||
run_instruction(opcode | (*is_32 as i32) << 8);
|
||||
dbg_assert!(*prefixes == 0);
|
||||
|
@ -2554,7 +2560,7 @@ unsafe fn jit_run_interpreted(phys_addr: i32) {
|
|||
};
|
||||
}
|
||||
|
||||
*timestamp_counter += 1;
|
||||
*instruction_counter += 1;
|
||||
|
||||
//if DEBUG {
|
||||
// logop(*previous_ip, opcode_0);
|
||||
|
@ -2601,8 +2607,8 @@ pub unsafe fn segment_prefix_op(seg: i32) {
|
|||
#[no_mangle]
|
||||
pub unsafe fn do_many_cycles_native() {
|
||||
profiler::stat_increment(DO_MANY_CYCLES);
|
||||
let initial_timestamp_counter = *timestamp_counter;
|
||||
while (*timestamp_counter).wrapping_sub(initial_timestamp_counter) < LOOP_COUNTER as u32
|
||||
let initial_instruction_counter = *instruction_counter;
|
||||
while (*instruction_counter).wrapping_sub(initial_instruction_counter) < LOOP_COUNTER as u32
|
||||
&& !*in_hlt
|
||||
{
|
||||
cycle_internal();
|
||||
|
|
|
@ -36,7 +36,7 @@ pub const sysenter_cs: *mut i32 = 636 as *mut i32;
|
|||
pub const sysenter_esp: *mut i32 = 640 as *mut i32;
|
||||
pub const sysenter_eip: *mut i32 = 644 as *mut i32;
|
||||
pub const prefixes: *mut u8 = 648 as *mut u8;
|
||||
pub const timestamp_counter: *mut u32 = 664 as *mut u32;
|
||||
pub const instruction_counter: *mut u32 = 664 as *mut u32;
|
||||
pub const sreg: *mut u16 = 668 as *mut u16;
|
||||
pub const dreg: *mut i32 = 684 as *mut i32;
|
||||
|
||||
|
|
|
@ -2115,7 +2115,7 @@ pub unsafe fn instr_FB() {
|
|||
else {
|
||||
*prefixes = 0;
|
||||
*previous_ip = *instruction_pointer;
|
||||
*timestamp_counter += 1;
|
||||
*instruction_counter += 1;
|
||||
run_instruction(return_on_pagefault!(read_imm8()) | (is_osize_32() as i32) << 8);
|
||||
|
||||
handle_irqs();
|
||||
|
|
|
@ -64,8 +64,6 @@ pub const HASH_PRIME: u32 = 6151;
|
|||
|
||||
pub const CHECK_JIT_STATE_INVARIANTS: bool = false;
|
||||
|
||||
pub const JIT_MAX_ITERATIONS_PER_FUNCTION: u32 = 100003;
|
||||
|
||||
pub const JIT_USE_LOOP_SAFETY: bool = true;
|
||||
|
||||
pub const JIT_THRESHOLD: u32 = 200 * 1000;
|
||||
|
@ -234,6 +232,7 @@ pub struct JitContext<'a> {
|
|||
pub exit_with_fault_label: Label,
|
||||
pub exit_label: Label,
|
||||
pub last_instruction: Instruction,
|
||||
pub instruction_counter: WasmLocal,
|
||||
}
|
||||
impl<'a> JitContext<'a> {
|
||||
pub fn reg(&self, i: u32) -> WasmLocal { self.register_locals[i as usize].unsafe_clone() }
|
||||
|
@ -1006,23 +1005,16 @@ fn jit_generate_module(
|
|||
})
|
||||
.collect();
|
||||
|
||||
let loop_limit_local = if JIT_USE_LOOP_SAFETY {
|
||||
builder.const_i32(JIT_MAX_ITERATIONS_PER_FUNCTION as i32);
|
||||
Some(builder.set_new_local())
|
||||
}
|
||||
else {
|
||||
None
|
||||
};
|
||||
builder.const_i32(0);
|
||||
let instruction_counter = builder.set_new_local();
|
||||
|
||||
let exit_label = builder.block_void();
|
||||
let exit_with_fault_label = builder.block_void();
|
||||
let main_loop_label = builder.loop_void();
|
||||
if let Some(loop_limit_local) = loop_limit_local.as_ref() {
|
||||
builder.get_local(loop_limit_local);
|
||||
builder.const_i32(-1);
|
||||
builder.add_i32();
|
||||
builder.tee_local(loop_limit_local);
|
||||
builder.eqz_i32();
|
||||
if JIT_USE_LOOP_SAFETY {
|
||||
builder.get_local(&instruction_counter);
|
||||
builder.const_i32(cpu::LOOP_COUNTER);
|
||||
builder.geu_i32();
|
||||
if cfg!(feature = "profiler") {
|
||||
builder.if_void();
|
||||
codegen::gen_debug_track_jit_exit(builder, 0);
|
||||
|
@ -1043,6 +1035,7 @@ fn jit_generate_module(
|
|||
exit_with_fault_label,
|
||||
exit_label,
|
||||
last_instruction: Instruction::Other,
|
||||
instruction_counter,
|
||||
};
|
||||
|
||||
let entry_blocks = {
|
||||
|
@ -1160,6 +1153,7 @@ fn jit_generate_module(
|
|||
codegen::gen_debug_track_jit_exit(ctx.builder, block.last_instruction_addr);
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_fn0_const(ctx.builder, "handle_irqs");
|
||||
codegen::gen_update_instruction_counter(ctx);
|
||||
ctx.builder.return_();
|
||||
continue;
|
||||
}
|
||||
|
@ -1630,20 +1624,18 @@ 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 let Some(loop_limit_local) = loop_limit_local.as_ref() {
|
||||
ctx.builder.get_local(loop_limit_local);
|
||||
ctx.builder.const_i32(-1);
|
||||
ctx.builder.add_i32();
|
||||
ctx.builder.tee_local(loop_limit_local);
|
||||
ctx.builder.eqz_i32();
|
||||
if JIT_USE_LOOP_SAFETY {
|
||||
ctx.builder.get_local(&ctx.instruction_counter);
|
||||
ctx.builder.const_i32(cpu::LOOP_COUNTER);
|
||||
ctx.builder.geu_i32();
|
||||
if cfg!(feature = "profiler") {
|
||||
ctx.builder.if_void();
|
||||
codegen::gen_debug_track_jit_exit(ctx.builder, 0);
|
||||
ctx.builder.br(ctx.exit_label);
|
||||
codegen::gen_debug_track_jit_exit(ctx.builder, addr);
|
||||
ctx.builder.br(exit_label);
|
||||
ctx.builder.block_end();
|
||||
}
|
||||
else {
|
||||
ctx.builder.br_if(ctx.exit_label);
|
||||
ctx.builder.br_if(exit_label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1748,20 +1740,21 @@ fn jit_generate_module(
|
|||
ctx.builder.block_end();
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_fn0_const(ctx.builder, "trigger_fault_end_jit");
|
||||
codegen::gen_update_instruction_counter(ctx);
|
||||
ctx.builder.return_();
|
||||
}
|
||||
{
|
||||
// exit
|
||||
ctx.builder.block_end();
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_update_instruction_counter(ctx);
|
||||
}
|
||||
|
||||
if let Some(local) = loop_limit_local {
|
||||
ctx.builder.free_local(local);
|
||||
}
|
||||
for local in ctx.register_locals.drain(..) {
|
||||
ctx.builder.free_local(local);
|
||||
}
|
||||
ctx.builder
|
||||
.free_local(ctx.instruction_counter.unsafe_clone());
|
||||
|
||||
ctx.builder.finish();
|
||||
|
||||
|
@ -1822,7 +1815,11 @@ fn jit_generate_basic_block(ctx: &mut JitContext, block: &BasicBlock) {
|
|||
ctx.builder.call_fn1("enter_basic_block");
|
||||
}
|
||||
|
||||
codegen::gen_increment_timestamp_counter(ctx.builder, block.number_of_instructions as i32);
|
||||
ctx.builder.get_local(&ctx.instruction_counter);
|
||||
ctx.builder.const_i32(block.number_of_instructions as i32);
|
||||
ctx.builder.add_i32();
|
||||
ctx.builder.set_local(&ctx.instruction_counter);
|
||||
|
||||
ctx.cpu.eip = start_addr;
|
||||
ctx.last_instruction = Instruction::Other;
|
||||
|
||||
|
|
|
@ -4017,6 +4017,8 @@ fn gen_popf(ctx: &mut JitContext, is_32: bool) {
|
|||
codegen::gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
|
||||
codegen::gen_move_registers_from_locals_to_memory(ctx);
|
||||
codegen::gen_fn0_const(ctx.builder, "handle_irqs");
|
||||
|
||||
codegen::gen_update_instruction_counter(ctx);
|
||||
ctx.builder.return_();
|
||||
}
|
||||
ctx.builder.block_end();
|
||||
|
|
|
@ -318,7 +318,7 @@ else {
|
|||
|
||||
emulator.cpu_exception_hook = function(n)
|
||||
{
|
||||
emulator.v86.cpu.timestamp_counter[0] += 100000; // always make progress
|
||||
emulator.v86.cpu.instruction_counter[0] += 100000; // always make progress
|
||||
|
||||
if(waiting_to_receive_next_test)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue