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