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

pull/21/head
Ondřej Hruška 4 years ago
parent 8ea60f52eb
commit 7a3cb539e1
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 9
      crsn/src/asm/data/mod.rs
  2. 3
      crsn/src/asm/data/rd.rs
  3. 59
      crsn/src/asm/data/rdwr.rs
  4. 11
      crsn/src/asm/data/wr.rs
  5. 15
      crsn/src/asm/parse/arg_parser.rs
  6. 4
      crsn/src/builtin/defs.rs
  7. 8
      crsn/src/builtin/exec.rs
  8. 4
      crsn/src/builtin/parse.rs
  9. 11
      crsn/src/runtime/run_thread/state.rs
  10. 132
      crsn_arith/src/parse.rs

@ -6,6 +6,7 @@ pub use rd::Rd;
pub use rd::RdObj; pub use rd::RdObj;
pub use reg::Register; pub use reg::Register;
pub use wr::Wr; pub use wr::Wr;
pub use rdwr::RdWr;
use crate::asm::data::literal::{as_signed, is_negative, Value}; use crate::asm::data::literal::{as_signed, is_negative, Value};
@ -15,8 +16,8 @@ pub mod literal;
pub mod reg; pub mod reg;
mod rd; mod rd;
mod wr; mod wr;
mod rdwr;
/// Data source disposition /// Data source disposition
#[derive(Debug, Clone, Copy, Eq, PartialEq)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
@ -134,6 +135,12 @@ pub enum WrData {
Discard, Discard,
} }
impl WrData {
pub fn is_readable(self) -> bool {
self != Self::Discard
}
}
impl Display for WrData { impl Display for WrData {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self { match self {

@ -12,9 +12,6 @@ impl Rd {
pub const fn new(src: RdData) -> Self { pub const fn new(src: RdData) -> Self {
Rd(src) Rd(src)
} }
pub const fn data(self) -> RdData {
self.0
}
pub const fn immediate(val: Value) -> Rd { pub const fn immediate(val: Value) -> Rd {
Rd(RdData::Immediate(val)) Rd(RdData::Immediate(val))
} }

@ -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)
}
}

@ -5,21 +5,22 @@ use crate::asm::data::{Rd, WrData};
/// Data destination argument (read-write) /// Data destination argument (read-write)
#[derive(Clone, Copy, Eq, PartialEq)] #[derive(Clone, Copy, Eq, PartialEq)]
pub struct Wr(WrData); pub struct Wr(pub WrData);
impl Wr { impl Wr {
pub fn new(dst: WrData) -> Self { pub fn new(dst: WrData) -> Self {
Wr(dst) Wr(dst)
} }
pub fn d(self) -> WrData { pub fn discard() -> Wr {
self.0 Wr(WrData::Discard)
} }
pub fn as_rd(self) -> Rd { pub fn as_rd(self) -> Rd {
Rd(self.0.into()) Rd(self.0.into())
} }
pub fn discard() -> Wr { pub fn is_readable(self) -> bool {
Wr(WrData::Discard) self.0.is_readable()
} }
pub fn is_discard(self) -> bool { pub fn is_discard(self) -> bool {

@ -1,6 +1,6 @@
use sexp::{Sexp, SourcePosition}; 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::error::CrsnError;
use crate::asm::parse::parse_data::{parse_rd, parse_wr}; use crate::asm::parse::parse_data::{parse_rd, parse_wr};
use crate::asm::parse::ParserContext; use crate::asm::parse::ParserContext;
@ -109,4 +109,17 @@ impl<'a> TokenParser<'a> {
pub fn next_wr(&mut self) -> Result<Wr, CrsnError> { pub fn next_wr(&mut self) -> Result<Wr, CrsnError> {
parse_wr(self.next_or_err()?, self.pcx) 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))
}
} }

@ -1,6 +1,6 @@
use sexp::SourcePosition; 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::data::literal::{DebugMsg, Label, RoutineName};
use crate::asm::instr::Op; use crate::asm::instr::Op;
use crate::asm::instr::op::OpKind; use crate::asm::instr::op::OpKind;
@ -73,7 +73,7 @@ pub enum BuiltinOp {
/// Copy value /// Copy value
MoveValue { dst: Wr, src: Rd }, MoveValue { dst: Wr, src: Rd },
/// Swap two registers /// Swap two registers
SwapValues { a: Wr, b: Wr }, SwapValues { a: RdWr, b: RdWr },
/// Store runtime status to a register /// Store runtime status to a register
StoreFlags { dst: Wr }, StoreFlags { dst: Wr },
/// Load runtime status from a register /// Load runtime status from a register

@ -110,10 +110,10 @@ impl OpTrait for BuiltinOp {
state.write(*dst, val)?; state.write(*dst, val)?;
} }
BuiltinOp::SwapValues { a, b } => { BuiltinOp::SwapValues { a, b } => {
let aa = state.read(a.as_rd())?; let aa = state.read(a)?;
let bb = state.read(b.as_rd())?; let bb = state.read(b)?;
state.write(*a, bb)?; state.write(a, bb)?;
state.write(*b, aa)?; state.write(b, aa)?;
} }
BuiltinOp::StoreFlags { dst } => { BuiltinOp::StoreFlags { dst } => {
let packed = state.frame.status.store(); let packed = state.frame.status.store();

@ -185,8 +185,8 @@ pub(crate) fn parse_op<'a>(op_pos: &SourcePosition, keyword: &str, mut args: Tok
"swap" => { "swap" => {
BuiltinOp::SwapValues { BuiltinOp::SwapValues {
a: args.next_wr()?, a: args.next_rdwr()?,
b: args.next_wr()?, b: args.next_rdwr()?,
} }
} }

@ -93,8 +93,9 @@ impl RunState {
} }
/// Read a `Rd` value /// Read a `Rd` value
pub fn read(&mut self, rd: Rd) -> Result<Value, Fault> { pub fn read(&mut self, rd: impl Into<Rd>) -> Result<Value, Fault> {
match rd.data() { let rd = rd.into();
match rd.0 {
RdData::Register(Register::Gen(rn)) => { RdData::Register(Register::Gen(rn)) => {
if likely(rn < REG_COUNT as u8) { if likely(rn < REG_COUNT as u8) {
trace!("Rd {:?} = {}", rd, self.frame.gen[rn as usize]); trace!("Rd {:?} = {}", rd, self.frame.gen[rn as usize]);
@ -161,10 +162,12 @@ impl RunState {
} }
/// Write a value to a `Wr` location /// 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); trace!("WR {:?} := {}", wr, val);
match wr.d() { match wr.0 {
WrData::Register(Register::Gen(rn)) => { WrData::Register(Register::Gen(rn)) => {
if likely(rn < REG_COUNT as u8) { if likely(rn < REG_COUNT as u8) {
self.frame.gen[rn as usize] = val; self.frame.gen[rn as usize] = val;

@ -30,19 +30,19 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
"inc" => { "inc" => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Add { ArithOp::Add {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
b: Rd::immediate(1), b: Rd::immediate(1),
} }
} }
"dec" => { "dec" => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Sub { ArithOp::Sub {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
b: Rd::immediate(1), b: Rd::immediate(1),
} }
} }
@ -57,10 +57,10 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Add { ArithOp::Add {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
b: args.next_rd()?, b: args.next_rd()?,
} }
} }
@ -80,10 +80,10 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Sub { ArithOp::Sub {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
b: args.next_rd()?, b: args.next_rd()?,
} }
} }
@ -103,10 +103,10 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Mul { ArithOp::Mul {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
b: args.next_rd()?, b: args.next_rd()?,
} }
} }
@ -119,13 +119,13 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
"divr" => { "divr" => {
match args.len() { match args.len() {
3 => { 3 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
let rem = args.next_wr()?; let rem = args.next_wr()?;
let div = args.next_rd()?; let div = args.next_rd()?;
ArithOp::Div { ArithOp::Div {
dst, dst: dst.wr(),
rem, rem,
a: dst.as_rd(), a: dst.rd(),
div, div,
} }
} }
@ -154,12 +154,12 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
let div = args.next_rd()?; let div = args.next_rd()?;
ArithOp::Div { ArithOp::Div {
dst, dst: dst.wr(),
rem: Wr::discard(), rem: Wr::discard(),
a: dst.as_rd(), a: dst.rd(),
div, div,
} }
} }
@ -179,11 +179,11 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
let div = args.next_rd()?; let div = args.next_rd()?;
ArithOp::Mod { ArithOp::Mod {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
div, div,
} }
} }
@ -203,10 +203,10 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::And { ArithOp::And {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
b: args.next_rd()?, b: args.next_rd()?,
} }
} }
@ -226,10 +226,10 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Or { ArithOp::Or {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
b: args.next_rd()?, b: args.next_rd()?,
} }
} }
@ -249,10 +249,10 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Xor { ArithOp::Xor {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
b: args.next_rd()?, b: args.next_rd()?,
} }
} }
@ -271,10 +271,10 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
1 => { 1 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Cpl { ArithOp::Cpl {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
} }
} }
_ => { _ => {
@ -293,18 +293,18 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Rol { ArithOp::Rol {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
n: args.next_rd()?, n: args.next_rd()?,
} }
} }
1 => { 1 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Rol { ArithOp::Rol {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
n: Rd::immediate(1), n: Rd::immediate(1),
} }
} }
@ -324,18 +324,18 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Ror { ArithOp::Ror {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
n: args.next_rd()?, n: args.next_rd()?,
} }
} }
1 => { 1 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Ror { ArithOp::Ror {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
n: Rd::immediate(1), n: Rd::immediate(1),
} }
} }
@ -355,18 +355,18 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Lsl { ArithOp::Lsl {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
n: args.next_rd()?, n: args.next_rd()?,
} }
} }
1 => { 1 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Lsl { ArithOp::Lsl {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
n: Rd::immediate(1), n: Rd::immediate(1),
} }
} }
@ -386,18 +386,18 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Lsr { ArithOp::Lsr {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
n: args.next_rd()?, n: args.next_rd()?,
} }
} }
1 => { 1 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Lsr { ArithOp::Lsr {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
n: Rd::immediate(1), n: Rd::immediate(1),
} }
} }
@ -417,18 +417,18 @@ pub(crate) fn parse<'a>(pos: &SourcePosition, keyword: &str, mut args: TokenPars
} }
} }
2 => { 2 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Asr { ArithOp::Asr {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
n: args.next_rd()?, n: args.next_rd()?,
} }
} }
1 => { 1 => {
let dst = args.next_wr()?; let dst = args.next_rdwr()?;
ArithOp::Asr { ArithOp::Asr {
dst, dst: dst.wr(),
a: dst.as_rd(), a: dst.rd(),
n: Rd::immediate(1), n: Rd::immediate(1),
} }
} }

Loading…
Cancel
Save