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]]
|
||||
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"
|
||||
|
||||
@@ -6,6 +6,7 @@ authors = ["Jur van den Berg <Jurl.berg@gmail.com>"]
|
||||
[dependencies]
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
lazy_static = "1.3.0"
|
||||
|
||||
[features]
|
||||
default = ["bonus", "extra"]
|
||||
|
||||
@@ -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<u8>;
|
||||
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<i32>;
|
||||
|
||||
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 {
|
||||
@@ -47,13 +47,13 @@ impl<T: BinReadable> BinRead for T {
|
||||
|
||||
fn read_u16(&mut self) -> Result<u16> {
|
||||
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<u32> {
|
||||
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<i8> {
|
||||
@@ -78,7 +78,7 @@ impl<T: BinReadable> BinRead for T {
|
||||
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()?))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<i32>,
|
||||
types: Vec<ops::Args>,
|
||||
types: &'static Vec<ops::Args>,
|
||||
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<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);
|
||||
|
||||
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)?;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
pub mod ijvmreader;
|
||||
pub mod binread;
|
||||
|
||||
@@ -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<Read + Send + Sync>,
|
||||
pub stream_out: Arc<Mutex<Write + Send + Sync>>,
|
||||
|
||||
}
|
||||
|
||||
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<usize> {
|
||||
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<Mutex<Write + Send + Sync>>) {
|
||||
self.stream_out = outstream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
123
src/ops.rs
123
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<Args>),
|
||||
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<u8, Operation> = {
|
||||
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(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user