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 crate::translator::code_translator::bitcast_wasm_returns;
16use core::convert::TryFrom;
17use cranelift_codegen::entity::EntityRef;
18use cranelift_codegen::ir::{self, Block, InstBuilder, ValueLabel};
19use cranelift_codegen::timing;
20use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
21use wasmer_compiler::wasmparser::RefType;
22use wasmer_compiler::{FunctionBinaryReader, ModuleTranslationState, wptype_to_type};
23use wasmer_compiler::{wasm_unsupported, wasmparser};
24use wasmer_types::{LocalFunctionIndex, WasmResult};
25
26pub struct FuncTranslator {
32 func_ctx: FunctionBuilderContext,
33 state: FuncTranslationState,
34 allow_unaligned_memory_accesses: bool,
35}
36
37impl wasmer_compiler::FuncTranslator for FuncTranslator {}
38
39impl FuncTranslator {
40 pub fn new(allow_unaligned_memory_accesses: bool) -> Self {
42 Self {
43 func_ctx: FunctionBuilderContext::new(),
44 state: FuncTranslationState::new(),
45 allow_unaligned_memory_accesses,
46 }
47 }
48
49 pub fn translate(
68 &mut self,
69 module_translation_state: &ModuleTranslationState,
70 reader: &mut dyn FunctionBinaryReader,
71 func: &mut ir::Function,
72 environ: &mut FuncEnvironment<'_>,
73 local_function_index: LocalFunctionIndex,
74 ) -> WasmResult<()> {
75 environ.push_params_on_stack(local_function_index);
76 self.translate_from_reader(module_translation_state, reader, func, environ)
77 }
78
79 pub fn translate_from_reader(
81 &mut self,
82 module_translation_state: &ModuleTranslationState,
83 reader: &mut dyn FunctionBinaryReader,
84 func: &mut ir::Function,
85 environ: &mut FuncEnvironment<'_>,
86 ) -> WasmResult<()> {
87 let _tt = timing::wasm_translate_function();
88 tracing::trace!(
89 "translate({} bytes, {}{})",
90 reader.bytes_remaining(),
91 func.name,
92 func.signature
93 );
94 debug_assert_eq!(func.dfg.num_blocks(), 0, "Function must be empty");
95 debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty");
96
97 let mut builder = FunctionBuilder::new(func, &mut self.func_ctx);
99 builder.set_srcloc(cur_srcloc(reader));
100 let entry_block = builder.create_block();
101 builder.append_block_params_for_function_params(entry_block);
102 builder.switch_to_block(entry_block); builder.seal_block(entry_block); builder.ensure_inserted_block();
108
109 let num_params = declare_wasm_parameters(&mut builder, entry_block, environ);
110
111 let exit_block = builder.create_block();
114 builder.append_block_params_for_function_returns(exit_block);
115 self.state.initialize(&builder.func.signature, exit_block);
116
117 parse_local_decls(reader, &mut builder, num_params, environ)?;
118 parse_function_body(
119 module_translation_state,
120 reader,
121 &mut builder,
122 &mut self.state,
123 environ,
124 self.allow_unaligned_memory_accesses,
125 )?;
126
127 builder.finalize();
128 Ok(())
129 }
130}
131
132fn declare_wasm_parameters(
136 builder: &mut FunctionBuilder,
137 entry_block: Block,
138 environ: &FuncEnvironment<'_>,
139) -> usize {
140 let sig_len = builder.func.signature.params.len();
141 let mut next_local = 0;
142 for i in 0..sig_len {
143 let param_type = builder.func.signature.params[i];
144 if environ.is_wasm_parameter(&builder.func.signature, i) {
147 let local = builder.declare_var(param_type.value_type);
149 let local_index = local.index();
150 debug_assert_eq!(local_index, next_local);
151 debug_assert!(u32::try_from(local_index).is_ok());
152 next_local += 1;
153
154 let param_value = builder.block_params(entry_block)[i];
155 builder.def_var(local, param_value);
156 }
157 if param_type.purpose == ir::ArgumentPurpose::VMContext {
158 let param_value = builder.block_params(entry_block)[i];
159 builder.set_val_label(param_value, get_vmctx_value_label());
160 }
161 }
162
163 next_local
164}
165
166fn parse_local_decls(
170 reader: &mut dyn FunctionBinaryReader,
171 builder: &mut FunctionBuilder,
172 num_params: usize,
173 environ: &mut FuncEnvironment<'_>,
174) -> WasmResult<()> {
175 let mut next_local = num_params;
176 let local_count = reader.read_local_count()?;
177
178 for _ in 0..local_count {
179 builder.set_srcloc(cur_srcloc(reader));
180 let (count, ty) = reader.read_local_decl()?;
181 declare_locals(builder, count, ty, &mut next_local, environ)?;
182 }
183
184 Ok(())
185}
186
187fn declare_locals(
191 builder: &mut FunctionBuilder,
192 count: u32,
193 wasm_type: wasmparser::ValType,
194 next_local: &mut usize,
195 environ: &mut FuncEnvironment<'_>,
196) -> WasmResult<()> {
197 use wasmparser::ValType::*;
199 let zeroval = match wasm_type {
200 I32 => builder.ins().iconst(ir::types::I32, 0),
201 I64 => builder.ins().iconst(ir::types::I64, 0),
202 F32 => builder.ins().f32const(ir::immediates::Ieee32::with_bits(0)),
203 F64 => builder.ins().f64const(ir::immediates::Ieee64::with_bits(0)),
204 V128 => {
205 let constant_handle = builder.func.dfg.constants.insert([0; 16].to_vec().into());
206 builder.ins().vconst(ir::types::I8X16, constant_handle)
207 }
208 Ref(ty) => {
209 if ty.is_func_ref() || ty.is_extern_ref() {
210 builder.ins().iconst(environ.reference_type(), 0)
211 } else if ty == RefType::EXNREF || ty == RefType::EXN {
212 builder.ins().iconst(EXN_REF_TYPE, 0)
214 } else {
215 return Err(wasm_unsupported!("unsupported reference type: {:?}", ty));
216 }
217 }
218 };
219
220 let wasmer_ty = wptype_to_type(wasm_type).unwrap();
221 let ty = builder.func.dfg.value_type(zeroval);
222 for _ in 0..count {
223 let local = builder.declare_var(ty);
224 let local_index = local.index();
225 debug_assert_eq!(local_index, *next_local);
226 debug_assert!(u32::try_from(local_index).is_ok());
227 builder.def_var(local, zeroval);
228 builder.set_val_label(zeroval, ValueLabel::new(*next_local));
229 environ.push_local_decl_on_stack(wasmer_ty);
230 *next_local += 1;
231 }
232 Ok(())
233}
234
235fn parse_function_body(
240 module_translation_state: &ModuleTranslationState,
241 reader: &mut dyn FunctionBinaryReader,
242 builder: &mut FunctionBuilder,
243 state: &mut FuncTranslationState,
244 environ: &mut FuncEnvironment<'_>,
245 allow_unaligned_memory_accesses: bool,
246) -> WasmResult<()> {
247 debug_assert_eq!(state.control_stack.len(), 1, "State not initialized");
249
250 while !state.control_stack.is_empty() {
252 builder.set_srcloc(cur_srcloc(reader));
253 let op = reader.read_operator()?;
254 translate_operator(
255 module_translation_state,
256 &op,
257 builder,
258 state,
259 environ,
260 allow_unaligned_memory_accesses,
261 )?;
262 }
263
264 if state.reachable {
270 if !builder.is_unreachable() {
272 {
273 bitcast_wasm_returns(environ, &mut state.stack, builder);
274 builder.ins().return_(&state.stack)
275 };
276 }
277 }
278
279 state.stack.clear();
282 debug_assert!(reader.eof());
285
286 Ok(())
287}
288
289fn cur_srcloc(reader: &dyn FunctionBinaryReader) -> ir::SourceLoc {
291 ir::SourceLoc::new(reader.original_position() as u32)
294}