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;
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct Wasm {
|
|
|
|
operators: Vec<wasm_encoder::Instruction<'static>>,
|
|
|
|
locals: Vec<wasm_encoder::ValType>,
|
|
|
|
func_types: Vec<(Vec<wasm_encoder::ValType>, Vec<wasm_encoder::ValType>)>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Wasm {
|
|
|
|
fn create_type(
|
|
|
|
&mut self,
|
|
|
|
params: Vec<wasm_encoder::ValType>,
|
|
|
|
results: Vec<wasm_encoder::ValType>,
|
|
|
|
) -> u32 {
|
|
|
|
let idx = self.func_types.len() as u32;
|
|
|
|
self.func_types.push((params, results));
|
|
|
|
idx
|
|
|
|
}
|
|
|
|
fn translate(&mut self, op: &SerializedOperator, locations: &Locations) {
|
|
|
|
match op {
|
|
|
|
SerializedOperator::StartBlock {
|
|
|
|
ref params,
|
|
|
|
ref results,
|
|
|
|
..
|
|
|
|
} => {
|
|
|
|
let ty = self.create_type(
|
|
|
|
params.iter().map(|(ty, _)| ty_to_valty(*ty)).collect(),
|
|
|
|
results.iter().map(|ty| ty_to_valty(*ty)).collect(),
|
|
|
|
);
|
|
|
|
self.operators
|
|
|
|
.push(wasm_encoder::Instruction::Block(BlockType::FunctionType(
|
|
|
|
ty,
|
|
|
|
)));
|
|
|
|
}
|
|
|
|
SerializedOperator::StartLoop {
|
|
|
|
ref params,
|
|
|
|
ref results,
|
|
|
|
..
|
|
|
|
} => {
|
|
|
|
let ty = self.create_type(
|
|
|
|
params.iter().map(|(ty, _)| ty_to_valty(*ty)).collect(),
|
|
|
|
results.iter().map(|ty| ty_to_valty(*ty)).collect(),
|
|
|
|
);
|
|
|
|
self.operators
|
|
|
|
.push(wasm_encoder::Instruction::Loop(BlockType::FunctionType(ty)));
|
|
|
|
}
|
|
|
|
SerializedOperator::End => {
|
|
|
|
self.operators.push(wasm_encoder::Instruction::End);
|
|
|
|
}
|
|
|
|
SerializedOperator::GetArg(index) => {
|
|
|
|
self.operators
|
|
|
|
.push(wasm_encoder::Instruction::LocalGet(*index as u32));
|
|
|
|
}
|
|
|
|
SerializedOperator::Operator(op) => {
|
|
|
|
self.operators.push(op.clone().into());
|
|
|
|
}
|
|
|
|
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 {
|
|
|
|
cond,
|
|
|
|
ref if_true,
|
|
|
|
ref if_false,
|
|
|
|
} => {
|
2021-12-24 02:28:44 -06:00
|
|
|
let loc = *locations.locations.get(&(*cond, 0)).unwrap();
|
|
|
|
self.operators
|
|
|
|
.push(wasm_encoder::Instruction::LocalGet(loc));
|
|
|
|
self.operators.push(wasm_encoder::Instruction::If(
|
|
|
|
wasm_encoder::BlockType::Empty,
|
|
|
|
));
|
|
|
|
self.translate_target(1, if_true, locations);
|
|
|
|
self.operators.push(wasm_encoder::Instruction::Else);
|
|
|
|
self.translate_target(1, if_false, locations);
|
|
|
|
self.operators.push(wasm_encoder::Instruction::End);
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
|
|
|
SerializedOperator::BrTable {
|
|
|
|
index,
|
|
|
|
ref targets,
|
|
|
|
ref default,
|
|
|
|
} => {
|
2021-12-24 02:28:44 -06:00
|
|
|
for _ in 0..(targets.len() + 2) {
|
|
|
|
self.operators.push(wasm_encoder::Instruction::Block(
|
|
|
|
wasm_encoder::BlockType::Empty,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
let loc = *locations.locations.get(&(*index, 0)).unwrap();
|
|
|
|
self.operators
|
|
|
|
.push(wasm_encoder::Instruction::LocalGet(loc));
|
|
|
|
let br_table_targets = (1..=targets.len()).map(|i| i as u32).collect::<Vec<_>>();
|
|
|
|
self.operators.push(wasm_encoder::Instruction::BrTable(
|
|
|
|
Cow::Owned(br_table_targets),
|
|
|
|
0,
|
|
|
|
));
|
|
|
|
self.operators.push(wasm_encoder::Instruction::End);
|
|
|
|
|
|
|
|
self.translate_target(targets.len() + 1, default, locations);
|
|
|
|
self.operators.push(wasm_encoder::Instruction::End);
|
|
|
|
|
|
|
|
for i in 0..targets.len() {
|
|
|
|
self.translate_target(targets.len() - i, &targets[i], locations);
|
|
|
|
self.operators.push(wasm_encoder::Instruction::End);
|
|
|
|
}
|
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();
|
|
|
|
self.operators
|
|
|
|
.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();
|
|
|
|
self.operators
|
|
|
|
.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();
|
|
|
|
self.operators
|
|
|
|
.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);
|
|
|
|
}
|
|
|
|
self.operators.push(wasm_encoder::Instruction::Br(
|
|
|
|
(branch + extra_blocks) as u32,
|
|
|
|
));
|
2021-12-24 02:07:45 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-24 02:28:44 -06:00
|
|
|
pub fn produce_func_wasm(f: &FunctionBody, body: &SerializedBody, locations: &Locations) -> Wasm {
|
2021-12-24 02:07:45 -06:00
|
|
|
let mut wasm = Wasm {
|
|
|
|
operators: vec![],
|
|
|
|
locals: vec![],
|
|
|
|
func_types: 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)));
|
|
|
|
|
|
|
|
let mut next_delete = 0;
|
|
|
|
for (index, operator) in body.operators.iter().enumerate() {
|
|
|
|
if next_delete < locations.delete.len() && locations.delete[next_delete] == index {
|
|
|
|
next_delete += 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
wasm.translate(operator, locations);
|
|
|
|
}
|
|
|
|
|
|
|
|
wasm
|
|
|
|
}
|