use ijvm::binread::BinRead; use ijvm::machine::Machine; use ijvm::frame::Frame; use ijvm::Result; use std::io::Write; use std::io::Read; pub type OpFunc = fn(&mut Machine) -> Result<()>; pub enum Operation { Op(&'static str, OpFunc), Invalid(u8) } const JUMP_OFFSET: i32 = 3; pub fn num_to_op(op: u8) -> Operation { match op { 0x00 => Operation::Op("NOP", nop), 0x10 => Operation::Op("BIPUSH", bipush), 0x13 => Operation::Op("LDC_W", ldc_w), 0x15 => Operation::Op("ILOAD", iload), 0x36 => Operation::Op("ISTORE", istore), 0x57 => Operation::Op("POP", pop), 0x59 => Operation::Op("DUP", dup), 0x5F => Operation::Op("SWAP", swap), 0x60 => Operation::Op("IADD", iadd), 0x64 => Operation::Op("ISUB", isub), 0x7E => Operation::Op("IAND", iand), 0xB0 => Operation::Op("IOR", ior), 0x84 => Operation::Op("IINC", iinc), 0x99 => Operation::Op("IFEQ", ifeq), 0x9b => Operation::Op("IFLT", iflt), 0x9F => Operation::Op("IF_ICMPEQ", if_icmpeq), 0xA7 => Operation::Op("GOTO", goto), 0xAC => Operation::Op("IRETURN", ireturn), 0xB6 => Operation::Op("INVOKEVIRTUAL", invokevirtual), 0xC4 => Operation::Op("WIDE", wide), 0xFC => Operation::Op("IN", _in), 0xFD => Operation::Op("OUT", out), 0xFF => Operation::Op("HALT", halt), 0xF0 => Operation::Op("SLP", slp), x => Operation::Invalid(x) } } fn nop(_: &mut Machine) -> Result<()> { Ok(()) } fn bipush(machine: &mut Machine) -> Result<()> { let val = match machine.block.read_i8() { Ok(a) => a, Err(_) => return Err("Expected argument"), } as i32; machine.cur_stack().push(val); Ok(()) } fn dup(machine: &mut Machine) -> Result<()> { let val = machine.cur_stack().top()?; machine.cur_stack().push(val); Ok(()) } fn out(machine: &mut Machine) -> Result<()> { let val = machine.cur_stack().pop()?; print!("{}", val as u8 as char); ::std::io::stdout().flush().unwrap(); Ok(()) } fn pop(machine: &mut Machine) -> Result<()> { machine.cur_stack().pop()?; Ok(()) } fn iadd(machine: &mut Machine) -> Result<()> { let a = machine.cur_stack().pop()?; let b = machine.cur_stack().pop()?; machine.cur_stack().push(a + b); Ok(()) } fn isub(machine: &mut Machine) -> Result<()> { let a = machine.cur_stack().pop()?; let b = machine.cur_stack().pop()?; machine.cur_stack().push(b - a); Ok(()) } fn _in(machine: &mut Machine) -> Result<()> { let char: Option = ::std::io::stdin() .bytes() .next() .and_then(|r| r.ok()); let val = match char { None => 0 as i32, Some(i) => i as i32 }; machine.cur_stack().push(val); Ok(()) } fn goto(machine: &mut Machine) -> Result<()> { let offset = machine.block.read_i16()? as i32 - JUMP_OFFSET; machine.block.jump(offset) } fn halt(_: &mut Machine) -> Result<()> { Err("Halt") } fn ifeq(machine: &mut Machine) -> Result<()> { let offset = machine.block.read_i16()? as i32 - JUMP_OFFSET; if machine.cur_stack().pop()? == 0 { return machine.block.jump(offset) } Ok(()) } fn iflt(machine: &mut Machine) -> Result<()> { let offset = machine.block.read_i16()? as i32 - JUMP_OFFSET; if machine.cur_stack().pop()? < 0 { return machine.block.jump(offset) } Ok(()) } fn if_icmpeq(machine: &mut Machine) -> Result<()> { let offset = machine.block.read_i16()? as i32 - JUMP_OFFSET; if machine.cur_stack().pop()? == machine.cur_stack().pop()? { return machine.block.jump(offset) } Ok(()) } fn iand(machine: &mut Machine) -> Result<()> { let a = machine.cur_stack().pop()?; let b = machine.cur_stack().pop()?; machine.cur_stack().push(a & b); Ok(()) } fn ior(machine: &mut Machine) -> Result<()> { let a = machine.cur_stack().pop()?; let b = machine.cur_stack().pop()?; machine.cur_stack().push(a | b); Ok(()) } fn ldc_w(machine: &mut Machine) -> Result<()> { let offset = machine.block.read_i16()? as usize; let val = machine.pool.get(offset)?; machine.cur_stack().push(val); Ok(()) } fn swap(machine: &mut Machine) -> Result<()> { let a = machine.cur_stack().pop()?; let b = machine.cur_stack().pop()?; machine.cur_stack().push(a); machine.cur_stack().push(b); Ok(()) } fn wide(machine: &mut Machine) -> Result<()> { machine.wide = true; Ok(()) } fn iload(machine: &mut Machine) -> Result<()> { let a = machine.read_index()?; let val = machine.cur_frame().get(a)?; machine.cur_stack().push(val); Ok(()) } fn istore(machine: &mut Machine) -> Result<()> { let a = machine.read_index()?; let val = machine.cur_stack().pop()?; machine.cur_frame().set(a, val) } fn iinc(machine: &mut Machine) -> Result<()> { let a = machine.read_index()?; let b = machine.block.read_i8()?; let val = machine.cur_frame().get(a)?; machine.cur_frame().set(a, val + b as i32) } fn invokevirtual(machine: &mut Machine) -> Result<()> { let method_index = machine.block.read_u16()?; let invoke_addr = machine.pool.get(method_index as usize)?; let return_addr = machine.get_program_counter(); // println!("METHOD {}", method_index); machine.block.seek(invoke_addr as usize)?; let arg_count = machine.block.read_u16()?; let var_count = machine.block.read_u16()?; let mut newframe = Frame::new((arg_count + var_count) as usize); // Lifetime for cur_stack { let mut cur_stack = machine.cur_stack(); for i in 1..arg_count { newframe.set((arg_count - i) as usize, cur_stack.pop()?)?; } cur_stack.pop()?; // Nuke the OBJREF } // println!("retaddr set {}" ,return_addr); newframe.set(0, return_addr as i32)?; machine.frame.push(newframe); Ok(()) } fn ireturn(machine: &mut Machine) -> Result<()> { let mut prev_frame: Frame = match machine.frame.pop() { Some(a) => a, None => return Err("Got no frame... somehow...") }; // println!("stack: {:?}", prev_frame.stack); let result = prev_frame.stack.pop()?; let return_addr = prev_frame.get(0)?; // println!("result: {}\nretaddr: {}", result, return_addr); machine.cur_stack().push(result); machine.block.seek(return_addr as usize) } fn slp(machine: &mut Machine) -> Result<()> { use std::time; use std::thread; let val = match machine.block.read_u8() { Ok(a) => a, Err(_) => return Err("Expected argument"), } as u64; let slpdur = time::Duration::from_millis(val*100); thread::sleep(slpdur); Ok(()) }