Don't generate DWARF sections when no functions were compiled. (#894)

This commit is contained in:
Yury Delendik
2020-02-03 14:41:29 -06:00
committed by GitHub
parent ea4faa4a01
commit 4599234c6f
8 changed files with 138 additions and 62 deletions

View File

@@ -7,14 +7,28 @@ use wasmtime_environ::entity::EntityRef;
use wasmtime_environ::ir::{StackSlots, ValueLabel, ValueLabelsRanges, ValueLoc}; use wasmtime_environ::ir::{StackSlots, ValueLabel, ValueLabelsRanges, ValueLoc};
use wasmtime_environ::isa::RegUnit; use wasmtime_environ::isa::RegUnit;
use wasmtime_environ::wasm::{get_vmctx_value_label, DefinedFuncIndex}; use wasmtime_environ::wasm::{get_vmctx_value_label, DefinedFuncIndex};
use wasmtime_environ::ModuleMemoryOffset;
#[derive(Debug)] #[derive(Debug)]
pub struct FunctionFrameInfo<'a> { pub struct FunctionFrameInfo<'a> {
pub value_ranges: &'a ValueLabelsRanges, pub value_ranges: &'a ValueLabelsRanges,
pub memory_offset: i64, pub memory_offset: ModuleMemoryOffset,
pub stack_slots: &'a StackSlots, pub stack_slots: &'a StackSlots,
} }
impl<'a> FunctionFrameInfo<'a> {
fn vmctx_memory_offset(&self) -> Option<i64> {
match self.memory_offset {
ModuleMemoryOffset::Defined(x) => Some(x as i64),
ModuleMemoryOffset::Imported(_) => {
// TODO implement memory offset for imported memory
None
}
ModuleMemoryOffset::None => None,
}
}
}
#[derive(Debug)] #[derive(Debug)]
enum CompiledExpressionPart { enum CompiledExpressionPart {
Code(Vec<u8>), Code(Vec<u8>),
@@ -142,20 +156,32 @@ fn append_memory_deref(
) -> write::Result<bool> { ) -> write::Result<bool> {
use gimli::write::Writer; use gimli::write::Writer;
let mut writer = write::EndianVec::new(endian); let mut writer = write::EndianVec::new(endian);
// FIXME for imported memory
match vmctx_loc { match vmctx_loc {
ValueLoc::Reg(vmctx_reg) => { ValueLoc::Reg(vmctx_reg) => {
let reg = map_reg(vmctx_reg); let reg = map_reg(vmctx_reg);
writer.write_u8(gimli::constants::DW_OP_breg0.0 + reg.0 as u8)?; writer.write_u8(gimli::constants::DW_OP_breg0.0 + reg.0 as u8)?;
writer.write_sleb128(frame_info.memory_offset)?; let memory_offset = match frame_info.vmctx_memory_offset() {
Some(offset) => offset,
None => {
return Ok(false);
}
};
writer.write_sleb128(memory_offset)?;
} }
ValueLoc::Stack(ss) => { ValueLoc::Stack(ss) => {
if let Some(ss_offset) = frame_info.stack_slots[ss].offset { if let Some(ss_offset) = frame_info.stack_slots[ss].offset {
writer.write_u8(gimli::constants::DW_OP_breg0.0 + X86_64::RBP.0 as u8)?; writer.write_u8(gimli::constants::DW_OP_breg0.0 + X86_64::RBP.0 as u8)?;
writer.write_sleb128(ss_offset as i64 + 16)?; writer.write_sleb128(ss_offset as i64 + 16)?;
writer.write_u8(gimli::constants::DW_OP_deref.0 as u8)?; writer.write_u8(gimli::constants::DW_OP_deref.0 as u8)?;
writer.write_u8(gimli::constants::DW_OP_consts.0 as u8)?; writer.write_u8(gimli::constants::DW_OP_consts.0 as u8)?;
writer.write_sleb128(frame_info.memory_offset)?; let memory_offset = match frame_info.vmctx_memory_offset() {
Some(offset) => offset,
None => {
return Ok(false);
}
};
writer.write_sleb128(memory_offset)?;
writer.write_u8(gimli::constants::DW_OP_plus.0 as u8)?; writer.write_u8(gimli::constants::DW_OP_plus.0 as u8)?;
} else { } else {
return Ok(false); return Ok(false);

View File

@@ -3,7 +3,7 @@ use super::expression::{CompiledExpression, FunctionFrameInfo};
use anyhow::Error; use anyhow::Error;
use gimli::write; use gimli::write;
use wasmtime_environ::wasm::DefinedFuncIndex; use wasmtime_environ::wasm::DefinedFuncIndex;
use wasmtime_environ::{ModuleVmctxInfo, ValueLabelsRanges}; use wasmtime_environ::{ModuleMemoryOffset, ModuleVmctxInfo, ValueLabelsRanges};
pub(crate) fn add_internal_types( pub(crate) fn add_internal_types(
comp_unit: &mut write::Unit, comp_unit: &mut write::Unit,
@@ -46,18 +46,26 @@ pub(crate) fn add_internal_types(
write::AttributeValue::ThisUnitEntryRef(memory_byte_die_id), write::AttributeValue::ThisUnitEntryRef(memory_byte_die_id),
); );
let memory_offset = module_info.memory_offset; // Create artificial VMContext type and its reference for convinience viewing
// its fields (such as memory ref) in a debugger.
let vmctx_die_id = comp_unit.add(root_id, gimli::DW_TAG_structure_type); let vmctx_die_id = comp_unit.add(root_id, gimli::DW_TAG_structure_type);
let vmctx_die = comp_unit.get_mut(vmctx_die_id); let vmctx_die = comp_unit.get_mut(vmctx_die_id);
vmctx_die.set( vmctx_die.set(
gimli::DW_AT_name, gimli::DW_AT_name,
write::AttributeValue::StringRef(out_strings.add("WasmtimeVMContext")), write::AttributeValue::StringRef(out_strings.add("WasmtimeVMContext")),
); );
match module_info.memory_offset {
ModuleMemoryOffset::Defined(memory_offset) => {
// The context has defined memory: extend the WasmtimeVMContext size
// past the "memory" field.
const MEMORY_FIELD_SIZE_PLUS_PADDING: u32 = 8;
vmctx_die.set( vmctx_die.set(
gimli::DW_AT_byte_size, gimli::DW_AT_byte_size,
write::AttributeValue::Data4(memory_offset as u32 + 8), write::AttributeValue::Data4(memory_offset + MEMORY_FIELD_SIZE_PLUS_PADDING),
); );
// Define the "memory" field which is a direct pointer to allocated Wasm memory.
let m_die_id = comp_unit.add(vmctx_die_id, gimli::DW_TAG_member); let m_die_id = comp_unit.add(vmctx_die_id, gimli::DW_TAG_member);
let m_die = comp_unit.get_mut(m_die_id); let m_die = comp_unit.get_mut(m_die_id);
m_die.set( m_die.set(
@@ -72,6 +80,12 @@ pub(crate) fn add_internal_types(
gimli::DW_AT_data_member_location, gimli::DW_AT_data_member_location,
write::AttributeValue::Udata(memory_offset as u64), write::AttributeValue::Udata(memory_offset as u64),
); );
}
ModuleMemoryOffset::Imported(_) => {
// TODO implement convinience pointer to and additional types for VMMemoryImport.
}
ModuleMemoryOffset::None => (),
}
let vmctx_ptr_die_id = comp_unit.add(root_id, gimli::DW_TAG_pointer_type); let vmctx_ptr_die_id = comp_unit.add(root_id, gimli::DW_TAG_pointer_type);
let vmctx_ptr_die = comp_unit.get_mut(vmctx_ptr_die_id); let vmctx_ptr_die = comp_unit.get_mut(vmctx_ptr_die_id);
@@ -141,7 +155,7 @@ where
if let Some(value_ranges) = value_ranges.get(func_index) { if let Some(value_ranges) = value_ranges.get(func_index) {
let frame_info = FunctionFrameInfo { let frame_info = FunctionFrameInfo {
value_ranges, value_ranges,
memory_offset: module_info.memory_offset, memory_offset: module_info.memory_offset.clone(),
stack_slots: &module_info.stack_slots[func_index], stack_slots: &module_info.stack_slots[func_index],
}; };
Some(frame_info) Some(frame_info)

View File

@@ -48,10 +48,22 @@ pub type ValueLabelsRanges = PrimaryMap<DefinedFuncIndex, cranelift_codegen::Val
/// Stack slots for functions. /// Stack slots for functions.
pub type StackSlots = PrimaryMap<DefinedFuncIndex, ir::StackSlots>; pub type StackSlots = PrimaryMap<DefinedFuncIndex, ir::StackSlots>;
/// Memory definition offset in the VMContext structure.
#[derive(Debug, Clone)]
pub enum ModuleMemoryOffset {
/// Not available.
None,
/// Offset to the defined memory.
Defined(u32),
/// Offset to the imported memory.
Imported(u32),
}
/// Module `vmctx` related info. /// Module `vmctx` related info.
#[derive(Debug, Clone)]
pub struct ModuleVmctxInfo { pub struct ModuleVmctxInfo {
/// The memory definition offset in the VMContext structure. /// The memory definition offset in the VMContext structure.
pub memory_offset: i64, pub memory_offset: ModuleMemoryOffset,
/// The functions stack slots. /// The functions stack slots.
pub stack_slots: StackSlots, pub stack_slots: StackSlots,

View File

@@ -40,7 +40,8 @@ pub mod cranelift;
pub mod lightbeam; pub mod lightbeam;
pub use crate::address_map::{ pub use crate::address_map::{
FunctionAddressMap, InstructionAddressMap, ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges, FunctionAddressMap, InstructionAddressMap, ModuleAddressMap, ModuleMemoryOffset,
ModuleVmctxInfo, ValueLabelsRanges,
}; };
pub use crate::cache::{create_new_config as cache_create_new_config, init as cache_init}; pub use crate::cache::{create_new_config as cache_create_new_config, init as cache_init};
pub use crate::compilation::{ pub use crate::compilation::{

View File

@@ -13,3 +13,9 @@ fn instantiate_empty_module() {
let data = wat::parse_str(include_str!("./regressions/empty.wat")).unwrap(); let data = wat::parse_str(include_str!("./regressions/empty.wat")).unwrap();
oracles::instantiate(&data, Strategy::Auto); oracles::instantiate(&data, Strategy::Auto);
} }
#[test]
fn instantiate_empty_module_with_memory() {
let data = wat::parse_str(include_str!("./regressions/empty_with_memory.wat")).unwrap();
oracles::instantiate(&data, Strategy::Auto);
}

View File

@@ -0,0 +1 @@
(module (memory 1))

View File

@@ -14,10 +14,11 @@ use std::convert::TryFrom;
use wasmtime_debug::{emit_debugsections_image, DebugInfoData}; use wasmtime_debug::{emit_debugsections_image, DebugInfoData};
use wasmtime_environ::entity::{EntityRef, PrimaryMap}; use wasmtime_environ::entity::{EntityRef, PrimaryMap};
use wasmtime_environ::isa::{TargetFrontendConfig, TargetIsa}; use wasmtime_environ::isa::{TargetFrontendConfig, TargetIsa};
use wasmtime_environ::wasm::{DefinedFuncIndex, DefinedMemoryIndex}; use wasmtime_environ::wasm::{DefinedFuncIndex, DefinedMemoryIndex, MemoryIndex};
use wasmtime_environ::{ use wasmtime_environ::{
Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo, Compiler as _C, Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo, Compiler as _C,
FunctionBodyData, Module, ModuleVmctxInfo, Relocations, Traps, Tunables, VMOffsets, FunctionBodyData, Module, ModuleMemoryOffset, ModuleVmctxInfo, Relocations, Traps, Tunables,
VMOffsets,
}; };
use wasmtime_runtime::{ use wasmtime_runtime::{
get_mut_trap_registry, jit_function_registry, InstantiationError, SignatureRegistry, get_mut_trap_registry, jit_function_registry, InstantiationError, SignatureRegistry,
@@ -174,10 +175,11 @@ impl Compiler {
jit_function_registry::register(ptr as usize, ptr as usize + body_len, tag); jit_function_registry::register(ptr as usize, ptr as usize + body_len, tag);
} }
let dbg = if let Some(debug_data) = debug_data { // Translate debug info (DWARF) only if at least one function is present.
let dbg = if debug_data.is_some() && !allocated_functions.is_empty() {
let target_config = self.isa.frontend_config(); let target_config = self.isa.frontend_config();
let ofs = VMOffsets::new(target_config.pointer_bytes(), &module); let ofs = VMOffsets::new(target_config.pointer_bytes(), &module);
if ofs.num_defined_memories > 0 {
let mut funcs = Vec::new(); let mut funcs = Vec::new();
for (i, allocated) in allocated_functions.into_iter() { for (i, allocated) in allocated_functions.into_iter() {
let ptr = (*allocated) as *const u8; let ptr = (*allocated) as *const u8;
@@ -185,17 +187,23 @@ impl Compiler {
funcs.push((ptr, body_len)); funcs.push((ptr, body_len));
} }
let module_vmctx_info = { let module_vmctx_info = {
let memory_offset =
ofs.vmctx_vmmemory_definition_base(DefinedMemoryIndex::new(0)) as i64;
ModuleVmctxInfo { ModuleVmctxInfo {
memory_offset, memory_offset: if ofs.num_imported_memories > 0 {
ModuleMemoryOffset::Imported(ofs.vmctx_vmmemory_import(MemoryIndex::new(0)))
} else if ofs.num_defined_memories > 0 {
ModuleMemoryOffset::Defined(
ofs.vmctx_vmmemory_definition_base(DefinedMemoryIndex::new(0)),
)
} else {
ModuleMemoryOffset::None
},
stack_slots, stack_slots,
} }
}; };
let bytes = emit_debugsections_image( let bytes = emit_debugsections_image(
self.isa.triple().clone(), self.isa.triple().clone(),
target_config, target_config,
&debug_data, debug_data.as_ref().unwrap(),
&module_vmctx_info, &module_vmctx_info,
&address_transform, &address_transform,
&value_ranges, &value_ranges,
@@ -205,9 +213,6 @@ impl Compiler {
Some(bytes) Some(bytes)
} else { } else {
None None
}
} else {
None
}; };
let jt_offsets = compilation.get_jt_offsets(); let jt_offsets = compilation.get_jt_offsets();

View File

@@ -17,7 +17,8 @@ use wasmtime_debug::{emit_debugsections, read_debuginfo};
use wasmtime_environ::Lightbeam; use wasmtime_environ::Lightbeam;
use wasmtime_environ::{ use wasmtime_environ::{
cache_init, entity::EntityRef, settings, settings::Configurable, wasm::DefinedMemoryIndex, cache_init, entity::EntityRef, settings, settings::Configurable, wasm::DefinedMemoryIndex,
Compiler, Cranelift, ModuleEnvironment, ModuleVmctxInfo, Tunables, VMOffsets, wasm::MemoryIndex, Compiler, Cranelift, ModuleEnvironment, ModuleMemoryOffset, ModuleVmctxInfo,
Tunables, VMOffsets,
}; };
use wasmtime_jit::native; use wasmtime_jit::native;
use wasmtime_obj::emit_module; use wasmtime_obj::emit_module;
@@ -161,12 +162,22 @@ impl WasmToObjCommand {
} }
.context("failed to compile module")?; .context("failed to compile module")?;
if compilation.is_empty() {
bail!("no functions were found/compiled");
}
let module_vmctx_info = { let module_vmctx_info = {
let ofs = VMOffsets::new(target_config.pointer_bytes(), &module); let ofs = VMOffsets::new(target_config.pointer_bytes(), &module);
let memory_offset =
ofs.vmctx_vmmemory_definition_base(DefinedMemoryIndex::new(0)) as i64;
ModuleVmctxInfo { ModuleVmctxInfo {
memory_offset, memory_offset: if ofs.num_imported_memories > 0 {
ModuleMemoryOffset::Imported(ofs.vmctx_vmmemory_import(MemoryIndex::new(0)))
} else if ofs.num_defined_memories > 0 {
ModuleMemoryOffset::Defined(
ofs.vmctx_vmmemory_definition_base(DefinedMemoryIndex::new(0)),
)
} else {
ModuleMemoryOffset::None
},
stack_slots, stack_slots,
} }
}; };