Skip to content

Commit

Permalink
wasmtime: Implement table.fill
Browse files Browse the repository at this point in the history
  • Loading branch information
fitzgen committed Jul 2, 2020
1 parent b04bd00 commit 0c63abb
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 13 deletions.
5 changes: 0 additions & 5 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,6 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
("simd", "simd_load") => return true, // FIXME Unsupported feature: proposed SIMD operator I32x4TruncSatF32x4S
("simd", "simd_splat") => return true, // FIXME Unsupported feature: proposed SIMD operator I32x4TruncSatF32x4S

// Still working on implementing these. See #929.
("reference_types", "table_fill") => {
return true;
}

// TODO(#1886): Ignore reference types tests if this isn't x64,
// because Cranelift only supports reference types on x64.
("reference_types", _) => {
Expand Down
46 changes: 38 additions & 8 deletions crates/environ/src/func_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ declare_builtin_functions! {
table_grow_funcref(vmctx, i32, i32, pointer) -> (i32);
/// Returns an index for Wasm's `table.grow` instruction for `externref`s.
table_grow_externref(vmctx, i32, i32, reference) -> (i32);
/// Returns an index for Wasm's `table.fill` instruction for `externref`s.
table_fill_externref(vmctx, i32, i32, reference, i32) -> ();
/// Returns an index for Wasm's `table.fill` instruction for `funcref`s.
table_fill_funcref(vmctx, i32, i32, pointer, i32) -> ();
/// Returns an index to drop a `VMExternRef`.
drop_externref(pointer) -> ();
/// Returns an index to do a GC and then insert a `VMExternRef` into the
Expand Down Expand Up @@ -1009,15 +1013,41 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m

fn translate_table_fill(
&mut self,
_: cranelift_codegen::cursor::FuncCursor<'_>,
_: TableIndex,
_: ir::Value,
_: ir::Value,
_: ir::Value,
mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
table_index: TableIndex,
dst: ir::Value,
val: ir::Value,
len: ir::Value,
) -> WasmResult<()> {
Err(WasmError::Unsupported(
"the `table.fill` instruction is not supported yet".into(),
))
let (builtin_idx, builtin_sig) =
match self.module.table_plans[table_index].table.wasm_ty {
WasmType::FuncRef => (
BuiltinFunctionIndex::table_fill_funcref(),
self.builtin_function_signatures
.table_fill_funcref(&mut pos.func),
),
WasmType::ExternRef => (
BuiltinFunctionIndex::table_fill_externref(),
self.builtin_function_signatures
.table_fill_externref(&mut pos.func),
),
_ => return Err(WasmError::Unsupported(
"`table.fill` with a table element type that is not `funcref` or `externref`"
.into(),
)),
};

let (vmctx, builtin_addr) =
self.translate_load_builtin_function_address(&mut pos, builtin_idx);

let table_index_arg = pos.ins().iconst(I32, table_index.as_u32() as i64);
pos.ins().call_indirect(
builtin_sig,
builtin_addr,
&[vmctx, table_index_arg, dst, val, len],
);

Ok(())
}

fn translate_ref_null(
Expand Down
35 changes: 35 additions & 0 deletions crates/runtime/src/libcalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,41 @@ pub unsafe extern "C" fn wasmtime_table_grow(
}
}

/// Implementation of `table.fill`.
pub unsafe extern "C" fn wasmtime_table_fill(
vmctx: *mut VMContext,
table_index: u32,
dst: u32,
// NB: we don't know whether this is a `VMExternRef` or a pointer to a
// `VMCallerCheckedAnyfunc` until we look at the table's element type.
val: *mut u8,
len: u32,
) {
let result = {
let instance = (&mut *vmctx).instance();
let table_index = TableIndex::from_u32(table_index);
let table = instance.get_table(table_index);
match table.element_type() {
TableElementType::Func => {
let val = val as *mut VMCallerCheckedAnyfunc;
table.fill(dst, val.into(), len)
}
TableElementType::Val(ty) => {
debug_assert_eq!(ty, crate::ref_type());
let val = if val.is_null() {
None
} else {
Some(VMExternRef::clone_from_raw(val))
};
table.fill(dst, val.into(), len)
}
}
};
if let Err(trap) = result {
raise_lib_trap(trap);
}
}

/// Implementation of `table.copy`.
pub unsafe extern "C" fn wasmtime_table_copy(
vmctx: *mut VMContext,
Expand Down
20 changes: 20 additions & 0 deletions crates/runtime/src/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@ impl Table {
}
}

/// Fill `table[dst..dst + len]` with `val`.
///
/// Returns a trap error on out-of-bounds accesses.
pub fn fill(&self, dst: u32, val: TableElement, len: u32) -> Result<(), Trap> {
let start = dst;
let end = start
.checked_add(len)
.ok_or_else(|| Trap::wasm(ir::TrapCode::TableOutOfBounds))?;

if end > self.size() {
return Err(Trap::wasm(ir::TrapCode::TableOutOfBounds));
}

for i in start..end {
self.set(i, val.clone()).unwrap();
}

Ok(())
}

/// Grow table by the specified amount of elements.
///
/// Returns the previous size of the table if growth is successful.
Expand Down
4 changes: 4 additions & 0 deletions crates/runtime/src/vmcontext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,10 @@ impl VMBuiltinFunctionsArray {
wasmtime_externref_global_get as usize;
ptrs[BuiltinFunctionIndex::externref_global_set().index() as usize] =
wasmtime_externref_global_set as usize;
ptrs[BuiltinFunctionIndex::table_fill_externref().index() as usize] =
wasmtime_table_fill as usize;
ptrs[BuiltinFunctionIndex::table_fill_funcref().index() as usize] =
wasmtime_table_fill as usize;

if cfg!(debug_assertions) {
for i in 0..ptrs.len() {
Expand Down

0 comments on commit 0c63abb

Please sign in to comment.