wasmer_compiler_cranelift/translator/
func_translator.rs1use super::code_translator::translate_operator;
11use super::func_state::FuncTranslationState;
12use super::translation_utils::get_vmctx_value_label;
13use crate::func_environ::FuncEnvironment;
14use crate::translator::EXN_REF_TYPE;
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::wasmparser::RefType;
21use wasmer_compiler::{FunctionBinaryReader, ModuleTranslationState, wptype_to_type};
22use wasmer_compiler::{wasm_unsupported, wasmparser};
23use wasmer_types::{LocalFunctionIndex, WasmResult};
24
25pub struct FuncTranslator {
31 func_ctx: FunctionBuilderContext,
32 state: FuncTranslationState,
33 allow_unaligned_memory_accesses: bool,
34}
35
36impl wasmer_compiler::FuncTranslator for FuncTranslator {}
37
38impl FuncTranslator {
39 pub fn new(allow_unaligned_memory_accesses: bool) -> Self {
41 Self {
42 func_ctx: FunctionBuilderContext::new(),
43 state: FuncTranslationState::new(),
44 allow_unaligned_memory_accesses,
45 }
46 }
47
48 pub fn translate(
67 &mut self,
68 module_translation_state: &ModuleTranslationState,
69 reader: &mut dyn FunctionBinaryReader,
70 func: &mut ir::Function,
71 environ: &mut FuncEnvironment<'_>,
72 local_function_index: LocalFunctionIndex,
73 ) -> WasmResult<()> {
74 environ.push_params_on_stack(local_function_index);
75 self.translate_from_reader(module_translation_state, reader, func, environ)
76 }
77
78 pub fn translate_from_reader(
80 &mut self,
81 module_translation_state: &ModuleTranslationState,
82 reader: &mut dyn FunctionBinaryReader,
83 func: &mut ir::Function,
84 environ: &mut FuncEnvironment<'_>,
85 ) -> WasmResult<()> {
86 let _tt = timing::wasm_translate_function();
87 tracing::trace!(
88 "translate({} bytes, {}{})",
89 reader.bytes_remaining(),
90 func.name,
91 func.signature
92 );
93 debug_assert_eq!(func.dfg.num_blocks(), 0, "Function must be empty");
94 debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty");
95
96 let mut builder = FunctionBuilder::new(func, &mut self.func_ctx);
98 builder.set_srcloc(cur_srcloc(reader));
99 let entry_block = builder.create_block();
100 builder.append_block_params_for_function_params(entry_block);
101 builder.switch_to_block(entry_block); builder.seal_block(entry_block); builder.ensure_inserted_block();
107
108 let num_params = declare_wasm_parameters(&mut builder, entry_block, environ);
109
110 let exit_block = builder.create_block();
113 for &ty in environ.return_types() {
114 builder.append_block_param(
115 exit_block,
116 crate::translator::type_to_irtype(ty, environ.target_config())?,
117 );
118 }
119 self.state.initialize(
120 &builder.func.signature,
121 exit_block,
122 environ.return_types().len(),
123 );
124
125 parse_local_decls(reader, &mut builder, num_params, environ)?;
126 parse_function_body(
127 module_translation_state,
128 reader,
129 &mut builder,
130 &mut self.state,
131 environ,
132 self.allow_unaligned_memory_accesses,
133 )?;
134
135 builder.finalize(environ.target_config());
136 Ok(())
137 }
138}
139
140fn declare_wasm_parameters(
144 builder: &mut FunctionBuilder,
145 entry_block: Block,
146 environ: &FuncEnvironment<'_>,
147) -> usize {
148 let sig_len = builder.func.signature.params.len();
149 let mut next_local = 0;
150 for i in 0..sig_len {
151 let param_type = builder.func.signature.params[i];
152 if environ.is_wasm_parameter(&builder.func.signature, i) {
155 let local = builder.declare_var(param_type.value_type);
157 let local_index = local.index();
158 debug_assert_eq!(local_index, next_local);
159 debug_assert!(u32::try_from(local_index).is_ok());
160 next_local += 1;
161
162 let param_value = builder.block_params(entry_block)[i];
163 builder.def_var(local, param_value);
164 }
165 if param_type.purpose == ir::ArgumentPurpose::VMContext {
166 let param_value = builder.block_params(entry_block)[i];
167 builder.set_val_label(param_value, get_vmctx_value_label());
168 }
169 }
170
171 next_local
172}
173
174fn parse_local_decls(
178 reader: &mut dyn FunctionBinaryReader,
179 builder: &mut FunctionBuilder,
180 num_params: usize,
181 environ: &mut FuncEnvironment<'_>,
182) -> WasmResult<()> {
183 let mut next_local = num_params;
184 let local_count = reader.read_local_count()?;
185
186 for _ in 0..local_count {
187 builder.set_srcloc(cur_srcloc(reader));
188 let (count, ty) = reader.read_local_decl()?;
189 declare_locals(builder, count, ty, &mut next_local, environ)?;
190 }
191
192 Ok(())
193}
194
195fn declare_locals(
199 builder: &mut FunctionBuilder,
200 count: u32,
201 wasm_type: wasmparser::ValType,
202 next_local: &mut usize,
203 environ: &mut FuncEnvironment<'_>,
204) -> WasmResult<()> {
205 use wasmparser::ValType::*;
207 let zeroval = match wasm_type {
208 I32 => builder.ins().iconst(ir::types::I32, 0),
209 I64 => builder.ins().iconst(ir::types::I64, 0),
210 F32 => builder.ins().f32const(ir::immediates::Ieee32::with_bits(0)),
211 F64 => builder.ins().f64const(ir::immediates::Ieee64::with_bits(0)),
212 V128 => {
213 let constant_handle = builder.func.dfg.constants.insert([0; 16].to_vec().into());
214 builder.ins().vconst(ir::types::I8X16, constant_handle)
215 }
216 Ref(ty) => {
217 if ty.is_func_ref() || ty.is_extern_ref() {
218 builder.ins().iconst(environ.reference_type(), 0)
219 } else if ty == RefType::EXNREF || ty == RefType::EXN {
220 builder.ins().iconst(EXN_REF_TYPE, 0)
222 } else {
223 return Err(wasm_unsupported!("unsupported reference type: {:?}", ty));
224 }
225 }
226 };
227
228 let wasmer_ty = wptype_to_type(wasm_type).unwrap();
229 let ty = builder.func.dfg.value_type(zeroval);
230 for _ in 0..count {
231 let local = builder.declare_var(ty);
232 let local_index = local.index();
233 debug_assert_eq!(local_index, *next_local);
234 debug_assert!(u32::try_from(local_index).is_ok());
235 builder.def_var(local, zeroval);
236 builder.set_val_label(zeroval, ValueLabel::new(*next_local));
237 environ.push_local_decl_on_stack(wasmer_ty);
238 *next_local += 1;
239 }
240 Ok(())
241}
242
243fn parse_function_body(
248 module_translation_state: &ModuleTranslationState,
249 reader: &mut dyn FunctionBinaryReader,
250 builder: &mut FunctionBuilder,
251 state: &mut FuncTranslationState,
252 environ: &mut FuncEnvironment<'_>,
253 allow_unaligned_memory_accesses: bool,
254) -> WasmResult<()> {
255 debug_assert_eq!(state.control_stack.len(), 1, "State not initialized");
257
258 while !state.control_stack.is_empty() {
260 builder.set_srcloc(cur_srcloc(reader));
261 let op = reader.read_operator()?;
262 translate_operator(
263 module_translation_state,
264 &op,
265 builder,
266 state,
267 environ,
268 allow_unaligned_memory_accesses,
269 )?;
270 }
271
272 if state.reachable {
278 if !builder.is_unreachable() {
280 environ.emit_wasm_return(builder, &state.stack);
281 }
282 }
283
284 state.stack.clear();
287 debug_assert!(reader.eof());
290
291 Ok(())
292}
293
294fn cur_srcloc(reader: &dyn FunctionBinaryReader) -> ir::SourceLoc {
296 ir::SourceLoc::new(reader.original_position() as u32)
299}