1use std::{rc::Rc, vec};
2
3use dfwasm_template::{split_templates, Args, Block, Item, Template};
4use wasmparser::{ConstExpr, MemoryType, Operator, Parser, RecGroup};
5
6use crate::{
7 df_helper::{format_df_number_u64, var, DF_VAR_MEM_SIZE},
8 DFWasmError, DFWasmResult,
9};
10
11use super::{
12 df_helper::{format_df_number_i64, num, DF_FUNC_CALL_FUNC},
13 sections::compile_section,
14};
15
16#[derive(Debug, Clone, PartialEq)]
18pub(crate) enum ControlStackEntry {
19 FunctionStart(usize),
20 Block(usize),
21 Loop(usize),
22 If(usize),
23 Else(usize),
24}
25
26#[derive(Default, Debug, Clone)]
28pub struct DFWasmCompilerOptions {
29 pub module_name: Option<String>,
31 pub debugger: bool,
33 pub skip_nop_debugger: bool,
35 pub max_template_size: Option<usize>,
38 pub batch_data_size: Option<usize>,
46 pub only_include_module_init: bool,
49}
50
51pub struct DFWasmCompiler<'a> {
53 pub wasm: &'a [u8],
55 pub options: DFWasmCompilerOptions,
57
58 pub(crate) templates: Vec<Template>,
60
61 pub(crate) memory_type: Option<MemoryType>,
63
64 pub(crate) start_method: Option<usize>,
66
67 pub(crate) control_stack: Vec<ControlStackEntry>,
69
70 pub(crate) table_to_init_expr: Vec<Item>,
72
73 pub(crate) function_counter: usize,
75
76 pub(crate) table_counter: usize,
78
79 pub(crate) function_to_type_signature: Vec<Rc<RecGroup>>,
81
82 pub(crate) function_signatures: Vec<Rc<RecGroup>>,
84}
85
86impl<'a> DFWasmCompiler<'a> {
87 pub fn compile_wasm(
89 wasm: &'a [u8],
90 options: DFWasmCompilerOptions,
91 ) -> DFWasmResult<Vec<Template>> {
92 let this = Self {
93 wasm,
94 options,
95 templates: Vec::new(),
96 memory_type: None,
97 start_method: None,
98 control_stack: Vec::new(),
99 table_to_init_expr: Vec::new(),
100 function_counter: 0,
101 table_counter: 0,
102 function_to_type_signature: Vec::new(),
103 function_signatures: Vec::new(),
104 };
105 this.compile()
106 }
107
108 fn compile(mut self) -> DFWasmResult<Vec<Template>> {
110 let parser = Parser::new(0);
112
113 let module_template_name = match &self.options.module_name {
115 Some(name) => format!("wasm.{}.init", name),
116 None => "wasm.module.init".to_string(),
117 };
118 let mut module_template = Template::start_function(module_template_name.clone());
119
120 for section in parser.parse_all(self.wasm) {
122 let section = section?;
123 compile_section(&mut self, &mut module_template, section)?;
124 }
125
126 if let Some(start_method) = self.start_method {
128 module_template.blocks.push(Block::CallFunction {
129 args: Args::with(vec![num(start_method), num(0), num(0)]),
130 func: DF_FUNC_CALL_FUNC.to_string(),
131 });
132 }
133
134 if let Some(memory_type) = self.memory_type {
136 module_template.set_var(
137 "=",
138 Args::with(vec![
139 var(DF_VAR_MEM_SIZE),
140 num(format_df_number_u64(memory_type.initial)),
141 ]),
142 );
143 }
144
145 if self.options.only_include_module_init {
146 self.templates.clear();
147 }
148
149 self.templates.push(module_template);
150
151 if let Some(max_template_size) = self.options.max_template_size {
153 Ok(split_templates(self.templates, max_template_size))
154 } else {
155 Ok(self.templates)
156 }
157 }
158
159 pub(crate) fn get_current_template_idx(&self) -> Option<usize> {
161 self.control_stack.last().map(|entry| match entry {
162 ControlStackEntry::FunctionStart(template_idx)
163 | ControlStackEntry::Block(template_idx)
164 | ControlStackEntry::Loop(template_idx)
165 | ControlStackEntry::If(template_idx)
166 | ControlStackEntry::Else(template_idx) => *template_idx,
167 })
168 }
169
170 pub(crate) fn get_current_template(&mut self) -> &mut Template {
172 let template_idx = self.get_current_template_idx().expect("No template");
173
174 self.templates
175 .get_mut(template_idx)
176 .expect("Template not found")
177 }
178
179 pub(crate) fn eval_const_expr(&self, expr: &ConstExpr) -> DFWasmResult<Item> {
183 let mut reader = expr.get_operators_reader();
184 let op = reader.read()?;
185
186 let result = match op {
187 Operator::I32Const { value } => num(format_df_number_i64(value as i64)),
188 Operator::I64Const { value } => num(format_df_number_i64(value)),
189 Operator::F32Const { value: _ } => todo!("float constant expressions"),
190 Operator::F64Const { value: _ } => todo!("float constant expressions"),
191 Operator::RefNull { hty: _ } => num(-1),
192 Operator::RefFunc { function_index } => num(function_index),
193 Operator::GlobalGet { global_index: _ } => todo!("global get within a const expr"),
194 _ => return Err(DFWasmError::UnsupportedConstExpr),
195 };
196
197 if reader.eof() {
198 Ok(result)
199 } else {
200 match reader.read()? {
201 Operator::End => Ok(result),
202 _ => Err(DFWasmError::UnsupportedConstExpr),
204 }
205 }
206 }
207
208 pub(crate) fn eval_const_expr_as_offset(&self, expr: &ConstExpr) -> DFWasmResult<usize> {
212 let mut reader = expr.get_operators_reader();
213 let op = reader.read()?;
214
215 let result = match op {
216 Operator::I32Const { value } => usize::from_le_bytes((value as i64).to_le_bytes()),
217 Operator::I64Const { value } => usize::from_le_bytes(value.to_le_bytes()),
218 Operator::GlobalGet { global_index: _ } => todo!("global get within a const expr"),
219 _ => return Err(DFWasmError::UnsupportedConstExpr),
220 };
221
222 if reader.eof() {
223 Ok(result)
224 } else {
225 match reader.read()? {
226 Operator::End => Ok(result),
227 _ => Err(DFWasmError::UnsupportedConstExpr),
229 }
230 }
231 }
232
233 pub(crate) fn arg_count_of_type(signature: &RecGroup) -> Option<usize> {
235 Some(signature.types().next()?.unwrap_func().params().len())
236 }
237
238 pub(crate) fn result_count_of_type(signature: &RecGroup) -> Option<usize> {
241 Some(signature.types().next()?.unwrap_func().results().len())
242 }
243}