add new rdwr access type to guard against illegal writes that can be caught at compile time

This commit is contained in:
2020-10-10 15:39:18 +02:00
parent 8ea60f52eb
commit 7a3cb539e1
10 changed files with 168 additions and 88 deletions
+8 -1
View File
@@ -6,6 +6,7 @@ pub use rd::Rd;
pub use rd::RdObj;
pub use reg::Register;
pub use wr::Wr;
pub use rdwr::RdWr;
use crate::asm::data::literal::{as_signed, is_negative, Value};
@@ -15,8 +16,8 @@ pub mod literal;
pub mod reg;
mod rd;
mod wr;
mod rdwr;
/// Data source disposition
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
@@ -134,6 +135,12 @@ pub enum WrData {
Discard,
}
impl WrData {
pub fn is_readable(self) -> bool {
self != Self::Discard
}
}
impl Display for WrData {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
-3
View File
@@ -12,9 +12,6 @@ impl Rd {
pub const fn new(src: RdData) -> Self {
Rd(src)
}
pub const fn data(self) -> RdData {
self.0
}
pub const fn immediate(val: Value) -> Rd {
Rd(RdData::Immediate(val))
}
+59
View File
@@ -0,0 +1,59 @@
use std::fmt::{Debug, Display, Formatter};
use std::fmt;
use crate::asm::data::{Rd, WrData, Wr};
/// Data destination argument (read-write)
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct RdWr(pub WrData);
impl RdWr {
pub fn new(dst: WrData) -> Self {
if !dst.is_readable() {
panic!("Not readable: {}", dst);
}
RdWr(dst)
}
pub fn wr(self) -> Wr {
Wr(self.0)
}
pub fn rd(self) -> Rd {
Rd(self.0.into())
}
}
impl From<RdWr> for Rd {
fn from(rdwr: RdWr) -> Self {
rdwr.rd()
}
}
impl From<RdWr> for Wr {
fn from(rdwr: RdWr) -> Self {
rdwr.wr()
}
}
impl From<&RdWr> for Rd {
fn from(rdwr: &RdWr) -> Self {
rdwr.rd()
}
}
impl From<&RdWr> for Wr {
fn from(rdwr: &RdWr) -> Self {
rdwr.wr()
}
}
impl Display for RdWr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Debug for RdWr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "RdWr({})", self.0)
}
}
+6 -5
View File
@@ -5,21 +5,22 @@ use crate::asm::data::{Rd, WrData};
/// Data destination argument (read-write)
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Wr(WrData);
pub struct Wr(pub WrData);
impl Wr {
pub fn new(dst: WrData) -> Self {
Wr(dst)
}
pub fn d(self) -> WrData {
self.0
pub fn discard() -> Wr {
Wr(WrData::Discard)
}
pub fn as_rd(self) -> Rd {
Rd(self.0.into())
}
pub fn discard() -> Wr {
Wr(WrData::Discard)
pub fn is_readable(self) -> bool {
self.0.is_readable()
}
pub fn is_discard(self) -> bool {
+14 -1
View File
@@ -1,6 +1,6 @@
use sexp::{Sexp, SourcePosition};
use crate::asm::data::{Rd, RdData, RdObj, Wr};
use crate::asm::data::{Rd, RdData, RdObj, Wr, RdWr};
use crate::asm::error::CrsnError;
use crate::asm::parse::parse_data::{parse_rd, parse_wr};
use crate::asm::parse::ParserContext;
@@ -109,4 +109,17 @@ impl<'a> TokenParser<'a> {
pub fn next_wr(&mut self) -> Result<Wr, CrsnError> {
parse_wr(self.next_or_err()?, self.pcx)
}
/// Get the next entry as write location
pub fn next_rdwr(&mut self) -> Result<RdWr, CrsnError> {
let next = self.next_or_err()?;
let pos = next.pos().clone();
let wr = parse_wr(next, self.pcx)?;
if !wr.is_readable() {
return Err(CrsnError::Parse("Argument is not readable!".into(), pos));
}
Ok(RdWr::new(wr.0))
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
use sexp::SourcePosition;
use crate::asm::data::{Rd, RdObj, Wr};
use crate::asm::data::{Rd, RdObj, Wr, RdWr};
use crate::asm::data::literal::{DebugMsg, Label, RoutineName};
use crate::asm::instr::Op;
use crate::asm::instr::op::OpKind;
@@ -73,7 +73,7 @@ pub enum BuiltinOp {
/// Copy value
MoveValue { dst: Wr, src: Rd },
/// Swap two registers
SwapValues { a: Wr, b: Wr },
SwapValues { a: RdWr, b: RdWr },
/// Store runtime status to a register
StoreFlags { dst: Wr },
/// Load runtime status from a register
+4 -4
View File
@@ -110,10 +110,10 @@ impl OpTrait for BuiltinOp {
state.write(*dst, val)?;
}
BuiltinOp::SwapValues { a, b } => {
let aa = state.read(a.as_rd())?;
let bb = state.read(b.as_rd())?;
state.write(*a, bb)?;
state.write(*b, aa)?;
let aa = state.read(a)?;
let bb = state.read(b)?;
state.write(a, bb)?;
state.write(b, aa)?;
}
BuiltinOp::StoreFlags { dst } => {
let packed = state.frame.status.store();
+2 -2
View File
@@ -185,8 +185,8 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok
"swap" => {
BuiltinOp::SwapValues {
a: args.next_wr()?,
b: args.next_wr()?,
a: args.next_rdwr()?,
b: args.next_rdwr()?,
}
}
+7 -4
View File
@@ -93,8 +93,9 @@ impl RunState {
}
/// Read a `Rd` value
pub fn read(&mut self, rd: Rd) -> Result<Value, Fault> {
match rd.data() {
pub fn read(&mut self, rd: impl Into<Rd>) -> Result<Value, Fault> {
let rd = rd.into();
match rd.0 {
RdData::Register(Register::Gen(rn)) => {
if likely(rn < REG_COUNT as u8) {
trace!("Rd {:?} = {}", rd, self.frame.gen[rn as usize]);
@@ -161,10 +162,12 @@ impl RunState {
}
/// Write a value to a `Wr` location
pub fn write(&mut self, wr: Wr, val: Value) -> Result<(), Fault> {
pub fn write(&mut self, wr: impl Into<Wr>, val: Value) -> Result<(), Fault> {
let wr = wr.into();
trace!("WR {:?} := {}", wr, val);
match wr.d() {
match wr.0 {
WrData::Register(Register::Gen(rn)) => {
if likely(rn < REG_COUNT as u8) {
self.frame.gen[rn as usize] = val;