Skip to content

Commit df69b9a

Browse files
authored
Implement the table64 extension to the memory64 proposal (#9206)
This commit implements the table64 extention in both Wasmtime and Cranelift. Most of the work was changing a bunch of u32 values to u64/usize. The decisions were made in align with the PR #3153 which implemented the memory64 propsal itself. One significant change was the introduction of `IndexType` and `Limits` which streamline and unify the handling of limits for both memories and tables. The spec and fuzzing tests related to table64 are re-enabled which provides a good coverage of the feature.
1 parent 4f906bc commit df69b9a

67 files changed

Lines changed: 1252 additions & 1023 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cranelift/wasm/src/environ/dummy.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
761761
&mut self,
762762
_table_index: TableIndex,
763763
_base: Option<GlobalIndex>,
764-
_offset: u32,
764+
_offset: u64,
765765
_elements: Box<[FuncIndex]>,
766766
) -> WasmResult<()> {
767767
// We do nothing

cranelift/wasm/src/environ/spec.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,7 @@ pub trait ModuleEnvironment<'data>: TypeConvert {
833833
&mut self,
834834
table_index: TableIndex,
835835
base: Option<GlobalIndex>,
836-
offset: u32,
836+
offset: u64,
837837
elements: Box<[FuncIndex]>,
838838
) -> WasmResult<()>;
839839

cranelift/wasm/src/sections_translator.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::{
1414
TypeIndex, WasmError, WasmResult,
1515
};
1616
use cranelift_entity::packed_option::ReservedValue;
17-
use cranelift_entity::EntityRef;
17+
use cranelift_entity::{EntityRef, Unsigned};
1818
use std::boxed::Box;
1919
use std::vec::Vec;
2020
use wasmparser::{
@@ -185,7 +185,7 @@ pub fn parse_export_section<'data>(
185185
// The input has already been validated, so we should be able to
186186
// assume valid UTF-8 and use `from_utf8_unchecked` if performance
187187
// becomes a concern here.
188-
let index = index as usize;
188+
let index = usize::try_from(index)?;
189189
match *kind {
190190
ExternalKind::Func => environ.declare_func_export(FuncIndex::new(index), name)?,
191191
ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), name)?,
@@ -252,7 +252,8 @@ pub fn parse_element_section<'data>(
252252
} => {
253253
let mut offset_expr_reader = offset_expr.get_binary_reader();
254254
let (base, offset) = match offset_expr_reader.read_operator()? {
255-
Operator::I32Const { value } => (None, value as u32),
255+
Operator::I32Const { value } => (None, u64::from(value.unsigned())),
256+
Operator::I64Const { value } => (None, value.unsigned()),
256257
Operator::GlobalGet { global_index } => {
257258
(Some(GlobalIndex::from_u32(global_index)), 0)
258259
}
@@ -271,7 +272,7 @@ pub fn parse_element_section<'data>(
271272
)?
272273
}
273274
ElementKind::Passive => {
274-
let index = ElemIndex::from_u32(index as u32);
275+
let index = ElemIndex::from_u32(u32::try_from(index)?);
275276
environ.declare_passive_element(index, segments)?;
276277
}
277278
ElementKind::Declared => {
@@ -302,8 +303,8 @@ pub fn parse_data_section<'data>(
302303
} => {
303304
let mut offset_expr_reader = offset_expr.get_binary_reader();
304305
let (base, offset) = match offset_expr_reader.read_operator()? {
305-
Operator::I32Const { value } => (None, value as u64),
306-
Operator::I64Const { value } => (None, value as u64),
306+
Operator::I32Const { value } => (None, u64::try_from(value)?),
307+
Operator::I64Const { value } => (None, u64::try_from(value)?),
307308
Operator::GlobalGet { global_index } => {
308309
(Some(GlobalIndex::from_u32(global_index)), 0)
309310
}
@@ -322,7 +323,7 @@ pub fn parse_data_section<'data>(
322323
)?;
323324
}
324325
DataKind::Passive => {
325-
let index = DataIndex::from_u32(index as u32);
326+
let index = DataIndex::from_u32(u32::try_from(index)?);
326327
environ.declare_passive_data(index, data)?;
327328
}
328329
}

