From 64155896b6ca86ad963c3a71357561597302a465 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 14 Jul 2020 15:17:30 -0700 Subject: [PATCH 1/2] Validate modules while translating This commit is a change to cranelift-wasm to validate each function body as it is translated. Additionally top-level module translation functions will perform module validation. This commit builds on changes in wasmparser to perform module validation interwtwined with parsing and translation. This will be necessary for future wasm features such as module linking where the type behind a function index, for example, can be far away in another module. Additionally this also brings a nice benefit where parsing the binary only happens once (instead of having an up-front serial validation step) and validation can happen in parallel for each function. Most of the changes in this commit are plumbing to make sure everything lines up right. The major functional change here is that module compilation should be faster by validating in parallel (or skipping function validation entirely in the case of a cache hit). Otherwise from a user-facing perspective nothing should be that different. This commit does mean that cranelift's translation now inherently validates the input wasm module. This means that the Spidermonkey integration of cranelift-wasm will also be validating the function as it's being translated with cranelift. The associated PR for wasmparser (bytecodealliance/wasmparser#62) provides the necessary tools to create a `FuncValidator` for Gecko, but this is something I'll want careful review for before landing! --- Cargo.lock | 28 +- Cargo.toml | 1 + cranelift/wasm/Cargo.toml | 3 +- cranelift/wasm/src/code_translator.rs | 763 +++++++++------------- cranelift/wasm/src/environ/dummy.rs | 29 +- cranelift/wasm/src/environ/spec.rs | 16 +- cranelift/wasm/src/func_translator.rs | 172 +++-- cranelift/wasm/src/lib.rs | 5 + cranelift/wasm/src/module_translator.rs | 71 +- cranelift/wasm/src/sections_translator.rs | 30 +- cranelift/wasm/src/translation_utils.rs | 65 +- cranelift/wasm/tests/wasm_testsuite.rs | 12 +- cranelift/wasmtests/passive-data.wat | 1 + cranelift/wasmtests/ref-func-0.wat | 4 +- crates/cranelift/src/lib.rs | 22 +- crates/debug/Cargo.toml | 2 +- crates/environ/Cargo.toml | 2 +- crates/environ/src/compilation.rs | 2 +- crates/environ/src/module_environ.rs | 36 +- crates/fuzzing/Cargo.toml | 4 +- crates/fuzzing/src/generators/api.rs | 5 +- crates/jit/Cargo.toml | 2 +- crates/jit/src/compiler.rs | 27 +- crates/jit/src/instantiate.rs | 10 +- crates/lightbeam/Cargo.toml | 2 +- crates/lightbeam/src/microwasm.rs | 20 +- crates/lightbeam/src/module.rs | 17 +- crates/lightbeam/wasmtime/Cargo.toml | 2 +- crates/lightbeam/wasmtime/src/lib.rs | 4 +- crates/wasmtime/Cargo.toml | 2 +- crates/wasmtime/src/instance.rs | 2 +- crates/wasmtime/src/module.rs | 83 +-- crates/wasmtime/src/runtime.rs | 46 +- src/obj.rs | 10 +- 34 files changed, 711 insertions(+), 789 deletions(-) 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..a328fe33ec5b 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, @@ -229,12 +227,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. @@ -277,26 +279,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 +312,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 +329,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 +351,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 +368,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 +395,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