mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-23 05:31:32 +00:00
Add wip debugging code
This commit is contained in:
@ -6,8 +6,8 @@ use crate::{
|
|||||||
resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines,
|
resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines,
|
||||||
};
|
};
|
||||||
|
|
||||||
use cranelift_codegen::entity::{EntityRef, PrimaryMap};
|
use cranelift_codegen::entity::EntityRef;
|
||||||
use cranelift_codegen::ir::{self, Ebb, Function, InstBuilder};
|
use cranelift_codegen::ir::{self, Ebb, Function, InstBuilder, ValueLabel};
|
||||||
use cranelift_codegen::isa::CallConv;
|
use cranelift_codegen::isa::CallConv;
|
||||||
use cranelift_codegen::{cursor::FuncCursor, isa};
|
use cranelift_codegen::{cursor::FuncCursor, isa};
|
||||||
use cranelift_frontend::{FunctionBuilder, Position, Variable};
|
use cranelift_frontend::{FunctionBuilder, Position, Variable};
|
||||||
@ -71,6 +71,7 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
|
|||||||
fn next_function(
|
fn next_function(
|
||||||
&mut self,
|
&mut self,
|
||||||
module_info: Arc<RwLock<ModuleInfo>>,
|
module_info: Arc<RwLock<ModuleInfo>>,
|
||||||
|
loc: (u32, u32),
|
||||||
) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> {
|
) -> Result<&mut CraneliftFunctionCodeGenerator, CodegenError> {
|
||||||
// define_function_body(
|
// define_function_body(
|
||||||
|
|
||||||
@ -101,8 +102,12 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
|
|||||||
target_config: self.isa.frontend_config().clone(),
|
target_config: self.isa.frontend_config().clone(),
|
||||||
clif_signatures: self.clif_signatures.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_ebbs(), 0, "Function must be empty");
|
||||||
debug_assert_eq!(func_env.func.dfg.num_insts(), 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,
|
&mut func_env.position,
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO srcloc
|
builder.set_srcloc(ir::SourceLoc::new(loc.0));
|
||||||
//builder.set_srcloc(cur_srcloc(&reader));
|
|
||||||
|
|
||||||
let entry_block = builder.create_ebb();
|
let entry_block = builder.create_ebb();
|
||||||
builder.append_ebb_params_for_function_params(entry_block);
|
builder.append_ebb_params_for_function_params(entry_block);
|
||||||
@ -141,37 +145,19 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
|
|||||||
fn finalize(
|
fn finalize(
|
||||||
self,
|
self,
|
||||||
module_info: &ModuleInfo,
|
module_info: &ModuleInfo,
|
||||||
) -> Result<((Caller, Option<wasmer_runtime_core::codegen::DebugMetadata>), Box<dyn CacheGen>), CodegenError> {
|
) -> Result<
|
||||||
|
(
|
||||||
use wasm_debug::types::{CompiledFunctionData};
|
(Caller, Option<wasmer_runtime_core::codegen::DebugMetadata>),
|
||||||
let mut debug_metadata = wasmer_runtime_core::codegen::DebugMetadata {
|
Box<dyn CacheGen>,
|
||||||
func_info: PrimaryMap::new(),
|
),
|
||||||
inst_info: PrimaryMap::new(),
|
CodegenError,
|
||||||
};
|
> {
|
||||||
let mut func_bodies: Map<LocalFuncIndex, ir::Function> = Map::new();
|
let mut func_bodies: Map<LocalFuncIndex, (ir::Function, (u32, u32))> = Map::new();
|
||||||
for f in self.functions.into_iter() {
|
for f in self.functions.into_iter() {
|
||||||
// TODO: review
|
func_bodies.push((f.func, (f.start, f.end)));
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (func_resolver_builder, handler_data) =
|
let (func_resolver_builder, debug_metadata, handler_data) =
|
||||||
FuncResolverBuilder::new(&*self.isa, func_bodies, module_info)?;
|
FuncResolverBuilder::new(&*self.isa, func_bodies, module_info)?;
|
||||||
|
|
||||||
let trampolines = Arc::new(Trampolines::new(&*self.isa, module_info));
|
let trampolines = Arc::new(Trampolines::new(&*self.isa, module_info));
|
||||||
@ -195,7 +181,10 @@ impl ModuleCodeGenerator<CraneliftFunctionCodeGenerator, Caller, CodegenError>
|
|||||||
));
|
));
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
(Caller::new(handler_data, trampolines, func_resolver), Some(debug_metadata)),
|
(
|
||||||
|
Caller::new(handler_data, trampolines, func_resolver),
|
||||||
|
debug_metadata,
|
||||||
|
),
|
||||||
cache_gen,
|
cache_gen,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -265,6 +254,8 @@ pub struct CraneliftFunctionCodeGenerator {
|
|||||||
next_local: usize,
|
next_local: usize,
|
||||||
position: Position,
|
position: Position,
|
||||||
func_env: FunctionEnvironment,
|
func_env: FunctionEnvironment,
|
||||||
|
start: u32,
|
||||||
|
end: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FunctionEnvironment {
|
pub struct FunctionEnvironment {
|
||||||
@ -467,7 +458,7 @@ impl FuncEnvironment for FunctionEnvironment {
|
|||||||
let local_memory_bound = func.create_global_value(ir::GlobalValueData::Load {
|
let local_memory_bound = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
base: local_memory_ptr,
|
base: local_memory_ptr,
|
||||||
offset: (vm::LocalMemory::offset_bound() as i32).into(),
|
offset: (vm::LocalMemory::offset_bound() as i32).into(),
|
||||||
global_type: ptr_type,
|
global_type: ir::types::I32,
|
||||||
readonly: false,
|
readonly: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -575,7 +566,7 @@ impl FuncEnvironment for FunctionEnvironment {
|
|||||||
let table_count = func.create_global_value(ir::GlobalValueData::Load {
|
let table_count = func.create_global_value(ir::GlobalValueData::Load {
|
||||||
base: table_struct_ptr,
|
base: table_struct_ptr,
|
||||||
offset: (vm::LocalTable::offset_count() as i32).into(),
|
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.
|
// The table length can change, so it can't be readonly.
|
||||||
readonly: false,
|
readonly: false,
|
||||||
});
|
});
|
||||||
@ -1092,13 +1083,14 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
|
|||||||
Ok(())
|
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 next_local = self.next_local;
|
||||||
let mut builder = FunctionBuilder::new(
|
let mut builder = FunctionBuilder::new(
|
||||||
&mut self.func,
|
&mut self.func,
|
||||||
&mut self.func_translator.func_ctx,
|
&mut self.func_translator.func_ctx,
|
||||||
&mut self.position,
|
&mut self.position,
|
||||||
);
|
);
|
||||||
|
builder.set_srcloc(ir::SourceLoc::new(loc));
|
||||||
cranelift_wasm::declare_locals(
|
cranelift_wasm::declare_locals(
|
||||||
&mut builder,
|
&mut builder,
|
||||||
n as u32,
|
n as u32,
|
||||||
@ -1114,7 +1106,7 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
|
|||||||
Ok(())
|
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 {
|
let op = match event {
|
||||||
Event::Wasm(x) => x,
|
Event::Wasm(x) => x,
|
||||||
Event::WasmOwned(ref x) => x,
|
Event::WasmOwned(ref x) => x,
|
||||||
@ -1136,6 +1128,8 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
|
|||||||
&mut self.func_translator.func_ctx,
|
&mut self.func_translator.func_ctx,
|
||||||
&mut self.position,
|
&mut self.position,
|
||||||
);
|
);
|
||||||
|
builder.func.collect_debug_info();
|
||||||
|
builder.set_srcloc(ir::SourceLoc::new(loc));
|
||||||
let module_state = ModuleTranslationState::new();
|
let module_state = ModuleTranslationState::new();
|
||||||
let func_state = &mut self.func_translator.state;
|
let func_state = &mut self.func_translator.state;
|
||||||
translate_operator(
|
translate_operator(
|
||||||
@ -1145,6 +1139,7 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
|
|||||||
func_state,
|
func_state,
|
||||||
&mut self.func_env,
|
&mut self.func_env,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1173,6 +1168,8 @@ impl FunctionCodeGenerator<CodegenError> for CraneliftFunctionCodeGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.finalize();
|
||||||
|
|
||||||
// Discard any remaining values on the stack. Either we just returned them,
|
// Discard any remaining values on the stack. Either we just returned them,
|
||||||
// or the end of the function is unreachable.
|
// or the end of the function is unreachable.
|
||||||
state.stack.clear();
|
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.
|
// This is a normal WebAssembly signature parameter, so create a local for it.
|
||||||
let local = Variable::new(next_local);
|
let local = Variable::new(next_local);
|
||||||
builder.declare_var(local, param_type.value_type);
|
builder.declare_var(local, param_type.value_type);
|
||||||
|
let value_label = ValueLabel::from_u32(next_local as u32);
|
||||||
next_local += 1;
|
next_local += 1;
|
||||||
|
|
||||||
let param_value = builder.ebb_params(entry_block)[i];
|
let param_value = builder.ebb_params(entry_block)[i];
|
||||||
|
builder.set_val_label(param_value, value_label);
|
||||||
builder.def_var(local, param_value);
|
builder.def_var(local, param_value);
|
||||||
}
|
}
|
||||||
if param_type.purpose == ir::ArgumentPurpose::VMContext {
|
if param_type.purpose == ir::ArgumentPurpose::VMContext {
|
||||||
|
@ -42,7 +42,7 @@ fn get_isa() -> Box<dyn isa::TargetIsa> {
|
|||||||
builder.set("opt_level", "speed_and_size").unwrap();
|
builder.set("opt_level", "speed_and_size").unwrap();
|
||||||
builder.set("jump_tables_enabled", "false").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();
|
builder.set("enable_verifier", "false").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,6 @@ impl Module {
|
|||||||
runnable_module: Arc::new(Box::new(runnable_module)),
|
runnable_module: Arc::new(Box::new(runnable_module)),
|
||||||
cache_gen,
|
cache_gen,
|
||||||
info,
|
info,
|
||||||
debug_info: None,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use cranelift_codegen::{
|
use cranelift_codegen::{
|
||||||
|
ValueLabelsRanges,
|
||||||
binemit::{Stackmap, StackmapSink},
|
binemit::{Stackmap, StackmapSink},
|
||||||
|
entity::PrimaryMap,
|
||||||
ir, isa, Context,
|
ir, isa, Context,
|
||||||
};
|
};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
@ -96,54 +98,159 @@ impl FuncResolverBuilder {
|
|||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
isa: &dyn isa::TargetIsa,
|
isa: &dyn isa::TargetIsa,
|
||||||
function_bodies: Map<LocalFuncIndex, ir::Function>,
|
function_bodies: Map<LocalFuncIndex, (ir::Function, (u32, u32))>,
|
||||||
info: &ModuleInfo,
|
info: &ModuleInfo,
|
||||||
) -> CompileResult<(Self, HandlerData)> {
|
) -> CompileResult<(
|
||||||
|
Self,
|
||||||
|
Option<wasmer_runtime_core::codegen::DebugMetadata>,
|
||||||
|
HandlerData,
|
||||||
|
)> {
|
||||||
let num_func_bodies = function_bodies.len();
|
let num_func_bodies = function_bodies.len();
|
||||||
let mut local_relocs = Map::with_capacity(num_func_bodies);
|
let mut local_relocs = Map::with_capacity(num_func_bodies);
|
||||||
let mut external_relocs = Map::with_capacity(num_func_bodies);
|
let mut external_relocs = Map::with_capacity(num_func_bodies);
|
||||||
|
|
||||||
let mut trap_sink = TrapSink::new();
|
let mut trap_sink = TrapSink::new();
|
||||||
|
|
||||||
let compiled_functions: Result<Vec<(Vec<u8>, (RelocSink, LocalTrapSink))>, CompileError> =
|
let fb = function_bodies.iter().collect::<Vec<(_,_)>>();
|
||||||
function_bodies
|
rayon::ThreadPoolBuilder::new().num_threads(1).build_global().unwrap();
|
||||||
.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 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;
|
let mut total_size = 0;
|
||||||
// We separate into two iterators, one iterable and one into iterable
|
// We separate into two iterators, one iterable and one into iterable
|
||||||
let (code_bufs, sinks): (Vec<Vec<u8>>, Vec<(RelocSink, LocalTrapSink)>) =
|
let (code_bufs, sinks): (
|
||||||
compiled_functions.into_iter().unzip();
|
Vec<Vec<u8>>,
|
||||||
for (code_buf, (reloc_sink, mut local_trap_sink)) in code_bufs.iter().zip(sinks.into_iter())
|
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
|
// Clear the local trap sink and consolidate all trap info
|
||||||
// into a single location.
|
// into a single location.
|
||||||
trap_sink.drain_local(total_size, &mut local_trap_sink);
|
trap_sink.drain_local(total_size, &mut local_trap_sink);
|
||||||
|
|
||||||
// Round up each function's size to pointer alignment.
|
// 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());
|
local_relocs.push(reloc_sink.local_relocs.into_boxed_slice());
|
||||||
external_relocs.push(reloc_sink.external_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;
|
let mut previous_end = 0;
|
||||||
for compiled in code_bufs.iter() {
|
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 {
|
unsafe {
|
||||||
memory.as_slice_mut()[previous_end..previous_end + compiled.len()]
|
memory.as_slice_mut()[previous_end..previous_end + compiled.len()]
|
||||||
.copy_from_slice(&compiled[..]);
|
.copy_from_slice(&compiled[..]);
|
||||||
@ -197,7 +309,7 @@ impl FuncResolverBuilder {
|
|||||||
|
|
||||||
func_resolver_builder.relocate_locals();
|
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) {
|
fn relocate_locals(&mut self) {
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
// TODO: add attribution to LLVM for data definitions and WasmTime for code structure
|
// TODO: add attribution to LLVM for data definitions and WasmTime for code structure
|
||||||
use std::str::FromStr;
|
|
||||||
use std::ptr;
|
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
|
use std::ptr;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub use wasm_debug::{read_debuginfo, DebugInfoData, WasmFileInfo};
|
|
||||||
pub use wasm_debug::{emit_dwarf, ResolvedSymbol, SymbolResolver};
|
pub use wasm_debug::{emit_dwarf, ResolvedSymbol, SymbolResolver};
|
||||||
|
pub use wasm_debug::{read_debuginfo, DebugInfoData, WasmFileInfo};
|
||||||
|
|
||||||
use target_lexicon::{Triple, Architecture, Vendor, OperatingSystem, Environment, BinaryFormat};
|
use gimli::write::{
|
||||||
use gimli::write::{self, DwarfUnit, Sections, Address, RangeList, EndianVec, AttributeValue, Range};
|
self, Address, AttributeValue, DwarfUnit, EndianVec, Range, RangeList, Sections,
|
||||||
|
};
|
||||||
|
use target_lexicon::{Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor};
|
||||||
|
|
||||||
use wasmer_runtime_core::{module::ModuleInfo, state::CodeVersion};
|
use wasmer_runtime_core::{module::ModuleInfo, state::CodeVersion};
|
||||||
|
|
||||||
@ -138,8 +140,8 @@ pub fn generate_dwarf(module_info: &ModuleInfo, debug_info_data: &DebugInfoData,
|
|||||||
// `DW_AT_low_pc` and `DW_AT_high_pc` are good for continuous
|
// `DW_AT_low_pc` and `DW_AT_high_pc` are good for continuous
|
||||||
// `DW_AT_low_pc` alone can work for a single address, but we can probably not
|
// `DW_AT_low_pc` alone can work for a single address, but we can probably not
|
||||||
// worry about that for now. These attribtues associate machine code with the DIE
|
// worry about that for now. These attribtues associate machine code with the DIE
|
||||||
// -
|
// -
|
||||||
|
|
||||||
match platform {
|
match platform {
|
||||||
X86_64_GNU_LINUX => unimplemented!("in progress"),
|
X86_64_GNU_LINUX => unimplemented!("in progress"),
|
||||||
X86_64_OSX => unimplemented!("in progress"),
|
X86_64_OSX => unimplemented!("in progress"),
|
||||||
@ -151,7 +153,12 @@ pub fn generate_dwarf(module_info: &ModuleInfo, debug_info_data: &DebugInfoData,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// converts existing dwarf into a usable form with metadata from the JIT
|
// converts existing dwarf into a usable form with metadata from the JIT
|
||||||
fn reprocess_dwarf(module_info: &ModuleInfo, debug_info_data: &DebugInfoData, code_version: &CodeVersion, platform: Triple) -> Option<write::Dwarf> {
|
fn reprocess_dwarf(
|
||||||
|
module_info: &ModuleInfo,
|
||||||
|
debug_info_data: &DebugInfoData,
|
||||||
|
code_version: &CodeVersion,
|
||||||
|
platform: Triple,
|
||||||
|
) -> Option<write::Dwarf> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ impl FunctionMiddleware for BlockTrace {
|
|||||||
op: Event<'a, 'b>,
|
op: Event<'a, 'b>,
|
||||||
_module_info: &ModuleInfo,
|
_module_info: &ModuleInfo,
|
||||||
sink: &mut EventSink<'a, 'b>,
|
sink: &mut EventSink<'a, 'b>,
|
||||||
|
_loc: u32,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
match op {
|
match op {
|
||||||
Event::Internal(InternalEvent::FunctionBegin(_)) => {
|
Event::Internal(InternalEvent::FunctionBegin(_)) => {
|
||||||
|
@ -26,6 +26,7 @@ impl FunctionMiddleware for CallTrace {
|
|||||||
op: Event<'a, 'b>,
|
op: Event<'a, 'b>,
|
||||||
_module_info: &ModuleInfo,
|
_module_info: &ModuleInfo,
|
||||||
sink: &mut EventSink<'a, 'b>,
|
sink: &mut EventSink<'a, 'b>,
|
||||||
|
_loc: u32,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let counter = self.counter.clone();
|
let counter = self.counter.clone();
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ impl FunctionMiddleware for Metering {
|
|||||||
op: Event<'a, 'b>,
|
op: Event<'a, 'b>,
|
||||||
_module_info: &ModuleInfo,
|
_module_info: &ModuleInfo,
|
||||||
sink: &mut EventSink<'a, 'b>,
|
sink: &mut EventSink<'a, 'b>,
|
||||||
|
_loc: u32,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
match op {
|
match op {
|
||||||
Event::Internal(InternalEvent::FunctionBegin(_)) => {
|
Event::Internal(InternalEvent::FunctionBegin(_)) => {
|
||||||
|
@ -112,9 +112,12 @@ pub trait ModuleCodeGenerator<FCG: FunctionCodeGenerator<E>, RM: RunnableModule,
|
|||||||
/// Checks the precondition for a module.
|
/// Checks the precondition for a module.
|
||||||
fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), E>;
|
fn check_precondition(&mut self, module_info: &ModuleInfo) -> Result<(), E>;
|
||||||
/// Creates a new function and returns the function-scope code generator for it.
|
/// Creates a new function and returns the function-scope code generator for it.
|
||||||
fn next_function(&mut self, module_info: Arc<RwLock<ModuleInfo>>) -> Result<&mut FCG, E>;
|
fn next_function(&mut self, module_info: Arc<RwLock<ModuleInfo>>, loc: (u32, u32)) -> Result<&mut FCG, E>;
|
||||||
/// Finalizes this module.
|
/// Finalizes this module.
|
||||||
fn finalize(self, module_info: &ModuleInfo) -> Result<((RM, Option<DebugMetadata>), Box<dyn CacheGen>), E>;
|
fn finalize(
|
||||||
|
self,
|
||||||
|
module_info: &ModuleInfo,
|
||||||
|
) -> Result<((RM, Option<DebugMetadata>), Box<dyn CacheGen>), E>;
|
||||||
|
|
||||||
/// Creates a module from cache.
|
/// Creates a module from cache.
|
||||||
unsafe fn from_cache(cache: Artifact, _: Token) -> Result<ModuleInner, CacheError>;
|
unsafe fn from_cache(cache: Artifact, _: Token) -> Result<ModuleInner, CacheError>;
|
||||||
@ -127,6 +130,10 @@ pub struct DebugMetadata {
|
|||||||
pub func_info: PrimaryMap<FuncIndex, wasm_debug::types::CompiledFunctionData>,
|
pub func_info: PrimaryMap<FuncIndex, wasm_debug::types::CompiledFunctionData>,
|
||||||
/// inst_info
|
/// inst_info
|
||||||
pub inst_info: PrimaryMap<FuncIndex, wasm_debug::types::ValueLabelsRangesInner>,
|
pub inst_info: PrimaryMap<FuncIndex, wasm_debug::types::ValueLabelsRangesInner>,
|
||||||
|
/// stack slot offsets!
|
||||||
|
pub stack_slot_offsets: PrimaryMap<FuncIndex, Vec<Option<i32>>>,
|
||||||
|
/// function pointers and their lengths
|
||||||
|
pub pointers: Vec<(*const u8, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A streaming compiler which is designed to generated code for a module based on a stream
|
/// A streaming compiler which is designed to generated code for a module based on a stream
|
||||||
@ -241,7 +248,6 @@ impl<
|
|||||||
validate_with_features(wasm, &compiler_config.features)?;
|
validate_with_features(wasm, &compiler_config.features)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let mut mcg = match MCG::backend_id() {
|
let mut mcg = match MCG::backend_id() {
|
||||||
"llvm" => MCG::new_with_target(
|
"llvm" => MCG::new_with_target(
|
||||||
compiler_config.triple.clone(),
|
compiler_config.triple.clone(),
|
||||||
@ -252,13 +258,15 @@ impl<
|
|||||||
};
|
};
|
||||||
let mut chain = (self.middleware_chain_generator)();
|
let mut chain = (self.middleware_chain_generator)();
|
||||||
let info = crate::parse::read_module(wasm, &mut mcg, &mut chain, &compiler_config)?;
|
let info = crate::parse::read_module(wasm, &mut mcg, &mut chain, &compiler_config)?;
|
||||||
let ((exec_context, debug_metadata), cache_gen) =
|
let ((exec_context, debug_metadata), cache_gen) = mcg
|
||||||
mcg.finalize(&info.read().unwrap())
|
.finalize(&info.read().unwrap())
|
||||||
.map_err(|x| CompileError::InternalError {
|
.map_err(|x| CompileError::InternalError {
|
||||||
msg: format!("{:?}", x),
|
msg: format!("{:?}", x),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
use target_lexicon::{Triple, Architecture, Vendor, OperatingSystem, Environment, BinaryFormat};
|
use target_lexicon::{
|
||||||
|
Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor,
|
||||||
|
};
|
||||||
const X86_64_OSX: Triple = Triple {
|
const X86_64_OSX: Triple = Triple {
|
||||||
architecture: Architecture::X86_64,
|
architecture: Architecture::X86_64,
|
||||||
vendor: Vendor::Apple,
|
vendor: Vendor::Apple,
|
||||||
@ -266,34 +274,37 @@ impl<
|
|||||||
environment: Environment::Unknown,
|
environment: Environment::Unknown,
|
||||||
binary_format: BinaryFormat::Macho,
|
binary_format: BinaryFormat::Macho,
|
||||||
};
|
};
|
||||||
|
|
||||||
if compiler_config.generate_debug_info {
|
if compiler_config.generate_debug_info {
|
||||||
let debug_metadata = debug_metadata.expect("debug metadata");
|
let debug_metadata = debug_metadata.expect("debug metadata");
|
||||||
let debug_info = wasm_debug::read_debuginfo(wasm);
|
let debug_info = wasm_debug::read_debuginfo(wasm);
|
||||||
let extra_info = wasm_debug::types::ModuleVmctxInfo {
|
let extra_info = wasm_debug::types::ModuleVmctxInfo::new(14 * 8, debug_metadata.stack_slot_offsets.values());
|
||||||
memory_offset: 0,
|
|
||||||
stack_slot_offsets: cranelift_entity::PrimaryMap::new(),
|
|
||||||
};
|
|
||||||
// lazy type hack (TODO:)
|
// lazy type hack (TODO:)
|
||||||
let compiled_fn_map = unsafe { std::mem::transmute(debug_metadata.func_info) };
|
let compiled_fn_map = wasm_debug::types::create_module_address_map(debug_metadata.func_info.values());
|
||||||
let range_map = unsafe { std::mem::transmute(debug_metadata.inst_info) };
|
let range_map = wasm_debug::types::build_values_ranges(debug_metadata.inst_info.values());
|
||||||
let raw_func_slice = vec![];//exec_context.get_local_function_pointers_and_lengths().expect("raw func slice");
|
let raw_func_slice = debug_metadata.pointers;
|
||||||
dbg!("DEBUG INFO GENERATED");
|
|
||||||
let debug_image = wasm_debug::emit_debugsections_image(X86_64_OSX,
|
|
||||||
std::mem::size_of::<usize>() as u8,
|
|
||||||
&debug_info,
|
|
||||||
&extra_info,
|
|
||||||
&compiled_fn_map,
|
|
||||||
&range_map,
|
|
||||||
&raw_func_slice).expect("make debug image");
|
|
||||||
|
|
||||||
crate::jit_debug::register_new_jit_code_entry(&debug_image, crate::jit_debug::JITAction::JIT_REGISTER_FN);
|
dbg!("DEBUG INFO GENERATED");
|
||||||
}
|
let debug_image = wasm_debug::emit_debugsections_image(
|
||||||
|
X86_64_OSX,
|
||||||
|
std::mem::size_of::<usize>() as u8,
|
||||||
|
&debug_info,
|
||||||
|
&extra_info,
|
||||||
|
&compiled_fn_map,
|
||||||
|
&range_map,
|
||||||
|
&raw_func_slice,
|
||||||
|
)
|
||||||
|
.expect("make debug image");
|
||||||
|
|
||||||
|
crate::jit_debug::register_new_jit_code_entry(
|
||||||
|
&debug_image,
|
||||||
|
crate::jit_debug::JITAction::JIT_REGISTER_FN,
|
||||||
|
);
|
||||||
|
}
|
||||||
Ok(ModuleInner {
|
Ok(ModuleInner {
|
||||||
cache_gen,
|
cache_gen,
|
||||||
runnable_module: Arc::new(Box::new(exec_context)),
|
runnable_module: Arc::new(Box::new(exec_context)),
|
||||||
info: Arc::try_unwrap(info).unwrap().into_inner().unwrap(),
|
info: Arc::try_unwrap(info).unwrap().into_inner().unwrap(),
|
||||||
debug_info: None,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,6 +351,7 @@ impl MiddlewareChain {
|
|||||||
fcg: Option<&mut FCG>,
|
fcg: Option<&mut FCG>,
|
||||||
ev: Event,
|
ev: Event,
|
||||||
module_info: &ModuleInfo,
|
module_info: &ModuleInfo,
|
||||||
|
loc: u32,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let mut sink = EventSink {
|
let mut sink = EventSink {
|
||||||
buffer: SmallVec::new(),
|
buffer: SmallVec::new(),
|
||||||
@ -348,12 +360,12 @@ impl MiddlewareChain {
|
|||||||
for m in &mut self.chain {
|
for m in &mut self.chain {
|
||||||
let prev: SmallVec<[Event; 2]> = sink.buffer.drain().collect();
|
let prev: SmallVec<[Event; 2]> = sink.buffer.drain().collect();
|
||||||
for ev in prev {
|
for ev in prev {
|
||||||
m.feed_event(ev, module_info, &mut sink)?;
|
m.feed_event(ev, module_info, &mut sink, loc)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(fcg) = fcg {
|
if let Some(fcg) = fcg {
|
||||||
for ev in sink.buffer {
|
for ev in sink.buffer {
|
||||||
fcg.feed_event(ev, module_info)
|
fcg.feed_event(ev, module_info, loc)
|
||||||
.map_err(|x| format!("{:?}", x))?;
|
.map_err(|x| format!("{:?}", x))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -372,6 +384,7 @@ pub trait FunctionMiddleware {
|
|||||||
op: Event<'a, 'b>,
|
op: Event<'a, 'b>,
|
||||||
module_info: &ModuleInfo,
|
module_info: &ModuleInfo,
|
||||||
sink: &mut EventSink<'a, 'b>,
|
sink: &mut EventSink<'a, 'b>,
|
||||||
|
loc: u32,
|
||||||
) -> Result<(), Self::Error>;
|
) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,6 +394,7 @@ pub(crate) trait GenericFunctionMiddleware {
|
|||||||
op: Event<'a, 'b>,
|
op: Event<'a, 'b>,
|
||||||
module_info: &ModuleInfo,
|
module_info: &ModuleInfo,
|
||||||
sink: &mut EventSink<'a, 'b>,
|
sink: &mut EventSink<'a, 'b>,
|
||||||
|
loc: u32,
|
||||||
) -> Result<(), String>;
|
) -> Result<(), String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,8 +404,9 @@ impl<E: Debug, T: FunctionMiddleware<Error = E>> GenericFunctionMiddleware for T
|
|||||||
op: Event<'a, 'b>,
|
op: Event<'a, 'b>,
|
||||||
module_info: &ModuleInfo,
|
module_info: &ModuleInfo,
|
||||||
sink: &mut EventSink<'a, 'b>,
|
sink: &mut EventSink<'a, 'b>,
|
||||||
|
loc: u32,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
<Self as FunctionMiddleware>::feed_event(self, op, module_info, sink)
|
<Self as FunctionMiddleware>::feed_event(self, op, module_info, sink, loc)
|
||||||
.map_err(|x| format!("{:?}", x))
|
.map_err(|x| format!("{:?}", x))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -405,13 +420,13 @@ pub trait FunctionCodeGenerator<E: Debug> {
|
|||||||
fn feed_param(&mut self, ty: WpType) -> Result<(), E>;
|
fn feed_param(&mut self, ty: WpType) -> Result<(), E>;
|
||||||
|
|
||||||
/// Adds `n` locals to the function.
|
/// Adds `n` locals to the function.
|
||||||
fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), E>;
|
fn feed_local(&mut self, ty: WpType, n: usize, loc: u32) -> Result<(), E>;
|
||||||
|
|
||||||
/// Called before the first call to `feed_opcode`.
|
/// Called before the first call to `feed_opcode`.
|
||||||
fn begin_body(&mut self, module_info: &ModuleInfo) -> Result<(), E>;
|
fn begin_body(&mut self, module_info: &ModuleInfo) -> Result<(), E>;
|
||||||
|
|
||||||
/// Called for each operator.
|
/// Called for each operator.
|
||||||
fn feed_event(&mut self, op: Event, module_info: &ModuleInfo) -> Result<(), E>;
|
fn feed_event(&mut self, op: Event, module_info: &ModuleInfo, loc: u32) -> Result<(), E>;
|
||||||
|
|
||||||
/// Finalizes the function.
|
/// Finalizes the function.
|
||||||
fn finalize(&mut self) -> Result<(), E>;
|
fn finalize(&mut self) -> Result<(), E>;
|
||||||
|
@ -86,9 +86,14 @@ impl Instance {
|
|||||||
None => vm::Ctx::new(backing, import_backing, &module),
|
None => vm::Ctx::new(backing, import_backing, &module),
|
||||||
};
|
};
|
||||||
vmctx.as_mut_ptr().write(real_ctx);
|
vmctx.as_mut_ptr().write(real_ctx);
|
||||||
|
for (_, memory) in backing.vm_memories.iter_mut() {
|
||||||
|
let mem: &mut vm::LocalMemory = &mut **memory;
|
||||||
|
mem.vmctx = dbg!(vmctx.as_mut_ptr());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Box::leak(vmctx);
|
Box::leak(vmctx);
|
||||||
|
|
||||||
|
|
||||||
let instance = Instance {
|
let instance = Instance {
|
||||||
module,
|
module,
|
||||||
inner,
|
inner,
|
||||||
|
@ -8,15 +8,25 @@ use std::ptr;
|
|||||||
//
|
//
|
||||||
// see also https://sourceware.org/gdb/current/onlinedocs/gdb.html#JIT-Interface
|
// see also https://sourceware.org/gdb/current/onlinedocs/gdb.html#JIT-Interface
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub extern "C" fn __jit_debug_register_code() {
|
extern "C" fn __jit_debug_register_code() {
|
||||||
|
// implementation of this function copied from wasmtime (TODO: link and attribution)
|
||||||
|
// prevent optimization of this function
|
||||||
|
let x = 3;
|
||||||
|
unsafe {
|
||||||
|
std::ptr::read_volatile(&x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
pub enum JITAction { JIT_NOACTION = 0, JIT_REGISTER_FN = 1, JIT_UNREGISTER_FN = 2 }
|
pub enum JITAction {
|
||||||
|
JIT_NOACTION = 0,
|
||||||
|
JIT_REGISTER_FN = 1,
|
||||||
|
JIT_UNREGISTER_FN = 2,
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@ -76,9 +86,15 @@ unsafe fn push_front(jce: *mut JITCodeEntry) {
|
|||||||
|
|
||||||
// deleted static (added and deleted by Mark): TODO:
|
// deleted static (added and deleted by Mark): TODO:
|
||||||
pub fn register_new_jit_code_entry(bytes: &[u8], action: JITAction) -> *mut JITCodeEntry {
|
pub fn register_new_jit_code_entry(bytes: &[u8], action: JITAction) -> *mut JITCodeEntry {
|
||||||
|
let owned_bytes = bytes.iter().cloned().collect::<Vec<u8>>();
|
||||||
|
let ptr = owned_bytes.as_ptr();
|
||||||
|
let len = owned_bytes.len();
|
||||||
|
|
||||||
|
std::mem::forget(bytes);
|
||||||
|
|
||||||
let entry: *mut JITCodeEntry = Box::into_raw(Box::new(JITCodeEntry {
|
let entry: *mut JITCodeEntry = Box::into_raw(Box::new(JITCodeEntry {
|
||||||
symfile_addr: bytes.as_ptr(),
|
symfile_addr: ptr,
|
||||||
symfile_size: bytes.len() as _,
|
symfile_size: len as _,
|
||||||
..JITCodeEntry::default()
|
..JITCodeEntry::default()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -86,6 +102,9 @@ pub fn register_new_jit_code_entry(bytes: &[u8], action: JITAction) -> *mut JITC
|
|||||||
push_front(entry);
|
push_front(entry);
|
||||||
__jit_debug_descriptor.relevant_entry = entry;
|
__jit_debug_descriptor.relevant_entry = entry;
|
||||||
__jit_debug_descriptor.action_flag = action as u32;
|
__jit_debug_descriptor.action_flag = action as u32;
|
||||||
|
__jit_debug_register_code();
|
||||||
|
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
|
||||||
|
__jit_debug_descriptor.action_flag = JITAction::JIT_NOACTION as _;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry
|
entry
|
||||||
|
@ -66,10 +66,10 @@ pub mod vmcalls;
|
|||||||
pub use trampoline_x64 as trampoline;
|
pub use trampoline_x64 as trampoline;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub mod fault;
|
pub mod fault;
|
||||||
|
pub mod jit_debug;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
#[cfg(feature = "managed")]
|
#[cfg(feature = "managed")]
|
||||||
pub mod tiering;
|
pub mod tiering;
|
||||||
pub mod jit_debug;
|
|
||||||
|
|
||||||
use self::error::CompileResult;
|
use self::error::CompileResult;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
|
@ -227,6 +227,7 @@ impl UnsharedMemory {
|
|||||||
base: std::ptr::null_mut(),
|
base: std::ptr::null_mut(),
|
||||||
bound: 0,
|
bound: 0,
|
||||||
memory: std::ptr::null_mut(),
|
memory: std::ptr::null_mut(),
|
||||||
|
vmctx: std::ptr::null_mut(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let storage = match desc.memory_type() {
|
let storage = match desc.memory_type() {
|
||||||
@ -314,6 +315,7 @@ impl SharedMemory {
|
|||||||
base: std::ptr::null_mut(),
|
base: std::ptr::null_mut(),
|
||||||
bound: 0,
|
bound: 0,
|
||||||
memory: std::ptr::null_mut(),
|
memory: std::ptr::null_mut(),
|
||||||
|
vmctx: std::ptr::null_mut(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let memory = StaticMemory::new(desc, &mut local)?;
|
let memory = StaticMemory::new(desc, &mut local)?;
|
||||||
|
@ -20,18 +20,12 @@ use indexmap::IndexMap;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct DebugInfo {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This is used to instantiate a new WebAssembly module.
|
/// This is used to instantiate a new WebAssembly module.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct ModuleInner {
|
pub struct ModuleInner {
|
||||||
pub runnable_module: Arc<Box<dyn RunnableModule>>,
|
pub runnable_module: Arc<Box<dyn RunnableModule>>,
|
||||||
pub cache_gen: Box<dyn CacheGen>,
|
pub cache_gen: Box<dyn CacheGen>,
|
||||||
pub info: ModuleInfo,
|
pub info: ModuleInfo,
|
||||||
pub debug_info: Option<DebugInfo>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Container for module data including memories, globals, tables, imports, and exports.
|
/// Container for module data including memories, globals, tables, imports, and exports.
|
||||||
@ -83,6 +77,18 @@ pub struct ModuleInfo {
|
|||||||
|
|
||||||
/// Custom sections.
|
/// Custom sections.
|
||||||
pub custom_sections: HashMap<String, Vec<u8>>,
|
pub custom_sections: HashMap<String, Vec<u8>>,
|
||||||
|
|
||||||
|
/// Debug info for funcs
|
||||||
|
pub func_debug_info: Map<FuncIndex, FuncDebugInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
/// info about functions for debugging
|
||||||
|
pub struct FuncDebugInfo {
|
||||||
|
/// byte offset from start of code section where the function starts at
|
||||||
|
pub start: u32,
|
||||||
|
/// byte offset from start of code section where the function starts at
|
||||||
|
pub end: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleInfo {
|
impl ModuleInfo {
|
||||||
|
@ -6,8 +6,8 @@ use crate::{
|
|||||||
backend::{CompilerConfig, RunnableModule},
|
backend::{CompilerConfig, RunnableModule},
|
||||||
error::CompileError,
|
error::CompileError,
|
||||||
module::{
|
module::{
|
||||||
DataInitializer, ExportIndex, ImportName, ModuleInfo, StringTable, StringTableBuilder,
|
DataInitializer, ExportIndex, FuncDebugInfo, ImportName, ModuleInfo, StringTable,
|
||||||
TableInitializer,
|
StringTableBuilder, TableInitializer,
|
||||||
},
|
},
|
||||||
structures::{Map, TypedIndex},
|
structures::{Map, TypedIndex},
|
||||||
types::{
|
types::{
|
||||||
@ -90,6 +90,8 @@ pub fn read_module<
|
|||||||
em_symbol_map: compiler_config.symbol_map.clone(),
|
em_symbol_map: compiler_config.symbol_map.clone(),
|
||||||
|
|
||||||
custom_sections: HashMap::new(),
|
custom_sections: HashMap::new(),
|
||||||
|
|
||||||
|
func_debug_info: Map::new(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let mut parser = wasmparser::ValidatingParser::new(
|
let mut parser = wasmparser::ValidatingParser::new(
|
||||||
@ -206,91 +208,113 @@ pub fn read_module<
|
|||||||
ParserState::StartSectionEntry(start_index) => {
|
ParserState::StartSectionEntry(start_index) => {
|
||||||
info.write().unwrap().start_func = Some(FuncIndex::new(start_index as usize));
|
info.write().unwrap().start_func = Some(FuncIndex::new(start_index as usize));
|
||||||
}
|
}
|
||||||
ParserState::BeginFunctionBody { .. } => {
|
ParserState::BeginFunctionBody { range } => {
|
||||||
let id = func_count;
|
let id = func_count;
|
||||||
if !mcg_info_fed {
|
if !mcg_info_fed {
|
||||||
mcg_info_fed = true;
|
mcg_info_fed = true;
|
||||||
info.write().unwrap().namespace_table =
|
{
|
||||||
namespace_builder.take().unwrap().finish();
|
let mut info_write = info.write().unwrap();
|
||||||
info.write().unwrap().name_table = name_builder.take().unwrap().finish();
|
info_write.namespace_table = namespace_builder.take().unwrap().finish();
|
||||||
mcg.feed_signatures(info.read().unwrap().signatures.clone())
|
info_write.name_table = name_builder.take().unwrap().finish();
|
||||||
|
}
|
||||||
|
let info_read = info.read().unwrap();
|
||||||
|
mcg.feed_signatures(info_read.signatures.clone())
|
||||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||||
mcg.feed_function_signatures(info.read().unwrap().func_assoc.clone())
|
mcg.feed_function_signatures(info_read.func_assoc.clone())
|
||||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||||
mcg.check_precondition(&info.read().unwrap())
|
mcg.check_precondition(&info_read)
|
||||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let fcg = mcg
|
let fcg = mcg
|
||||||
.next_function(Arc::clone(&info))
|
.next_function(Arc::clone(&info), (range.start as u32, range.end as u32))
|
||||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||||
|
|
||||||
let info_read = info.read().unwrap();
|
{
|
||||||
let sig = info_read
|
let info_read = info.read().unwrap();
|
||||||
.signatures
|
let sig = info_read
|
||||||
.get(
|
.signatures
|
||||||
*info
|
.get(
|
||||||
.read()
|
*info
|
||||||
.unwrap()
|
.read()
|
||||||
.func_assoc
|
.unwrap()
|
||||||
.get(FuncIndex::new(
|
.func_assoc
|
||||||
id as usize + info.read().unwrap().imported_functions.len(),
|
.get(FuncIndex::new(
|
||||||
))
|
id as usize + info_read.imported_functions.len(),
|
||||||
.unwrap(),
|
))
|
||||||
)
|
.unwrap(),
|
||||||
.unwrap();
|
)
|
||||||
for ret in sig.returns() {
|
.unwrap();
|
||||||
fcg.feed_return(type_to_wp_type(*ret))
|
for ret in sig.returns() {
|
||||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
fcg.feed_return(type_to_wp_type(*ret))
|
||||||
}
|
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||||
for param in sig.params() {
|
}
|
||||||
fcg.feed_param(type_to_wp_type(*param))
|
for param in sig.params() {
|
||||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
fcg.feed_param(type_to_wp_type(*param))
|
||||||
}
|
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||||
|
|
||||||
let mut body_begun = false;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let state = parser.read();
|
|
||||||
match state {
|
|
||||||
ParserState::Error(err) => return Err(LoadError::Parse(*err)),
|
|
||||||
ParserState::FunctionBodyLocals { ref locals } => {
|
|
||||||
for &(count, ty) in locals.iter() {
|
|
||||||
fcg.feed_local(ty, count as usize)
|
|
||||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ParserState::CodeOperator(op) => {
|
|
||||||
if !body_begun {
|
|
||||||
body_begun = true;
|
|
||||||
fcg.begin_body(&info.read().unwrap())
|
|
||||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
|
||||||
middlewares
|
|
||||||
.run(
|
|
||||||
Some(fcg),
|
|
||||||
Event::Internal(InternalEvent::FunctionBegin(id as u32)),
|
|
||||||
&info.read().unwrap(),
|
|
||||||
)
|
|
||||||
.map_err(LoadError::Codegen)?;
|
|
||||||
}
|
|
||||||
middlewares
|
|
||||||
.run(Some(fcg), Event::Wasm(op), &info.read().unwrap())
|
|
||||||
.map_err(LoadError::Codegen)?;
|
|
||||||
}
|
|
||||||
ParserState::EndFunctionBody => break,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
middlewares
|
|
||||||
.run(
|
let mut operator_parser = parser.create_binary_reader();
|
||||||
Some(fcg),
|
|
||||||
Event::Internal(InternalEvent::FunctionEnd),
|
// read locals in function body
|
||||||
&info.read().unwrap(),
|
{
|
||||||
)
|
let local_count = operator_parser.read_local_count().unwrap();
|
||||||
.map_err(LoadError::Codegen)?;
|
let mut total = 0;
|
||||||
|
for _ in 0..local_count {
|
||||||
|
let cur_pos = range.start as u32 + operator_parser.current_position() as u32;
|
||||||
|
let (count, ty) = operator_parser
|
||||||
|
.read_local_decl(&mut total)
|
||||||
|
.expect("Expected local");
|
||||||
|
fcg.feed_local(ty, count as usize, cur_pos)
|
||||||
|
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read instruction locations into vector for debug purposes
|
||||||
|
{
|
||||||
|
let info_read = info.read().unwrap();
|
||||||
|
let mut cur_pos = range.start as u32 + operator_parser.current_position() as u32;
|
||||||
|
fcg.begin_body(&info_read)
|
||||||
|
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||||
|
middlewares
|
||||||
|
.run(
|
||||||
|
Some(fcg),
|
||||||
|
Event::Internal(InternalEvent::FunctionBegin(id as u32)),
|
||||||
|
&info_read,
|
||||||
|
cur_pos,
|
||||||
|
)
|
||||||
|
.map_err(LoadError::Codegen)?;
|
||||||
|
|
||||||
|
while let Ok(op) = operator_parser.read_operator() {
|
||||||
|
middlewares
|
||||||
|
.run(Some(fcg), Event::WasmOwned(op), &info_read, cur_pos)
|
||||||
|
.map_err(LoadError::Codegen)?;
|
||||||
|
cur_pos = range.start as u32 + operator_parser.current_position() as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_pos = range.start as u32 + operator_parser.current_position() as u32;
|
||||||
|
middlewares
|
||||||
|
.run(
|
||||||
|
Some(fcg),
|
||||||
|
Event::Internal(InternalEvent::FunctionEnd),
|
||||||
|
&info_read,
|
||||||
|
cur_pos,
|
||||||
|
)
|
||||||
|
.map_err(LoadError::Codegen)?;
|
||||||
|
}
|
||||||
|
|
||||||
fcg.finalize()
|
fcg.finalize()
|
||||||
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
.map_err(|x| LoadError::Codegen(format!("{:?}", x)))?;
|
||||||
func_count = func_count.wrapping_add(1);
|
func_count = func_count.wrapping_add(1);
|
||||||
|
|
||||||
|
// debug info
|
||||||
|
let debug_entry = FuncDebugInfo {
|
||||||
|
start: range.start as u32,
|
||||||
|
end: range.end as u32,
|
||||||
|
};
|
||||||
|
info.write().unwrap().func_debug_info.push(debug_entry);
|
||||||
}
|
}
|
||||||
ParserState::BeginActiveElementSectionEntry(table_index) => {
|
ParserState::BeginActiveElementSectionEntry(table_index) => {
|
||||||
let table_index = TableIndex::new(table_index as usize);
|
let table_index = TableIndex::new(table_index as usize);
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
module::{ModuleInfo, ModuleInner},
|
module::{ModuleInfo, ModuleInner},
|
||||||
sig_registry::SigRegistry,
|
sig_registry::SigRegistry,
|
||||||
structures::TypedIndex,
|
structures::TypedIndex,
|
||||||
types::{LocalOrImport, MemoryIndex, TableIndex, Value},
|
types::{LocalOrImport, MemoryIndex, TableIndex, Value, LocalMemoryIndex},
|
||||||
vmcalls,
|
vmcalls,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
@ -134,6 +134,9 @@ pub struct InternalCtx {
|
|||||||
|
|
||||||
/// Interrupt signal mem.
|
/// Interrupt signal mem.
|
||||||
pub interrupt_signal_mem: *mut u8,
|
pub interrupt_signal_mem: *mut u8,
|
||||||
|
|
||||||
|
/// hmm
|
||||||
|
pub first_mem: *mut LocalMemory,
|
||||||
}
|
}
|
||||||
|
|
||||||
static INTERNAL_FIELDS: AtomicUsize = AtomicUsize::new(0);
|
static INTERNAL_FIELDS: AtomicUsize = AtomicUsize::new(0);
|
||||||
@ -283,6 +286,7 @@ impl Ctx {
|
|||||||
};
|
};
|
||||||
((*mem).base, (*mem).bound)
|
((*mem).base, (*mem).bound)
|
||||||
};
|
};
|
||||||
|
dbg!(mem_bound);
|
||||||
Self {
|
Self {
|
||||||
internal: InternalCtx {
|
internal: InternalCtx {
|
||||||
memories: local_backing.vm_memories.as_mut_ptr(),
|
memories: local_backing.vm_memories.as_mut_ptr(),
|
||||||
@ -306,6 +310,7 @@ impl Ctx {
|
|||||||
internals: &mut local_backing.internals.0,
|
internals: &mut local_backing.internals.0,
|
||||||
|
|
||||||
interrupt_signal_mem: get_interrupt_signal_mem(),
|
interrupt_signal_mem: get_interrupt_signal_mem(),
|
||||||
|
first_mem: local_backing.vm_memories[LocalMemoryIndex::new(0)],
|
||||||
},
|
},
|
||||||
local_functions: local_backing.local_functions.as_ptr(),
|
local_functions: local_backing.local_functions.as_ptr(),
|
||||||
|
|
||||||
@ -336,6 +341,8 @@ impl Ctx {
|
|||||||
};
|
};
|
||||||
((*mem).base, (*mem).bound)
|
((*mem).base, (*mem).bound)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dbg!(mem_bound);
|
||||||
Self {
|
Self {
|
||||||
internal: InternalCtx {
|
internal: InternalCtx {
|
||||||
memories: local_backing.vm_memories.as_mut_ptr(),
|
memories: local_backing.vm_memories.as_mut_ptr(),
|
||||||
@ -359,6 +366,8 @@ impl Ctx {
|
|||||||
internals: &mut local_backing.internals.0,
|
internals: &mut local_backing.internals.0,
|
||||||
|
|
||||||
interrupt_signal_mem: get_interrupt_signal_mem(),
|
interrupt_signal_mem: get_interrupt_signal_mem(),
|
||||||
|
|
||||||
|
first_mem: local_backing.vm_memories[LocalMemoryIndex::new(0)],
|
||||||
},
|
},
|
||||||
local_functions: local_backing.local_functions.as_ptr(),
|
local_functions: local_backing.local_functions.as_ptr(),
|
||||||
|
|
||||||
@ -537,7 +546,7 @@ impl Ctx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const fn offset_local_functions() -> u8 {
|
pub const fn offset_local_functions() -> u8 {
|
||||||
14 * (mem::size_of::<usize>() as u8)
|
15 * (mem::size_of::<usize>() as u8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,6 +675,9 @@ pub struct LocalMemory {
|
|||||||
/// This is either `*mut DynamicMemory`, `*mut StaticMemory`,
|
/// This is either `*mut DynamicMemory`, `*mut StaticMemory`,
|
||||||
/// or `*mut SharedStaticMemory`.
|
/// or `*mut SharedStaticMemory`.
|
||||||
pub memory: *mut (),
|
pub memory: *mut (),
|
||||||
|
|
||||||
|
/// wat
|
||||||
|
pub vmctx: *mut Ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
// manually implemented because LocalMemory contains raw pointers
|
// manually implemented because LocalMemory contains raw pointers
|
||||||
|
Reference in New Issue
Block a user