|  |  |  | @ -3,7 +3,7 @@ use std::sync::Arc; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | use crate::asm::data::literal::{Addr, Label, RoutineName}; | 
			
		
	
		
			
				
					|  |  |  |  | use crate::asm::instr::Op; | 
			
		
	
		
			
				
					|  |  |  |  | use crate::builtin::defs::BuiltinOp; | 
			
		
	
		
			
				
					|  |  |  |  | use crate::builtin::defs::{BuiltinOp, Barrier}; | 
			
		
	
		
			
				
					|  |  |  |  | use crate::module::CrsnExtension; | 
			
		
	
		
			
				
					|  |  |  |  | use crate::runtime::fault::Fault; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -12,25 +12,30 @@ pub struct Program { | 
			
		
	
		
			
				
					|  |  |  |  |     pub ops: Vec<Op>, | 
			
		
	
		
			
				
					|  |  |  |  |     pub extensions: Arc<Vec<Box<dyn CrsnExtension>>>, | 
			
		
	
		
			
				
					|  |  |  |  |     routines: HashMap<RoutineName, Addr>, | 
			
		
	
		
			
				
					|  |  |  |  |     local_labels: HashMap<Label, Addr>, | 
			
		
	
		
			
				
					|  |  |  |  |     far_labels: HashMap<Label, Addr>, | 
			
		
	
		
			
				
					|  |  |  |  |     barriers: Vec<Addr>, | 
			
		
	
		
			
				
					|  |  |  |  |     /// Barriers from-to (inclusive).
 | 
			
		
	
		
			
				
					|  |  |  |  |     /// Standalone barriers have both addresses the same.
 | 
			
		
	
		
			
				
					|  |  |  |  |     barriers: Vec<(Addr, Addr)>, | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | impl Program { | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn new(ops: Vec<Op>, extensions: Arc<Vec<Box<dyn CrsnExtension>>>) -> Arc<Self> { | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn new(ops: Vec<Op>, extensions: Arc<Vec<Box<dyn CrsnExtension>>>) -> anyhow::Result<Arc<Self>> { | 
			
		
	
		
			
				
					|  |  |  |  |         let mut p = Self { | 
			
		
	
		
			
				
					|  |  |  |  |             ops, | 
			
		
	
		
			
				
					|  |  |  |  |             extensions, | 
			
		
	
		
			
				
					|  |  |  |  |             routines: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |             local_labels: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |             far_labels: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |             barriers: Default::default(), | 
			
		
	
		
			
				
					|  |  |  |  |         }; | 
			
		
	
		
			
				
					|  |  |  |  |         p.scan(); | 
			
		
	
		
			
				
					|  |  |  |  |         Arc::new(p) | 
			
		
	
		
			
				
					|  |  |  |  |         p.scan()?; | 
			
		
	
		
			
				
					|  |  |  |  |         Ok(Arc::new(p)) | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /// Find all the named things
 | 
			
		
	
		
			
				
					|  |  |  |  |     fn scan(&mut self) { | 
			
		
	
		
			
				
					|  |  |  |  |     fn scan(&mut self) -> anyhow::Result<()> { | 
			
		
	
		
			
				
					|  |  |  |  |         let mut barrier_starts : HashMap<&Label, Addr> = HashMap::new(); | 
			
		
	
		
			
				
					|  |  |  |  |         for (pos, op) in self.ops.iter().enumerate() { | 
			
		
	
		
			
				
					|  |  |  |  |             match op { | 
			
		
	
		
			
				
					|  |  |  |  |                 Op::BuiltIn(BuiltinOp::FarLabel(name)) => { | 
			
		
	
	
		
			
				
					|  |  |  | @ -39,12 +44,45 @@ impl Program { | 
			
		
	
		
			
				
					|  |  |  |  |                 Op::BuiltIn(BuiltinOp::Routine(name)) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     self.routines.insert(name.clone(), pos.into()); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 Op::BuiltIn(BuiltinOp::Barrier(_)) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     self.barriers.push(pos.into()); | 
			
		
	
		
			
				
					|  |  |  |  |                 Op::BuiltIn( | 
			
		
	
		
			
				
					|  |  |  |  |                     BuiltinOp::Barrier { | 
			
		
	
		
			
				
					|  |  |  |  |                         kind: Barrier::Open(lbl), .. | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 ) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     barrier_starts.insert(lbl, pos.into()); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 Op::BuiltIn( | 
			
		
	
		
			
				
					|  |  |  |  |                     BuiltinOp::Barrier { | 
			
		
	
		
			
				
					|  |  |  |  |                         kind: Barrier::Close(lbl), | 
			
		
	
		
			
				
					|  |  |  |  |                         msg, | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 ) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     if let Some(start_pos) = barrier_starts.remove(lbl) { | 
			
		
	
		
			
				
					|  |  |  |  |                         self.barriers.push((start_pos, pos.into())); | 
			
		
	
		
			
				
					|  |  |  |  |                         self.far_labels.insert(lbl.clone(), pos.into()); | 
			
		
	
		
			
				
					|  |  |  |  |                     } else { | 
			
		
	
		
			
				
					|  |  |  |  |                         anyhow::bail!("Block barrier \"{:?}\" closed without being open!", msg); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 Op::BuiltIn( | 
			
		
	
		
			
				
					|  |  |  |  |                     BuiltinOp::Barrier { | 
			
		
	
		
			
				
					|  |  |  |  |                         kind: Barrier::Standalone, | 
			
		
	
		
			
				
					|  |  |  |  |                         .. | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 ) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     self.barriers.push((pos.into(), pos.into())); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 _ => {} | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if !barrier_starts.is_empty() { | 
			
		
	
		
			
				
					|  |  |  |  |             anyhow::bail!("Some block barriers open without being closed!"); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         debug!("Program scanned: {:?}", self); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         Ok(()) | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /// Read a program instruction at address
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -62,14 +100,28 @@ impl Program { | 
			
		
	
		
			
				
					|  |  |  |  |             std::mem::swap(&mut from, &mut to); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         for b in &self.barriers { | 
			
		
	
		
			
				
					|  |  |  |  |             if *b >= from && *b <= to { | 
			
		
	
		
			
				
					|  |  |  |  |                 if let Op::BuiltIn(BuiltinOp::Barrier(msg)) = self.read(*b) { | 
			
		
	
		
			
				
					|  |  |  |  |                     return Err(Fault::JumpThroughBarrier { | 
			
		
	
		
			
				
					|  |  |  |  |                         msg: msg.clone().unwrap_or("No msg".into()) | 
			
		
	
		
			
				
					|  |  |  |  |                     }); | 
			
		
	
		
			
				
					|  |  |  |  |                 } else { | 
			
		
	
		
			
				
					|  |  |  |  |                     unreachable!(); | 
			
		
	
		
			
				
					|  |  |  |  |         for (b0, b1) in &self.barriers { | 
			
		
	
		
			
				
					|  |  |  |  |             if b0 != b1 { | 
			
		
	
		
			
				
					|  |  |  |  |                 // block barrier that only partially intersects the jump
 | 
			
		
	
		
			
				
					|  |  |  |  |                 if (*b0 >= from && *b0 <= to) != (*b1 >= from && *b1 <= to) { | 
			
		
	
		
			
				
					|  |  |  |  |                     if let Op::BuiltIn(BuiltinOp::Barrier { msg, .. }) = self.read(*b0) { | 
			
		
	
		
			
				
					|  |  |  |  |                         return Err(Fault::JumpThroughBarrier { | 
			
		
	
		
			
				
					|  |  |  |  |                             msg: msg.clone().unwrap_or("BLOCK BARRIER".into()) | 
			
		
	
		
			
				
					|  |  |  |  |                         }); | 
			
		
	
		
			
				
					|  |  |  |  |                     } else { | 
			
		
	
		
			
				
					|  |  |  |  |                         unreachable!(); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |  |                 // point barrier
 | 
			
		
	
		
			
				
					|  |  |  |  |                 if *b0 >= from && *b0 <= to { | 
			
		
	
		
			
				
					|  |  |  |  |                     if let Op::BuiltIn(BuiltinOp::Barrier { msg, .. }) = self.read(*b0) { | 
			
		
	
		
			
				
					|  |  |  |  |                         return Err(Fault::JumpThroughBarrier { | 
			
		
	
		
			
				
					|  |  |  |  |                             msg: msg.clone().unwrap_or("POINT BARRIER".into()) | 
			
		
	
		
			
				
					|  |  |  |  |                         }); | 
			
		
	
		
			
				
					|  |  |  |  |                     } else { | 
			
		
	
		
			
				
					|  |  |  |  |                         unreachable!(); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
	
		
			
				
					|  |  |  | @ -87,37 +139,5 @@ impl Program { | 
			
		
	
		
			
				
					|  |  |  |  |         self.far_labels.get(name).copied() | 
			
		
	
		
			
				
					|  |  |  |  |             .ok_or_else(|| Fault::NoSuchLabel { label: name.clone() }) | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /// Find local label by name (label within a boundary-delimited region).
 | 
			
		
	
		
			
				
					|  |  |  |  |     /// If more than one such label exists, the outcome is undefined.
 | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn find_local_label(&self, pc: Addr, name: &Label) -> Result<Addr, Fault> { | 
			
		
	
		
			
				
					|  |  |  |  |         // TODO more efficient impl with look-up
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         for at in (0..=pc.0).rev() { | 
			
		
	
		
			
				
					|  |  |  |  |             match &self.ops[at as usize] { | 
			
		
	
		
			
				
					|  |  |  |  |                 Op::BuiltIn(BuiltinOp::Label(lbl)) if lbl == name => { | 
			
		
	
		
			
				
					|  |  |  |  |                     return Ok(at.into()); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 Op::BuiltIn(BuiltinOp::Barrier(_)) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     break; | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 _ => {} | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         for at in pc.0..(self.ops.len() as u64) { | 
			
		
	
		
			
				
					|  |  |  |  |             match &self.ops[at as usize] { | 
			
		
	
		
			
				
					|  |  |  |  |                 Op::BuiltIn(BuiltinOp::Label(lbl)) if lbl == name => { | 
			
		
	
		
			
				
					|  |  |  |  |                     return Ok(at.into()); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 Op::BuiltIn(BuiltinOp::Barrier(_)) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     break; | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 _ => {} | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         Err(Fault::NoSuchLabel { label: name.clone() }) | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | 
 |