Fix a lot of things and implement gc

This commit is contained in:
2019-05-29 21:06:42 +02:00
parent c3876da74f
commit 84bdcf4b20
16 changed files with 146 additions and 55 deletions

View File

@@ -2,7 +2,6 @@ use block::Block;
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;

View File

@@ -1,11 +1,17 @@
use value::Value;
use std::rc::Rc;
use std::cell::RefCell;
pub type Heap = Rc<RefCell<Vec<Value>>>;
#[derive(Debug,Default)]
pub struct Heap {
pub heaps: Vec<Vec<i32>>
pub struct Heaps {
pub heaps: Vec<Heap>
}
impl Heap {
pub fn new() -> Heap {
Heap {
impl Heaps {
pub fn new() -> Heaps {
Heaps {
heaps: Vec::new()
}
}
@@ -14,16 +20,38 @@ impl Heap {
self.heaps.len()
}
pub fn get(&mut self, i: usize) -> &mut Vec<i32> {
&mut self.heaps[i]
pub fn get(&mut self, i: usize) -> Heap {
self.heaps[i].clone()
}
pub fn alloc(&mut self, size: usize) -> usize {
self.heaps.push(vec![0; size]);
self.len() - 1
pub fn alloc(&mut self, size: usize) -> Heap {
let heap = Rc::new(RefCell::new(vec![Value::Int(0); size]));
self.heaps.push(heap.clone());
heap
}
pub fn is_empty(&self) -> bool {
self.heaps.is_empty()
}
}
pub fn gc(&mut self) {
let pre_size = self.len();
if cfg!(feature = "debug:gc") {
for (i, heap) in self.heaps.iter().enumerate() {
eprintln!("GC heap {} ref = {}", i, Rc::strong_count(heap));
}
}
self.heaps = self.heaps.iter()
.filter(|e| Rc::strong_count(e) > 1)
.map(|e| Rc::clone(e))
.collect();
let post_size = self.len();
if cfg!(feature = "debug:gc") {
eprintln!("GC reaped {} heaps", pre_size - post_size);
}
}
}

View File

@@ -2,6 +2,7 @@
extern crate serde_derive;
#[macro_use]
extern crate lazy_static;
extern crate core;
pub mod ijvmreader;
pub mod binread;

View File

@@ -11,7 +11,7 @@ use stack::Stack;
use Result;
#[cfg(feature = "bonus:heap")]
use heap::Heap;
use heap::Heaps;
#[cfg(feature = "bonus:network")]
use netstack::NetStack;
use std::convert::TryInto;
@@ -28,7 +28,7 @@ pub struct Machine {
#[cfg(feature = "bonus:network")]
pub net: NetStack,
#[cfg(feature = "bonus:heap")]
pub heap: Heap,
pub heap: Heaps,
pub stream_in: Box<Read + Send + Sync>,
pub stream_out: Arc<Mutex<Write + Send + Sync>>,
@@ -49,7 +49,7 @@ impl Machine {
net: NetStack::new(),
#[cfg(feature = "bonus:heap")]
heap: Heap::new(),
heap: Heaps::new(),
}
}

View File

@@ -74,6 +74,7 @@ lazy_static! {
m[0xD1] = Operation::Op("NEWARRAY", newarray, vec![]);
m[0xD2] = Operation::Op("IALOAD", iaload, vec![]);
m[0xD3] = Operation::Op("IASTORE", iastore, vec![]);
m[0xD4] = Operation::Op("GC", gc, vec![]);
}
m
@@ -110,7 +111,7 @@ fn out(machine: &mut Machine) -> Result<()> {
let mut out = machine.stream_out.lock().unwrap();
out.write_all(&buffer).unwrap();
out.flush().unwrap();
return Ok(());
Ok(())
}
fn pop(machine: &mut Machine) -> Result<()> {
@@ -266,14 +267,20 @@ fn invokevirtual(machine: &mut Machine) -> Result<()> {
}
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..."),
};
let result = prev_frame.stack.pop()?;
let return_addr: i32 = prev_frame.get(0)?.try_into()?;
machine.cur_stack().push(result);
machine.block.seek(return_addr as usize)
// Lifetime for prev frame, allows gc to reap into the frame
{
let mut prev_frame: Frame = match machine.frame.pop() {
Some(a) => a,
None => return Err("Got no frame... somehow..."),
};
let result = prev_frame.stack.pop()?;
let return_addr: i32 = prev_frame.get(0)?.try_into()?;
machine.cur_stack().push(result);
machine.block.seek(return_addr as usize)?;
}
machine.heap.gc();
Ok(())
}
#[cfg(feature = "extra:sleep")]
@@ -323,40 +330,46 @@ fn netclose(machine: &mut Machine) -> Result<()> {
#[cfg(feature = "bonus:heap")]
fn newarray(machine: &mut Machine) -> Result<()> {
let size: i32 = machine.cur_stack().pop()?.try_into()?;
let heapref = machine.heap.alloc(size as usize);
machine.cur_stack().push(Value::HeapRef(heapref));
let heap = machine.heap.alloc(size as usize);
machine.cur_stack().push(Value::HeapRef(heap));
Ok(())
}
#[cfg(feature = "bonus:heap")]
fn iastore(machine: &mut Machine) -> Result<()> {
let heapref = match machine.cur_stack().pop()? {
use std::cell::RefCell;
let heap = 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 value = machine.cur_stack().pop()?.clone();
let heap = machine.heap.get(heapref);
heap[index as usize] = value;
RefCell::borrow_mut(&heap)[index as usize] = value;
Ok(())
}
#[cfg(feature = "bonus:heap")]
fn iaload(machine: &mut Machine) -> Result<()> {
let heapref = match machine.cur_stack().pop()? {
let heap = 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 value: Value;
{
let heap = machine.heap.get(heapref);
value = heap[index as usize];
value = heap.borrow()[index as usize].clone();
}
machine.cur_stack().push(Value::Int(value));
machine.cur_stack().push(value);
Ok(())
}
#[cfg(feature = "bonus:heap")]
fn gc(machine: &mut Machine) -> Result<()> {
machine.heap.gc();
Ok(())
}

View File

@@ -1,10 +1,11 @@
use Result;
use std::convert::TryInto;
use heap::Heap;
#[derive(Debug, Copy, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Int(i32),
HeapRef(usize),
HeapRef(Heap),
}
impl TryInto<i32> for Value {
@@ -22,9 +23,9 @@ 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"),
match *self {
Value::Int(a) => Ok(a),
Value::HeapRef(_) => Err("Cannot use HeapRef as i32"),
}
}
}