wasmtime_cranelift/translate/
func_translator.rs1use crate::func_environ::FuncEnvironment;
8use crate::translate::code_translator::{bitcast_wasm_returns, translate_operator};
9use crate::translate::state::FuncTranslationState;
10use crate::translate::translation_utils::get_vmctx_value_label;
11use crate::translate::TargetEnvironment;
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};
17use wasmtime_environ::{TypeConvert, WasmResult};
18
19pub struct FuncTranslator {
25 func_ctx: FunctionBuilderContext,
26 state: FuncTranslationState,
27}
28
29impl FuncTranslator {
30 pub fn new() -> Self {
32 Self {
33 func_ctx: FunctionBuilderContext::new(),
34 state: FuncTranslationState::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 = Variable::new(next_local);
117 builder.declare_var(local, param_type.value_type);
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 environ.after_locals(next_local);
159
160 Ok(())
161}
162
163fn declare_locals(
167 builder: &mut FunctionBuilder,
168 count: u32,
169 wasm_type: wasmparser::ValType,
170 next_local: &mut usize,
171 environ: &mut FuncEnvironment<'_>,
172) -> WasmResult<()> {
173 use wasmparser::ValType::*;
175 let (ty, init, needs_stack_map) = match wasm_type {
176 I32 => (
177 ir::types::I32,
178 Some(builder.ins().iconst(ir::types::I32, 0)),
179 false,
180 ),
181 I64 => (
182 ir::types::I64,
183 Some(builder.ins().iconst(ir::types::I64, 0)),
184 false,
185 ),
186 F32 => (
187 ir::types::F32,
188 Some(builder.ins().f32const(ir::immediates::Ieee32::with_bits(0))),
189 false,
190 ),
191 F64 => (
192 ir::types::F64,
193 Some(builder.ins().f64const(ir::immediates::Ieee64::with_bits(0))),
194 false,
195 ),
196 V128 => {
197 let constant_handle = builder.func.dfg.constants.insert([0; 16].to_vec().into());
198 (
199 ir::types::I8X16,
200 Some(builder.ins().vconst(ir::types::I8X16, constant_handle)),
201 false,
202 )
203 }
204 Ref(rt) => {
205 let hty = environ.convert_heap_type(rt.heap_type());
206 let (ty, needs_stack_map) = environ.reference_type(hty);
207 let init = if rt.is_nullable() {
208 Some(environ.translate_ref_null(builder.cursor(), hty)?)
209 } else {
210 None
211 };
212 (ty, init, needs_stack_map)
213 }
214 };
215
216 for _ in 0..count {
217 let local = Variable::new(*next_local);
218 builder.declare_var(local, ty);
219 if needs_stack_map {
220 builder.declare_var_needs_stack_map(local);
221 }
222 if let Some(init) = init {
223 builder.def_var(local, init);
224 builder.set_val_label(init, ValueLabel::new(*next_local));
225 }
226 *next_local += 1;
227 }
228 Ok(())
229}
230
231fn parse_function_body(
236 validator: &mut FuncValidator<impl WasmModuleResources>,
237 mut reader: BinaryReader,
238 builder: &mut FunctionBuilder,
239 state: &mut FuncTranslationState,
240 environ: &mut FuncEnvironment<'_>,
241) -> WasmResult<()> {
242 debug_assert_eq!(state.control_stack.len(), 1, "State not initialized");
244
245 environ.before_translate_function(builder, state)?;
246 while !reader.eof() {
247 let pos = reader.original_position();
248 builder.set_srcloc(cur_srcloc(&reader));
249 let op = reader.read_operator()?;
250 validator.op(pos, &op)?;
251 environ.before_translate_operator(&op, builder, state)?;
252 translate_operator(validator, &op, builder, state, environ)?;
253 environ.after_translate_operator(&op, builder, state)?;
254 }
255 environ.after_translate_function(builder, state)?;
256 let pos = reader.original_position();
257 validator.finish(pos)?;
258
259 if state.reachable {
265 if !builder.is_unreachable() {
266 environ.handle_before_return(&state.stack, builder);
267 bitcast_wasm_returns(&mut state.stack, builder);
268 builder.ins().return_(&state.stack);
269 }
270 }
271
272 state.stack.clear();
275
276 Ok(())
277}
278
279fn cur_srcloc(reader: &BinaryReader) -> ir::SourceLoc {
281 ir::SourceLoc::new(reader.original_position().try_into().unwrap())
284}