use std::time::Duration; use crate::asm::data::{Rd, RdData}; use crate::asm::data::literal::Addr; use crate::asm::instr::Cond; use crate::builtin::defs::{Barrier, BuiltinOp}; use crate::module::{EvalRes, OpTrait}; use crate::runtime::fault::Fault; use crate::runtime::frame::StackFrame; use crate::runtime::run_thread::{state::RunState, ThreadInfo}; impl OpTrait for BuiltinOp { fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result { 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 { kind: Barrier::Open(lbl), .. } => { match program.find_far_label(lbl) { Ok(pos) => { res.cycles = 0; state.set_pc(pos); } Err(e) => { return Err(e); } } } BuiltinOp::Barrier { msg, .. } => { return Err(Fault::FaultInstr { 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) => { state.set_pc(pos); } Err(e) => { return Err(e); } } } BuiltinOp::Jump(_name) => { panic!("jump not translated to skip by assembler!"); } 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(state.read(*arg)?); } let mut frame2 = StackFrame::new(pos, &values); std::mem::swap(&mut state.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(state.read(*arg)?); } state.frame = previous; state.frame.set_retvals(&values); } None => { return Err(Fault::CallStackUnderflow); } } } BuiltinOp::Skip(val) => { let steps = state.read(*val)?; res.advance = i64::from_ne_bytes(steps.to_ne_bytes()); let pc = state.get_pc(); program.validate_jump(pc, Addr((pc.0 as i64 + res.advance) as u64))?; } BuiltinOp::Move { dst, src } => { state.clear_status(); let val = state.read(*src)?; state.update_status(val); state.write(*dst, val)?; } BuiltinOp::StoreStatus { dst } => { let packed = state.frame.status.store(); state.write(*dst, packed)?; } BuiltinOp::LoadStatus { src } => { let x = state.read(*src)?; state.frame.status.load(x); } BuiltinOp::Sleep { micros } => { std::thread::sleep(Duration::from_micros(state.read(*micros)?)) } BuiltinOp::Drop(obj) => { let x = state.read(Rd::new(RdData::Register(obj.reg())))?; trace!("Drop object: {:#x}", x); let mut dropped = false; for ex in info.program.extensions.iter() { if ex.drop_obj(info, state, x)?.is_some() { dropped = true; } } if !dropped { warn!("Object {:#x} to drop does not exist!", x); state.set_flag(Cond::Invalid, true); } } } Ok(res) } // }