Track last executed jump instruction, check for missed entry points while looking for compiled code

This commit is contained in:
Fabian 2018-09-17 17:14:10 -05:00
parent 7e3f1ad401
commit 7e1d398e05
5 changed files with 143 additions and 9 deletions

View file

@ -25,7 +25,8 @@ const print_stats = {
"RUN_INTERPRETED_PENDING",
"RUN_INTERPRETED_NEAR_END_OF_PAGE",
"RUN_INTERPRETED_DIFFERENT_STATE",
"RUN_INTERPRETED_MISSED_COMPILED_ENTRY",
"RUN_INTERPRETED_MISSED_COMPILED_ENTRY_RUN_INTERPRETED",
"RUN_INTERPRETED_MISSED_COMPILED_ENTRY_LOOKUP",
"RUN_INTERPRETED_STEPS",
"RUN_FROM_CACHE",
"RUN_FROM_CACHE_STEPS",

View file

@ -351,6 +351,7 @@ fn gen_safe_read(ctx: &mut JitContext, bits: BitSize) {
.load_u8(global_pointers::PAGE_FAULT);
builder.instruction_body.if_void();
gen_debug_track_jit_exit(builder, ctx.start_of_current_instruction);
builder.instruction_body.return_();
builder.instruction_body.block_end();
@ -494,6 +495,7 @@ fn gen_safe_write(
.load_u8(global_pointers::PAGE_FAULT);
builder.instruction_body.if_void();
gen_debug_track_jit_exit(builder, ctx.start_of_current_instruction);
builder.instruction_body.return_();
builder.instruction_body.block_end();
@ -698,6 +700,7 @@ pub fn gen_task_switch_test(ctx: &mut JitContext) {
gen_fn0_const(ctx.builder, "task_switch_test_void");
gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
ctx.builder.instruction_body.return_();
ctx.builder.instruction_body.block_end();
@ -717,6 +720,7 @@ pub fn gen_task_switch_test_mmx(ctx: &mut JitContext) {
gen_fn0_const(ctx.builder, "task_switch_test_mmx_void");
gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
ctx.builder.instruction_body.return_();
ctx.builder.instruction_body.block_end();
@ -949,6 +953,7 @@ pub fn gen_safe_read_write(
.load_u8(global_pointers::PAGE_FAULT);
ctx.builder.instruction_body.if_void();
gen_debug_track_jit_exit(ctx.builder, ctx.start_of_current_instruction);
ctx.builder.instruction_body.return_();
ctx.builder.instruction_body.block_end();
@ -961,3 +966,9 @@ pub fn gen_profiler_stat_increment(builder: &mut WasmBuilder, stat: profiler::st
let addr = unsafe { profiler::stat_array.as_mut_ptr().offset(stat as isize) } as u32;
gen_increment_variable(builder, addr, 1)
}
pub fn gen_debug_track_jit_exit(builder: &mut WasmBuilder, address: u32) {
if cfg!(feature = "profiler") {
gen_fn1_const(builder, "track_jit_exit", address);
}
}

View file

@ -67,6 +67,8 @@ pub union reg128 {
pub f64_0: [f64; 2],
}
pub const CHECK_MISSED_ENTRY_POINTS: bool = false;
pub const FLAG_CARRY: i32 = 1;
pub const FLAG_PARITY: i32 = 4;
pub const FLAG_ADJUST: i32 = 16;
@ -248,6 +250,41 @@ pub static mut tsc_offset: u64 = 0;
pub static mut valid_tlb_entries: [i32; 10000] = [0; 10000];
pub static mut valid_tlb_entries_count: i32 = 0;
pub enum LastJump {
Interrupt {
phys_addr: u32,
int: u8,
software: bool,
error: Option<u32>,
},
Compiled {
phys_addr: u32,
},
Interpreted {
phys_addr: u32,
},
None,
}
impl LastJump {
pub fn phys_address(&self) -> Option<u32> {
match self {
LastJump::Interrupt { phys_addr, .. } => Some(*phys_addr),
LastJump::Compiled { phys_addr } => Some(*phys_addr),
LastJump::Interpreted { phys_addr } => Some(*phys_addr),
LastJump::None => None,
}
}
pub fn name(&self) -> &'static str {
match self {
LastJump::Interrupt { .. } => "interrupt",
LastJump::Compiled { .. } => "compiled",
LastJump::Interpreted { .. } => "interpreted",
LastJump::None => "none",
}
}
}
pub static mut debug_last_jump: LastJump = LastJump::None;
pub struct SegmentSelector {
raw: u16,
}
@ -304,6 +341,13 @@ impl SegmentDescriptor {
pub unsafe fn after_block_boundary() { jit_block_boundary = true; }
#[no_mangle]
pub fn track_jit_exit(phys_addr: u32) {
unsafe {
debug_last_jump = LastJump::Compiled { phys_addr };
}
}
pub unsafe fn same_page(addr1: i32, addr2: i32) -> bool { return addr1 & !0xFFF == addr2 & !0xFFF; }
#[no_mangle]
@ -1044,6 +1088,13 @@ pub unsafe fn cycle_internal() {
);
}
else {
#[cfg(feature = "profiler")]
{
if CHECK_MISSED_ENTRY_POINTS {
::jit::check_missed_entry_points(phys_addr, state_flags as u32);
}
}
if DEBUG {
dbg_assert!(!must_not_fault);
must_not_fault = true
@ -1090,6 +1141,12 @@ unsafe fn jit_run_interpreted(phys_addr: i32) {
profiler::stat_increment(S_RUN_INTERPRETED);
dbg_assert!(!in_mapped_range(phys_addr as u32));
if cfg!(debug_assertions) {
debug_last_jump = LastJump::Interpreted {
phys_addr: phys_addr as u32,
};
}
jit_block_boundary = false;
let opcode = *mem8.offset(phys_addr as isize) as i32;
*instruction_pointer += 1;
@ -1102,13 +1159,13 @@ unsafe fn jit_run_interpreted(phys_addr: i32) {
*previous_ip = *instruction_pointer;
let opcode = return_on_pagefault!(read_imm8());
if DEBUG {
if CHECK_MISSED_ENTRY_POINTS {
let phys_addr = return_on_pagefault!(get_phys_eip()) as u32;
let state_flags: CachedStateFlags = pack_current_state_flags();
let entry = ::c_api::jit_find_cache_entry(phys_addr, state_flags as u32);
if entry != 0 {
profiler::stat_increment(S_RUN_INTERPRETED_MISSED_COMPILED_ENTRY);
profiler::stat_increment(S_RUN_INTERPRETED_MISSED_COMPILED_ENTRY_RUN_INTERPRETED);
//dbg_log!(
// "missed entry point at {:x} prev_opcode={:x} opcode={:x}",
// phys_addr,
@ -1118,6 +1175,12 @@ unsafe fn jit_run_interpreted(phys_addr: i32) {
}
}
if cfg!(debug_assertions) {
debug_last_jump = LastJump::Interpreted {
phys_addr: phys_addr as u32,
};
}
*timestamp_counter += 1;
//if DEBUG {

View file

@ -49,7 +49,7 @@ mod jit_cache_array {
pub struct Entry {
pub start_addr: u32,
#[cfg(debug_assertions)]
#[cfg(any(debug_assertions, feature = "profiler"))]
pub len: u32,
#[cfg(debug_assertions)]
@ -82,7 +82,7 @@ mod jit_cache_array {
state_flags,
pending,
#[cfg(debug_assertions)]
#[cfg(any(debug_assertions, feature = "profiler"))]
len: 0,
#[cfg(debug_assertions)]
@ -116,7 +116,7 @@ mod jit_cache_array {
state_flags: CachedStateFlags::EMPTY,
pending: false,
#[cfg(debug_assertions)]
#[cfg(any(debug_assertions, feature = "profiler"))]
len: 0,
#[cfg(debug_assertions)]
opcode: 0,
@ -131,7 +131,7 @@ mod jit_cache_array {
state_flags: CachedStateFlags::EMPTY,
pending: false,
#[cfg(debug_assertions)]
#[cfg(any(debug_assertions, feature = "profiler"))]
len: 0,
#[cfg(debug_assertions)]
opcode: 0,
@ -817,9 +817,13 @@ fn jit_analyze_and_generate(
true,
);
#[cfg(debug_assertions)]
#[cfg(any(debug_assertions, feature = "profiler"))]
{
entry.len = block.end_addr - block.addr;
}
#[cfg(debug_assertions)]
{
entry.opcode = cpu::read32(block.addr);
}
@ -963,6 +967,7 @@ fn jit_generate_module(
.get_local(gen_local_iteration_counter);
builder.instruction_body.eqz_i32();
builder.instruction_body.if_void();
codegen::gen_debug_track_jit_exit(builder, 0);
builder.instruction_body.return_();
builder.instruction_body.block_end();
}
@ -1001,6 +1006,7 @@ fn jit_generate_module(
match &block.ty {
BasicBlockType::Exit => {
// Exit this function
codegen::gen_debug_track_jit_exit(builder, block.last_instruction_addr);
builder.instruction_body.return_();
},
BasicBlockType::Normal { next_block_addr } => {
@ -1058,6 +1064,7 @@ fn jit_generate_module(
}
else {
// Jump to different page
codegen::gen_debug_track_jit_exit(builder, block.last_instruction_addr);
builder.instruction_body.return_();
}
@ -1077,6 +1084,7 @@ fn jit_generate_module(
}
else {
// End of this page
codegen::gen_debug_track_jit_exit(builder, block.last_instruction_addr);
builder.instruction_body.return_();
}
@ -1377,3 +1385,53 @@ pub fn jit_get_wasm_table_index_free_list_count(ctx: &JitState) -> u32 {
pub fn jit_get_op_len(ctx: &JitState) -> u32 { ctx.wasm_builder.get_op_len() }
pub fn jit_get_op_ptr(ctx: &JitState) -> *const u8 { ctx.wasm_builder.get_op_ptr() }
#[cfg(feature = "profiler")]
pub fn check_missed_entry_points(phys_address: u32, state_flags: u32) {
let state_flags = CachedStateFlags::of_u32(state_flags);
let page = Page::page_of(phys_address);
for i in page.to_address()..page.to_address() + 4096 {
// No need to check [CODE_CACHE_SEARCH_SIZE] entries here as we look at consecutive
// addresses anyway
let index = i & jit_cache_array::MASK;
let entry = jit_cache_array::get_unchecked(index);
if !entry.pending
&& entry.state_flags == state_flags
&& phys_address >= entry.start_addr
&& phys_address < entry.start_addr + entry.len
{
profiler::stat_increment(stat::S_RUN_INTERPRETED_MISSED_COMPILED_ENTRY_LOOKUP);
let last_jump_type = unsafe { cpu2::cpu::debug_last_jump.name() };
let last_jump_addr = unsafe { cpu2::cpu::debug_last_jump.phys_address() }.unwrap_or(0);
let last_jump_opcode = if last_jump_addr != 0 {
cpu::read32(last_jump_addr)
}
else {
0
};
let opcode = cpu::read32(phys_address);
dbg_log!(
"Compiled exists, but no entry point, \
start={:x} end={:x} phys_addr={:x} opcode={:02x} {:02x} {:02x} {:02x}. \
Last jump at {:x} ({}) opcode={:02x} {:02x} {:02x} {:02x}",
entry.start_addr,
entry.start_addr + entry.len,
phys_address,
opcode & 0xFF,
opcode >> 8 & 0xFF,
opcode >> 16 & 0xFF,
opcode >> 16 & 0xFF,
last_jump_addr,
last_jump_type,
last_jump_opcode & 0xFF,
last_jump_opcode >> 8 & 0xFF,
last_jump_opcode >> 16 & 0xFF,
last_jump_opcode >> 16 & 0xFF,
);
}
}
}

View file

@ -12,7 +12,8 @@ pub enum stat {
S_RUN_INTERPRETED_PENDING,
S_RUN_INTERPRETED_NEAR_END_OF_PAGE,
S_RUN_INTERPRETED_DIFFERENT_STATE,
S_RUN_INTERPRETED_MISSED_COMPILED_ENTRY,
S_RUN_INTERPRETED_MISSED_COMPILED_ENTRY_RUN_INTERPRETED,
S_RUN_INTERPRETED_MISSED_COMPILED_ENTRY_LOOKUP,
S_RUN_INTERPRETED_STEPS,
S_RUN_FROM_CACHE,