1use std::mem::take;
2
3use anyhow::Context;
4use trie_rs::map::{Trie, TrieBuilder};
5use waffle::{
6 util::new_sig, Block, BlockTarget, ExportKind, Func, FuncDecl, FunctionBody, ImportKind,
7 MemoryArg, Module, Operator, Signature, SignatureData, Type, Value,
8};
9use waffle_ast::{add_op, Builder};
10
11pub fn internal_trie(m: &Module) -> Trie<u8, Func> {
12 let mut b = TrieBuilder::new();
13 for f in m.funcs.iter() {
14 b.push(m.funcs[f].name().as_bytes(), f);
15 }
16 return b.build();
17}
18pub fn export_trie(m: &Module) -> Trie<u8, Func> {
19 let mut b = TrieBuilder::new();
20 for f in m.exports.iter() {
21 let ExportKind::Func(func) = &f.kind else {
22 continue;
23 };
24 b.push(f.name.as_bytes(), *func);
25 }
26 return b.build();
27}
28pub fn tx<T>(
29 m: &mut Module,
30 t: &Trie<u8, T>,
31 x: &[u8],
32 f: &mut FunctionBody,
33 k: Block,
34 v: Value,
35 s: &mut impl FnMut(&T, &mut Module) -> bool,
36 go: &mut impl FnMut(&T, &mut FunctionBody, &mut Module, Block) -> anyhow::Result<()>,
37) -> anyhow::Result<()> {
38 if let Some(0) = x.last() {
39 if let Some(x) = t.exact_match(&x[..(x.len() - 2)]) {
40 if s(x, m) {
41 return go(x, f, m, k);
42 }
43 return Ok(());
44 }
45 }
46 let p = t
47 .postfix_search::<Vec<_>, _>(x)
48 .filter(|a| s(a.1, m))
49 .map(|_| ())
50 .collect::<Vec<_>>()
51 .len();
52 if p == 0 {
53 return Ok(());
54 }
55 let ty = f.values[v]
56 .ty(&f.type_pool)
57 .context("in getting the type")?;
58 let mem = m
59 .exports
60 .iter()
61 .find_map(|x| {
62 if x.name == "memory" {
63 match &x.kind {
64 waffle::ExportKind::Memory(m) => Some(*m),
65 _ => None,
66 }
67 } else {
68 None
69 }
70 })
71 .context("in getting the main memory")?;
72 let a = add_op(
73 f,
74 &[v],
75 &[ty.clone()],
76 Operator::I32Load8U {
77 memory: MemoryArg {
78 memory: mem,
79 align: 0,
80 offset: x.len() as u64,
81 },
82 },
83 );
84 f.append_to_block(k, a);
85 let xs = 0..=255;
86 let xs = xs.map(|i| {
87 let mut x = x.to_vec();
88 x.push(i);
89 let b = f.add_block();
90 tx(m, t, &x, f, b, v, s, go)?;
91 anyhow::Ok(BlockTarget {
92 block: b,
93 args: vec![],
94 })
95 });
96 let xs = xs.collect::<anyhow::Result<Vec<_>>>()?;
97 let xa = xs[0].clone();
98 f.set_terminator(
99 k,
100 waffle::Terminator::Select {
101 value: a,
102 targets: xs,
103 default: xa,
104 },
105 );
106 Ok(())
107}
108pub fn emit(m: &mut Module) -> anyhow::Result<()> {
109 let t_internal = internal_trie(&m);
110 let t_export = export_trie(&m);
111 for i in take(&mut m.imports) {
112 if let Some(a) = i.module.strip_prefix("dyn_call") {
113 let t = match a {
114 "func" => &t_internal,
115 "export" => &t_export,
116 _ => {
117 m.imports.push(i);
118 continue;
119 }
120 };
121 if let ImportKind::Func(f) = i.kind {
122 let s = m.signatures[m.funcs[f].sig()].clone();
123 let SignatureData::Func { params, returns } = s else{
124 anyhow::bail!("not a func")
125 };
126 let s = new_sig(
127 m,
128 SignatureData::Func {
129 returns: returns,
130 params: params[1..].iter().cloned().collect(),
131 },
132 );
133 let os = m.funcs[f].sig();
134 let n = m.funcs[f].name().to_owned();
135 let mut body = FunctionBody::new(&m, os);
136 let e = body.entry;
137 let mut p = body.blocks[e].params.iter();
138 let pv = p.next().context("in getting the first param")?.1;
139 let ps = p.map(|a| a.1).collect::<Vec<_>>();
140 tx(
141 m,
142 &*t,
143 &[],
144 &mut body,
145 e,
146 pv,
147 &mut |a,m| m.funcs[*a].sig() == s,
148 &mut |f, b, m, k| {
149 b.set_terminator(
150 k,
151 waffle::Terminator::ReturnCall {
152 func: *f,
153 args: ps.clone(),
154 },
155 );
156 Ok(())
157 },
158 )?;
159 m.funcs[f] = FuncDecl::Body(os, n, body);
160 continue;
161 }
162 }
163 m.imports.push(i)
164 }
165 Ok(())
166}