Store instruction counter in local, use it for loop limits

This commit is contained in:
Fabian 2020-12-31 19:14:33 -06:00
parent 28800164cc
commit a238684de6
9 changed files with 59 additions and 48 deletions

View file

@ -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
{

View file

@ -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;

View file

@ -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) {

View file

@ -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();

View file

@ -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;

View file

@ -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();

View file

@ -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;

View file

@ -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();

View file

@ -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)
{