Passing all tests i guess
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
target
|
||||
*.jas
|
||||
*.ijvm
|
||||
*.conf
|
||||
goJASM
|
||||
4
Cargo.lock
generated
Normal file
4
Cargo.lock
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
[root]
|
||||
name = "rustijvm"
|
||||
version = "0.1.0"
|
||||
|
||||
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "rustijvm"
|
||||
version = "0.1.0"
|
||||
authors = ["Jur van den Berg <Jurl.berg@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
82
src/ijvm/binread.rs
Normal file
82
src/ijvm/binread.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
use ijvm::Result;
|
||||
use ijvm::block::Block;
|
||||
use ijvm::ops::{Operation,num_to_op};
|
||||
|
||||
pub trait BinReadable {
|
||||
fn get(&mut self) -> Result<u8>;
|
||||
fn cur(&self) -> usize;
|
||||
fn len(&self) -> usize;
|
||||
fn slice(&mut self, len: usize) -> &[u8];
|
||||
}
|
||||
|
||||
pub trait BinRead {
|
||||
fn has_i8(&self) -> bool;
|
||||
fn has_i16(&self) -> bool;
|
||||
fn has_i32(&self) -> bool;
|
||||
|
||||
fn read_u8(&mut self) -> Result<u8>;
|
||||
fn read_u16(&mut self) -> Result<u16>;
|
||||
fn read_u32(&mut self) -> Result<u32>;
|
||||
|
||||
fn read_i8(&mut self) -> Result<i8>;
|
||||
fn read_i16(&mut self) -> Result<i16>;
|
||||
fn read_i32(&mut self) -> Result<i32>;
|
||||
|
||||
fn read_block(&mut self) -> Result<Block>;
|
||||
fn read_op(&mut self) -> Result<Operation>;
|
||||
}
|
||||
|
||||
impl<T: BinReadable> BinRead for T {
|
||||
fn has_i8(&self) -> bool {
|
||||
self.cur() < self.len()
|
||||
}
|
||||
|
||||
fn has_i16(&self) -> bool {
|
||||
self.cur() + 1 < self.len()
|
||||
}
|
||||
|
||||
fn has_i32(&self) -> bool {
|
||||
self.cur() + 3 < self.len()
|
||||
}
|
||||
|
||||
fn read_u8(&mut self) -> Result<u8> {
|
||||
self.get()
|
||||
}
|
||||
|
||||
fn read_u16(&mut self) -> Result<u16> {
|
||||
let a = self.read_u8()? as u16;
|
||||
let b = self.read_u8()? as u16;
|
||||
Ok(a << 8 | b)
|
||||
}
|
||||
|
||||
fn read_u32(&mut self) -> Result<u32> {
|
||||
let a = self.read_u16()? as u32;
|
||||
let b = self.read_u16()? as u32;
|
||||
Ok(a << 16 | b)
|
||||
}
|
||||
fn read_i8(&mut self) -> Result<i8> {
|
||||
Ok(self.get()? as i8)
|
||||
}
|
||||
|
||||
fn read_i16(&mut self) -> Result<i16> {
|
||||
let a = self.read_u8()? as i16;
|
||||
let b = self.read_u8()? as i16;
|
||||
Ok((a << 8 | b) as i16)
|
||||
}
|
||||
|
||||
fn read_i32(&mut self) -> Result<i32> {
|
||||
let a = self.read_u16()? as i32;
|
||||
let b = self.read_u16()? as i32;
|
||||
Ok(a << 16 | b)
|
||||
}
|
||||
|
||||
fn read_block(&mut self) -> Result<Block> {
|
||||
let origin = self.read_u32()?;
|
||||
let len = self.read_u32()? as usize;
|
||||
Ok(Block::new(origin, self.slice(len)))
|
||||
}
|
||||
|
||||
fn read_op(&mut self) -> Result<Operation> {
|
||||
Ok(num_to_op(self.read_u8()?))
|
||||
}
|
||||
}
|
||||
71
src/ijvm/block.rs
Normal file
71
src/ijvm/block.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
use ijvm::Result;
|
||||
use ijvm::binread::BinReadable;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Block {
|
||||
origin: u32,
|
||||
|
||||
length: usize,
|
||||
pointer: usize,
|
||||
source: Vec<u8>
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn new(origin: u32, source: &[u8]) -> Block {
|
||||
Block {
|
||||
origin: origin,
|
||||
length: source.len(),
|
||||
pointer: 0,
|
||||
source: source.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn jump(&mut self, offset: i32) -> Result<()> {
|
||||
if offset < 0 {
|
||||
if (-offset as usize) > self.pointer {
|
||||
return Err("Jump before block")
|
||||
}
|
||||
self.pointer -= -offset as usize;
|
||||
} else {
|
||||
if self.pointer + (offset as usize) >= self.length {
|
||||
return Err("Jump outside of block")
|
||||
}
|
||||
self.pointer += offset as usize;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn seek(&mut self, location: usize) -> Result<()> {
|
||||
if location >= self.length {
|
||||
println!("hoho {}", location);
|
||||
return Err("Seek outside of block")
|
||||
}
|
||||
self.pointer = location;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl BinReadable for Block {
|
||||
fn get(&mut self) -> Result<u8> {
|
||||
if self.pointer >= self.length {
|
||||
return Err("EOF reached")
|
||||
}
|
||||
let byte = self.source[self.pointer];
|
||||
self.pointer += 1;
|
||||
return Ok(byte)
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
return self.source.len()
|
||||
}
|
||||
|
||||
fn cur(&self) -> usize {
|
||||
return self.pointer;
|
||||
}
|
||||
|
||||
fn slice(&mut self, len: usize) -> &[u8] {
|
||||
let slice = &self.source[self.pointer..self.pointer+len];
|
||||
self.pointer += len;
|
||||
slice
|
||||
}
|
||||
}
|
||||
33
src/ijvm/frame.rs
Normal file
33
src/ijvm/frame.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
use ijvm::Result;
|
||||
use ijvm::stack::Stack;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Frame {
|
||||
pub stack: Stack,
|
||||
locals: Vec<i32>,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn new(num_locals: usize) -> Frame {
|
||||
// println!("Initializing frame of len {}", num_locals);
|
||||
return Frame {
|
||||
stack: Stack::new(),
|
||||
locals: vec![0; num_locals+1],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, offset: usize) -> Result<i32> {
|
||||
if offset >= self.locals.len() {
|
||||
return Err("Local variable out of range");
|
||||
}
|
||||
return Ok(self.locals[offset])
|
||||
}
|
||||
|
||||
pub fn set(&mut self, offset: usize, val: i32) -> Result<()> {
|
||||
if offset >= self.locals.len() {
|
||||
return Err("Local variable out of range");
|
||||
}
|
||||
self.locals[offset] = val;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
48
src/ijvm/ijvmreader.rs
Normal file
48
src/ijvm/ijvmreader.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use std::io::Read;
|
||||
use std::fs::File;
|
||||
use ijvm::Result;
|
||||
use ijvm::binread::BinReadable;
|
||||
|
||||
pub struct IJVMReader {
|
||||
pointer: usize,
|
||||
source: Vec<u8>
|
||||
}
|
||||
|
||||
impl IJVMReader {
|
||||
pub fn new(path: &str) -> Result<IJVMReader> {
|
||||
let file = match File::open(path) {
|
||||
Ok(file) => file,
|
||||
Err(_) => return Err("Could not open file"),
|
||||
};
|
||||
let abc: Vec<u8> = file.bytes().map(|e| e.unwrap()).collect();
|
||||
Ok(IJVMReader {
|
||||
pointer: 0,
|
||||
source: abc
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl BinReadable for IJVMReader {
|
||||
fn get(&mut self) -> Result<u8> {
|
||||
if self.pointer >= self.source.len() {
|
||||
return Err("EOF reached")
|
||||
}
|
||||
let byte = self.source[self.pointer];
|
||||
self.pointer += 1;
|
||||
return Ok(byte)
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
return self.source.len()
|
||||
}
|
||||
|
||||
fn cur(&self) -> usize {
|
||||
return self.pointer;
|
||||
}
|
||||
|
||||
fn slice(&mut self, len: usize) -> &[u8] {
|
||||
let slice = &self.source[self.pointer..self.pointer+len];
|
||||
self.pointer += len;
|
||||
slice
|
||||
}
|
||||
}
|
||||
96
src/ijvm/machine.rs
Normal file
96
src/ijvm/machine.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use ijvm::block::Block;
|
||||
|
||||
use ijvm::ops::Operation;
|
||||
use ijvm::ijvmreader::IJVMReader;
|
||||
use ijvm::binread::BinReadable;
|
||||
use ijvm::binread::BinRead;
|
||||
use ijvm::frame::Frame;
|
||||
use ijvm::stack::Stack;
|
||||
use ijvm::pool::Pool;
|
||||
use ijvm::Result;
|
||||
|
||||
const MAGIC_HEADER:u32 = 0x1deadfad;
|
||||
const ANTI_BS_SIZE:usize = 0xFFFF;
|
||||
|
||||
pub struct Machine {
|
||||
pub wide: bool,
|
||||
pub pool: Pool,
|
||||
pub block: Block,
|
||||
pub frame: Vec<Frame>
|
||||
}
|
||||
|
||||
impl Machine {
|
||||
pub fn new(pool: Pool, block: Block) -> Machine{
|
||||
Machine {
|
||||
wide: false,
|
||||
pool: pool,
|
||||
block: block,
|
||||
frame: vec![Frame::new(ANTI_BS_SIZE)],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_file(file: &str) -> Result<Machine> {
|
||||
let mut reader = IJVMReader::new(file).unwrap();
|
||||
let magic = reader.read_u32()?;
|
||||
if magic != MAGIC_HEADER {
|
||||
return Err("Invalid magic header");
|
||||
}
|
||||
let constants = match reader.read_block() {
|
||||
Ok(a) => a,
|
||||
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")
|
||||
};
|
||||
|
||||
let pool = Pool::new(constants)?;
|
||||
|
||||
return Ok(Machine::new(pool, text));
|
||||
}
|
||||
|
||||
pub fn step(&mut self) -> Result<()> {
|
||||
match self.block.read_op() {
|
||||
Ok(Operation::Op(a, func)) => {
|
||||
// println!("{}", a);
|
||||
// println!("Stack: {:?}", self.cur_frame().stack.data);
|
||||
let x = func(self);
|
||||
// println!("Stack: {:?}", self.cur_frame().stack.data);
|
||||
x
|
||||
},
|
||||
Ok(Operation::Invalid(a)) => {
|
||||
println!("OP: {}", a);
|
||||
Err("Invalid op")
|
||||
},
|
||||
Err(str) => Err(str)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_step(&self) -> bool {
|
||||
return self.block.has_i8();
|
||||
}
|
||||
|
||||
pub fn get_program_counter(&self) -> usize {
|
||||
return self.block.cur()
|
||||
}
|
||||
|
||||
pub fn cur_frame(&mut self) -> &mut Frame {
|
||||
return self.frame.last_mut().unwrap();
|
||||
}
|
||||
|
||||
pub fn cur_stack(&mut self) -> &mut Stack {
|
||||
return &mut self.cur_frame().stack;
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
Ok(self.block.read_u8()? as usize)
|
||||
}
|
||||
}
|
||||
10
src/ijvm/mod.rs
Normal file
10
src/ijvm/mod.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
pub mod ijvmreader;
|
||||
pub mod binread;
|
||||
pub mod block;
|
||||
pub mod ops;
|
||||
pub mod machine;
|
||||
pub mod stack;
|
||||
pub mod pool;
|
||||
pub mod frame;
|
||||
|
||||
type Result<T> = ::std::result::Result<T, &'static str>;
|
||||
245
src/ijvm/ops.rs
Normal file
245
src/ijvm/ops.rs
Normal file
@@ -0,0 +1,245 @@
|
||||
use ijvm::binread::BinRead;
|
||||
use ijvm::machine::Machine;
|
||||
use ijvm::frame::Frame;
|
||||
use ijvm::Result;
|
||||
use std::io::Write;
|
||||
use std::io::Read;
|
||||
|
||||
pub type OpFunc = fn(&mut Machine) -> Result<()>;
|
||||
|
||||
pub enum Operation {
|
||||
Op(&'static str, OpFunc),
|
||||
Invalid(u8)
|
||||
}
|
||||
|
||||
const JUMP_OFFSET: i32 = 3;
|
||||
|
||||
pub fn num_to_op(op: u8) -> Operation {
|
||||
match op {
|
||||
0x00 => Operation::Op("NOP", nop),
|
||||
0x10 => Operation::Op("BIPUSH", bipush),
|
||||
0x13 => Operation::Op("LDC_W", ldc_w),
|
||||
0x15 => Operation::Op("ILOAD", iload),
|
||||
0x36 => Operation::Op("ISTORE", istore),
|
||||
0x57 => Operation::Op("POP", pop),
|
||||
0x59 => Operation::Op("DUP", dup),
|
||||
0x5F => Operation::Op("SWAP", swap),
|
||||
0x60 => Operation::Op("IADD", iadd),
|
||||
0x64 => Operation::Op("ISUB", isub),
|
||||
0x7E => Operation::Op("IAND", iand),
|
||||
0xB0 => Operation::Op("IOR", ior),
|
||||
0x84 => Operation::Op("IINC", iinc),
|
||||
0x99 => Operation::Op("IFEQ", ifeq),
|
||||
0x9b => Operation::Op("IFLT", iflt),
|
||||
0x9F => Operation::Op("IF_ICMPEQ", if_icmpeq),
|
||||
0xA7 => Operation::Op("GOTO", goto),
|
||||
0xAC => Operation::Op("IRETURN", ireturn),
|
||||
0xB6 => Operation::Op("INVOKEVIRTUAL", invokevirtual),
|
||||
0xC4 => Operation::Op("WIDE", wide),
|
||||
0xFC => Operation::Op("IN", _in),
|
||||
0xFD => Operation::Op("OUT", out),
|
||||
0xFF => Operation::Op("HALT", halt),
|
||||
|
||||
0xF0 => Operation::Op("SLP", slp),
|
||||
x => Operation::Invalid(x)
|
||||
}
|
||||
}
|
||||
|
||||
fn nop(_: &mut Machine) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn bipush(machine: &mut Machine) -> Result<()> {
|
||||
let val = match machine.block.read_i8() {
|
||||
Ok(a) => a,
|
||||
Err(_) => return Err("Expected argument"),
|
||||
} as i32;
|
||||
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()?;
|
||||
print!("{}", val as u8 as char);
|
||||
::std::io::stdout().flush().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pop(machine: &mut Machine) -> Result<()> {
|
||||
machine.cur_stack().pop()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn iadd(machine: &mut Machine) -> Result<()> {
|
||||
let a = machine.cur_stack().pop()?;
|
||||
let b = machine.cur_stack().pop()?;
|
||||
machine.cur_stack().push(a + b);
|
||||
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);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _in(machine: &mut Machine) -> Result<()> {
|
||||
let char: Option<u8> =
|
||||
::std::io::stdin()
|
||||
.bytes()
|
||||
.next()
|
||||
.and_then(|r| r.ok());
|
||||
let val = match char {
|
||||
None => 0 as i32,
|
||||
Some(i) => i as i32
|
||||
};
|
||||
machine.cur_stack().push(val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn goto(machine: &mut Machine) -> Result<()> {
|
||||
let offset = machine.block.read_i16()? as i32 - JUMP_OFFSET;
|
||||
machine.block.jump(offset)
|
||||
}
|
||||
|
||||
fn halt(_: &mut Machine) -> Result<()> {
|
||||
Err("Halt")
|
||||
}
|
||||
|
||||
fn ifeq(machine: &mut Machine) -> Result<()> {
|
||||
let offset = machine.block.read_i16()? as i32 - JUMP_OFFSET;
|
||||
if machine.cur_stack().pop()? == 0 {
|
||||
return machine.block.jump(offset)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn iflt(machine: &mut Machine) -> Result<()> {
|
||||
let offset = machine.block.read_i16()? as i32 - JUMP_OFFSET;
|
||||
if machine.cur_stack().pop()? < 0 {
|
||||
return machine.block.jump(offset)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn if_icmpeq(machine: &mut Machine) -> Result<()> {
|
||||
let offset = machine.block.read_i16()? as i32 - 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;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 = machine.block.read_i8()?;
|
||||
let val = machine.cur_frame().get(a)?;
|
||||
machine.cur_frame().set(a, val + b as i32)
|
||||
}
|
||||
|
||||
fn invokevirtual(machine: &mut Machine) -> Result<()> {
|
||||
let method_index = machine.block.read_u16()?;
|
||||
let invoke_addr = machine.pool.get(method_index as usize)?;
|
||||
let return_addr = machine.get_program_counter();
|
||||
// println!("METHOD {}", method_index);
|
||||
machine.block.seek(invoke_addr as usize)?;
|
||||
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);
|
||||
|
||||
// Lifetime for cur_stack
|
||||
{
|
||||
let mut 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
|
||||
}
|
||||
|
||||
// println!("retaddr set {}" ,return_addr);
|
||||
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...")
|
||||
};
|
||||
// println!("stack: {:?}", prev_frame.stack);
|
||||
let result = prev_frame.stack.pop()?;
|
||||
let return_addr = prev_frame.get(0)?;
|
||||
// println!("result: {}\nretaddr: {}", result, return_addr);
|
||||
machine.cur_stack().push(result);
|
||||
machine.block.seek(return_addr as usize)
|
||||
}
|
||||
|
||||
fn slp(machine: &mut Machine) -> Result<()> {
|
||||
use std::time;
|
||||
use std::thread;
|
||||
let val = match machine.block.read_u8() {
|
||||
Ok(a) => a,
|
||||
Err(_) => return Err("Expected argument"),
|
||||
} as u64;
|
||||
let slpdur = time::Duration::from_millis(val*100);
|
||||
thread::sleep(slpdur);
|
||||
Ok(())
|
||||
}
|
||||
28
src/ijvm/pool.rs
Normal file
28
src/ijvm/pool.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use ijvm::Result;
|
||||
use ijvm::block::Block;
|
||||
use ijvm::binread::{BinRead, BinReadable};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Pool {
|
||||
pub data: Vec<i32>
|
||||
}
|
||||
|
||||
impl Pool {
|
||||
pub fn new(mut block: Block) -> Result<Pool> {
|
||||
let cap = block.len() / 4;
|
||||
let mut vec = Vec::with_capacity(cap);
|
||||
while block.has_i32() {
|
||||
vec.push(block.read_i32()?);
|
||||
}
|
||||
Ok(Pool {
|
||||
data: vec
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get(&self, index: usize) -> Result<i32> {
|
||||
if index >= self.data.len() {
|
||||
return Err("No such constant")
|
||||
}
|
||||
Ok(self.data[index])
|
||||
}
|
||||
}
|
||||
40
src/ijvm/stack.rs
Normal file
40
src/ijvm/stack.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use ijvm::Result;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Stack {
|
||||
pub data: Vec<i32>
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
pub fn new() -> Stack {
|
||||
Stack {
|
||||
data: Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn len(&self) -> usize {
|
||||
// return self.data.len();
|
||||
// }
|
||||
|
||||
pub fn top(&self) -> Result<i32> {
|
||||
Ok(match self.data.last() {
|
||||
Some(a) => *a,
|
||||
None => return Err("Stack empty"),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Result<i32> {
|
||||
Ok(match self.data.pop() {
|
||||
Some(a) => a,
|
||||
None => return Err("Stack empty"),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn push(&mut self, val: i32) {
|
||||
self.data.push(val);
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
}
|
||||
31
src/main.rs
Normal file
31
src/main.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
mod ijvm;
|
||||
|
||||
|
||||
use ijvm::machine::Machine;
|
||||
use std::env;
|
||||
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
||||
if args.len() < 2 {
|
||||
println!("Usage: {} ijvmfile", args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
let ijvmfile = &args[1];
|
||||
|
||||
let mut machine = Machine::new_from_file(ijvmfile).unwrap();
|
||||
while machine.has_step() {
|
||||
match machine.step() {
|
||||
Ok(_) => (),
|
||||
Err(str) => {
|
||||
println!("\n\nERROR: pc=0x{:x} fp=0x{:x}: {}\nProgram exit",
|
||||
machine.get_program_counter(),
|
||||
machine.frame.len() - 1,
|
||||
str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user