diff --git a/Cargo.lock b/Cargo.lock index dcc7920647f5..9a031eef6b54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2342,14 +2342,12 @@ checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" [[package]] name = "wasmparser" version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a950e6a618f62147fd514ff445b2a0b53120d382751960797f85f058c7eda9b9" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=wasmtime-parser-updates#a45714b2a48e18a4bb74ac02e7e69bff45536e3d" [[package]] name = "wasmprinter" version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "334551eb8b0b1be16cf366a54ce9b541ac32a96e9b51e67ebbae1696f108f112" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=wasmtime-parser-updates#a45714b2a48e18a4bb74ac02e7e69bff45536e3d" dependencies = [ "anyhow", "wasmparser 0.59.0", diff --git a/Cargo.toml b/Cargo.toml index c7b56dc0e15e..f45a416924cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,3 +95,7 @@ harness = false [profile.dev.package.backtrace] debug = false # FIXME(#1813) + +[patch.crates-io] +wasmparser = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'wasmtime-parser-updates' } +wasmprinter = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'wasmtime-parser-updates' } diff --git a/cranelift/entity/src/iter.rs b/cranelift/entity/src/iter.rs index 8c681023d268..fb0a8af9e07c 100644 --- a/cranelift/entity/src/iter.rs +++ b/cranelift/entity/src/iter.rs @@ -1,6 +1,7 @@ //! A double-ended iterator over entity references and entities. use crate::EntityRef; +use alloc::vec; use core::iter::Enumerate; use core::marker::PhantomData; use core::slice; @@ -84,3 +85,40 @@ impl<'a, K: EntityRef, V> DoubleEndedIterator for IterMut<'a, K, V> { } impl<'a, K: EntityRef, V> ExactSizeIterator for IterMut<'a, K, V> {} + +/// Iterate over all keys in order. +pub struct IntoIter { + enumerate: Enumerate>, + unused: PhantomData, +} + +impl IntoIter { + /// Create an `IntoIter` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(iter: vec::IntoIter) -> Self { + Self { + enumerate: iter.enumerate(), + unused: PhantomData, + } + } +} + +impl Iterator for IntoIter { + type Item = (K, V); + + fn next(&mut self) -> Option { + self.enumerate.next().map(|(i, v)| (K::new(i), v)) + } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + self.enumerate.next_back().map(|(i, v)| (K::new(i), v)) + } +} + +impl ExactSizeIterator for IntoIter {} diff --git a/cranelift/entity/src/primary.rs b/cranelift/entity/src/primary.rs index 974033addd15..f798a66876fb 100644 --- a/cranelift/entity/src/primary.rs +++ b/cranelift/entity/src/primary.rs @@ -1,6 +1,6 @@ //! Densely numbered entity references as mapping keys. use crate::boxed_slice::BoxedSlice; -use crate::iter::{Iter, IterMut}; +use crate::iter::{IntoIter, Iter, IterMut}; use crate::keys::Keys; use crate::EntityRef; use alloc::boxed::Box; @@ -150,6 +150,15 @@ where } } +impl Default for PrimaryMap +where + K: EntityRef, +{ + fn default() -> PrimaryMap { + PrimaryMap::new() + } +} + /// Immutable indexing into an `PrimaryMap`. /// The indexed value must be in the map. impl Index for PrimaryMap @@ -197,6 +206,18 @@ where } } +impl IntoIterator for PrimaryMap +where + K: EntityRef, +{ + type Item = (K, V); + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.elems.into_iter()) + } +} + impl FromIterator for PrimaryMap where K: EntityRef, diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index 79eae5c2a6b9..d3f3b8d3c02c 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -24,7 +24,7 @@ //! argument. use super::{hash_map, HashMap}; use crate::environ::{FuncEnvironment, GlobalVariable, ReturnMode, WasmResult}; -use crate::state::{ControlStackFrame, ElseData, FuncTranslationState, ModuleTranslationState}; +use crate::state::{ControlStackFrame, ElseData, FuncTranslationState}; use crate::translation_utils::{ block_with_params, blocktype_params_results, f32_translation, f64_translation, }; @@ -43,7 +43,7 @@ use cranelift_frontend::{FunctionBuilder, Variable}; use std::cmp; use std::convert::TryFrom; use std::vec::Vec; -use wasmparser::{MemoryImmediate, Operator}; +use wasmparser::{FuncValidator, MemoryImmediate, Operator}; // Clippy warns about "flags: _" but its important to document that the flags field is ignored #[cfg_attr( @@ -53,14 +53,14 @@ use wasmparser::{MemoryImmediate, Operator}; /// Translates wasm operators into Cranelift IR instructions. Returns `true` if it inserted /// a return. pub fn translate_operator( - module_translation_state: &ModuleTranslationState, + validator: &mut FuncValidator, op: &Operator, builder: &mut FunctionBuilder, state: &mut FuncTranslationState, environ: &mut FE, ) -> WasmResult<()> { if !state.reachable { - translate_unreachable_operator(module_translation_state, &op, builder, state, environ)?; + translate_unreachable_operator(validator, &op, builder, state, environ)?; return Ok(()); } @@ -180,12 +180,12 @@ pub fn translate_operator( * possible `Block`'s arguments values. ***********************************************************************************/ Operator::Block { ty } => { - let (params, results) = blocktype_params_results(module_translation_state, *ty)?; + let (params, results) = blocktype_params_results(validator, *ty)?; let next = block_with_params(builder, results, environ)?; state.push_block(next, params.len(), results.len()); } Operator::Loop { ty } => { - let (params, results) = blocktype_params_results(module_translation_state, *ty)?; + let (params, results) = blocktype_params_results(validator, *ty)?; let loop_body = block_with_params(builder, params, environ)?; let next = block_with_params(builder, results, environ)?; builder.ins().jump(loop_body, state.peekn(params.len())); @@ -204,7 +204,7 @@ pub fn translate_operator( Operator::If { ty } => { let val = state.pop1(); - let (params, results) = blocktype_params_results(module_translation_state, *ty)?; + let (params, results) = blocktype_params_results(validator, *ty)?; let (destination, else_data) = if params == results { // It is possible there is no `else` block, so we will only // allocate a block for it if/when we find the `else`. For now, @@ -268,7 +268,7 @@ pub fn translate_operator( let else_block = match *else_data { ElseData::NoElse { branch_inst } => { let (params, _results) = - blocktype_params_results(module_translation_state, blocktype)?; + blocktype_params_results(validator, blocktype)?; debug_assert_eq!(params.len(), num_return_values); let else_block = block_with_params(builder, params, environ)?; builder.ins().jump(destination, state.peekn(params.len())); @@ -384,9 +384,10 @@ pub fn translate_operator( } Operator::BrIf { relative_depth } => translate_br_if(*relative_depth, builder, state), Operator::BrTable { table } => { - let (depths, default) = table.read_table()?; + let mut depths = table.targets().collect::, _>>()?; + let default = depths.pop().unwrap().0; let mut min_depth = default; - for depth in &*depths { + for (depth, _) in depths.iter() { if *depth < min_depth { min_depth = *depth; } @@ -404,7 +405,7 @@ pub fn translate_operator( let mut data = JumpTableData::with_capacity(depths.len()); if jump_args_count == 0 { // No jump arguments - for depth in &*depths { + for (depth, _) in depths.iter() { let block = { let i = state.control_stack.len() - 1 - (*depth as usize); let frame = &mut state.control_stack[i]; @@ -427,7 +428,7 @@ pub fn translate_operator( let return_count = jump_args_count; let mut dest_block_sequence = vec![]; let mut dest_block_map = HashMap::new(); - for depth in &*depths { + for (depth, _) in depths.iter() { let branch_block = match dest_block_map.entry(*depth as usize) { hash_map::Entry::Occupied(entry) => *entry.get(), hash_map::Entry::Vacant(entry) => { @@ -1051,9 +1052,9 @@ pub fn translate_operator( let index = FuncIndex::from_u32(*function_index); state.push1(environ.translate_ref_func(builder.cursor(), index)?); } - Operator::AtomicNotify { .. } - | Operator::I32AtomicWait { .. } - | Operator::I64AtomicWait { .. } + Operator::MemoryAtomicNotify { .. } + | Operator::MemoryAtomicWait32 { .. } + | Operator::MemoryAtomicWait64 { .. } | Operator::I32AtomicLoad { .. } | Operator::I64AtomicLoad { .. } | Operator::I32AtomicLoad8U { .. } @@ -1631,7 +1632,7 @@ pub fn translate_operator( /// are dropped but special ones like `End` or `Else` signal the potential end of the unreachable /// portion so the translation state must be updated accordingly. fn translate_unreachable_operator( - module_translation_state: &ModuleTranslationState, + validator: &FuncValidator, op: &Operator, builder: &mut FunctionBuilder, state: &mut FuncTranslationState, @@ -1675,7 +1676,7 @@ fn translate_unreachable_operator( let else_block = match *else_data { ElseData::NoElse { branch_inst } => { let (params, _results) = - blocktype_params_results(module_translation_state, blocktype)?; + blocktype_params_results(validator, blocktype)?; let else_block = block_with_params(builder, params, environ)?; // We change the target of the branch instruction. diff --git a/cranelift/wasm/src/environ/dummy.rs b/cranelift/wasm/src/environ/dummy.rs index 9047df05d27e..1fd753cb8fc8 100644 --- a/cranelift/wasm/src/environ/dummy.rs +++ b/cranelift/wasm/src/environ/dummy.rs @@ -10,7 +10,6 @@ use crate::environ::{ WasmFuncType, WasmResult, }; use crate::func_translator::FuncTranslator; -use crate::state::ModuleTranslationState; use crate::translation_utils::{ DataIndex, DefinedFuncIndex, ElemIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, TableIndex, @@ -26,6 +25,7 @@ use cranelift_frontend::FunctionBuilder; use std::boxed::Box; use std::string::String; use std::vec::Vec; +use wasmparser::{FuncValidator, FunctionBody}; /// Compute a `ir::ExternalName` for a given wasm function index. fn get_func_name(func_index: FuncIndex) -> ir::ExternalName { @@ -715,10 +715,11 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment { fn define_function_body( &mut self, - module_translation_state: &ModuleTranslationState, - body_bytes: &'data [u8], - body_offset: usize, + mut validator: FuncValidator, + body: FunctionBody<'data>, ) -> WasmResult<()> { + self.func_bytecode_sizes + .push(body.get_binary_reader().bytes_remaining()); let func = { let mut func_environ = DummyFuncEnvironment::new(&self.info, self.return_mode); let func_index = @@ -729,16 +730,10 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment { if self.debug_info { func.collect_debug_info(); } - self.trans.translate( - module_translation_state, - body_bytes, - body_offset, - &mut func, - &mut func_environ, - )?; + self.trans + .translate_body(&mut validator, body, &mut func, &mut func_environ)?; func }; - self.func_bytecode_sizes.push(body_bytes.len()); self.info.function_bodies.push(func); Ok(()) } diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index 9a3498b05eab..1dc57cdf52f4 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -6,7 +6,7 @@ //! //! [Wasmtime]: https://github.com/bytecodealliance/wasmtime -use crate::state::{FuncTranslationState, ModuleTranslationState}; +use crate::state::FuncTranslationState; use crate::translation_utils::{ DataIndex, ElemIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, TableIndex, @@ -23,8 +23,7 @@ use serde::{Deserialize, Serialize}; use std::boxed::Box; use std::string::ToString; use thiserror::Error; -use wasmparser::BinaryReaderError; -use wasmparser::Operator; +use wasmparser::{BinaryReaderError, FuncValidator, FunctionBody, Operator, WasmFeatures}; /// WebAssembly value type -- equivalent of `wasmparser`'s Type. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -749,9 +748,8 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment { /// functions is already provided by `reserve_func_types`. fn define_function_body( &mut self, - module_translation_state: &ModuleTranslationState, - body_bytes: &'data [u8], - body_offset: usize, + validator: FuncValidator, + body: FunctionBody<'data>, ) -> WasmResult<()>; /// Provides the number of data initializers up front. By default this does nothing, but @@ -789,4 +787,9 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment { fn custom_section(&mut self, _name: &'data str, _data: &'data [u8]) -> WasmResult<()> { Ok(()) } + + /// Returns the list of enabled wasm features this translation will be using. + fn wasm_features(&self) -> WasmFeatures { + WasmFeatures::default() + } } diff --git a/cranelift/wasm/src/func_translator.rs b/cranelift/wasm/src/func_translator.rs index 11ec5b6ca72b..0ac903989b4a 100644 --- a/cranelift/wasm/src/func_translator.rs +++ b/cranelift/wasm/src/func_translator.rs @@ -6,7 +6,7 @@ use crate::code_translator::{bitcast_arguments, translate_operator, wasm_param_types}; use crate::environ::{FuncEnvironment, ReturnMode, WasmResult}; -use crate::state::{FuncTranslationState, ModuleTranslationState}; +use crate::state::FuncTranslationState; use crate::translation_utils::get_vmctx_value_label; use crate::wasm_unsupported; use core::convert::TryInto; @@ -15,7 +15,7 @@ use cranelift_codegen::ir::{self, Block, InstBuilder, ValueLabel}; use cranelift_codegen::timing; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; use log::info; -use wasmparser::{self, BinaryReader}; +use wasmparser::{self, BinaryReader, FuncValidator, FunctionBody}; /// WebAssembly to Cranelift IR function translator. /// @@ -56,29 +56,30 @@ impl FuncTranslator { /// pub fn translate( &mut self, - module_translation_state: &ModuleTranslationState, + validator: &mut FuncValidator, code: &[u8], code_offset: usize, func: &mut ir::Function, environ: &mut FE, ) -> WasmResult<()> { - self.translate_from_reader( - module_translation_state, - BinaryReader::new_with_offset(code, code_offset), + self.translate_body( + validator, + FunctionBody::new(code_offset, code), func, environ, ) } - /// Translate a binary WebAssembly function from a `BinaryReader`. - pub fn translate_from_reader( + /// Translate a binary WebAssembly function from a `FunctionBody`. + pub fn translate_body( &mut self, - module_translation_state: &ModuleTranslationState, - mut reader: BinaryReader, + validator: &mut FuncValidator, + body: FunctionBody<'_>, func: &mut ir::Function, environ: &mut FE, ) -> WasmResult<()> { let _tt = timing::wasm_translate_function(); + let mut reader = body.get_binary_reader(); info!( "translate({} bytes, {}{})", reader.bytes_remaining(), @@ -108,14 +109,8 @@ impl FuncTranslator { builder.append_block_params_for_function_returns(exit_block); self.state.initialize(&builder.func.signature, exit_block); - parse_local_decls(&mut reader, &mut builder, num_params, environ)?; - parse_function_body( - module_translation_state, - reader, - &mut builder, - &mut self.state, - environ, - )?; + parse_local_decls(&mut reader, &mut builder, num_params, environ, validator)?; + parse_function_body(validator, reader, &mut builder, &mut self.state, environ)?; builder.finalize(); Ok(()) @@ -162,14 +157,17 @@ fn parse_local_decls( builder: &mut FunctionBuilder, num_params: usize, environ: &mut FE, + validator: &mut FuncValidator, ) -> WasmResult<()> { let mut next_local = num_params; - let local_count = reader.read_local_count()?; + let local_count = reader.read_var_u32()?; - let mut locals_total = 0; for _ in 0..local_count { builder.set_srcloc(cur_srcloc(reader)); - let (count, ty) = reader.read_local_decl(&mut locals_total)?; + let pos = reader.original_position(); + let count = reader.read_var_u32()?; + let ty = reader.read_type()?; + validator.define_locals(pos, count, ty)?; declare_locals(builder, count, ty, &mut next_local, environ)?; } @@ -219,7 +217,7 @@ fn declare_locals( /// This assumes that the local variable declarations have already been parsed and function /// arguments and locals are declared in the builder. fn parse_function_body( - module_translation_state: &ModuleTranslationState, + validator: &mut FuncValidator, mut reader: BinaryReader, builder: &mut FunctionBuilder, state: &mut FuncTranslationState, @@ -230,12 +228,16 @@ fn parse_function_body( // Keep going until the final `End` operator which pops the outermost block. while !state.control_stack.is_empty() { + let pos = reader.original_position(); builder.set_srcloc(cur_srcloc(&reader)); let op = reader.read_operator()?; + validator.op(pos, &op)?; environ.before_translate_operator(&op, builder, state)?; - translate_operator(module_translation_state, &op, builder, state, environ)?; + translate_operator(validator, &op, builder, state, environ)?; environ.after_translate_operator(&op, builder, state)?; } + let pos = reader.original_position(); + validator.finish(pos)?; // The final `End` operator left us in the exit block where we need to manually add a return // instruction. diff --git a/cranelift/wasm/src/module_translator.rs b/cranelift/wasm/src/module_translator.rs index 9903a2979cbe..e7a3b29eb59e 100644 --- a/cranelift/wasm/src/module_translator.rs +++ b/cranelift/wasm/src/module_translator.rs @@ -8,7 +8,7 @@ use crate::sections_translator::{ }; use crate::state::ModuleTranslationState; use cranelift_codegen::timing; -use wasmparser::{NameSectionReader, Parser, Payload}; +use wasmparser::{NameSectionReader, Parser, Payload, Validator}; /// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cranelift IR /// [`Function`](cranelift_codegen::ir::Function). @@ -18,72 +18,108 @@ pub fn translate_module<'data>( ) -> WasmResult { let _tt = timing::wasm_translate_module(); let mut module_translation_state = ModuleTranslationState::new(); + let mut validator = Validator::new(); + validator.wasm_features(environ.wasm_features()); for payload in Parser::new(0).parse_all(data) { match payload? { - Payload::Version { .. } | Payload::End => {} + Payload::Version { num, range } => { + validator.version(num, &range)?; + } + Payload::End => { + validator.end()?; + } Payload::TypeSection(types) => { + validator.type_section(&types)?; parse_type_section(types, &mut module_translation_state, environ)?; } Payload::ImportSection(imports) => { + validator.import_section(&imports)?; parse_import_section(imports, environ)?; } Payload::FunctionSection(functions) => { + validator.function_section(&functions)?; parse_function_section(functions, environ)?; } Payload::TableSection(tables) => { + validator.table_section(&tables)?; parse_table_section(tables, environ)?; } Payload::MemorySection(memories) => { + validator.memory_section(&memories)?; parse_memory_section(memories, environ)?; } Payload::GlobalSection(globals) => { + validator.global_section(&globals)?; parse_global_section(globals, environ)?; } Payload::ExportSection(exports) => { + validator.export_section(&exports)?; parse_export_section(exports, environ)?; } - Payload::StartSection { func, .. } => { + Payload::StartSection { func, range } => { + validator.start_section(func, &range)?; parse_start_section(func, environ)?; } Payload::ElementSection(elements) => { + validator.element_section(&elements)?; parse_element_section(elements, environ)?; } - Payload::CodeSectionStart { .. } => {} - Payload::CodeSectionEntry(code) => { - let mut code = code.get_binary_reader(); - let size = code.bytes_remaining(); - let offset = code.original_position(); - environ.define_function_body( - &module_translation_state, - code.read_bytes(size)?, - offset, - )?; + Payload::CodeSectionStart { + count, + range, + size: _, + } => { + validator.code_section_start(count, &range)?; + } + + Payload::CodeSectionEntry(body) => { + let func_validator = validator.code_section_entry()?; + environ.define_function_body(func_validator, body)?; } Payload::DataSection(data) => { + validator.data_section(&data)?; parse_data_section(data, environ)?; } - Payload::DataCountSection { count, .. } => { + Payload::DataCountSection { count, range } => { + validator.data_count_section(count, &range)?; environ.reserve_passive_data(count)?; } - Payload::ModuleSection(_) - | Payload::InstanceSection(_) - | Payload::AliasSection(_) - | Payload::ModuleCodeSectionStart { .. } - | Payload::ModuleCodeSectionEntry { .. } => { + Payload::ModuleSection(s) => { + validator.module_section(&s)?; + unimplemented!("module linking not implemented yet") + } + Payload::InstanceSection(s) => { + validator.instance_section(&s)?; + unimplemented!("module linking not implemented yet") + } + Payload::AliasSection(s) => { + validator.alias_section(&s)?; + unimplemented!("module linking not implemented yet") + } + Payload::ModuleCodeSectionStart { + count, + range, + size: _, + } => { + validator.module_code_section_start(count, &range)?; + unimplemented!("module linking not implemented yet") + } + + Payload::ModuleCodeSectionEntry { .. } => { unimplemented!("module linking not implemented yet") } @@ -95,7 +131,10 @@ pub fn translate_module<'data>( Payload::CustomSection { name, data, .. } => environ.custom_section(name, data)?, - Payload::UnknownSection { .. } => unreachable!(), + Payload::UnknownSection { id, range, .. } => { + validator.unknown_section(id, &range)?; + unreachable!(); + } } } diff --git a/cranelift/wasm/src/sections_translator.rs b/cranelift/wasm/src/sections_translator.rs index 3bc4d7d144a8..8224f6db00c4 100644 --- a/cranelift/wasm/src/sections_translator.rs +++ b/cranelift/wasm/src/sections_translator.rs @@ -27,7 +27,7 @@ use wasmparser::{ ElementSectionReader, Export, ExportSectionReader, ExternalKind, FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType, ImportSectionReader, MemorySectionReader, MemoryType, NameSectionReader, Naming, NamingReader, Operator, - TableSectionReader, Type, TypeDef, TypeSectionReader, + TableSectionReader, TypeDef, TypeSectionReader, }; /// Parses the Type section of the wasm module. @@ -313,13 +313,7 @@ pub fn parse_element_section<'data>( environ.reserve_table_elements(elements.get_count())?; for (index, entry) in elements.into_iter().enumerate() { - let Element { kind, items, ty } = entry?; - if ty != Type::FuncRef { - return Err(wasm_unsupported!( - "unsupported table element type: {:?}", - ty - )); - } + let Element { kind, items, ty: _ } = entry?; let segments = read_elems(&items)?; match kind { ElementKind::Active { diff --git a/cranelift/wasm/src/translation_utils.rs b/cranelift/wasm/src/translation_utils.rs index 2975584f7346..1586cb5627da 100644 --- a/cranelift/wasm/src/translation_utils.rs +++ b/cranelift/wasm/src/translation_utils.rs @@ -1,6 +1,5 @@ //! Helper functions and structures for the translation. use crate::environ::{TargetEnvironment, WasmResult, WasmType}; -use crate::state::ModuleTranslationState; use crate::wasm_unsupported; use core::convert::TryInto; use core::u32; @@ -10,7 +9,7 @@ use cranelift_codegen::ir::immediates::V128Imm; use cranelift_frontend::FunctionBuilder; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; -use wasmparser; +use wasmparser::{FuncValidator, WasmModuleResources}; /// Index type of a function (imported or defined) inside the WebAssembly module. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] @@ -195,7 +194,7 @@ pub fn tabletype_to_type( /// Get the parameter and result types for the given Wasm blocktype. pub fn blocktype_params_results( - module_translation_state: &ModuleTranslationState, + validator: &FuncValidator, ty_or_ft: wasmparser::TypeOrFuncType, ) -> WasmResult<(&[wasmparser::Type], &[wasmparser::Type])> { Ok(match ty_or_ft { @@ -211,9 +210,8 @@ pub fn blocktype_params_results( ty => return Err(wasm_unsupported!("blocktype_params_results: type {:?}", ty)), }, wasmparser::TypeOrFuncType::FuncType(ty_index) => { - let sig_idx = SignatureIndex::from_u32(ty_index); - let (ref params, ref returns) = module_translation_state.wasm_types[sig_idx]; - (&*params, &*returns) + let ty = validator.func_type_at(ty_index).expect("should be valid"); + (&ty.params, &ty.returns) } }) } diff --git a/crates/environ/src/compilation.rs b/crates/environ/src/compilation.rs index 0aa13cd2000e..a233af53a36a 100644 --- a/crates/environ/src/compilation.rs +++ b/crates/environ/src/compilation.rs @@ -2,8 +2,7 @@ //! module. use crate::cache::ModuleCacheDataTupleType; -use crate::CacheConfig; -use crate::ModuleTranslation; +use crate::{CacheConfig, FunctionBodyData, ModuleTranslation}; use cranelift_codegen::{binemit, ir, isa, isa::unwind::UnwindInfo}; use cranelift_entity::PrimaryMap; use cranelift_wasm::{DefinedFuncIndex, FuncIndex, WasmError}; @@ -189,6 +188,7 @@ pub trait Compiler { /// Compile a parsed module with the given `TargetIsa`. fn compile_module( translation: &ModuleTranslation, + funcs: PrimaryMap>, isa: &dyn isa::TargetIsa, cache_config: &CacheConfig, ) -> Result; diff --git a/crates/environ/src/cranelift.rs b/crates/environ/src/cranelift.rs index 91a0db47b434..5cd50d313333 100644 --- a/crates/environ/src/cranelift.rs +++ b/crates/environ/src/cranelift.rs @@ -98,9 +98,7 @@ use cranelift_codegen::machinst::buffer::MachSrcLoc; use cranelift_codegen::print_errors::pretty_error; use cranelift_codegen::{binemit, isa, Context}; use cranelift_entity::PrimaryMap; -use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator, ModuleTranslationState}; -#[cfg(feature = "parallel-compilation")] -use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; +use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator}; use std::convert::TryFrom; use std::hash::{Hash, Hasher}; @@ -267,8 +265,11 @@ fn get_function_address_map<'data>( // Generate artificial srcloc for function start/end to identify boundary // within module. Similar to FuncTranslator::cur_srcloc(): it will wrap around // if byte code is larger than 4 GB. - let start_srcloc = ir::SourceLoc::new(data.module_offset as u32); - let end_srcloc = ir::SourceLoc::new((data.module_offset + data.data.len()) as u32); + let data = data.body.get_binary_reader(); + let offset = data.original_position(); + let len = data.bytes_remaining(); + let start_srcloc = ir::SourceLoc::new(offset as u32); + let end_srcloc = ir::SourceLoc::new((offset + len) as u32); FunctionAddressMap { instructions, @@ -288,6 +289,7 @@ impl crate::compilation::Compiler for Cranelift { /// associated relocations. fn compile_module( translation: &ModuleTranslation, + function_body_inputs: PrimaryMap>, isa: &dyn isa::TargetIsa, cache_config: &CacheConfig, ) -> Result { @@ -296,10 +298,7 @@ impl crate::compilation::Compiler for Cranelift { let data = cache_entry.get_data( CompileEnv { local: &translation.module.local, - module_translation: HashedModuleTranslationState( - translation.module_translation.as_ref().unwrap(), - ), - function_body_inputs: &translation.function_body_inputs, + function_body_inputs: HashedBodies(function_body_inputs), isa: Isa(isa), tunables: &translation.tunables, }, @@ -311,27 +310,30 @@ impl crate::compilation::Compiler for Cranelift { fn compile(env: CompileEnv<'_>) -> Result { let Isa(isa) = env.isa; - let mut functions = PrimaryMap::with_capacity(env.function_body_inputs.len()); - let mut relocations = PrimaryMap::with_capacity(env.function_body_inputs.len()); - let mut address_transforms = PrimaryMap::with_capacity(env.function_body_inputs.len()); - let mut value_ranges = PrimaryMap::with_capacity(env.function_body_inputs.len()); - let mut stack_slots = PrimaryMap::with_capacity(env.function_body_inputs.len()); - let mut traps = PrimaryMap::with_capacity(env.function_body_inputs.len()); - let mut stack_maps = PrimaryMap::with_capacity(env.function_body_inputs.len()); - - type FunctionBodyInput<'a> = (DefinedFuncIndex, &'a FunctionBodyData<'a>); + let HashedBodies(function_body_inputs) = env.function_body_inputs; + let mut functions = PrimaryMap::with_capacity(function_body_inputs.len()); + let mut relocations = PrimaryMap::with_capacity(function_body_inputs.len()); + let mut address_transforms = PrimaryMap::with_capacity(function_body_inputs.len()); + let mut value_ranges = PrimaryMap::with_capacity(function_body_inputs.len()); + let mut stack_slots = PrimaryMap::with_capacity(function_body_inputs.len()); + let mut traps = PrimaryMap::with_capacity(function_body_inputs.len()); + let mut stack_maps = PrimaryMap::with_capacity(function_body_inputs.len()); + let local = env.local; + let tunables = env.tunables; + + type FunctionBodyInput<'a> = (DefinedFuncIndex, FunctionBodyData<'a>); let compile_function = |func_translator: &mut FuncTranslator, - (i, input): &FunctionBodyInput| { - let func_index = env.local.func_index(*i); + (i, mut input): FunctionBodyInput| { + let func_index = local.func_index(i); let mut context = Context::new(); context.func.name = get_func_name(func_index); - context.func.signature = env.local.native_func_signature(func_index).clone(); - if env.tunables.debug_info { + context.func.signature = local.native_func_signature(func_index).clone(); + if tunables.debug_info { context.func.collect_debug_info(); } - let mut func_env = FuncEnvironment::new(isa.frontend_config(), env.local, env.tunables); + let mut func_env = FuncEnvironment::new(isa.frontend_config(), local, tunables); // We use these as constant offsets below in // `stack_limit_from_arguments`, so assert their values here. This @@ -366,10 +368,9 @@ fn compile(env: CompileEnv<'_>) -> Result) -> Result) -> Result = env.function_body_inputs.into_iter().collect(); - let results: Result, CompileError> = { cfg_if::cfg_if! { - if #[cfg(feature = "parallel-compilation")] { - inputs - .par_iter() + if #[cfg(feature = "3parallel-compilation")] { + use rayon::prelude::*; + function_body_inputs + .into_iter() + .collect::>() + .into_par_iter() .map_init(FuncTranslator::new, compile_function) .collect() } else { let mut func_translator = FuncTranslator::new(); - inputs - .iter() + function_body_inputs + .into_iter() .map(|input| compile_function(&mut func_translator, input)) .collect() } @@ -479,8 +481,7 @@ fn compile(env: CompileEnv<'_>) -> Result { local: &'a ModuleLocal, - module_translation: HashedModuleTranslationState<'a>, - function_body_inputs: &'a PrimaryMap>, + function_body_inputs: HashedBodies<'a>, isa: Isa<'a, 'a>, tunables: &'a Tunables, } @@ -508,16 +509,18 @@ impl Hash for Isa<'_, '_> { } } -/// A wrapper struct around cranelift's `ModuleTranslationState` to implement -/// `Hash` since it's not `Hash` upstream yet. +/// This is a wrapper struct to hash only the body of each function, not its +/// validator. /// -/// TODO: we should upstream a `Hash` implementation, it would be very small! At -/// this moment though based on the definition it should be fine to not hash it -/// since we'll re-hash the signatures later. -struct HashedModuleTranslationState<'a>(&'a ModuleTranslationState); - -impl Hash for HashedModuleTranslationState<'_> { - fn hash(&self, _hasher: &mut H) { - // nothing to hash right now +/// The validator is derived from the module's environment which is already +/// hashed elsewhere. +struct HashedBodies<'a>(PrimaryMap>); + +impl Hash for HashedBodies<'_> { + fn hash(&self, hasher: &mut H) { + self.0.len().hash(hasher); + for (_, data) in self.0.iter() { + data.body.get_binary_reader().hash(hasher); + } } } diff --git a/crates/environ/src/lightbeam.rs b/crates/environ/src/lightbeam.rs index 49fda2f8a023..18890272cd7f 100644 --- a/crates/environ/src/lightbeam.rs +++ b/crates/environ/src/lightbeam.rs @@ -3,13 +3,13 @@ use crate::cache::ModuleCacheDataTupleType; use crate::compilation::{Compilation, CompileError}; use crate::func_environ::FuncEnvironment; -use crate::CacheConfig; -use crate::ModuleTranslation; +use crate::{CacheConfig, FunctionBodyData, ModuleTranslation}; // TODO: Put this in `compilation` use crate::address_map::{ModuleAddressMap, ValueLabelsRanges}; use crate::cranelift::{RelocSink, TrapSink}; use cranelift_codegen::isa; use cranelift_entity::{PrimaryMap, SecondaryMap}; +use cranelift_wasm::DefinedFuncIndex; use lightbeam::{CodeGenSession, NullOffsetSink, Sinks}; /// A compiler that compiles a WebAssembly module with Lightbeam, directly translating the Wasm file. @@ -20,6 +20,7 @@ impl crate::compilation::Compiler for Lightbeam { /// associated relocations. fn compile_module( translation: &ModuleTranslation, + function_body_inputs: PrimaryMap>, isa: &dyn isa::TargetIsa, _cache_config: &CacheConfig, ) -> Result { @@ -32,21 +33,27 @@ impl crate::compilation::Compiler for Lightbeam { &translation.module.local, &translation.tunables, ); - let mut relocations = PrimaryMap::with_capacity(translation.function_body_inputs.len()); - let mut traps = PrimaryMap::with_capacity(translation.function_body_inputs.len()); - let stack_maps = PrimaryMap::with_capacity(translation.function_body_inputs.len()); + let mut relocations = PrimaryMap::with_capacity(function_body_inputs.len()); + let mut traps = PrimaryMap::with_capacity(function_body_inputs.len()); + let stack_maps = PrimaryMap::with_capacity(function_body_inputs.len()); let mut codegen_session: CodeGenSession<_> = CodeGenSession::new( - translation.function_body_inputs.len() as u32, + function_body_inputs.len() as u32, &env, lightbeam::microwasm::I32, ); - for (i, function_body) in &translation.function_body_inputs { + for (i, mut function_body) in function_body_inputs { let func_index = translation.module.local.func_index(i); let mut reloc_sink = RelocSink::new(func_index); let mut trap_sink = TrapSink::new(); + function_body + .validator + .validate(&function_body.body) + .map_err(|e| { + CompileError::Codegen(format!("Failed to validate function: {}", e)) + })?; lightbeam::translate_function( &mut codegen_session, Sinks { @@ -55,7 +62,7 @@ impl crate::compilation::Compiler for Lightbeam { offsets: &mut NullOffsetSink, }, i.as_u32(), - wasmparser::FunctionBody::new(0, function_body.data), + function_body.body, ) .map_err(|e| CompileError::Codegen(format!("Failed to translate function: {}", e)))?; diff --git a/crates/environ/src/module_environ.rs b/crates/environ/src/module_environ.rs index 9499250a1205..29f97a1ed862 100644 --- a/crates/environ/src/module_environ.rs +++ b/crates/environ/src/module_environ.rs @@ -12,15 +12,14 @@ use cranelift_wasm::{ use serde::{Deserialize, Serialize}; use std::convert::TryFrom; use std::sync::Arc; +use wasmparser::{FuncValidator, FunctionBody, WasmFeatures}; /// Contains function data: byte code and its offset in the module. -#[derive(Hash)] pub struct FunctionBodyData<'a> { - /// Body byte code. - pub data: &'a [u8], - - /// Body offset in the module file. - pub module_offset: usize, + /// The body of the function, containing code and locals. + pub body: FunctionBody<'a>, + /// Validator for the function body + pub validator: FuncValidator, } /// The result of translating via `ModuleEnvironment`. Function bodies are not @@ -50,11 +49,16 @@ pub struct ModuleTranslation<'data> { pub struct ModuleEnvironment<'data> { /// The result to be filled in. result: ModuleTranslation<'data>, + features: WasmFeatures, } impl<'data> ModuleEnvironment<'data> { /// Allocates the environment data structures. - pub fn new(target_config: TargetFrontendConfig, tunables: &Tunables) -> Self { + pub fn new( + target_config: TargetFrontendConfig, + tunables: &Tunables, + features: &WasmFeatures, + ) -> Self { Self { result: ModuleTranslation { target_config, @@ -64,6 +68,7 @@ impl<'data> ModuleEnvironment<'data> { tunables: tunables.clone(), module_translation: None, }, + features: *features, } } @@ -348,14 +353,12 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data fn define_function_body( &mut self, - _module_translation: &ModuleTranslationState, - body_bytes: &'data [u8], - body_offset: usize, + validator: FuncValidator, + body: FunctionBody<'data>, ) -> WasmResult<()> { - self.result.function_body_inputs.push(FunctionBodyData { - data: body_bytes, - module_offset: body_offset, - }); + self.result + .function_body_inputs + .push(FunctionBodyData { validator, body }); Ok(()) } @@ -435,6 +438,10 @@ and for re-adding support for interface types you can see this issue: _ => Ok(()), } } + + fn wasm_features(&self) -> WasmFeatures { + self.features + } } /// Add environment-specific function parameters. diff --git a/crates/jit/src/compiler.rs b/crates/jit/src/compiler.rs index 534f963fd985..8ab2b4285fb1 100644 --- a/crates/jit/src/compiler.rs +++ b/crates/jit/src/compiler.rs @@ -4,6 +4,8 @@ use crate::instantiate::SetupError; use crate::object::{build_object, ObjectUnwindInfo}; use cranelift_codegen::ir; use object::write::Object; +use std::mem; +use wasmparser::WasmFeatures; use wasmtime_debug::{emit_dwarf, DebugInfoData, DwarfSection}; use wasmtime_environ::entity::{EntityRef, PrimaryMap}; use wasmtime_environ::isa::{unwind::UnwindInfo, TargetFrontendConfig, TargetIsa}; @@ -40,6 +42,7 @@ pub struct Compiler { strategy: CompilationStrategy, cache_config: CacheConfig, tunables: Tunables, + features: WasmFeatures, } impl Compiler { @@ -49,12 +52,14 @@ impl Compiler { strategy: CompilationStrategy, cache_config: CacheConfig, tunables: Tunables, + features: WasmFeatures, ) -> Self { Self { isa, strategy, cache_config, tunables, + features, } } } @@ -126,12 +131,18 @@ impl Compiler { &self.tunables } + /// Return the enabled wasm features. + pub fn features(&self) -> &WasmFeatures { + &self.features + } + /// Compile the given function bodies. pub(crate) fn compile<'data>( &self, - translation: &ModuleTranslation, + translation: &mut ModuleTranslation, debug_data: Option, ) -> Result { + let functions = mem::take(&mut translation.function_body_inputs); let ( compilation, relocations, @@ -146,6 +157,7 @@ impl Compiler { CompilationStrategy::Auto | CompilationStrategy::Cranelift => { wasmtime_environ::cranelift::Cranelift::compile_module( translation, + functions, &*self.isa, &self.cache_config, ) @@ -154,6 +166,7 @@ impl Compiler { CompilationStrategy::Lightbeam => { wasmtime_environ::lightbeam::Lightbeam::compile_module( translation, + functions, &*self.isa, &self.cache_config, ) diff --git a/crates/jit/src/instantiate.rs b/crates/jit/src/instantiate.rs index 0e50a927d6f8..a3e7f339fa8e 100644 --- a/crates/jit/src/instantiate.rs +++ b/crates/jit/src/instantiate.rs @@ -83,9 +83,13 @@ pub struct CompilationArtifacts { impl CompilationArtifacts { /// Builds compilation artifacts. pub fn build(compiler: &Compiler, data: &[u8]) -> Result { - let environ = ModuleEnvironment::new(compiler.frontend_config(), compiler.tunables()); + let environ = ModuleEnvironment::new( + compiler.frontend_config(), + compiler.tunables(), + compiler.features(), + ); - let translation = environ + let mut translation = environ .translate(data) .map_err(|error| SetupError::Compile(CompileError::Wasm(error)))?; @@ -103,7 +107,7 @@ impl CompilationArtifacts { traps, stack_maps, address_transform, - } = compiler.compile(&translation, debug_data)?; + } = compiler.compile(&mut translation, debug_data)?; let ModuleTranslation { module, diff --git a/crates/lightbeam/src/microwasm.rs b/crates/lightbeam/src/microwasm.rs index 20b978700896..39509228c4a5 100644 --- a/crates/lightbeam/src/microwasm.rs +++ b/crates/lightbeam/src/microwasm.rs @@ -1940,12 +1940,13 @@ where } WasmOperator::BrTable { table } => { self.unreachable = true; - let (targets, default) = table.read_table()?; + let mut targets = table.targets().collect::, _>>()?; + let default = targets.pop().unwrap().0; let control_frames = &mut self.control_frames; let stack = &self.stack; let targets = targets .into_iter() - .map(|&depth| { + .map(|(depth, _)| { control_frames[depth as _].mark_branched_to(); let block = &control_frames[depth as _]; diff --git a/crates/wasmtime/src/instance.rs b/crates/wasmtime/src/instance.rs index f4ecffe97257..42267ef04093 100644 --- a/crates/wasmtime/src/instance.rs +++ b/crates/wasmtime/src/instance.rs @@ -66,7 +66,7 @@ fn instantiate( let instance = store.add_instance(instance); instance .initialize( - config.wasm_bulk_memory, + config.features.bulk_memory, &compiled_module.data_initializers(), ) .map_err(|e| -> Error { diff --git a/crates/wasmtime/src/module.rs b/crates/wasmtime/src/module.rs index ca3f6571e5ee..3a504543da1f 100644 --- a/crates/wasmtime/src/module.rs +++ b/crates/wasmtime/src/module.rs @@ -4,6 +4,7 @@ use crate::types::{EntityType, ExportType, ExternType, ImportType}; use anyhow::{bail, Context, Result}; use std::path::Path; use std::sync::{Arc, Mutex}; +use wasmparser::Validator; use wasmtime_jit::{CompilationArtifacts, CompiledModule}; /// A compiled WebAssembly module, ready to be instantiated. @@ -236,42 +237,13 @@ impl Module { /// # } /// ``` pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result { - Module::validate(engine, binary)?; - // Note that the call to `from_binary_unchecked` here should be ok - // because we previously validated the binary, meaning we're guaranteed - // to pass a valid binary for `engine`. - unsafe { Module::from_binary_unchecked(engine, binary) } - } + let compiled = CompiledModule::new(engine.compiler(), binary, &*engine.config().profiler)?; - /// Creates a new WebAssembly `Module` from the given in-memory `binary` - /// data, skipping validation and asserting that `binary` is a valid - /// WebAssembly module. - /// - /// This function is the same as [`Module::new`] except that it skips the - /// call to [`Module::validate`] and it does not support the text format of - /// WebAssembly. The WebAssembly binary is not validated for - /// correctness and it is simply assumed as valid. - /// - /// For more information about creation of a module and the `engine` argument - /// see the documentation of [`Module::new`]. - /// - /// # Unsafety - /// - /// This function is `unsafe` due to the unchecked assumption that the input - /// `binary` is valid. If the `binary` is not actually a valid wasm binary it - /// may cause invalid machine code to get generated, cause panics, etc. - /// - /// It is only safe to call this method if [`Module::validate`] succeeds on - /// the same arguments passed to this function. - /// - /// # Errors - /// - /// This function may fail for many of the same reasons as [`Module::new`]. - /// While this assumes that the binary is valid it still needs to actually - /// be somewhat valid for decoding purposes, and the basics of decoding can - /// still fail. - pub unsafe fn from_binary_unchecked(engine: &Engine, binary: &[u8]) -> Result { - Module::compile(engine, binary) + Ok(Module { + engine: engine.clone(), + compiled: Arc::new(compiled), + frame_info_registration: Arc::new(Mutex::new(None)), + }) } /// Validates `binary` input data as a WebAssembly binary given the @@ -295,20 +267,12 @@ impl Module { /// /// [binary]: https://webassembly.github.io/spec/core/binary/index.html pub fn validate(engine: &Engine, binary: &[u8]) -> Result<()> { - engine.config().validator().validate_all(binary)?; + let mut validator = Validator::new(); + validator.wasm_features(engine.config().features); + validator.validate_all(binary)?; Ok(()) } - unsafe fn compile(engine: &Engine, binary: &[u8]) -> Result { - let compiled = CompiledModule::new(engine.compiler(), binary, &*engine.config().profiler)?; - - Ok(Module { - engine: engine.clone(), - compiled: Arc::new(compiled), - frame_info_registration: Arc::new(Mutex::new(None)), - }) - } - /// Serialize compilation artifacts to the buffer. See also `deseriaize`. pub fn serialize(&self) -> Result> { let artifacts = ( diff --git a/crates/wasmtime/src/runtime.rs b/crates/wasmtime/src/runtime.rs index f46fb253b39c..260044280e4f 100644 --- a/crates/wasmtime/src/runtime.rs +++ b/crates/wasmtime/src/runtime.rs @@ -11,7 +11,7 @@ use std::path::Path; use std::rc::{Rc, Weak}; use std::sync::Arc; use target_lexicon::Triple; -use wasmparser::Validator; +use wasmparser::WasmFeatures; use wasmtime_environ::settings::{self, Configurable, SetError}; use wasmtime_environ::{ir, isa, isa::TargetIsa, wasm, CacheConfig, Tunables}; use wasmtime_jit::{native, CompilationStrategy, Compiler}; @@ -41,11 +41,7 @@ pub struct Config { pub(crate) profiler: Arc, pub(crate) memory_creator: Option, pub(crate) max_wasm_stack: usize, - wasm_threads: bool, - wasm_reference_types: bool, - pub(crate) wasm_bulk_memory: bool, - wasm_simd: bool, - wasm_multi_value: bool, + pub(crate) features: WasmFeatures, } impl Config { @@ -93,11 +89,7 @@ impl Config { profiler: Arc::new(NullProfilerAgent), memory_creator: None, max_wasm_stack: 1 << 20, - wasm_threads: false, - wasm_reference_types: false, - wasm_bulk_memory: false, - wasm_simd: false, - wasm_multi_value: true, + features: WasmFeatures::default(), } } @@ -162,7 +154,7 @@ impl Config { /// /// [threads]: https://github.com/webassembly/threads pub fn wasm_threads(&mut self, enable: bool) -> &mut Self { - self.wasm_threads = enable; + self.features.threads = enable; // The threads proposal depends on the bulk memory proposal if enable { self.wasm_bulk_memory(true); @@ -192,7 +184,7 @@ impl Config { /// /// [proposal]: https://github.com/webassembly/reference-types pub fn wasm_reference_types(&mut self, enable: bool) -> &mut Self { - self.wasm_reference_types = enable; + self.features.reference_types = enable; self.flags .set("enable_safepoints", if enable { "true" } else { "false" }) @@ -227,7 +219,7 @@ impl Config { /// /// [proposal]: https://github.com/webassembly/simd pub fn wasm_simd(&mut self, enable: bool) -> &mut Self { - self.wasm_simd = enable; + self.features.simd = enable; let val = if enable { "true" } else { "false" }; self.flags .set("enable_simd", val) @@ -251,7 +243,7 @@ impl Config { /// /// [proposal]: https://github.com/webassembly/bulk-memory-operations pub fn wasm_bulk_memory(&mut self, enable: bool) -> &mut Self { - self.wasm_bulk_memory = enable; + self.features.bulk_memory = enable; self } @@ -265,7 +257,7 @@ impl Config { /// /// [proposal]: https://github.com/webassembly/multi-value pub fn wasm_multi_value(&mut self, enable: bool) -> &mut Self { - self.wasm_multi_value = enable; + self.features.multi_value = enable; self } @@ -616,16 +608,6 @@ impl Config { self.isa_flags.clone().finish(settings::Flags::new(flags)) } - pub(crate) fn validator(&self) -> Validator { - let mut ret = Validator::new(); - ret.wasm_threads(self.wasm_threads) - .wasm_bulk_memory(self.wasm_bulk_memory) - .wasm_multi_value(self.wasm_multi_value) - .wasm_reference_types(self.wasm_reference_types) - .wasm_simd(self.wasm_simd); - return ret; - } - fn build_compiler(&self) -> Compiler { let isa = self.target_isa(); Compiler::new( @@ -633,6 +615,7 @@ impl Config { self.strategy, self.cache_config.clone(), self.tunables.clone(), + self.features, ) } @@ -672,11 +655,11 @@ impl fmt::Debug for Config { f.debug_struct("Config") .field("debug_info", &self.tunables.debug_info) .field("strategy", &self.strategy) - .field("wasm_threads", &self.wasm_threads) - .field("wasm_reference_types", &self.wasm_reference_types) - .field("wasm_bulk_memory", &self.wasm_bulk_memory) - .field("wasm_simd", &self.wasm_simd) - .field("wasm_multi_value", &self.wasm_multi_value) + .field("wasm_threads", &self.features.threads) + .field("wasm_reference_types", &self.features.reference_types) + .field("wasm_bulk_memory", &self.features.bulk_memory) + .field("wasm_simd", &self.features.simd) + .field("wasm_multi_value", &self.features.multi_value) .field( "flags", &settings::Flags::new(self.flags.clone()).to_string(), diff --git a/src/obj.rs b/src/obj.rs index 90fef7146e5c..32203aefbdbd 100644 --- a/src/obj.rs +++ b/src/obj.rs @@ -1,5 +1,6 @@ use anyhow::{anyhow, bail, Context as _, Result}; use object::write::Object; +use std::mem; use target_lexicon::Triple; use wasmtime::Strategy; use wasmtime_debug::{emit_dwarf, read_debuginfo}; @@ -56,11 +57,12 @@ pub fn compile_to_obj( let mut tunables = Tunables::default(); tunables.debug_info = debug_info; - let environ = ModuleEnvironment::new(isa.frontend_config(), &tunables); + let environ = ModuleEnvironment::new(isa.frontend_config(), &tunables, &Default::default()); - let translation = environ + let mut translation = environ .translate(wasm) .context("failed to translate module")?; + let functions = mem::take(&mut translation.function_body_inputs); // TODO: use the traps and stack maps information. let ( @@ -73,10 +75,12 @@ pub fn compile_to_obj( _stack_maps, ) = match strategy { Strategy::Auto | Strategy::Cranelift => { - Cranelift::compile_module(&translation, &*isa, cache_config) + Cranelift::compile_module(&translation, functions, &*isa, cache_config) } #[cfg(feature = "lightbeam")] - Strategy::Lightbeam => Lightbeam::compile_module(&translation, &*isa, cache_config), + Strategy::Lightbeam => { + Lightbeam::compile_module(&translation, functions, &*isa, cache_config) + } #[cfg(not(feature = "lightbeam"))] Strategy::Lightbeam => bail!("lightbeam support not enabled"), other => bail!("unsupported compilation strategy {:?}", other),