diff --git a/codegen/luajit/runtime/runtime.lua b/codegen/luajit/runtime/runtime.lua index 6fe6b83..3489a6b 100644 --- a/codegen/luajit/runtime/runtime.lua +++ b/codegen/luajit/runtime/runtime.lua @@ -795,6 +795,19 @@ do return old end end + + function allocator.copy(memory, destination, source, length) + local destination_addr = by_offset(memory.data, destination) + local source_addr = by_offset(memory.data, source) + + ffi.copy(destination_addr, source_addr, length) + end + + function allocator.fill(memory, address, value, length) + local start = by_offset(memory.data, address) + + ffi.fill(start, length, value) + end module.load = load module.store = store diff --git a/codegen/luajit/src/backend/statement.rs b/codegen/luajit/src/backend/statement.rs index 9ddcccc..879f818 100644 --- a/codegen/luajit/src/backend/statement.rs +++ b/codegen/luajit/src/backend/statement.rs @@ -4,8 +4,8 @@ use std::{ }; use wasm_ast::node::{ - Block, Br, BrIf, BrTable, Call, CallIndirect, FuncData, If, LabelType, MemoryGrow, SetGlobal, - SetLocal, SetTemporary, Statement, StoreAt, Terminator, + Block, Br, BrIf, BrTable, Call, CallIndirect, FuncData, If, LabelType, MemoryGrow, MemoryCopy, + MemoryFill, SetGlobal, SetLocal, SetTemporary, Statement, StoreAt, Terminator, }; use wasmparser::ValType; @@ -282,6 +282,32 @@ impl DriverNoContext for MemoryGrow { } } +impl DriverNoContext for MemoryCopy { + fn write(&self, w: &mut dyn Write) -> Result<()> { + let dst = self.dst(); + let src = self.src(); + + write!(w, "rt.allocator.copy(memory_at_0, {dst}, {src}, ")?; + self.size().write(w)?; + write!(w, ")") + + } +} + +impl DriverNoContext for MemoryFill { + fn write(&self, w: &mut dyn Write) -> Result<()> { + let mem = self.mem(); + let value = self.value(); + let n = self.n(); + + write!(w, "rt.allocator.fill(memory_at_0, {mem}, ")?; + value.write(w)?; + write!(w, ", ")?; + n.write(w)?; + write!(w, ")") + } +} + fn write_stat(stat: &dyn DriverNoContext, mng: &mut Manager, w: &mut dyn Write) -> Result<()> { indentation!(mng, w)?; stat.write(w)?; @@ -301,6 +327,8 @@ impl Driver for Statement { Self::SetGlobal(s) => write_stat(s, mng, w), Self::StoreAt(s) => write_stat(s, mng, w), Self::MemoryGrow(s) => write_stat(s, mng, w), + Self::MemoryCopy(s) => write_stat(s, mng, w), + Self::MemoryFill(s) => write_stat(s, mng, w) } } } diff --git a/codegen/luau/runtime/runtime.lua b/codegen/luau/runtime/runtime.lua index cfaad23..ef14f12 100644 --- a/codegen/luau/runtime/runtime.lua +++ b/codegen/luau/runtime/runtime.lua @@ -944,6 +944,20 @@ do return old end end + + function allocator.copy(memory, destination, source, length) + for i = 1, length do + local v = load_byte(memory, source + i - 1) + + store_byte(memory, destination + i - 1, v) + end + end + + function allocator.fill(memory, destination, value, length) + for i = 1, length do + store_byte(memory, destination + i - 1, value) + end + end module.load = load module.store = store @@ -951,3 +965,4 @@ do end return module + diff --git a/codegen/luau/src/backend/statement.rs b/codegen/luau/src/backend/statement.rs index 9611dec..36dec2f 100644 --- a/codegen/luau/src/backend/statement.rs +++ b/codegen/luau/src/backend/statement.rs @@ -4,8 +4,8 @@ use std::{ }; use wasm_ast::node::{ - Block, Br, BrIf, BrTable, Call, CallIndirect, FuncData, If, LabelType, MemoryGrow, SetGlobal, - SetLocal, SetTemporary, Statement, StoreAt, Terminator, + Block, Br, BrIf, BrTable, Call, CallIndirect, FuncData, If, LabelType, MemoryGrow, MemoryCopy, + MemoryFill, SetGlobal, SetLocal, SetTemporary, Statement, StoreAt, Terminator, }; use wasmparser::ValType; @@ -301,6 +301,32 @@ impl DriverNoContext for MemoryGrow { } } +impl DriverNoContext for MemoryCopy { + fn write(&self, w: &mut dyn Write) -> Result<()> { + let dst = self.dst(); + let src = self.src(); + let size = self.size(); + + write!(w, "rt.store.copy(memory_at_0, {dst}, {src}, ")?; + size.write(w)?; + write!(w, ")") + } +} + +impl DriverNoContext for MemoryFill { + fn write(&self, w: &mut dyn Write) -> Result<()> { + let mem = self.mem(); + let value = self.value(); + let n = self.n(); + + write!(w, "rt.store.copy(memory_at_0, {mem}, ")?; + value.write(w)?; + write!(w, ", ")?; + n.write(w)?; + write!(w, ")") + } +} + fn write_stat(stat: &dyn DriverNoContext, mng: &mut Manager, w: &mut dyn Write) -> Result<()> { indentation!(mng, w)?; stat.write(w)?; @@ -320,6 +346,8 @@ impl Driver for Statement { Self::SetGlobal(s) => write_stat(s, mng, w), Self::StoreAt(s) => write_stat(s, mng, w), Self::MemoryGrow(s) => write_stat(s, mng, w), + Self::MemoryCopy(s) => write_stat(s, mng, w), + Self::MemoryFill(s) => write_stat(s, mng, w), } } } diff --git a/wasm-ast/src/factory.rs b/wasm-ast/src/factory.rs index febb73b..49cf34c 100644 --- a/wasm-ast/src/factory.rs +++ b/wasm-ast/src/factory.rs @@ -5,8 +5,8 @@ use crate::{ node::{ BinOp, BinOpType, Block, Br, BrIf, BrTable, Call, CallIndirect, CmpOp, CmpOpType, Expression, FuncData, GetGlobal, GetLocal, If, LabelType, LoadAt, LoadType, MemoryGrow, - MemorySize, Select, SetGlobal, SetLocal, Statement, StoreAt, StoreType, Terminator, UnOp, - UnOpType, Value, + MemoryCopy, MemoryFill, MemorySize, Select, SetGlobal, SetLocal, Statement, StoreAt, + StoreType, Terminator, UnOp, UnOpType, Value, }, stack::{ReadType, Stack}, }; @@ -611,6 +611,29 @@ impl<'a> Factory<'a> { self.target.leak_memory_write(memory); self.target.code.push(data); } + Operator::MemoryCopy { src, dst } => { + let size = self.target.stack.pop().into(); + + let data = Statement::MemoryCopy(MemoryCopy { + dst, + src, + size, + }); + + self.target.code.push(data); + } + Operator::MemoryFill { mem } => { + let n = self.target.stack.pop().into(); + let value = self.target.stack.pop().into(); + + let data = Statement::MemoryFill(MemoryFill { + mem, + n, + value, + }); + + self.target.code.push(data); + } Operator::I32Const { value } => self.target.push_constant(value), Operator::I64Const { value } => self.target.push_constant(value), Operator::F32Const { value } => self.target.push_constant(value.bits()), diff --git a/wasm-ast/src/node.rs b/wasm-ast/src/node.rs index dba1975..f34f509 100644 --- a/wasm-ast/src/node.rs +++ b/wasm-ast/src/node.rs @@ -1108,6 +1108,48 @@ impl MemoryGrow { } } +pub struct MemoryCopy { + pub(crate) dst: u32, + pub(crate) src: u32, + pub(crate) size: Box, +} + +impl MemoryCopy { + #[must_use] + pub fn dst(&self) -> u32 { + self.dst + } + #[must_use] + pub fn src(&self) -> u32 { + self.src + } + #[must_use] + pub fn size(&self) -> &Expression { + &self.size + } +} + +pub struct MemoryFill { + pub(crate) mem: u32, + pub(crate) value: Box, + pub(crate) n: Box, +} + +impl MemoryFill { + #[must_use] + pub fn mem(&self) -> u32 { + self.mem + } + #[must_use] + pub fn value(&self) -> &Expression { + &self.value + } + #[must_use] + pub fn n(&self) -> &Expression { + &self.n + } +} + pub enum Statement { Block(Block), BrIf(BrIf), @@ -1119,6 +1161,8 @@ pub enum Statement { SetGlobal(SetGlobal), StoreAt(StoreAt), MemoryGrow(MemoryGrow), + MemoryCopy(MemoryCopy), + MemoryFill(MemoryFill) } pub struct FuncData { diff --git a/wasm-ast/src/visit.rs b/wasm-ast/src/visit.rs index 0961e76..ab58bb2 100644 --- a/wasm-ast/src/visit.rs +++ b/wasm-ast/src/visit.rs @@ -1,6 +1,6 @@ use crate::node::{ BinOp, Block, Br, BrIf, BrTable, Call, CallIndirect, CmpOp, Expression, FuncData, GetGlobal, - GetLocal, GetTemporary, If, LoadAt, MemoryGrow, MemorySize, Select, SetGlobal, SetLocal, + GetLocal, GetTemporary, If, LoadAt, MemoryGrow, MemorySize, MemoryCopy, MemoryFill, Select, SetGlobal, SetLocal, SetTemporary, Statement, StoreAt, Terminator, UnOp, Value, }; @@ -55,6 +55,10 @@ pub trait Visitor { fn visit_memory_grow(&mut self, _: &MemoryGrow) {} + fn visit_memory_copy(&mut self, _: &MemoryCopy) {} + + fn visit_memory_fill(&mut self, _: &MemoryFill) {} + fn visit_statement(&mut self, _: &Statement) {} } @@ -104,6 +108,23 @@ impl Driver for MemorySize { } } +impl Driver for MemoryCopy { + fn accept(&self, visitor: &mut T) { + self.size().accept(visitor); + + visitor.visit_memory_copy(self); + } +} + +impl Driver for MemoryFill { + fn accept(&self, visitor: &mut T) { + self.value().accept(visitor); + self.n().accept(visitor); + + visitor.visit_memory_fill(self); + } +} + impl Driver for Value { fn accept(&self, visitor: &mut T) { visitor.visit_value(self); @@ -292,6 +313,8 @@ impl Driver for Statement { Self::SetGlobal(v) => v.accept(visitor), Self::StoreAt(v) => v.accept(visitor), Self::MemoryGrow(v) => v.accept(visitor), + Self::MemoryCopy(v) => v.accept(visitor), + Self::MemoryFill(v) => v.accept(visitor), } visitor.visit_statement(self);