Skip to content

Commit

Permalink
Implement basic atomic instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
maximecb committed Sep 7, 2024
1 parent af2aef5 commit eafc62c
Showing 1 changed file with 61 additions and 1 deletion.
62 changes: 61 additions & 1 deletion vm/src/vm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::sync::{Arc, Mutex};
use std::sync::atomic::{Ordering, AtomicU64};
use std::mem::{transmute, size_of, align_of};
use std::collections::{HashSet, HashMap};
use std::thread;
Expand Down Expand Up @@ -216,6 +217,22 @@ pub enum Op
load_global_u64 <addr:u24>
*/

// Atomic load with acquire semantics
// atomic_load (addr)
atomic_load_u64,

// Atomic store with release semantics
// atomic_store (addr) (value)
atomic_store_u64,

// Compare-and-swap
// Uses acquire semantics on success, relaxed on failure.
// Store has relaxed semantics.
// This instruction can be used to implement spin locks.
// atomic_cas (addr) (cmp-val) (store-val)
// Pushes the value found at the memory address
atomic_cas_u64,

// Set thread-local variable
// thread_set <idx:u8> (val)
thread_set,
Expand Down Expand Up @@ -1442,6 +1459,49 @@ impl Thread
unsafe { *heap_ptr = val; }
}

Op::atomic_load_u64 => {
let addr = self.pop().as_usize();
let heap_ptr = self.get_heap_ptr_mut(addr, 1);
let atomic = unsafe {AtomicU64::from_ptr(heap_ptr) };
let val = atomic.load(Ordering::Acquire);
self.push(Value::from(val));
}

Op::atomic_store_u64 => {
let val = self.pop().as_u64();
let addr = self.pop().as_usize();
let heap_ptr = self.get_heap_ptr_mut(addr, 1);
let atomic = unsafe {AtomicU64::from_ptr(heap_ptr) };
atomic.store(1, Ordering::Release);
}

// Compare-and-swap
// Uses acquire semantics on success, relaxed on failure.
// Store has relaxed semantics.
// This instruction can be used to implement spin locks.
// atomic_cas (addr) (cmp-val) (store-val)
// Pushes the value found at the memory address
Op::atomic_cas_u64 => {
let addr = self.pop().as_usize();
let cmp_val = self.pop().as_u64();
let store_val = self.pop().as_u64();

let heap_ptr = self.get_heap_ptr_mut(addr, 1);
let atomic = unsafe {AtomicU64::from_ptr(heap_ptr) };

let result = atomic.compare_exchange(
cmp_val,
store_val,
Ordering::Acquire,
Ordering::Relaxed,
);

match result {
Ok(val) => self.push(Value::from(val)),
Err(actual_val) => self.push(Value::from(actual_val)),
}
}

Op::thread_set => {
let idx = self.code.read_pc::<u8>(&mut pc) as usize;
let val = self.pop();
Expand Down Expand Up @@ -1800,7 +1860,7 @@ mod tests

// Keep track of how many short opcodes we have so far
dbg!(Op::ret as usize);
assert!(Op::ret as usize <= 114);
assert!(Op::ret as usize <= 117);
}

#[test]
Expand Down

0 comments on commit eafc62c

Please sign in to comment.