Files
RustIJVM/src/ops.rs

351 lines
9.8 KiB
Rust

use binread::BinRead;
use frame::Frame;
use machine::Machine;
use std::io::Read;
use std::num::Wrapping;
use Result;
pub type OpFunc = fn(&mut Machine) -> Result<()>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Args {
Byte,
Short,
Var,
Label,
Constant,
}
#[derive(Clone)]
pub enum Operation {
Op(&'static str, OpFunc, Vec<Args>),
Invalid,
}
const JUMP_OFFSET: i32 = 3;
lazy_static! {
static ref OPS_MAP: Vec<Operation> = {
let mut m = vec![Operation::Invalid; 0xFF + 1];
m[0x00] = Operation::Op("NOP", nop, vec![]);
m[0x10] = Operation::Op("BIPUSH", bipush, vec![Args::Byte]);
m[0x13] = Operation::Op("LDC_W", ldc_w, vec![Args::Constant]);
m[0x15] = Operation::Op("ILOAD", iload, vec![Args::Var]);
m[0x36] = Operation::Op("ISTORE", istore, vec![Args::Var]);
m[0x57] = Operation::Op("POP", pop, vec![]);
m[0x59] = Operation::Op("DUP", dup, vec![]);
m[0x5F] = Operation::Op("SWAP", swap, vec![]);
m[0x60] = Operation::Op("IADD", iadd, vec![]);
m[0x64] = Operation::Op("ISUB", isub, vec![]);
m[0x7E] = Operation::Op("IAND", iand, vec![]);
m[0xB0] = Operation::Op("IOR", ior, vec![]);
m[0x84] = Operation::Op("IINC", iinc, vec![Args::Var, Args::Byte]);
m[0x99] = Operation::Op("IFEQ", ifeq, vec![Args::Label]);
m[0x9b] = Operation::Op("IFLT", iflt, vec![Args::Label]);
m[0x9F] = Operation::Op("IF_ICMPEQ", if_icmpeq, vec![Args::Label]);
m[0xA7] = Operation::Op("GOTO", goto, vec![Args::Label]);
m[0xAC] = Operation::Op("IRETURN", ireturn, vec![]);
m[0xB6] = Operation::Op("INVOKEVIRTUAL", invokevirtual, vec![Args::Constant]);
m[0xC4] = Operation::Op("WIDE", wide, vec![]);
m[0xFC] = Operation::Op("IN", _in, vec![]);
m[0xFD] = Operation::Op("OUT", out, vec![]);
m[0xFE] = Operation::Op("ERR", err, vec![]);
m[0xFF] = Operation::Op("HALT", halt, vec![]);
#[cfg(feature = "extra:sleep")]
{
m[0xF0] = Operation::Op("SLP", slp, vec![Args::Byte]);
}
#[cfg(feature = "bonus:network")]
{
m[0xE1] = Operation::Op("NETBIND", netbind, vec![]);
m[0xE2] = Operation::Op("NETCONNECT", netconnect, vec![]);
m[0xE3] = Operation::Op("NETIN", netin, vec![]);
m[0xE4] = Operation::Op("NETOUT", netout, vec![]);
m[0xE5] = Operation::Op("NETCLOSE", netclose, vec![]);
}
#[cfg(feature = "bonus:heap")]
{
m[0xD1] = Operation::Op("NEWARRAY", newarray, vec![]);
m[0xD2] = Operation::Op("IALOAD", iaload, vec![]);
m[0xD3] = Operation::Op("IASTORE", iastore, vec![]);
}
m
};
}
pub fn num_to_op(op: u8) -> &'static Operation {
&OPS_MAP[op as usize]
}
fn nop(_: &mut Machine) -> Result<()> {
Ok(())
}
fn bipush(machine: &mut Machine) -> Result<()> {
let val = match machine.block.read_i8() {
Ok(a) => i32::from(a),
Err(_) => return Err("Expected argument"),
};
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()?;
let buffer = [val as u8];
let mut out = machine.stream_out.lock().unwrap();
out.write_all(&buffer).unwrap();
out.flush().unwrap();
Ok(())
}
fn pop(machine: &mut Machine) -> Result<()> {
machine.cur_stack().pop()?;
Ok(())
}
fn iadd(machine: &mut Machine) -> Result<()> {
let a = Wrapping(machine.cur_stack().pop()?);
let b = Wrapping(machine.cur_stack().pop()?);
machine.cur_stack().push((a + b).0);
Ok(())
}
fn isub(machine: &mut Machine) -> Result<()> {
let a = Wrapping(machine.cur_stack().pop()?);
let b = Wrapping(machine.cur_stack().pop()?);
machine.cur_stack().push((b - a).0);
Ok(())
}
fn _in(machine: &mut Machine) -> Result<()> {
let mut buffer = [0; 1];
let val = match machine.stream_in.read_exact(&mut buffer) {
Err(_) => 0i32,
Ok(_) => i32::from(buffer[0]),
};
machine.cur_stack().push(val);
Ok(())
}
fn goto(machine: &mut Machine) -> Result<()> {
let offset = i32::from(machine.block.read_i16()?) - JUMP_OFFSET;
machine.block.jump(offset)
}
fn err(machine: &mut Machine) -> Result<()> {
machine.halted = true;
eprintln!("MACHINE CALLED ERR");
Ok(())
}
fn halt(machine: &mut Machine) -> Result<()> {
machine.halted = true;
Ok(())
}
fn ifeq(machine: &mut Machine) -> Result<()> {
let offset = i32::from(machine.block.read_i16()?) - JUMP_OFFSET;
if machine.cur_stack().pop()? == 0 {
return machine.block.jump(offset);
}
Ok(())
}
fn iflt(machine: &mut Machine) -> Result<()> {
let offset = i32::from(machine.block.read_i16()?) - JUMP_OFFSET;
if machine.cur_stack().pop()? < 0 {
return machine.block.jump(offset);
}
Ok(())
}
fn if_icmpeq(machine: &mut Machine) -> Result<()> {
let offset = i32::from(machine.block.read_i16()?) - 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;
machine.step()
}
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 = i32::from(machine.block.read_i8()?);
let val = machine.cur_frame().get(a)?;
machine.cur_frame().set(a, val + b)
}
fn invokevirtual(machine: &mut Machine) -> Result<()> {
let method_index = machine.block.read_u16()?;
let invoke_addr = machine.pool.get(method_index as usize)? as usize;
let return_addr = machine.get_program_counter();
machine.block.seek(invoke_addr)?;
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, invoke_addr);
// Lifetime for cur_stack
{
let 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
}
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..."),
};
let result = prev_frame.stack.pop()?;
let return_addr = prev_frame.get(0)?;
machine.cur_stack().push(result);
machine.block.seek(return_addr as usize)
}
#[cfg(feature = "extra:sleep")]
fn slp(machine: &mut Machine) -> Result<()> {
use std::thread;
use std::time;
let val = match machine.block.read_u8() {
Ok(a) => u64::from(a),
Err(_) => return Err("Expected argument"),
};
let slpdur = time::Duration::from_millis(val * 100);
thread::sleep(slpdur);
Ok(())
}
#[cfg(feature = "bonus:network")]
fn netbind(machine: &mut Machine) -> Result<()> {
let port = machine.cur_stack().pop()? as u16;
machine.net.bind(port)
}
#[cfg(feature = "bonus:network")]
fn netconnect(machine: &mut Machine) -> Result<()> {
let port = machine.cur_stack().pop()? as u16;
let host = machine.cur_stack().pop()? as u32;
machine.net.connect(host, port)
}
#[cfg(feature = "bonus:network")]
fn netin(machine: &mut Machine) -> Result<()> {
let byte = i32::from(machine.net.read_byte()?);
machine.cur_stack().push(byte);
Ok(())
}
#[cfg(feature = "bonus:network")]
fn netout(machine: &mut Machine) -> Result<()> {
let val = machine.cur_stack().pop()? as u8;
machine.net.write_byte(val)
}
#[cfg(feature = "bonus:network")]
fn netclose(machine: &mut Machine) -> Result<()> {
machine.net.close()
}
#[cfg(feature = "bonus:heap")]
fn newarray(machine: &mut Machine) -> Result<()> {
let size = machine.cur_stack().pop()? as usize;
let heapref = machine.heap.alloc(size);
machine.cur_stack().push(heapref as i32);
Ok(())
}
#[cfg(feature = "bonus:heap")]
fn iastore(machine: &mut Machine) -> Result<()> {
let heapref = machine.cur_stack().pop()? as usize;
let index = machine.cur_stack().pop()? as usize;
let value = machine.cur_stack().pop()?;
let heap = machine.heap.get(heapref);
heap[index] = value;
Ok(())
}
#[cfg(feature = "bonus:heap")]
fn iaload(machine: &mut Machine) -> Result<()> {
let heapref = machine.cur_stack().pop()? as usize;
let index = machine.cur_stack().pop()? as usize;
let value: i32;
{
let heap = machine.heap.get(heapref);
value = heap[index];
}
machine.cur_stack().push(value);
Ok(())
}