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

View File

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

View File

@ -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,
}) })
} }
} }

View File

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

View File

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

View File

@ -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(_)) => {

View File

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

View File

@ -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(_)) => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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