cleanup. remove conditional jumps, replaced by condition embedded in the enum

This commit is contained in:
2020-10-04 23:30:11 +02:00
parent 810ed2dddc
commit 986f3be6a2
28 changed files with 172 additions and 181 deletions
+1
View File
@@ -0,0 +1 @@
Files in this folder were developed for crsn but are not currently used by core or any extension.
+92
View File
@@ -0,0 +1,92 @@
use std::fmt;
use std::fmt::Formatter;
use std::sync::atomic::{AtomicU32, Ordering};
use crate::runtime::fault::Fault;
use crate::runtime::run_thread::ThreadToken;
use crate::runtime::span::MemorySpan;
/// Records memory claims and protects from illegal access
#[derive(Debug, Default)]
struct MemoryGuard {
claims: Vec<Claim>,
counter: AtomicU32,
}
#[derive(Clone, Copy, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub struct ClaimId(pub u32);
impl fmt::Display for ClaimId {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone)]
struct Claim {
owner: ThreadToken,
span: MemorySpan,
id: ClaimId,
}
impl MemoryGuard {
pub fn new() -> Self {
Default::default()
}
/// Claim a memory area
pub fn claim(&mut self, owner: ThreadToken, span: MemorySpan) -> Result<ClaimId, Fault> {
// naive
for claim in &self.claims {
if claim.span.intersects(span) && claim.owner != owner {
return Err(Fault::MemoryLocked {
area: claim.span,
owner: claim.owner,
});
}
}
let id = self.next_id();
self.claims.push(Claim {
id,
owner,
span,
});
Ok(id)
}
/// Get a unique claim ID and increment the counter
pub fn next_id(&self) -> ClaimId {
ClaimId(self.counter.fetch_and(1, Ordering::Relaxed))
}
/// Get the next claim ID (ID is incremented after calling "next").
/// May be used for release_owned_after()
pub fn epoch(&self) -> ClaimId {
ClaimId(self.counter.load(Ordering::Relaxed))
}
/// Release a claim by claim ID
pub fn release(&mut self, owner: ThreadToken, claim: ClaimId) -> Result<(), Fault> {
match self.claims.iter().position(|c| c.id == claim && c.owner == owner) {
Some(pos) => {
self.claims.swap_remove(pos);
Ok(())
}
None => Err(Fault::ClaimNotExist { claim, owner }),
}
}
/// Release all owned by a thread (thread ends)
pub fn release_owned(&mut self, owner: ThreadToken) {
self.claims.retain(|c| c.owner != owner);
}
/// Release all owned by a thread, with claim ID >= a given value
/// (return from a subroutine)
pub fn release_owned_after(&mut self, owner: ThreadToken, epoch: ClaimId) {
self.claims.retain(|c| c.owner != owner || c.id >= epoch);
}
}
+45
View File
@@ -0,0 +1,45 @@
use crate::asm::data::literal::Addr;
#[derive(Debug, Clone, Copy)]
pub struct MemorySpan {
addr: usize,
len: usize,
}
impl MemorySpan {
pub fn new(addr: Addr, len: usize) -> MemorySpan {
if len == 0 {
panic!("Cannot create empty span!");
}
Self {
addr: addr.0 as usize,
len,
}
}
/// Get start address
pub fn start(&self) -> Addr {
Addr(self.addr as u64)
}
/// Get end address (last included byte)
pub fn last(&self) -> Addr {
Addr((self.addr + self.len - 1) as u64)
}
/// Check if this intersects another span
pub fn intersects(&self, other: MemorySpan) -> bool {
!(
self.last() < other.start()
|| self.start() > other.last()
)
}
/// Check if this is a strict subset of another span
pub fn inside(&self, other: MemorySpan) -> bool {
self.start() >= other.start()
&& self.last() <= other.last()
}
}
+317
View File
@@ -0,0 +1,317 @@
use std::io::Write;
#[derive(Default)]
pub struct SparseBuffer {
chunks: Vec<(usize, Vec<u8>)>,
}
impl SparseBuffer {
pub fn new() -> Self {
Default::default()
}
pub fn write(&mut self, addr: usize, bytes: &[u8]) {
if self.chunks.is_empty() {
self.chunks.push((addr, Vec::from(bytes)));
return;
}
enum InsertLoc {
Head,
Append(usize),
Tail,
}
let mut loc = None;
for (i, (at, _ch)) in self.chunks.iter().enumerate() {
if *at > addr {
if i == 0 {
loc = Some(InsertLoc::Head);
} else {
loc = Some(InsertLoc::Append(i - 1));
}
break;
}
}
let loc = if let Some(l) = loc {
l
} else {
InsertLoc::Tail
};
match loc {
InsertLoc::Head => self.write_head(addr, bytes),
InsertLoc::Append(i) => self.write_after(i, addr, bytes),
InsertLoc::Tail => self.write_tail(addr, bytes),
};
}
fn write_head(&mut self, addr: usize, bytes: &[u8]) {
self.chunks.insert(0, (addr, vec![]));
self.write_after(0, addr, bytes);
}
fn write_after(&mut self, index: usize, addr: usize, bytes: &[u8]) {
if index == self.chunks.len() - 1 {
self.write_tail(addr, bytes);
return;
}
let end_addr = addr + bytes.len();
// This means we have at least two chunks.
// The written area can:
// - fit within the chunk
// - extend the chunk, but still end before the second's start address
// - extend the chunk, overflowing into one or more following chunks
let (a, slice) = self.chunks.iter().nth(index + 1).unwrap();
let second_start = *a;
let _second_len = slice.len();
let (a, slice) = self.chunks.get_mut(index).unwrap();
let first_addr = *a;
let first_len = slice.len();
if end_addr <= first_addr + first_len {
(&mut slice[(addr - first_addr) as usize..]).write(bytes);
} else if end_addr <= second_start {
slice.truncate((addr - first_addr) as usize);
slice.extend_from_slice(bytes);
} else {
// overflows into one or more chunks
slice.truncate((addr - first_addr) as usize);
slice.extend_from_slice(&bytes[..(second_start - addr) as usize]);
// recurse
self.write_after(index + 1, second_start, &bytes[(second_start - addr) as usize..]);
}
}
fn write_tail(&mut self, addr: usize, bytes: &[u8]) {
let (a, slice) = self.chunks.last_mut().unwrap();
let last_addr = *a;
let last_len = slice.len();
let end_addr = addr + bytes.len();
assert!(addr >= last_addr);
if end_addr <= last_addr + last_len {
// Entirely contained within the last chunk
(&mut slice[((addr - last_addr) as usize)..]).write(bytes);
} else if addr > last_addr + last_len {
self.chunks.push((addr, Vec::from(bytes)));
} else {
// The write slice starts within the last chunk, but extends past its end.
slice.truncate((addr - last_addr) as usize);
slice.extend_from_slice(bytes);
}
}
pub fn coalesce(&mut self) {
let mut prev = Option::<(usize, Vec<u8>)>::None;
let mut merged = vec![];
for chunk in self.chunks.drain(..) {
if let Some(prevchunk) = &mut prev {
if chunk.0 == prevchunk.0 + prevchunk.1.len() {
prevchunk.1.extend_from_slice(&chunk.1[..]);
continue;
} else {
merged.push(prev.take().unwrap());
}
}
prev = Some(chunk);
}
if let Some(prevchunk) = prev {
merged.push(prevchunk);
}
self.chunks = merged;
}
}
#[cfg(test)]
mod tests {
use super::SparseBuffer;
#[test]
fn test_empty() {
let mut sparse = SparseBuffer::new();
sparse.write(100, &[0, 1, 2, 3, 4]);
assert_eq!(vec![(100, vec![0, 1, 2, 3, 4])], sparse.chunks);
}
#[test]
fn test_append_sparse() {
let mut sparse = SparseBuffer::new();
sparse.write(0, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
sparse.write(100, &[7, 8, 9, 10]);
assert_eq!(vec![
(0, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
(100, vec![7, 8, 9, 10])
], sparse.chunks);
}
#[test]
fn test_append_inside_last() {
let mut sparse = SparseBuffer::new();
sparse.write(0, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
sparse.write(7, &[70, 80, 90]);
assert_eq!(vec![
(0, vec![0, 1, 2, 3, 4, 5, 6, 70, 80, 90, 10]),
], sparse.chunks);
}
#[test]
fn test_append_extend_last() {
let mut sparse = SparseBuffer::new();
sparse.write(0, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
sparse.write(5, &[50, 60, 70, 80, 90, 100, 110, 120, 130, 140]);
assert_eq!(vec![(0, vec![0, 1, 2, 3, 4, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140])], sparse.chunks);
}
#[test]
fn test_prepend_sparse() {
let mut sparse = SparseBuffer::new();
sparse.write(100, &[0, 1, 2, 3, 4]);
sparse.write(10, &[70, 80, 90, 100]);
assert_eq!(vec![
(10, vec![70, 80, 90, 100]),
(100, vec![0, 1, 2, 3, 4])
], sparse.chunks);
}
#[test]
fn test_within_first() {
let mut sparse = SparseBuffer::new();
sparse.write(0, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
sparse.write(4, &[40, 50, 60]);
assert_eq!(vec![
(0, vec![0, 1, 2, 3, 40, 50, 60, 7, 8, 9]),
], sparse.chunks);
}
#[test]
fn test_grows_first() {
let mut sparse = SparseBuffer::new();
sparse.write(0, &[0, 1, 2, 3, 4, 5]);
sparse.write(10, &[10, 11, 12]);
sparse.write(4, &[40, 50, 60]);
assert_eq!(vec![
(0, vec![0, 1, 2, 3, 40, 50, 60]),
(10, vec![10, 11, 12]),
], sparse.chunks);
}
#[test]
fn test_grows_first2() {
let mut sparse = SparseBuffer::new();
sparse.write(0, &[0, 1, 2, 3, 4, 5]);
sparse.write(10, &[10, 11, 12]);
sparse.write(4, &[40, 50, 60, 70, 80, 90]);
assert_eq!(vec![
(0, vec![0, 1, 2, 3, 40, 50, 60, 70, 80, 90]),
(10, vec![10, 11, 12]),
], sparse.chunks);
}
#[test]
fn test_overflow_first() {
let mut sparse = SparseBuffer::new();
sparse.write(0, &[0, 1, 2, 3, 4, 5]);
sparse.write(10, &[10, 11, 12, 13, 14, 15]);
sparse.write(4, &[40, 50, 60, 70, 80, 90, 100, 110, 120]);
assert_eq!(vec![
(0, vec![0, 1, 2, 3, 40, 50, 60, 70, 80, 90]),
(10, vec![100, 110, 120, 13, 14, 15]),
], sparse.chunks);
}
#[test]
fn test_join_tail() {
let mut sparse = SparseBuffer::new();
sparse.write(0, &[0, 1, 2]);
sparse.write(3, &[3, 4, 5]);
sparse.write(6, &[6, 7, 8]);
assert_eq!(vec![
(0, vec![0, 1, 2, 3, 4, 5, 6, 7, 8]),
], sparse.chunks);
}
#[test]
fn test_overflow_multiple() {
let mut sparse = SparseBuffer::new();
sparse.write(0, &[0, 1, 2]);
sparse.write(4, &[4, 5, 6]);
sparse.write(8, &[8, 9, 10]);
assert_eq!(vec![
(0, vec![0, 1, 2]),
(4, vec![4, 5, 6]),
(8, vec![8, 9, 10]),
], sparse.chunks);
sparse.write(2, &[20, 30, 40, 50, 60, 70, 80, 90]);
assert_eq!(vec![
(0, vec![0, 1, 20, 30]),
(4, vec![40, 50, 60, 70]),
(8, vec![80, 90, 10]),
], sparse.chunks);
}
#[test]
fn test_overflow_multiple2() {
let mut sparse = SparseBuffer::new();
sparse.write(0, &[0, 1, 2]);
sparse.write(4, &[4, 5, 6]);
sparse.write(8, &[8, 9, 10]);
assert_eq!(vec![
(0, vec![0, 1, 2]),
(4, vec![4, 5, 6]),
(8, vec![8, 9, 10]),
], sparse.chunks);
sparse.coalesce();
// no change, as expected
assert_eq!(vec![
(0, vec![0, 1, 2]),
(4, vec![4, 5, 6]),
(8, vec![8, 9, 10]),
], sparse.chunks);
sparse.write(2, &[20, 30, 40, 50, 60, 70, 80, 90, 100, 110]);
assert_eq!(vec![
(0, vec![0, 1, 20, 30]),
(4, vec![40, 50, 60, 70]),
(8, vec![80, 90, 100, 110]),
], sparse.chunks);
// join contiguous
sparse.coalesce();
assert_eq!(vec![
(0, vec![0, 1, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110]),
], sparse.chunks);
}
}