wasmer_compiler_cranelift/translator/
func_translator.rs1use super::code_translator::translate_operator;
11use super::func_environ::{FuncEnvironment, ReturnMode};
12use super::func_state::FuncTranslationState;
13use super::translation_utils::get_vmctx_value_label;
14use crate::translator::code_translator::bitcast_wasm_returns;
15use core::convert::TryFrom;
16use cranelift_codegen::entity::EntityRef;
17use cranelift_codegen::ir::{self, Block, InstBuilder, ValueLabel};
18use cranelift_codegen::timing;
19use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
20use wasmer_compiler::{FunctionBinaryReader, ModuleTranslationState, wptype_to_type};
21use wasmer_compiler::{wasm_unsupported, wasmparser};
22use wasmer_types::{LocalFunctionIndex, WasmResult};
23
24pub struct FuncTranslator {
30 func_ctx: FunctionBuilderContext,
31 state: FuncTranslationState,
32}
33
34impl FuncTranslator {
35 pub fn new() -> Self {
37 Self {
38 func_ctx: FunctionBuilderContext::new(),
39 state: FuncTranslationState::new(),
40 }
41 }
42
43 pub fn translate<FE: FuncEnvironment + ?Sized>(
62 &mut self,
63 module_translation_state: &ModuleTranslationState,
64 reader: &mut dyn FunctionBinaryReader,
65 func: &mut ir::Function,
66 environ: &mut FE,
67 local_function_index: LocalFunctionIndex,
68 ) -> WasmResult<()> {
69 environ.push_params_on_stack(local_function_index);
70 self.translate_from_reader(module_translation_state, reader, func, environ)
71 }
72
73 pub fn translate_from_reader<FE: FuncEnvironment + ?Sized>(
75 &mut self,
76 module_translation_state: &ModuleTranslationState,
77 reader: &mut dyn FunctionBinaryReader,
78 func: &mut ir::Function,
79 environ: &mut FE,
80 ) -> WasmResult<()> {
81 let _tt = timing::wasm_translate_function();
82 tracing::trace!(
83 "translate({} bytes, {}{})",
84 reader.bytes_remaining(),
85 func.name,
86 func.signature
87 );
88 debug_assert_eq!(func.dfg.num_blocks(), 0, "Function must be empty");
89 debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty");
90
91 let mut builder = FunctionBuilder::new(func, &mut self.func_ctx);
93 builder.set_srcloc(cur_srcloc(reader));
94 let entry_block = builder.create_block();
95 builder.append_block_params_for_function_params(entry_block);
96 builder.switch_to_block(entry_block); builder.seal_block(entry_block); builder.ensure_inserted_block();
102
103 let num_params = declare_wasm_parameters(&mut builder, entry_block, environ);
104
105 let exit_block = builder.create_block();
108 builder.append_block_params_for_function_returns(exit_block);
109 self.state.initialize(&builder.func.signature, exit_block);
110
111 parse_local_decls(reader, &mut builder, num_params, environ)?;
112 parse_function_body(
113 module_translation_state,
114 reader,
115 &mut builder,
116 &mut self.state,
117 environ,
118 )?;
119
120 builder.finalize();
121 Ok(())
122 }
123}
124
125fn declare_wasm_parameters<FE: FuncEnvironment + ?Sized>(
129 builder: &mut FunctionBuilder,
130 entry_block: Block,
131 environ: &FE,
132) -> usize {
133 let sig_len = builder.func.signature.params.len();
134 let mut next_local = 0;
135 for i in 0..sig_len {
136 let param_type = builder.func.signature.params[i];
137 if environ.is_wasm_parameter(&builder.func.signature, i) {
140 let local = builder.declare_var(param_type.value_type);
142 let local_index = local.index();
143 debug_assert_eq!(local_index, next_local);
144 debug_assert!(u32::try_from(local_index).is_ok());
145 next_local += 1;
146
147 let param_value = builder.block_params(entry_block)[i];
148 builder.def_var(local, param_value);
149 }
150 if param_type.purpose == ir::ArgumentPurpose::VMContext {
151 let param_value = builder.block_params(entry_block)[i];
152 builder.set_val_label(param_value, get_vmctx_value_label());
153 }
154 }
155
156 next_local
157}
158
159fn parse_local_decls<FE: FuncEnvironment + ?Sized>(
163 reader: &mut dyn FunctionBinaryReader,
164 builder: &mut FunctionBuilder,
165 num_params: usize,
166 environ: &mut FE,
167) -> WasmResult<()> {
168 let mut next_local = num_params;
169 let local_count = reader.read_local_count()?;
170
171 for _ in 0..local_count {
172 builder.set_srcloc(cur_srcloc(reader));
173 let (count, ty) = reader.read_local_decl()?;
174 declare_locals(builder, count, ty, &mut next_local, environ)?;
175 }
176
177 Ok(())
178}
179
180fn declare_locals<FE: FuncEnvironment + ?Sized>(
184 builder: &mut FunctionBuilder,
185 count: u32,
186 wasm_type: wasmparser::ValType,
187 next_local: &mut usize,
188 environ: &mut FE,
189) -> WasmResult<()> {
190 use wasmparser::ValType::*;
192 let zeroval = match wasm_type {
193 I32 => builder.ins().iconst(ir::types::I32, 0),
194 I64 => builder.ins().iconst(ir::types::I64, 0),
195 F32 => builder.ins().f32const(ir::immediates::Ieee32::with_bits(0)),
196 F64 => builder.ins().f64const(ir::immediates::Ieee64::with_bits(0)),
197 V128 => {
198 let constant_handle = builder.func.dfg.constants.insert([0; 16].to_vec().into());
199 builder.ins().vconst(ir::types::I8X16, constant_handle)
200 }
201 Ref(ty) => {
202 if ty.is_func_ref() || ty.is_extern_ref() {
203 builder.ins().iconst(environ.reference_type(), 0)
204 } else {
205 return Err(wasm_unsupported!("unsupported reference type: {:?}", ty));
206 }
207 }
208 };
209
210 let wasmer_ty = wptype_to_type(wasm_type).unwrap();
211 let ty = builder.func.dfg.value_type(zeroval);
212 for _ in 0..count {
213 let local = builder.declare_var(ty);
214 let local_index = local.index();
215 debug_assert_eq!(local_index, *next_local);
216 debug_assert!(u32::try_from(local_index).is_ok());
217 builder.def_var(local, zeroval);
218 builder.set_val_label(zeroval, ValueLabel::new(*next_local));
219 environ.push_local_decl_on_stack(wasmer_ty);
220 *next_local += 1;
221 }
222 Ok(())
223}
224
225fn parse_function_body<FE: FuncEnvironment + ?Sized>(
230 module_translation_state: &ModuleTranslationState,
231 reader: &mut dyn FunctionBinaryReader,
232 builder: &mut FunctionBuilder,
233 state: &mut FuncTranslationState,
234 environ: &mut FE,
235) -> WasmResult<()> {
236 debug_assert_eq!(state.control_stack.len(), 1, "State not initialized");
238
239 while !state.control_stack.is_empty() {
241 builder.set_srcloc(cur_srcloc(reader));
242 let op = reader.read_operator()?;
243 environ.before_translate_operator(&op, builder, state)?;
244 translate_operator(module_translation_state, &op, builder, state, environ)?;
245 environ.after_translate_operator(&op, builder, state)?;
246 }
247
248 if state.reachable {
254 if !builder.is_unreachable() {
256 match environ.return_mode() {
257 ReturnMode::NormalReturns => {
258 bitcast_wasm_returns(environ, &mut state.stack, builder);
259 builder.ins().return_(&state.stack)
260 }
261 };
262 }
263 }
264
265 state.stack.clear();
268 debug_assert!(reader.eof());
271
272 Ok(())
273}
274
275fn cur_srcloc(reader: &dyn FunctionBinaryReader) -> ir::SourceLoc {
277 ir::SourceLoc::new(reader.original_position() as u32)
280}