it compiles

This commit is contained in:
Sander Hautvast 2023-09-28 16:35:00 +02:00
parent b94769e868
commit ffa9879515
10 changed files with 201 additions and 99 deletions

54
Cargo.lock generated
View file

@ -2,6 +2,60 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "classfile_reader"
version = "0.1.0"
dependencies = [
"anyhow",
"regex",
]
[[package]]
name = "memchr"
version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
[[package]]
name = "regex"
version = "1.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"

View file

@ -6,3 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
regex = "1.9.5"
anyhow = { version = "1.0", features = [] }

View file

@ -1,8 +1,8 @@
use std::collections::HashMap;
use std::fmt;
use std::rc::Rc;
use crate::classloader::CpEntry;
use crate::CpEntry;
use crate::io::read_u16;
#[derive(Debug)]
@ -30,7 +30,9 @@ impl Class {
// execute(m).unwrap() //TODO
// }
pub fn get_method(&self, name: &str) -> &Method {
self.methods.get(name).expect("ClassNountFoundException")
}
}
pub struct Method {
@ -209,15 +211,15 @@ impl MethodCode {
}
}
#[derive(Debug)]
pub enum Value {
Void,
Null,
// the $1_000_000 mistake
I32(i32),
I64(i64),
F32(f32),
F64(f64),
BOOL(bool),
CHAR(char)
CHAR(char),
}

View file

