Add wip debugging code

This commit is contained in:
Mark McCaskey
2020-02-11 09:52:21 -08:00
parent 42132c42b6
commit 0564000da3
16 changed files with 402 additions and 199 deletions

View File

@ -6,8 +6,8 @@ use crate::{
resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines,
};
use cranelift_codegen::entity::{EntityRef, PrimaryMap};
use cranelift_codegen::ir::{self, Ebb, Function, InstBuilder};
use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::{self, Ebb, Function, InstBuilder, ValueLabel};
use cranelift_codegen::isa::CallConv;
use cranelift_codegen::{cursor::FuncCursor, isa};
use cranelift_frontend::{FunctionBuilder, Position, Variable};
@ -71,6 +71,7 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
fn next_function(
&mut self,
module_info: Arc<RwLock<ModuleInfo>>,
loc: (u32, u32),
) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> {
// define_function_body(
@ -101,8 +102,12 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
target_config: self.isa.frontend_config().clone(),
clif_signatures: self.clif_signatures.clone(),
},
start: loc.0,
end: loc.1,
};
func_env.func.collect_debug_info();
debug_assert_eq!(func_env.func.dfg.num_ebbs(), 0, "Function must be empty");
debug_assert_eq!(func_env.func.dfg.num_insts(), 0, "Function must be empty");
@ -112,8 +117,7 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
&mut func_env.position,
);
// TODO srcloc
//builder.set_srcloc(cur_srcloc(&reader));
builder.set_srcloc(ir::SourceLoc::new(loc.0));
let entry_block = builder.create_ebb();
builder.append_ebb_params_for_function_params(entry_block);
@ -141,37 +145,19 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
fn finalize(
self,
module_info: &ModuleInfo,
) -> Result<((Caller, Option<wasmer_runtime_core::codegen::DebugMetadata>), Box<dyn CacheGen>), CodegenError> {
use wasm_debug::types::{CompiledFunctionData};
let mut debug_metadata = wasmer_runtime_core::codegen::DebugMetadata {
func_info: PrimaryMap::new(),
inst_info: PrimaryMap::new(),
};
let mut func_bodies: Map<LocalFuncIndex, ir::Function> = Map::new();
) -> Result<
(
(Caller, Option<wasmer_runtime_core::codegen::DebugMetadata>),
Box<dyn CacheGen>,
),
CodegenError,
> {
let mut func_bodies: Map<LocalFuncIndex, (ir::Function, (u32, u32))> = Map::new();
for f in self.functions.into_iter() {
// TODO: review
// if container is stable, then first and last probably makes more sense here,
let min_srcloc = f.func.srclocs.iter().map(|x| x.1.bits()).min().unwrap_or_default();
let max_srcloc = f.func.srclocs.iter().map(|x| x.1.bits()).max().unwrap_or_default();
let entry = CompiledFunctionData {
instructions: vec![],
start: wasm_debug::types::SourceLoc::new(min_srcloc),
end: wasm_debug::types::SourceLoc::new(max_srcloc),
compiled_offset: 0,
compiled_size: 0,
};
debug_metadata.func_info.push(entry);
/*let mut map = std::collections::HashMap::new();
for (k, v) in f.func.srclocs {
map.
}
debug_metadata.inst_info.push(map);*/
func_bodies.push(f.func);
func_bodies.push((f.func, (f.start, f.end)));
}
let (func_resolver_builder, handler_data) =
let (func_resolver_builder, debug_metadata, handler_data) =
FuncResolverBuilder::new(&*self.isa, func_bodies, module_info)?;
let trampolines = Arc::new(Trampolines::new(&*self.isa, module_info));
@ -195,7 +181,10 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
));
Ok((
(Caller::new(handler_data, trampolines, func_resolver), Some(debug_metadata)),
(
Caller::new(handler_data, trampolines, func_resolver),
debug_metadata,
),
cache_gen,
))
}
@ -265,6 +254,8 @@ pub struct CraneliftFunctionCodeGenerator {
next_local: usize,
position: Position,
func_env: FunctionEnvironment,
start: u32,
end: u32,
}
pub struct FunctionEnvironment {
@ -467,7 +458,7 @@ impl FuncEnvironment for FunctionEnvironment {
let local_memory_bound = func.create_global_value(ir::GlobalValueData::Load {
base: local_memory_ptr,
offset: (vm::LocalMemory::offset_bound() as i32).into(),
global_type: ptr_type,
global_type: ir::types::I32,
readonly: false,
});
@ -575,7 +566,7 @@ impl FuncEnvironment for FunctionEnvironment {
let table_count = func.create_global_value(ir::GlobalValueData::Load {
base: table_struct_ptr,
offset: (vm::LocalTable::offset_count() as i32).into(),
global_type: ptr_type,
global_type: ir::types::I32,
// The table length can change, so it can't be readonly.
readonly: false,
});
@ -1092,13 +1083,14 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
Ok(())
}
fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> {
fn feed_local(&mut self, ty: WpType, n: usize, loc: u32) -> Result<(), CodegenError> {
let mut next_local = self.next_local;
let mut builder = FunctionBuilder::new(
&mut self.func,
&mut self.func_translator.func_ctx,
&mut self.position,
);
builder.set_srcloc(ir::SourceLoc::new(loc));
cranelift_wasm::declare_locals(
&mut builder,
n as u32,
@ -1114,7 +1106,7 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
Ok(())
}
fn feed_event(&mut self, event: Event, _module_info: &ModuleInfo) -> Result<(), CodegenError> {
fn feed_event(&mut self, event: Event, _module_info: &ModuleInfo, loc: u32) -> Result<(), CodegenError> {
let op = match event {
Event::Wasm(x) => x,
Event::WasmOwned(ref x) => x,
@ -1136,6 +1128,8 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
&mut self.func_translator.func_ctx,
&mut self.position,
);
builder.func.collect_debug_info();
builder.set_srcloc(ir::SourceLoc::new(loc));
let module_state = ModuleTranslationState::new();
let func_state = &mut self.func_translator.state;
translate_operator(
@ -1145,6 +1139,7 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
func_state,
&mut self.func_env,
)?;
Ok(())
}
@ -1173,6 +1168,8 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
}
}
builder.finalize();
// Discard any remaining values on the stack. Either we just returned them,
// or the end of the function is unreachable.
state.stack.clear();
@ -1249,9 +1246,11 @@ fn declare_wasm_parameters(builder: &mut FunctionBuilder, entry_block: Ebb) -> u
// This is a normal WebAssembly signature parameter, so create a local for it.
let local = Variable::new(next_local);
builder.declare_var(local, param_type.value_type);
let value_label = ValueLabel::from_u32(next_local as u32);
next_local += 1;
let param_value = builder.ebb_params(entry_block)[i];
builder.set_val_label(param_value, value_label);
builder.def_var(local, param_value);
}
if param_type.purpose == ir::ArgumentPurpose::VMContext {

View File

@ -42,7 +42,7 @@ fn get_isa() -> Box<dyn isa::TargetIsa> {
builder.set("opt_level", "speed_and_size").unwrap();
builder.set("jump_tables_enabled", "false").unwrap();
if cfg!(not(test)) {
if cfg!(not(test)) && cfg!(not(debug)) {
builder.set("enable_verifier", "false").unwrap();
}

View File

@ -45,7 +45,6 @@ impl Module {
runnable_module: Arc::new(Box::new(runnable_module)),
cache_gen,
info,
debug_info: None,
})
}
}

View File

@ -10,7 +10,9 @@ use crate::{
};
use byteorder::{ByteOrder, LittleEndian};
use cranelift_codegen::{
ValueLabelsRanges,
binemit::{Stackmap, StackmapSink},
entity::PrimaryMap,
ir, isa, Context,
};
use rayon::prelude::*;
@ -96,54 +98,159 @@ impl FuncResolverBuilder {
pub fn new(
isa: &dyn isa::TargetIsa,
function_bodies: Map<LocalFuncIndex, ir::Function>,
function_bodies: Map<LocalFuncIndex, (ir::Function, (u32, u32))>,
info: &ModuleInfo,
) -> CompileResult<(Self, HandlerData)> {
) -> CompileResult<(
Self,
Option<wasmer_runtime_core::codegen::DebugMetadata>,
HandlerData,
)> {
let num_func_bodies = function_bodies.len();
let mut local_relocs = Map::with_capacity(num_func_bodies);
let mut external_relocs = Map::with_capacity(num_func_bodies);
let mut trap_sink = TrapSink::new();
let compiled_functions: Result<Vec<(Vec<u8>, (RelocSink, LocalTrapSink))>, CompileError> =
function_bodies
.into_vec()
.par_iter()
.map_init(
|| Context::new(),
|ctx, func| {
let mut code_buf = Vec::new();
ctx.func = func.to_owned();
let mut reloc_sink = RelocSink::new();
let mut local_trap_sink = LocalTrapSink::new();
let mut stackmap_sink = NoopStackmapSink {};
ctx.compile_and_emit(
isa,
&mut code_buf,
&mut reloc_sink,
&mut local_trap_sink,
&mut stackmap_sink,
)
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
ctx.clear();
Ok((code_buf, (reloc_sink, local_trap_sink)))
},
)
.collect();
let fb = function_bodies.iter().collect::<Vec<(_,_)>>();
rayon::ThreadPoolBuilder::new().num_threads(1).build_global().unwrap();
let compiled_functions = compiled_functions?;
let compiled_functions: Result<
Vec<(Vec<u8>,
(
LocalFuncIndex,
CompiledFunctionData,
ValueLabelsRanges,
Vec<Option<i32>>,
RelocSink,
LocalTrapSink,
),
)>,
CompileError,
> = fb
.par_iter()
.map_init(
|| Context::new(),
|ctx, (lfi, (func, (start, end)))| {
let mut code_buf = Vec::new();
ctx.func = func.to_owned();
let mut reloc_sink = RelocSink::new();
let mut local_trap_sink = LocalTrapSink::new();
let mut stackmap_sink = NoopStackmapSink {};
//ctx.eliminate_unreachable_code(isa).unwrap();
/*ctx.dce(isa).unwrap();
ctx.shrink_instructions(isa).unwrap();
ctx.redundant_reload_remover(isa).unwrap();
ctx.preopt(isa).unwrap();
ctx.legalize(isa).unwrap();
ctx.postopt(isa).unwrap();*/
ctx.verify(isa).unwrap();
ctx.compile_and_emit(
isa,
&mut code_buf,
&mut reloc_sink,
&mut local_trap_sink,
&mut stackmap_sink,
)
.map_err(|e| CompileError::InternalError { msg: e.to_string() })?;
// begin debug stuff
let func = &ctx.func;
let encinfo = isa.encoding_info();
let mut ebbs = func.layout.ebbs().collect::<Vec<_>>();
ebbs.sort_by_key(|ebb| func.offsets[*ebb]);
let instructions = /*func
.layout
.ebbs()*/
ebbs.into_iter()
.flat_map(|ebb| {
func.inst_offsets(ebb, &encinfo)
.map(|(offset, inst, length)| {
let srcloc = func.srclocs[inst];
let val = srcloc.bits();
wasm_debug::types::CompiledInstructionData {
// we write this data later
loc: wasm_debug::types::SourceLoc::new(val),//srcloc.bits()),
offset: offset as usize,
length: length as usize,
}
})
})
.collect::<Vec<_>>();
/*let mut unwind = vec![];
ctx.emit_unwind_info(isa, &mut unwind);
dbg!(unwind.len());*/
let stack_slots = ctx.func.stack_slots.iter().map(|(_, ssd)| ssd.offset).collect::<Vec<Option<i32>>>();
let labels_ranges = ctx.build_value_labels_ranges(isa).unwrap_or_default();
if labels_ranges.len() == 24 || labels_ranges.len() == 25 {
let mut vec = labels_ranges.iter().map(|(a,b)| (*a, b.clone())).collect::<Vec<_>>();
vec.sort_by(|a, b| a.0.as_u32().cmp(&b.0.as_u32()));
dbg!(labels_ranges.len(), &vec);
}
let entry = CompiledFunctionData {
instructions,
start: wasm_debug::types::SourceLoc::new(*start),
end: wasm_debug::types::SourceLoc::new(*end),
// this not being 0 breaks inst-level debugging
compiled_offset: 0,
compiled_size: code_buf.len(),
};
// end debug stuff
ctx.clear();
Ok((code_buf, (*lfi, entry, labels_ranges, stack_slots, reloc_sink, local_trap_sink)))
},
)
.collect();
use wasm_debug::types::CompiledFunctionData;
let mut debug_metadata = wasmer_runtime_core::codegen::DebugMetadata {
func_info: PrimaryMap::new(),
inst_info: PrimaryMap::new(),
pointers: vec![],
stack_slot_offsets: PrimaryMap::new(),
};
let mut compiled_functions = compiled_functions?;
compiled_functions.sort_by(|a, b| (a.1).0.cmp(&(b.1).0));
let compiled_functions = compiled_functions;
let mut total_size = 0;
// We separate into two iterators, one iterable and one into iterable
let (code_bufs, sinks): (Vec<Vec<u8>>, Vec<(RelocSink, LocalTrapSink)>) =
compiled_functions.into_iter().unzip();
for (code_buf, (reloc_sink, mut local_trap_sink)) in code_bufs.iter().zip(sinks.into_iter())
let (code_bufs, sinks): (
Vec<Vec<u8>>,
Vec<(
LocalFuncIndex,
CompiledFunctionData,
ValueLabelsRanges,
Vec<Option<i32>>,
RelocSink,
LocalTrapSink,
)>,
) = compiled_functions.into_iter().unzip();
for (
code_buf,
(_, entry, vlr, stackslots, reloc_sink, mut local_trap_sink),
) in code_bufs
.iter()
.zip(sinks.into_iter())
{
let rounded_size = round_up(code_buf.len(), mem::size_of::<usize>());
debug_metadata.func_info.push(entry);
debug_metadata.inst_info.push(unsafe {std::mem::transmute(vlr)});
debug_metadata.stack_slot_offsets.push(stackslots);
// Clear the local trap sink and consolidate all trap info
// into a single location.
trap_sink.drain_local(total_size, &mut local_trap_sink);
// Round up each function's size to pointer alignment.
total_size += round_up(code_buf.len(), mem::size_of::<usize>());
total_size += rounded_size;
local_relocs.push(reloc_sink.local_relocs.into_boxed_slice());
external_relocs.push(reloc_sink.external_relocs.into_boxed_slice());
@ -175,7 +282,12 @@ impl FuncResolverBuilder {
let mut previous_end = 0;
for compiled in code_bufs.iter() {
let new_end = previous_end + round_up(compiled.len(), mem::size_of::<usize>());
let length = round_up(compiled.len(), mem::size_of::<usize>());
debug_metadata.pointers.push((
(memory.as_ptr() as usize + previous_end) as *const u8,
length,
));
let new_end = previous_end + length;
unsafe {
memory.as_slice_mut()[previous_end..previous_end + compiled.len()]
.copy_from_slice(&compiled[..]);
@ -197,7 +309,7 @@ impl FuncResolverBuilder {
func_resolver_builder.relocate_locals();
Ok((func_resolver_builder, handler_data))
Ok((func_resolver_builder, Some(debug_metadata), handler_data))
}
fn relocate_locals(&mut self) {