Compare commits

...

2 Commits

9 changed files with 119 additions and 97 deletions

58
Cargo.lock generated
View File

@@ -1,70 +1,70 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "lazy_static"
version = "1.3.0"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "proc-macro2"
version = "0.4.4"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-ident",
]
[[package]]
name = "quote"
version = "0.6.3"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
]
[[package]]
name = "rustijvm"
version = "1.0.0"
version = "1.1.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)",
"lazy_static",
"serde",
"serde_derive",
]
[[package]]
name = "serde"
version = "1.0.65"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
[[package]]
name = "serde_derive"
version = "1.0.65"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
dependencies = [
"proc-macro2 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "0.14.1"
version = "1.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf"
dependencies = [
"proc-macro2 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-xid"
version = "0.1.0"
name = "unicode-ident"
version = "1.0.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"
"checksum serde_derive 1.0.65 (registry+https://github.com/rust-lang/crates.io-index)" = "35eff0f5f70b6a2e902a2bbf4b079be4aacb14afc9676ba4798e0486401cedcb"
"checksum syn 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6dfd71b2be5a58ee30a6f8ea355ba8290d397131c00dfa55c3d34e6e13db5101"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"

View File

@@ -1,25 +1,25 @@
[package]
name = "rustijvm"
version = "1.0.0"
version = "1.1.0"
authors = ["Jur van den Berg <Jurl.berg@gmail.com>"]
[dependencies]
serde = "1.0"
serde_derive = "1.0"
lazy_static = "1.3.0"
lazy_static = "1.4.0"
[features]
default = ["bonus", "extra"]
bonus = ["bonus:network", "bonus:heap"]
"bonus:network" = []
"bonus:heap" = []
bonus = ["bonus.network", "bonus.heap"]
"bonus.network" = []
"bonus.heap" = []
extra = ["extra:sleep", "extra:arithmetic"]
"extra:sleep" = []
"extra:arithmetic" = []
extra = ["extra.sleep", "extra.arithmetic"]
"extra.sleep" = []
"extra.arithmetic" = []
debug = ["debug:instr", "debug:frame", "debug:gc"]
"debug:instr" = []
"debug:frame" = []
"debug:gc" = []
debug = ["debug.instr", "debug.frame", "debug.gc"]
"debug.instr" = []
"debug.frame" = []
"debug.gc" = []

View File

@@ -5,6 +5,8 @@ use binread::BinReadable;
#[derive(Debug)]
pub struct Block {
// Origin is part of the spec, and while we never use it, I'd rather keep it
#[allow(dead_code)]
origin: u32,
length: usize,

View File

@@ -6,7 +6,7 @@ use ops;
use Result;
use std::clone::Clone;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::rc::Rc;
@@ -47,27 +47,18 @@ impl DebugSymbols {
}
fn lookup_method(&self, location: usize) -> Option<String> {
match self.methods.get(&location) {
Some(name) => Some(name.to_string()),
None => None,
}
self.methods.get(&location).map(|name| name.to_string())
}
fn lookup_method_idx(&self, idx: usize) -> Option<String> {
if idx >= self.constants.len() {
return None;
}
match self.methods.get(&self.constants[idx]) {
Some(name) => Some(name.to_string()),
None => None,
}
self.methods.get(&self.constants[idx]).map(|name| name.to_string())
}
fn lookup_label(&self, location: usize) -> Option<String> {
match self.labels.get(&location) {
Some(name) => Some(name.to_string()),
None => None,
}
self.labels.get(&location).map(|name| name.to_string())
}
}
@@ -176,10 +167,7 @@ impl Method {
.instructions
.iter()
.filter(|e| !e.types.is_empty())
.filter(|e| match e.types[0] {
ops::Args::Var => true,
_ => false,
})
.filter(|e| matches!(e.types[0], ops::Args::Var))
.map(|e| e.params[0])
.max();
@@ -244,7 +232,7 @@ pub struct Disassembler {
text: Block,
pool: Block,
symbols: Rc<DebugSymbols>,
suspects: Vec<usize>,
suspects: HashSet<usize>,
found: Vec<usize>,
}
@@ -255,7 +243,7 @@ impl Disassembler {
text,
pool,
symbols: Rc::new(symbols),
suspects: Vec::new(),
suspects: HashSet::new(),
found: Vec::new(),
}
}
@@ -278,6 +266,31 @@ impl Disassembler {
let (name, args) = match ops::num_to_op(opcode) {
ops::Operation::Invalid => {
// There is a slight edge case here. It *could* be that the invalid op was a dead method.
// (i.e. method that is not called)
// I will not try to convince anyone this will catch all dead methods, but it's worth a shot
// So see if a constant with that *value* exists, if so add it to the suspects list and pray
if self.disassembly.constants.iter().any(|v| v.value == pos as i32) {
self.suspects.insert(pos);
// And rewind the tape to before we started parsing this to let it try again
return self.text.seek(pos);
}
// Fine another edge case then:
// usually the first method byte is 0x00 -> nop
// if this is the case, check if the nop is the method start
if let Some(previous_instruction) = method.instructions.last().cloned() {
if previous_instruction.op == 0x00 && self.disassembly.constants.iter().any(|v| v.value == previous_instruction.pos as i32) {
// Oh wow, this might work then
self.suspects.insert(previous_instruction.pos);
method.instructions.pop();
// And rewind the tape to before we started parsing this to let it try again
return self.text.seek(previous_instruction.pos);
}
}
eprintln!("INVALID OP 0x{:X}\n", opcode);
return Err("Invalid operation");
}
@@ -375,9 +388,7 @@ impl Disassembler {
Ok(method)
}
fn find_methods(&mut self) -> Result<Vec<usize>> {
let mut res = Vec::new();
fn find_method_suspects(&mut self) -> Result<()> {
while self.text.has_i8() {
let op = self.text.read_u8()?;
// INVOKEVIRTUAL
@@ -391,13 +402,13 @@ impl Disassembler {
let v = self.text[constant.value as usize];
if v == 0 {
res.push(constant.value as usize);
self.suspects.insert(constant.value as usize);
}
}
}
self.text.seek(0)?;
Ok(res)
Ok(())
}
pub fn disassemble(&mut self) -> Result<Disassembly> {
@@ -406,7 +417,15 @@ impl Disassembler {
self.disassembly.constants.push(Constant::new(addr));
}
self.suspects = self.find_methods()?;
self.find_method_suspects()?;
if !self.symbols.methods.is_empty() {
for &pos in self.symbols.methods.keys() {
if pos == 0 {
continue;
}
self.suspects.insert(pos);
}
}
let mut main = self.disasm_method(-1, 0, 0, 0)?;
main.update_vars();
@@ -442,6 +461,7 @@ impl Disassembly {
let mut symbols = DebugSymbols::default();
if let Ok(block) = reader.read_block() {
symbols.add_methods(block)?;
if let Ok(labels) = reader.read_block() {
symbols.add_labels(labels)?;
}
@@ -470,7 +490,7 @@ impl Disassembly {
impl fmt::Display for Disassembly {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if !self.constants.is_empty() {
if self.constants.iter().any(|c| !c.method) {
writeln!(f, ".constant")?;
for (i, c) in self.constants.iter().enumerate() {
if !c.method {

View File

@@ -12,7 +12,7 @@ pub struct Frame {
impl Frame {
pub fn new(num_locals: usize, base: usize) -> Frame {
if cfg!(feature = "debug:frame") {
if cfg!(feature = "debug.frame") {
println!("Initializing frame of len {}", num_locals);
}
Frame {
@@ -24,7 +24,7 @@ impl Frame {
}
pub fn new_extendable(base: usize) -> Frame {
if cfg!(feature = "debug:frame") {
if cfg!(feature = "debug.frame") {
println!("Initializing extendable frame");
}
Frame {

View File

@@ -14,9 +14,9 @@ pub mod pool;
pub mod frame;
pub mod stubs;
#[cfg(feature = "bonus:network")]
#[cfg(feature = "bonus.network")]
pub mod netstack;
#[cfg(feature = "bonus:heap")]
#[cfg(feature = "bonus.heap")]
pub mod heap;
type Result<T> = ::std::result::Result<T, &'static str>;

View File

@@ -10,9 +10,9 @@ use pool::Pool;
use stack::Stack;
use Result;
#[cfg(feature = "bonus:heap")]
#[cfg(feature = "bonus.heap")]
use heap::Heaps;
#[cfg(feature = "bonus:network")]
#[cfg(feature = "bonus.network")]
use netstack::NetStack;
use std::convert::TryInto;
@@ -25,9 +25,9 @@ pub struct Machine {
pub block: Block,
pub frame: Vec<Frame>,
#[cfg(feature = "bonus:network")]
#[cfg(feature = "bonus.network")]
pub net: NetStack,
#[cfg(feature = "bonus:heap")]
#[cfg(feature = "bonus.heap")]
pub heap: Heaps,
pub stream_in: Box<dyn Read + Send + Sync>,
@@ -45,10 +45,10 @@ impl Machine {
stream_in: Box::new(::std::io::stdin()),
stream_out: Arc::new(Mutex::new(::std::io::stdout())),
#[cfg(feature = "bonus:network")]
#[cfg(feature = "bonus.network")]
net: NetStack::new(),
#[cfg(feature = "bonus:heap")]
#[cfg(feature = "bonus.heap")]
heap: Heaps::new(),
}
}
@@ -85,7 +85,7 @@ impl Machine {
pub fn step(&mut self) -> Result<()> {
match self.block.read_op() {
Ok(Operation::Op(a, func, _)) => {
if cfg!(feature = "debug:instr") {
if cfg!(feature = "debug.instr") {
println!("{}", a);
println!("Stack: {:?}", self.cur_frame().stack.data);
let x = func(self);

View File

@@ -66,7 +66,7 @@ impl NetStack {
}
}
#[cfg(feature = "bonus:network")]
#[cfg(feature = "bonus.network")]
pub fn write_byte(&mut self, byte: u8) -> Result<()> {
match self.stream {
Some(ref mut stream) => {

View File

@@ -45,7 +45,7 @@ lazy_static! {
m[0x60] = Operation::Op("IADD", iadd, vec![]);
m[0x64] = Operation::Op("ISUB", isub, vec![]);
#[cfg(feature = "extra:arithmetic")]
#[cfg(feature = "extra.arithmetic")]
{
m[0x70] = Operation::Op("SHL", shl, vec![]);
m[0x71] = Operation::Op("SHR", shr, vec![]);
@@ -68,7 +68,7 @@ lazy_static! {
m[0xC4] = Operation::Op("WIDE", wide, vec![]);
#[cfg(feature = "bonus:heap")]
#[cfg(feature = "bonus.heap")]
{
m[0xD1] = Operation::Op("NEWARRAY", newarray, vec![]);
m[0xD2] = Operation::Op("IALOAD", iaload, vec![]);
@@ -76,7 +76,7 @@ lazy_static! {
m[0xD4] = Operation::Op("GC", gc, vec![]);
}
#[cfg(feature = "bonus:network")]
#[cfg(feature = "bonus.network")]
{
m[0xE1] = Operation::Op("NETBIND", netbind, vec![]);
m[0xE2] = Operation::Op("NETCONNECT", netconnect, vec![]);
@@ -85,7 +85,7 @@ lazy_static! {
m[0xE5] = Operation::Op("NETCLOSE", netclose, vec![]);
}
#[cfg(feature = "extra:sleep")]
#[cfg(feature = "extra.sleep")]
{
m[0xF0] = Operation::Op("SLP", slp, vec![Args::Byte]);
}
@@ -294,7 +294,7 @@ fn ireturn(machine: &mut Machine) -> Result<()> {
machine.block.seek(return_addr as usize)
}
#[cfg(feature = "extra:sleep")]
#[cfg(feature = "extra.sleep")]
fn slp(machine: &mut Machine) -> Result<()> {
use std::thread;
use std::time;
@@ -307,7 +307,7 @@ fn slp(machine: &mut Machine) -> Result<()> {
Ok(())
}
#[cfg(feature = "bonus:network")]
#[cfg(feature = "bonus.network")]
fn netbind(machine: &mut Machine) -> Result<()> {
let port: i32 = machine.cur_stack().pop()?.try_into()?;
@@ -319,7 +319,7 @@ fn netbind(machine: &mut Machine) -> Result<()> {
Ok(())
}
#[cfg(feature = "bonus:network")]
#[cfg(feature = "bonus.network")]
fn netconnect(machine: &mut Machine) -> Result<()> {
let port: i32 = machine.cur_stack().pop()?.try_into()?;
let host: i32 = machine.cur_stack().pop()?.try_into()?;
@@ -331,7 +331,7 @@ fn netconnect(machine: &mut Machine) -> Result<()> {
Ok(())
}
#[cfg(feature = "bonus:network")]
#[cfg(feature = "bonus.network")]
fn netin(machine: &mut Machine) -> Result<()> {
let netref: i32 = machine.cur_stack().pop()?.try_into()?;
if netref != 1 {
@@ -343,7 +343,7 @@ fn netin(machine: &mut Machine) -> Result<()> {
Ok(())
}
#[cfg(feature = "bonus:network")]
#[cfg(feature = "bonus.network")]
fn netout(machine: &mut Machine) -> Result<()> {
let netref: i32 = machine.cur_stack().pop()?.try_into()?;
if netref != 1 {
@@ -354,7 +354,7 @@ fn netout(machine: &mut Machine) -> Result<()> {
machine.net.write_byte(val as u8)
}
#[cfg(feature = "bonus:network")]
#[cfg(feature = "bonus.network")]
fn netclose(machine: &mut Machine) -> Result<()> {
let netref: i32 = machine.cur_stack().pop()?.try_into()?;
if netref != 1 {
@@ -363,7 +363,7 @@ fn netclose(machine: &mut Machine) -> Result<()> {
machine.net.close()
}
#[cfg(feature = "bonus:heap")]
#[cfg(feature = "bonus.heap")]
fn newarray(machine: &mut Machine) -> Result<()> {
let size: i32 = machine.cur_stack().pop()?.try_into()?;
let heap = machine.heap.alloc(size as usize);
@@ -371,7 +371,7 @@ fn newarray(machine: &mut Machine) -> Result<()> {
Ok(())
}
#[cfg(feature = "bonus:heap")]
#[cfg(feature = "bonus.heap")]
fn iastore(machine: &mut Machine) -> Result<()> {
use std::cell::RefCell;
@@ -387,7 +387,7 @@ fn iastore(machine: &mut Machine) -> Result<()> {
Ok(())
}
#[cfg(feature = "bonus:heap")]
#[cfg(feature = "bonus.heap")]
fn iaload(machine: &mut Machine) -> Result<()> {
let heap = match machine.cur_stack().pop()? {
Value::HeapRef(a) => a,
@@ -404,13 +404,13 @@ fn iaload(machine: &mut Machine) -> Result<()> {
Ok(())
}
#[cfg(feature = "bonus:heap")]
#[cfg(feature = "bonus.heap")]
fn gc(machine: &mut Machine) -> Result<()> {
machine.heap.gc();
Ok(())
}
#[cfg(feature = "extra:arithmetic")]
#[cfg(feature = "extra.arithmetic")]
fn shl(machine: &mut Machine) -> Result<()> {
let shift: i32 = machine.cur_stack().pop()?.try_into()?;
let value: i32 = machine.cur_stack().pop()?.try_into()?;
@@ -419,7 +419,7 @@ fn shl(machine: &mut Machine) -> Result<()> {
Ok(())
}
#[cfg(feature = "extra:arithmetic")]
#[cfg(feature = "extra.arithmetic")]
fn shr(machine: &mut Machine) -> Result<()> {
let shift: i32 = machine.cur_stack().pop()?.try_into()?;
let value: i32 = machine.cur_stack().pop()?.try_into()?;
@@ -429,7 +429,7 @@ fn shr(machine: &mut Machine) -> Result<()> {
Ok(())
}
#[cfg(feature = "extra:arithmetic")]
#[cfg(feature = "extra.arithmetic")]
fn imul(machine: &mut Machine) -> Result<()> {
let a: i32 = machine.cur_stack().pop()?.try_into()?;
let b: i32 = machine.cur_stack().pop()?.try_into()?;
@@ -438,7 +438,7 @@ fn imul(machine: &mut Machine) -> Result<()> {
Ok(())
}
#[cfg(feature = "extra:arithmetic")]
#[cfg(feature = "extra.arithmetic")]
fn idiv(machine: &mut Machine) -> Result<()> {
let divisor: i32 = machine.cur_stack().pop()?.try_into()?;
let value: i32 = machine.cur_stack().pop()?.try_into()?;