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
|
/*.jas
|
||||||
/*.ijvm
|
/*.ijvm
|
||||||
*.conf
|
*.conf
|
||||||
goJASM
|
gojasm
|
||||||
rustijvm
|
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 = ["extra:sleep"]
|
||||||
"extra:sleep" = []
|
"extra:sleep" = []
|
||||||
|
|
||||||
debug = ["debug:instr", "debug:frame"]
|
debug = ["debug:instr", "debug:frame", "debug:gc"]
|
||||||
"debug:instr" = []
|
"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 ops::{num_to_op, Operation};
|
||||||
use Result;
|
use Result;
|
||||||
|
|
||||||
#[allow(unknown_lints, len_without_is_empty)]
|
|
||||||
pub trait BinReadable {
|
pub trait BinReadable {
|
||||||
fn get(&mut self) -> Result<u8>;
|
fn get(&mut self) -> Result<u8>;
|
||||||
fn cur(&self) -> usize;
|
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)]
|
#[derive(Debug,Default)]
|
||||||
pub struct Heap {
|
pub struct Heaps {
|
||||||
pub heaps: Vec<Vec<i32>>
|
pub heaps: Vec<Heap>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Heap {
|
impl Heaps {
|
||||||
pub fn new() -> Heap {
|
pub fn new() -> Heaps {
|
||||||
Heap {
|
Heaps {
|
||||||
heaps: Vec::new()
|
heaps: Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,16 +20,38 @@ impl Heap {
|
|||||||
self.heaps.len()
|
self.heaps.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&mut self, i: usize) -> &mut Vec<i32> {
|
pub fn get(&mut self, i: usize) -> Heap {
|
||||||
&mut self.heaps[i]
|
self.heaps[i].clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alloc(&mut self, size: usize) -> usize {
|
pub fn alloc(&mut self, size: usize) -> Heap {
|
||||||
self.heaps.push(vec![0; size]);
|
let heap = Rc::new(RefCell::new(vec![Value::Int(0); size]));
|
||||||
self.len() - 1
|
self.heaps.push(heap.clone());
|
||||||
|
heap
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.heaps.is_empty()
|
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;
|
extern crate serde_derive;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
pub mod ijvmreader;
|
pub mod ijvmreader;
|
||||||
pub mod binread;
|
pub mod binread;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use stack::Stack;
|
|||||||
use Result;
|
use Result;
|
||||||
|
|
||||||
#[cfg(feature = "bonus:heap")]
|
#[cfg(feature = "bonus:heap")]
|
||||||
use heap::Heap;
|
use heap::Heaps;
|
||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
use netstack::NetStack;
|
use netstack::NetStack;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
@@ -28,7 +28,7 @@ pub struct Machine {
|
|||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
pub net: NetStack,
|
pub net: NetStack,
|
||||||
#[cfg(feature = "bonus:heap")]
|
#[cfg(feature = "bonus:heap")]
|
||||||
pub heap: Heap,
|
pub heap: Heaps,
|
||||||
|
|
||||||
pub stream_in: Box<Read + Send + Sync>,
|
pub stream_in: Box<Read + Send + Sync>,
|
||||||
pub stream_out: Arc<Mutex<Write + Send + Sync>>,
|
pub stream_out: Arc<Mutex<Write + Send + Sync>>,
|
||||||
@@ -49,7 +49,7 @@ impl Machine {
|
|||||||
net: NetStack::new(),
|
net: NetStack::new(),
|
||||||
|
|
||||||
#[cfg(feature = "bonus:heap")]
|
#[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[0xD1] = Operation::Op("NEWARRAY", newarray, vec![]);
|
||||||
m[0xD2] = Operation::Op("IALOAD", iaload, vec![]);
|
m[0xD2] = Operation::Op("IALOAD", iaload, vec![]);
|
||||||
m[0xD3] = Operation::Op("IASTORE", iastore, vec![]);
|
m[0xD3] = Operation::Op("IASTORE", iastore, vec![]);
|
||||||
|
m[0xD4] = Operation::Op("GC", gc, vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
m
|
m
|
||||||
@@ -110,7 +111,7 @@ fn out(machine: &mut Machine) -> Result<()> {
|
|||||||
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();
|
||||||
return Ok(());
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop(machine: &mut Machine) -> Result<()> {
|
fn pop(machine: &mut Machine) -> Result<()> {
|
||||||
@@ -266,14 +267,20 @@ fn invokevirtual(machine: &mut Machine) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ireturn(machine: &mut Machine) -> Result<()> {
|
fn ireturn(machine: &mut Machine) -> Result<()> {
|
||||||
let mut prev_frame: Frame = match machine.frame.pop() {
|
// Lifetime for prev frame, allows gc to reap into the frame
|
||||||
Some(a) => a,
|
{
|
||||||
None => return Err("Got no frame... somehow..."),
|
let mut prev_frame: Frame = match machine.frame.pop() {
|
||||||
};
|
Some(a) => a,
|
||||||
let result = prev_frame.stack.pop()?;
|
None => return Err("Got no frame... somehow..."),
|
||||||
let return_addr: i32 = prev_frame.get(0)?.try_into()?;
|
};
|
||||||
machine.cur_stack().push(result);
|
let result = prev_frame.stack.pop()?;
|
||||||
machine.block.seek(return_addr as usize)
|
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")]
|
#[cfg(feature = "extra:sleep")]
|
||||||
@@ -323,40 +330,46 @@ 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: i32 = machine.cur_stack().pop()?.try_into()?;
|
let size: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
let heapref = machine.heap.alloc(size as usize);
|
let heap = machine.heap.alloc(size as usize);
|
||||||
machine.cur_stack().push(Value::HeapRef(heapref));
|
machine.cur_stack().push(Value::HeapRef(heap));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "bonus:heap")]
|
#[cfg(feature = "bonus:heap")]
|
||||||
fn iastore(machine: &mut Machine) -> Result<()> {
|
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,
|
Value::HeapRef(a) => a,
|
||||||
_ => return Err("Cannot use int as heapref"),
|
_ => return Err("Cannot use int as heapref"),
|
||||||
};
|
};
|
||||||
let index: i32 = machine.cur_stack().pop()?.try_into()?;
|
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);
|
RefCell::borrow_mut(&heap)[index as usize] = 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 = match machine.cur_stack().pop()? {
|
let heap = match machine.cur_stack().pop()? {
|
||||||
Value::HeapRef(a) => a,
|
Value::HeapRef(a) => a,
|
||||||
_ => return Err("Cannot use int as heapref"),
|
_ => return Err("Cannot use int as heapref"),
|
||||||
};
|
};
|
||||||
let index: i32 = machine.cur_stack().pop()?.try_into()?;
|
let index: i32 = machine.cur_stack().pop()?.try_into()?;
|
||||||
|
|
||||||
let value: i32;
|
let value: Value;
|
||||||
{
|
{
|
||||||
let heap = machine.heap.get(heapref);
|
value = heap.borrow()[index as usize].clone();
|
||||||
value = heap[index as usize];
|
|
||||||
}
|
}
|
||||||
machine.cur_stack().push(Value::Int(value));
|
machine.cur_stack().push(value);
|
||||||
|
|
||||||
Ok(())
|
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 Result;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use heap::Heap;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Int(i32),
|
Int(i32),
|
||||||
HeapRef(usize),
|
HeapRef(Heap),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryInto<i32> for Value {
|
impl TryInto<i32> for Value {
|
||||||
@@ -22,9 +23,9 @@ impl TryInto<i32> for &Value {
|
|||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
|
|
||||||
fn try_into(self) -> Result<i32> {
|
fn try_into(self) -> Result<i32> {
|
||||||
match self {
|
match *self {
|
||||||
&Value::Int(a) => Ok(a),
|
Value::Int(a) => Ok(a),
|
||||||
&Value::HeapRef(_) => Err("Cannot use HeapRef as i32"),
|
Value::HeapRef(_) => Err("Cannot use HeapRef as i32"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
extern crate rustijvm;
|
extern crate rustijvm;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::io::{Seek, SeekFrom, Read};
|
||||||
use std::io::{Cursor, Seek, SeekFrom, Read};
|
|
||||||
|
|
||||||
fn steps(machine: &mut rustijvm::Machine, num: usize) {
|
fn steps(machine: &mut rustijvm::Machine, num: usize) {
|
||||||
for _ in 0..num {
|
for _ in 0..num {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
extern crate rustijvm;
|
extern crate rustijvm;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::io::{Seek, SeekFrom, Read};
|
||||||
use std::io::{Cursor, Seek, SeekFrom, Read};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn advanced4_tanenbaum() {
|
fn advanced4_tanenbaum() {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
extern crate rustijvm;
|
extern crate rustijvm;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::io::{Seek, SeekFrom, Read};
|
||||||
use std::io::{Cursor, Seek, SeekFrom, Read};
|
|
||||||
|
|
||||||
fn run_calc(input: &'static str, expected: &str) {
|
fn run_calc(input: &'static str, expected: &str) {
|
||||||
let rc = rustijvm::stubs::output_stub();
|
let rc = rustijvm::stubs::output_stub();
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
extern crate rustijvm;
|
extern crate rustijvm;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::io::{Seek, SeekFrom, Read};
|
||||||
use std::io::{Cursor, Seek, SeekFrom, Read};
|
|
||||||
|
|
||||||
fn run_calc(input: &'static str, expected: &str) {
|
fn run_calc(input: &'static str, expected: &str) {
|
||||||
let rc = rustijvm::stubs::output_stub();
|
let rc = rustijvm::stubs::output_stub();
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
extern crate rustijvm;
|
extern crate rustijvm;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::io::{Seek, SeekFrom, Read};
|
||||||
use std::io::{Cursor, Seek, SeekFrom, Read};
|
|
||||||
|
|
||||||
fn run_bfi(file: &str) -> String {
|
fn run_bfi(file: &str) -> String {
|
||||||
let file = File::open(file).expect("Missing bf file");
|
let file = File::open(file).expect("Missing bf file");
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
extern crate rustijvm;
|
extern crate rustijvm;
|
||||||
|
|
||||||
use std::io::{Cursor, Read, Seek, SeekFrom};
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
fn steps(machine: &mut rustijvm::Machine, num: usize) {
|
fn steps(machine: &mut rustijvm::Machine, num: usize) {
|
||||||
for _ in 0..num {
|
for _ in 0..num {
|
||||||
|
|||||||
Reference in New Issue
Block a user