Fix a lot of things and implement gc
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,5 +2,5 @@ target
|
||||
/*.jas
|
||||
/*.ijvm
|
||||
*.conf
|
||||
goJASM
|
||||
gojasm
|
||||
rustijvm
|
||||
|
||||
17
.gitlab-ci.yml
Normal file
17
.gitlab-ci.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
stages:
|
||||
- build
|
||||
|
||||
rust-latest:
|
||||
stage: build
|
||||
image: rust:latest
|
||||
script:
|
||||
- cargo build --verbose
|
||||
- cargo test --verbose
|
||||
allow_failure: true
|
||||
|
||||
rust-nightly:
|
||||
stage: build
|
||||
image: rustlang/rust:nightly
|
||||
script:
|
||||
- cargo build --verbose
|
||||
- cargo test --verbose
|
||||
@@ -18,6 +18,7 @@ bonus = ["bonus:network", "bonus:heap"]
|
||||
extra = ["extra:sleep"]
|
||||
"extra:sleep" = []
|
||||
|
||||
debug = ["debug:instr", "debug:frame"]
|
||||
debug = ["debug:instr", "debug:frame", "debug:gc"]
|
||||
"debug:instr" = []
|
||||
"debug:frame" = []
|
||||
"debug:frame" = []
|
||||
"debug:gc" = []
|
||||
|
||||
37
ijvm.config
Normal file
37
ijvm.config
Normal file
@@ -0,0 +1,37 @@
|
||||
0x10 BIPUSH byte
|
||||
0x59 DUP
|
||||
0xA7 GOTO label
|
||||
0x60 IADD
|
||||
0x7E IAND
|
||||
0x99 IFEQ label
|
||||
0x9B IFLT label
|
||||
0x9F IF_ICMPEQ label
|
||||
0x84 IINC var byte
|
||||
0x15 ILOAD var
|
||||
0xB6 INVOKEVIRTUAL method
|
||||
0xB0 IOR
|
||||
0xAC IRETURN
|
||||
0x36 ISTORE var
|
||||
0x64 ISUB
|
||||
0x13 LDC_W constant
|
||||
0x00 NOP
|
||||
0x57 POP
|
||||
0x5F SWAP
|
||||
0xC4 WIDE
|
||||
0xFF HALT
|
||||
0xFE ERR
|
||||
0xFD OUT
|
||||
0xFC IN
|
||||
|
||||
0xD1 NEWARRAY
|
||||
0xD2 IALOAD
|
||||
0xD3 IASTORE
|
||||
0xD4 GC
|
||||
|
||||
0xE1 NETBIND
|
||||
0xE2 NETCONNECT
|
||||
0xE3 NETIN
|
||||
0xE4 NETOUT
|
||||
0xE5 NETCLOSE
|
||||
|
||||
0xF0 SLP byte
|
||||
@@ -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;
|
||||
|
||||
50
src/heap.rs
50
src/heap.rs
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
extern crate serde_derive;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate core;
|
||||
|
||||
pub mod ijvmreader;
|
||||
pub mod binread;
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
53
src/ops.rs
53
src/ops.rs
@@ -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(())
|
||||
}
|
||||
|
||||
11
src/value.rs
11
src/value.rs
@@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
extern crate rustijvm;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::io::{Cursor, Seek, SeekFrom, Read};
|
||||
use std::io::{Seek, SeekFrom, Read};
|
||||
|
||||
fn steps(machine: &mut rustijvm::Machine, num: usize) {
|
||||
for _ in 0..num {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
extern crate rustijvm;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::io::{Cursor, Seek, SeekFrom, Read};
|
||||
use std::io::{Seek, SeekFrom, Read};
|
||||
|
||||
#[test]
|
||||
fn advanced4_tanenbaum() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
extern crate rustijvm;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::io::{Cursor, Seek, SeekFrom, Read};
|
||||
use std::io::{Seek, SeekFrom, Read};
|
||||
|
||||
fn run_calc(input: &'static str, expected: &str) {
|
||||
let rc = rustijvm::stubs::output_stub();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
extern crate rustijvm;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::io::{Cursor, Seek, SeekFrom, Read};
|
||||
use std::io::{Seek, SeekFrom, Read};
|
||||
|
||||
fn run_calc(input: &'static str, expected: &str) {
|
||||
let rc = rustijvm::stubs::output_stub();
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
extern crate rustijvm;
|
||||
|
||||
use std::fs::File;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::io::{Cursor, Seek, SeekFrom, Read};
|
||||
use std::io::{Seek, SeekFrom, Read};
|
||||
|
||||
fn run_bfi(file: &str) -> String {
|
||||
let file = File::open(file).expect("Missing bf file");
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
extern crate rustijvm;
|
||||
|
||||
use std::io::{Cursor, Read, Seek, SeekFrom};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
|
||||
fn steps(machine: &mut rustijvm::Machine, num: usize) {
|
||||
for _ in 0..num {
|
||||
|
||||
Reference in New Issue
Block a user