1use crate::code_translator::{bitcast_wasm_returns, translate_operator};
8use crate::environ::FuncEnvironment;
9use crate::state::FuncTranslationState;
10use crate::translation_utils::get_vmctx_value_label;
11use crate::WasmResult;
12use cranelift_codegen::entity::EntityRef;
13use cranelift_codegen::ir::{self, Block, InstBuilder, ValueLabel};
14use cranelift_codegen::timing;
15use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
16use wasmparser::{BinaryReader, FuncValidator, FunctionBody, WasmModuleResources};
17
18pub struct FuncTranslator {
24 func_ctx: FunctionBuilderContext,
25 state: FuncTranslationState,
26}
27
28impl FuncTranslator {
29 pub fn new() -> Self {
31 Self {
32 func_ctx: FunctionBuilderContext::new(),
33 state: FuncTranslationState::new(),
34 }
35 }
36
37 pub fn context(&mut self) -> &mut FunctionBuilderContext {
40 &mut self.func_ctx
41 }
42
43 pub fn translate_body<FE: FuncEnvironment + ?Sized>(
54 &mut self,
55 validator: &mut FuncValidator<impl WasmModuleResources>,
56 body: FunctionBody<'_>,
57 func: &mut ir::Function,
58 environ: &mut FE,
59 ) -> WasmResult<()> {
60 let _tt = timing::wasm_translate_function();
61 let mut reader = body.get_binary_reader();
62 log::trace!(
63 "translate({} bytes, {}{})",
64 reader.bytes_remaining(),
65 func.name,
66 func.signature
67 );
68 debug_assert_eq!(func.dfg.num_blocks(), 0, "Function must be empty");
69 debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty");
70
71 let mut builder = FunctionBuilder::new(func, &mut self.func_ctx);
72 builder.set_srcloc(cur_srcloc(&reader));
73 let entry_block = builder.create_block();
74 builder.append_block_params_for_function_params(entry_block);
75 builder.switch_to_block(entry_block);
76 builder.seal_block(entry_block); builder.ensure_inserted_block();
81
82 let num_params = declare_wasm_parameters(&mut builder, entry_block, environ);
83
84 let exit_block = builder.create_block();
87 builder.append_block_params_for_function_returns(exit_block);
88 self.state.initialize(&builder.func.signature, exit_block);
89
90 parse_local_decls(&mut reader, &mut builder, num_params, environ, validator)?;
91 parse_function_body(validator, reader, &mut builder, &mut self.state, environ)?;
92
93 builder.finalize();
94 log::trace!("translated Wasm to CLIF:\n{}", func.display());
95 Ok(())
96 }
97}
98
99fn declare_wasm_parameters<FE: FuncEnvironment + ?Sized>(
103 builder: &mut FunctionBuilder,
104 entry_block: Block,
105 environ: &FE,
106) -> usize {
107 let sig_len = builder.func.signature.params.len();
108 let mut next_local = 0;
109 for i in 0..sig_len {
110 let param_type = builder.func.signature.params[i];
111 if environ.is_wasm_parameter(&builder.func.signature, i) {
114 let local = Variable::new(next_local);
116 builder.declare_var(local, param_type.value_type);
117 next_local += 1;
118
119 if environ.param_needs_stack_map(&builder.func.signature, i) {
120 builder.declare_var_needs_stack_map(local);
121 }
122
123 let param_value = builder.block_params(entry_block)[i];
124 builder.def_var(local, param_value);
125 }
126 if param_type.purpose == ir::ArgumentPurpose::VMContext {
127 let param_value = builder.block_params(entry_block)[i];
128 builder.set_val_label(param_value, get_vmctx_value_label());
129 }
130 }
131
132 next_local
133}
134
135fn parse_local_decls<FE: FuncEnvironment + ?Sized>(
139 reader: &mut BinaryReader,
140 builder: &mut FunctionBuilder,
141 num_params: usize,
142 environ: &mut FE,
143 validator: &mut FuncValidator<impl WasmModuleResources>,
144) -> WasmResult<()> {
145 let mut next_local = num_params;
146 let local_count = reader.read_var_u32()?;
147
148 for _ in 0..local_count {
149 builder.set_srcloc(cur_srcloc(reader));
150 let pos = reader.original_position();
151 let count = reader.read_var_u32()?;
152 let ty = reader.read()?;
153 validator.define_locals(pos, count, ty)?;
154 declare_locals(builder, count, ty, &mut next_local, environ)?;
155 }
156
157 environ.after_locals(next_local);
158
159 Ok(())
160}
161
162fn declare_locals<FE: FuncEnvironment + ?Sized>(
166 builder: &mut FunctionBuilder,
167 count: u32,
168 wasm_type: wasmparser::ValType,
169 next_local: &mut usize,
170 environ: &mut FE,
171) -> WasmResult<()> {
172 use wasmparser::ValType::*;
174 let (ty, init, needs_stack_map) = match wasm_type {
175 I32 => (
176 ir::types::I32,
177 Some(builder.ins().iconst(ir::types::I32, 0)),
178 false,
179 ),
180 I64 => (
181 ir::types::I64,
182 Some(builder.ins().iconst(ir::types::I64, 0)),
183 false,
184 ),
185 F32 => (
186 ir::types::F32,
187 Some(builder.ins().f32const(ir::immediates::Ieee32::with_bits(0))),
188 false,
189 ),
190 F64 => (
191 ir::types::F64,
192 Some(builder.ins().f64const(ir::immediates::Ieee64::with_bits(0))),
193 false,
194 ),
195 V128 => {
196 let constant_handle = builder.func.dfg.constants.insert([0; 16].to_vec().into());
197 (
198 ir::types::I8X16,
199 Some(builder.ins().vconst(ir::types::I8X16, constant_handle)),
200 false,
201 )
202 }
203 Ref(rt) => {
204 let hty = environ.convert_heap_type(rt.heap_type());
205 let (ty, needs_stack_map) = environ.reference_type(hty);
206 let init = if rt.is_nullable() {
207 Some(environ.translate_ref_null(builder.cursor(), hty)?)
208 } else {
209 None
210 };
211 (ty, init, needs_stack_map)
212 }
213 };
214
215 for _ in 0..count {
216 let local = Variable::new(*next_local);
217 builder.declare_var(local, ty);
218 if needs_stack_map {
219 builder.declare_var_needs_stack_map(local);
220 }
221 if let Some(init) = init {
222 builder.def_var(local, init);
223 builder.set_val_label(init, ValueLabel::new(*next_local));
224 }
225 *next_local += 1;
226 }
227 Ok(())
228}
229
230fn parse_function_body<FE: FuncEnvironment + ?Sized>(
235 validator: &mut FuncValidator<impl WasmModuleResources>,
236 mut reader: BinaryReader,
237 builder: &mut FunctionBuilder,
238 state: &mut FuncTranslationState,
239 environ: &mut FE,
240) -> WasmResult<()> {
241 debug_assert_eq!(state.control_stack.len(), 1, "State not initialized");
243
244 environ.before_translate_function(builder, state)?;
245 while !reader.eof() {
246 let pos = reader.original_position();
247 builder.set_srcloc(cur_srcloc(&reader));
248 let op = reader.read_operator()?;
249 validator.op(pos, &op)?;
250 environ.before_translate_operator(&op, builder, state)?;
251 translate_operator(validator, &op, builder, state, environ)?;
252 environ.after_translate_operator(&op, builder, state)?;
253 }
254 environ.after_translate_function(builder, state)?;
255 let pos = reader.original_position();
256 validator.finish(pos)?;
257
258 if state.reachable {
264 if !builder.is_unreachable() {
265 environ.handle_before_return(&state.stack, builder);
266 bitcast_wasm_returns(environ, &mut state.stack, builder);
267 builder.ins().return_(&state.stack);
268 }
269 }
270
271 state.stack.clear();
274
275 Ok(())
276}
277
278fn cur_srcloc(reader: &BinaryReader) -> ir::SourceLoc {
280 ir::SourceLoc::new(reader.original_position() as u32)
283}