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 { 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, 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 { 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>, 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> = 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)) } }