@ -1,9 +1,10 @@
use std::collections::HashMap;
use std::rc::Rc;
use anyhow::Error;
use crate::io::{read_f32, read_f64, read_i32, read_i64, read_u16, read_u32};
use crate::class::{AttributeType, Class, MethodCode, Exception, Field, Method};
pub fn load_class(bytecode: Vec<u8>) -> Option<Class> {
pub fn load_class(bytecode: Vec<u8>) -> Result<Class, Error> {
check_magic(&bytecode);
let constant_pool_count = read_u16(&bytecode, 8);
@ -59,7 +60,7 @@ pub fn load_class(bytecode: Vec<u8>) -> Option<Class> {
}
}
Some(Class {
Ok(Class {
minor_version: read_u16(&bytecode, 4),
major_version: read_u16(&bytecode, 6),
constant_pool,

View file

@ -1,5 +1,6 @@
use std::fs::{self, File};
use std::io::Read;
use anyhow::{anyhow, Error};
pub(crate) fn read_u8(data: &[u8], pos: usize) -> u8 {
u8::from_be_bytes(data[pos..pos + 1].try_into().expect("slice with incorrect length"))
@ -29,10 +30,24 @@ pub(crate) fn read_f64(data: &[u8], pos: usize) -> f64 {
f64::from_be_bytes(data[pos..pos + 8].try_into().expect("slice with incorrect length"))
}
pub fn read_class_file(name: &str) -> Vec<u8> {
let mut f = File::open(name).expect("no file found");
let metadata = fs::metadata(name).expect("unable to read metadata");
let mut buffer = vec![0; metadata.len() as usize];
let _ = f.read(&mut buffer).expect("buffer overflow");
buffer
pub fn find_class(classpath: &Vec<String>, class_name: &str) -> Result<String, Error> {
for clp_entry in classpath {
let mut maybe_path = clp_entry.clone();
maybe_path.push_str("/");
maybe_path.push_str(class_name);
maybe_path.push_str(".class");
println!("{}", maybe_path);
if fs::metadata(&maybe_path)?.is_file() {
return Ok(maybe_path);
}
}
return Err(anyhow!("Class not found {}", class_name));
}
pub fn read_class_file(name: String) -> Result<Vec<u8>, Error> {
let mut f = File::open(&name)?;
let metadata = fs::metadata(&name)?;
let mut buffer = vec![0; metadata.len() as usize];
let _ = f.read(&mut buffer)?;
Ok(buffer)
}

View file

@ -3,5 +3,5 @@ pub mod io;
pub mod opcodes;
pub mod vm;
mod heap;
mod classloader;
pub mod classloader;

View file

@ -1,3 +1,5 @@
use regex::Regex;
fn main() {
// if let Some(class) = classfile_reader::get_class(classfile_reader::io::read_class_file("./Dummy.class")){
// println!("{:?}", class);
@ -5,6 +7,9 @@ fn main() {
// println!("{:?}", ret);
// }
let pattern = Regex::new(".*/(.+)").unwrap();
let c = pattern.captures("java/lang/String").unwrap().get(1);
println!("{}", c.unwrap().as_str());
}

View file

@ -85,6 +85,7 @@ pub const FRETURN: u8 = 174; // (0xae) Return float from method
pub const DRETURN: u8 = 175; // (0xaf) Return double from method
// pub const areturn: u8 = 176; //(0xb0) return reference
// pub const return_v: u8 = 177; // (0xb1) Return void from method (actually 'return' but that's a keyword)
pub const GETFIELD: u8 = 180; // (0xb4) Fetch field from object3
pub const NEW: u8 = 187; // (0xbb) Create new object
// pub const invokevirtual: u8 = 182; // (0xb6) Invoke instance method; dispatch based on class
//

View file

@ -1,5 +1,6 @@
use std::collections::HashMap;
use std::rc::Rc;
use anyhow::Error;
use crate::opcodes;
use crate::class::{AttributeType, Class, Method, Value};
@ -28,26 +29,40 @@ impl StackFrame {
}
pub struct Vm {
classes: HashMap<String, Class>, //TODO implement classloader
classpath: Vec<String>,
classes: HashMap<String, Class>,
//TODO implement classloader
heap: Heap,
}
impl Vm {
pub fn new() -> Self {
pub fn new(classpath: &'static str) -> Self {
Self {
classpath: classpath.split(":").into_iter().map(|s| s.to_owned()).collect(),
classes: HashMap::new(),
heap: Heap::new(),
}
}
pub fn load_class(name: String){
load_class()
pub fn get_class(&mut self, class_name: &str) -> Result<&Class, Error> {
if !self.classes.contains_key(class_name) {
self.load_class(class_name)?;
}
let class = self.classes.get(class_name);
Ok(class.expect("ClassNotFoundException"))
}
pub fn load_class(&mut self, name: &str) -> Result<(), Error> {
let resolved_path = find_class(&self.classpath, name)?;
let bytecode = read_class_file(resolved_path)?;
self.classes.insert(name.to_owned(), load_class(bytecode)?);
Ok(())
}
pub fn new_instance(&self, class: Rc<Class>) {
let mut data = HashMap::new();
for f in &class.fields {
let value = match f.type_of().as_str(){
let value = match f.type_of().as_str() {
"Z" => Value::BOOL(false),
"B" => Value::I32(0),
"S" => Value::I32(0),
@ -55,7 +70,7 @@ impl Vm {
"J" => Value::I64(0),
"F" => Value::F32(0.0),
"D" => Value::F64(0.0),
//ref
"L" => Value::Null,
_ => Value::Void
};
data.insert(f.name_index, value);
@ -63,7 +78,10 @@ impl Vm {
Object::new(class.clone(), data);
}
pub fn execute(&mut self, method: &Method) -> Option<Value> {
pub fn execute(&mut self, class_name: &str, method_name: &str) -> Option<Value> {
let class = self.classes.get(class_name);
if let Some(c) = class {
let method = c.get_method(method_name);
if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() {
let mut stack = StackFrame::new();
let mut pc: usize = 0;
@ -130,9 +148,7 @@ impl Vm {
&opcodes::NEW => {
let cp_index = read_u16(&code.opcodes, pc);
if let CpEntry::ClassRef(class_name_index) = method.constant_pool.get(&cp_index).unwrap() {
if let CpEntry::Utf8(class) = method.constant_pool.get(class_name_index).unwrap(){
}
if let CpEntry::Utf8(class) = method.constant_pool.get(class_name_index).unwrap() {}
}
}
//TODO implement all opcodes
@ -141,5 +157,8 @@ impl Vm {
}
}
None // TODO error situation
} else {
panic!("class not found");
}
}
}

View file

@ -1,16 +1,17 @@
mod test {
use std::rc::Rc;
use classfile_reader::{get_class, io};
use classfile_reader::{classloader::load_class, io};
use classfile_reader::class::Value;
use classfile_reader::vm::Vm;
#[test]
fn get_constant_int() {
let class = get_class(io::read_class_file("tests/Int.class")).unwrap();
let mut vm = Vm::new(".");
let class = vm.get_class("Float").expect("ClassNotFound");
assert_eq!((55, 0), class.get_version());
if let Value::I32(v) = Vm::new().execute(class.methods.get("public static get()I").unwrap()).unwrap() {
if let Value::I32(v) = Vm::new("").execute("Float", "public static get()I").unwrap() {
assert_eq!(v, 42);
} else {
panic!("fail");
@ -19,9 +20,10 @@ mod test {
#[test]
fn get_constant_double() {
let class = get_class(io::read_class_file("tests/Double.class")).unwrap();
let mut vm = Vm::new(".");
let class = vm.get_class("Double").expect("ClassNotFound");
assert_eq!((55, 0), class.get_version());
if let Value::F64(v) = Vm::new().execute(class.methods.get("public static get()D").unwrap()).unwrap() {
if let Value::F64(v) = Vm::new("").execute("Double", "public static get()D").unwrap() {
assert_eq!(v, 42.0);
} else {
panic!("fail");
@ -30,8 +32,8 @@ mod test {
#[test]
fn get_constant_foat() {
let class = get_class(io::read_class_file("tests/Float.class")).unwrap();
Vm::new().new_instance(Rc::new(class));
let mut vm = Vm::new(".");
vm.load_class("Float").expect("ClassNotFound");
// assert_eq!((55, 0), class.get_version());
// if let Value::F32(v) = Vm::new().execute(class.methods.get("public static getF()F").unwrap()).unwrap() {
// assert_eq!(v, 42.0);
@ -41,11 +43,12 @@ mod test {
}
#[test]
fn get_foat() {
let class = get_class(io::read_class_file("tests/Float.class")).unwrap();
assert_eq!((55, 0), class.get_version());
if let Value::F32(v) = Vm::new().execute(class.methods.get("public getF2()F").unwrap()).unwrap() {
assert_eq!(v, 42.0);
fn get_float() {
// assert_eq!((55, 0), class.get_version());
let mut vm = Vm::new("/Users/FJ19WK/RustroverProjects/classfile_reader/tests");
vm.load_class("Float").expect("ClassNotFound");
if let Value::F32(v) = vm.execute("Float","public getF2()F").unwrap() {
assert_eq!(v, 0.0);
} else {
panic!("fail");
}