From ba0fca8755e5bcaa5052ccc631e4f4f1fb785306 Mon Sep 17 00:00:00 2001 From: Jur van den Berg Date: Mon, 29 Apr 2019 15:21:37 +0200 Subject: [PATCH 1/2] Initial stack typing --- src/frame.rs | 11 +++--- src/lib.rs | 1 + src/machine.rs | 3 +- src/ops.rs | 100 +++++++++++++++++++++++++++---------------------- src/stack.rs | 20 +++++----- src/value.rs | 30 +++++++++++++++ 6 files changed, 106 insertions(+), 59 deletions(-) create mode 100644 src/value.rs diff --git a/src/frame.rs b/src/frame.rs index 884a337..f4b4275 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -1,11 +1,12 @@ use stack::Stack; use Result; +use value::Value; #[derive(Debug)] pub struct Frame { pub base: usize, pub stack: Stack, - pub locals: Vec, + pub locals: Vec, } impl Frame { @@ -16,7 +17,7 @@ impl Frame { Frame { base, 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() } - pub fn get(&self, offset: usize) -> Result { + pub fn get(&self, offset: usize) -> Result<&Value> { if offset >= self.locals.len() { 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() { return Err("Local variable out of range"); } diff --git a/src/lib.rs b/src/lib.rs index df4f386..994c2b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ extern crate lazy_static; pub mod ijvmreader; pub mod binread; pub mod block; +pub mod value; pub mod ops; pub mod stack; pub mod pool; diff --git a/src/machine.rs b/src/machine.rs index b49cb8a..57b8ac0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -14,6 +14,7 @@ use Result; use heap::Heap; #[cfg(feature = "bonus:network")] use netstack::NetStack; +use std::convert::TryInto; pub const MAGIC_HEADER: u32 = 0x1DEA_DFAD; const ANTI_BS_SIZE: usize = 0xFF; @@ -119,7 +120,7 @@ impl Machine { } pub fn get_tos(&mut self) -> Result { - self.cur_stack().top() + self.cur_stack().top()?.try_into() } pub fn cur_frame(&mut self) -> &mut Frame { diff --git a/src/ops.rs b/src/ops.rs index 36ad400..76c1189 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -4,6 +4,8 @@ use machine::Machine; use std::io::Read; use std::num::Wrapping; use Result; +use value::Value; +use std::convert::TryInto; pub type OpFunc = fn(&mut Machine) -> Result<()>; @@ -91,23 +93,24 @@ fn bipush(machine: &mut Machine) -> Result<()> { Ok(a) => i32::from(a), Err(_) => return Err("Expected argument"), }; - machine.cur_stack().push(val); + machine.cur_stack().push(Value::Int(val)); Ok(()) } fn dup(machine: &mut Machine) -> Result<()> { - let val = machine.cur_stack().top()?; + let val = machine.cur_stack().top()?.clone(); machine.cur_stack().push(val); Ok(()) } 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 mut out = machine.stream_out.lock().unwrap(); out.write_all(&buffer).unwrap(); out.flush().unwrap(); - Ok(()) + return Ok(()); } fn pop(machine: &mut Machine) -> Result<()> { @@ -116,16 +119,17 @@ fn pop(machine: &mut Machine) -> Result<()> { } fn iadd(machine: &mut Machine) -> Result<()> { - let a = Wrapping(machine.cur_stack().pop()?); - let b = Wrapping(machine.cur_stack().pop()?); - machine.cur_stack().push((a + b).0); + let a: i32 = machine.cur_stack().pop()?.try_into()?; + let b: i32 = machine.cur_stack().pop()?.try_into()?; + let res = Wrapping(a) + Wrapping(b); + machine.cur_stack().push(Value::Int(res.0)); Ok(()) } fn isub(machine: &mut Machine) -> Result<()> { - let a = Wrapping(machine.cur_stack().pop()?); - let b = Wrapping(machine.cur_stack().pop()?); - machine.cur_stack().push((b - a).0); + let a: Wrapping = Wrapping(machine.cur_stack().pop()?.try_into()?); + let b: Wrapping = Wrapping(machine.cur_stack().pop()?.try_into()?); + machine.cur_stack().push(Value::Int((b - a).0)); Ok(()) } @@ -135,7 +139,7 @@ fn _in(machine: &mut Machine) -> Result<()> { Err(_) => 0i32, Ok(_) => i32::from(buffer[0]), }; - machine.cur_stack().push(val); + machine.cur_stack().push(Value::Int(val)); Ok(()) } @@ -157,7 +161,8 @@ 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 { + let compare: i32 = machine.cur_stack().pop()?.try_into()?; + if compare == 0 { return machine.block.jump(offset); } Ok(()) @@ -165,7 +170,8 @@ 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 { + let compare: i32 = machine.cur_stack().pop()?.try_into()?; + if compare < 0 { return machine.block.jump(offset); } Ok(()) @@ -180,23 +186,23 @@ fn if_icmpeq(machine: &mut Machine) -> Result<()> { } fn iand(machine: &mut Machine) -> Result<()> { - let a = machine.cur_stack().pop()?; - let b = machine.cur_stack().pop()?; - machine.cur_stack().push(a & b); + let a: i32 = machine.cur_stack().pop()?.try_into()?; + let b: i32 = machine.cur_stack().pop()?.try_into()?; + machine.cur_stack().push(Value::Int(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); + let a: i32 = machine.cur_stack().pop()?.try_into()?; + let b: i32 = machine.cur_stack().pop()?.try_into()?; + machine.cur_stack().push(Value::Int(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); + machine.cur_stack().push(Value::Int(val)); Ok(()) } @@ -215,7 +221,7 @@ fn wide(machine: &mut Machine) -> Result<()> { fn iload(machine: &mut Machine) -> Result<()> { 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); Ok(()) } @@ -229,8 +235,8 @@ fn istore(machine: &mut Machine) -> Result<()> { fn iinc(machine: &mut Machine) -> Result<()> { let a = machine.read_index()?; let b = i32::from(machine.block.read_i8()?); - let val = machine.cur_frame().get(a)?; - machine.cur_frame().set(a, val + b) + let val: i32 = machine.cur_frame().get(a)?.try_into()?; + machine.cur_frame().set(a, Value::Int(val + b)) } fn invokevirtual(machine: &mut Machine) -> Result<()> { @@ -253,7 +259,7 @@ fn invokevirtual(machine: &mut Machine) -> Result<()> { 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); Ok(()) @@ -265,7 +271,7 @@ fn ireturn(machine: &mut Machine) -> Result<()> { None => return Err("Got no frame... somehow..."), }; 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.block.seek(return_addr as usize) } @@ -285,28 +291,28 @@ fn slp(machine: &mut Machine) -> Result<()> { #[cfg(feature = "bonus:network")] fn netbind(machine: &mut Machine) -> Result<()> { - let port = machine.cur_stack().pop()? as u16; - machine.net.bind(port) + let port: i32 = machine.cur_stack().pop()?.try_into()?; + machine.net.bind(port as u16) } #[cfg(feature = "bonus:network")] fn netconnect(machine: &mut Machine) -> Result<()> { - let port = machine.cur_stack().pop()? as u16; - let host = machine.cur_stack().pop()? as u32; - machine.net.connect(host, port) + let port: i32 = machine.cur_stack().pop()?.try_into()?; + let host: i32 = machine.cur_stack().pop()?.try_into()?; + machine.net.connect(host as u32, port as u16) } #[cfg(feature = "bonus:network")] fn netin(machine: &mut Machine) -> Result<()> { let byte = i32::from(machine.net.read_byte()?); - machine.cur_stack().push(byte); + machine.cur_stack().push(Value::Int(byte)); Ok(()) } #[cfg(feature = "bonus:network")] fn netout(machine: &mut Machine) -> Result<()> { - let val = machine.cur_stack().pop()? as u8; - machine.net.write_byte(val) + let val: i32 = machine.cur_stack().pop()?.try_into()?; + machine.net.write_byte(val as u8) } #[cfg(feature = "bonus:network")] @@ -316,35 +322,41 @@ fn netclose(machine: &mut Machine) -> Result<()> { #[cfg(feature = "bonus:heap")] fn newarray(machine: &mut Machine) -> Result<()> { - let size = machine.cur_stack().pop()? as usize; - let heapref = machine.heap.alloc(size); - machine.cur_stack().push(heapref as i32); + let size: i32 = machine.cur_stack().pop()?.try_into()?; + let heapref = machine.heap.alloc(size as usize); + machine.cur_stack().push(Value::HeapRef(heapref)); Ok(()) } #[cfg(feature = "bonus:heap")] fn iastore(machine: &mut Machine) -> Result<()> { - let heapref = machine.cur_stack().pop()? as usize; - let index = machine.cur_stack().pop()? as usize; - let value = machine.cur_stack().pop()?; + let heapref = match machine.cur_stack().pop()? { + Value::HeapRef(a) => a, + _ => 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); - heap[index] = value; + heap[index as usize] = value; Ok(()) } #[cfg(feature = "bonus:heap")] fn iaload(machine: &mut Machine) -> Result<()> { - let heapref = machine.cur_stack().pop()? as usize; - let index = machine.cur_stack().pop()? as usize; + let heapref = match machine.cur_stack().pop()? { + Value::HeapRef(a) => a, + _ => return Err("Cannot use int as heapref"), + }; + let index: i32 = machine.cur_stack().pop()?.try_into()?; let value: i32; { 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(()) } diff --git a/src/stack.rs b/src/stack.rs index c94e182..ae38ae9 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -1,8 +1,10 @@ use Result; +use value::Value; + #[derive(Debug, Default)] pub struct Stack { - pub data: Vec + pub data: Vec } impl Stack { @@ -20,25 +22,25 @@ impl Stack { self.len() == 0 } - pub fn get(&self, i: usize) -> i32 { - self.data[i] + pub fn get(&self, i: usize) -> &Value { + &self.data[i] } - pub fn top(&self) -> Result { - Ok(match self.data.last() { - Some(a) => *a, + pub fn top(&self) -> Result<&Value> { + Ok(match self.data.last() { + Some(a) => a, None => return Err("Stack empty"), }) } - pub fn pop(&mut self) -> Result { + pub fn pop(&mut self) -> Result { Ok(match self.data.pop() { Some(a) => a, None => return Err("Stack empty"), }) } - pub fn push(&mut self, val: i32) { + pub fn push(&mut self, val: Value) { self.data.push(val); } -} \ No newline at end of file +} diff --git a/src/value.rs b/src/value.rs new file mode 100644 index 0000000..9c2b1a6 --- /dev/null +++ b/src/value.rs @@ -0,0 +1,30 @@ +use Result; +use std::convert::TryInto; + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum Value { + Int(i32), + HeapRef(usize), +} + +impl TryInto for Value { + type Error = &'static str; + + fn try_into(self) -> Result { + match self { + Value::Int(a) => Ok(a), + Value::HeapRef(_) => Err("Cannot use HeapRef as i32"), + } + } +} + +impl TryInto for &Value { + type Error = &'static str; + + fn try_into(self) -> Result { + match self { + &Value::Int(a) => Ok(a), + &Value::HeapRef(_) => Err("Cannot use HeapRef as i32"), + } + } +} From 23cc193333642d6fca8d92ea7e74756bfca6d29e Mon Sep 17 00:00:00 2001 From: Jur van den Berg Date: Wed, 29 May 2019 15:38:00 +0200 Subject: [PATCH 2/2] Fix tests --- tests/advanced3.rs | 12 +++++++----- tests/advancedstack.rs | 14 +++++++++++--- tests/task4.rs | 17 +++++++++-------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/tests/advanced3.rs b/tests/advanced3.rs index 5370d59..76e3b2d 100644 --- a/tests/advanced3.rs +++ b/tests/advanced3.rs @@ -8,12 +8,13 @@ fn steps(machine: &mut rustijvm::Machine, num: usize) { #[test] fn advanced3_wide1() { - let mut machine = rustijvm::Machine::new_from_file("files/advanced/test-wide1.ijvm").unwrap(); + use rustijvm::value::Value::Int; + let mut machine = rustijvm::Machine::new_from_file("files/advanced/test-wide1.ijvm").unwrap(); steps(&mut machine, 6); - assert_eq!(machine.cur_frame().get(1), Ok(0x1)); + assert_eq!(machine.cur_frame().get(1), Ok(&Int(0x1))); steps(&mut machine, 2); - assert_eq!(machine.cur_frame().get(257), Ok(0x2)); + assert_eq!(machine.cur_frame().get(257), Ok(&Int(0x2))); steps(&mut machine, 1); assert_eq!(machine.get_tos(), Ok(0x1)); @@ -23,12 +24,13 @@ fn advanced3_wide1() { #[test] fn advanced3_wide2() { + use rustijvm::value::Value::Int; let mut machine = rustijvm::Machine::new_from_file("files/advanced/test-wide2.ijvm").unwrap(); steps(&mut machine, 6); - assert_eq!(machine.cur_frame().get(1), Ok(0x1)); + assert_eq!(machine.cur_frame().get(1), Ok(&Int(0x1))); steps(&mut machine, 2); - assert_eq!(machine.cur_frame().get(32768), Ok(0x2)); + assert_eq!(machine.cur_frame().get(32768), Ok(&Int(0x2))); steps(&mut machine, 1); assert_eq!(machine.get_tos(), Ok(0x1)); diff --git a/tests/advancedstack.rs b/tests/advancedstack.rs index 8f79bc1..ee086a4 100644 --- a/tests/advancedstack.rs +++ b/tests/advancedstack.rs @@ -1,5 +1,7 @@ extern crate rustijvm; +use std::convert::TryInto; + fn steps(machine: &mut rustijvm::Machine, num: usize) { for _ in 0..num { machine.step().unwrap(); @@ -44,7 +46,9 @@ fn advancedstack_contents() { let size = stack.len(); assert!(size >= 100); - let markers = (0..size).filter(|i| { stack.get(*i) == 0x2 }).count(); + let markers = (0..size).filter(|i| { + stack.get(*i).try_into().unwrap_or(0) == 0x2 + }).count(); assert!(markers >= 99); } @@ -55,7 +59,9 @@ fn advancedstack_method() { steps(&mut machine, 8); { let stack = machine.cur_stack(); - let markers = (0..stack.len()).filter(|i| { stack.get(*i) == 0x2 }).count(); + let markers = (0..stack.len()).filter(|i| { + stack.get(*i).try_into().unwrap_or(0) == 0x2 + }).count(); assert_eq!(markers, 4); } @@ -63,7 +69,9 @@ fn advancedstack_method() { steps(&mut machine, 2 * 5000); { let stack = machine.cur_stack(); - let markers = (0..stack.len()).filter(|i| { stack.get(*i) == 0x2 }).count(); + let markers = (0..stack.len()).filter(|i| { + stack.get(*i).try_into().unwrap_or(0) == 0x2 + }).count(); assert!(markers > 4000); } } diff --git a/tests/task4.rs b/tests/task4.rs index 15ca0c4..7781e1c 100644 --- a/tests/task4.rs +++ b/tests/task4.rs @@ -100,23 +100,24 @@ fn task4_iteration_load() { #[test] fn task4_iinc() { + use rustijvm::value::Value::Int; let mut machine = rustijvm::Machine::new_from_file("files/task4/IINCTest.ijvm").unwrap(); steps(&mut machine, 4); - assert_eq!(machine.cur_frame().get(0), Ok(0)); - assert_eq!(machine.cur_frame().get(1), Ok(0)); + assert_eq!(machine.cur_frame().get(0), Ok(&Int(0))); + assert_eq!(machine.cur_frame().get(1), Ok(&Int(0))); steps(&mut machine, 1); - assert_eq!(machine.cur_frame().get(0), Ok(0)); + assert_eq!(machine.cur_frame().get(0), Ok(&Int(0))); steps(&mut machine, 1); - assert_eq!(machine.cur_frame().get(0), Ok(1)); + assert_eq!(machine.cur_frame().get(0), Ok(&Int(1))); steps(&mut machine, 1); - assert_eq!(machine.cur_frame().get(0), Ok(4)); + assert_eq!(machine.cur_frame().get(0), Ok(&Int(4))); steps(&mut machine, 1); - assert_eq!(machine.cur_frame().get(1), Ok(0)); + assert_eq!(machine.cur_frame().get(1), Ok(&Int(0))); steps(&mut machine, 1); - assert_eq!(machine.cur_frame().get(1), Ok(-1)); + assert_eq!(machine.cur_frame().get(1), Ok(&Int(-1))); steps(&mut machine, 1); - assert_eq!(machine.cur_frame().get(1), Ok(-4)); + assert_eq!(machine.cur_frame().get(1), Ok(&Int(-4))); }