Initial stack typing
This commit is contained in:
11
src/frame.rs
11
src/frame.rs
@@ -1,11 +1,12 @@
|
|||||||
use stack::Stack;
|
use stack::Stack;
|
||||||
use Result;
|
use Result;
|
||||||
|
use value::Value;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Frame {
|
pub struct Frame {
|
||||||
pub base: usize,
|
pub base: usize,
|
||||||
pub stack: Stack,
|
pub stack: Stack,
|
||||||
pub locals: Vec<i32>,
|
pub locals: Vec<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
@@ -16,7 +17,7 @@ impl Frame {
|
|||||||
Frame {
|
Frame {
|
||||||
base,
|
base,
|
||||||
stack: Stack::new(),
|
stack: Stack::new(),
|
||||||
locals: vec![0; num_locals],
|
locals: vec![Value::Int(0); num_locals],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,14 +29,14 @@ impl Frame {
|
|||||||
self.locals.is_empty()
|
self.locals.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, offset: usize) -> Result<i32> {
|
pub fn get(&self, offset: usize) -> Result<&Value> {
|
||||||
if offset >= self.locals.len() {
|
if offset >= self.locals.len() {
|
||||||
return Err("Local variable out of range");
|
return Err("Local variable out of range");
|
||||||
}
|
}
|
||||||
Ok(self.locals[offset])
|
Ok(&self.locals[offset])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, offset: usize, val: i32) -> Result<()> {
|
pub fn set(&mut self, offset: usize, val: Value) -> Result<()> {
|
||||||
if offset >= self.locals.len() {
|
if offset >= self.locals.len() {
|
||||||
return Err("Local variable out of range");
|
return Err("Local variable out of range");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ extern crate lazy_static;
|
|||||||
pub mod ijvmreader;
|
pub mod ijvmreader;
|
||||||
pub mod binread;
|
pub mod binread;
|
||||||
pub mod block;
|
pub mod block;
|
||||||
|
pub mod value;
|
||||||
pub mod ops;
|
pub mod ops;
|
||||||
pub mod stack;
|
pub mod stack;
|
||||||
pub mod pool;
|
pub mod pool;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use Result;
|
|||||||
use heap::Heap;
|
use heap::Heap;
|
||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
use netstack::NetStack;
|
use netstack::NetStack;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
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;
|
||||||
@@ -119,7 +120,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tos(&mut self) -> Result<i32> {
|
pub fn get_tos(&mut self) -> Result<i32> {
|
||||||
self.cur_stack().top()
|
self.cur_stack().top()?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cur_frame(&mut self) -> &mut Frame {
|
pub fn cur_frame(&mut self) -> &mut Frame {
|
||||||
|
|||||||
100
src/ops.rs
100
src/ops.rs
@@ -4,6 +4,8 @@ use machine::Machine;
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
use Result;
|
use Result;
|
||||||
|
use value::Value;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
pub type OpFunc = fn(&mut Machine) -> Result<()>;
|
pub type OpFunc = fn(&mut Machine) -> Result<()>;
|
||||||
|
|
||||||
@@ -91,23 +93,24 @@ fn bipush(machine: &mut Machine) -> Result<()> {
|
|||||||
Ok(a) => i32::from(a),
|
Ok(a) => i32::from(a),
|
||||||
Err(_) => return Err("Expected argument"),
|
Err(_) => return Err("Expected argument"),
|
||||||
};
|
};
|
||||||
machine.cur_stack().push(val);
|
machine.cur_stack().push(Value::Int(val));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(machine: &mut Machine) -> Result<()> {
|
fn dup(machine: &mut Machine) -> Result<()> {
|
||||||
let val = machine.cur_stack().top()?;
|
let val = machine.cur_stack().top()?.clone();
|
||||||
machine.cur_stack().push(val);
|
machine.cur_stack().push(val);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn out(machine: &mut Machine) -> Result<()> {
|
fn out(machine: &mut Machine) -> Result<()> {
|
||||||
let val = machine.cur_stack().pop()?;
|
let val: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
|
|
||||||
let buffer = [val as u8];
|
let buffer = [val as u8];
|
||||||
let mut out = machine.stream_out.lock().unwrap();
|
let mut out = machine.stream_out.lock().unwrap();
|
||||||
out.write_all(&buffer).unwrap();
|
out.write_all(&buffer).unwrap();
|
||||||
out.flush().unwrap();
|
out.flush().unwrap();
|
||||||
Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop(machine: &mut Machine) -> Result<()> {
|
fn pop(machine: &mut Machine) -> Result<()> {
|
||||||
@@ -116,16 +119,17 @@ fn pop(machine: &mut Machine) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn iadd(machine: &mut Machine) -> Result<()> {
|
fn iadd(machine: &mut Machine) -> Result<()> {
|
||||||
let a = Wrapping(machine.cur_stack().pop()?);
|
let a: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
let b = Wrapping(machine.cur_stack().pop()?);
|
let b: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
machine.cur_stack().push((a + b).0);
|
let res = Wrapping(a) + Wrapping(b);
|
||||||
|
machine.cur_stack().push(Value::Int(res.0));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn isub(machine: &mut Machine) -> Result<()> {
|
fn isub(machine: &mut Machine) -> Result<()> {
|
||||||
let a = Wrapping(machine.cur_stack().pop()?);
|
let a: Wrapping<i32> = Wrapping(machine.cur_stack().pop()?.try_into()?);
|
||||||
let b = Wrapping(machine.cur_stack().pop()?);
|
let b: Wrapping<i32> = Wrapping(machine.cur_stack().pop()?.try_into()?);
|
||||||
machine.cur_stack().push((b - a).0);
|
machine.cur_stack().push(Value::Int((b - a).0));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +139,7 @@ fn _in(machine: &mut Machine) -> Result<()> {
|
|||||||
Err(_) => 0i32,
|
Err(_) => 0i32,
|
||||||
Ok(_) => i32::from(buffer[0]),
|
Ok(_) => i32::from(buffer[0]),
|
||||||
};
|
};
|
||||||
machine.cur_stack().push(val);
|
machine.cur_stack().push(Value::Int(val));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +161,8 @@ 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 {
|
let compare: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
|
if compare == 0 {
|
||||||
return machine.block.jump(offset);
|
return machine.block.jump(offset);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -165,7 +170,8 @@ 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 {
|
let compare: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
|
if compare < 0 {
|
||||||
return machine.block.jump(offset);
|
return machine.block.jump(offset);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -180,23 +186,23 @@ fn if_icmpeq(machine: &mut Machine) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn iand(machine: &mut Machine) -> Result<()> {
|
fn iand(machine: &mut Machine) -> Result<()> {
|
||||||
let a = machine.cur_stack().pop()?;
|
let a: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
let b = machine.cur_stack().pop()?;
|
let b: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
machine.cur_stack().push(a & b);
|
machine.cur_stack().push(Value::Int(a & b));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ior(machine: &mut Machine) -> Result<()> {
|
fn ior(machine: &mut Machine) -> Result<()> {
|
||||||
let a = machine.cur_stack().pop()?;
|
let a: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
let b = machine.cur_stack().pop()?;
|
let b: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
machine.cur_stack().push(a | b);
|
machine.cur_stack().push(Value::Int(a | b));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ldc_w(machine: &mut Machine) -> Result<()> {
|
fn ldc_w(machine: &mut Machine) -> Result<()> {
|
||||||
let offset = machine.block.read_i16()? as usize;
|
let offset = machine.block.read_i16()? as usize;
|
||||||
let val = machine.pool.get(offset)?;
|
let val = machine.pool.get(offset)?;
|
||||||
machine.cur_stack().push(val);
|
machine.cur_stack().push(Value::Int(val));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +221,7 @@ fn wide(machine: &mut Machine) -> Result<()> {
|
|||||||
|
|
||||||
fn iload(machine: &mut Machine) -> Result<()> {
|
fn iload(machine: &mut Machine) -> Result<()> {
|
||||||
let a = machine.read_index()?;
|
let a = machine.read_index()?;
|
||||||
let val = machine.cur_frame().get(a)?;
|
let val = machine.cur_frame().get(a)?.clone();
|
||||||
machine.cur_stack().push(val);
|
machine.cur_stack().push(val);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -229,8 +235,8 @@ fn istore(machine: &mut Machine) -> Result<()> {
|
|||||||
fn iinc(machine: &mut Machine) -> Result<()> {
|
fn iinc(machine: &mut Machine) -> Result<()> {
|
||||||
let a = machine.read_index()?;
|
let a = machine.read_index()?;
|
||||||
let b = i32::from(machine.block.read_i8()?);
|
let b = i32::from(machine.block.read_i8()?);
|
||||||
let val = machine.cur_frame().get(a)?;
|
let val: i32 = machine.cur_frame().get(a)?.try_into()?;
|
||||||
machine.cur_frame().set(a, val + b)
|
machine.cur_frame().set(a, Value::Int(val + b))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invokevirtual(machine: &mut Machine) -> Result<()> {
|
fn invokevirtual(machine: &mut Machine) -> Result<()> {
|
||||||
@@ -253,7 +259,7 @@ fn invokevirtual(machine: &mut Machine) -> Result<()> {
|
|||||||
cur_stack.pop()?; // Nuke the OBJREF
|
cur_stack.pop()?; // Nuke the OBJREF
|
||||||
}
|
}
|
||||||
|
|
||||||
newframe.set(0, return_addr as i32)?;
|
newframe.set(0, Value::Int(return_addr as i32))?;
|
||||||
|
|
||||||
machine.frame.push(newframe);
|
machine.frame.push(newframe);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -265,7 +271,7 @@ fn ireturn(machine: &mut Machine) -> Result<()> {
|
|||||||
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: i32 = prev_frame.get(0)?.try_into()?;
|
||||||
machine.cur_stack().push(result);
|
machine.cur_stack().push(result);
|
||||||
machine.block.seek(return_addr as usize)
|
machine.block.seek(return_addr as usize)
|
||||||
}
|
}
|
||||||
@@ -285,28 +291,28 @@ fn slp(machine: &mut Machine) -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
fn netbind(machine: &mut Machine) -> Result<()> {
|
fn netbind(machine: &mut Machine) -> Result<()> {
|
||||||
let port = machine.cur_stack().pop()? as u16;
|
let port: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
machine.net.bind(port)
|
machine.net.bind(port as u16)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
fn netconnect(machine: &mut Machine) -> Result<()> {
|
fn netconnect(machine: &mut Machine) -> Result<()> {
|
||||||
let port = machine.cur_stack().pop()? as u16;
|
let port: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
let host = machine.cur_stack().pop()? as u32;
|
let host: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
machine.net.connect(host, port)
|
machine.net.connect(host as u32, port as u16)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
fn netin(machine: &mut Machine) -> Result<()> {
|
fn netin(machine: &mut Machine) -> Result<()> {
|
||||||
let byte = i32::from(machine.net.read_byte()?);
|
let byte = i32::from(machine.net.read_byte()?);
|
||||||
machine.cur_stack().push(byte);
|
machine.cur_stack().push(Value::Int(byte));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
fn netout(machine: &mut Machine) -> Result<()> {
|
fn netout(machine: &mut Machine) -> Result<()> {
|
||||||
let val = machine.cur_stack().pop()? as u8;
|
let val: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
machine.net.write_byte(val)
|
machine.net.write_byte(val as u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
@@ -316,35 +322,41 @@ fn netclose(machine: &mut Machine) -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(feature = "bonus:heap")]
|
#[cfg(feature = "bonus:heap")]
|
||||||
fn newarray(machine: &mut Machine) -> Result<()> {
|
fn newarray(machine: &mut Machine) -> Result<()> {
|
||||||
let size = machine.cur_stack().pop()? as usize;
|
let size: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
let heapref = machine.heap.alloc(size);
|
let heapref = machine.heap.alloc(size as usize);
|
||||||
machine.cur_stack().push(heapref as i32);
|
machine.cur_stack().push(Value::HeapRef(heapref));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bonus:heap")]
|
#[cfg(feature = "bonus:heap")]
|
||||||
fn iastore(machine: &mut Machine) -> Result<()> {
|
fn iastore(machine: &mut Machine) -> Result<()> {
|
||||||
let heapref = machine.cur_stack().pop()? as usize;
|
let heapref = match machine.cur_stack().pop()? {
|
||||||
let index = machine.cur_stack().pop()? as usize;
|
Value::HeapRef(a) => a,
|
||||||
let value = machine.cur_stack().pop()?;
|
_ => return Err("Cannot use int as heapref"),
|
||||||
|
};
|
||||||
|
let index: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
|
let value: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
|
|
||||||
let heap = machine.heap.get(heapref);
|
let heap = machine.heap.get(heapref);
|
||||||
heap[index] = value;
|
heap[index as usize] = value;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bonus:heap")]
|
#[cfg(feature = "bonus:heap")]
|
||||||
fn iaload(machine: &mut Machine) -> Result<()> {
|
fn iaload(machine: &mut Machine) -> Result<()> {
|
||||||
let heapref = machine.cur_stack().pop()? as usize;
|
let heapref = match machine.cur_stack().pop()? {
|
||||||
let index = machine.cur_stack().pop()? as usize;
|
Value::HeapRef(a) => a,
|
||||||
|
_ => return Err("Cannot use int as heapref"),
|
||||||
|
};
|
||||||
|
let index: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
|
|
||||||
let value: i32;
|
let value: i32;
|
||||||
{
|
{
|
||||||
let heap = machine.heap.get(heapref);
|
let heap = machine.heap.get(heapref);
|
||||||
value = heap[index];
|
value = heap[index as usize];
|
||||||
}
|
}
|
||||||
machine.cur_stack().push(value);
|
machine.cur_stack().push(Value::Int(value));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/stack.rs
16
src/stack.rs
@@ -1,8 +1,10 @@
|
|||||||
use Result;
|
use Result;
|
||||||
|
use value::Value;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Stack {
|
pub struct Stack {
|
||||||
pub data: Vec<i32>
|
pub data: Vec<Value>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stack {
|
impl Stack {
|
||||||
@@ -20,25 +22,25 @@ impl Stack {
|
|||||||
self.len() == 0
|
self.len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, i: usize) -> i32 {
|
pub fn get(&self, i: usize) -> &Value {
|
||||||
self.data[i]
|
&self.data[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn top(&self) -> Result<i32> {
|
pub fn top(&self) -> Result<&Value> {
|
||||||
Ok(match self.data.last() {
|
Ok(match self.data.last() {
|
||||||
Some(a) => *a,
|
Some(a) => a,
|
||||||
None => return Err("Stack empty"),
|
None => return Err("Stack empty"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop(&mut self) -> Result<i32> {
|
pub fn pop(&mut self) -> Result<Value> {
|
||||||
Ok(match self.data.pop() {
|
Ok(match self.data.pop() {
|
||||||
Some(a) => a,
|
Some(a) => a,
|
||||||
None => return Err("Stack empty"),
|
None => return Err("Stack empty"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, val: i32) {
|
pub fn push(&mut self, val: Value) {
|
||||||
self.data.push(val);
|
self.data.push(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
30
src/value.rs
Normal file
30
src/value.rs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
use Result;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum Value {
|
||||||
|
Int(i32),
|
||||||
|
HeapRef(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryInto<i32> for Value {
|
||||||
|
type Error = &'static str;
|
||||||
|
|
||||||
|
fn try_into(self) -> Result<i32> {
|
||||||
|
match self {
|
||||||
|
Value::Int(a) => Ok(a),
|
||||||
|
Value::HeapRef(_) => Err("Cannot use HeapRef as i32"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryInto<i32> for &Value {
|
||||||
|
type Error = &'static str;
|
||||||
|
|
||||||
|
fn try_into(self) -> Result<i32> {
|
||||||
|
match self {
|
||||||
|
&Value::Int(a) => Ok(a),
|
||||||
|
&Value::HeapRef(_) => Err("Cannot use HeapRef as i32"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user