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. # It is not intended for manual editing.
version = 3 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]] [[package]]
name = "classfile_reader" name = "classfile_reader"
version = "0.1.0" 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 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
regex = "1.9.5"
anyhow = { version = "1.0", features = [] }

View file

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

View file

@ -1,9 +1,10 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use anyhow::Error;
use crate::io::{read_f32, read_f64, read_i32, read_i64, read_u16, read_u32}; use crate::io::{read_f32, read_f64, read_i32, read_i64, read_u16, read_u32};
use crate::class::{AttributeType, Class, MethodCode, Exception, Field, Method}; 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); check_magic(&bytecode);
let constant_pool_count = read_u16(&bytecode, 8); 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), minor_version: read_u16(&bytecode, 4),
major_version: read_u16(&bytecode, 6), major_version: read_u16(&bytecode, 6),
constant_pool, constant_pool,

View file

@ -1,5 +1,6 @@
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::Read; use std::io::Read;
use anyhow::{anyhow, Error};
pub(crate) fn read_u8(data: &[u8], pos: usize) -> u8 { 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")) 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")) f64::from_be_bytes(data[pos..pos + 8].try_into().expect("slice with incorrect length"))
} }
pub fn read_class_file(name: &str) -> Vec<u8> { pub fn find_class(classpath: &Vec<String>, class_name: &str) -> Result<String, Error> {
let mut f = File::open(name).expect("no file found"); for clp_entry in classpath {
let metadata = fs::metadata(name).expect("unable to read metadata"); let mut maybe_path = clp_entry.clone();
let mut buffer = vec![0; metadata.len() as usize]; maybe_path.push_str("/");
let _ = f.read(&mut buffer).expect("buffer overflow"); maybe_path.push_str(class_name);
buffer 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 opcodes;
pub mod vm; pub mod vm;
mod heap; mod heap;
mod classloader; pub mod classloader;

View file

@ -1,3 +1,5 @@
use regex::Regex;
fn main() { fn main() {
// if let Some(class) = classfile_reader::get_class(classfile_reader::io::read_class_file("./Dummy.class")){ // if let Some(class) = classfile_reader::get_class(classfile_reader::io::read_class_file("./Dummy.class")){
// println!("{:?}", class); // println!("{:?}", class);
@ -5,6 +7,9 @@ fn main() {
// println!("{:?}", ret); // 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 DRETURN: u8 = 175; // (0xaf) Return double from method
// pub const areturn: u8 = 176; //(0xb0) return reference // 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 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 NEW: u8 = 187; // (0xbb) Create new object
// pub const invokevirtual: u8 = 182; // (0xb6) Invoke instance method; dispatch based on class // 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::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use anyhow::Error;
use crate::opcodes; use crate::opcodes;
use crate::class::{AttributeType, Class, Method, Value}; use crate::class::{AttributeType, Class, Method, Value};
@ -28,20 +29,34 @@ impl StackFrame {
} }
pub struct Vm { pub struct Vm {
classes: HashMap<String, Class>, //TODO implement classloader classpath: Vec<String>,
classes: HashMap<String, Class>,
//TODO implement classloader
heap: Heap, heap: Heap,
} }
impl Vm { impl Vm {
pub fn new() -> Self { pub fn new(classpath: &'static str) -> Self {
Self { Self {
classpath: classpath.split(":").into_iter().map(|s| s.to_owned()).collect(),
classes: HashMap::new(), classes: HashMap::new(),
heap: Heap::new(), heap: Heap::new(),
} }
} }
pub fn load_class(name: String){ pub fn get_class(&mut self, class_name: &str) -> Result<&Class, Error> {
load_class() 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>) { pub fn new_instance(&self, class: Rc<Class>) {
@ -55,7 +70,7 @@ impl Vm {
"J" => Value::I64(0), "J" => Value::I64(0),
"F" => Value::F32(0.0), "F" => Value::F32(0.0),
"D" => Value::F64(0.0), "D" => Value::F64(0.0),
//ref "L" => Value::Null,
_ => Value::Void _ => Value::Void
}; };
data.insert(f.name_index, value); data.insert(f.name_index, value);
@ -63,7 +78,10 @@ impl Vm {
Object::new(class.clone(), data); 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() { if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() {
let mut stack = StackFrame::new(); let mut stack = StackFrame::new();
let mut pc: usize = 0; let mut pc: usize = 0;
@ -130,9 +148,7 @@ impl Vm {
&opcodes::NEW => { &opcodes::NEW => {
let cp_index = read_u16(&code.opcodes, pc); 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::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 //TODO implement all opcodes
@ -141,5 +157,8 @@ impl Vm {
} }
} }
None // TODO error situation None // TODO error situation
} else {
panic!("class not found");
}
} }
} }

View file

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