cranelift/wasm/src/table.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use cranelift_codegen::cursor::FuncCursor;
22
use cranelift_codegen::ir::{self, condcodes::IntCC, immediates::Imm64, InstBuilder};
3+
use cranelift_codegen::isa::TargetIsa;
34
use cranelift_frontend::FunctionBuilder;
45

56
/// Size of a WebAssembly table, in elements.
@@ -8,7 +9,7 @@ pub enum TableSize {
89
/// Non-resizable table.
910
Static {
1011
/// Non-resizable tables have a constant size known at compile time.
11-
bound: u32,
12+
bound: u64,
1213
},
1314
/// Resizable table.
1415
Dynamic {
@@ -20,10 +21,21 @@ pub enum TableSize {
2021

2122
impl TableSize {
2223
/// Get a CLIF value representing the current bounds of this table.
23-
pub fn bound(&self, mut pos: FuncCursor, index_ty: ir::Type) -> ir::Value {
24+
pub fn bound(&self, isa: &dyn TargetIsa, mut pos: FuncCursor, index_ty: ir::Type) -> ir::Value {
2425
match *self {
25-
TableSize::Static { bound } => pos.ins().iconst(index_ty, Imm64::new(i64::from(bound))),
26-
TableSize::Dynamic { bound_gv } => pos.ins().global_value(index_ty, bound_gv),
26+
// Instead of `i64::try_from(bound)`, here we just want to direcly interpret `bound` as an i64.
27+
TableSize::Static { bound } => pos.ins().iconst(index_ty, Imm64::new(bound as i64)),
28+
TableSize::Dynamic { bound_gv } => {
29+
let ty = pos.func.global_values[bound_gv].global_type(isa);
30+
let gv = pos.ins().global_value(ty, bound_gv);
31+
if index_ty == ty {
32+
gv
33+
} else if index_ty.bytes() < ty.bytes() {
34+
pos.ins().ireduce(index_ty, gv)
35+
} else {
36+
pos.ins().uextend(index_ty, gv)
37+
}
38+
}
2739
}
2840
}
2941
}
@@ -46,22 +58,22 @@ impl TableData {
4658
/// given index within this table.
4759
pub fn prepare_table_addr(
4860
&self,
61+
isa: &dyn TargetIsa,
4962
pos: &mut FunctionBuilder,
5063
mut index: ir::Value,
51-
addr_ty: ir::Type,
52-
enable_table_access_spectre_mitigation: bool,
5364
) -> (ir::Value, ir::MemFlags) {
5465
let index_ty = pos.func.dfg.value_type(index);
66+
let addr_ty = isa.pointer_type();
5567

5668
// Start with the bounds check. Trap if `index + 1 > bound`.
57-
let bound = self.bound.bound(pos.cursor(), index_ty);
69+
let bound = self.bound.bound(isa, pos.cursor(), index_ty);
5870

5971
// `index > bound - 1` is the same as `index >= bound`.
6072
let oob = pos
6173
.ins()
6274
.icmp(IntCC::UnsignedGreaterThanOrEqual, index, bound);
6375

64-
if !enable_table_access_spectre_mitigation {
76+
if !isa.flags().enable_table_access_spectre_mitigation() {
6577
pos.ins().trapnz(oob, ir::TrapCode::TableOutOfBounds);
6678
}
6779

@@ -88,7 +100,7 @@ impl TableData {
88100
let base_flags = ir::MemFlags::new()
89101
.with_aligned()
90102
.with_alias_region(Some(ir::AliasRegion::Table));
91-
if enable_table_access_spectre_mitigation {
103+
if isa.flags().enable_table_access_spectre_mitigation() {
92104
// Short-circuit the computed table element address to a null pointer
93105
// when out-of-bounds. The consumer of this address will trap when
94106
// trying to access it.

crates/c-api/include/wasmtime/table.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ wasmtime_table_type(const wasmtime_context_t *store,
5757
*/
5858
WASM_API_EXTERN bool wasmtime_table_get(wasmtime_context_t *store,
5959
const wasmtime_table_t *table,
60-
uint32_t index, wasmtime_val_t *val);
60+
uint64_t index, wasmtime_val_t *val);
6161

6262
/**
6363
* \brief Sets a value in a table.
@@ -74,12 +74,12 @@ WASM_API_EXTERN bool wasmtime_table_get(wasmtime_context_t *store,
7474
*/
7575
WASM_API_EXTERN wasmtime_error_t *
7676
wasmtime_table_set(wasmtime_context_t *store, const wasmtime_table_t *table,
77-
uint32_t index, const wasmtime_val_t *value);
77+
uint64_t index, const wasmtime_val_t *value);
7878

7979
/**
8080
* \brief Returns the size, in elements, of the specified table
8181
*/
82-
WASM_API_EXTERN uint32_t wasmtime_table_size(const wasmtime_context_t *store,
82+
WASM_API_EXTERN uint64_t wasmtime_table_size(const wasmtime_context_t *store,
8383
const wasmtime_table_t *table);
8484

8585
/**
@@ -101,8 +101,8 @@ WASM_API_EXTERN uint32_t wasmtime_table_size(const wasmtime_context_t *store,
101101
*/
102102
WASM_API_EXTERN wasmtime_error_t *
103103
wasmtime_table_grow(wasmtime_context_t *store, const wasmtime_table_t *table,
104-
uint32_t delta, const wasmtime_val_t *init,
105-
uint32_t *prev_size);
104+
uint64_t delta, const wasmtime_val_t *init,
105+
uint64_t *prev_size);
106106

107107
#ifdef __cplusplus
108108
} // extern "C"

crates/c-api/src/store.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ pub extern "C" fn wasmtime_store_limiter(
180180
limiter = limiter.memory_size(memory_size as usize);
181181
}
182182
if table_elements >= 0 {
183-
limiter = limiter.table_elements(table_elements as u32);
183+
limiter = limiter.table_elements(table_elements as usize);
184184
}
185185
if instances >= 0 {
186186
limiter = limiter.instances(instances as usize);

crates/c-api/src/table.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ pub unsafe extern "C" fn wasm_table_get(
6767
index: wasm_table_size_t,
6868
) -> Option<Box<wasm_ref_t>> {
6969
let table = t.table();
70-
let r = table.get(t.ext.store.context_mut(), index)?;
70+
let r = table.get(t.ext.store.context_mut(), u64::from(index))?;
7171
wasm_ref_t::new(r)
7272
}
7373

@@ -79,14 +79,16 @@ pub unsafe extern "C" fn wasm_table_set(
7979
) -> bool {
8080
let table = t.table();
8181
let val = option_wasm_ref_t_to_ref(r, &table.ty(t.ext.store.context()));
82-
table.set(t.ext.store.context_mut(), index, val).is_ok()
82+
table
83+
.set(t.ext.store.context_mut(), u64::from(index), val)
84+
.is_ok()
8385
}
8486

8587
#[no_mangle]
8688
pub unsafe extern "C" fn wasm_table_size(t: &wasm_table_t) -> wasm_table_size_t {
8789
let table = t.table();
8890
let store = t.ext.store.context();
89-
table.size(&store)
91+
u32::try_from(table.size(&store)).unwrap()
9092
}
9193

9294
#[no_mangle]
@@ -97,7 +99,9 @@ pub unsafe extern "C" fn wasm_table_grow(
9799
) -> bool {
98100
let table = t.table();
99101
let init = option_wasm_ref_t_to_ref(init, &table.ty(t.ext.store.context()));
100-
table.grow(t.ext.store.context_mut(), delta, init).is_ok()
102+
table
103+
.grow(t.ext.store.context_mut(), u64::from(delta), init)
104+
.is_ok()
101105
}
102106

103107
#[no_mangle]
@@ -139,7 +143,7 @@ pub unsafe extern "C" fn wasmtime_table_type(
139143
pub extern "C" fn wasmtime_table_get(
140144
store: WasmtimeStoreContextMut<'_>,
141145
table: &Table,
142-
index: u32,
146+
index: u64,
143147
ret: &mut MaybeUninit<wasmtime_val_t>,
144148
) -> bool {
145149
let mut scope = RootScope::new(store);
@@ -156,7 +160,7 @@ pub extern "C" fn wasmtime_table_get(
156160
pub unsafe extern "C" fn wasmtime_table_set(
157161
mut store: WasmtimeStoreContextMut<'_>,
158162
table: &Table,
159-
index: u32,
163+
index: u64,
160164
val: &wasmtime_val_t,
161165
) -> Option<Box<wasmtime_error_t>> {
162166
let mut scope = RootScope::new(&mut store);
@@ -170,17 +174,17 @@ pub unsafe extern "C" fn wasmtime_table_set(
170174
}
171175

172176
#[no_mangle]
173-
pub extern "C" fn wasmtime_table_size(store: WasmtimeStoreContext<'_>, table: &Table) -> u32 {
177+
pub extern "C" fn wasmtime_table_size(store: WasmtimeStoreContext<'_>, table: &Table) -> u64 {
174178
table.size(store)
175179
}
176180

177181
#[no_mangle]
178182
pub unsafe extern "C" fn wasmtime_table_grow(
179183
mut store: WasmtimeStoreContextMut<'_>,
180184
table: &Table,
181-
delta: u32,
185+
delta: u64,
182186
val: &wasmtime_val_t,
183-
prev_size: &mut u32,
187+
prev_size: &mut u64,
184188
) -> Option<Box<wasmtime_error_t>> {
185189
let mut scope = RootScope::new(&mut store);
186190
handle_result(

crates/c-api/src/types/table.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ pub extern "C" fn wasm_tabletype_element(tt: &wasm_tabletype_t) -> &wasm_valtype
7474
pub extern "C" fn wasm_tabletype_limits(tt: &wasm_tabletype_t) -> &wasm_limits_t {
7575
let tt = tt.ty();
7676
tt.limits_cache.get_or_init(|| wasm_limits_t {
77-
min: tt.ty.minimum(),
78-
max: tt.ty.maximum().unwrap_or(u32::max_value()),
77+
min: u32::try_from(tt.ty.minimum()).unwrap(),
78+
max: u32::try_from(tt.ty.maximum().unwrap_or(u64::from(u32::MAX))).unwrap(),
7979
})
8080
}
8181

crates/cli-flags/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ wasmtime_option_group! {
118118

119119
/// The maximum table elements for any table defined in a module when
120120
/// using the pooling allocator.
121-
pub pooling_table_elements: Option<u32>,
121+
pub pooling_table_elements: Option<usize>,
122122

123123
/// The maximum size, in bytes, allocated for a core instance's metadata
124124
/// when using the pooling allocator.
@@ -215,7 +215,7 @@ wasmtime_option_group! {
215215
/// WebAssembly modules to return -1 and fail.
216216
pub max_memory_size: Option<usize>,
217217
/// Maximum size, in table elements, that a table is allowed to reach.
218-
pub max_table_elements: Option<u32>,
218+
pub max_table_elements: Option<usize>,
219219
/// Maximum number of WebAssembly instances allowed to be created.
220220
pub max_instances: Option<usize>,
221221
/// Maximum number of WebAssembly tables allowed to be created.

0 commit comments

Comments
 (0)