2021-12-24 02:07:45 -06:00
|
|
|
//! Final Wasm operator sequence production.
|
|
|
|
|
2021-12-24 02:28:44 -06:00
|
|
|
use super::{Locations, SerializedBlockTarget, SerializedBody, SerializedOperator};
|
|
|
|
use crate::{ops::ty_to_valty, FunctionBody};
|
|
|
|
use std::borrow::Cow;
|
2021-12-24 02:07:45 -06:00
|
|
|
use wasm_encoder::BlockType;
|
2021-12-24 15:00:21 -06:00
|
|
|
use wasmparser::Type;
|
2021-12-24 02:07:45 -06:00
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct Wasm {
|
2021-12-24 15:00:21 -06:00
|
|
|
pub operators: Vec<wasm_encoder::Instruction<'static>>,
|
|
|
|
pub locals: Vec<wasm_encoder::ValType>,
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
|
|
|
|
2021-12-24 15:00:21 -06:00
|
|
|
struct WasmContext<'a, FT: FuncTypeSink> {
|
|
|
|
wasm: &'a mut Wasm,
|
|
|
|
func_type_sink: &'a mut FT,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait FuncTypeSink {
|
|
|
|
fn add_signature(&mut self, params: Vec<Type>, results: Vec<Type>) -> u32;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> {
|
|
|
|
fn create_type(&mut self, params: Vec<Type>, results: Vec<Type>) -> u32 {
|
|
|
|
self.func_type_sink.add_signature(params, results)
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
2021-12-24 15:00:21 -06:00
|
|
|
|
2021-12-24 02:07:45 -06:00
|
|
|
fn translate(&mut self, op: &SerializedOperator, locations: &Locations) {
|
|
|
|
match op {
|
|
|
|
SerializedOperator::StartBlock {
|
|
|
|
ref params,
|
|
|
|
ref results,
|
|
|
|
..
|
|
|
|
} => {
|
2021-12-24 15:00:21 -06:00
|
|
|
let ty =
|
|
|
|
self.create_type(params.iter().map(|&(ty, _)| ty).collect(), results.clone());
|
|
|
|
self.wasm.operators.push(wasm_encoder::Instruction::Block(
|
|
|
|
BlockType::FunctionType(ty),
|
|
|
|
));
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
|
|
|
SerializedOperator::StartLoop {
|
|
|
|
ref params,
|
|
|
|
ref results,
|
|
|
|
..
|
|
|
|
} => {
|
2021-12-24 15:00:21 -06:00
|
|
|
let ty =
|
|
|
|
self.create_type(params.iter().map(|&(ty, _)| ty).collect(), results.clone());
|
|
|
|
self.wasm
|
|
|
|
.operators
|
2021-12-24 02:07:45 -06:00
|
|
|
.push(wasm_encoder::Instruction::Loop(BlockType::FunctionType(ty)));
|
|
|
|
}
|
|
|
|
SerializedOperator::End => {
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm.operators.push(wasm_encoder::Instruction::End);
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
|
|
|
SerializedOperator::GetArg(index) => {
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm
|
|
|
|
.operators
|
2021-12-24 02:07:45 -06:00
|
|
|
.push(wasm_encoder::Instruction::LocalGet(*index as u32));
|
|
|
|
}
|
|
|
|
SerializedOperator::Operator(op) => {
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm.operators.push(op.clone().into());
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
|
|
|
SerializedOperator::Br(ref target) => {
|
2021-12-24 02:28:44 -06:00
|
|
|
self.translate_target(0, target, locations);
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
|
|
|
SerializedOperator::BrIf {
|
|
|
|
ref if_true,
|
|
|
|
ref if_false,
|
|
|
|
} => {
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm.operators.push(wasm_encoder::Instruction::If(
|
2021-12-24 02:28:44 -06:00
|
|
|
wasm_encoder::BlockType::Empty,
|
|
|
|
));
|
|
|
|
self.translate_target(1, if_true, locations);
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm.operators.push(wasm_encoder::Instruction::Else);
|
2021-12-24 02:28:44 -06:00
|
|
|
self.translate_target(1, if_false, locations);
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm.operators.push(wasm_encoder::Instruction::End);
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
|
|
|
SerializedOperator::BrTable {
|
|
|
|
ref targets,
|
|
|
|
ref default,
|
|
|
|
} => {
|
2021-12-24 15:00:21 -06:00
|
|
|
let ty = self.create_type(vec![Type::I32], vec![]);
|
2021-12-24 02:28:44 -06:00
|
|
|
for _ in 0..(targets.len() + 2) {
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm.operators.push(wasm_encoder::Instruction::Block(
|
2021-12-24 02:35:18 -06:00
|
|
|
wasm_encoder::BlockType::FunctionType(ty),
|
2021-12-24 02:28:44 -06:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
let br_table_targets = (1..=targets.len()).map(|i| i as u32).collect::<Vec<_>>();
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm.operators.push(wasm_encoder::Instruction::BrTable(
|
2021-12-24 02:28:44 -06:00
|
|
|
Cow::Owned(br_table_targets),
|
|
|
|
0,
|
|
|
|
));
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm.operators.push(wasm_encoder::Instruction::End);
|
2021-12-24 02:28:44 -06:00
|
|
|
|
|
|
|
self.translate_target(targets.len() + 1, default, locations);
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm.operators.push(wasm_encoder::Instruction::End);
|
2021-12-24 02:28:44 -06:00
|
|
|
|
|
|
|
for i in 0..targets.len() {
|
|
|
|
self.translate_target(targets.len() - i, &targets[i], locations);
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm.operators.push(wasm_encoder::Instruction::End);
|
2021-12-24 02:28:44 -06:00
|
|
|
}
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
|
|
|
SerializedOperator::Get(v, i) => {
|
2021-12-24 02:28:44 -06:00
|
|
|
let loc = *locations.locations.get(&(*v, *i)).unwrap();
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm
|
|
|
|
.operators
|
2021-12-24 02:28:44 -06:00
|
|
|
.push(wasm_encoder::Instruction::LocalGet(loc));
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
|
|
|
SerializedOperator::Set(v, i) => {
|
2021-12-24 02:28:44 -06:00
|
|
|
let loc = *locations.locations.get(&(*v, *i)).unwrap();
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm
|
|
|
|
.operators
|
2021-12-24 02:28:44 -06:00
|
|
|
.push(wasm_encoder::Instruction::LocalSet(loc));
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
|
|
|
SerializedOperator::Tee(v, i) => {
|
2021-12-24 02:28:44 -06:00
|
|
|
let loc = *locations.locations.get(&(*v, *i)).unwrap();
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm
|
|
|
|
.operators
|
2021-12-24 02:28:44 -06:00
|
|
|
.push(wasm_encoder::Instruction::LocalTee(loc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn translate_target(
|
|
|
|
&mut self,
|
|
|
|
extra_blocks: usize,
|
|
|
|
target: &SerializedBlockTarget,
|
|
|
|
locations: &Locations,
|
|
|
|
) {
|
|
|
|
match target {
|
|
|
|
&SerializedBlockTarget::Fallthrough(ref ops) => {
|
|
|
|
for op in ops {
|
|
|
|
self.translate(op, locations);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
&SerializedBlockTarget::Branch(branch, ref ops) => {
|
|
|
|
for op in ops {
|
|
|
|
self.translate(op, locations);
|
|
|
|
}
|
2021-12-24 15:00:21 -06:00
|
|
|
self.wasm.operators.push(wasm_encoder::Instruction::Br(
|
2021-12-24 02:28:44 -06:00
|
|
|
(branch + extra_blocks) as u32,
|
|
|
|
));
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-24 15:00:21 -06:00
|
|
|
pub fn produce_func_wasm<FT: FuncTypeSink>(
|
|
|
|
f: &FunctionBody,
|
|
|
|
body: &SerializedBody,
|
|
|
|
locations: &Locations,
|
|
|
|
ft: &mut FT,
|
|
|
|
) -> Wasm {
|
2021-12-24 02:07:45 -06:00
|
|
|
let mut wasm = Wasm {
|
|
|
|
operators: vec![],
|
|
|
|
locals: vec![],
|
|
|
|
};
|
|
|
|
wasm.locals
|
|
|
|
.extend(f.locals.iter().map(|ty| ty_to_valty(*ty)));
|
|
|
|
wasm.locals
|
|
|
|
.extend(locations.new_locals.iter().map(|ty| ty_to_valty(*ty)));
|
|
|
|
|
2021-12-24 15:00:21 -06:00
|
|
|
let mut ctx = WasmContext {
|
|
|
|
wasm: &mut wasm,
|
|
|
|
func_type_sink: ft,
|
|
|
|
};
|
2021-12-24 13:42:02 -06:00
|
|
|
for operator in &body.operators {
|
2021-12-24 15:00:21 -06:00
|
|
|
ctx.translate(operator, locations);
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
2021-12-24 16:29:32 -06:00
|
|
|
wasm.operators.push(wasm_encoder::Instruction::End);
|
2021-12-24 02:07:45 -06:00
|
|
|
|
|
|
|
wasm
|
|
|
|
}
|