wasmer_compiler_cranelift/translator/func_environ.rs
1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/main/docs/ATTRIBUTIONS.md
3
4//! All the runtime support necessary for the wasm to cranelift translation is formalized by the
5//! traits `FunctionEnvMutironment`.
6
7use super::func_state::FuncTranslationState;
8use super::translation_utils::reference_type;
9use crate::heap::{Heap, HeapData};
10use crate::translator::func_state::LandingPad;
11use core::convert::From;
12use cranelift_codegen::cursor::FuncCursor;
13use cranelift_codegen::ir::immediates::Offset32;
14use cranelift_codegen::ir::{self, InstBuilder};
15use cranelift_codegen::isa::TargetFrontendConfig;
16use cranelift_frontend::FunctionBuilder;
17use smallvec::SmallVec;
18use wasmer_compiler::wasmparser::{HeapType, Operator};
19use wasmer_types::entity::PrimaryMap;
20use wasmer_types::{
21 FunctionIndex, FunctionType, GlobalIndex, LocalFunctionIndex, MemoryIndex, SignatureIndex,
22 TableIndex, TagIndex, Type as WasmerType, WasmResult,
23};
24
25/// The value of a WebAssembly global variable.
26#[derive(Clone, Copy)]
27pub enum GlobalVariable {
28 #[allow(dead_code)]
29 /// This is a constant global with a value known at compile time.
30 Const(ir::Value),
31
32 /// This is a variable in memory that should be referenced through a `GlobalValue`.
33 Memory {
34 /// The address of the global variable storage.
35 gv: ir::GlobalValue,
36 /// An offset to add to the address.
37 offset: Offset32,
38 /// The global variable's type.
39 ty: ir::Type,
40 },
41
42 #[allow(dead_code)]
43 /// This is a global variable that needs to be handled by the environment.
44 Custom,
45}
46
47#[allow(dead_code)]
48/// How to return from functions.
49#[derive(Copy, Clone, PartialEq, Eq, Debug)]
50pub enum ReturnMode {
51 /// Use normal return instructions as needed.
52 NormalReturns,
53}
54
55/// Environment affecting the translation of a WebAssembly.
56pub trait TargetEnvironment {
57 /// Get the information needed to produce Cranelift IR for the given target.
58 fn target_config(&self) -> TargetFrontendConfig;
59
60 /// Get the Cranelift integer type to use for native pointers.
61 ///
62 /// This returns `I64` for 64-bit architectures and `I32` for 32-bit architectures.
63 fn pointer_type(&self) -> ir::Type {
64 ir::Type::int(u16::from(self.target_config().pointer_bits())).unwrap()
65 }
66
67 /// Get the size of a native pointer, in bytes.
68 #[allow(dead_code)]
69 fn pointer_bytes(&self) -> u8 {
70 self.target_config().pointer_bytes()
71 }
72
73 /// Get the Cranelift reference type to use for native references.
74 ///
75 /// This returns the target pointer type for both `funcref` and `externref`.
76 fn reference_type(&self) -> ir::Type {
77 reference_type(self.target_config()).expect("expected reference type")
78 }
79}
80
81/// Environment affecting the translation of a single WebAssembly function.
82///
83/// A `FuncEnvironment` trait object is required to translate a WebAssembly function to Cranelift
84/// IR. The function environment provides information about the WebAssembly module as well as the
85/// runtime environment.
86pub trait FuncEnvironment: TargetEnvironment {
87 /// Whether to enable Spectre mitigations for heap accesses.
88 fn heap_access_spectre_mitigation(&self) -> bool;
89
90 /// Whether to add proof-carrying-code facts to verify memory accesses.
91 fn proof_carrying_code(&self) -> bool;
92
93 /// Is the given parameter of the given function a wasm-level parameter, as opposed to a hidden
94 /// parameter added for use by the implementation?
95 fn is_wasm_parameter(&self, signature: &ir::Signature, index: usize) -> bool {
96 signature.params[index].purpose == ir::ArgumentPurpose::Normal
97 }
98
99 /// Is the given return of the given function a wasm-level parameter, as
100 /// opposed to a hidden parameter added for use by the implementation?
101 fn is_wasm_return(&self, signature: &ir::Signature, index: usize) -> bool {
102 signature.returns[index].purpose == ir::ArgumentPurpose::Normal
103 }
104
105 /// Should the code be structured to use a single `fallthrough_return` instruction at the end
106 /// of the function body, rather than `return` instructions as needed? This is used by VMs
107 /// to append custom epilogues.
108 fn return_mode(&self) -> ReturnMode {
109 ReturnMode::NormalReturns
110 }
111
112 /// Set up the necessary preamble definitions in `func` to access the global variable
113 /// identified by `index`.
114 ///
115 /// The index space covers both imported globals and globals defined by the module.
116 ///
117 /// Return the global variable reference that should be used to access the global and the
118 /// WebAssembly type of the global.
119 fn make_global(
120 &mut self,
121 func: &mut ir::Function,
122 index: GlobalIndex,
123 ) -> WasmResult<GlobalVariable>;
124
125 /// Inserts code before updating a global.
126 fn update_global(
127 &mut self,
128 _builder: &mut FunctionBuilder,
129 _global_index: u32,
130 _value: ir::Value,
131 ) {
132 }
133
134 /// Get the heaps for this function environment.
135 ///
136 /// The returned map should provide heap format details (encoded in
137 /// `HeapData`) for each `Heap` that was previously returned by
138 /// `make_heap()`. The translator will first call make_heap for each Wasm
139 /// memory, and then later when translating code, will invoke `heaps()` to
140 /// learn how to access the environment's implementation of each memory.
141 fn heaps(&self) -> &PrimaryMap<Heap, HeapData>;
142
143 /// Set up the necessary preamble definitions in `func` to access the linear memory identified
144 /// by `index`.
145 ///
146 /// The index space covers both imported and locally declared memories.
147 fn make_heap(&mut self, func: &mut ir::Function, index: MemoryIndex) -> WasmResult<Heap>;
148
149 /// Set up a signature definition in the preamble of `func` that can be used for an indirect
150 /// call with signature `index`.
151 ///
152 /// The signature may contain additional arguments needed for an indirect call, but the
153 /// arguments marked as `ArgumentPurpose::Normal` must correspond to the WebAssembly signature
154 /// arguments.
155 ///
156 /// The signature will only be used for indirect calls, even if the module has direct function
157 /// calls with the same WebAssembly type.
158 fn make_indirect_sig(
159 &mut self,
160 func: &mut ir::Function,
161 index: SignatureIndex,
162 ) -> WasmResult<ir::SigRef>;
163
164 /// Set up an external function definition in the preamble of `func` that can be used to
165 /// directly call the function `index`.
166 ///
167 /// The index space covers both imported functions and functions defined in the current module.
168 ///
169 /// The function's signature may contain additional arguments needed for a direct call, but the
170 /// arguments marked as `ArgumentPurpose::Normal` must correspond to the WebAssembly signature
171 /// arguments.
172 ///
173 /// The function's signature will only be used for direct calls, even if the module has
174 /// indirect calls with the same WebAssembly type.
175 fn make_direct_func(
176 &mut self,
177 func: &mut ir::Function,
178 index: FunctionIndex,
179 ) -> WasmResult<ir::FuncRef>;
180
181 /// Translate a `call` WebAssembly instruction at `pos`.
182 ///
183 /// Insert instructions at `pos` for a direct call to the function `callee_index`.
184 ///
185 /// The function reference `callee` was previously created by `make_direct_func()`.
186 ///
187 /// Return the call instruction whose results are the WebAssembly return values.
188 fn translate_call(
189 &mut self,
190 builder: &mut FunctionBuilder,
191 _callee_index: FunctionIndex,
192 callee: ir::FuncRef,
193 call_args: &[ir::Value],
194 landing_pad: Option<LandingPad>,
195 ) -> WasmResult<SmallVec<[ir::Value; 4]>>;
196
197 /// Translate a `call_indirect` WebAssembly instruction at `pos`.
198 ///
199 /// Insert instructions at `pos` for an indirect call to the function `callee` in the table
200 /// `table_index` with WebAssembly signature `sig_index`. The `callee` value will have type
201 /// `i32`.
202 ///
203 /// The signature `sig_ref` was previously created by `make_indirect_sig()`.
204 ///
205 /// Return the call instruction whose results are the WebAssembly return values.
206 /// Returns `None` if this statically traps instead of creating a call
207 /// instruction.
208 #[allow(clippy::too_many_arguments)]
209 fn translate_call_indirect(
210 &mut self,
211 builder: &mut FunctionBuilder,
212 table_index: TableIndex,
213 sig_index: SignatureIndex,
214 sig_ref: ir::SigRef,
215 callee: ir::Value,
216 call_args: &[ir::Value],
217 landing_pad: Option<LandingPad>,
218 ) -> WasmResult<SmallVec<[ir::Value; 4]>>;
219
220 /// Return the number of WebAssembly values contained in the payload for the given exception tag.
221 fn tag_param_arity(&self, tag_index: TagIndex) -> usize;
222
223 /// Get the exception reference from the raw exception pointer (used by libunwind).
224 fn translate_exn_pointer_to_ref(
225 &mut self,
226 builder: &mut FunctionBuilder,
227 exn_ptr: ir::Value,
228 ) -> ir::Value;
229
230 /// Extract the payload values from an exception reference produced by the given tag.
231 fn translate_exn_unbox(
232 &mut self,
233 builder: &mut FunctionBuilder,
234 tag_index: TagIndex,
235 exnref: ir::Value,
236 ) -> WasmResult<SmallVec<[ir::Value; 4]>>;
237
238 /// Emit IR to allocate and throw a new exception with the specified tag.
239 fn translate_exn_throw(
240 &mut self,
241 builder: &mut FunctionBuilder,
242 tag_index: TagIndex,
243 args: &[ir::Value],
244 landing_pad: Option<LandingPad>,
245 ) -> WasmResult<()>;
246
247 /// Emit IR to rethrow an existing exception reference.
248 fn translate_exn_throw_ref(
249 &mut self,
250 builder: &mut FunctionBuilder,
251 exnref: ir::Value,
252 landing_pad: Option<LandingPad>,
253 ) -> WasmResult<()>;
254
255 /// Invoke the runtime personality helper to choose the matching catch tag for an exception.
256 fn translate_exn_personality_selector(
257 &mut self,
258 builder: &mut FunctionBuilder,
259 exn_ptr: ir::Value,
260 ) -> WasmResult<ir::Value>;
261
262 /// Reraise an exception when no catch clause within the current handler matches.
263 fn translate_exn_reraise_unmatched(
264 &mut self,
265 builder: &mut FunctionBuilder,
266 exnref: ir::Value,
267 ) -> WasmResult<()>;
268
269 /// Translate a `memory.grow` WebAssembly instruction.
270 ///
271 /// The `index` provided identifies the linear memory to grow, and `heap` is the heap reference
272 /// returned by `make_heap` for the same index.
273 ///
274 /// The `val` value is the requested memory size in pages.
275 ///
276 /// Returns the old size (in pages) of the memory.
277 fn translate_memory_grow(
278 &mut self,
279 pos: FuncCursor,
280 index: MemoryIndex,
281 heap: Heap,
282 val: ir::Value,
283 ) -> WasmResult<ir::Value>;
284
285 /// Translates a `memory.size` WebAssembly instruction.
286 ///
287 /// The `index` provided identifies the linear memory to query, and `heap` is the heap reference
288 /// returned by `make_heap` for the same index.
289 ///
290 /// Returns the size in pages of the memory.
291 fn translate_memory_size(
292 &mut self,
293 pos: FuncCursor,
294 index: MemoryIndex,
295 heap: Heap,
296 ) -> WasmResult<ir::Value>;
297
298 /// Translate a `memory.copy` WebAssembly instruction.
299 ///
300 /// The `index` provided identifies the linear memory to query, and `heap` is the heap reference
301 /// returned by `make_heap` for the same index.
302 #[allow(clippy::too_many_arguments)]
303 fn translate_memory_copy(
304 &mut self,
305 pos: FuncCursor,
306 src_index: MemoryIndex,
307 src_heap: Heap,
308 dst_index: MemoryIndex,
309 dst_heap: Heap,
310 dst: ir::Value,
311 src: ir::Value,
312 len: ir::Value,
313 ) -> WasmResult<()>;
314
315 /// Translate a `memory.fill` WebAssembly instruction.
316 ///
317 /// The `index` provided identifies the linear memory to query, and `heap` is the heap reference
318 /// returned by `make_heap` for the same index.
319 fn translate_memory_fill(
320 &mut self,
321 pos: FuncCursor,
322 index: MemoryIndex,
323 heap: Heap,
324 dst: ir::Value,
325 val: ir::Value,
326 len: ir::Value,
327 ) -> WasmResult<()>;
328
329 /// Translate a `memory.init` WebAssembly instruction.
330 ///
331 /// The `index` provided identifies the linear memory to query, and `heap` is the heap reference
332 /// returned by `make_heap` for the same index. `seg_index` is the index of the segment to copy
333 /// from.
334 #[allow(clippy::too_many_arguments)]
335 fn translate_memory_init(
336 &mut self,
337 pos: FuncCursor,
338 index: MemoryIndex,
339 heap: Heap,
340 seg_index: u32,
341 dst: ir::Value,
342 src: ir::Value,
343 len: ir::Value,
344 ) -> WasmResult<()>;
345
346 /// Translate a `data.drop` WebAssembly instruction.
347 fn translate_data_drop(&mut self, pos: FuncCursor, seg_index: u32) -> WasmResult<()>;
348
349 /// Translate a `table.size` WebAssembly instruction.
350 fn translate_table_size(&mut self, pos: FuncCursor, index: TableIndex)
351 -> WasmResult<ir::Value>;
352
353 /// Translate a `table.grow` WebAssembly instruction.
354 fn translate_table_grow(
355 &mut self,
356 pos: FuncCursor,
357 table_index: TableIndex,
358 delta: ir::Value,
359 init_value: ir::Value,
360 ) -> WasmResult<ir::Value>;
361
362 /// Translate a `table.get` WebAssembly instruction.
363 fn translate_table_get(
364 &mut self,
365 builder: &mut FunctionBuilder,
366 table_index: TableIndex,
367 index: ir::Value,
368 ) -> WasmResult<ir::Value>;
369
370 /// Translate a `table.set` WebAssembly instruction.
371 fn translate_table_set(
372 &mut self,
373 builder: &mut FunctionBuilder,
374 table_index: TableIndex,
375 value: ir::Value,
376 index: ir::Value,
377 ) -> WasmResult<()>;
378
379 /// Translate a `table.copy` WebAssembly instruction.
380 #[allow(clippy::too_many_arguments)]
381 fn translate_table_copy(
382 &mut self,
383 pos: FuncCursor,
384 dst_table_index: TableIndex,
385 src_table_index: TableIndex,
386 dst: ir::Value,
387 src: ir::Value,
388 len: ir::Value,
389 ) -> WasmResult<()>;
390
391 /// Translate a `table.fill` WebAssembly instruction.
392 fn translate_table_fill(
393 &mut self,
394 pos: FuncCursor,
395 table_index: TableIndex,
396 dst: ir::Value,
397 val: ir::Value,
398 len: ir::Value,
399 ) -> WasmResult<()>;
400
401 /// Translate a `table.init` WebAssembly instruction.
402 #[allow(clippy::too_many_arguments)]
403 fn translate_table_init(
404 &mut self,
405 pos: FuncCursor,
406 seg_index: u32,
407 table_index: TableIndex,
408 dst: ir::Value,
409 src: ir::Value,
410 len: ir::Value,
411 ) -> WasmResult<()>;
412
413 /// Translate a `elem.drop` WebAssembly instruction.
414 fn translate_elem_drop(&mut self, pos: FuncCursor, seg_index: u32) -> WasmResult<()>;
415
416 /// Translate a `ref.null T` WebAssembly instruction.
417 ///
418 /// By default, translates into a null reference type.
419 ///
420 /// Override this if you don't use Cranelift reference types for all Wasm
421 /// reference types (e.g. you use a raw pointer for `funcref`s) or if the
422 /// null sentinel is not a null reference type pointer for your type. If you
423 /// override this method, then you should also override
424 /// `translate_ref_is_null` as well.
425 fn translate_ref_null(&mut self, mut pos: FuncCursor, ty: HeapType) -> WasmResult<ir::Value> {
426 let _ = ty;
427 Ok(pos.ins().iconst(self.reference_type(), 0))
428 }
429
430 /// Translate a `ref.is_null` WebAssembly instruction.
431 ///
432 /// By default, assumes that `value` is a Cranelift reference type, and that
433 /// a null Cranelift reference type is the null value for all Wasm reference
434 /// types.
435 ///
436 /// If you override this method, you probably also want to override
437 /// `translate_ref_null` as well.
438 fn translate_ref_is_null(
439 &mut self,
440 mut pos: FuncCursor,
441 value: ir::Value,
442 ) -> WasmResult<ir::Value> {
443 let is_null = pos
444 .ins()
445 .icmp_imm(cranelift_codegen::ir::condcodes::IntCC::Equal, value, 0);
446 Ok(pos.ins().uextend(ir::types::I32, is_null))
447 }
448
449 /// Translate a `ref.func` WebAssembly instruction.
450 fn translate_ref_func(
451 &mut self,
452 pos: FuncCursor,
453 func_index: FunctionIndex,
454 ) -> WasmResult<ir::Value>;
455
456 /// Translate a `global.get` WebAssembly instruction at `pos` for a global
457 /// that is custom.
458 fn translate_custom_global_get(
459 &mut self,
460 pos: FuncCursor,
461 global_index: GlobalIndex,
462 ) -> WasmResult<ir::Value>;
463
464 /// Translate a `global.set` WebAssembly instruction at `pos` for a global
465 /// that is custom.
466 fn translate_custom_global_set(
467 &mut self,
468 pos: FuncCursor,
469 global_index: GlobalIndex,
470 val: ir::Value,
471 ) -> WasmResult<()>;
472
473 /// Translate an `i32.atomic.wait` or `i64.atomic.wait` WebAssembly instruction.
474 /// The `index` provided identifies the linear memory containing the value
475 /// to wait on, and `heap` is the heap reference returned by `make_heap`
476 /// for the same index. Whether the waited-on value is 32- or 64-bit can be
477 /// determined by examining the type of `expected`, which must be only I32 or I64.
478 ///
479 /// Returns an i32, which is negative if the helper call failed.
480 fn translate_atomic_wait(
481 &mut self,
482 pos: FuncCursor,
483 index: MemoryIndex,
484 heap: Heap,
485 addr: ir::Value,
486 expected: ir::Value,
487 timeout: ir::Value,
488 ) -> WasmResult<ir::Value>;
489
490 /// Translate an `atomic.notify` WebAssembly instruction.
491 /// The `index` provided identifies the linear memory containing the value
492 /// to wait on, and `heap` is the heap reference returned by `make_heap`
493 /// for the same index.
494 ///
495 /// Returns an i64, which is negative if the helper call failed.
496 fn translate_atomic_notify(
497 &mut self,
498 pos: FuncCursor,
499 index: MemoryIndex,
500 heap: Heap,
501 addr: ir::Value,
502 count: ir::Value,
503 ) -> WasmResult<ir::Value>;
504
505 /// Emit code at the beginning of every wasm loop.
506 ///
507 /// This can be used to insert explicit interrupt or safepoint checking at
508 /// the beginnings of loops.
509 fn translate_loop_header(&mut self, _pos: FuncCursor) -> WasmResult<()> {
510 // By default, don't emit anything.
511 Ok(())
512 }
513
514 /// Optional callback for the `FunctionEnvMutironment` performing this translation to maintain
515 /// internal state or prepare custom state for the operator to translate
516 fn before_translate_operator(
517 &mut self,
518 _op: &Operator,
519 _builder: &mut FunctionBuilder,
520 _state: &FuncTranslationState,
521 ) -> WasmResult<()> {
522 Ok(())
523 }
524
525 /// Optional callback for the `FunctionEnvMutironment` performing this translation to maintain
526 /// internal state or finalize custom state for the operator that was translated
527 fn after_translate_operator(
528 &mut self,
529 _op: &Operator,
530 _builder: &mut FunctionBuilder,
531 _state: &FuncTranslationState,
532 ) -> WasmResult<()> {
533 Ok(())
534 }
535
536 /// Optional callback for the `FuncEnvironment` performing this translation
537 /// to maintain, prepare, or finalize custom, internal state when we
538 /// statically determine that a Wasm memory access will unconditionally
539 /// trap, rendering the rest of the block unreachable. Called just before
540 /// the unconditional trap is emitted.
541 fn before_unconditionally_trapping_memory_access(
542 &mut self,
543 _builder: &mut FunctionBuilder,
544 ) -> WasmResult<()> {
545 Ok(())
546 }
547
548 /// Get the type of the global at the given index.
549 #[allow(dead_code)]
550 fn get_global_type(&self, global_index: GlobalIndex) -> Option<WasmerType>;
551
552 /// Push a local declaration on to the stack to track the type of locals.
553 fn push_local_decl_on_stack(&mut self, ty: WasmerType);
554
555 /// Push locals for a the params of a function on to the stack.
556 fn push_params_on_stack(&mut self, function_index: LocalFunctionIndex);
557
558 /// Get the type of the local at the given index.
559 #[allow(dead_code)]
560 fn get_local_type(&self, local_index: u32) -> Option<WasmerType>;
561
562 /// Get the types of all the current locals.
563 #[allow(dead_code)]
564 fn get_local_types(&self) -> &[WasmerType];
565
566 /// Get the type of the local at the given index.
567 #[allow(dead_code)]
568 fn get_function_type(&self, function_index: FunctionIndex) -> Option<&FunctionType>;
569
570 /// Get the type of a function with the given signature index.
571 #[allow(dead_code)]
572 fn get_function_sig(&self, sig_index: SignatureIndex) -> Option<&FunctionType>;
573
574 /// Inserts code before a function return.
575 fn handle_before_return(&mut self, _retvals: &[ir::Value], _builder: &mut FunctionBuilder) {}
576
577 /// Inserts code before a load.
578 fn before_load(
579 &mut self,
580 _builder: &mut FunctionBuilder,
581 _val_size: u8,
582 _addr: ir::Value,
583 _offset: u64,
584 ) {
585 }
586
587 /// Inserts code before a store.
588 fn before_store(
589 &mut self,
590 _builder: &mut FunctionBuilder,
591 _val_size: u8,
592 _addr: ir::Value,
593 _offset: u64,
594 ) {
595 }
596}