use std::io::{Read, Write}; use std::sync::{Arc, Mutex}; use binread::{BinRead, BinReadable}; use block::Block; use frame::Frame; use ijvmreader::IJVMReader; use ops::{num_to_op, Args, Operation}; use pool::Pool; use stack::Stack; use Result; #[cfg(feature = "bonus:heap")] use heap::Heaps; #[cfg(feature = "bonus:network")] use netstack::NetStack; use std::convert::TryInto; pub const MAGIC_HEADER: u32 = 0x1DEA_DFAD; pub struct Machine { pub wide: bool, pub halted: bool, pub pool: Pool, pub block: Block, pub frame: Vec, #[cfg(feature = "bonus:network")] pub net: NetStack, #[cfg(feature = "bonus:heap")] pub heap: Heaps, pub stream_in: Box, pub stream_out: Arc>, } impl Machine { pub fn new(pool: Pool, block: Block) -> Machine { Machine { wide: false, halted: false, pool, block, frame: vec![Frame::new_extendable(0)], stream_in: Box::new(::std::io::stdin()), stream_out: Arc::new(Mutex::new(::std::io::stdout())), #[cfg(feature = "bonus:network")] net: NetStack::new(), #[cfg(feature = "bonus:heap")] heap: Heaps::new(), } } pub fn new_from_reader(mut reader: IJVMReader) -> Result { let magic = reader.read_u32()?; if magic != MAGIC_HEADER { return Err("Invalid magic header"); } let constants = match reader.read_block() { Ok(a) => a, Err(_) => return Err("Failed to read constants block"), }; let text = match reader.read_block() { Ok(block) => block, Err(_) => return Err("Failed to read text block"), }; let pool = Pool::new(constants)?; Ok(Machine::new(pool, text)) } pub fn new_from_file(file: &str) -> Result { let reader = IJVMReader::new(file).unwrap(); Machine::new_from_reader(reader) } pub fn new_from_slice(source: &[u8]) -> Result { let reader = IJVMReader::new_from_slice(source); Machine::new_from_reader(reader) } pub fn step(&mut self) -> Result<()> { match self.block.read_op() { Ok(Operation::Op(a, func, _)) => { if cfg!(feature = "debug:instr") { println!("{}", a); println!("Stack: {:?}", self.cur_frame().stack.data); let x = func(self); println!("Stack: {:?}", self.cur_frame().stack.data); x } else { func(self) } } Ok(Operation::Invalid) => { println!("Reached invalid operation"); Err("Invalid op") } Err(str) => Err(str), } } pub fn run(&mut self) -> Result<()> { while self.has_step() { self.step()?; } Ok(()) } pub fn has_step(&self) -> bool { !self.halted && self.block.has_i8() } pub fn get_program_counter(&self) -> usize { self.block.cur() } pub fn get_tos(&mut self) -> Result { self.cur_stack().top()?.try_into() } pub fn cur_frame(&mut self) -> &mut Frame { self.frame.last_mut().unwrap() } pub fn cur_stack(&mut self) -> &mut Stack { &mut self.cur_frame().stack } pub fn cur_instruction(&mut self) -> u8 { self.block[self.get_program_counter()] } pub fn next_instruction(&mut self) -> Result<(String, Vec)> { let checkpoint = self.block.cur(); let mut opcode = self.block.read_u8()?; let mut params = Vec::new(); let mut wide = false; // WIDE if opcode == 0xC4 { wide = true; opcode = self.block.read_u8()?; } let (name, args) = match num_to_op(opcode) { Operation::Invalid => return Err("Invalid operation"), Operation::Op(name, _, args) => (name, args), }; for arg in args { let v = match arg { Args::Byte => i32::from(self.block.read_i8()?), Args::Short => i32::from(self.block.read_i16()?), Args::Var => { if wide { i32::from(self.block.read_u16()?) } else { i32::from(self.block.read_u8()?) } } Args::Label => i32::from(self.block.read_i16()?), Args::Constant => i32::from(self.block.read_u16()?), }; params.push(v); } self.block.seek(checkpoint).unwrap(); Ok(((*name).to_string(), params)) } // pub fn get_stack_pointer(&self) -> usize { // return self.frame.last().unwrap().stack.len(); // } pub fn read_index(&mut self) -> Result { if self.wide { self.wide = false; return Ok(self.block.read_u16()? as usize); } Ok(self.block.read_u8()? as usize) } pub fn set_input(&mut self, instream: Box) { self.stream_in = instream; } pub fn set_output(&mut self, outstream: Arc>) { self.stream_out = outstream; } }