allow module environment to parse name section
This commit is contained in:
committed by
Benjamin Bouvier
parent
3293ca6b69
commit
ac2ca6116b
@@ -17,7 +17,7 @@ use cranelift_codegen::ir::immediates::{Offset32, Uimm64};
|
|||||||
use cranelift_codegen::ir::types::*;
|
use cranelift_codegen::ir::types::*;
|
||||||
use cranelift_codegen::ir::{self, InstBuilder};
|
use cranelift_codegen::ir::{self, InstBuilder};
|
||||||
use cranelift_codegen::isa::TargetFrontendConfig;
|
use cranelift_codegen::isa::TargetFrontendConfig;
|
||||||
use cranelift_entity::{EntityRef, PrimaryMap};
|
use cranelift_entity::{EntityRef, PrimaryMap, SecondaryMap};
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
@@ -124,6 +124,9 @@ pub struct DummyEnvironment {
|
|||||||
|
|
||||||
/// Instructs to collect debug data during translation.
|
/// Instructs to collect debug data during translation.
|
||||||
debug_info: bool,
|
debug_info: bool,
|
||||||
|
|
||||||
|
/// Function names.
|
||||||
|
function_names: SecondaryMap<FuncIndex, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DummyEnvironment {
|
impl DummyEnvironment {
|
||||||
@@ -135,6 +138,7 @@ impl DummyEnvironment {
|
|||||||
func_bytecode_sizes: Vec::new(),
|
func_bytecode_sizes: Vec::new(),
|
||||||
return_mode,
|
return_mode,
|
||||||
debug_info,
|
debug_info,
|
||||||
|
function_names: SecondaryMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,6 +156,12 @@ impl DummyEnvironment {
|
|||||||
pub fn get_num_func_imports(&self) -> usize {
|
pub fn get_num_func_imports(&self) -> usize {
|
||||||
self.info.imported_funcs.len()
|
self.info.imported_funcs.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the name of the function, if a name for the function with
|
||||||
|
/// the corresponding index exists.
|
||||||
|
pub fn get_func_name(&self, func_index: FuncIndex) -> Option<&str> {
|
||||||
|
self.function_names.get(func_index).map(String::as_ref)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The `FuncEnvironment` implementation for use by the `DummyEnvironment`.
|
/// The `FuncEnvironment` implementation for use by the `DummyEnvironment`.
|
||||||
@@ -539,4 +549,9 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
|
|||||||
self.info.function_bodies.push(func);
|
self.info.function_bodies.push(func);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn declare_func_name(&mut self, func_index: FuncIndex, name: &'data str) -> WasmResult<()> {
|
||||||
|
self.function_names[func_index] = String::from(name);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -468,6 +468,14 @@ pub trait ModuleEnvironment<'data> {
|
|||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
) -> WasmResult<()>;
|
) -> WasmResult<()>;
|
||||||
|
|
||||||
|
/// 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(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Indicates that a custom section has been found in the wasm file
|
/// Indicates that a custom section has been found in the wasm file
|
||||||
fn custom_section(&mut self, name: &'data str, data: &'data [u8]) -> WasmResult<()> {
|
fn custom_section(&mut self, name: &'data str, data: &'data [u8]) -> WasmResult<()> {
|
||||||
drop((name, data));
|
drop((name, data));
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ use crate::environ::{ModuleEnvironment, WasmError, WasmResult};
|
|||||||
use crate::sections_translator::{
|
use crate::sections_translator::{
|
||||||
parse_code_section, parse_data_section, parse_element_section, parse_export_section,
|
parse_code_section, parse_data_section, parse_element_section, parse_export_section,
|
||||||
parse_function_section, parse_global_section, parse_import_section, parse_memory_section,
|
parse_function_section, parse_global_section, parse_import_section, parse_memory_section,
|
||||||
parse_start_section, parse_table_section, parse_type_section,
|
parse_name_section, parse_start_section, parse_table_section, parse_type_section,
|
||||||
};
|
};
|
||||||
use cranelift_codegen::timing;
|
use cranelift_codegen::timing;
|
||||||
use wasmparser::{ModuleReader, SectionCode};
|
use wasmparser::{CustomSectionKind, ModuleReader, SectionCode};
|
||||||
|
|
||||||
/// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cranelift IR
|
/// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cranelift IR
|
||||||
/// [`Function`](cranelift_codegen::ir::Function).
|
/// [`Function`](cranelift_codegen::ir::Function).
|
||||||
@@ -83,6 +83,14 @@ pub fn translate_module<'data>(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SectionCode::Custom {
|
||||||
|
kind: CustomSectionKind::Name,
|
||||||
|
name: _,
|
||||||
|
} => {
|
||||||
|
let names = section.get_name_section_reader()?;
|
||||||
|
parse_name_section(names, environ)?;
|
||||||
|
}
|
||||||
|
|
||||||
SectionCode::Custom { name, kind: _ } => {
|
SectionCode::Custom { name, kind: _ } => {
|
||||||
let mut reader = section.get_binary_reader();
|
let mut reader = section.get_binary_reader();
|
||||||
let len = reader.bytes_remaining();
|
let len = reader.bytes_remaining();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::translation_utils::{
|
|||||||
tabletype_to_type, type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory,
|
tabletype_to_type, type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory,
|
||||||
MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex,
|
MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex,
|
||||||
};
|
};
|
||||||
use crate::wasm_unsupported;
|
use crate::{wasm_unsupported, HashMap};
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use cranelift_codegen::ir::{self, AbiParam, Signature};
|
use cranelift_codegen::ir::{self, AbiParam, Signature};
|
||||||
use cranelift_entity::EntityRef;
|
use cranelift_entity::EntityRef;
|
||||||
@@ -21,8 +21,8 @@ use wasmparser::{
|
|||||||
self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementKind,
|
self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementKind,
|
||||||
ElementSectionReader, Export, ExportSectionReader, ExternalKind, FuncType,
|
ElementSectionReader, Export, ExportSectionReader, ExternalKind, FuncType,
|
||||||
FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType,
|
FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType,
|
||||||
ImportSectionReader, MemorySectionReader, MemoryType, Operator, TableSectionReader,
|
ImportSectionReader, MemorySectionReader, MemoryType, NameSectionReader, Naming, NamingReader,
|
||||||
TypeSectionReader,
|
Operator, TableSectionReader, TypeSectionReader,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parses the Type section of the wasm module.
|
/// Parses the Type section of the wasm module.
|
||||||
@@ -351,3 +351,47 @@ pub fn parse_data_section<'data>(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses the Name section of the wasm module.
|
||||||
|
pub fn parse_name_section<'data>(
|
||||||
|
mut 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)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
wasmparser::Name::Local(_) | wasmparser::Name::Module(_) => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_function_name_subsection<'data>(
|
||||||
|
mut naming_reader: NamingReader<'data>,
|
||||||
|
) -> 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 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(function_names);
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use cranelift_codegen::isa;
|
|||||||
use cranelift_codegen::print_errors::pretty_verifier_error;
|
use cranelift_codegen::print_errors::pretty_verifier_error;
|
||||||
use cranelift_codegen::settings::{self, Flags};
|
use cranelift_codegen::settings::{self, Flags};
|
||||||
use cranelift_codegen::verifier;
|
use cranelift_codegen::verifier;
|
||||||
use cranelift_wasm::{translate_module, DummyEnvironment, ReturnMode};
|
use cranelift_wasm::{translate_module, DummyEnvironment, FuncIndex, ReturnMode};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -10,7 +10,7 @@ use std::io::prelude::*;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use target_lexicon::triple;
|
use target_lexicon::triple;
|
||||||
use wabt::{wat2wasm_with_features, Features};
|
use wabt::{wat2wasm_with_features, Features, Wat2Wasm};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn testsuite() {
|
fn testsuite() {
|
||||||
@@ -31,17 +31,42 @@ fn testsuite() {
|
|||||||
let flags = Flags::new(settings::builder());
|
let flags = Flags::new(settings::builder());
|
||||||
for path in paths {
|
for path in paths {
|
||||||
let path = path.path();
|
let path = path.path();
|
||||||
handle_module(&path, &flags, ReturnMode::NormalReturns);
|
let data = read_module(&path);
|
||||||
|
handle_module(data, &flags, ReturnMode::NormalReturns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn use_fallthrough_return() {
|
fn use_fallthrough_return() {
|
||||||
let flags = Flags::new(settings::builder());
|
let flags = Flags::new(settings::builder());
|
||||||
handle_module(
|
let path = Path::new("../wasmtests/use_fallthrough_return.wat");
|
||||||
Path::new("../wasmtests/use_fallthrough_return.wat"),
|
let data = read_module(&path);
|
||||||
&flags,
|
handle_module(data, &flags, ReturnMode::FallthroughReturn);
|
||||||
ReturnMode::FallthroughReturn,
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn use_name_section() {
|
||||||
|
let wat = r#"
|
||||||
|
(module $module_name
|
||||||
|
(func $func_name (local $loc_name i32)
|
||||||
|
)
|
||||||
|
)"#;
|
||||||
|
let data = Wat2Wasm::new()
|
||||||
|
.write_debug_names(true)
|
||||||
|
.convert(wat)
|
||||||
|
.unwrap_or_else(|e| panic!("error converting wat to wasm: {:?}", e));
|
||||||
|
|
||||||
|
let flags = Flags::new(settings::builder());
|
||||||
|
let triple = triple!("riscv64");
|
||||||
|
let isa = isa::lookup(triple).unwrap().finish(flags.clone());
|
||||||
|
let return_mode = ReturnMode::NormalReturns;
|
||||||
|
let mut dummy_environ = DummyEnvironment::new(isa.frontend_config(), return_mode, false);
|
||||||
|
|
||||||
|
translate_module(data.as_ref(), &mut dummy_environ).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
dummy_environ.get_func_name(FuncIndex::from_u32(0)).unwrap(),
|
||||||
|
"func_name"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,10 +77,10 @@ fn read_file(path: &Path) -> io::Result<Vec<u8>> {
|
|||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_module(path: &Path, flags: &Flags, return_mode: ReturnMode) {
|
fn read_module(path: &Path) -> Vec<u8> {
|
||||||
let mut features = Features::new();
|
let mut features = Features::new();
|
||||||
features.enable_all();
|
features.enable_all();
|
||||||
let data = match path.extension() {
|
match path.extension() {
|
||||||
None => {
|
None => {
|
||||||
panic!("the file extension is not wasm or wat");
|
panic!("the file extension is not wasm or wat");
|
||||||
}
|
}
|
||||||
@@ -72,7 +97,10 @@ fn handle_module(path: &Path, flags: &Flags, return_mode: ReturnMode) {
|
|||||||
}
|
}
|
||||||
None | Some(&_) => panic!("the file extension for {:?} is not wasm or wat", path),
|
None | Some(&_) => panic!("the file extension for {:?} is not wasm or wat", path),
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_module(data: Vec<u8>, flags: &Flags, return_mode: ReturnMode) {
|
||||||
let triple = triple!("riscv64");
|
let triple = triple!("riscv64");
|
||||||
let isa = isa::lookup(triple).unwrap().finish(flags.clone());
|
let isa = isa::lookup(triple).unwrap().finish(flags.clone());
|
||||||
let mut dummy_environ = DummyEnvironment::new(isa.frontend_config(), return_mode, false);
|
let mut dummy_environ = DummyEnvironment::new(isa.frontend_config(), return_mode, false);
|
||||||
|
|||||||
Reference in New Issue
Block a user