Wasm: Use environment to translate reference types instructions and add support for multiple tables

This commit introduces environment functions to handle the translation of
reference type instructions, analogous to how bulk-memory was implemented.

Additionally, the bulk-memory instructions that operate on tables are extended
to support multiple table indices.
This commit is contained in:
Ryan Hunt
2020-01-06 15:40:15 -06:00
parent 3125431ece
commit f41bf5ecca
3 changed files with 128 additions and 24 deletions

View File

@@ -965,8 +965,8 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let val = builder.ins().is_null(arg); let val = builder.ins().is_null(arg);
state.push1(val); state.push1(val);
} }
Operator::RefFunc { .. } => { Operator::RefFunc { function_index } => {
return Err(wasm_unsupported!("proposed ref operator {:?}", op)) state.push1(environ.translate_ref_func(builder.cursor(), *function_index)?);
} }
Operator::AtomicNotify { .. } Operator::AtomicNotify { .. }
| Operator::I32AtomicWait { .. } | Operator::I32AtomicWait { .. }
@@ -1089,56 +1089,73 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
table, table,
)?); )?);
} }
Operator::TableCopy { .. } => { Operator::TableGrow { table } => {
// The WebAssembly MVP only supports one table and wasmparser will let delta = state.pop1();
// ensure that the table index specified is zero. let init_value = state.pop1();
let dst_table_index = 0; state.push1(environ.translate_table_grow(
let dst_table = state.get_table(builder.func, dst_table_index, environ)?; builder.cursor(),
let src_table_index = 0; *table,
let src_table = state.get_table(builder.func, src_table_index, environ)?; delta,
init_value,
)?);
}
Operator::TableGet { table } => {
let index = state.pop1();
state.push1(environ.translate_table_get(builder.cursor(), *table, index)?);
}
Operator::TableSet { table } => {
let value = state.pop1();
let index = state.pop1();
environ.translate_table_set(builder.cursor(), *table, value, index)?;
}
Operator::TableCopy {
dst_table: dst_table_index,
src_table: src_table_index,
} => {
let dst_table = state.get_table(builder.func, *dst_table_index, environ)?;
let src_table = state.get_table(builder.func, *src_table_index, environ)?;
let len = state.pop1(); let len = state.pop1();
let src = state.pop1(); let src = state.pop1();
let dest = state.pop1(); let dest = state.pop1();
environ.translate_table_copy( environ.translate_table_copy(
builder.cursor(), builder.cursor(),
TableIndex::from_u32(dst_table_index), TableIndex::from_u32(*dst_table_index),
dst_table, dst_table,
TableIndex::from_u32(src_table_index), TableIndex::from_u32(*src_table_index),
src_table, src_table,
dest, dest,
src, src,
len, len,
)?; )?;
} }
Operator::TableInit { segment, table: _ } => { Operator::TableFill { table } => {
let len = state.pop1();
let val = state.pop1();
let dest = state.pop1();
environ.translate_table_fill(builder.cursor(), *table, dest, val, len)?;
}
Operator::TableInit {
segment,
table: table_index,
} => {
// The WebAssembly MVP only supports one table and we assume it here. // The WebAssembly MVP only supports one table and we assume it here.
let table_index = 0; let table = state.get_table(builder.func, *table_index, environ)?;
let table = state.get_table(builder.func, table_index, environ)?;
let len = state.pop1(); let len = state.pop1();
let src = state.pop1(); let src = state.pop1();
let dest = state.pop1(); let dest = state.pop1();
environ.translate_table_init( environ.translate_table_init(
builder.cursor(), builder.cursor(),
*segment, *segment,
TableIndex::from_u32(table_index), TableIndex::from_u32(*table_index),
table, table,
dest, dest,
src, src,
len, len,
)?; )?;
} }
Operator::TableFill { .. } => {
return Err(wasm_unsupported!("proposed table operator {:?}", op));
}
Operator::ElemDrop { segment } => { Operator::ElemDrop { segment } => {
environ.translate_elem_drop(builder.cursor(), *segment)?; environ.translate_elem_drop(builder.cursor(), *segment)?;
} }
Operator::TableGet { .. } | Operator::TableSet { .. } | Operator::TableGrow { .. } => {
return Err(wasm_unsupported!(
"proposed reference types operator {:?}",
op
));
}
Operator::V128Const { value } => { Operator::V128Const { value } => {
let data = value.bytes().to_vec().into(); let data = value.bytes().to_vec().into();
let handle = builder.func.dfg.constants.insert(data); let handle = builder.func.dfg.constants.insert(data);

View File

@@ -426,6 +426,35 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
Ok(pos.ins().iconst(I32, -1)) Ok(pos.ins().iconst(I32, -1))
} }
fn translate_table_grow(
&mut self,
mut pos: FuncCursor,
_table_index: u32,
_delta: ir::Value,
_init_value: ir::Value,
) -> WasmResult<ir::Value> {
Ok(pos.ins().iconst(I32, -1))
}
fn translate_table_get(
&mut self,
mut pos: FuncCursor,
_table_index: u32,
_index: ir::Value,
) -> WasmResult<ir::Value> {
Ok(pos.ins().null(self.reference_type()))
}
fn translate_table_set(
&mut self,
_pos: FuncCursor,
_table_index: u32,
_value: ir::Value,
_index: ir::Value,
) -> WasmResult<()> {
Ok(())
}
fn translate_table_copy( fn translate_table_copy(
&mut self, &mut self,
_pos: FuncCursor, _pos: FuncCursor,
@@ -440,6 +469,17 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
Ok(()) Ok(())
} }
fn translate_table_fill(
&mut self,
_pos: FuncCursor,
_table_index: u32,
_dst: ir::Value,
_val: ir::Value,
_len: ir::Value,
) -> WasmResult<()> {
Ok(())
}
fn translate_table_init( fn translate_table_init(
&mut self, &mut self,
_pos: FuncCursor, _pos: FuncCursor,
@@ -456,6 +496,14 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
fn translate_elem_drop(&mut self, _pos: FuncCursor, _seg_index: u32) -> WasmResult<()> { fn translate_elem_drop(&mut self, _pos: FuncCursor, _seg_index: u32) -> WasmResult<()> {
Ok(()) Ok(())
} }
fn translate_ref_func(
&mut self,
mut pos: FuncCursor,
_func_index: u32,
) -> WasmResult<ir::Value> {
Ok(pos.ins().null(self.reference_type()))
}
} }
impl TargetEnvironment for DummyEnvironment { impl TargetEnvironment for DummyEnvironment {

View File

@@ -337,6 +337,32 @@ pub trait FuncEnvironment: TargetEnvironment {
table: ir::Table, table: ir::Table,
) -> WasmResult<ir::Value>; ) -> WasmResult<ir::Value>;
/// Translate a `table.grow` WebAssembly instruction.
fn translate_table_grow(
&mut self,
pos: FuncCursor,
table_index: u32,
delta: ir::Value,
init_value: ir::Value,
) -> WasmResult<ir::Value>;
/// Translate a `table.get` WebAssembly instruction.
fn translate_table_get(
&mut self,
pos: FuncCursor,
table_index: u32,
index: ir::Value,
) -> WasmResult<ir::Value>;
/// Translate a `table.set` WebAssembly instruction.
fn translate_table_set(
&mut self,
pos: FuncCursor,
table_index: u32,
value: ir::Value,
index: ir::Value,
) -> WasmResult<()>;
/// Translate a `table.copy` WebAssembly instruction. /// Translate a `table.copy` WebAssembly instruction.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn translate_table_copy( fn translate_table_copy(
@@ -351,6 +377,16 @@ pub trait FuncEnvironment: TargetEnvironment {
len: ir::Value, len: ir::Value,
) -> WasmResult<()>; ) -> WasmResult<()>;
/// Translate a `table.fill` WebAssembly instruction.
fn translate_table_fill(
&mut self,
pos: FuncCursor,
table_index: u32,
dst: ir::Value,
val: ir::Value,
len: ir::Value,
) -> WasmResult<()>;
/// Translate a `table.init` WebAssembly instruction. /// Translate a `table.init` WebAssembly instruction.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn translate_table_init( fn translate_table_init(
@@ -367,6 +403,9 @@ pub trait FuncEnvironment: TargetEnvironment {
/// Translate a `elem.drop` WebAssembly instruction. /// Translate a `elem.drop` WebAssembly instruction.
fn translate_elem_drop(&mut self, pos: FuncCursor, seg_index: u32) -> WasmResult<()>; fn translate_elem_drop(&mut self, pos: FuncCursor, seg_index: u32) -> WasmResult<()>;
/// Translate a `ref.func` WebAssembly instruction.
fn translate_ref_func(&mut self, pos: FuncCursor, func_index: u32) -> WasmResult<ir::Value>;
/// Emit code at the beginning of every wasm loop. /// Emit code at the beginning of every wasm loop.
/// ///
/// This can be used to insert explicit interrupt or safepoint checking at /// This can be used to insert explicit interrupt or safepoint checking at