wasmtime_internal_cranelift/translate/
func_translator.rs1use crate::func_environ::FuncEnvironment;
8use crate::translate::TargetEnvironment;
9use crate::translate::code_translator::{bitcast_wasm_returns, translate_operator};
10use crate::translate::translation_utils::get_vmctx_value_label;
11use cranelift_codegen::entity::EntityRef;
12use cranelift_codegen::ir::{self, Block, InstBuilder, ValueLabel};
13use cranelift_codegen::timing;
14use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
15use wasmparser::{BinaryReader, FuncValidator, FunctionBody, OperatorsReader, WasmModuleResources};
16use wasmtime_environ::{TypeConvert, WasmResult};
17
18pub struct FuncTranslator {
24 func_ctx: FunctionBuilderContext,
25}
26
27impl FuncTranslator {
28 pub fn new() -> Self {
30 Self {
31 func_ctx: FunctionBuilderContext::new(),
32 }
33 }
34
35 pub fn context(&mut self) -> &mut FunctionBuilderContext {
38 &mut self.func_ctx
39 }
40
41 pub fn translate_body(
52 &mut self,
53 validator: &mut FuncValidator<impl WasmModuleResources>,
54 body: FunctionBody<'_>,
55 func: &mut ir::Function,
56 environ: &mut FuncEnvironment<'_>,
57 ) -> WasmResult<()> {
58 let _tt = timing::wasm_translate_function();
59 let mut reader = body.get_binary_reader();
60 log::trace!(
61 "translate({} bytes, {}{})",
62 reader.bytes_remaining(),
63 func.name,
64 func.signature
65 );
66 debug_assert_eq!(func.dfg.num_blocks(), 0, "Function must be empty");
67 debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty");
68
69 let mut builder = FunctionBuilder::new(func, &mut self.func_ctx);
70 builder.set_srcloc(cur_srcloc(&reader));
71 let entry_block = builder.create_block();
72 builder.append_block_params_for_function_params(entry_block);
73 builder.switch_to_block(entry_block);
74 builder.seal_block(entry_block); environ.create_state_slot(&mut builder);
77
78 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 environ
89 .stacks
90 .initialize(&builder.func.signature, exit_block);
91
92 parse_local_decls(&mut reader, &mut builder, num_params, environ, validator)?;
93 parse_function_body(validator, reader, &mut builder, environ)?;
94
95 builder.finalize();
96 log::trace!("translated Wasm to CLIF:\n{}", func.display());
97 Ok(())
98 }
99}
100
101fn declare_wasm_parameters(
105 builder: &mut FunctionBuilder,
106 entry_block: Block,
107 environ: &mut FuncEnvironment<'_>,
108) -> usize {
109 let sig_len = builder.func.signature.params.len();
110 let mut next_local = 0;
111 for i in 0..sig_len {
112 let param_type = builder.func.signature.params[i];
113 if let Some(wasm_type) = environ.clif_param_as_wasm_param(i) {
116 let local = builder.declare_var(param_type.value_type);
118 debug_assert_eq!(local.index(), next_local);
119 next_local += 1;
120
121 if environ.param_needs_stack_map(&builder.func.signature, i) {
122 builder.declare_var_needs_stack_map(local);
123 }
124
125 let param_value = builder.block_params(entry_block)[i];
126 builder.def_var(local, param_value);
127
128 environ.add_state_slot_local(builder, wasm_type, Some(param_value));
129 }
130 if param_type.purpose == ir::ArgumentPurpose::VMContext {
131 let param_value = builder.block_params(entry_block)[i];
132 builder.set_val_label(param_value, get_vmctx_value_label());
133 }
134 }
135
136 next_local
137}
138
139fn parse_local_decls(
143 reader: &mut BinaryReader,
144 builder: &mut FunctionBuilder,
145 num_params: usize,
146 environ: &mut FuncEnvironment<'_>,
147 validator: &mut FuncValidator<impl WasmModuleResources>,
148) -> WasmResult<()> {
149 let mut next_local = num_params;
150 let local_count = reader.read_var_u32()?;
151
152 for _ in 0..local_count {
153 builder.set_srcloc(cur_srcloc(reader));
154 let pos = reader.original_position();
155 let count = reader.read_var_u32()?;
156 let ty = reader.read()?;
157 validator.define_locals(pos, count, ty)?;
158 declare_locals(builder, count, ty, &mut next_local, environ)?;
159 }
160
161 Ok(())
162}
163
164fn declare_locals(
168 builder: &mut FunctionBuilder,
169 count: u32,
170 wasm_type: wasmparser::ValType,
171 next_local: &mut usize,
172 environ: &mut FuncEnvironment<'_>,
173) -> WasmResult<()> {
174 use wasmparser::ValType::*;
176 let (ty, init, needs_stack_map) = match wasm_type {
177 I32 => (
178 ir::types::I32,
179 Some(builder.ins().iconst(ir::types::I32, 0)),
180 false,
181 ),
182 I64 => (
183 ir::types::I64,
184 Some(builder.ins().iconst(ir::types::I64, 0)),
185 false,
186 ),
187 F32 => (
188 ir::types::F32,
189 Some(builder.ins().f32const(ir::immediates::Ieee32::with_bits(0))),
190 false,
191 ),
192 F64 => (
193 ir::types::F64,
194 Some(builder.ins().f64const(ir::immediates::Ieee64::with_bits(0))),
195 false,
196 ),
197 V128 => {
198 let constant_handle = builder.func.dfg.constants.insert([0; 16].to_vec().into());
199 (
200 ir::types::I8X16,
201 Some(builder.ins().vconst(ir::types::I8X16, constant_handle)),
202 false,
203 )
204 }
205 Ref(rt) => {
206 let hty = environ.convert_heap_type(rt.heap_type())?;
207 let (ty, needs_stack_map) = environ.reference_type(hty);
208 let init = if rt.is_nullable() {
209 Some(environ.translate_ref_null(builder.cursor(), hty)?)
210 } else {
211 None
212 };
213 (ty, init, needs_stack_map)
214 }
215 };
216
217 for _ in 0..count {
218 let local = builder.declare_var(ty);
219 debug_assert_eq!(local.index(), *next_local);
220 if needs_stack_map {
221 builder.declare_var_needs_stack_map(local);
222 }
223 if let Some(init) = init {
224 builder.def_var(local, init);
225 builder.set_val_label(init, ValueLabel::new(*next_local));
226 }
227 environ.add_state_slot_local(builder, environ.convert_valtype(wasm_type)?, init);
228 *next_local += 1;
229 }
230 Ok(())
231}
232
233fn parse_function_body(
238 validator: &mut FuncValidator<impl WasmModuleResources>,
239 reader: BinaryReader,
240 builder: &mut FunctionBuilder,
241 environ: &mut FuncEnvironment<'_>,
242) -> WasmResult<()> {
243 debug_assert_eq!(
245 environ.stacks.control_stack.len(),
246 1,
247 "State not initialized"
248 );
249
250 environ.before_translate_function(builder)?;
251
252 let mut reader = OperatorsReader::new(reader);
253 let mut operand_types = vec![];
254
255 while !reader.eof() {
256 let pos = reader.original_position();
257 builder.set_srcloc(cur_srcloc(&reader.get_binary_reader()));
258
259 let op = reader.read()?;
260 environ.next_srcloc = cur_srcloc(&reader.get_binary_reader());
261 let operand_types =
262 validate_op_and_get_operand_types(validator, environ, &mut operand_types, &op, pos)?;
263
264 environ.before_translate_operator(&op, operand_types, builder)?;
265 translate_operator(validator, &op, operand_types, builder, environ)?;
266 environ.after_translate_operator(&op, validator, builder)?;
267 }
268
269 environ.after_translate_function(builder)?;
270 reader.finish()?;
271
272 if environ.is_reachable() {
278 if !builder.is_unreachable() {
279 let mut returns = core::mem::take(&mut environ.stacks.stack);
280 environ.handle_before_return(&returns, builder);
281 bitcast_wasm_returns(&mut returns, builder);
282 builder.ins().return_(&returns);
283 }
284 }
285
286 environ.stacks.stack.clear();
289 environ.stacks.stack_shape.clear();
290
291 Ok(())
292}
293
294fn validate_op_and_get_operand_types<'a>(
295 validator: &mut FuncValidator<impl WasmModuleResources>,
296 environ: &mut FuncEnvironment<'_>,
297 operand_types: &'a mut Vec<wasmtime_environ::WasmValType>,
298 op: &wasmparser::Operator<'_>,
299 pos: usize,
300) -> WasmResult<Option<&'a [wasmtime_environ::WasmValType]>> {
301 let arity = op.operator_arity(&*validator);
312 operand_types.clear();
313 let operand_types = arity.and_then(|(operand_arity, _result_arity)| {
314 for i in (0..operand_arity).rev() {
315 let i = usize::try_from(i).unwrap();
316 let ty = validator.get_operand_type(i)??;
317 let ty = environ.convert_valtype(ty).ok()?;
318 operand_types.push(ty);
319 }
320 Some(&operand_types[..])
321 });
322
323 validator.op(pos, &op)?;
324
325 Ok(operand_types)
326}
327
328fn cur_srcloc(reader: &BinaryReader) -> ir::SourceLoc {
330 ir::SourceLoc::new(reader.original_position().try_into().unwrap())
333}