Implement the memory.copy instruction from the bulk memory proposal

This commit is contained in:
Nick Fitzgerald
2020-02-19 15:37:49 -08:00
parent cb97e4ec8e
commit 98ecef1700
7 changed files with 445 additions and 11 deletions

View File

@@ -15,6 +15,7 @@ use crate::vmcontext::{
VMTableDefinition, VMTableImport,
};
use crate::{TrapDescription, TrapRegistration};
use backtrace::Backtrace;
use memoffset::offset_of;
use more_asserts::assert_lt;
use std::alloc::{self, Layout};
@@ -601,7 +602,7 @@ impl Instance {
source_loc,
trap_code: ir::TrapCode::TableOutOfBounds,
},
backtrace: backtrace::Backtrace::new(),
backtrace: Backtrace::new(),
});
}
@@ -625,6 +626,71 @@ impl Instance {
}
}
/// Do a `memory.copy` for a locally defined memory.
///
/// # Errors
///
/// Returns a `Trap` error when the source or destination ranges are out of
/// bounds.
pub(crate) fn defined_memory_copy(
&self,
memory_index: DefinedMemoryIndex,
dst: u32,
src: u32,
len: u32,
source_loc: ir::SourceLoc,
) -> Result<(), Trap> {
// https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy
let memory = self.memory(memory_index);
if src
.checked_add(len)
.map_or(true, |n| n as usize > memory.current_length)
|| dst
.checked_add(len)
.map_or(true, |m| m as usize > memory.current_length)
{
return Err(Trap::Wasm {
desc: TrapDescription {
source_loc,
trap_code: ir::TrapCode::HeapOutOfBounds,
},
backtrace: Backtrace::new(),
});
}
let dst = isize::try_from(dst).unwrap();
let src = isize::try_from(src).unwrap();
// Bounds and casts are checked above, by this point we know that
// everything is safe.
unsafe {
let dst = memory.base.offset(dst);
let src = memory.base.offset(src);
ptr::copy(src, dst, len as usize);
}
Ok(())
}
/// Perform a `memory.copy` on an imported memory.
pub(crate) fn imported_memory_copy(
&self,
memory_index: MemoryIndex,
dst: u32,
src: u32,
len: u32,
source_loc: ir::SourceLoc,
) -> Result<(), Trap> {
let import = self.imported_memory(memory_index);
unsafe {
let foreign_instance = (&*import.vmctx).instance();
let foreign_memory = &*import.from;
let foreign_index = foreign_instance.memory_index(foreign_memory);
foreign_instance.defined_memory_copy(foreign_index, dst, src, len, source_loc)
}
}
/// Get a table by index regardless of whether it is locally-defined or an
/// imported, foreign table.
pub(crate) fn get_table(&self, table_index: TableIndex) -> &Table {