winch: Prepare for an update to the wasm-tools crates (#5238)

This commit prepares the `winch` crate for updating `wasm-tools`,
notably changing a bit about how the visitation of operators works. This
moves the function body and wasm validator out of the `CodeGen`
structure and into parameters threaded into the emission of the actual
function.

Additionally the `VisitOperator` implementation was updated to remove
the explicit calls to the validator, favoring instead a macro-generated
solution to guarantee that all validation happens before any translation
proceeds. This means that the `VisitOperator for CodeGen` impl is now
infallible and the various methods have been inlined into the trait
methods as well as removing the `Result<_>`.

Finally this commit updates translation to call `validator.finish(..)`
which is required to perform the final validation steps of the function
body.
This commit is contained in:
Alex Crichton
2022-11-10 14:01:42 -06:00
committed by GitHub
parent 1f09954fa4
commit 3b9668558f
7 changed files with 91 additions and 105 deletions

View File

@@ -7,7 +7,6 @@
use crate::codegen::CodeGen;
use crate::masm::{MacroAssembler, OperandSize, RegImm};
use crate::stack::Val;
use anyhow::Result;
use wasmparser::ValType;
use wasmparser::VisitOperator;
@@ -15,23 +14,6 @@ impl<'a, M> CodeGen<'a, M>
where
M: MacroAssembler,
{
fn emit_i32_add(&mut self) -> Result<()> {
let is_const = self
.context
.stack
.peek()
.expect("value at stack top")
.is_i32_const();
if is_const {
self.add_imm_i32();
} else {
self.add_i32();
}
Ok(())
}
fn add_imm_i32(&mut self) {
let val = self
.context
@@ -65,41 +47,6 @@ where
self.regalloc.free_gpr(src);
self.context.stack.push(Val::reg(dst));
}
fn emit_i32_const(&mut self, val: i32) -> Result<()> {
self.context.stack.push(Val::i32(val));
Ok(())
}
fn emit_local_get(&mut self, index: u32) -> Result<()> {
let context = &mut self.context;
let slot = context
.frame
.get_local(index)
.expect(&format!("valid local at slot = {}", index));
match slot.ty {
ValType::I32 | ValType::I64 => context.stack.push(Val::local(index)),
_ => panic!("Unsupported type {:?} for local", slot.ty),
}
Ok(())
}
// TODO verify the case where the target local is on the stack.
fn emit_local_set(&mut self, index: u32) -> Result<()> {
let context = &mut self.context;
let frame = context.frame;
let slot = frame
.get_local(index)
.expect(&format!("vald local at slot = {}", index));
let size: OperandSize = slot.ty.into();
let src = self.regalloc.pop_to_reg(context, size);
let addr = context.masm.local_address(&slot);
context.masm.store(RegImm::reg(src), addr, size);
self.regalloc.free_gpr(src);
Ok(())
}
}
/// A macro to define unsupported WebAssembly operators.
@@ -136,30 +83,53 @@ impl<'a, M> VisitOperator<'a> for CodeGen<'a, M>
where
M: MacroAssembler,
{
type Output = Result<()>;
type Output = ();
fn visit_i32_const(&mut self, offset: usize, value: i32) -> Result<()> {
self.validator.visit_i32_const(offset, value)?;
self.emit_i32_const(value)
fn visit_i32_const(&mut self, _offset: usize, val: i32) {
self.context.stack.push(Val::i32(val));
}
fn visit_i32_add(&mut self, offset: usize) -> Result<()> {
self.validator.visit_i32_add(offset)?;
self.emit_i32_add()
fn visit_i32_add(&mut self, _offset: usize) {
let is_const = self
.context
.stack
.peek()
.expect("value at stack top")
.is_i32_const();
if is_const {
self.add_imm_i32();
} else {
self.add_i32();
}
}
fn visit_end(&mut self, offset: usize) -> Result<()> {
self.validator.visit_end(offset).map_err(|e| e.into())
fn visit_end(&mut self, _offset: usize) {}
fn visit_local_get(&mut self, _offset: usize, index: u32) {
let context = &mut self.context;
let slot = context
.frame
.get_local(index)
.expect(&format!("valid local at slot = {}", index));
match slot.ty {
ValType::I32 | ValType::I64 => context.stack.push(Val::local(index)),
_ => panic!("Unsupported type {:?} for local", slot.ty),
}
}
fn visit_local_get(&mut self, offset: usize, local_index: u32) -> Result<()> {
self.validator.visit_local_get(offset, local_index)?;
self.emit_local_get(local_index)
}
fn visit_local_set(&mut self, offset: usize, local_index: u32) -> Result<()> {
self.validator.visit_local_set(offset, local_index)?;
self.emit_local_set(local_index)
// TODO verify the case where the target local is on the stack.
fn visit_local_set(&mut self, _offset: usize, index: u32) {
let context = &mut self.context;
let frame = context.frame;
let slot = frame
.get_local(index)
.expect(&format!("vald local at slot = {}", index));
let size: OperandSize = slot.ty.into();
let src = self.regalloc.pop_to_reg(context, size);
let addr = context.masm.local_address(&slot);
context.masm.store(RegImm::reg(src), addr, size);
self.regalloc.free_gpr(src);
}
wasmparser::for_each_operator!(def_unsupported);