Implement table.init and elem.drop from the bulk memory proposal

This commit is contained in:
Nick Fitzgerald
2020-02-18 16:41:43 -08:00
parent 33b4a37bcb
commit cb97e4ec8e
12 changed files with 352 additions and 55 deletions

View File

@@ -1,7 +1,7 @@
use crate::module::{MemoryPlan, MemoryStyle, ModuleLocal, TableStyle};
use crate::vmoffsets::VMOffsets;
use crate::WASM_PAGE_SIZE;
use cranelift_codegen::cursor::FuncCursor;
use cranelift_codegen::cursor::{Cursor, FuncCursor};
use cranelift_codegen::ir;
use cranelift_codegen::ir::condcodes::*;
use cranelift_codegen::ir::immediates::{Offset32, Uimm64};
@@ -62,9 +62,17 @@ impl BuiltinFunctionIndex {
pub const fn get_table_copy_imported_imported_index() -> Self {
Self(7)
}
/// Returns an index for wasm's `table.init`.
pub const fn get_table_init_index() -> Self {
Self(8)
}
/// Returns an index for wasm's `elem.drop`.
pub const fn get_elem_drop_index() -> Self {
Self(9)
}
/// Returns the total number of builtin functions.
pub const fn builtin_functions_total_number() -> u32 {
8
10
}
/// Return the index as an u32 number.
@@ -96,6 +104,12 @@ pub struct FuncEnvironment<'module_environment> {
/// (it's the same for both local and imported tables).
table_copy_sig: Option<ir::SigRef>,
/// The external function signature for implementing wasm's `table.init`.
table_init_sig: Option<ir::SigRef>,
/// The external function signature for implementing wasm's `elem.drop`.
elem_drop_sig: Option<ir::SigRef>,
/// Offsets to struct fields accessed by JIT code.
offsets: VMOffsets,
}
@@ -112,6 +126,8 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
memory32_size_sig: None,
memory_grow_sig: None,
table_copy_sig: None,
table_init_sig: None,
elem_drop_sig: None,
offsets: VMOffsets::new(target_config.pointer_bytes(), module),
}
}
@@ -294,6 +310,67 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
}
}
fn get_table_init_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.table_init_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
// Table index.
AbiParam::new(I32),
// Segment index.
AbiParam::new(I32),
// Destination index within table.
AbiParam::new(I32),
// Source index within segment.
AbiParam::new(I32),
// Number of elements to initialize.
AbiParam::new(I32),
// Source location.
AbiParam::new(I32),
],
returns: vec![],
call_conv: self.target_config.default_call_conv,
})
});
self.table_init_sig = Some(sig);
sig
}
fn get_table_init_func(
&mut self,
func: &mut Function,
table_index: TableIndex,
) -> (ir::SigRef, usize, BuiltinFunctionIndex) {
let sig = self.get_table_init_sig(func);
let table_index = table_index.as_u32() as usize;
(
sig,
table_index,
BuiltinFunctionIndex::get_table_init_index(),
)
}
fn get_elem_drop_sig(&mut self, func: &mut Function) -> ir::SigRef {
let sig = self.elem_drop_sig.unwrap_or_else(|| {
func.import_signature(Signature {
params: vec![
AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
// Element index.
AbiParam::new(I32),
],
returns: vec![],
call_conv: self.target_config.default_call_conv,
})
});
self.elem_drop_sig = Some(sig);
sig
}
fn get_elem_drop_func(&mut self, func: &mut Function) -> (ir::SigRef, BuiltinFunctionIndex) {
let sig = self.get_elem_drop_sig(func);
(sig, BuiltinFunctionIndex::get_elem_drop_index())
}
/// Translates load of builtin function and returns a pair of values `vmctx`
/// and address of the loaded function.
fn translate_load_builtin_function_address(
@@ -960,8 +1037,6 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
src: ir::Value,
len: ir::Value,
) -> WasmResult<()> {
use cranelift_codegen::cursor::Cursor;
let (func_sig, dst_table_index_arg, src_table_index_arg, func_idx) =
self.get_table_copy_func(&mut pos.func, dst_table_index, src_table_index);
@@ -992,22 +1067,52 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
fn translate_table_init(
&mut self,
_pos: FuncCursor,
_seg_index: u32,
_table_index: TableIndex,
mut pos: FuncCursor,
seg_index: u32,
table_index: TableIndex,
_table: ir::Table,
_dst: ir::Value,
_src: ir::Value,
_len: ir::Value,
dst: ir::Value,
src: ir::Value,
len: ir::Value,
) -> WasmResult<()> {
Err(WasmError::Unsupported(
"bulk memory: `table.init`".to_string(),
))
let (func_sig, table_index_arg, func_idx) =
self.get_table_init_func(&mut pos.func, table_index);
let table_index_arg = pos.ins().iconst(I32, table_index_arg as i64);
let seg_index_arg = pos.ins().iconst(I32, seg_index as i64);
let src_loc = pos.srcloc();
let src_loc_arg = pos.ins().iconst(I32, src_loc.bits() as i64);
let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
pos.ins().call_indirect(
func_sig,
func_addr,
&[
vmctx,
table_index_arg,
seg_index_arg,
dst,
src,
len,
src_loc_arg,
],
);
Ok(())
}
fn translate_elem_drop(&mut self, _pos: FuncCursor, _seg_index: u32) -> WasmResult<()> {
Err(WasmError::Unsupported(
"bulk memory: `elem.drop`".to_string(),
))
fn translate_elem_drop(&mut self, mut pos: FuncCursor, elem_index: u32) -> WasmResult<()> {
let (func_sig, func_idx) = self.get_elem_drop_func(&mut pos.func);
let elem_index_arg = pos.ins().iconst(I32, elem_index as i64);
let (vmctx, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx);
pos.ins()
.call_indirect(func_sig, func_addr, &[vmctx, elem_index_arg]);
Ok(())
}
}