Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasmtime: Implement table.fill #1973

Merged
merged 1 commit into from
Jul 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,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