Passing all tests i guess

This commit is contained in:
2017-06-06 14:19:35 +02:00
commit 1b3c582ee2
13 changed files with 699 additions and 0 deletions

245
src/ijvm/ops.rs Normal file
View File

@@ -0,0 +1,245 @@
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<u8> =
::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(())
}