You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
4.1 KiB
109 lines
4.1 KiB
use sexp::SourcePosition;
|
|
|
|
use crate::asm::error::CrsnError;
|
|
use crate::asm::instr::op::OpKind;
|
|
use crate::asm::parse::arg_parser::TokenParser;
|
|
use crate::module::{CrsnExtension, ParseRes};
|
|
use crate::asm::data::literal::Value;
|
|
use crate::asm::instr::{Flatten, Op};
|
|
use crate::asm::parse::parse_instructions;
|
|
use crate::builtin::defs::BuiltinOp;
|
|
use crate::asm::instr::flatten::jumps_to_skips;
|
|
use crate::asm::data::{Rd, RdData};
|
|
|
|
pub mod defs;
|
|
pub mod exec;
|
|
pub mod parse;
|
|
|
|
pub(crate) const RT_OPT_TIMESLICE : u64 = 1;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct BuiltinOps;
|
|
|
|
impl BuiltinOps {
|
|
pub fn new() -> Box<dyn CrsnExtension> {
|
|
Box::new(Self)
|
|
}
|
|
}
|
|
|
|
impl CrsnExtension for BuiltinOps {
|
|
fn name(&self) -> &'static str {
|
|
"builtin"
|
|
}
|
|
|
|
fn parse_op<'a>(&self, pos: &SourcePosition, keyword: &str, args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
|
parse::parse_op(pos, keyword, args)
|
|
}
|
|
|
|
/// Get value of an extension-provided constant.
|
|
/// This constant may be an object handle, or a constant value used as argument in some other instruction.
|
|
fn get_constant_value<'a>(&self, name: &str) -> Option<Value> {
|
|
match name {
|
|
"RT_TIMESLICE" => Some(RT_OPT_TIMESLICE),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
/// Parse a generic S-expression (non-op) that started with the given keyword
|
|
///
|
|
/// pcx is available on the arg_tokens parser
|
|
fn parse_syntax<'a>(&self, pos: &SourcePosition, keyword: &str, tokens: TokenParser<'a>)
|
|
-> Result<ParseRes<'a, Box<dyn Flatten>>, CrsnError>
|
|
{
|
|
if keyword == "crit" || keyword == "critical" {
|
|
let pcx = tokens.pcx;
|
|
let opts = parse_instructions(tokens.into_iter(), pos, pcx)?;
|
|
|
|
let flattened = jumps_to_skips(opts.flatten(&pcx.state.borrow_mut().label_num)?)?;
|
|
|
|
let len = flattened.len();
|
|
|
|
for (n, op) in flattened.iter().enumerate() {
|
|
match op.kind {
|
|
OpKind::BuiltIn(BuiltinOp::Skip(Rd(RdData::Immediate(skip)))) => {
|
|
let signed = i64::from_ne_bytes(skip.to_ne_bytes());
|
|
let target = n as i64 + signed;
|
|
if target < 0 || target > len as i64 {
|
|
return Err(CrsnError::Parse("Cannot jump out of a critical section!".into(), op.pos()));
|
|
}
|
|
}
|
|
/* Non-constant skip cannot be validated */
|
|
OpKind::BuiltIn(BuiltinOp::Skip(_)) => {
|
|
return Err(CrsnError::Parse("Variable skips are not allowed in a critical section".into(), op.pos()));
|
|
}
|
|
/* Yield in critical makes zero sense */
|
|
OpKind::BuiltIn(BuiltinOp::Yield { .. }) => {
|
|
return Err(CrsnError::Parse("Yield in a critical section!".into(), op.pos()));
|
|
}
|
|
/* This is likely a bug */
|
|
OpKind::BuiltIn(BuiltinOp::Ret(_)) => {
|
|
return Err(CrsnError::Parse("Ret in a critical section!".into(), op.pos()));
|
|
}
|
|
/* Probably also a bug. If someone really wants this, they can start and end the critical section manually. */
|
|
OpKind::BuiltIn(BuiltinOp::FarJump(_)) => {
|
|
return Err(CrsnError::Parse("Far jump a critical section!".into(), op.pos()));
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
let vec : Vec<Box<dyn Flatten>> = vec![
|
|
Box::new(Op {
|
|
kind: OpKind::BuiltIn(BuiltinOp::CriticalBegin),
|
|
cond: None,
|
|
pos: pos.clone()
|
|
}),
|
|
Box::new(flattened),
|
|
Box::new(Op {
|
|
kind: OpKind::BuiltIn(BuiltinOp::CriticalEnd),
|
|
cond: None,
|
|
pos: pos.clone()
|
|
})
|
|
];
|
|
|
|
return Ok(ParseRes::Parsed(Box::new(vec)));
|
|
}
|
|
|
|
Ok(ParseRes::Unknown(tokens))
|
|
}
|
|
}
|
|
|