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::stack::FuncTranslationStacks;
11use crate::translate::translation_utils::get_vmctx_value_label;
12use cranelift_codegen::entity::EntityRef;
13use cranelift_codegen::ir::{self, Block, InstBuilder, ValueLabel};
14use cranelift_codegen::timing;
15use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
16use wasmparser::{BinaryReader, FuncValidator, FunctionBody, OperatorsReader, WasmModuleResources};
17use wasmtime_environ::{TypeConvert, WasmResult};
18
19pub struct FuncTranslator {
25 func_ctx: FunctionBuilderContext,
26 state: FuncTranslationStacks,
27}
28
29impl FuncTranslator {
30 pub fn new() -> Self {
32 Self {
33 func_ctx: FunctionBuilderContext::new(),
34 state: FuncTranslationStacks::new(),
35 }
36 }
37
38 pub fn context(&mut self) -> &mut FunctionBuilderContext {
41 &mut self.func_ctx
42 }
43
44 pub fn translate_body(
55 &mut self,
56 validator: &mut FuncValidator<impl WasmModuleResources>,
57 body: FunctionBody<'_>,
58 func: &mut ir::Function,
59 environ: &mut FuncEnvironment<'_>,
60 ) -> WasmResult<()> {
61 let _tt = timing::wasm_translate_function();
62 let mut reader = body.get_binary_reader();
63 log::trace!(
64 "translate({} bytes, {}{})",
65 reader.bytes_remaining(),
66 func.name,
67 func.signature
68 );
69 debug_assert_eq!(func.dfg.num_blocks(), 0, "Function must be empty");
70 debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty");
71
72 let mut builder = FunctionBuilder::new(func, &mut self.func_ctx);
73 builder.set_srcloc(cur_srcloc(&reader));
74 let entry_block = builder.create_block();
75 builder.append_block_params_for_function_params(entry_block);
76 builder.switch_to_block(entry_block);
77 builder.seal_block(entry_block); builder.ensure_inserted_block();
82
83 let num_params = declare_wasm_parameters(&mut builder, entry_block, environ);
84
85 let exit_block = builder.create_block();
88 builder.append_block_params_for_function_returns(exit_block);
89 self.state.initialize(&builder.func.signature, exit_block);
90
91 parse_local_decls(&mut reader, &mut builder, num_params, environ, validator)?;
92 parse_function_body(validator, reader, &mut builder, &mut self.state, environ)?;
93
94 builder.finalize();
95 log::trace!("translated Wasm to CLIF:\n{}", func.display());
96 Ok(())
97 }
98}
99
100fn declare_wasm_parameters(
104 builder: &mut FunctionBuilder,
105 entry_block: Block,
106 environ: &FuncEnvironment<'_>,
107) -> usize {
108 let sig_len = builder.func.signature.params.len();
109 let mut next_local = 0;
110 for i in 0..sig_len {
111 let param_type = builder.func.signature.params[i];
112 if environ.is_wasm_parameter(&builder.func.signature, i) {
115 let local = builder.declare_var(param_type.value_type);
117 debug_assert_eq!(local.index(), next_local);
118 next_local += 1;
119
120 if environ.param_needs_stack_map(&builder.func.signature, i) {
121 builder.declare_var_needs_stack_map(local);
122 }
123
124 let param_value = builder.block_params(entry_block)[i];
125 builder.def_var(local, param_value);
126 }
127 if param_type.purpose == ir::ArgumentPurpose::VMContext {
128 let param_value = builder.block_params(entry_block)[i];
129 builder.set_val_label(param_value, get_vmctx_value_label());
130 }
131 }
132
133 next_local
134}
135
136fn parse_local_decls(
140 reader: &mut BinaryReader,
141 builder: &mut FunctionBuilder,
142 num_params: usize,
143 environ: &mut FuncEnvironment<'_>,
144 validator: &mut FuncValidator<impl WasmModuleResources>,
145) -> WasmResult<()> {
146 let mut next_local = num_params;
147 let local_count = reader.read_var_u32()?;
148
149 for _ in 0..local_count {
150 builder.set_srcloc(cur_srcloc(reader));
151 let pos = reader.original_position();
152 let count = reader.read_var_u32()?;
153 let ty = reader.read()?;
154 validator.define_locals(pos, count, ty)?;
155 declare_locals(builder, count, ty, &mut next_local, environ)?;
156 }
157
158 Ok(())
159}
160
161fn declare_locals(
165 builder: &mut FunctionBuilder,
166 count: u32,
167 wasm_type: wasmparser::ValType,
168 next_local: &mut usize,
169 environ: &mut FuncEnvironment<'_>,
170) -> WasmResult<()> {
171 use wasmparser::ValType::*;
173 let (ty, init, needs_stack_map) = match wasm_type {
174 I32 => (
175 ir::types::I32,
176 Some(builder.ins().iconst(ir::types::I32, 0)),
177 false,
178 ),
179 I64 => (
180 ir::types::I64,
181 Some(builder.ins().iconst(ir::types::I64, 0)),
182 false,
183 ),
184 F32 => (
185 ir::types::F32,
186 Some(builder.ins().f32const(ir::immediates::Ieee32::with_bits(0))),
187 false,
188 ),
189 F64 => (
190 ir::types::F64,
191 Some(builder.ins().f64const(ir::immediates::Ieee64::with_bits(0))),
192 false,
193 ),
194 V128 => {
195 let constant_handle = builder.func.dfg.constants.insert([0; 16].to_vec().into());
196 (
197 ir::types::I8X16,
198 Some(builder.ins().vconst(ir::types::I8X16, constant_handle)),
199 false,
200 )
201 }
202 Ref(rt) => {
203 let hty = environ.convert_heap_type(rt.heap_type())?;
204 let (ty, needs_stack_map) = environ.reference_type(hty);
205 let init = if rt.is_nullable() {
206 Some(environ.translate_ref_null(builder.cursor(), hty)?)
207 } else {
208 None
209 };
210 (ty, init, needs_stack_map)
211 }
212 };
213
214 for _ in 0..count {
215 let local = builder.declare_var(ty);
216 debug_assert_eq!(local.index(), *next_local);
217 if needs_stack_map {
218 builder.declare_var_needs_stack_map(local);
219 }
220 if let Some(init) = init {
221 builder.def_var(local, init);
222 builder.set_val_label(init, ValueLabel::new(*next_local));
223 }
224 *next_local += 1;
225 }
226 Ok(())
227}
228
229fn parse_function_body(
234 validator: &mut FuncValidator<impl WasmModuleResources>,
235 reader: BinaryReader,
236 builder: &mut FunctionBuilder,
237 stack: &mut FuncTranslationStacks,
238 environ: &mut FuncEnvironment<'_>,
239) -> WasmResult<()> {
240 debug_assert_eq!(stack.control_stack.len(), 1, "State not initialized");
242
243 environ.before_translate_function(builder, stack)?;
244
245 let mut reader = OperatorsReader::new(reader);
246 let mut operand_types = vec![];
247
248 while !reader.eof() {
249 let pos = reader.original_position();
250 builder.set_srcloc(cur_srcloc(&reader.get_binary_reader()));
251
252 let op = reader.read()?;
253 let operand_types =
254 validate_op_and_get_operand_types(validator, environ, &mut operand_types, &op, pos)?;
255
256 environ.before_translate_operator(&op, operand_types, builder, stack)?;
257 translate_operator(validator, &op, operand_types, builder, stack, environ)?;
258 environ.after_translate_operator(&op, operand_types, builder, stack)?;
259 }
260 environ.after_translate_function(builder, stack)?;
261 reader.finish()?;
262
263 if stack.reachable {
269 if !builder.is_unreachable() {
270 environ.handle_before_return(&stack.stack, builder);
271 bitcast_wasm_returns(&mut stack.stack, builder);
272 builder.ins().return_(&stack.stack);
273 }
274 }
275
276 stack.stack.clear();
279
280 Ok(())
281}
282
283fn validate_op_and_get_operand_types<'a>(
284 validator: &mut FuncValidator<impl WasmModuleResources>,
285 environ: &mut FuncEnvironment<'_>,
286 operand_types: &'a mut Vec<wasmtime_environ::WasmValType>,
287 op: &wasmparser::Operator<'_>,
288 pos: usize,
289) -> WasmResult<Option<&'a [wasmtime_environ::WasmValType]>> {
290 let arity = op.operator_arity(&*validator);
301 operand_types.clear();
302 let operand_types = arity.and_then(|(operand_arity, _result_arity)| {
303 for i in (0..operand_arity).rev() {
304 let i = usize::try_from(i).unwrap();
305 let ty = validator.get_operand_type(i)??;
306 let ty = environ.convert_valtype(ty).ok()?;
307 operand_types.push(ty);
308 }
309 Some(&operand_types[..])
310 });
311
312 validator.op(pos, &op)?;
313
314 Ok(operand_types)
315}
316
317fn cur_srcloc(reader: &BinaryReader) -> ir::SourceLoc {
319 ir::SourceLoc::new(reader.original_position().try_into().unwrap())
322}