From 6ed58151ee67c7f7f12711481d053c7da555b219 Mon Sep 17 00:00:00 2001 From: Jur van den Berg Date: Mon, 8 Apr 2019 16:03:49 +0200 Subject: [PATCH] Now with a hashmap for ops lookup --- Cargo.lock | 9 ++++ Cargo.toml | 1 + src/binread.rs | 16 +++--- src/disassembler.rs | 64 ++++++++++++----------- src/lib.rs | 2 + src/machine.rs | 53 ++++++++++--------- src/ops.rs | 123 +++++++++++++++++++++++++------------------- 7 files changed, 149 insertions(+), 119 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c4f715..1b01c60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,10 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "lazy_static" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "proc-macro2" version = "0.4.4" @@ -18,6 +25,7 @@ dependencies = [ name = "rustijvm" version = "1.0.0" dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -53,6 +61,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum proc-macro2 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1fa93823f53cfd0f5ac117b189aed6cfdfb2cfc0a9d82e956dd7927595ed7d46" "checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" "checksum serde 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)" = "5d47469df098fe8701d4da22680da5145e83801bdaaafea0cf91a180436fc343" diff --git a/Cargo.toml b/Cargo.toml index b587d3f..e63c1e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ authors = ["Jur van den Berg "] [dependencies] serde = "1.0" serde_derive = "1.0" +lazy_static = "1.3.0" [features] default = ["bonus", "extra"] diff --git a/src/binread.rs b/src/binread.rs index 13121cd..461eb88 100644 --- a/src/binread.rs +++ b/src/binread.rs @@ -1,13 +1,13 @@ -use Result; use block::Block; -use ops::{Operation,num_to_op}; +use ops::{num_to_op, Operation}; +use Result; +#[allow(unknown_lints, len_without_is_empty)] pub trait BinReadable { fn get(&mut self) -> Result; fn cur(&self) -> usize; fn len(&self) -> usize; fn slice(&mut self, len: usize) -> &[u8]; - fn is_empty(&self) -> bool; } @@ -25,7 +25,7 @@ pub trait BinRead { fn read_i32(&mut self) -> Result; fn read_block(&mut self) -> Result; - fn read_op(&mut self) -> Result; + fn read_op(&mut self) -> Result<&'static Operation>; } impl BinRead for T { @@ -47,13 +47,13 @@ impl BinRead for T { fn read_u16(&mut self) -> Result { let a = u16::from(self.read_u8()?); - let b = u16::from( self.read_u8()?); + let b = u16::from(self.read_u8()?); Ok(a << 8 | b) } fn read_u32(&mut self) -> Result { let a = u32::from(self.read_u16()?); - let b = u32::from( self.read_u16()?); + let b = u32::from(self.read_u16()?); Ok(a << 16 | b) } fn read_i8(&mut self) -> Result { @@ -78,7 +78,7 @@ impl BinRead for T { Ok(Block::new(origin, self.slice(len))) } - fn read_op(&mut self) -> Result { + fn read_op(&mut self) -> Result<&'static Operation> { Ok(num_to_op(self.read_u8()?)) } -} \ No newline at end of file +} diff --git a/src/disassembler.rs b/src/disassembler.rs index 259e1c2..4a62730 100644 --- a/src/disassembler.rs +++ b/src/disassembler.rs @@ -1,12 +1,12 @@ +use binread::{BinRead, BinReadable}; use block::Block; use ijvmreader::IJVMReader; -use binread::{BinRead, BinReadable}; use machine::MAGIC_HEADER; -use Result; use ops; +use Result; -use std::collections::HashMap; use std::clone::Clone; +use std::collections::HashMap; use std::fmt; use std::rc::Rc; @@ -73,7 +73,7 @@ pub struct Instruction { op: OpCode, name: &'static str, params: Vec, - types: Vec, + types: &'static Vec, wide: bool, pos: usize, label: bool, @@ -84,7 +84,8 @@ pub struct Instruction { impl fmt::Display for Instruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.label { - let name = self.symbols + let name = self + .symbols .lookup_label(self.pos) .unwrap_or_else(|| format!("LBL_{}", self.pos)); writeln!(f, "\n{}:", name)?; @@ -99,14 +100,16 @@ impl fmt::Display for Instruction { for (typ, val) in self.types.iter().zip(&self.params) { match *typ { ops::Args::Label => { - let name = self.symbols + let name = self + .symbols .lookup_label(*val as usize) .unwrap_or_else(|| format!("LBL_{}", val)); write!(f, " {}", name)?; - }, + } ops::Args::Constant => { if self.op == 0xB6 { - let name = self.symbols + let name = self + .symbols .lookup_method_idx(*val as usize) .unwrap_or_else(|| format!("func_{}", val)); @@ -114,7 +117,7 @@ impl fmt::Display for Instruction { } else { write!(f, " CONST_{}", val)?; } - }, + } ops::Args::Var => write!(f, " var{}", val)?, _ => write!(f, " {}", val)?, } @@ -166,16 +169,15 @@ impl Method { } pub fn update_vars(&mut self) { - let max = self.instructions + let max = self + .instructions .iter() .filter(|e| !e.types.is_empty()) - .filter(|e| { - match e.types[0] { - ops::Args::Var => true, - _ => false, - } + .filter(|e| match e.types[0] { + ops::Args::Var => true, + _ => false, }) - .map(|e| e.params[0] ) + .map(|e| e.params[0]) .max(); if let Some(v) = max { @@ -205,7 +207,7 @@ impl fmt::Display for Method { write!(f, "{}var{}", comma, i)?; comma = ", "; } - writeln!(f,")")?; + writeln!(f, ")")?; 0 }; @@ -223,7 +225,6 @@ impl fmt::Display for Method { write!(f, "{}", inst)?; } - if self.name == "main" { writeln!(f, "\n.end-main\n")?; } else { @@ -273,10 +274,10 @@ impl Disassembler { } let (name, args) = match ops::num_to_op(opcode) { - ops::Operation::Invalid(x) => { - eprintln!("INVALID OP 0x{:X}\n", x); + ops::Operation::Invalid => { + eprintln!("INVALID OP 0x{:X}\n", opcode); return Err("Invalid operation"); - }, + } ops::Operation::Op(name, _, args) => (name, args), }; @@ -290,7 +291,7 @@ impl Disassembler { } else { i32::from(self.text.read_u8()?) } - }, + } ops::Args::Label => { let offset = self.text.read_i16()?; let target = pos as i64 + i64::from(offset); @@ -299,7 +300,7 @@ impl Disassembler { } method.labels.push(target as usize); target as i32 - }, + } ops::Args::Constant => i32::from(self.text.read_u16()?), }; params.push(v); @@ -338,7 +339,8 @@ impl Disassembler { let arg_count = (self.text.read_u16()? - 1) as usize; let var_count = self.text.read_u16()? as usize; - let callee = self.disasm_method(inst.params[0], target_addr, arg_count, var_count)?; + let callee = + self.disasm_method(inst.params[0], target_addr, arg_count, var_count)?; self.disassembly.methods.push(callee); self.text.seek(save_pos)?; @@ -351,7 +353,10 @@ impl Disassembler { } fn disasm_method(&mut self, i: i32, pc: usize, args: usize, vars: usize) -> Result { - let name = self.symbols.lookup_method(pc).unwrap_or_else(|| format!("func_{}", i)); + let name = self + .symbols + .lookup_method(pc) + .unwrap_or_else(|| format!("func_{}", i)); let mut method = Method::new(name, pc, args, vars); while self.text.has_i8() && !self.is_method(self.text.cur()) { @@ -400,7 +405,6 @@ impl Disassembler { main.update_vars(); self.disassembly.methods.insert(0, main); - Ok(self.disassembly.clone()) } } @@ -419,14 +423,13 @@ impl Disassembly { } let mut pool = match reader.read_block() { Ok(a) => a, - Err(_) => return Err("Failed to read constants block") + 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") + Err(_) => return Err("Failed to read text block"), }; - let mut symbols = DebugSymbols::default(); if let Ok(block) = reader.read_block() { symbols.add_methods(block)?; @@ -454,14 +457,13 @@ impl Disassembly { let reader = IJVMReader::new_from_slice(source); Self::disassemble_reader(reader) } - } impl fmt::Display for Disassembly { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if !self.constants.is_empty() { writeln!(f, ".constant")?; - for (i, c) in self.constants.iter().enumerate() { + for (i, c) in self.constants.iter().enumerate() { if !c.method { writeln!(f, " CONST_{:<6} {}", i, c.value)?; } diff --git a/src/lib.rs b/src/lib.rs index a6bf2db..df4f386 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,7 @@ #[macro_use] extern crate serde_derive; +#[macro_use] +extern crate lazy_static; pub mod ijvmreader; pub mod binread; diff --git a/src/machine.rs b/src/machine.rs index 541cef1..7138a13 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,22 +1,22 @@ use std::io::{Read, Write}; -use std::sync::{Mutex, Arc}; +use std::sync::{Arc, Mutex}; -use Result; -use block::Block; -use ops::{Operation, Args, num_to_op}; -use ijvmreader::IJVMReader; use binread::{BinRead, BinReadable}; +use block::Block; use frame::Frame; -use stack::Stack; +use ijvmreader::IJVMReader; +use ops::{num_to_op, Args, Operation}; use pool::Pool; +use stack::Stack; +use Result; -#[cfg(feature = "bonus:network")] -use netstack::NetStack; #[cfg(feature = "bonus:heap")] use heap::Heap; +#[cfg(feature = "bonus:network")] +use netstack::NetStack; -pub const MAGIC_HEADER:u32 = 0x1DEA_DFAD; -const ANTI_BS_SIZE:usize = 0xFF; +pub const MAGIC_HEADER: u32 = 0x1DEA_DFAD; +const ANTI_BS_SIZE: usize = 0xFF; pub struct Machine { pub wide: bool, @@ -32,11 +32,10 @@ pub struct Machine { pub stream_in: Box, pub stream_out: Arc>, - } impl Machine { - pub fn new(pool: Pool, block: Block) -> Machine{ + pub fn new(pool: Pool, block: Block) -> Machine { Machine { wide: false, halted: false, @@ -61,11 +60,11 @@ impl Machine { } let constants = match reader.read_block() { Ok(a) => a, - Err(_) => return Err("Failed to read constants block") + 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") + Err(_) => return Err("Failed to read text block"), }; let pool = Pool::new(constants)?; @@ -95,12 +94,12 @@ impl Machine { } else { func(self) } - }, - Ok(Operation::Invalid(a)) => { - println!("UNDEFINED OP: 0x{:X}", a); + } + Ok(Operation::Invalid) => { + println!("Reached invalid operation"); Err("Invalid op") - }, - Err(str) => Err(str) + } + Err(str) => Err(str), } } @@ -149,11 +148,11 @@ impl Machine { } let (name, args) = match num_to_op(opcode) { - Operation::Invalid(_) => return Err("Invalid operation"), + Operation::Invalid => return Err("Invalid operation"), Operation::Op(name, _, args) => (name, args), }; - for arg in &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()?), @@ -163,7 +162,7 @@ impl Machine { } else { i32::from(self.block.read_u8()?) } - }, + } Args::Label => i32::from(self.block.read_i16()?), Args::Constant => i32::from(self.block.read_u16()?), }; @@ -174,14 +173,14 @@ impl Machine { Ok((name.to_string(), params)) } -// pub fn get_stack_pointer(&self) -> usize { -// return self.frame.last().unwrap().stack.len(); -// } + // 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) + return Ok(self.block.read_u16()? as usize); } Ok(self.block.read_u8()? as usize) } @@ -193,4 +192,4 @@ impl Machine { pub fn set_output(&mut self, outstream: Arc>) { self.stream_out = outstream; } -} \ No newline at end of file +} diff --git a/src/ops.rs b/src/ops.rs index ef3ed74..ec1a6f5 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -1,8 +1,10 @@ use binread::BinRead; -use machine::Machine; use frame::Frame; +use machine::Machine; +use std::collections::HashMap; +use std::io::Read; +use std::num::Wrapping; use Result; -use std::io::{Read}; pub type OpFunc = fn(&mut Machine) -> Result<()>; @@ -17,61 +19,77 @@ pub enum Args { pub enum Operation { Op(&'static str, OpFunc, Vec), - Invalid(u8) + Invalid, } const JUMP_OFFSET: i32 = 3; +const INVALID_OP: Operation = Operation::Invalid; -pub fn num_to_op(op: u8) -> Operation { - match op { - 0x00 => Operation::Op("NOP", nop, vec![]), - 0x10 => Operation::Op("BIPUSH", bipush, vec![Args::Byte]), - 0x13 => Operation::Op("LDC_W", ldc_w, vec![Args::Constant]), - 0x15 => Operation::Op("ILOAD", iload, vec![Args::Var]), - 0x36 => Operation::Op("ISTORE", istore, vec![Args::Var]), - 0x57 => Operation::Op("POP", pop, vec![]), - 0x59 => Operation::Op("DUP", dup, vec![]), - 0x5F => Operation::Op("SWAP", swap, vec![]), - 0x60 => Operation::Op("IADD", iadd, vec![]), - 0x64 => Operation::Op("ISUB", isub, vec![]), - 0x7E => Operation::Op("IAND", iand, vec![]), - 0xB0 => Operation::Op("IOR", ior, vec![]), - 0x84 => Operation::Op("IINC", iinc, vec![Args::Var, Args::Byte]), - 0x99 => Operation::Op("IFEQ", ifeq, vec![Args::Label]), - 0x9b => Operation::Op("IFLT", iflt, vec![Args::Label]), - 0x9F => Operation::Op("IF_ICMPEQ", if_icmpeq, vec![Args::Label]), - 0xA7 => Operation::Op("GOTO", goto, vec![Args::Label]), - 0xAC => Operation::Op("IRETURN", ireturn, vec![]), - 0xB6 => Operation::Op("INVOKEVIRTUAL", invokevirtual, vec![Args::Constant]), - 0xC4 => Operation::Op("WIDE", wide, vec![]), - 0xFC => Operation::Op("IN", _in, vec![]), - 0xFD => Operation::Op("OUT", out, vec![]), - 0xFE => Operation::Op("ERR", err, vec![]), - 0xFF => Operation::Op("HALT", halt, vec![]), +lazy_static! { + static ref OPS_MAP: HashMap = { + let mut m = HashMap::new(); + + m.insert(0x00, Operation::Op("NOP", nop, vec![])); + m.insert(0x10, Operation::Op("BIPUSH", bipush, vec![Args::Byte])); + m.insert(0x13, Operation::Op("LDC_W", ldc_w, vec![Args::Constant])); + m.insert(0x15, Operation::Op("ILOAD", iload, vec![Args::Var])); + m.insert(0x36, Operation::Op("ISTORE", istore, vec![Args::Var])); + m.insert(0x57, Operation::Op("POP", pop, vec![])); + m.insert(0x59, Operation::Op("DUP", dup, vec![])); + m.insert(0x5F, Operation::Op("SWAP", swap, vec![])); + m.insert(0x60, Operation::Op("IADD", iadd, vec![])); + m.insert(0x64, Operation::Op("ISUB", isub, vec![])); + m.insert(0x7E, Operation::Op("IAND", iand, vec![])); + m.insert(0xB0, Operation::Op("IOR", ior, vec![])); + m.insert( + 0x84, + Operation::Op("IINC", iinc, vec![Args::Var, Args::Byte]), + ); + m.insert(0x99, Operation::Op("IFEQ", ifeq, vec![Args::Label])); + m.insert(0x9b, Operation::Op("IFLT", iflt, vec![Args::Label])); + m.insert( + 0x9F, + Operation::Op("IF_ICMPEQ", if_icmpeq, vec![Args::Label]), + ); + m.insert(0xA7, Operation::Op("GOTO", goto, vec![Args::Label])); + m.insert(0xAC, Operation::Op("IRETURN", ireturn, vec![])); + m.insert( + 0xB6, + Operation::Op("INVOKEVIRTUAL", invokevirtual, vec![Args::Constant]), + ); + m.insert(0xC4, Operation::Op("WIDE", wide, vec![])); + m.insert(0xFC, Operation::Op("IN", _in, vec![])); + m.insert(0xFD, Operation::Op("OUT", out, vec![])); + m.insert(0xFE, Operation::Op("ERR", err, vec![])); + m.insert(0xFF, Operation::Op("HALT", halt, vec![])); #[cfg(feature = "extra:sleep")] - 0xF0 => Operation::Op("SLP", slp, vec![Args::Byte]), + m.insert(0xF0, Operation::Op("SLP", slp, vec![Args::Byte])); #[cfg(feature = "bonus:network")] - 0xE1 => Operation::Op("NETBIND", netbind, vec![]), + m.insert(0xE1, Operation::Op("NETBIND", netbind, vec![])); #[cfg(feature = "bonus:network")] - 0xE2 => Operation::Op("NETCONNECT", netconnect, vec![]), + m.insert(0xE2, Operation::Op("NETCONNECT", netconnect, vec![])); #[cfg(feature = "bonus:network")] - 0xE3 => Operation::Op("NETIN", netin, vec![]), + m.insert(0xE3, Operation::Op("NETIN", netin, vec![])); #[cfg(feature = "bonus:network")] - 0xE4 => Operation::Op("NETOUT", netout, vec![]), + m.insert(0xE4, Operation::Op("NETOUT", netout, vec![])); #[cfg(feature = "bonus:network")] - 0xE5 => Operation::Op("NETCLOSE", netclose, vec![]), + m.insert(0xE5, Operation::Op("NETCLOSE", netclose, vec![])); #[cfg(feature = "bonus:heap")] - 0xD1 => Operation::Op("NEWARRAY", newarray, vec![]), + m.insert(0xD1, Operation::Op("NEWARRAY", newarray, vec![])); #[cfg(feature = "bonus:heap")] - 0xD2 => Operation::Op("IALOAD", iaload, vec![]), + m.insert(0xD2, Operation::Op("IALOAD", iaload, vec![])); #[cfg(feature = "bonus:heap")] - 0xD3 => Operation::Op("IASTORE", iastore, vec![]), + m.insert(0xD3, Operation::Op("IASTORE", iastore, vec![])); - x => Operation::Invalid(x) - } + m + }; +} + +pub fn num_to_op(op: u8) -> &'static Operation { + OPS_MAP.get(&op).unwrap_or(&INVALID_OP) } fn nop(_: &mut Machine) -> Result<()> { @@ -108,16 +126,16 @@ fn pop(machine: &mut Machine) -> Result<()> { } fn iadd(machine: &mut Machine) -> Result<()> { - let a = machine.cur_stack().pop()?; - let b = machine.cur_stack().pop()?; - machine.cur_stack().push(a + b); + 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 = machine.cur_stack().pop()?; - let b = machine.cur_stack().pop()?; - machine.cur_stack().push(b - a); + let a = Wrapping(machine.cur_stack().pop()?); + let b = Wrapping(machine.cur_stack().pop()?); + machine.cur_stack().push((b - a).0); Ok(()) } @@ -150,7 +168,7 @@ fn halt(machine: &mut Machine) -> Result<()> { 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) + return machine.block.jump(offset); } Ok(()) } @@ -158,7 +176,7 @@ fn ifeq(machine: &mut Machine) -> Result<()> { 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) + return machine.block.jump(offset); } Ok(()) } @@ -166,7 +184,7 @@ fn iflt(machine: &mut Machine) -> Result<()> { 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) + return machine.block.jump(offset); } Ok(()) } @@ -249,13 +267,12 @@ fn invokevirtual(machine: &mut Machine) -> Result<()> { 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...") + None => return Err("Got no frame... somehow..."), }; let result = prev_frame.stack.pop()?; let return_addr = prev_frame.get(0)?; @@ -265,13 +282,13 @@ fn ireturn(machine: &mut Machine) -> Result<()> { #[cfg(feature = "extra:sleep")] fn slp(machine: &mut Machine) -> Result<()> { - use std::time; 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); + let slpdur = time::Duration::from_millis(val * 100); thread::sleep(slpdur); Ok(()) }