Skip to content

Commit 65a434a

Browse files
committed
Implement the table64 extension to the memory64 proposal
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 bc8b17a commit 65a434a

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)