wasmtime_cranelift/translate/
table.rs1use crate::func_environ::FuncEnvironment;
2use cranelift_codegen::cursor::FuncCursor;
3use cranelift_codegen::ir::{self, condcodes::IntCC, immediates::Imm64, InstBuilder};
4use cranelift_codegen::isa::TargetIsa;
5use cranelift_frontend::FunctionBuilder;
6
7#[derive(Clone)]
9pub enum TableSize {
10 Static {
12 bound: u64,
14 },
15 Dynamic {
17 bound_gv: ir::GlobalValue,
20 },
21}
22
23impl TableSize {
24 pub fn bound(&self, isa: &dyn TargetIsa, mut pos: FuncCursor, index_ty: ir::Type) -> ir::Value {
26 match *self {
27 TableSize::Static { bound } => pos.ins().iconst(index_ty, Imm64::new(bound as i64)),
29 TableSize::Dynamic { bound_gv } => {
30 let ty = pos.func.global_values[bound_gv].global_type(isa);
31 let gv = pos.ins().global_value(ty, bound_gv);
32 if index_ty == ty {
33 gv
34 } else if index_ty.bytes() < ty.bytes() {
35 pos.ins().ireduce(index_ty, gv)
36 } else {
37 pos.ins().uextend(index_ty, gv)
38 }
39 }
40 }
41 }
42}
43
44#[derive(Clone)]
46pub struct TableData {
47 pub base_gv: ir::GlobalValue,
49
50 pub bound: TableSize,
52
53 pub element_size: u32,
55}
56
57impl TableData {
58 pub fn prepare_table_addr(
61 &self,
62 env: &mut FuncEnvironment<'_>,
63 pos: &mut FunctionBuilder,
64 mut index: ir::Value,
65 ) -> (ir::Value, ir::MemFlags) {
66 let index_ty = pos.func.dfg.value_type(index);
67 let addr_ty = env.pointer_type();
68 let spectre_mitigations_enabled =
69 env.isa().flags().enable_table_access_spectre_mitigation()
70 && env.clif_memory_traps_enabled();
71
72 let bound = self.bound.bound(env.isa(), pos.cursor(), index_ty);
74
75 let oob = pos
77 .ins()
78 .icmp(IntCC::UnsignedGreaterThanOrEqual, index, bound);
79
80 if !spectre_mitigations_enabled {
81 env.trapnz(pos, oob, crate::TRAP_TABLE_OUT_OF_BOUNDS);
82 }
83
84 if addr_ty.bytes() > index_ty.bytes() {
86 index = pos.ins().uextend(addr_ty, index);
87 } else if addr_ty.bytes() < index_ty.bytes() {
88 index = pos.ins().ireduce(addr_ty, index);
89 }
90
91 let base = pos.ins().global_value(addr_ty, self.base_gv);
93
94 let element_size = self.element_size;
95 let offset = if element_size == 1 {
96 index
97 } else if element_size.is_power_of_two() {
98 pos.ins()
99 .ishl_imm(index, i64::from(element_size.trailing_zeros()))
100 } else {
101 pos.ins().imul_imm(index, element_size as i64)
102 };
103
104 let element_addr = pos.ins().iadd(base, offset);
105
106 let base_flags = ir::MemFlags::new()
107 .with_aligned()
108 .with_alias_region(Some(ir::AliasRegion::Table));
109 if spectre_mitigations_enabled {
110 let zero = pos.ins().iconst(addr_ty, 0);
114 (
115 pos.ins().select_spectre_guard(oob, zero, element_addr),
116 base_flags.with_trap_code(Some(crate::TRAP_TABLE_OUT_OF_BOUNDS)),
117 )
118 } else {
119 (element_addr, base_flags.with_trap_code(None))
120 }
121 }
122}