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::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}
35
36impl FuncTranslator {
37 pub fn new() -> Self {
39 Self {
40 func_ctx: FunctionBuilderContext::new(),
41 state: FuncTranslationState::new(),
42 }
43 }
44
45 pub fn translate<FE: FuncEnvironment + ?Sized>(
64 &mut self,
65 module_translation_state: &ModuleTranslationState,
66 reader: &mut dyn FunctionBinaryReader,
67 func: &mut ir::Function,
68 environ: &mut FE,
69 local_function_index: LocalFunctionIndex,
70 ) -> WasmResult<()> {
71 environ.push_params_on_stack(local_function_index);
72 self.translate_from_reader(module_translation_state, reader, func, environ)
73 }
74
75 pub fn translate_from_reader<FE: FuncEnvironment + ?Sized>(
77 &mut self,
78 module_translation_state: &ModuleTranslationState,
79 reader: &mut dyn FunctionBinaryReader,
80 func: &mut ir::Function,
81 environ: &mut FE,
82 ) -> WasmResult<()> {
83 let _tt = timing::wasm_translate_function();
84 tracing::trace!(
85 "translate({} bytes, {}{})",
86 reader.bytes_remaining(),
87 func.name,
88 func.signature
89 );
90 debug_assert_eq!(func.dfg.num_blocks(), 0, "Function must be empty");
91 debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty");
92
93 let mut builder = FunctionBuilder::new(func, &mut self.func_ctx);
95 builder.set_srcloc(cur_srcloc(reader));
96 let entry_block = builder.create_block();
97 builder.append_block_params_for_function_params(entry_block);
98 builder.switch_to_block(entry_block); builder.seal_block(entry_block); builder.ensure_inserted_block();
104
105 let num_params = declare_wasm_parameters(&mut builder, entry_block, environ);
106
107 let exit_block = builder.create_block();
110 builder.append_block_params_for_function_returns(exit_block);
111 self.state.initialize(&builder.func.signature, exit_block);
112
113 parse_local_decls(reader, &mut builder, num_params, environ)?;
114 parse_function_body(
115 module_translation_state,
116 reader,
117 &mut builder,
118 &mut self.state,
119 environ,
120 )?;
121
122 builder.finalize();
123 Ok(())
124 }
125}
126
127fn declare_wasm_parameters<FE: FuncEnvironment + ?Sized>(
131 builder: &mut FunctionBuilder,
132 entry_block: Block,
133 environ: &FE,
134) -> usize {
135 let sig_len = builder.func.signature.params.len();
136 let mut next_local = 0;
137 for i in 0..sig_len {
138 let param_type = builder.func.signature.params[i];
139 if environ.is_wasm_parameter(&builder.func.signature, i) {
142 let local = builder.declare_var(param_type.value_type);
144 let local_index = local.index();
145 debug_assert_eq!(local_index, next_local);
146 debug_assert!(u32::try_from(local_index).is_ok());
147 next_local += 1;
148
149 let param_value = builder.block_params(entry_block)[i];
150 builder.def_var(local, param_value);
151 }
152 if param_type.purpose == ir::ArgumentPurpose::VMContext {
153 let param_value = builder.block_params(entry_block)[i];
154 builder.set_val_label(param_value, get_vmctx_value_label());
155 }
156 }
157
158 next_local
159}
160
161fn parse_local_decls<FE: FuncEnvironment + ?Sized>(
165 reader: &mut dyn FunctionBinaryReader,
166 builder: &mut FunctionBuilder,
167 num_params: usize,
168 environ: &mut FE,
169) -> WasmResult<()> {
170 let mut next_local = num_params;
171 let local_count = reader.read_local_count()?;
172
173 for _ in 0..local_count {
174 builder.set_srcloc(cur_srcloc(reader));
175 let (count, ty) = reader.read_local_decl()?;
176 declare_locals(builder, count, ty, &mut next_local, environ)?;
177 }
178
179 Ok(())
180}
181
182fn declare_locals<FE: FuncEnvironment + ?Sized>(
186 builder: &mut FunctionBuilder,
187 count: u32,
188 wasm_type: wasmparser::ValType,
189 next_local: &mut usize,
190 environ: &mut FE,
191) -> WasmResult<()> {
192 use wasmparser::ValType::*;
194 let zeroval = match wasm_type {
195 I32 => builder.ins().iconst(ir::types::I32, 0),
196 I64 => builder.ins().iconst(ir::types::I64, 0),
197 F32 => builder.ins().f32const(ir::immediates::Ieee32::with_bits(0)),
198 F64 => builder.ins().f64const(ir::immediates::Ieee64::with_bits(0)),
199 V128 => {
200 let constant_handle = builder.func.dfg.constants.insert([0; 16].to_vec().into());
201 builder.ins().vconst(ir::types::I8X16, constant_handle)
202 }
203 Ref(ty) => {
204 if ty.is_func_ref() || ty.is_extern_ref() {
205 builder.ins().iconst(environ.reference_type(), 0)
206 } else if ty == RefType::EXNREF {
207 builder.ins().iconst(EXN_REF_TYPE, 0)
208 } else {
209 return Err(wasm_unsupported!("unsupported reference type: {:?}", ty));
210 }
211 }
212 };
213
214 let wasmer_ty = wptype_to_type(wasm_type).unwrap();
215 let ty = builder.func.dfg.value_type(zeroval);
216 for _ in 0..count {
217 let local = builder.declare_var(ty);
218 let local_index = local.index();
219 debug_assert_eq!(local_index, *next_local);
220 debug_assert!(u32::try_from(local_index).is_ok());
221 builder.def_var(local, zeroval);
222 builder.set_val_label(zeroval, ValueLabel::new(*next_local));
223 environ.push_local_decl_on_stack(wasmer_ty);
224 *next_local += 1;
225 }
226 Ok(())
227}
228
229fn parse_function_body<FE: FuncEnvironment + ?Sized>(
234 module_translation_state: &ModuleTranslationState,
235 reader: &mut dyn FunctionBinaryReader,
236 builder: &mut FunctionBuilder,
237 state: &mut FuncTranslationState,
238 environ: &mut FE,
239) -> WasmResult<()> {
240 debug_assert_eq!(state.control_stack.len(), 1, "State not initialized");
242
243 while !state.control_stack.is_empty() {
245 builder.set_srcloc(cur_srcloc(reader));
246 let op = reader.read_operator()?;
247 environ.before_translate_operator(&op, builder, state)?;
248 translate_operator(module_translation_state, &op, builder, state, environ)?;
249 environ.after_translate_operator(&op, builder, state)?;
250 }
251
252 if state.reachable {
258 if !builder.is_unreachable() {
260 match environ.return_mode() {
261 ReturnMode::NormalReturns => {
262 bitcast_wasm_returns(environ, &mut state.stack, builder);
263 builder.ins().return_(&state.stack)
264 }
265 };
266 }
267 }
268
269 state.stack.clear();
272 debug_assert!(reader.eof());
275
276 Ok(())
277}
278
279fn cur_srcloc(reader: &dyn FunctionBinaryReader) -> ir::SourceLoc {
281 ir::SourceLoc::new(reader.original_position() as u32)
284}