use crate::asm::instr::op::{OpTrait, EvalRes}; use crate::runtime::fault::Fault; use crate::runtime::frame::{StackFrame}; use crate::builtin::defs::BuiltinOp; use crate::asm::data::literal::Addr; use crate::runtime::run_thread::{ThreadInfo, RunState}; impl OpTrait for BuiltinOp { fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result { let frame = &mut state.frame; let program = &info.program; let mut res = EvalRes::default(); match self { BuiltinOp::Nop => {} BuiltinOp::Halt => { trace!("HALT - stop execution"); return Err(Fault::Halt); } BuiltinOp::Label(_) | BuiltinOp::FarLabel(_) | BuiltinOp::Routine(_) => { /* this is nop, but without any cost - just markers */ res.cycles = 0; } BuiltinOp::Barrier(msg) => { return Err(Fault::Barrier { msg: msg.clone().unwrap_or_else(|| "BARRIER".into()) }); } BuiltinOp::Fault(msg) => { return Err(Fault::FaultInstr { msg: msg.clone().unwrap_or_else(|| "FAULT".into()) }); } BuiltinOp::FarJump(name) => { match program.find_far_label(name) { Ok(pos) => { frame.pc = pos; } Err(e) => { return Err(e); } } } BuiltinOp::Jump(name) => { match program.find_local_label(frame.pc, name) { Ok(pos) => { frame.pc = pos; } Err(e) => { return Err(e); } } } BuiltinOp::JumpIf(cond, name) => { if frame.status.test(*cond) { match program.find_local_label(frame.pc, name) { Ok(pos) => { frame.pc = pos; } Err(e) => { return Err(e); } } } } BuiltinOp::FarJumpIf(cond, name) => { if frame.status.test(*cond) { match program.find_far_label(name) { Ok(pos) => { frame.pc = pos; } Err(e) => { return Err(e); } } } } BuiltinOp::Call(name, args) => { match program.find_routine(&name) { Ok(pos) => { let mut values = Vec::with_capacity(args.len()); for arg in args { values.push(frame.read(*arg)?); } let mut frame2 = StackFrame::new(pos, &values); std::mem::swap(frame, &mut frame2); state.call_stack.push(frame2); res.advance = 0; } Err(e) => { return Err(e); } } } BuiltinOp::Ret(retvals) => { match state.call_stack.pop() { Some(previous) => { let mut values = Vec::with_capacity(retvals.len()); for arg in retvals { values.push(frame.read(*arg)?); } *frame = previous; frame.set_retvals(&values); } None => { return Err(Fault::CallStackUnderflow); } } } BuiltinOp::Skip(val) => { let steps = frame.read(*val)?; res.advance = i64::from_ne_bytes(steps.to_ne_bytes()); program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + res.advance) as u64))?; } BuiltinOp::SkipIf(cond, val) => { if frame.status.test(*cond) { debug!("Skipping"); let steps = frame.read(*val)?; res.advance = i64::from_ne_bytes(steps.to_ne_bytes()); program.validate_jump(frame.pc, Addr((frame.pc.0 as i64 + res.advance) as u64))?; } } BuiltinOp::Move { dst, src } => { frame.status.clear(); let val = frame.read(*src)?; frame.status.update(val); frame.write(*dst, val)?; } BuiltinOp::StoreStatus { dst } => { let packed = frame.status.store(); frame.write(*dst, packed)?; } BuiltinOp::LoadStatus { src } => { let x = frame.read(*src)?; frame.status.load(x); } } Ok(res) } // }