Skip to content

Commit 1448bc5

Browse files
committed
Allow unaligned loads/stores
1 parent a209692 commit 1448bc5

2 files changed

Lines changed: 64 additions & 19 deletions

File tree

vm/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ libc = "0.2" # needed for mmap
1212
[features]
1313
count_insns = []
1414

15+
# Fully optimize the dependencies in debug mode
16+
[profile.dev.package."*"]
17+
opt-level = 3
18+
1519
[profile.dev]
1620
debug = true
1721
opt-level = 1

vm/src/vm.rs

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ impl MemBlock
498498

499499
/// Grow to a new size in bytes
500500
/// This operation is a no-op if the existing size
501-
/// is greater or equal to the requested size
501+
/// is less than or equal to the requested size
502502
///
503503
/// Note: this operation must be guarded by the VM
504504
pub fn grow(&mut self, mut new_size: usize) -> usize
@@ -512,7 +512,6 @@ impl MemBlock
512512

513513
let cur_size = *self.cur_size;
514514

515-
// Growing the memory block, need to map as read | write
516515
if new_size <= cur_size {
517516
return cur_size;
518517
}
@@ -523,6 +522,7 @@ impl MemBlock
523522
let map_size = new_size - cur_size;
524523
assert!(map_size % self.page_size == 0);
525524

525+
// Growing the memory block, need to map as read | write
526526
let mem_block = unsafe {libc::mmap(
527527
map_addr,
528528
map_size,
@@ -542,7 +542,7 @@ impl MemBlock
542542
new_size
543543
}
544544

545-
// Create a new thread-local view on this memory block
545+
// Create a new thread-local view of this memory block
546546
fn new_view(&self) -> MemView
547547
{
548548
MemView {
@@ -626,6 +626,38 @@ impl MemView
626626
}
627627
}
628628

629+
/// Read a value at an address
630+
/// The address does not need to be aligned
631+
pub fn read<T>(&self, addr: usize) -> T where T: Copy
632+
{
633+
// Check that the address is within bounds
634+
let cur_size = unsafe { *self.cur_size };
635+
if addr + size_of::<T>() > cur_size {
636+
panic!("attempting to read past end of heap");
637+
}
638+
639+
unsafe {
640+
let ptr = self.mem_block.add(addr) as *const T;
641+
std::ptr::read_unaligned(ptr)
642+
}
643+
}
644+
645+
/// Write a value at an address
646+
/// The address does not need to be aligned
647+
pub fn write<T>(&mut self, addr: usize, val: T) where T: Copy
648+
{
649+
// Check that the address is within bounds
650+
let cur_size = unsafe { *self.cur_size };
651+
if addr + size_of::<T>() > cur_size {
652+
panic!("attempting to write past end of heap");
653+
}
654+
655+
unsafe {
656+
let ptr = self.mem_block.add(addr) as *mut T;
657+
std::ptr::write_unaligned(ptr, val);
658+
}
659+
}
660+
629661
/// Read a value at the current PC and then increment the PC
630662
pub fn read_pc<T>(&self, pc: &mut usize) -> T where T: Copy
631663
{
@@ -1404,60 +1436,53 @@ impl Thread
14041436
self.push(v.as_f32() as i32);
14051437
}
14061438

1439+
// Note: load/store accept unaligned addresses
14071440
Op::load_u8 => {
14081441
let addr = self.pop().as_usize();
1409-
let heap_ptr = self.get_heap_ptr_mut(addr, 1);
1410-
let val: u8 = unsafe { *heap_ptr };
1442+
let val: u8 = self.heap.read(addr);
14111443
self.push(val);
14121444
}
14131445

14141446
Op::load_u16 => {
14151447
let addr = self.pop().as_usize();
1416-
let heap_ptr = self.get_heap_ptr_mut(addr, 1);
1417-
let val: u16 = unsafe { *heap_ptr };
1448+
let val: u16 = self.heap.read(addr);
14181449
self.push(val);
14191450
}
14201451

14211452
Op::load_u32 => {
14221453
let addr = self.pop().as_usize();
1423-
let heap_ptr = self.get_heap_ptr_mut(addr, 1);
1424-
let val: u32 = unsafe { *heap_ptr };
1454+
let val: u32 = self.heap.read(addr);
14251455
self.push(val);
14261456
}
14271457

14281458
Op::load_u64 => {
14291459
let addr = self.pop().as_usize();
1430-
let heap_ptr = self.get_heap_ptr_mut(addr, 1);
1431-
let val: u64 = unsafe { *heap_ptr };
1460+
let val: u64 = self.heap.read(addr);
14321461
self.push(val);
14331462
}
14341463

14351464
Op::store_u8 => {
14361465
let val = self.pop().as_u8();
14371466
let addr = self.pop().as_usize();
1438-
let heap_ptr = self.get_heap_ptr_mut(addr, 1);
1439-
unsafe { *heap_ptr = val; }
1467+
self.heap.write(addr, val);
14401468
}
14411469

14421470
Op::store_u16 => {
14431471
let val = self.pop().as_u16();
14441472
let addr = self.pop().as_usize();
1445-
let heap_ptr = self.get_heap_ptr_mut(addr, 1);
1446-
unsafe { *heap_ptr = val; }
1473+
self.heap.write(addr, val);
14471474
}
14481475

14491476
Op::store_u32 => {
14501477
let val = self.pop().as_u32();
14511478
let addr = self.pop().as_usize();
1452-
let heap_ptr = self.get_heap_ptr_mut(addr, 1);
1453-
unsafe { *heap_ptr = val; }
1479+
self.heap.write(addr, val);
14541480
}
14551481

14561482
Op::store_u64 => {
14571483
let val = self.pop().as_u64();
14581484
let addr = self.pop().as_usize();
1459-
let heap_ptr = self.get_heap_ptr_mut(addr, 1);
1460-
unsafe { *heap_ptr = val; }
1485+
self.heap.write(addr, val);
14611486
}
14621487

14631488
Op::atomic_load_u64 => {
@@ -1923,6 +1948,22 @@ mod tests
19231948
eval_i64(".data; .zero 255; .code; push_i8 0; push_i8 77; store_u8; push_i8 11; ret;", 11);
19241949
}
19251950

1951+
#[test]
1952+
fn test_unaligned_load_store()
1953+
{
1954+
// Store and load a u64 at an unaligned address
1955+
eval_i64(".data; .zero 255; .code; push 1; push 0x1122334455667788; store_u64; push 1; load_u64; ret;", 0x1122334455667788);
1956+
1957+
// Store and load a u32 at an unaligned address
1958+
eval_i64(".data; .zero 255; .code; push 3; push 0x0AABBCCD; store_u32; push 3; load_u32; ret;", 0x0AABBCCD);
1959+
1960+
// Store and load a u16 at an unaligned address
1961+
eval_i64(".data; .zero 255; .code; push 7; push 0x1234; store_u16; push 7; load_u16; ret;", 0x1234);
1962+
1963+
// Unaligned stores should not clobber neighbouring bytes
1964+
eval_i64(".data; .zero 255; .code; push 0; push 0xFF; store_u8; push 1; push 0x1122334455667788; store_u64; push 0; load_u8; ret;", 0xFF);
1965+
}
1966+
19261967
#[test]
19271968
fn test_setn()
19281969
{

0 commit comments

Comments
 (0)