Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/cranelift/src/translate/table.rs
1692 views
1
use crate::func_environ::FuncEnvironment;
2
use cranelift_codegen::cursor::FuncCursor;
3
use cranelift_codegen::ir::{self, InstBuilder, condcodes::IntCC, immediates::Imm64};
4
use cranelift_codegen::isa::TargetIsa;
5
use cranelift_frontend::FunctionBuilder;
6
7
/// Size of a WebAssembly table, in elements.
8
#[derive(Clone)]
9
pub enum TableSize {
10
/// Non-resizable table.
11
Static {
12
/// Non-resizable tables have a constant size known at compile time.
13
bound: u64,
14
},
15
/// Resizable table.
16
Dynamic {
17
/// Resizable tables declare a Cranelift global value to load the
18
/// current size from.
19
bound_gv: ir::GlobalValue,
20
},
21
}
22
23
impl TableSize {
24
/// Get a CLIF value representing the current bounds of this table.
25
pub fn bound(&self, isa: &dyn TargetIsa, mut pos: FuncCursor, index_ty: ir::Type) -> ir::Value {
26
match *self {
27
// Instead of `i64::try_from(bound)`, here we just want to directly interpret `bound` as an i64.
28
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
/// An implementation of a WebAssembly table.
45
#[derive(Clone)]
46
pub struct TableData {
47
/// Global value giving the address of the start of the table.
48
pub base_gv: ir::GlobalValue,
49
50
/// The size of the table, in elements.
51
pub bound: TableSize,
52
53
/// The size of a table element, in bytes.
54
pub element_size: u32,
55
}
56
57
impl TableData {
58
/// Return a CLIF value containing a native pointer to the beginning of the
59
/// given index within this table.
60
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
// Start with the bounds check. Trap if `index + 1 > bound`.
73
let bound = self.bound.bound(env.isa(), pos.cursor(), index_ty);
74
75
// `index > bound - 1` is the same as `index >= bound`.
76
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
// Convert `index` to `addr_ty`.
85
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
// Add the table base address base
92
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
// Short-circuit the computed table element address to a null pointer
111
// when out-of-bounds. The consumer of this address will trap when
112
// trying to access it.
113
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
}
123
124