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