diff --git a/Cargo.lock b/Cargo.lock index 4fc0480e9933..dc42b49edd5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -585,11 +585,12 @@ dependencies = [ "cranelift-entity", "cranelift-frontend", "hashbrown 0.7.2", + "itertools 0.9.0", "log", "serde", "target-lexicon", "thiserror", - "wasmparser 0.59.0", + "wasmparser 0.62.0", "wat", ] @@ -1102,7 +1103,7 @@ dependencies = [ "staticvec", "thiserror", "typemap", - "wasmparser 0.59.0", + "wasmparser 0.62.0", "wat", ] @@ -2336,18 +2337,18 @@ checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6" [[package]] name = "wasmparser" -version = "0.59.0" +version = "0.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a950e6a618f62147fd514ff445b2a0b53120d382751960797f85f058c7eda9b9" +checksum = "e36b5b8441a5d83ea606c9eb904a3ee3889ebfeda1df1a5c48b84725239d93ce" [[package]] name = "wasmprinter" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "334551eb8b0b1be16cf366a54ce9b541ac32a96e9b51e67ebbae1696f108f112" +checksum = "adc9e10f7145e1c15f16c809d6c0937ab51a79478f53458fb78ded3491819a94" dependencies = [ "anyhow", - "wasmparser 0.59.0", + "wasmparser 0.62.0", ] [[package]] @@ -2367,7 +2368,7 @@ dependencies = [ "smallvec", "target-lexicon", "tempfile", - "wasmparser 0.59.0", + "wasmparser 0.62.0", "wasmtime-cache", "wasmtime-environ", "wasmtime-jit", @@ -2445,6 +2446,7 @@ dependencies = [ "test-programs", "tracing-subscriber", "wasi-common", + "wasmparser 0.62.0", "wasmtime", "wasmtime-cache", "wasmtime-debug", @@ -2479,7 +2481,7 @@ dependencies = [ "object 0.21.1", "target-lexicon", "thiserror", - "wasmparser 0.59.0", + "wasmparser 0.62.0", "wasmtime-environ", ] @@ -2498,7 +2500,7 @@ dependencies = [ "more-asserts", "serde", "thiserror", - "wasmparser 0.59.0", + "wasmparser 0.62.0", ] [[package]] @@ -2526,7 +2528,7 @@ dependencies = [ "env_logger", "log", "rayon", - "wasmparser 0.59.0", + "wasmparser 0.62.0", "wasmprinter", "wasmtime", "wasmtime-wast", @@ -2553,7 +2555,7 @@ dependencies = [ "serde", "target-lexicon", "thiserror", - "wasmparser 0.59.0", + "wasmparser 0.62.0", "wasmtime-cranelift", "wasmtime-debug", "wasmtime-environ", @@ -2570,7 +2572,7 @@ version = "0.20.0" dependencies = [ "cranelift-codegen", "lightbeam", - "wasmparser 0.59.0", + "wasmparser 0.62.0", "wasmtime-environ", ] diff --git a/Cargo.toml b/Cargo.toml index d77efca0a0bb..9ec376a70ad4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ libc = "0.2.60" log = "0.4.8" rayon = "1.2.1" humantime = "1.3.0" +wasmparser = "0.62" [dev-dependencies] env_logger = "0.7.1" diff --git a/cranelift/wasm/Cargo.toml b/cranelift/wasm/Cargo.toml index 08288f32efe8..4ac50772e867 100644 --- a/cranelift/wasm/Cargo.toml +++ b/cranelift/wasm/Cargo.toml @@ -12,11 +12,12 @@ keywords = ["webassembly", "wasm"] edition = "2018" [dependencies] -wasmparser = { version = "0.59.0", default-features = false } +wasmparser = { version = "0.62.0", default-features = false } cranelift-codegen = { path = "../codegen", version = "0.67.0", default-features = false } cranelift-entity = { path = "../entity", version = "0.67.0" } cranelift-frontend = { path = "../frontend", version = "0.67.0", default-features = false } hashbrown = { version = "0.7", optional = true } +itertools = "0.9.0" log = { version = "0.4.6", default-features = false } serde = { version = "1.0.94", features = ["derive"], optional = true } thiserror = "1.0.4" diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index 18f7e7290170..a8e777205926 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,9 +43,9 @@ 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, WasmModuleResources}; -// Clippy warns about "flags: _" but its important to document that the flags field is ignored +// Clippy warns about "align: _" but its important to document that the flags field is ignored #[cfg_attr( feature = "cargo-clippy", allow(clippy::unneeded_field_pattern, clippy::cognitive_complexity) @@ -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,14 +180,14 @@ pub fn translate_operator( * possible `Block`'s arguments values. ***********************************************************************************/ Operator::Block { ty } => { - let (params, results) = blocktype_params_results(module_translation_state, *ty)?; - let next = block_with_params(builder, results, environ)?; + let (params, results) = blocktype_params_results(validator, *ty)?; + let next = block_with_params(builder, results.clone(), environ)?; state.push_block(next, params.len(), results.len()); } Operator::Loop { ty } => { - let (params, results) = blocktype_params_results(module_translation_state, *ty)?; - let loop_body = block_with_params(builder, params, environ)?; - let next = block_with_params(builder, results, environ)?; + let (params, results) = blocktype_params_results(validator, *ty)?; + let loop_body = block_with_params(builder, params.clone(), environ)?; + let next = block_with_params(builder, results.clone(), environ)?; builder.ins().jump(loop_body, state.peekn(params.len())); state.push_loop(loop_body, next, params.len(), results.len()); @@ -204,15 +204,15 @@ pub fn translate_operator( Operator::If { ty } => { let val = state.pop1(); - let (params, results) = blocktype_params_results(module_translation_state, *ty)?; - let (destination, else_data) = if params == results { + let (params, results) = blocktype_params_results(validator, *ty)?; + let (destination, else_data) = if params.clone().eq(results.clone()) { // 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, // we if the condition isn't true, then we jump directly to the // destination block following the whole `if...end`. If we do end // up discovering an `else`, then we will allocate a block for it // and go back and patch the jump. - let destination = block_with_params(builder, results, environ)?; + let destination = block_with_params(builder, results.clone(), environ)?; let branch_inst = builder .ins() .brz(val, destination, state.peekn(params.len())); @@ -220,8 +220,8 @@ pub fn translate_operator( } else { // The `if` type signature is not valid without an `else` block, // so we eagerly allocate the `else` block here. - let destination = block_with_params(builder, results, environ)?; - let else_block = block_with_params(builder, params, environ)?; + let destination = block_with_params(builder, results.clone(), environ)?; + let else_block = block_with_params(builder, params.clone(), environ)?; builder .ins() .brz(val, else_block, state.peekn(params.len())); @@ -268,9 +268,10 @@ 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)?; + let else_block = + block_with_params(builder, params.clone(), environ)?; builder.ins().jump(destination, state.peekn(params.len())); state.popn(params.len()); @@ -387,9 +388,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; } @@ -407,7 +409,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]; @@ -430,7 +432,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) => { @@ -570,137 +572,95 @@ pub fn translate_operator( * Memory management is handled by environment. It is usually translated into calls to * special functions. ************************************************************************************/ - Operator::MemoryGrow { reserved } => { + Operator::MemoryGrow { mem, mem_byte: _ } => { // The WebAssembly MVP only supports one linear memory, but we expect the reserved // argument to be a memory index. - let heap_index = MemoryIndex::from_u32(*reserved); - let heap = state.get_heap(builder.func, *reserved, environ)?; + let heap_index = MemoryIndex::from_u32(*mem); + let heap = state.get_heap(builder.func, *mem, environ)?; let val = state.pop1(); state.push1(environ.translate_memory_grow(builder.cursor(), heap_index, heap, val)?) } - Operator::MemorySize { reserved } => { - let heap_index = MemoryIndex::from_u32(*reserved); - let heap = state.get_heap(builder.func, *reserved, environ)?; + Operator::MemorySize { mem, mem_byte: _ } => { + let heap_index = MemoryIndex::from_u32(*mem); + let heap = state.get_heap(builder.func, *mem, environ)?; state.push1(environ.translate_memory_size(builder.cursor(), heap_index, heap)?); } /******************************* Load instructions *********************************** * Wasm specifies an integer alignment flag but we drop it in Cranelift. * The memory base address is provided by the environment. ************************************************************************************/ - Operator::I32Load8U { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Uload8, I32, builder, state, environ)?; + Operator::I32Load8U { memarg } => { + translate_load(memarg, ir::Opcode::Uload8, I32, builder, state, environ)?; } - Operator::I32Load16U { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Uload16, I32, builder, state, environ)?; + Operator::I32Load16U { memarg } => { + translate_load(memarg, ir::Opcode::Uload16, I32, builder, state, environ)?; } - Operator::I32Load8S { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Sload8, I32, builder, state, environ)?; + Operator::I32Load8S { memarg } => { + translate_load(memarg, ir::Opcode::Sload8, I32, builder, state, environ)?; } - Operator::I32Load16S { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Sload16, I32, builder, state, environ)?; + Operator::I32Load16S { memarg } => { + translate_load(memarg, ir::Opcode::Sload16, I32, builder, state, environ)?; } - Operator::I64Load8U { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Uload8, I64, builder, state, environ)?; + Operator::I64Load8U { memarg } => { + translate_load(memarg, ir::Opcode::Uload8, I64, builder, state, environ)?; } - Operator::I64Load16U { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Uload16, I64, builder, state, environ)?; + Operator::I64Load16U { memarg } => { + translate_load(memarg, ir::Opcode::Uload16, I64, builder, state, environ)?; } - Operator::I64Load8S { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Sload8, I64, builder, state, environ)?; + Operator::I64Load8S { memarg } => { + translate_load(memarg, ir::Opcode::Sload8, I64, builder, state, environ)?; } - Operator::I64Load16S { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Sload16, I64, builder, state, environ)?; + Operator::I64Load16S { memarg } => { + translate_load(memarg, ir::Opcode::Sload16, I64, builder, state, environ)?; } - Operator::I64Load32S { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Sload32, I64, builder, state, environ)?; + Operator::I64Load32S { memarg } => { + translate_load(memarg, ir::Opcode::Sload32, I64, builder, state, environ)?; } - Operator::I64Load32U { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Uload32, I64, builder, state, environ)?; + Operator::I64Load32U { memarg } => { + translate_load(memarg, ir::Opcode::Uload32, I64, builder, state, environ)?; } - Operator::I32Load { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Load, I32, builder, state, environ)?; + Operator::I32Load { memarg } => { + translate_load(memarg, ir::Opcode::Load, I32, builder, state, environ)?; } - Operator::F32Load { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Load, F32, builder, state, environ)?; + Operator::F32Load { memarg } => { + translate_load(memarg, ir::Opcode::Load, F32, builder, state, environ)?; } - Operator::I64Load { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Load, I64, builder, state, environ)?; + Operator::I64Load { memarg } => { + translate_load(memarg, ir::Opcode::Load, I64, builder, state, environ)?; } - Operator::F64Load { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Load, F64, builder, state, environ)?; + Operator::F64Load { memarg } => { + translate_load(memarg, ir::Opcode::Load, F64, builder, state, environ)?; } - Operator::V128Load { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_load(*offset, ir::Opcode::Load, I8X16, builder, state, environ)?; + Operator::V128Load { memarg } => { + translate_load(memarg, ir::Opcode::Load, I8X16, builder, state, environ)?; } - Operator::I16x8Load8x8S { - memarg: MemoryImmediate { flags: _, offset }, - } => { - let (flags, base, offset) = prepare_load(*offset, 8, builder, state, environ)?; + Operator::I16x8Load8x8S { memarg } => { + let (flags, base, offset) = prepare_load(memarg, 8, builder, state, environ)?; let loaded = builder.ins().sload8x8(flags, base, offset); state.push1(loaded); } - Operator::I16x8Load8x8U { - memarg: MemoryImmediate { flags: _, offset }, - } => { - let (flags, base, offset) = prepare_load(*offset, 8, builder, state, environ)?; + Operator::I16x8Load8x8U { memarg } => { + let (flags, base, offset) = prepare_load(memarg, 8, builder, state, environ)?; let loaded = builder.ins().uload8x8(flags, base, offset); state.push1(loaded); } - Operator::I32x4Load16x4S { - memarg: MemoryImmediate { flags: _, offset }, - } => { - let (flags, base, offset) = prepare_load(*offset, 8, builder, state, environ)?; + Operator::I32x4Load16x4S { memarg } => { + let (flags, base, offset) = prepare_load(memarg, 8, builder, state, environ)?; let loaded = builder.ins().sload16x4(flags, base, offset); state.push1(loaded); } - Operator::I32x4Load16x4U { - memarg: MemoryImmediate { flags: _, offset }, - } => { - let (flags, base, offset) = prepare_load(*offset, 8, builder, state, environ)?; + Operator::I32x4Load16x4U { memarg } => { + let (flags, base, offset) = prepare_load(memarg, 8, builder, state, environ)?; let loaded = builder.ins().uload16x4(flags, base, offset); state.push1(loaded); } - Operator::I64x2Load32x2S { - memarg: MemoryImmediate { flags: _, offset }, - } => { - let (flags, base, offset) = prepare_load(*offset, 8, builder, state, environ)?; + Operator::I64x2Load32x2S { memarg } => { + let (flags, base, offset) = prepare_load(memarg, 8, builder, state, environ)?; let loaded = builder.ins().sload32x2(flags, base, offset); state.push1(loaded); } - Operator::I64x2Load32x2U { - memarg: MemoryImmediate { flags: _, offset }, - } => { - let (flags, base, offset) = prepare_load(*offset, 8, builder, state, environ)?; + Operator::I64x2Load32x2U { memarg } => { + let (flags, base, offset) = prepare_load(memarg, 8, builder, state, environ)?; let loaded = builder.ins().uload32x2(flags, base, offset); state.push1(loaded); } @@ -708,45 +668,23 @@ pub fn translate_operator( * Wasm specifies an integer alignment flag but we drop it in Cranelift. * The memory base address is provided by the environment. ************************************************************************************/ - Operator::I32Store { - memarg: MemoryImmediate { flags: _, offset }, + Operator::I32Store { memarg } + | Operator::I64Store { memarg } + | Operator::F32Store { memarg } + | Operator::F64Store { memarg } => { + translate_store(memarg, ir::Opcode::Store, builder, state, environ)?; } - | Operator::I64Store { - memarg: MemoryImmediate { flags: _, offset }, + Operator::I32Store8 { memarg } | Operator::I64Store8 { memarg } => { + translate_store(memarg, ir::Opcode::Istore8, builder, state, environ)?; } - | Operator::F32Store { - memarg: MemoryImmediate { flags: _, offset }, + Operator::I32Store16 { memarg } | Operator::I64Store16 { memarg } => { + translate_store(memarg, ir::Opcode::Istore16, builder, state, environ)?; } - | Operator::F64Store { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_store(*offset, ir::Opcode::Store, builder, state, environ)?; - } - Operator::I32Store8 { - memarg: MemoryImmediate { flags: _, offset }, - } - | Operator::I64Store8 { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_store(*offset, ir::Opcode::Istore8, builder, state, environ)?; + Operator::I64Store32 { memarg } => { + translate_store(memarg, ir::Opcode::Istore32, builder, state, environ)?; } - Operator::I32Store16 { - memarg: MemoryImmediate { flags: _, offset }, - } - | Operator::I64Store16 { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_store(*offset, ir::Opcode::Istore16, builder, state, environ)?; - } - Operator::I64Store32 { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_store(*offset, ir::Opcode::Istore32, builder, state, environ)?; - } - Operator::V128Store { - memarg: MemoryImmediate { flags: _, offset }, - } => { - translate_store(*offset, ir::Opcode::Store, builder, state, environ)?; + Operator::V128Store { memarg } => { + translate_store(memarg, ir::Opcode::Store, builder, state, environ)?; } /****************************** Nullary Operators ************************************/ Operator::I32Const { value } => state.push1(builder.ins().iconst(I32, i64::from(*value))), @@ -1054,13 +992,13 @@ pub fn translate_operator( let index = FuncIndex::from_u32(*function_index); state.push1(environ.translate_ref_func(builder.cursor(), index)?); } - Operator::I32AtomicWait { .. } | Operator::I64AtomicWait { .. } => { + Operator::MemoryAtomicWait32 { .. } | Operator::MemoryAtomicWait64 { .. } => { // The WebAssembly MVP only supports one linear memory and // wasmparser will ensure that the memory indices specified are // zero. let implied_ty = match op { - Operator::I64AtomicWait { .. } => I64, - Operator::I32AtomicWait { .. } => I32, + Operator::MemoryAtomicWait64 { .. } => I64, + Operator::MemoryAtomicWait32 { .. } => I32, _ => unreachable!(), }; let heap_index = MemoryIndex::from_u32(0); @@ -1081,7 +1019,7 @@ pub fn translate_operator( )?; state.push1(res); } - Operator::AtomicNotify { .. } => { + Operator::MemoryAtomicNotify { .. } => { // The WebAssembly MVP only supports one linear memory and // wasmparser will ensure that the memory indices specified are // zero. @@ -1093,275 +1031,230 @@ pub fn translate_operator( environ.translate_atomic_notify(builder.cursor(), heap_index, heap, addr, count)?; state.push1(res); } - Operator::I32AtomicLoad { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_load(I32, I32, *offset, builder, state, environ)?, - Operator::I64AtomicLoad { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_load(I64, I64, *offset, builder, state, environ)?, - Operator::I32AtomicLoad8U { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_load(I32, I8, *offset, builder, state, environ)?, - Operator::I32AtomicLoad16U { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_load(I32, I16, *offset, builder, state, environ)?, - Operator::I64AtomicLoad8U { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_load(I64, I8, *offset, builder, state, environ)?, - Operator::I64AtomicLoad16U { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_load(I64, I16, *offset, builder, state, environ)?, - Operator::I64AtomicLoad32U { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_load(I64, I32, *offset, builder, state, environ)?, - - Operator::I32AtomicStore { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_store(I32, *offset, builder, state, environ)?, - Operator::I64AtomicStore { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_store(I64, *offset, builder, state, environ)?, - Operator::I32AtomicStore8 { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_store(I8, *offset, builder, state, environ)?, - Operator::I32AtomicStore16 { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_store(I16, *offset, builder, state, environ)?, - Operator::I64AtomicStore8 { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_store(I8, *offset, builder, state, environ)?, - Operator::I64AtomicStore16 { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_store(I16, *offset, builder, state, environ)?, - Operator::I64AtomicStore32 { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_store(I32, *offset, builder, state, environ)?, - - Operator::I32AtomicRmwAdd { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I32, AtomicRmwOp::Add, *offset, builder, state, environ)?, - Operator::I64AtomicRmwAdd { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I64, AtomicRmwOp::Add, *offset, builder, state, environ)?, - Operator::I32AtomicRmw8AddU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I8, AtomicRmwOp::Add, *offset, builder, state, environ)?, - Operator::I32AtomicRmw16AddU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I16, AtomicRmwOp::Add, *offset, builder, state, environ)?, - Operator::I64AtomicRmw8AddU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I8, AtomicRmwOp::Add, *offset, builder, state, environ)?, - Operator::I64AtomicRmw16AddU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I16, AtomicRmwOp::Add, *offset, builder, state, environ)?, - Operator::I64AtomicRmw32AddU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I32, AtomicRmwOp::Add, *offset, builder, state, environ)?, - - Operator::I32AtomicRmwSub { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I32, AtomicRmwOp::Sub, *offset, builder, state, environ)?, - Operator::I64AtomicRmwSub { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I64, AtomicRmwOp::Sub, *offset, builder, state, environ)?, - Operator::I32AtomicRmw8SubU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I8, AtomicRmwOp::Sub, *offset, builder, state, environ)?, - Operator::I32AtomicRmw16SubU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I16, AtomicRmwOp::Sub, *offset, builder, state, environ)?, - Operator::I64AtomicRmw8SubU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I8, AtomicRmwOp::Sub, *offset, builder, state, environ)?, - Operator::I64AtomicRmw16SubU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I16, AtomicRmwOp::Sub, *offset, builder, state, environ)?, - Operator::I64AtomicRmw32SubU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I32, AtomicRmwOp::Sub, *offset, builder, state, environ)?, - - Operator::I32AtomicRmwAnd { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I32, AtomicRmwOp::And, *offset, builder, state, environ)?, - Operator::I64AtomicRmwAnd { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I64, AtomicRmwOp::And, *offset, builder, state, environ)?, - Operator::I32AtomicRmw8AndU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I8, AtomicRmwOp::And, *offset, builder, state, environ)?, - Operator::I32AtomicRmw16AndU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I16, AtomicRmwOp::And, *offset, builder, state, environ)?, - Operator::I64AtomicRmw8AndU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I8, AtomicRmwOp::And, *offset, builder, state, environ)?, - Operator::I64AtomicRmw16AndU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I16, AtomicRmwOp::And, *offset, builder, state, environ)?, - Operator::I64AtomicRmw32AndU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I32, AtomicRmwOp::And, *offset, builder, state, environ)?, - - Operator::I32AtomicRmwOr { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I32, AtomicRmwOp::Or, *offset, builder, state, environ)?, - Operator::I64AtomicRmwOr { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I64, AtomicRmwOp::Or, *offset, builder, state, environ)?, - Operator::I32AtomicRmw8OrU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I8, AtomicRmwOp::Or, *offset, builder, state, environ)?, - Operator::I32AtomicRmw16OrU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I16, AtomicRmwOp::Or, *offset, builder, state, environ)?, - Operator::I64AtomicRmw8OrU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I8, AtomicRmwOp::Or, *offset, builder, state, environ)?, - Operator::I64AtomicRmw16OrU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I16, AtomicRmwOp::Or, *offset, builder, state, environ)?, - Operator::I64AtomicRmw32OrU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I32, AtomicRmwOp::Or, *offset, builder, state, environ)?, - - Operator::I32AtomicRmwXor { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I32, AtomicRmwOp::Xor, *offset, builder, state, environ)?, - Operator::I64AtomicRmwXor { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I64, AtomicRmwOp::Xor, *offset, builder, state, environ)?, - Operator::I32AtomicRmw8XorU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I8, AtomicRmwOp::Xor, *offset, builder, state, environ)?, - Operator::I32AtomicRmw16XorU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I16, AtomicRmwOp::Xor, *offset, builder, state, environ)?, - Operator::I64AtomicRmw8XorU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I8, AtomicRmwOp::Xor, *offset, builder, state, environ)?, - Operator::I64AtomicRmw16XorU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I16, AtomicRmwOp::Xor, *offset, builder, state, environ)?, - Operator::I64AtomicRmw32XorU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I32, AtomicRmwOp::Xor, *offset, builder, state, environ)?, - - Operator::I32AtomicRmwXchg { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw( - I32, - I32, - AtomicRmwOp::Xchg, - *offset, - builder, - state, - environ, - )?, - Operator::I64AtomicRmwXchg { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw( - I64, - I64, - AtomicRmwOp::Xchg, - *offset, - builder, - state, - environ, - )?, - Operator::I32AtomicRmw8XchgU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I32, I8, AtomicRmwOp::Xchg, *offset, builder, state, environ)?, - Operator::I32AtomicRmw16XchgU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw( - I32, - I16, - AtomicRmwOp::Xchg, - *offset, - builder, - state, - environ, - )?, - Operator::I64AtomicRmw8XchgU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw(I64, I8, AtomicRmwOp::Xchg, *offset, builder, state, environ)?, - Operator::I64AtomicRmw16XchgU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw( - I64, - I16, - AtomicRmwOp::Xchg, - *offset, - builder, - state, - environ, - )?, - Operator::I64AtomicRmw32XchgU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_rmw( - I64, - I32, - AtomicRmwOp::Xchg, - *offset, - builder, - state, - environ, - )?, - - Operator::I32AtomicRmwCmpxchg { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_cas(I32, I32, *offset, builder, state, environ)?, - Operator::I64AtomicRmwCmpxchg { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_cas(I64, I64, *offset, builder, state, environ)?, - Operator::I32AtomicRmw8CmpxchgU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_cas(I32, I8, *offset, builder, state, environ)?, - Operator::I32AtomicRmw16CmpxchgU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_cas(I32, I16, *offset, builder, state, environ)?, - Operator::I64AtomicRmw8CmpxchgU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_cas(I64, I8, *offset, builder, state, environ)?, - Operator::I64AtomicRmw16CmpxchgU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_cas(I64, I16, *offset, builder, state, environ)?, - Operator::I64AtomicRmw32CmpxchgU { - memarg: MemoryImmediate { flags: _, offset }, - } => translate_atomic_cas(I64, I32, *offset, builder, state, environ)?, + Operator::I32AtomicLoad { memarg } => { + translate_atomic_load(I32, I32, memarg, builder, state, environ)? + } + Operator::I64AtomicLoad { memarg } => { + translate_atomic_load(I64, I64, memarg, builder, state, environ)? + } + Operator::I32AtomicLoad8U { memarg } => { + translate_atomic_load(I32, I8, memarg, builder, state, environ)? + } + Operator::I32AtomicLoad16U { memarg } => { + translate_atomic_load(I32, I16, memarg, builder, state, environ)? + } + Operator::I64AtomicLoad8U { memarg } => { + translate_atomic_load(I64, I8, memarg, builder, state, environ)? + } + Operator::I64AtomicLoad16U { memarg } => { + translate_atomic_load(I64, I16, memarg, builder, state, environ)? + } + Operator::I64AtomicLoad32U { memarg } => { + translate_atomic_load(I64, I32, memarg, builder, state, environ)? + } + + Operator::I32AtomicStore { memarg } => { + translate_atomic_store(I32, memarg, builder, state, environ)? + } + Operator::I64AtomicStore { memarg } => { + translate_atomic_store(I64, memarg, builder, state, environ)? + } + Operator::I32AtomicStore8 { memarg } => { + translate_atomic_store(I8, memarg, builder, state, environ)? + } + Operator::I32AtomicStore16 { memarg } => { + translate_atomic_store(I16, memarg, builder, state, environ)? + } + Operator::I64AtomicStore8 { memarg } => { + translate_atomic_store(I8, memarg, builder, state, environ)? + } + Operator::I64AtomicStore16 { memarg } => { + translate_atomic_store(I16, memarg, builder, state, environ)? + } + Operator::I64AtomicStore32 { memarg } => { + translate_atomic_store(I32, memarg, builder, state, environ)? + } + + Operator::I32AtomicRmwAdd { memarg } => { + translate_atomic_rmw(I32, I32, AtomicRmwOp::Add, memarg, builder, state, environ)? + } + Operator::I64AtomicRmwAdd { memarg } => { + translate_atomic_rmw(I64, I64, AtomicRmwOp::Add, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw8AddU { memarg } => { + translate_atomic_rmw(I32, I8, AtomicRmwOp::Add, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw16AddU { memarg } => { + translate_atomic_rmw(I32, I16, AtomicRmwOp::Add, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw8AddU { memarg } => { + translate_atomic_rmw(I64, I8, AtomicRmwOp::Add, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw16AddU { memarg } => { + translate_atomic_rmw(I64, I16, AtomicRmwOp::Add, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw32AddU { memarg } => { + translate_atomic_rmw(I64, I32, AtomicRmwOp::Add, memarg, builder, state, environ)? + } + + Operator::I32AtomicRmwSub { memarg } => { + translate_atomic_rmw(I32, I32, AtomicRmwOp::Sub, memarg, builder, state, environ)? + } + Operator::I64AtomicRmwSub { memarg } => { + translate_atomic_rmw(I64, I64, AtomicRmwOp::Sub, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw8SubU { memarg } => { + translate_atomic_rmw(I32, I8, AtomicRmwOp::Sub, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw16SubU { memarg } => { + translate_atomic_rmw(I32, I16, AtomicRmwOp::Sub, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw8SubU { memarg } => { + translate_atomic_rmw(I64, I8, AtomicRmwOp::Sub, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw16SubU { memarg } => { + translate_atomic_rmw(I64, I16, AtomicRmwOp::Sub, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw32SubU { memarg } => { + translate_atomic_rmw(I64, I32, AtomicRmwOp::Sub, memarg, builder, state, environ)? + } + + Operator::I32AtomicRmwAnd { memarg } => { + translate_atomic_rmw(I32, I32, AtomicRmwOp::And, memarg, builder, state, environ)? + } + Operator::I64AtomicRmwAnd { memarg } => { + translate_atomic_rmw(I64, I64, AtomicRmwOp::And, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw8AndU { memarg } => { + translate_atomic_rmw(I32, I8, AtomicRmwOp::And, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw16AndU { memarg } => { + translate_atomic_rmw(I32, I16, AtomicRmwOp::And, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw8AndU { memarg } => { + translate_atomic_rmw(I64, I8, AtomicRmwOp::And, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw16AndU { memarg } => { + translate_atomic_rmw(I64, I16, AtomicRmwOp::And, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw32AndU { memarg } => { + translate_atomic_rmw(I64, I32, AtomicRmwOp::And, memarg, builder, state, environ)? + } + + Operator::I32AtomicRmwOr { memarg } => { + translate_atomic_rmw(I32, I32, AtomicRmwOp::Or, memarg, builder, state, environ)? + } + Operator::I64AtomicRmwOr { memarg } => { + translate_atomic_rmw(I64, I64, AtomicRmwOp::Or, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw8OrU { memarg } => { + translate_atomic_rmw(I32, I8, AtomicRmwOp::Or, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw16OrU { memarg } => { + translate_atomic_rmw(I32, I16, AtomicRmwOp::Or, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw8OrU { memarg } => { + translate_atomic_rmw(I64, I8, AtomicRmwOp::Or, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw16OrU { memarg } => { + translate_atomic_rmw(I64, I16, AtomicRmwOp::Or, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw32OrU { memarg } => { + translate_atomic_rmw(I64, I32, AtomicRmwOp::Or, memarg, builder, state, environ)? + } + + Operator::I32AtomicRmwXor { memarg } => { + translate_atomic_rmw(I32, I32, AtomicRmwOp::Xor, memarg, builder, state, environ)? + } + Operator::I64AtomicRmwXor { memarg } => { + translate_atomic_rmw(I64, I64, AtomicRmwOp::Xor, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw8XorU { memarg } => { + translate_atomic_rmw(I32, I8, AtomicRmwOp::Xor, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw16XorU { memarg } => { + translate_atomic_rmw(I32, I16, AtomicRmwOp::Xor, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw8XorU { memarg } => { + translate_atomic_rmw(I64, I8, AtomicRmwOp::Xor, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw16XorU { memarg } => { + translate_atomic_rmw(I64, I16, AtomicRmwOp::Xor, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw32XorU { memarg } => { + translate_atomic_rmw(I64, I32, AtomicRmwOp::Xor, memarg, builder, state, environ)? + } + + Operator::I32AtomicRmwXchg { memarg } => { + translate_atomic_rmw(I32, I32, AtomicRmwOp::Xchg, memarg, builder, state, environ)? + } + Operator::I64AtomicRmwXchg { memarg } => { + translate_atomic_rmw(I64, I64, AtomicRmwOp::Xchg, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw8XchgU { memarg } => { + translate_atomic_rmw(I32, I8, AtomicRmwOp::Xchg, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw16XchgU { memarg } => { + translate_atomic_rmw(I32, I16, AtomicRmwOp::Xchg, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw8XchgU { memarg } => { + translate_atomic_rmw(I64, I8, AtomicRmwOp::Xchg, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw16XchgU { memarg } => { + translate_atomic_rmw(I64, I16, AtomicRmwOp::Xchg, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw32XchgU { memarg } => { + translate_atomic_rmw(I64, I32, AtomicRmwOp::Xchg, memarg, builder, state, environ)? + } + + Operator::I32AtomicRmwCmpxchg { memarg } => { + translate_atomic_cas(I32, I32, memarg, builder, state, environ)? + } + Operator::I64AtomicRmwCmpxchg { memarg } => { + translate_atomic_cas(I64, I64, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw8CmpxchgU { memarg } => { + translate_atomic_cas(I32, I8, memarg, builder, state, environ)? + } + Operator::I32AtomicRmw16CmpxchgU { memarg } => { + translate_atomic_cas(I32, I16, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw8CmpxchgU { memarg } => { + translate_atomic_cas(I64, I8, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw16CmpxchgU { memarg } => { + translate_atomic_cas(I64, I16, memarg, builder, state, environ)? + } + Operator::I64AtomicRmw32CmpxchgU { memarg } => { + translate_atomic_cas(I64, I32, memarg, builder, state, environ)? + } Operator::AtomicFence { .. } => { builder.ins().fence(); } - Operator::MemoryCopy => { + Operator::MemoryCopy { src, dst } => { // The WebAssembly MVP only supports one linear memory and // wasmparser will ensure that the memory indices specified are // zero. - let heap_index = MemoryIndex::from_u32(0); - let heap = state.get_heap(builder.func, 0, environ)?; + assert_eq!(src, dst, "unimplemented between-memories copy"); + let heap_index = MemoryIndex::from_u32(*src); + let heap = state.get_heap(builder.func, *src, environ)?; let len = state.pop1(); let src = state.pop1(); let dest = state.pop1(); environ.translate_memory_copy(builder.cursor(), heap_index, heap, dest, src, len)?; } - Operator::MemoryFill => { - // The WebAssembly MVP only supports one linear memory and - // wasmparser will ensure that the memory index specified is - // zero. - let heap_index = MemoryIndex::from_u32(0); - let heap = state.get_heap(builder.func, 0, environ)?; + Operator::MemoryFill { mem } => { + let heap_index = MemoryIndex::from_u32(*mem); + let heap = state.get_heap(builder.func, *mem, environ)?; let len = state.pop1(); let val = state.pop1(); let dest = state.pop1(); environ.translate_memory_fill(builder.cursor(), heap_index, heap, dest, val, len)?; } - Operator::MemoryInit { segment } => { - // The WebAssembly MVP only supports one linear memory and - // wasmparser will ensure that the memory index specified is - // zero. - let heap_index = MemoryIndex::from_u32(0); - let heap = state.get_heap(builder.func, 0, environ)?; + Operator::MemoryInit { segment, mem } => { + let heap_index = MemoryIndex::from_u32(*mem); + let heap = state.get_heap(builder.func, *mem, environ)?; let len = state.pop1(); let src = state.pop1(); let dest = state.pop1(); @@ -1479,23 +1372,15 @@ pub fn translate_operator( let splatted = builder.ins().splat(type_of(op), state.pop1()); state.push1(splatted) } - Operator::V8x16LoadSplat { - memarg: MemoryImmediate { flags: _, offset }, - } - | Operator::V16x8LoadSplat { - memarg: MemoryImmediate { flags: _, offset }, - } - | Operator::V32x4LoadSplat { - memarg: MemoryImmediate { flags: _, offset }, - } - | Operator::V64x2LoadSplat { - memarg: MemoryImmediate { flags: _, offset }, - } => { + Operator::V8x16LoadSplat { memarg } + | Operator::V16x8LoadSplat { memarg } + | Operator::V32x4LoadSplat { memarg } + | Operator::V64x2LoadSplat { memarg } => { // TODO: For spec compliance, this is initially implemented as a combination of `load + // splat` but could be implemented eventually as a single instruction (`load_splat`). // See https://github.com/bytecodealliance/wasmtime/issues/1175. translate_load( - *offset, + memarg, ir::Opcode::Load, type_of(op).lane_type(), builder, @@ -1845,7 +1730,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, @@ -1889,7 +1774,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)?; let frame = state.control_stack.last().unwrap(); frame.truncate_value_stack_to_else_params(&mut state.stack); @@ -2056,7 +1941,7 @@ fn get_heap_addr( /// Prepare for a load; factors out common functionality between load and load_extend operations. fn prepare_load( - offset: u32, + memarg: &MemoryImmediate, loaded_bytes: u32, builder: &mut FunctionBuilder, state: &mut FuncTranslationState, @@ -2064,12 +1949,11 @@ fn prepare_load( ) -> WasmResult<(MemFlags, Value, Offset32)> { let addr32 = state.pop1(); - // We don't yet support multiple linear memories. - let heap = state.get_heap(builder.func, 0, environ)?; + let heap = state.get_heap(builder.func, memarg.memory, environ)?; let (base, offset) = get_heap_addr( heap, addr32, - offset, + memarg.offset, loaded_bytes, environ.pointer_type(), builder, @@ -2085,7 +1969,7 @@ fn prepare_load( /// Translate a load instruction. fn translate_load( - offset: u32, + memarg: &MemoryImmediate, opcode: ir::Opcode, result_ty: Type, builder: &mut FunctionBuilder, @@ -2093,7 +1977,7 @@ fn translate_load( environ: &mut FE, ) -> WasmResult<()> { let (flags, base, offset) = prepare_load( - offset, + memarg, mem_op_size(opcode, result_ty), builder, state, @@ -2106,7 +1990,7 @@ fn translate_load( /// Translate a store instruction. fn translate_store( - offset: u32, + memarg: &MemoryImmediate, opcode: ir::Opcode, builder: &mut FunctionBuilder, state: &mut FuncTranslationState, @@ -2115,12 +1999,11 @@ fn translate_store( let (addr32, val) = state.pop2(); let val_ty = builder.func.dfg.value_type(val); - // We don't yet support multiple linear memories. - let heap = state.get_heap(builder.func, 0, environ)?; + let heap = state.get_heap(builder.func, memarg.memory, environ)?; let (base, offset) = get_heap_addr( heap, addr32, - offset, + memarg.offset, mem_op_size(opcode, val_ty), environ.pointer_type(), builder, @@ -2153,7 +2036,7 @@ fn translate_icmp(cc: IntCC, builder: &mut FunctionBuilder, state: &mut FuncTran // and then compute the final effective address. fn finalise_atomic_mem_addr( linear_mem_addr: Value, - offset: u32, + memarg: &MemoryImmediate, access_ty: Type, builder: &mut FunctionBuilder, state: &mut FuncTranslationState, @@ -2161,7 +2044,9 @@ fn finalise_atomic_mem_addr( ) -> WasmResult { // Check the alignment of `linear_mem_addr`. let access_ty_bytes = access_ty.bytes(); - let final_lma = builder.ins().iadd_imm(linear_mem_addr, i64::from(offset)); + let final_lma = builder + .ins() + .iadd_imm(linear_mem_addr, i64::from(memarg.offset)); if access_ty_bytes != 1 { assert!(access_ty_bytes == 2 || access_ty_bytes == 4 || access_ty_bytes == 8); let final_lma_misalignment = builder @@ -2175,8 +2060,8 @@ fn finalise_atomic_mem_addr( .trapif(IntCC::NotEqual, f, ir::TrapCode::HeapMisaligned); } - // Compute the final effective address. Note, we don't yet support multiple linear memories. - let heap = state.get_heap(builder.func, 0, environ)?; + // Compute the final effective address. + let heap = state.get_heap(builder.func, memarg.memory, environ)?; let (base, offset) = get_heap_addr( heap, final_lma, @@ -2194,7 +2079,7 @@ fn translate_atomic_rmw( widened_ty: Type, access_ty: Type, op: AtomicRmwOp, - offset: u32, + memarg: &MemoryImmediate, builder: &mut FunctionBuilder, state: &mut FuncTranslationState, environ: &mut FE, @@ -2225,7 +2110,7 @@ fn translate_atomic_rmw( } let final_effective_address = - finalise_atomic_mem_addr(linear_mem_addr, offset, access_ty, builder, state, environ)?; + finalise_atomic_mem_addr(linear_mem_addr, memarg, access_ty, builder, state, environ)?; // See the comments in `prepare_load` about the flags. let flags = MemFlags::new(); @@ -2242,7 +2127,7 @@ fn translate_atomic_rmw( fn translate_atomic_cas( widened_ty: Type, access_ty: Type, - offset: u32, + memarg: &MemoryImmediate, builder: &mut FunctionBuilder, state: &mut FuncTranslationState, environ: &mut FE, @@ -2278,7 +2163,7 @@ fn translate_atomic_cas( } let final_effective_address = - finalise_atomic_mem_addr(linear_mem_addr, offset, access_ty, builder, state, environ)?; + finalise_atomic_mem_addr(linear_mem_addr, memarg, access_ty, builder, state, environ)?; // See the comments in `prepare_load` about the flags. let flags = MemFlags::new(); @@ -2295,7 +2180,7 @@ fn translate_atomic_cas( fn translate_atomic_load( widened_ty: Type, access_ty: Type, - offset: u32, + memarg: &MemoryImmediate, builder: &mut FunctionBuilder, state: &mut FuncTranslationState, environ: &mut FE, @@ -2320,7 +2205,7 @@ fn translate_atomic_load( assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes()); let final_effective_address = - finalise_atomic_mem_addr(linear_mem_addr, offset, access_ty, builder, state, environ)?; + finalise_atomic_mem_addr(linear_mem_addr, memarg, access_ty, builder, state, environ)?; // See the comments in `prepare_load` about the flags. let flags = MemFlags::new(); @@ -2336,7 +2221,7 @@ fn translate_atomic_load( fn translate_atomic_store( access_ty: Type, - offset: u32, + memarg: &MemoryImmediate, builder: &mut FunctionBuilder, state: &mut FuncTranslationState, environ: &mut FE, @@ -2366,7 +2251,7 @@ fn translate_atomic_store( } let final_effective_address = - finalise_atomic_mem_addr(linear_mem_addr, offset, access_ty, builder, state, environ)?; + finalise_atomic_mem_addr(linear_mem_addr, memarg, access_ty, builder, state, environ)?; // See the comments in `prepare_load` about the flags. let flags = MemFlags::new(); diff --git a/cranelift/wasm/src/environ/dummy.rs b/cranelift/wasm/src/environ/dummy.rs index 8bf4e0b1f9a1..ae87ec5727f3 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, ValidatorResources, WasmFeatures}; /// Compute a `ir::ExternalName` for a given wasm function index. fn get_func_name(func_index: FuncIndex) -> ir::ExternalName { @@ -738,10 +738,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 = @@ -752,16 +753,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(()) } @@ -773,4 +768,14 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment { fn declare_func_name(&mut self, func_index: FuncIndex, name: &'data str) { self.function_names[func_index] = String::from(name); } + + fn wasm_features(&self) -> WasmFeatures { + WasmFeatures { + multi_value: true, + simd: true, + reference_types: true, + bulk_memory: true, + ..WasmFeatures::default() + } + } } diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index 045d6e2f29f3..47fbb9d2c31d 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,8 @@ use serde::{Deserialize, Serialize}; use std::boxed::Box; use std::string::ToString; use thiserror::Error; -use wasmparser::BinaryReaderError; -use wasmparser::Operator; +use wasmparser::ValidatorResources; +use wasmparser::{BinaryReaderError, FuncValidator, FunctionBody, Operator, WasmFeatures}; /// WebAssembly value type -- equivalent of `wasmparser`'s Type. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -798,9 +798,8 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment { /// Provides the contents of a function body. 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 @@ -841,4 +840,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 f46b0f7fa0c2..158271ab9646 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; @@ -14,7 +14,7 @@ use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::{self, Block, InstBuilder, ValueLabel}; use cranelift_codegen::timing; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; -use wasmparser::{self, BinaryReader}; +use wasmparser::{self, BinaryReader, FuncValidator, FunctionBody, WasmModuleResources}; /// WebAssembly to Cranelift IR function translator. /// @@ -55,29 +55,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(); log::debug!( "translate({} bytes, {}{})", reader.bytes_remaining(), @@ -107,14 +108,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(()) @@ -161,14 +156,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)?; } @@ -218,7 +216,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, @@ -227,14 +225,17 @@ fn parse_function_body( // The control stack is initialized with a single block representing the whole function. debug_assert_eq!(state.control_stack.len(), 1, "State not initialized"); - // Keep going until the final `End` operator which pops the outermost block. - while !state.control_stack.is_empty() { + while !reader.eof() { + 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. @@ -261,8 +262,6 @@ fn parse_function_body( // or the end of the function is unreachable. state.stack.clear(); - debug_assert!(reader.eof()); - Ok(()) } @@ -277,26 +276,27 @@ fn cur_srcloc(reader: &BinaryReader) -> ir::SourceLoc { mod tests { use super::{FuncTranslator, ReturnMode}; use crate::environ::DummyEnvironment; - use crate::ModuleTranslationState; use cranelift_codegen::ir::types::I32; use cranelift_codegen::{ir, isa, settings, Context}; use log::debug; use target_lexicon::PointerWidth; + use wasmparser::{ + FuncValidator, FunctionBody, Parser, ValidPayload, Validator, ValidatorResources, + }; #[test] fn small1() { // Implicit return. - // - // (func $small1 (param i32) (result i32) - // (i32.add (get_local 0) (i32.const 1)) - // ) - const BODY: [u8; 7] = [ - 0x00, // local decl count - 0x20, 0x00, // get_local 0 - 0x41, 0x01, // i32.const 1 - 0x6a, // i32.add - 0x0b, // end - ]; + let wasm = wat::parse_str( + " + (module + (func $small2 (param i32) (result i32) + (i32.add (get_local 0) (i32.const 1)) + ) + ) + ", + ) + .unwrap(); let mut trans = FuncTranslator::new(); let flags = settings::Flags::new(settings::builder()); @@ -309,21 +309,15 @@ mod tests { false, ); - let module_translation_state = ModuleTranslationState::new(); let mut ctx = Context::new(); ctx.func.name = ir::ExternalName::testcase("small1"); ctx.func.signature.params.push(ir::AbiParam::new(I32)); ctx.func.signature.returns.push(ir::AbiParam::new(I32)); + let (body, mut validator) = extract_func(&wasm); trans - .translate( - &module_translation_state, - &BODY, - 0, - &mut ctx.func, - &mut runtime.func_env(), - ) + .translate_body(&mut validator, body, &mut ctx.func, &mut runtime.func_env()) .unwrap(); debug!("{}", ctx.func.display(None)); ctx.verify(&flags).unwrap(); @@ -332,18 +326,16 @@ mod tests { #[test] fn small2() { // Same as above, but with an explicit return instruction. - // - // (func $small2 (param i32) (result i32) - // (return (i32.add (get_local 0) (i32.const 1))) - // ) - const BODY: [u8; 8] = [ - 0x00, // local decl count - 0x20, 0x00, // get_local 0 - 0x41, 0x01, // i32.const 1 - 0x6a, // i32.add - 0x0f, // return - 0x0b, // end - ]; + let wasm = wat::parse_str( + " + (module + (func $small2 (param i32) (result i32) + (return (i32.add (get_local 0) (i32.const 1))) + ) + ) + ", + ) + .unwrap(); let mut trans = FuncTranslator::new(); let flags = settings::Flags::new(settings::builder()); @@ -356,21 +348,15 @@ mod tests { false, ); - let module_translation_state = ModuleTranslationState::new(); let mut ctx = Context::new(); ctx.func.name = ir::ExternalName::testcase("small2"); ctx.func.signature.params.push(ir::AbiParam::new(I32)); ctx.func.signature.returns.push(ir::AbiParam::new(I32)); + let (body, mut validator) = extract_func(&wasm); trans - .translate( - &module_translation_state, - &BODY, - 0, - &mut ctx.func, - &mut runtime.func_env(), - ) + .translate_body(&mut validator, body, &mut ctx.func, &mut runtime.func_env()) .unwrap(); debug!("{}", ctx.func.display(None)); ctx.verify(&flags).unwrap(); @@ -379,27 +365,21 @@ mod tests { #[test] fn infloop() { // An infinite loop, no return instructions. - // - // (func $infloop (result i32) - // (local i32) - // (loop (result i32) - // (i32.add (get_local 0) (i32.const 1)) - // (set_local 0) - // (br 0) - // ) - // ) - const BODY: [u8; 16] = [ - 0x01, // 1 local decl. - 0x01, 0x7f, // 1 i32 local. - 0x03, 0x7f, // loop i32 - 0x20, 0x00, // get_local 0 - 0x41, 0x01, // i32.const 0 - 0x6a, // i32.add - 0x21, 0x00, // set_local 0 - 0x0c, 0x00, // br 0 - 0x0b, // end - 0x0b, // end - ]; + let wasm = wat::parse_str( + " + (module + (func $infloop (result i32) + (local i32) + (loop (result i32) + (i32.add (get_local 0) (i32.const 1)) + (set_local 0) + (br 0) + ) + ) + ) + ", + ) + .unwrap(); let mut trans = FuncTranslator::new(); let flags = settings::Flags::new(settings::builder()); @@ -412,22 +392,27 @@ mod tests { false, ); - let module_translation_state = ModuleTranslationState::new(); let mut ctx = Context::new(); ctx.func.name = ir::ExternalName::testcase("infloop"); ctx.func.signature.returns.push(ir::AbiParam::new(I32)); + let (body, mut validator) = extract_func(&wasm); trans - .translate( - &module_translation_state, - &BODY, - 0, - &mut ctx.func, - &mut runtime.func_env(), - ) + .translate_body(&mut validator, body, &mut ctx.func, &mut runtime.func_env()) .unwrap(); debug!("{}", ctx.func.display(None)); ctx.verify(&flags).unwrap(); } + + fn extract_func(wat: &[u8]) -> (FunctionBody<'_>, FuncValidator) { + let mut validator = Validator::new(); + for payload in Parser::new(0).parse_all(wat) { + match validator.payload(&payload.unwrap()).unwrap() { + ValidPayload::Func(validator, body) => return (body, validator), + _ => {} + } + } + panic!("failed to find function"); + } } diff --git a/cranelift/wasm/src/lib.rs b/cranelift/wasm/src/lib.rs index 661bfe8dd4df..cbc4a51861c6 100644 --- a/cranelift/wasm/src/lib.rs +++ b/cranelift/wasm/src/lib.rs @@ -72,5 +72,10 @@ pub use crate::translation_utils::{ }; pub use cranelift_frontend::FunctionBuilder; +// Convenience reexport of the wasmparser crate that we're linking against, +// since a number of types in `wasmparser` show up in the public API of +// `cranelift-wasm`. +pub use wasmparser; + /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/cranelift/wasm/src/module_translator.rs b/cranelift/wasm/src/module_translator.rs index e3cd0b44bf89..89e6923fcf86 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,75 +18,105 @@ 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 { count, range, .. } => { + validator.code_section_start(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(); - let offset = code.original_position(); - environ.define_function_body( - &module_translation_state, - code.read_bytes(size)?, - offset, - )?; + 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") } @@ -105,7 +135,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 326782252679..da52b2846802 100644 --- a/cranelift/wasm/src/sections_translator.rs +++ b/cranelift/wasm/src/sections_translator.rs @@ -26,7 +26,7 @@ use wasmparser::{ self, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems, ElementKind, ElementSectionReader, Export, ExportSectionReader, ExternalKind, FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType, ImportSectionReader, - MemorySectionReader, MemoryType, NameSectionReader, Naming, Operator, TableSectionReader, Type, + MemorySectionReader, MemoryType, NameSectionReader, Naming, Operator, TableSectionReader, TypeDef, TypeSectionReader, }; @@ -88,7 +88,7 @@ pub fn parse_import_section<'data>( ImportSectionEntryType::Module(_sig) | ImportSectionEntryType::Instance(_sig) => { unimplemented!("module linking not implemented yet") } - ImportSectionEntryType::Memory(MemoryType { + ImportSectionEntryType::Memory(MemoryType::M32 { limits: ref memlimits, shared, }) => { @@ -102,6 +102,9 @@ pub fn parse_import_section<'data>( field_name, )?; } + ImportSectionEntryType::Memory(MemoryType::M64 { .. }) => { + unimplemented!(); + } ImportSectionEntryType::Global(ref ty) => { environ.declare_global_import( Global { @@ -189,11 +192,16 @@ pub fn parse_memory_section( for entry in memories { let memory = entry?; - environ.declare_memory(Memory { - minimum: memory.limits.initial, - maximum: memory.limits.maximum, - shared: memory.shared, - })?; + match memory { + MemoryType::M32 { limits, shared } => { + environ.declare_memory(Memory { + minimum: limits.initial, + maximum: limits.maximum, + shared: shared, + })?; + } + MemoryType::M64 { .. } => unimplemented!(), + } } Ok(()) @@ -313,13 +321,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..d8bb6c8593cd 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, WasmFuncType, WasmModuleResources}; /// Index type of a function (imported or defined) inside the WebAssembly module. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] @@ -194,38 +193,56 @@ 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, +pub fn blocktype_params_results<'a, T>( + validator: &'a FuncValidator, ty_or_ft: wasmparser::TypeOrFuncType, -) -> WasmResult<(&[wasmparser::Type], &[wasmparser::Type])> { - Ok(match ty_or_ft { - wasmparser::TypeOrFuncType::Type(ty) => match ty { - wasmparser::Type::I32 => (&[], &[wasmparser::Type::I32]), - wasmparser::Type::I64 => (&[], &[wasmparser::Type::I64]), - wasmparser::Type::F32 => (&[], &[wasmparser::Type::F32]), - wasmparser::Type::F64 => (&[], &[wasmparser::Type::F64]), - wasmparser::Type::V128 => (&[], &[wasmparser::Type::V128]), - wasmparser::Type::ExternRef => (&[], &[wasmparser::Type::ExternRef]), - wasmparser::Type::FuncRef => (&[], &[wasmparser::Type::FuncRef]), - wasmparser::Type::EmptyBlockType => (&[], &[]), - ty => return Err(wasm_unsupported!("blocktype_params_results: type {:?}", ty)), - }, +) -> WasmResult<( + impl ExactSizeIterator + Clone + 'a, + impl ExactSizeIterator + Clone + 'a, +)> +where + T: WasmModuleResources, +{ + return Ok(match ty_or_ft { + wasmparser::TypeOrFuncType::Type(ty) => { + let (params, results): (&'static [wasmparser::Type], &'static [wasmparser::Type]) = + match ty { + wasmparser::Type::I32 => (&[], &[wasmparser::Type::I32]), + wasmparser::Type::I64 => (&[], &[wasmparser::Type::I64]), + wasmparser::Type::F32 => (&[], &[wasmparser::Type::F32]), + wasmparser::Type::F64 => (&[], &[wasmparser::Type::F64]), + wasmparser::Type::V128 => (&[], &[wasmparser::Type::V128]), + wasmparser::Type::ExternRef => (&[], &[wasmparser::Type::ExternRef]), + wasmparser::Type::FuncRef => (&[], &[wasmparser::Type::FuncRef]), + wasmparser::Type::EmptyBlockType => (&[], &[]), + ty => return Err(wasm_unsupported!("blocktype_params_results: type {:?}", ty)), + }; + ( + itertools::Either::Left(params.iter().copied()), + itertools::Either::Left(results.iter().copied()), + ) + } 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 + .resources() + .func_type_at(ty_index) + .expect("should be valid"); + ( + itertools::Either::Right(ty.inputs()), + itertools::Either::Right(ty.outputs()), + ) } - }) + }); } /// Create a `Block` with the given Wasm parameters. pub fn block_with_params( builder: &mut FunctionBuilder, - params: &[wasmparser::Type], + params: impl IntoIterator, environ: &PE, ) -> WasmResult { let block = builder.create_block(); - for ty in params.iter() { + for ty in params { match ty { wasmparser::Type::I32 => { builder.append_block_param(block, ir::types::I32); @@ -240,7 +257,7 @@ pub fn block_with_params( builder.append_block_param(block, ir::types::F64); } wasmparser::Type::ExternRef | wasmparser::Type::FuncRef => { - builder.append_block_param(block, environ.reference_type((*ty).try_into()?)); + builder.append_block_param(block, environ.reference_type(ty.try_into()?)); } wasmparser::Type::V128 => { builder.append_block_param(block, ir::types::I8X16); diff --git a/cranelift/wasm/tests/wasm_testsuite.rs b/cranelift/wasm/tests/wasm_testsuite.rs index 65fd3cfdeb82..73b5508b2f45 100644 --- a/cranelift/wasm/tests/wasm_testsuite.rs +++ b/cranelift/wasm/tests/wasm_testsuite.rs @@ -4,9 +4,6 @@ use cranelift_codegen::settings::{self, Flags}; use cranelift_codegen::verifier; use cranelift_wasm::{translate_module, DummyEnvironment, FuncIndex, ReturnMode}; use std::fs; -use std::fs::File; -use std::io; -use std::io::prelude::*; use std::path::Path; use std::str::FromStr; use target_lexicon::triple; @@ -69,20 +66,13 @@ fn use_name_section() { ); } -fn read_file(path: &Path) -> io::Result> { - let mut buf: Vec = Vec::new(); - let mut file = File::open(path)?; - file.read_to_end(&mut buf)?; - Ok(buf) -} - fn read_module(path: &Path) -> Vec { match path.extension() { None => { panic!("the file extension is not wasm or wat"); } Some(ext) => match ext.to_str() { - Some("wasm") => read_file(path).expect("error reading wasm file"), + Some("wasm") => std::fs::read(path).expect("error reading wasm file"), Some("wat") => wat::parse_file(path) .map_err(|e| e.to_string()) .expect("failed to parse wat"), diff --git a/cranelift/wasmtests/passive-data.wat b/cranelift/wasmtests/passive-data.wat index 9316cd0f595d..00d3b2c849ae 100644 --- a/cranelift/wasmtests/passive-data.wat +++ b/cranelift/wasmtests/passive-data.wat @@ -1,5 +1,6 @@ (module (data $passive "this is a passive data segment") + (memory 0) (func (export "init") (param i32 i32 i32) local.get 0 ;; dst diff --git a/cranelift/wasmtests/ref-func-0.wat b/cranelift/wasmtests/ref-func-0.wat index 4616f54c2a69..4cdee3f567da 100644 --- a/cranelift/wasmtests/ref-func-0.wat +++ b/cranelift/wasmtests/ref-func-0.wat @@ -6,7 +6,7 @@ global.get 2 global.get 3) - (global (export "externref-imported") externref (ref.func $imported)) - (global (export "externref-local") externref (ref.func $local)) + (global (export "externref-imported") externref (ref.null extern)) + (global (export "externref-local") externref (ref.null extern)) (global (export "funcref-imported") funcref (ref.func $imported)) (global (export "funcref-local") funcref (ref.func $local))) diff --git a/crates/cranelift/src/lib.rs b/crates/cranelift/src/lib.rs index c6670659fc9d..2da7461cbba9 100644 --- a/crates/cranelift/src/lib.rs +++ b/crates/cranelift/src/lib.rs @@ -267,8 +267,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, @@ -302,7 +305,7 @@ impl Compiler for Cranelift { &self, translation: &ModuleTranslation<'_>, func_index: DefinedFuncIndex, - input: &FunctionBodyData<'_>, + mut input: FunctionBodyData<'_>, isa: &dyn isa::TargetIsa, ) -> Result { let module = &translation.module; @@ -351,14 +354,15 @@ impl Compiler for Cranelift { }); context.func.stack_limit = Some(stack_limit); let mut func_translator = self.take_translator(); - let result = func_translator.translate( - translation.module_translation.as_ref().unwrap(), - input.data, - input.module_offset, + let result = func_translator.translate_body( + &mut input.validator, + input.body.clone(), &mut context.func, &mut func_env, ); - self.save_translator(func_translator); + if result.is_ok() { + self.save_translator(func_translator); + } result?; let mut code_buf: Vec = Vec::new(); @@ -381,7 +385,7 @@ impl Compiler for Cranelift { CompileError::Codegen(pretty_error(&context.func, Some(isa), error)) })?; - let address_transform = get_function_address_map(&context, input, code_buf.len(), isa); + let address_transform = get_function_address_map(&context, &input, code_buf.len(), isa); let ranges = if tunables.debug_info { let ranges = context.build_value_labels_ranges(isa).map_err(|error| { diff --git a/crates/debug/Cargo.toml b/crates/debug/Cargo.toml index 183ee2dbd2e3..c17dfdf3ff69 100644 --- a/crates/debug/Cargo.toml +++ b/crates/debug/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" [dependencies] gimli = "0.22.0" -wasmparser = "0.59.0" +wasmparser = "0.62.0" object = { version = "0.21.1", default-features = false, features = ["read", "write"] } wasmtime-environ = { path = "../environ", version = "0.20.0" } target-lexicon = { version = "0.11.0", default-features = false } diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml index d63908f845b3..294399ec6228 100644 --- a/crates/environ/Cargo.toml +++ b/crates/environ/Cargo.toml @@ -16,7 +16,7 @@ anyhow = "1.0" cranelift-codegen = { path = "../../cranelift/codegen", version = "0.67.0", features = ["enable-serde"] } cranelift-entity = { path = "../../cranelift/entity", version = "0.67.0", features = ["enable-serde"] } cranelift-wasm = { path = "../../cranelift/wasm", version = "0.67.0", features = ["enable-serde"] } -wasmparser = "0.59.0" +wasmparser = "0.62.0" indexmap = { version = "1.0.2", features = ["serde-1"] } thiserror = "1.0.4" serde = { version = "1.0.94", features = ["derive"] } diff --git a/crates/environ/src/compilation.rs b/crates/environ/src/compilation.rs index 57cb6a46efa6..eb97e360708b 100644 --- a/crates/environ/src/compilation.rs +++ b/crates/environ/src/compilation.rs @@ -103,7 +103,7 @@ pub trait Compiler: Send + Sync { &self, translation: &ModuleTranslation<'_>, index: DefinedFuncIndex, - data: &FunctionBodyData<'_>, + data: FunctionBodyData<'_>, isa: &dyn isa::TargetIsa, ) -> Result; } diff --git a/crates/environ/src/module_environ.rs b/crates/environ/src/module_environ.rs index 19db0bdaf394..ef33de660762 100644 --- a/crates/environ/src/module_environ.rs +++ b/crates/environ/src/module_environ.rs @@ -15,12 +15,14 @@ use std::convert::TryFrom; use std::path::PathBuf; use std::sync::Arc; use wasmparser::Type as WasmType; +use wasmparser::{FuncValidator, FunctionBody, ValidatorResources, WasmFeatures}; /// Object containing the standalone environment information. pub struct ModuleEnvironment<'data> { /// The result to be filled in. result: ModuleTranslation<'data>, code_index: u32, + features: WasmFeatures, } /// The result of translating via `ModuleEnvironment`. Function bodies are not @@ -50,13 +52,11 @@ pub struct ModuleTranslation<'data> { } /// 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, } #[derive(Debug, Default)] @@ -102,7 +102,11 @@ pub struct FunctionMetadata { 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, @@ -118,6 +122,7 @@ impl<'data> ModuleEnvironment<'data> { }, }, code_index: 0, + features: *features, } } @@ -442,21 +447,15 @@ 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, - }); if let Some(info) = &mut self.result.debuginfo { let func_index = self.code_index + self.result.module.num_imported_funcs as u32; let func_index = FuncIndex::from_u32(func_index); let sig_index = self.result.module.functions[func_index]; let sig = &self.result.module.signatures[sig_index]; let mut locals = Vec::new(); - let body = wasmparser::FunctionBody::new(body_offset, body_bytes); for pair in body.get_locals_reader()? { locals.push(pair?); } @@ -465,6 +464,9 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data params: sig.0.params.iter().cloned().map(|i| i.into()).collect(), }); } + self.result + .function_body_inputs + .push(FunctionBodyData { validator, body }); self.code_index += 1; Ok(()) } @@ -564,6 +566,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/fuzzing/Cargo.toml b/crates/fuzzing/Cargo.toml index 1f33041c192f..d0aba47095a5 100644 --- a/crates/fuzzing/Cargo.toml +++ b/crates/fuzzing/Cargo.toml @@ -13,8 +13,8 @@ binaryen = { version = "0.10.0", optional = true } env_logger = "0.7.1" log = "0.4.8" rayon = "1.2.1" -wasmparser = "0.59.0" -wasmprinter = "0.2.6" +wasmparser = "0.62.0" +wasmprinter = "0.2.8" wasmtime = { path = "../wasmtime" } wasmtime-wast = { path = "../wast" } diff --git a/crates/fuzzing/src/generators/api.rs b/crates/fuzzing/src/generators/api.rs index db6474bf95c2..b27fcaee5966 100644 --- a/crates/fuzzing/src/generators/api.rs +++ b/crates/fuzzing/src/generators/api.rs @@ -219,7 +219,10 @@ fn predict_rss(wasm: &[u8]) -> Result { // the minimum amount of memory to our predicted rss. Payload::MemorySection(s) => { for entry in s { - let initial = entry?.limits.initial as usize; + let initial = match entry? { + MemoryType::M32 { limits, .. } => limits.initial as usize, + MemoryType::M64 { limits } => limits.initial as usize, + }; prediction += initial * 64 * 1024; } } diff --git a/crates/jit/Cargo.toml b/crates/jit/Cargo.toml index 53ba80494b40..4e812e093e96 100644 --- a/crates/jit/Cargo.toml +++ b/crates/jit/Cargo.toml @@ -28,7 +28,7 @@ rayon = { version = "1.0", optional = true } region = "2.1.0" thiserror = "1.0.4" target-lexicon = { version = "0.11.0", default-features = false } -wasmparser = "0.59.0" +wasmparser = "0.62.0" more-asserts = "0.2.1" anyhow = "1.0" cfg-if = "0.1.9" diff --git a/crates/jit/src/compiler.rs b/crates/jit/src/compiler.rs index 192b0abcc028..5487350894a4 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 object::write::Object; use std::hash::{Hash, Hasher}; +use std::mem; +use wasmparser::WasmFeatures; use wasmtime_debug::{emit_dwarf, DwarfSection}; use wasmtime_environ::entity::EntityRef; use wasmtime_environ::isa::{TargetFrontendConfig, TargetIsa}; @@ -40,11 +42,17 @@ pub struct Compiler { compiler: Box, strategy: CompilationStrategy, tunables: Tunables, + features: WasmFeatures, } impl Compiler { /// Construct a new `Compiler`. - pub fn new(isa: Box, strategy: CompilationStrategy, tunables: Tunables) -> Self { + pub fn new( + isa: Box, + strategy: CompilationStrategy, + tunables: Tunables, + features: WasmFeatures, + ) -> Self { Self { isa, strategy, @@ -56,6 +64,7 @@ impl Compiler { CompilationStrategy::Lightbeam => Box::new(wasmtime_lightbeam::Lightbeam), }, tunables, + features, } } } @@ -107,20 +116,26 @@ impl Compiler { &self.tunables } + /// Return the enabled wasm features. + pub fn features(&self) -> &WasmFeatures { + &self.features + } + /// Compile the given function bodies. pub fn compile<'data>( &self, - translation: &ModuleTranslation, + translation: &mut ModuleTranslation, ) -> Result { + let functions = mem::take(&mut translation.function_body_inputs); cfg_if::cfg_if! { if #[cfg(feature = "parallel-compilation")] { use rayon::prelude::*; - let iter = translation.function_body_inputs - .iter() + let iter = functions + .into_iter() .collect::>() .into_par_iter(); } else { - let iter = translation.function_body_inputs.iter(); + let iter = functions.into_iter(); } } let funcs = iter @@ -161,12 +176,14 @@ impl Hash for Compiler { compiler: _, isa, tunables, + features, } = self; // Hash compiler's flags: compilation strategy, isa, frontend config, // misc tunables. strategy.hash(hasher); isa.triple().hash(hasher); + features.hash(hasher); // TODO: if this `to_string()` is too expensive then we should upstream // a native hashing ability of flags into cranelift itself, but // compilation and/or cache loading is relatively expensive so seems diff --git a/crates/jit/src/instantiate.rs b/crates/jit/src/instantiate.rs index 71f81cb34266..3320fec25e44 100644 --- a/crates/jit/src/instantiate.rs +++ b/crates/jit/src/instantiate.rs @@ -82,9 +82,13 @@ struct FunctionInfo { 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)))?; @@ -92,7 +96,7 @@ impl CompilationArtifacts { obj, unwind_info, funcs, - } = compiler.compile(&translation)?; + } = compiler.compile(&mut translation)?; let ModuleTranslation { module, diff --git a/crates/lightbeam/Cargo.toml b/crates/lightbeam/Cargo.toml index 4f47ef4863b4..504c9d9622fd 100644 --- a/crates/lightbeam/Cargo.toml +++ b/crates/lightbeam/Cargo.toml @@ -24,7 +24,7 @@ smallvec = "1.0.0" staticvec = "0.10" thiserror = "1.0.9" typemap = "0.3" -wasmparser = "0.59.0" +wasmparser = "0.62.0" [dev-dependencies] lazy_static = "1.2" diff --git a/crates/lightbeam/src/microwasm.rs b/crates/lightbeam/src/microwasm.rs index 20b978700896..99b8b04a04cc 100644 --- a/crates/lightbeam/src/microwasm.rs +++ b/crates/lightbeam/src/microwasm.rs @@ -437,8 +437,9 @@ pub struct MemoryImmediate { impl From for MemoryImmediate { fn from(other: WasmMemoryImmediate) -> Self { + assert_eq!(other.memory, 0); MemoryImmediate { - flags: other.flags, + flags: other.align.into(), offset: other.offset, } } @@ -544,12 +545,8 @@ pub enum Operator