Don't re-parse wasm for debuginfo (#2085)
* Don't re-parse wasm for debuginfo This commit updates debuginfo parsing to happen during the main translation of the original wasm module. This avoid re-parsing the wasm module twice (at least the section-level headers). Additionally this ties debuginfo directly to a `ModuleTranslation` which makes it easier to process debuginfo for nested modules in the upcoming module linking proposal. The changes here are summarized by taking the `read_debuginfo` function and merging it with the main module translation that happens which is driven by cranelift. Some new hooks were added to the module environment trait to support this, but most of it was integrating with existing hooks. * Fix tests in debug crate
This commit is contained in:
@@ -743,13 +743,11 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn declare_module_name(&mut self, name: &'data str) -> WasmResult<()> {
|
||||
fn declare_module_name(&mut self, name: &'data str) {
|
||||
self.module_name = Some(String::from(name));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn declare_func_name(&mut self, func_index: FuncIndex, name: &'data str) -> WasmResult<()> {
|
||||
fn declare_func_name(&mut self, func_index: FuncIndex, name: &'data str) {
|
||||
self.function_names[func_index] = String::from(name);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,20 @@ impl TryFrom<wasmparser::Type> for WasmType {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WasmType> for wasmparser::Type {
|
||||
fn from(ty: WasmType) -> wasmparser::Type {
|
||||
match ty {
|
||||
WasmType::I32 => wasmparser::Type::I32,
|
||||
WasmType::I64 => wasmparser::Type::I64,
|
||||
WasmType::F32 => wasmparser::Type::F32,
|
||||
WasmType::F64 => wasmparser::Type::F64,
|
||||
WasmType::V128 => wasmparser::Type::V128,
|
||||
WasmType::FuncRef => wasmparser::Type::FuncRef,
|
||||
WasmType::ExternRef => wasmparser::Type::ExternRef,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// WebAssembly function type -- equivalent of `wasmparser`'s FuncType.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||
@@ -743,10 +757,13 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment {
|
||||
/// Declare a passive data segment.
|
||||
fn declare_passive_data(&mut self, data_index: DataIndex, data: &'data [u8]) -> WasmResult<()>;
|
||||
|
||||
/// Indicates how many functions the code section reports and the byte
|
||||
/// offset of where the code sections starts.
|
||||
fn reserve_function_bodies(&mut self, bodies: u32, code_section_offset: u64) {
|
||||
drop((bodies, code_section_offset));
|
||||
}
|
||||
|
||||
/// Provides the contents of a function body.
|
||||
///
|
||||
/// Note there's no `reserve_function_bodies` function because the number of
|
||||
/// functions is already provided by `reserve_func_types`.
|
||||
fn define_function_body(
|
||||
&mut self,
|
||||
module_translation_state: &ModuleTranslationState,
|
||||
@@ -773,16 +790,19 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment {
|
||||
///
|
||||
/// By default this does nothing, but implementations can use this to read
|
||||
/// the module name subsection of the custom name section if desired.
|
||||
fn declare_module_name(&mut self, _name: &'data str) -> WasmResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn declare_module_name(&mut self, _name: &'data str) {}
|
||||
|
||||
/// Declares the name of a function to the environment.
|
||||
///
|
||||
/// By default this does nothing, but implementations can use this to read
|
||||
/// the function name subsection of the custom name section if desired.
|
||||
fn declare_func_name(&mut self, _func_index: FuncIndex, _name: &'data str) -> WasmResult<()> {
|
||||
Ok(())
|
||||
fn declare_func_name(&mut self, _func_index: FuncIndex, _name: &'data str) {}
|
||||
|
||||
/// Declares the name of a function's local to the environment.
|
||||
///
|
||||
/// By default this does nothing, but implementations can use this to read
|
||||
/// the local name subsection of the custom name section if desired.
|
||||
fn declare_local_name(&mut self, _func_index: FuncIndex, _local_index: u32, _name: &'data str) {
|
||||
}
|
||||
|
||||
/// Indicates that a custom section has been found in the wasm file
|
||||
|
||||
@@ -59,7 +59,10 @@ pub fn translate_module<'data>(
|
||||
parse_element_section(elements, environ)?;
|
||||
}
|
||||
|
||||
Payload::CodeSectionStart { .. } => {}
|
||||
Payload::CodeSectionStart { count, range, .. } => {
|
||||
environ.reserve_function_bodies(count, range.start as u64);
|
||||
}
|
||||
|
||||
Payload::CodeSectionEntry(code) => {
|
||||
let mut code = code.get_binary_reader();
|
||||
let size = code.bytes_remaining();
|
||||
@@ -91,7 +94,14 @@ pub fn translate_module<'data>(
|
||||
name: "name",
|
||||
data,
|
||||
data_offset,
|
||||
} => parse_name_section(NameSectionReader::new(data, data_offset)?, environ)?,
|
||||
} => {
|
||||
let result = NameSectionReader::new(data, data_offset)
|
||||
.map_err(|e| e.into())
|
||||
.and_then(|s| parse_name_section(s, environ));
|
||||
if let Err(e) = result {
|
||||
log::warn!("failed to parse name section {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
Payload::CustomSection { name, data, .. } => environ.custom_section(name, data)?,
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::translation_utils::{
|
||||
tabletype_to_type, type_to_type, DataIndex, ElemIndex, FuncIndex, Global, GlobalIndex,
|
||||
GlobalInit, Memory, MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex,
|
||||
};
|
||||
use crate::{wasm_unsupported, HashMap};
|
||||
use crate::wasm_unsupported;
|
||||
use core::convert::TryFrom;
|
||||
use core::convert::TryInto;
|
||||
use cranelift_codegen::ir::immediates::V128Imm;
|
||||
@@ -26,8 +26,8 @@ use wasmparser::{
|
||||
self, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems, ElementKind,
|
||||
ElementSectionReader, Export, ExportSectionReader, ExternalKind, FunctionSectionReader,
|
||||
GlobalSectionReader, GlobalType, ImportSectionEntryType, ImportSectionReader,
|
||||
MemorySectionReader, MemoryType, NameSectionReader, Naming, NamingReader, Operator,
|
||||
TableSectionReader, Type, TypeDef, TypeSectionReader,
|
||||
MemorySectionReader, MemoryType, NameSectionReader, Naming, Operator, TableSectionReader, Type,
|
||||
TypeDef, TypeSectionReader,
|
||||
};
|
||||
|
||||
/// Parses the Type section of the wasm module.
|
||||
@@ -404,53 +404,40 @@ pub fn parse_data_section<'data>(
|
||||
|
||||
/// Parses the Name section of the wasm module.
|
||||
pub fn parse_name_section<'data>(
|
||||
mut names: NameSectionReader<'data>,
|
||||
names: NameSectionReader<'data>,
|
||||
environ: &mut dyn ModuleEnvironment<'data>,
|
||||
) -> WasmResult<()> {
|
||||
while let Ok(subsection) = names.read() {
|
||||
match subsection {
|
||||
wasmparser::Name::Function(function_subsection) => {
|
||||
if let Some(function_names) = function_subsection
|
||||
.get_map()
|
||||
.ok()
|
||||
.and_then(parse_function_name_subsection)
|
||||
{
|
||||
for (index, name) in function_names {
|
||||
environ.declare_func_name(index, name)?;
|
||||
for subsection in names {
|
||||
match subsection? {
|
||||
wasmparser::Name::Function(f) => {
|
||||
let mut names = f.get_map()?;
|
||||
for _ in 0..names.get_count() {
|
||||
let Naming { index, name } = names.read()?;
|
||||
// We reserve `u32::MAX` for our own use in cranelift-entity.
|
||||
if index != u32::max_value() {
|
||||
environ.declare_func_name(FuncIndex::from_u32(index), name);
|
||||
}
|
||||
}
|
||||
}
|
||||
wasmparser::Name::Module(module) => {
|
||||
if let Ok(name) = module.get_name() {
|
||||
environ.declare_module_name(name)?;
|
||||
let name = module.get_name()?;
|
||||
environ.declare_module_name(name);
|
||||
}
|
||||
wasmparser::Name::Local(l) => {
|
||||
let mut reader = l.get_function_local_reader()?;
|
||||
for _ in 0..reader.get_count() {
|
||||
let f = reader.read()?;
|
||||
if f.func_index == u32::max_value() {
|
||||
continue;
|
||||
}
|
||||
let mut map = f.get_map()?;
|
||||
for _ in 0..map.get_count() {
|
||||
let Naming { index, name } = map.read()?;
|
||||
environ.declare_local_name(FuncIndex::from_u32(f.func_index), index, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
wasmparser::Name::Local(_) => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_function_name_subsection(
|
||||
mut naming_reader: NamingReader<'_>,
|
||||
) -> Option<HashMap<FuncIndex, &str>> {
|
||||
let mut function_names = HashMap::new();
|
||||
for _ in 0..naming_reader.get_count() {
|
||||
let Naming { index, name } = naming_reader.read().ok()?;
|
||||
if index == std::u32::MAX {
|
||||
// We reserve `u32::MAX` for our own use in cranelift-entity.
|
||||
return None;
|
||||
}
|
||||
|
||||
if function_names
|
||||
.insert(FuncIndex::from_u32(index), name)
|
||||
.is_some()
|
||||
{
|
||||
// If the function index has been previously seen, then we
|
||||
// break out of the loop and early return `None`, because these
|
||||
// should be unique.
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(function_names)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user