Croissant Runtime
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.
 
 
crsn/crsn/src/runtime/run_thread/state.rs

247 lines
9.0 KiB

use std::any::{Any, TypeId};
use std::collections::HashMap;
use crate::asm::data::{Rd, RdData, RdObj, Register, Wr, WrData};
use crate::asm::data::literal::{Addr, Value};
use crate::asm::instr::Cond;
use crate::runtime::fault::Fault;
use crate::runtime::frame::{CallStack, REG_COUNT, StackFrame};
use std::sync::Arc;
use crate::runtime::run_thread::ThreadInfo;
use nudge::{likely};
use crate::asm::instr::cond::Flag;
use std::fmt::{Debug, Formatter};
use std::fmt;
pub struct RunState {
pub thread_info: Arc<ThreadInfo>,
/// Active stack frame
pub frame: StackFrame,
/// Call stack
pub call_stack: CallStack,
/// General purpose registers that stay valid for the entire run-time of the thread
pub global_regs: [Value; REG_COUNT],
/// Extension data
pub ext_data: ExtensionDataStore,
}
impl Debug for RunState {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("RunState")
.field("frame", &self.frame)
.field("call_stack", &self.call_stack)
.field("global_regs", &self.global_regs)
//.field("ext_data", &self.ext_data)
.finish()
}
}
#[derive(Debug,Default)]
pub struct ExtensionDataStore {
store: HashMap<TypeId, Box<dyn Any + Send>>
}
impl ExtensionDataStore {
pub fn new() -> Self {
Default::default()
}
/// Get an extension's persistent data object for mutation.
/// It will be created using Default if not present before.
pub fn get_mut<T: Send + Default + 'static>(&mut self) -> &mut T {
if !self.store.contains_key(&TypeId::of::<T>()) {
self.store.insert(TypeId::of::<T>(), Box::new(T::default()));
}
self.store.get_mut(&TypeId::of::<T>()).unwrap()
.downcast_mut().unwrap()
}
}
impl RunState {
/// Get an extension's persistent data object for mutation.
/// It will be created using Default if not present before.
pub fn ext_mut<T: Send + Default + 'static>(&mut self) -> &mut T {
self.ext_data.get_mut()
}
/// Set a status flag. Only supports simple, positive conds (i.e. not GreaterOrEqual)
#[inline(always)]
pub fn set_flag(&mut self, flag: Flag, set: bool) {
trace!("Flag {} = {:?}", flag, set);
self.frame.status.set(flag, set);
}
/// Check status flags for a condition
#[inline(always)]
pub fn test_cond(&self, cond: Cond) -> bool {
self.frame.status.test(cond)
}
/// Set program counter - address of the next instruction to run
pub fn set_pc(&mut self, pc: Addr) {
trace!("PC := {}", pc);
self.frame.pc = pc;
}
/// Get program counter - address of the next instruction to run
pub fn get_pc(&self) -> Addr {
self.frame.pc
}
/// Clear status flags
#[inline(always)]
pub fn clear_status(&mut self) {
self.frame.status.clear();
}
/// Update status flags using a variable.
/// The update is additive - call `clear_status()` first if desired!
#[inline(always)]
pub fn update_status(&mut self, val: Value) {
self.frame.status.update(val);
}
/// Update status flags using a variable.
/// The update is additive - call `clear_status()` first if desired!
#[inline(always)]
pub fn update_status_float(&mut self, val: f64) {
self.frame.status.update_float(val);
}
/// Read object handle value
pub fn read_obj(&mut self, rdo: impl Into<RdObj>) -> Result<Value, Fault> {
rdo.into().read(self)
}
/// Read a `Rd` value
#[inline]
pub fn read(&mut self, rd: impl Into<Rd>) -> Result<Value, Fault> {
let rd = rd.into();
// TODO dedupe
match rd.0 {
RdData::Immediate(v) => Ok(v),
RdData::Register(Register::Gen(rn)) => {
if likely(rn < REG_COUNT as u8) {
trace!("Rd {:?} = {}", rd, self.frame.gen[rn as usize]);
Ok(self.frame.gen[rn as usize])
} else {
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
}
}
RdData::Register(Register::Global(rn)) => {
if likely(rn < REG_COUNT as u8) {
trace!("Rd {:?} = {}", rd, self.global_regs[rn as usize]);
Ok(self.global_regs[rn as usize])
} else {
Err(Fault::RegisterNotExist { reg: Register::Global(rn) })
}
}
RdData::Register(Register::Arg(rn)) => {
if likely(rn < REG_COUNT as u8) {
trace!("Rd {:?} = {}", rd, self.frame.arg[rn as usize]);
Ok(self.frame.arg[rn as usize])
} else {
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
}
}
RdData::Register(Register::Res(rn)) => {
if likely(rn < REG_COUNT as u8) {
trace!("Rd {:?} = {}", rd, self.frame.res[rn as usize]);
Ok(self.frame.res[rn as usize])
} else {
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
}
}
RdData::RegObject(register) => {
let reference = self.read(Rd::new(RdData::Register(register)))?;
self.read_object(reference)
}
RdData::ImmObject(reference) => {
self.read_object(reference)
}
}
}
fn read_object(&mut self, reference: Value) -> Result<Value, Fault> {
// This is a shitty dirty hack to allow iterating over the extensions while passing a mutable reference
// to self to the reading methods. Since the extensions array is in an Arc, it can't be mutated internally
// anyway, and we know it will still live after the method returns - unless someone does something incredibly stupid.
let ti: &ThreadInfo = unsafe { &*(self.thread_info.as_ref() as *const _) }; // If this fails, just clone the arc for the loop...
for ext in ti.extensions.iter() {
if let Some(value) = ext.read_obj(self, reference)? {
return Ok(value);
}
}
Err(Fault::ObjectNotExist(reference))
}
fn write_object(&mut self, reference: Value, value: Value) -> Result<(), Fault> {
// This is a shitty dirty hack to allow iterating over the extensions while passing a mutable reference
// to self to the reading methods. Since the extensions array is in an Arc, it can't be mutated internally
// anyway, and we know it will still live after the method returns - unless someone does something incredibly stupid.
let ti: &ThreadInfo = unsafe { &*(self.thread_info.as_ref() as *const _) }; // If this fails, just clone the arc for the loop...
for ext in ti.extensions.iter() {
if ext.write_obj(self, reference, value)?.is_some() {
return Ok(());
}
}
Err(Fault::ObjectNotExist(reference))
}
/// Write a value to a `Wr` location
pub fn write(&mut self, wr: impl Into<Wr>, val: Value) -> Result<(), Fault> {
let wr = wr.into();
trace!("WR {:?} := {}", wr, val);
// TODO dedupe
match wr.0 {
WrData::Register(Register::Gen(rn)) => {
if likely(rn < REG_COUNT as u8) {
self.frame.gen[rn as usize] = val;
Ok(())
} else {
Err(Fault::RegisterNotExist { reg: Register::Gen(rn) })
}
}
WrData::Register(Register::Global(rn)) => {
if likely(rn < REG_COUNT as u8) {
self.global_regs[rn as usize] = val;
Ok(())
} else {
Err(Fault::RegisterNotExist { reg: Register::Global(rn) })
}
}
WrData::Register(Register::Arg(rn)) => {
if likely(rn < REG_COUNT as u8) {
Err(Fault::RegisterNotWritable { reg: Register::Res(rn) })
} else {
Err(Fault::RegisterNotExist { reg: Register::Arg(rn) })
}
}
WrData::Register(Register::Res(rn)) => {
if likely(rn < REG_COUNT as u8) {
Err(Fault::RegisterNotWritable { reg: Register::Res(rn) })
} else {
Err(Fault::RegisterNotExist { reg: Register::Res(rn) }) // TODO use match after @ when stabilized https://github.com/rust-lang/rust/issues/65490
}
}
WrData::Discard => {
/* Discard */
Ok(())
}
WrData::RegObject(register) => {
let reference = self.read(Rd::new(RdData::Register(register)))?;
self.write_object(reference, val)
}
WrData::ImmObject(reference) => {
self.write_object(reference, val)
}
}
}
}