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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user