From 78769a13aa4ab5875cabb4d307dfaea20771a106 Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Fri, 6 Dec 2019 09:13:53 -0600 Subject: [PATCH] Add hooks for implementing bulk-memory-operations (#1258) --- cranelift-wasm/src/code_translator.rs | 110 +++++++++++++++++++++++--- cranelift-wasm/src/environ/dummy.rs | 81 +++++++++++++++++++ cranelift-wasm/src/environ/spec.rs | 83 +++++++++++++++++++ 3 files changed, 262 insertions(+), 12 deletions(-) diff --git a/cranelift-wasm/src/code_translator.rs b/cranelift-wasm/src/code_translator.rs index 2f645f500..9bb4b0379 100644 --- a/cranelift-wasm/src/code_translator.rs +++ b/cranelift-wasm/src/code_translator.rs @@ -987,18 +987,104 @@ pub fn translate_operator( | Operator::Fence { .. } => { return Err(wasm_unsupported!("proposed thread operator {:?}", op)); } - Operator::MemoryInit { .. } - | Operator::DataDrop { .. } - | Operator::MemoryCopy - | Operator::MemoryFill - | Operator::TableInit { .. } - | Operator::ElemDrop { .. } - | Operator::TableCopy - | Operator::TableGet { .. } - | Operator::TableSet { .. } - | Operator::TableGrow { .. } - | Operator::TableSize { .. } => { - return Err(wasm_unsupported!("proposed bulk memory operator {:?}", op)); + Operator::MemoryCopy => { + // The WebAssembly MVP only supports one linear memory and + // wasmparser will ensure that the memory indices specified are + // zero. + let heap_index = MemoryIndex::from_u32(0); + let heap = state.get_heap(builder.func, 0, environ)?; + let len = state.pop1(); + let src = state.pop1(); + let dest = state.pop1(); + environ.translate_memory_copy(builder.cursor(), heap_index, heap, dest, src, len)?; + } + Operator::MemoryFill => { + // The WebAssembly MVP only supports one linear memory and + // wasmparser will ensure that the memory index specified is + // zero. + let heap_index = MemoryIndex::from_u32(0); + let heap = state.get_heap(builder.func, 0, environ)?; + let len = state.pop1(); + let val = state.pop1(); + let dest = state.pop1(); + environ.translate_memory_fill(builder.cursor(), heap_index, heap, dest, val, len)?; + } + Operator::MemoryInit { segment } => { + // The WebAssembly MVP only supports one linear memory and + // wasmparser will ensure that the memory index specified is + // zero. + let heap_index = MemoryIndex::from_u32(0); + let heap = state.get_heap(builder.func, 0, environ)?; + let len = state.pop1(); + let src = state.pop1(); + let dest = state.pop1(); + environ.translate_memory_init( + builder.cursor(), + heap_index, + heap, + *segment, + dest, + src, + len, + )?; + } + Operator::DataDrop { segment } => { + environ.translate_data_drop(builder.cursor(), *segment)?; + } + Operator::TableSize { table: index } => { + let table = state.get_table(builder.func, *index, environ)?; + state.push1(environ.translate_table_size( + builder.cursor(), + TableIndex::from_u32(*index), + table, + )?); + } + Operator::TableCopy => { + // The WebAssembly MVP only supports one table and wasmparser will + // ensure that the table index specified is zero. + let dst_table_index = 0; + let dst_table = state.get_table(builder.func, dst_table_index, environ)?; + let src_table_index = 0; + let src_table = state.get_table(builder.func, src_table_index, environ)?; + let len = state.pop1(); + let src = state.pop1(); + let dest = state.pop1(); + environ.translate_table_copy( + builder.cursor(), + TableIndex::from_u32(dst_table_index), + dst_table, + TableIndex::from_u32(src_table_index), + src_table, + dest, + src, + len, + )?; + } + Operator::TableInit { segment } => { + // 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 len = state.pop1(); + let src = state.pop1(); + let dest = state.pop1(); + environ.translate_table_init( + builder.cursor(), + *segment, + TableIndex::from_u32(table_index), + table, + dest, + src, + len, + )?; + } + Operator::ElemDrop { 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 } => { let data = value.bytes().to_vec().into(); diff --git a/cranelift-wasm/src/environ/dummy.rs b/cranelift-wasm/src/environ/dummy.rs index 57668d8f4..64ca5e7ca 100644 --- a/cranelift-wasm/src/environ/dummy.rs +++ b/cranelift-wasm/src/environ/dummy.rs @@ -371,6 +371,87 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ ) -> WasmResult { Ok(pos.ins().iconst(I32, -1)) } + + fn translate_memory_copy( + &mut self, + _pos: FuncCursor, + _index: MemoryIndex, + _heap: ir::Heap, + _dst: ir::Value, + _src: ir::Value, + _len: ir::Value, + ) -> WasmResult<()> { + Ok(()) + } + + fn translate_memory_fill( + &mut self, + _pos: FuncCursor, + _index: MemoryIndex, + _heap: ir::Heap, + _dst: ir::Value, + _val: ir::Value, + _len: ir::Value, + ) -> WasmResult<()> { + Ok(()) + } + + fn translate_memory_init( + &mut self, + _pos: FuncCursor, + _index: MemoryIndex, + _heap: ir::Heap, + _seg_index: u32, + _dst: ir::Value, + _src: ir::Value, + _len: ir::Value, + ) -> WasmResult<()> { + Ok(()) + } + + fn translate_data_drop(&mut self, _pos: FuncCursor, _seg_index: u32) -> WasmResult<()> { + Ok(()) + } + + fn translate_table_size( + &mut self, + mut pos: FuncCursor, + _index: TableIndex, + _table: ir::Table, + ) -> WasmResult { + Ok(pos.ins().iconst(I32, -1)) + } + + fn translate_table_copy( + &mut self, + _pos: FuncCursor, + _dst_index: TableIndex, + _dst_table: ir::Table, + _src_index: TableIndex, + _src_table: ir::Table, + _dst: ir::Value, + _src: ir::Value, + _len: ir::Value, + ) -> WasmResult<()> { + Ok(()) + } + + fn translate_table_init( + &mut self, + _pos: FuncCursor, + _seg_index: u32, + _table_index: TableIndex, + _table: ir::Table, + _dst: ir::Value, + _src: ir::Value, + _len: ir::Value, + ) -> WasmResult<()> { + Ok(()) + } + + fn translate_elem_drop(&mut self, _pos: FuncCursor, _seg_index: u32) -> WasmResult<()> { + Ok(()) + } } impl<'data> ModuleEnvironment<'data> for DummyEnvironment { diff --git a/cranelift-wasm/src/environ/spec.rs b/cranelift-wasm/src/environ/spec.rs index 9acaa2aa4..77fc6e2d1 100644 --- a/cranelift-wasm/src/environ/spec.rs +++ b/cranelift-wasm/src/environ/spec.rs @@ -266,6 +266,89 @@ pub trait FuncEnvironment { heap: ir::Heap, ) -> WasmResult; + /// Translate a `memory.copy` WebAssembly instruction. + /// + /// The `index` provided identifies the linear memory to query, and `heap` is the heap reference + /// returned by `make_heap` for the same index. + fn translate_memory_copy( + &mut self, + pos: FuncCursor, + index: MemoryIndex, + heap: ir::Heap, + dst: ir::Value, + src: ir::Value, + len: ir::Value, + ) -> WasmResult<()>; + + /// Translate a `memory.fill` WebAssembly instruction. + /// + /// The `index` provided identifies the linear memory to query, and `heap` is the heap reference + /// returned by `make_heap` for the same index. + fn translate_memory_fill( + &mut self, + pos: FuncCursor, + index: MemoryIndex, + heap: ir::Heap, + dst: ir::Value, + val: ir::Value, + len: ir::Value, + ) -> WasmResult<()>; + + /// Translate a `memory.init` WebAssembly instruction. + /// + /// The `index` provided identifies the linear memory to query, and `heap` is the heap reference + /// returned by `make_heap` for the same index. `seg_index` is the index of the segment to copy + /// from. + fn translate_memory_init( + &mut self, + pos: FuncCursor, + index: MemoryIndex, + heap: ir::Heap, + seg_index: u32, + dst: ir::Value, + src: ir::Value, + len: ir::Value, + ) -> WasmResult<()>; + + /// Translate a `data.drop` WebAssembly instruction. + fn translate_data_drop(&mut self, pos: FuncCursor, seg_index: u32) -> WasmResult<()>; + + /// Translate a `table.size` WebAssembly instruction. + fn translate_table_size( + &mut self, + pos: FuncCursor, + index: TableIndex, + table: ir::Table, + ) -> WasmResult; + + /// Translate a `table.copy` WebAssembly instruction. + fn translate_table_copy( + &mut self, + pos: FuncCursor, + dst_table_index: TableIndex, + dst_table: ir::Table, + src_table_index: TableIndex, + src_table: ir::Table, + dst: ir::Value, + src: ir::Value, + len: ir::Value, + ) -> WasmResult<()>; + + /// Translate a `table.init` WebAssembly instruction. + fn translate_table_init( + &mut self, + pos: FuncCursor, + seg_index: u32, + table_index: TableIndex, + table: ir::Table, + dst: ir::Value, + src: ir::Value, + len: ir::Value, + ) -> WasmResult<()>; + + /// Translate a `elem.drop` WebAssembly instruction. + fn translate_elem_drop(&mut self, pos: FuncCursor, seg_index: u32) -> WasmResult<()>; + /// Emit code at the beginning of every wasm loop. /// /// This can be used to insert explicit interrupt or safepoint checking at