wasmer_compiler_cranelift/
table.rs1use cranelift_codegen::cursor::FuncCursor;
2use cranelift_codegen::ir::{self, InstBuilder, condcodes::IntCC, immediates::Imm64};
3use cranelift_frontend::FunctionBuilder;
4
5#[derive(Clone, Debug)]
7pub enum TableSize {
8 Static {
10 bound: u32,
12 },
13 Dynamic {
15 bound_gv: ir::GlobalValue,
18 },
19}
20
21impl TableSize {
22 pub fn bound(&self, mut pos: FuncCursor, index_ty: ir::Type) -> ir::Value {
24 match *self {
25 Self::Static { bound } => pos.ins().iconst(index_ty, Imm64::new(i64::from(bound))),
26 Self::Dynamic { bound_gv } => pos.ins().global_value(index_ty, bound_gv),
27 }
28 }
29}
30
31#[derive(Clone, Debug)]
33pub struct TableData {
34 pub base_gv: ir::GlobalValue,
36
37 pub base_offset: i32,
39
40 pub bound: TableSize,
42
43 pub element_size: u32,
45
46 pub inline_anyfunc: bool,
48}
49
50impl TableData {
51 pub fn prepare_table_addr(
54 &self,
55 pos: &mut FunctionBuilder,
56 mut index: ir::Value,
57 addr_ty: ir::Type,
58 enable_table_access_spectre_mitigation: bool,
59 ) -> (ir::Value, ir::MemFlags) {
60 let index_ty = pos.func.dfg.value_type(index);
61
62 let bound = self.bound.bound(pos.cursor(), index_ty);
64
65 let oob = pos
67 .ins()
68 .icmp(IntCC::UnsignedGreaterThanOrEqual, index, bound);
69
70 if !enable_table_access_spectre_mitigation {
71 pos.ins().trapnz(oob, crate::TRAP_TABLE_OUT_OF_BOUNDS);
72 }
73
74 if index_ty != addr_ty {
76 index = pos.ins().uextend(addr_ty, index);
77 }
78
79 let mut base = pos.ins().global_value(addr_ty, self.base_gv);
81 if self.base_offset != 0 {
82 base = pos.ins().iadd_imm(base, i64::from(self.base_offset));
83 }
84
85 let element_size = self.element_size;
86 let offset = if element_size == 1 {
87 index
88 } else if element_size.is_power_of_two() {
89 pos.ins()
90 .ishl_imm(index, i64::from(element_size.trailing_zeros()))
91 } else {
92 pos.ins().imul_imm(index, element_size as i64)
93 };
94
95 let element_addr = pos.ins().iadd(base, offset);
96
97 let base_flags = ir::MemFlags::new()
98 .with_aligned()
99 .with_alias_region(Some(ir::AliasRegion::Table));
100 if enable_table_access_spectre_mitigation {
101 let zero = pos.ins().iconst(addr_ty, 0);
105 (
106 pos.ins().select_spectre_guard(oob, zero, element_addr),
107 base_flags.with_trap_code(Some(crate::TRAP_TABLE_OUT_OF_BOUNDS)),
108 )
109 } else {
110 (element_addr, base_flags.with_trap_code(None))
111 }
112 }
113}