Somewhat recursive string construction

This commit is contained in:
VegOwOtenks 2024-09-05 00:33:14 +02:00
parent 4dabd6c3a8
commit 3c4921aa54
9 changed files with 1130 additions and 185 deletions

View file

@ -72,6 +72,7 @@ impl Bytecode {
0xB8 => (Instruction::InvokeStatic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xB8 => (Instruction::InvokeStatic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
0xBA => (Instruction::InvokeDynamic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16, (self.bytes[offset+3] as u16) << 8 | self.bytes[offset+4] as u16), 5), 0xBA => (Instruction::InvokeDynamic((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16, (self.bytes[offset+3] as u16) << 8 | self.bytes[offset+4] as u16), 5),
0xBB => (Instruction::NewObject((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3), 0xBB => (Instruction::NewObject((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
0xBD => (Instruction::NewArray((self.bytes[offset+1] as u16) << 8 | self.bytes[offset+2] as u16), 3),
_ => (Instruction::Unknown(opcode), 1) _ => (Instruction::Unknown(opcode), 1)
} }
} }
@ -164,6 +165,7 @@ pub enum Instruction {
InvokeSpecial(u16) = 0xB7, // invoke instance method InvokeSpecial(u16) = 0xB7, // invoke instance method
InvokeStatic(u16) = 0xB8, // invoke static function InvokeStatic(u16) = 0xB8, // invoke static function
InvokeDynamic(u16, u16) = 0xBA, // invoke dynamic function InvokeDynamic(u16, u16) = 0xBA, // invoke dynamic function
NewObject(u16) = 0xBB, // Create a new object from a constant-pool reference NewObject(u16) = 0xBB, // Create a new object from a constant-pool class reference
NewArray(u16) = 0xBD, // Create a new array from a constant-pool component class reference
Unknown(u8), Unknown(u8),
} }

View file

@ -5,7 +5,7 @@ use core::str::Utf8Error;
use crate::accessmasks::*; use crate::accessmasks::*;
use crate::bytecode::Bytecode; use crate::bytecode::Bytecode;
use crate::constantpool::{ ConstantPoolInfo, ConstantUtf8Info, ConstantMethodRefInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo }; use crate::constantpool::{ ConstantFieldRefInfo, ConstantPoolInfo, ConstantUtf8Info, ConstantStringInfo, ConstantMethodRefInfo, ConstantClassInfo, ConstantNameAndTypeInfo, ConstantIntegerInfo, ConstantLongInfo };
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -217,6 +217,17 @@ impl JavaClassFile {
return Ok(methodref_entry); return Ok(methodref_entry);
} }
pub fn pool_fieldref_entry(&self, index: u16) -> Result<&ConstantFieldRefInfo, Error> {
let pool_entry = self.pool_entry(index)?;
let fieldref_entry = match pool_entry {
ConstantPoolInfo::FieldRef(data) => data,
_ => unreachable!(),
};
return Ok(fieldref_entry);
}
pub fn pool_class_entry(&self, index: u16) -> Result<&ConstantClassInfo, Error> { pub fn pool_class_entry(&self, index: u16) -> Result<&ConstantClassInfo, Error> {
let pool_entry = self.pool_entry(index)?; let pool_entry = self.pool_entry(index)?;
@ -235,6 +246,15 @@ impl JavaClassFile {
}; };
} }
pub fn pool_long_entry(&self, index: u16) -> Result<&ConstantLongInfo, Error> {
let pool_entry = self.pool_entry(index)?;
return match pool_entry {
ConstantPoolInfo::Long(data) => Ok(data),
_ => Err(Error::BadFileError(format!("Expected constant pool entry {} in class {} to be of type Long but found {:?}", index, self.get_classname()?, pool_entry)))
};
}
pub fn pool_int_entry(&self, index: u16) -> Result<&ConstantIntegerInfo, Error> { pub fn pool_int_entry(&self, index: u16) -> Result<&ConstantIntegerInfo, Error> {
let pool_entry = self.pool_entry(index)?; let pool_entry = self.pool_entry(index)?;
@ -253,6 +273,47 @@ impl JavaClassFile {
}; };
} }
pub fn pool_string_entry(&self, index: u16) -> Result<&ConstantStringInfo, Error> {
let pool_entry = self.pool_entry(index)?;
return match pool_entry {
ConstantPoolInfo::String(data) => Ok(data),
_ => Err(Error::BadFileError(format!("Expected constant pool entry {} in class {} to be of type String but found {:?}", index, self.get_classname()?, pool_entry)))
};
}
pub fn gather_string(&self, index: u16) -> Result<&String, Error> {
let string = self.pool_string_entry(index)?;
return Ok(&(self.pool_utf8_entry(string.string_index)?.utf8));
}
pub fn gather_nameandtype(&self, index: u16) -> Result<(&String, &String), Error> {
let nameandtype = self.pool_nameandtype_entry(index)?;
let name = &self.pool_utf8_entry(nameandtype.name_index)?.utf8;
let descriptor = &self.pool_utf8_entry(nameandtype.descriptor_index)?.utf8;
Ok((name, descriptor))
}
pub fn gather_fieldref(&self, index: u16) -> Result<(&String, &String, &String), Error> {
let fieldref = self.pool_fieldref_entry(index)?;
let (field_name, field_descriptor) = self.gather_nameandtype(fieldref.name_and_type_index)?;
let class_name = self.gather_class(fieldref.class_index)?;
Ok((class_name, field_name, field_descriptor))
}
pub fn gather_class(&self, index: u16) -> Result<&String, Error> {
let class_entry = self.pool_class_entry(index)?;
let class_name_entry = self.pool_utf8_entry(class_entry.name_index)?;
let class_name = &class_name_entry.utf8;
Ok(class_name)
}
pub fn gather_methodref(&self, index: u16) -> Result<(&String, &String, &String), Error> { pub fn gather_methodref(&self, index: u16) -> Result<(&String, &String, &String), Error> {
let methodref = self.pool_methodref_entry(index)?; let methodref = self.pool_methodref_entry(index)?;
let class_entry = self.pool_class_entry(methodref.class_index)?; let class_entry = self.pool_class_entry(methodref.class_index)?;
@ -671,7 +732,7 @@ impl ExceptionAttributeData {
} }
#[repr(u8)] #[repr(u8)]
#[derive(Debug, Eq, PartialEq, Clone)] #[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub enum AbstractTypeKind { pub enum AbstractTypeKind {
Void() = b'V', // void Void() = b'V', // void
Byte() = b'B', // signed byte Byte() = b'B', // signed byte
@ -702,7 +763,7 @@ impl Into<String> for &AbstractTypeKind {
} }
} }
#[derive(Debug, Eq, PartialEq, Clone)] #[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct AbstractTypeDescription { pub struct AbstractTypeDescription {
pub array_level: u8, pub array_level: u8,
pub kind: AbstractTypeKind, pub kind: AbstractTypeKind,
@ -725,7 +786,7 @@ impl Into<String> for &AbstractTypeDescription {
} }
impl AbstractTypeDescription { impl AbstractTypeDescription {
fn parse_first(s: &str) -> Result<(usize, Self), Error> { pub fn parse_first(s: &str) -> Result<(usize, Self), Error> {
let mut offset: usize = 0; let mut offset: usize = 0;
let arrays_parsed = s.trim_start_matches("["); let arrays_parsed = s.trim_start_matches("[");
let array_level = (s.len() - arrays_parsed.len()).try_into(); let array_level = (s.len() - arrays_parsed.len()).try_into();
@ -757,7 +818,7 @@ impl AbstractTypeDescription {
AbstractTypeKind::Classname(classname_string.to_string()) AbstractTypeKind::Classname(classname_string.to_string())
} }
_ => return Err(Error::BadFileError(format!("Invalid Type character: '{}' in string \"{}\"", type_char, s))), _ => return Err(Error::BadFileError(format!("Invalid Type character: '{}' in string '{}'", type_char, s))),
}; };
return Ok((offset, AbstractTypeDescription { array_level, kind })) return Ok((offset, AbstractTypeDescription { array_level, kind }))
@ -809,13 +870,14 @@ impl TryFrom<&String> for MethodDescriptor {
s.get(total_offset..).unwrap() s.get(total_offset..).unwrap()
.strip_prefix(")") .strip_prefix(")")
// unreachable?
.ok_or(Error::BadFileError(format!("Bad method descriptor")))?; .ok_or(Error::BadFileError(format!("Bad method descriptor")))?;
total_offset += 1; total_offset += 1;
let (offset, return_type) = AbstractTypeDescription::parse_first(s.get(total_offset..).unwrap())?; let (offset, return_type) = AbstractTypeDescription::parse_first(s.get(total_offset..).unwrap())?;
if offset != s.get(total_offset..).unwrap().len() { if offset != s.get(total_offset..).unwrap().len() {
return Err(Error::BadFileError(format!("Trailing characters in method descriptor string: \"{}\"", s))) return Err(Error::BadFileError(format!("Trailing characters in method descriptor string: '{}'", s)))
} }
Ok( Ok(
@ -942,11 +1004,11 @@ pub fn read_i32(reader: &mut dyn Read) -> Result<i32, std::io::Error> {
return Ok(i32::from_be_bytes(buffer)); return Ok(i32::from_be_bytes(buffer));
} }
pub fn read_u64(reader: &mut dyn Read) -> Result<u64, std::io::Error> { pub fn read_i64(reader: &mut dyn Read) -> Result<i64, std::io::Error> {
let high_bytes: u64 = read_u32(reader)?.into(); let mut buffer: [u8; 8] = [0; 8];
let low_bytes: u64 = read_u32(reader)?.into(); reader.read_exact(&mut buffer)?;
return Ok((high_bytes << 32) | low_bytes); return Ok(i64::from_be_bytes(buffer));
} }
pub fn read_u32(reader: &mut dyn Read) -> Result<u32, std::io::Error> { pub fn read_u32(reader: &mut dyn Read) -> Result<u32, std::io::Error> {

View file

@ -5,14 +5,25 @@ use std::error::Error as ErrorTrait;
use std::fs::File; use std::fs::File;
use std::path::PathBuf; use std::path::PathBuf;
use crate::classfile::JavaClassFile; use crate::classfile::{ JavaClassFile, AbstractTypeDescription, AbstractTypeKind };
use crate::classfile; use crate::classfile;
use crate::heap_area::ObjectReference;
use crate::iterators::CompatibleTypesIterator;
#[derive(Debug)] #[derive(Debug)]
pub struct ClassStore { pub struct ClassStore {
class_ids: HashMap<String, usize>, class_ids: HashMap<String, usize>,
classes: Vec<(bool, JavaClassFile)>, // was_init, class_file array_classes: HashMap<AbstractTypeDescription, ObjectReference>,
classes: Vec<ClassStoreEntry>,
class_path_fragments: Vec<PathBuf>, class_path_fragments: Vec<PathBuf>,
native_class_names: Vec<String>,
}
#[derive(Debug)]
struct ClassStoreEntry {
was_init: bool,
class_object: ObjectReference,
class_file: JavaClassFile,
} }
#[derive(Debug)] #[derive(Debug)]
@ -56,8 +67,10 @@ impl ClassStore {
ClassStore { ClassStore {
class_ids: HashMap::new(), class_ids: HashMap::new(),
array_classes: HashMap::new(),
classes: Vec::new(), classes: Vec::new(),
class_path_fragments: vec![current_dir_path], class_path_fragments: vec![current_dir_path],
native_class_names: Vec::new(),
} }
} }
@ -65,19 +78,34 @@ impl ClassStore {
return self.classes.len(); return self.classes.len();
} }
pub fn add_class(&mut self, class_file: JavaClassFile, was_init: bool) { pub fn add_class(&mut self, class_file: JavaClassFile, was_init: bool) -> Result<usize, Error> {
return self.classes.push((was_init, class_file)); let classname = class_file.get_classname()?;
self.class_ids.insert(classname.to_string(), self.classes.len());
let entry = ClassStoreEntry {
was_init,
class_object: ObjectReference::NULL,
class_file
};
self.classes.push(entry);
return Ok(self.classes.len() - 1);
}
pub fn add_native_class_name(&mut self, name: String) -> usize {
self.native_class_names.push(name);
return self.native_class_names.len() - 1;
}
pub fn get_native_class_name(&self, index: usize) -> &String {
return &self.native_class_names[index];
} }
pub fn load_class_from_file(&mut self, class_file_path: &PathBuf) -> Result<usize, Error> { pub fn load_class_from_file(&mut self, class_file_path: &PathBuf) -> Result<usize, Error> {
let mut file_reader = File::open(class_file_path)?; let mut file_reader = File::open(class_file_path)?;
let classfile = JavaClassFile::new(&mut file_reader)?; let class_file = JavaClassFile::new(&mut file_reader)?;
let classname = classfile.get_classname()?;
self.class_ids.insert(classname.to_string(), self.classes.len());
self.classes.push((false, classfile));
return Ok(self.classes.len() - 1); return self.add_class(class_file, false);
} }
pub fn load_class(&mut self, classname: &String) -> Result<usize, Error> { pub fn load_class(&mut self, classname: &String) -> Result<usize, Error> {
@ -96,6 +124,28 @@ impl ClassStore {
return Err(Error::ClassNotFoundError(format!("Could not find class '{}' in classpath", classname))); return Err(Error::ClassNotFoundError(format!("Could not find class '{}' in classpath", classname)));
} }
pub fn are_types_compatible(&self, my_type: &AbstractTypeDescription, other_type: &AbstractTypeDescription) -> bool {
if my_type == other_type { return true; }
if my_type.array_level != other_type.array_level { return false; }
if my_type.kind == other_type.kind { return true; }
let my_type_name = match &my_type.kind {
AbstractTypeKind::Classname(name) => name,
_ => unreachable!(),
};
let my_type_index = self.class_idx_from_name(&my_type_name).unwrap();
let other_type_name = match &other_type.kind {
AbstractTypeKind::Classname(name) => name,
_ => unreachable!(),
};
let compatible_count = CompatibleTypesIterator::new(my_type_index, self)
.filter(|type_name| *type_name == other_type_name)
.count();
compatible_count == 0
}
pub fn have_class(&self, classname: &String) -> bool { pub fn have_class(&self, classname: &String) -> bool {
return self.class_ids.contains_key(classname); return self.class_ids.contains_key(classname);
} }
@ -104,7 +154,7 @@ impl ClassStore {
let class_id = self.class_ids.get(classname); let class_id = self.class_ids.get(classname);
return match class_id { return match class_id {
Some(id) => Ok((&self.classes[*id].1, *id)), Some(id) => Ok((&self.classes[*id].class_file, *id)),
None => Err(Error::ClassNotFoundError(format!("Could not locate class '{}'", classname))), None => Err(Error::ClassNotFoundError(format!("Could not locate class '{}'", classname))),
} }
} }
@ -114,13 +164,13 @@ impl ClassStore {
return Ok(self.get_class(classname)?); return Ok(self.get_class(classname)?);
} else { } else {
let class_idx = self.load_class(classname)?; let class_idx = self.load_class(classname)?;
return Ok((&self.classes[class_idx].1, class_idx)); return Ok((&self.classes[class_idx].class_file, class_idx));
} }
} }
pub fn class_file_from_idx(&self, idx: usize) -> Option<&JavaClassFile> { pub fn class_file_from_idx(&self, idx: usize) -> Option<&JavaClassFile> {
return match self.classes.get(idx) { return match self.classes.get(idx) {
Some((_was_init, class_file)) => Some(class_file), Some(entry) => Some(&entry.class_file),
None => None, None => None,
} }
} }
@ -130,15 +180,29 @@ impl ClassStore {
} }
pub fn was_init(&self, classname: &String) -> Option<bool> { pub fn was_init(&self, classname: &String) -> Option<bool> {
let (was_init, _) = self.classes.get(self.class_idx_from_name(classname).unwrap()).unwrap(); let entry = self.classes.get(self.class_idx_from_name(classname).unwrap()).unwrap();
return Some(*was_init); return Some(entry.was_init);
} }
pub fn set_init(&mut self, class_idx: usize, was_init: bool) { pub fn set_init(&mut self, class_idx: usize, was_init: bool) {
let pair = self.classes.get_mut(class_idx).unwrap(); let entry = self.classes.get_mut(class_idx).unwrap();
pair.0 = was_init; entry.was_init = was_init;
}
pub fn put_array_class_ref(&mut self, type_desc: AbstractTypeDescription, class_ref: ObjectReference) {
self.array_classes.insert(type_desc, class_ref);
}
pub fn set_class_objectref_by_index(&mut self, index: usize, class_objref: ObjectReference) {
self.classes.get_mut(index).unwrap().class_object = class_objref;
}
pub fn get_class_objectref_from_index(&self, index: usize) -> ObjectReference {
self.classes[index].class_object
}
pub fn get_array_class_ref(&self, type_desc: &AbstractTypeDescription) -> Option<ObjectReference> {
return self.array_classes.get(type_desc).copied();
} }
} }

View file

@ -1,7 +1,7 @@
use std::io::Read; use std::io::Read;
use crate::classfile::Error; use crate::classfile::Error;
use crate::classfile::{read_u16, read_u8, read_f32, read_f64, read_u64, read_i32}; use crate::classfile::{read_u16, read_u8, read_f32, read_f64, read_i64, read_i32};
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct ConstantClassInfo { pub struct ConstantClassInfo {
@ -43,7 +43,7 @@ pub struct ConstantFloatInfo {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct ConstantLongInfo { pub struct ConstantLongInfo {
pub value: u64, pub value: i64,
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -176,7 +176,7 @@ impl ConstantPoolInfo {
5 => { 5 => {
ConstantPoolInfo::Long( ConstantPoolInfo::Long(
ConstantLongInfo { ConstantLongInfo {
value: read_u64(reader)? value: read_i64(reader)?
} }
) )
} }

View file

@ -5,6 +5,7 @@ use core::fmt::Debug as DebugTrait;
use crate::accessmasks::FieldAccessFlag; use crate::accessmasks::FieldAccessFlag;
use crate::classfile::{ JavaClassFile, AbstractTypeDescription, MethodInfo, AbstractTypeKind }; use crate::classfile::{ JavaClassFile, AbstractTypeDescription, MethodInfo, AbstractTypeKind };
use crate::classstore::ClassStore; use crate::classstore::ClassStore;
use crate::iterators::ClassFieldIterator;
use crate::jvm::Error; use crate::jvm::Error;
#[derive(Debug)] #[derive(Debug)]
@ -32,66 +33,153 @@ impl HeapArea {
return object_ref; return object_ref;
} }
pub fn make_empty_array(&mut self, class_store: &ClassStore, element_type_desc: AbstractTypeDescription, capacity: usize) -> ObjectReference {
let (array_ref, array_size) = self.object_area.make_empty_array(class_store, element_type_desc, capacity);
self.memory_used += array_size;
return array_ref;
}
pub fn make_array(&mut self, class_store: &ClassStore, elements: Box<[ObjectReference]>) -> ObjectReference {
let (array_ref, array_size) = self.object_area.make_array(class_store, elements);
self.memory_used += array_size;
return array_ref;
}
pub fn make_static(&mut self, class: &JavaClassFile, class_index: usize) { pub fn make_static(&mut self, class: &JavaClassFile, class_index: usize) {
self.memory_used += self.static_area.make(class, class_index); self.memory_used += self.static_area.make(class, class_index);
} }
pub fn byte_array_from_rust_string(&mut self, string: &str, class_store: &ClassStore) -> ObjectReference {
let mut byte_obj_vec = Vec::<ObjectReference>::with_capacity(string.len());
for byte in string.as_bytes() {
// TODO: Take bytes from ByteCache
let byte_class_idx = class_store.class_idx_from_name(&"java/lang/Byte".to_string()).unwrap();
let byte_obj = self.make_object(&class_store, byte_class_idx);
self.object_area.set_object_field(byte_obj, "value", FieldValue::Byte(*byte), byte_class_idx, &class_store).unwrap();
byte_obj_vec.push(byte_obj);
}
let byte_array = self.make_array(&class_store, byte_obj_vec.into_boxed_slice());
byte_array
}
} }
pub type ObjectReference=u32; #[derive(Debug, Clone, Copy)]
pub struct ObjectReference(u32);
const DEFAULT_COMPARTMENT_CAPACITY: usize = u16::MAX as usize;
impl ObjectReference {
pub const NULL: ObjectReference = ObjectReference(0);
}
const DEFAULT_COMPARTMENT_CAPACITY: u32 = u16::MAX as u32;
const INVALID_FIRST_OBJECT: usize = u16::MAX as usize; const INVALID_FIRST_OBJECT: usize = u16::MAX as usize;
const INVALID_NEXT_COMPARTMENT: usize = 0; const INVALID_NEXT_COMPARTMENT: usize = 0;
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ObjectArea { pub struct ObjectArea {
memory_used: usize,
compartments: Vec<ObjectCompartment>, compartments: Vec<ObjectCompartment>,
first_free_compartment: usize, first_free_compartment: usize,
} }
impl ObjectArea { impl ObjectArea {
pub fn make(&mut self, class_store: &ClassStore, target_class_index: usize) -> (ObjectReference, usize) { fn make_empty_array(&mut self, class_store: &ClassStore, element_type_desc: AbstractTypeDescription, capacity: usize) -> (ObjectReference, usize) {
let mut fields = Vec::new(); //
let mut current_class_index; // make new type desc
let mut next_class_index = target_class_index; let array_type_desc = AbstractTypeDescription {
array_level: 1 + element_type_desc.array_level,
kind: element_type_desc.kind,
};
let mut object_size = 0; let array_class_ref = class_store.get_array_class_ref(&array_type_desc).unwrap();
while next_class_index != class_store.class_count() { let array_object = HeapArray {
current_class_index = next_class_index; class_ref: array_class_ref,
content: vec![ObjectReference::NULL; capacity].into_boxed_slice(),
};
let class = class_store.class_file_from_idx(current_class_index).unwrap(); let array_size = std::mem::size_of::<HeapArray>() + std::mem::size_of::<ObjectReference>() * array_object.content.len();
for field in &class.fields { let array_object_ref = self.store_entry(CompartmentEntry::Array(array_object));
let new_field = ObjectField {
value: FieldValue::default_for(&field.descriptor)
};
object_size += std::mem::size_of_val(&new_field);
fields.push(new_field); self.memory_used += array_size;
}
if class.has_super_class() { (array_object_ref, array_size)
next_class_index = class_store.class_idx_from_name(class.get_super_class_name().unwrap()).unwrap(); }
} else {
next_class_index = class_store.class_count(); fn make_array(&mut self, class_store: &ClassStore, elements: Box<[ObjectReference]>) -> (ObjectReference, usize) {
} assert!(elements.len() != 0);
let array_element_class_name = self.get_reference_native_class_name(elements[0], class_store);
let array_element_type_desc = AbstractTypeDescription::parse_first(array_element_class_name).unwrap().1;
let (array_object_ref, array_size) = self.make_empty_array(class_store, array_element_type_desc, elements.len());
for (index, element) in elements.iter().enumerate() {
self.set_array_element(array_object_ref, index, *element);
} }
return (array_object_ref, array_size);
}
pub fn make(&mut self, class_store: &ClassStore, target_class_index: usize) -> (ObjectReference, usize) {
let fields: Vec<_> = ClassFieldIterator::new(target_class_index, class_store)
.filter(|f| ! (f.access_flags & FieldAccessFlag::Static))
.map(|f| ObjectField { value: FieldValue::default_for(&f.descriptor) })
.collect();
let object_size = std::mem::size_of::<HeapObject>() + std::mem::size_of::<ObjectField>() * fields.len();
let new_object = HeapObject { let new_object = HeapObject {
class_index: target_class_index, class_index: target_class_index,
fields: fields.into_boxed_slice(), fields: fields.into_boxed_slice(),
}; };
object_size += std::mem::size_of_val(&new_object);
object_size += std::mem::size_of_val(&new_object.fields);
let object_ref = self.store_object(new_object); let object_ref = self.store_entry(CompartmentEntry::Object(new_object));
self.memory_used += object_size;
return (object_ref, object_size); return (object_ref, object_size);
} }
fn store_object(&mut self, object: HeapObject) -> ObjectReference { pub fn get_reference_native_class_name<'a>(&self, reference: ObjectReference, class_store: &'a ClassStore) -> &'a String {
let class_ref = self.get_reference_class_ref(reference, class_store);
let class_data_ref = match self.get_object_field(class_ref, "classData", self.get_object_class_index(class_ref), class_store).unwrap() {
FieldValue::Reference(r) => r,
_ => unreachable!(),
};
let native_name_index = match self.get_object_field(class_data_ref, "native_class_descriptor_index", self.get_object_class_index(class_data_ref), class_store).unwrap() {
FieldValue::Int(i) => i,
_ => unreachable!(),
};
return class_store.get_native_class_name(native_name_index as usize);
}
fn get_object_class_index(&self, reference: ObjectReference) -> usize {
match self.get_object(reference) {
CompartmentEntry::Object(o) => o.class_index,
_ => unreachable!(),
}
}
fn get_reference_class_ref(&self, reference: ObjectReference, class_store: &ClassStore) -> ObjectReference {
match self.get_object(reference) {
CompartmentEntry::Object(o) => class_store.get_class_objectref_from_index(o.class_index),
CompartmentEntry::Array(a) => a.class_ref,
_ => unreachable!(),
}
}
fn store_entry(&mut self, object: CompartmentEntry) -> ObjectReference {
if self.first_free_compartment == 0 { if self.first_free_compartment == 0 {
self.compartments.push(ObjectCompartment::new(INVALID_NEXT_COMPARTMENT)); self.compartments.push(ObjectCompartment::new(INVALID_NEXT_COMPARTMENT));
self.first_free_compartment = self.compartments.len(); self.first_free_compartment = self.compartments.len();
@ -103,12 +191,116 @@ impl ObjectArea {
self.first_free_compartment = self.compartments[compartment_index].next_free_compartment; self.first_free_compartment = self.compartments[compartment_index].next_free_compartment;
} }
return object_index + (DEFAULT_COMPARTMENT_CAPACITY as u32 * (compartment_index+1) as u32); return ObjectReference(object_index + (DEFAULT_COMPARTMENT_CAPACITY * (compartment_index as u32 + 1)));
}
fn get_object(&self, reference: ObjectReference) -> &CompartmentEntry {
let index = reference.0;
let compartment_index: u32 = (index / DEFAULT_COMPARTMENT_CAPACITY) - 1;
let object_index: u32 = index % DEFAULT_COMPARTMENT_CAPACITY;
let compartment = self.compartments.get(compartment_index as usize).unwrap();
let object = compartment.objects.get(object_index as usize).unwrap();
return object;
}
fn get_object_mut(&mut self, reference: ObjectReference) -> &mut CompartmentEntry {
let index = reference.0;
let compartment_index: u32 = (index / DEFAULT_COMPARTMENT_CAPACITY) - 1;
let object_index: u32 = index % DEFAULT_COMPARTMENT_CAPACITY;
let compartment = self.compartments.get_mut(compartment_index as usize).unwrap();
let object = compartment.objects.get_mut(object_index as usize).unwrap();
return object;
}
pub fn get_object_field(&self, reference: ObjectReference, field_name: &str, accessing_class_idx: usize, class_store: &ClassStore) -> Result<FieldValue, Error> {
// TODO: Check access rights
let object = match self.get_object(reference) {
CompartmentEntry::Object(o) => o,
_ => unreachable!(),
};
let field_option = ClassFieldIterator::new(object.class_index, class_store)
.filter(|f| ! (f.access_flags & FieldAccessFlag::Static))
.filter(|f| f.name == field_name)
.enumerate()
.next();
match field_option {
Some((field_index, _)) => {
Ok(object.fields[field_index].value)
},
None => Err(
Error::RunTimeError(
format!(
"Trying to get field '{}' on instance of '{}' but there is no such field",
field_name,
class_store.class_file_from_idx(object.class_index).unwrap().get_classname().unwrap()
)
)
)
}
}
pub fn set_array_element(&mut self, array_reference: ObjectReference, index: usize, element: ObjectReference) {
let array = match self.get_object_mut(array_reference) {
CompartmentEntry::Array(a) => a,
_ => unreachable!(),
};
let array_element = array.content.get_mut(index).unwrap();
*array_element = element;
}
pub fn set_object_field(&mut self, reference: ObjectReference, field_name: &str, value: FieldValue, accessing_class_idx: usize, class_store: &ClassStore) -> Result<(), Error> {
// TODO: Check access rights
let object = match self.get_object_mut(reference) {
CompartmentEntry::Object(o) => o,
_ => unreachable!(),
};
let field_option = ClassFieldIterator::new(object.class_index, class_store)
.filter(|f| ! (f.access_flags & FieldAccessFlag::Static))
.filter(|f| f.name == field_name)
.enumerate()
.next();
match field_option {
Some((field_index, field_info)) => {
let object_field = object.fields.get_mut(field_index).unwrap();
if std::mem::discriminant(&value) == std::mem::discriminant(&object_field.value) {
// TODO: Check reference types
object_field.value = value;
Ok(())
} else {
Err(
Error::RunTimeError(
format!(
"Trying set value '{:?}' on a field with descriptor '{:?}' in instance of '{}'",
value,
field_info.descriptor,
class_store.class_file_from_idx(object.class_index).unwrap().get_classname().unwrap()
)
)
)
}
},
None => Err(Error::RunTimeError(format!(
"Trying to set field '{}' on instance of class '{}' but there is no such field",
field_name,
class_store.class_file_from_idx(object.class_index).unwrap().get_classname().unwrap()
)))
}
} }
} }
pub struct ObjectCompartment { pub struct ObjectCompartment {
objects: Box<[ObjectCompartmentEntry]>, objects: Box<[CompartmentEntry]>,
first_free: usize, first_free: usize,
reserved_count: usize, reserved_count: usize,
next_free_compartment: usize, next_free_compartment: usize,
@ -116,11 +308,11 @@ pub struct ObjectCompartment {
impl ObjectCompartment { impl ObjectCompartment {
fn new(next_free: usize) -> Self { fn new(next_free: usize) -> Self {
let mut os = Vec::with_capacity(DEFAULT_COMPARTMENT_CAPACITY); let mut os = Vec::with_capacity(DEFAULT_COMPARTMENT_CAPACITY as usize);
for i in 0..DEFAULT_COMPARTMENT_CAPACITY-1 { for i in 0..DEFAULT_COMPARTMENT_CAPACITY-1 {
os.push(ObjectCompartmentEntry::EmptyNext(i+1)); os.push(CompartmentEntry::EmptyNext(i as usize + 1));
} }
os.push(ObjectCompartmentEntry::EmptyTail()); os.push(CompartmentEntry::EmptyTail());
ObjectCompartment { ObjectCompartment {
objects: os.into_boxed_slice(), objects: os.into_boxed_slice(),
@ -130,22 +322,24 @@ impl ObjectCompartment {
} }
} }
fn store(&mut self, object: HeapObject) -> ObjectReference { fn store(&mut self, object: CompartmentEntry) -> u32 {
let store_slot = self.objects.get(self.first_free).unwrap(); let store_slot = self.objects.get(self.first_free).unwrap();
let compartment_index = self.first_free; let compartment_index = self.first_free;
match store_slot { match store_slot {
ObjectCompartmentEntry::Valid(_) => unreachable!(), CompartmentEntry::EmptyNext(next) => {
ObjectCompartmentEntry::EmptyNext(next) => {
self.first_free = *next; self.first_free = *next;
}, },
ObjectCompartmentEntry::EmptyTail() => { CompartmentEntry::EmptyTail() => {
// TODO: Maybe change to something else // TODO: Maybe change to something else
self.first_free = INVALID_FIRST_OBJECT; self.first_free = INVALID_FIRST_OBJECT;
}, },
CompartmentEntry::Object(_) => unreachable!(),
CompartmentEntry::Array(_) => unreachable!(),
} }
*self.objects.get_mut(compartment_index).unwrap() = ObjectCompartmentEntry::Valid(object); *self.objects.get_mut(compartment_index).unwrap() = object;
self.reserved_count += 1; self.reserved_count += 1;
return compartment_index as u32; return compartment_index as u32;
@ -161,18 +355,24 @@ impl DebugTrait for ObjectCompartment {
.field("objects", &self.objects .field("objects", &self.objects
.iter() .iter()
.enumerate() .enumerate()
.filter(|e| match e { (_, ObjectCompartmentEntry::Valid(_)) => true, _ => false}) .filter(|e| match e { (_, CompartmentEntry::EmptyNext(_)) | (_, CompartmentEntry::EmptyTail()) => false, _ => true})
.map(|e| match e { (i, ObjectCompartmentEntry::Valid(o)) => (i, o), _ => unreachable!()}) .collect::<Vec<_>>()
.collect::<Vec<(usize, &HeapObject)>>()
).finish() ).finish()
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub enum ObjectCompartmentEntry { pub enum CompartmentEntry {
Valid(HeapObject), Object(HeapObject),
Array(HeapArray),
EmptyNext(usize), EmptyNext(usize),
EmptyTail(), // next empty value EmptyTail(), // last empty value
}
#[derive(Debug)]
pub struct HeapArray {
class_ref: ObjectReference,
content: Box<[ObjectReference]>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -183,12 +383,14 @@ pub struct HeapObject {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct StaticArea { pub struct StaticArea {
memory_used: usize,
static_objects: HashMap<String, StaticObject>, static_objects: HashMap<String, StaticObject>,
} }
impl StaticArea { impl StaticArea {
pub fn set(&mut self, class_name: &String, field_name: &String, field_value: FieldValue) -> Result<(), Error> { pub fn set(&mut self, class_name: &String, field_name: &String, field_value: FieldValue) -> Result<(), Error> {
// TODO: Access permission checking
let static_object = match self.static_objects.get_mut(class_name) { let static_object = match self.static_objects.get_mut(class_name) {
Some(o) => o, Some(o) => o,
None => return Err(Error::RunTimeError(format!("Trying to set '{}.{}={:?}' but there is no such static object.", class_name, field_name, field_value))), None => return Err(Error::RunTimeError(format!("Trying to set '{}.{}={:?}' but there is no such static object.", class_name, field_name, field_value))),
@ -234,7 +436,11 @@ impl StaticArea {
let _ = self.static_objects.insert(class.get_classname().unwrap().to_string(), new_object); let _ = self.static_objects.insert(class.get_classname().unwrap().to_string(), new_object);
return object_memory_size + field_array_size + fields_cumulative_size + method_array_size; let total_object_size = object_memory_size + field_array_size + fields_cumulative_size + method_array_size;
self.memory_used += total_object_size;
return total_object_size;
} }
} }
@ -268,7 +474,7 @@ pub struct ObjectField {
pub value: FieldValue, pub value: FieldValue,
} }
#[derive(Debug)] #[derive(Debug, Clone, Copy)]
pub enum FieldValue { pub enum FieldValue {
Boolean(bool), Boolean(bool),
Byte(u8), Byte(u8),
@ -294,7 +500,7 @@ impl FieldValue {
fn default_for(t: &AbstractTypeDescription) -> Self { fn default_for(t: &AbstractTypeDescription) -> Self {
if t.array_level != 0 { if t.array_level != 0 {
return Self::Reference(0); return Self::Reference(ObjectReference::NULL);
} }
match &t.kind { match &t.kind {
AbstractTypeKind::Void() => unreachable!(), AbstractTypeKind::Void() => unreachable!(),
@ -304,7 +510,7 @@ impl FieldValue {
AbstractTypeKind::Float() => Self::Float(0.0), AbstractTypeKind::Float() => Self::Float(0.0),
AbstractTypeKind::Int() => Self::Int(0), AbstractTypeKind::Int() => Self::Int(0),
AbstractTypeKind::Long() => Self::Long(0), AbstractTypeKind::Long() => Self::Long(0),
AbstractTypeKind::Classname(_) => Self::Reference(0), AbstractTypeKind::Classname(_) => Self::Reference(ObjectReference::NULL),
AbstractTypeKind::Short() => Self::Short(0), AbstractTypeKind::Short() => Self::Short(0),
AbstractTypeKind::Boolean() => Self::Boolean(true), AbstractTypeKind::Boolean() => Self::Boolean(true),
} }

130
src/iterators.rs Normal file
View file

@ -0,0 +1,130 @@
use crate::classstore::ClassStore;
use crate::classfile::{ FieldInfo, MethodInfo };
// Iterator over all the fields of a class object including superclass fields
pub struct ClassFieldIterator<'i> {
field_index: usize,
class_index: usize,
class_store: &'i ClassStore,
}
impl <'i>ClassFieldIterator<'i> {
pub fn new(class_index: usize, class_store: &'i ClassStore) -> Self {
ClassFieldIterator {
field_index: 0,
class_index,
class_store,
}
}
}
impl <'i> Iterator for ClassFieldIterator<'i>{
type Item = &'i FieldInfo;
fn next(&mut self) -> Option<Self::Item> {
let mut class_file = self.class_store.class_file_from_idx(self.class_index).unwrap();
while class_file.has_super_class() && class_file.fields.len() == self.field_index {
let super_class_name = class_file.get_super_class_name().unwrap();
let (super_class_file, super_class_index) = self.class_store.get_class(super_class_name).unwrap();
class_file = super_class_file;
self.class_index = super_class_index;
self.field_index = 0;
}
if class_file.fields.len() == self.field_index {
return None;
} else {
let field_info = &class_file.fields[self.field_index];
self.field_index += 1;
return Some(field_info);
}
}
}
pub struct CompatibleTypesIterator<'i> {
class_stack: Vec<(usize, usize)>, // class_index, interface_index
class_store: &'i ClassStore,
}
impl <'i>CompatibleTypesIterator<'i> {
pub fn new(class_index: usize, class_store: &'i ClassStore) -> Self {
CompatibleTypesIterator {
class_stack: vec![(class_index, 0)],
class_store,
}
}
}
impl <'i> Iterator for CompatibleTypesIterator<'i>{
type Item = &'i String; // class index, method index, method info
fn next(&mut self) -> Option<Self::Item> {
let (class_index, interface_index) = match self.class_stack.pop() {
None => return None,
Some(a) => a,
};
let class_file = self.class_store.class_file_from_idx(class_index).unwrap();
if class_file.interfaces.len() == interface_index {
if class_file.has_super_class() {
let super_class_index = self.class_store.class_idx_from_name(class_file.get_super_class_name().unwrap()).unwrap();
self.class_stack.push((super_class_index, 0));
Some(class_file.get_super_class_name().unwrap())
} else {
None
}
} else {
let interface_name = class_file.gather_class(class_file.interfaces[interface_index]).unwrap();
let interface_index = self.class_store.class_idx_from_name(interface_name).unwrap();
self.class_stack.push((class_index, interface_index + 1));
self.class_stack.push((interface_index, 0));
Some(interface_name)
}
}
}
pub struct ClassMethodIterator<'i> {
method_index: usize,
class_index: usize,
class_store: &'i ClassStore,
}
impl <'i>ClassMethodIterator<'i> {
pub fn new(class_index: usize, class_store: &'i ClassStore) -> Self {
ClassMethodIterator {
method_index: 0,
class_index,
class_store,
}
}
}
impl <'i> Iterator for ClassMethodIterator<'i>{
type Item = (usize, usize, &'i MethodInfo); // class index, method index, method info
fn next(&mut self) -> Option<Self::Item> {
let mut class_file = self.class_store.class_file_from_idx(self.class_index).unwrap();
while class_file.has_super_class() && class_file.methods.len() == self.method_index {
let super_class_name = class_file.get_super_class_name().unwrap();
let (super_class_file, super_class_index) = self.class_store.get_class(super_class_name).unwrap();
class_file = super_class_file;
self.class_index = super_class_index;
self.method_index = 0;
}
if class_file.methods.len() == self.method_index {
return None;
} else {
let method_info = &class_file.methods[self.method_index];
self.method_index += 1;
return Some((self.class_index, self.method_index - 1, method_info));
}
}
}

View file

@ -3,14 +3,15 @@ use core::fmt::{Display, Formatter};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::error::Error as ErrorTrait; use std::error::Error as ErrorTrait;
use crate::accessmasks::{ ClassAccessFlagMask, ClassAccessFlag, MethodAccessFlagMask, MethodAccessFlag, FieldAccessFlag }; use crate::accessmasks::{ ClassAccessFlagMask, ClassAccessFlag, MethodAccessFlagMask, MethodAccessFlag, FieldAccessFlag, FieldAccessFlagMask };
use crate::bytecode::{ Bytecode, Instruction }; use crate::bytecode::{ Bytecode, Instruction };
use crate::classfile; use crate::classfile;
use crate::classfile::{ JavaClassFile, MethodInfo, MethodDescriptor, AbstractTypeDescription, AbstractTypeKind, AttributeInfo, AttributeData, CodeAttributeData, ConstantValueAttributeData }; use crate::classfile::{ JavaClassFile, FieldInfo, MethodInfo, MethodDescriptor, AbstractTypeDescription, AbstractTypeKind, AttributeInfo, AttributeData, CodeAttributeData, ConstantValueAttributeData };
use crate::classstore; use crate::classstore;
use crate::classstore::ClassStore; use crate::classstore::ClassStore;
use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info, ConstantMethodRefInfo, ConstantNameAndTypeInfo}; use crate::constantpool::{ ConstantPoolInfo, ConstantClassInfo, ConstantUtf8Info, ConstantMethodRefInfo, ConstantNameAndTypeInfo};
use crate::heap_area::{ HeapArea, FieldValue, ObjectReference }; use crate::heap_area::{ HeapArea, FieldValue, ObjectReference };
use crate::iterators::{ ClassMethodIterator, ClassFieldIterator, CompatibleTypesIterator };
use crate::stackframe; use crate::stackframe;
use crate::stackframe::{ StackFrame, StackValue, OperandStack }; use crate::stackframe::{ StackFrame, StackValue, OperandStack };
@ -63,7 +64,124 @@ impl JVM {
} }
} }
pub fn entrypoint(&mut self, class_name: &String, method_name: &String, arguments: &[StackValue]) -> Result<(), Error> { fn class_native_class_data() -> JavaClassFile {
JavaClassFile {
minor_version: 0,
major_version: 0,
constant_pool: Box::new([
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 2 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "::NativeClassData".to_string() }),
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 4 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "java/lang/Object".to_string() }),
]
),
access_flags: ClassAccessFlagMask { mask: ClassAccessFlag::Super.discriminant() },
this_class: 1,
super_class: 3,
interfaces: Box::new([]),
fields: Box::new([
FieldInfo {
access_flags: FieldAccessFlagMask {
mask: FieldAccessFlag::Public.discriminant()
},
name: "native_class_descriptor_index".to_string(),
descriptor: AbstractTypeDescription {
array_level: 0,
kind: AbstractTypeKind::Int(),
},
attributes: Box::new([]),
},
]),
methods: Box::new([]),
attributes: Box::new([]),
}
}
fn make_class_class(&mut self, class_name: &str) {
let class_object = self.heap_area.make_object(&self.class_store, self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap());
let class_data_object = self.heap_area.make_object(&self.class_store, self.class_store.class_idx_from_name(&"::NativeClassData".to_string()).unwrap());
self.heap_area.object_area.set_object_field(
class_object,
"classData",
FieldValue::Reference(class_data_object),
self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap(),
&self.class_store,
).unwrap();
// set native name index on class data
self.heap_area.object_area.set_object_field(
class_data_object,
"native_class_descriptor_index",
FieldValue::Int(self.class_store.add_native_class_name(class_name.to_string()) as i32),
self.class_store.class_idx_from_name(&"::NativeClassData".to_string()).unwrap(),
&self.class_store,
).unwrap();
let parsed_class_name = match AbstractTypeDescription::parse_first(class_name).unwrap() {
(_, desc) => {
assert!(desc.array_level == 0);
match desc.kind {
AbstractTypeKind::Classname(name) => name,
_ => unreachable!(),
}
}
};
self.class_store.set_class_objectref_by_index(self.class_store.class_idx_from_name(&parsed_class_name).unwrap(), class_object);
}
fn make_array_class(&mut self, element_descriptor_string: &str) {
let (chars_consumed, element_descriptor) = AbstractTypeDescription::parse_first(element_descriptor_string).unwrap();
assert!(chars_consumed == element_descriptor_string.len());
let element_class_ref = if element_descriptor.array_level == 0 {
match element_descriptor.kind {
AbstractTypeKind::Classname(ref name) => {
self.class_store.get_class_objectref_from_index(
self.class_store.class_idx_from_name(&name).unwrap()
)
}
_ => unreachable!(),
}
} else {
self.class_store.get_array_class_ref(&element_descriptor).unwrap()
};
let array_class_object = self.heap_area.make_object(&self.class_store, 6);
let array_class_data_object = self.heap_area.make_object(&self.class_store, 1);
let array_type_description = AbstractTypeDescription {
array_level: 1 + element_descriptor.array_level,
kind: element_descriptor.kind,
};
// set component type
self.heap_area.object_area.set_object_field(
array_class_object,
"componentType",
FieldValue::Reference(element_class_ref),
self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap(),
&self.class_store,
).unwrap();
// set classdata object
self.heap_area.object_area.set_object_field(
array_class_object,
"classData",
FieldValue::Reference(array_class_data_object),
self.class_store.class_idx_from_name(&"java/lang/Class".to_string()).unwrap(),
&self.class_store,
).unwrap();
// set native name index on class data
self.heap_area.object_area.set_object_field(
array_class_data_object,
"native_class_descriptor_index",
FieldValue::Int(self.class_store.add_native_class_name((&array_type_description).into()) as i32),
self.class_store.class_idx_from_name(&"::NativeClassData".to_string()).unwrap(),
&self.class_store,
).unwrap();
self.class_store.put_array_class_ref(
array_type_description,
array_class_object,
);
}
pub fn entrypoint(&mut self, class_name: &String, method_name: &String, arguments: &[&str]) -> Result<(), Error> {
let entry_class = JavaClassFile { let entry_class = JavaClassFile {
minor_version: 0, minor_version: 0,
major_version: 0, major_version: 0,
@ -72,11 +190,17 @@ impl JVM {
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "::EntryPoint".to_string() }), ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "::EntryPoint".to_string() }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "Code".to_string() }), ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "Code".to_string() }),
ConstantPoolInfo::MethodRef(ConstantMethodRefInfo { class_index: 5, name_and_type_index: 6}), ConstantPoolInfo::MethodRef(ConstantMethodRefInfo { class_index: 5, name_and_type_index: 6}),
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 7 }), ConstantPoolInfo::Class(ConstantClassInfo { name_index: 7 }), // 5
ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 8, descriptor_index: 9 }), ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 8, descriptor_index: 9 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: class_name.to_string() }), ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: class_name.to_string() }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: method_name.to_string() }), ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: method_name.to_string() }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "()V".to_string() }), ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "()V".to_string() }),
ConstantPoolInfo::MethodRef(ConstantMethodRefInfo { class_index: 11, name_and_type_index: 13}), // 10
ConstantPoolInfo::Class(ConstantClassInfo { name_index: 12 } ),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "java/lang/String".to_string() }),
ConstantPoolInfo::NameAndType(ConstantNameAndTypeInfo { name_index: 14, descriptor_index: 15 }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "<init>".to_string() }),
ConstantPoolInfo::Utf8(ConstantUtf8Info { utf8: "([B)V".to_string() }), // 15
] ]
), ),
access_flags: ClassAccessFlagMask { mask: ClassAccessFlag::Super.discriminant() }, access_flags: ClassAccessFlagMask { mask: ClassAccessFlag::Super.discriminant() },
@ -104,7 +228,7 @@ impl JVM {
data: AttributeData::Code( data: AttributeData::Code(
CodeAttributeData { CodeAttributeData {
max_stack: 0, max_stack: 0,
max_locals: 0, max_locals: 1,
code: Bytecode { code: Bytecode {
bytes: Box::new([ bytes: Box::new([
0xB8_u8.to_be(), // invokestatic 0xB8_u8.to_be(), // invokestatic
@ -118,26 +242,92 @@ impl JVM {
) )
} }
]) ])
} },
MethodInfo {
access_flags: MethodAccessFlagMask {
mask: MethodAccessFlag::Public.discriminant() | MethodAccessFlag::Static.discriminant()
},
name: "make_arg_string".to_string(),
descriptor: MethodDescriptor {
argument_types: Box::new([]),
return_type: AbstractTypeDescription {
array_level: 0,
kind: AbstractTypeKind::Void(),
}
},
code_attribute_index: 0,
attributes: Box::new([
AttributeInfo {
attribute_name_index: 3,
data: AttributeData::Code(
CodeAttributeData {
max_stack: 3,
max_locals: 3,
code: Bytecode {
bytes: Box::new([
0xBB_u8.to_be(), // new
11_u16.to_be_bytes()[0], // index 11 into the constant
11_u16.to_be_bytes()[1], // pool
0x59_u8.to_be(), // dup
0x2A_u8.to_be(), // aload 0
0xB7_u8.to_be(), // invokespecial
10_u16.to_be_bytes()[0], // index 10 into the constant
10_u16.to_be_bytes()[1], // pool
])
},
exception_table: Box::new([]),
attributes: Box::new([]),
}
)
}
])
}
]), ]),
attributes: Box::new([]), attributes: Box::new([]),
}; };
let entry_frame = StackFrame::new(&entry_class, 0, 0, &[]);
self.class_store.add_class(entry_class, true)?; // 0
self.class_store.add_class(JVM::class_native_class_data(), true)?; // 1
self.class_store.load_class(&"java/lang/Object".to_string())?; // 2
self.class_store.load_class(&"java/lang/Number".to_string())?; // 3
self.class_store.load_class(&"java/lang/Byte".to_string())?; // 4
self.class_store.load_class(&"java/lang/String".to_string())?; // 5
self.class_store.load_class(&"java/lang/Class".to_string())?; // 6
self.stack_frames.push( self.make_class_class("Ljava/lang/Byte;");
StackFrame::new(&entry_class, 0, 0, arguments), self.make_class_class("Ljava/lang/String;");
); self.make_array_class("Ljava/lang/Byte;");
self.make_array_class("Ljava/lang/String;");
self.class_store.add_class(entry_class, true); let argument_array = self.heap_area.make_empty_array(&self.class_store, AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/String".into()) }, arguments.len());
self.class_store.load_class(&"java/lang/Class".to_string())?; for (arg_index, argument) in arguments.iter().enumerate() {
self.class_store.load_class(&"java/lang/Object".to_string())?; let byte_array = self.heap_area.byte_array_from_rust_string(argument, &self.class_store);
self.stack_frames.push(
StackFrame::new(
self.class_store.get_class(&"::EntryPoint".to_string()).unwrap().0,
self.class_store.class_idx_from_name(&"::EntryPoint".to_string()).unwrap(),
1, // method index
&[StackValue::Reference(byte_array), StackValue::Reference(argument_array), StackValue::Int(arg_index as i32)],
)
);
self.new_object(&"java/lang/Class".to_string())?; self.run()?;
}
// push the entry frame which will call main
self.stack_frames.push(entry_frame);
Ok(()) Ok(())
} }
pub fn run(&mut self) -> Result<(), Error> { pub fn run(&mut self) -> Result<(), Error> {
while self.stack_frames.len() != 0 { while self.stack_frames.len() != 0 {
println!("Enter bytecode loop:");
let jvm_op = self.bytecode_loop()?; let jvm_op = self.bytecode_loop()?;
match jvm_op { match jvm_op {
JVMCallbackOperation::PopFrame() => { JVMCallbackOperation::PopFrame() => {
@ -167,6 +357,10 @@ impl JVM {
JVMCallbackOperation::InitClass(name) => { JVMCallbackOperation::InitClass(name) => {
// TODO: throw exception // TODO: throw exception
self.init_class_hierarchy(&name)?; self.init_class_hierarchy(&name)?;
},
JVMCallbackOperation::MakeArrayClass(component_descriptor_string) => {
self.make_array_class(&component_descriptor_string);
} }
} }
} }
@ -174,39 +368,25 @@ impl JVM {
Ok(()) Ok(())
} }
fn new_object(&mut self, class_name: &String) -> Result<ObjectReference, Error> {
let (_, class_idx) = self.class_store.get_class(class_name)?;
Ok(self.heap_area.make_object(&mut self.class_store, class_idx))
}
fn load_class_hierarchy(&mut self, name: &String) -> Result<(), Error> { fn load_class_hierarchy(&mut self, name: &String) -> Result<(), Error> {
self.class_store.load_class(&name)?; let mut waiting_queue = VecDeque::new();
let super_class_name = { waiting_queue.push_back(name.clone());
let (file, _) = self.class_store.get_class(&name)?;
file.get_super_class_name()?.clone()
};
let mut super_classes = vec![super_class_name];
while super_classes.len() != 0 { while waiting_queue.len() != 0 {
let current_super = super_classes.pop().unwrap(); let class_name = waiting_queue.pop_front().unwrap();
let have_super_super = {
let (super_file, _) = self.class_store.get_class(&current_super)?;
super_file.has_super_class()
};
if have_super_super { if ! self.class_store.have_class(&class_name) {
let super_super_name = { println!("Loading Class {class_name}");
let (super_file, _) = self.class_store.get_class(&current_super)?; self.class_store.load_class(&class_name)?;
super_file.get_super_class_name()? let (file, _) = self.class_store.get_class(&class_name).unwrap();
}; if file.has_super_class() {
if self.class_store.have_class(super_super_name) { waiting_queue.push_back(file.get_super_class_name()?.to_string());
self.class_store.load_class(&current_super)?; }
} else {
super_classes.push(current_super); for interface_index in &file.interfaces {
super_classes.push(super_super_name.to_string()); let interface_name = file.gather_class(*interface_index)?;
waiting_queue.push_back(interface_name.to_string());
} }
} else {
self.class_store.load_class(&current_super)?;
} }
} }
@ -245,53 +425,125 @@ impl JVM {
} }
fn init_class(&mut self, class_idx: usize) -> Result<(), Error> { fn init_class(&mut self, class_idx: usize) -> Result<(), Error> {
let class_file = self.class_store.class_file_from_idx(class_idx).unwrap(); {
let clinit_idx = class_file.find_method_index(&"<clinit>".to_string()); let class_file = self.class_store.class_file_from_idx(class_idx).unwrap();
self.heap_area.make_static(class_file, class_idx); self.heap_area.make_static(class_file, class_idx);
for field in &class_file.fields { for field in &class_file.fields {
if field.access_flags & FieldAccessFlag::Static { if field.access_flags & FieldAccessFlag::Static {
let cvalue_attrs: Vec<&ConstantValueAttributeData> = (&field.attributes).iter() let cvalue_attrs: Vec<&ConstantValueAttributeData> = (&field.attributes).iter()
.filter(|a| match a.data { AttributeData::ConstantValue(_) => true, _ => false }) .filter(|a| match a.data { AttributeData::ConstantValue(_) => true, _ => false })
.map(|a| match &a.data { AttributeData::ConstantValue(c) => c, _ => unreachable!() }) .map(|a| match &a.data { AttributeData::ConstantValue(c) => c, _ => unreachable!() })
.collect(); .collect();
assert!(cvalue_attrs.len() < 2); assert!(cvalue_attrs.len() < 2);
// TODO: Throw error // TODO: Throw error
if cvalue_attrs.len() == 1 { if cvalue_attrs.len() == 1 {
let constant_value_info = cvalue_attrs[0]; let constant_value_info = cvalue_attrs[0];
assert!(field.descriptor.array_level == 0); assert!(field.descriptor.array_level == 0);
// TODO: Throw Error // TODO: Throw Error
let field_value = match field.descriptor.kind { let field_value = match field.descriptor.kind {
AbstractTypeKind::Boolean() => { AbstractTypeKind::Boolean() => {
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?; let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
FieldValue::Boolean(int_entry.value != 0) FieldValue::Boolean(int_entry.value != 0)
}, },
AbstractTypeKind::Int() => { AbstractTypeKind::Byte() => {
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?; let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
FieldValue::Int(int_entry.value) FieldValue::Byte(int_entry.value as u8)
}, },
AbstractTypeKind::Short() => { AbstractTypeKind::Char() => {
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?; let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
FieldValue::Short(int_entry.value as i16) FieldValue::Char(int_entry.value as u16)
}, },
_ => todo!() AbstractTypeKind::Int() => {
}; let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
self.heap_area.static_area.set(class_file.get_classname()?, &field.name, field_value)?; FieldValue::Int(int_entry.value)
},
AbstractTypeKind::Short() => {
let int_entry = class_file.pool_int_entry(constant_value_info.constant_value_index)?;
FieldValue::Short(int_entry.value as i16)
},
AbstractTypeKind::Long() => {
let long_entry = class_file.pool_long_entry(constant_value_info.constant_value_index)?;
FieldValue::Long(long_entry.value)
},
AbstractTypeKind::Classname(ref name) => {
if name == "java/lang/String" {
let string_entry = class_file.gather_string(constant_value_info.constant_value_index)?;
let (string_class_file, string_class_index) = self.class_store.get_class(name).unwrap();
let string_object = self.heap_area.make_object(&self.class_store, string_class_index);
// TODO: Review this if it looks like there will be stack
// overflows in initialization
let string_init_function_index = match ClassMethodIterator::new(string_class_index, &self.class_store)
.filter(|( cid, _mid, _minfo)| *cid == string_class_index)
.filter(|(_cid, _mid, minfo)| minfo.name == "<init>")
.filter(|(_cid, _mid, minfo)| minfo.descriptor.argument_types.len() == 1)
.filter(|(_cid, _mid, minfo)| minfo.descriptor.argument_types[0] == AbstractTypeDescription { array_level: 1, kind: AbstractTypeKind::Byte() })
.next() {
Some((_, method_index, _)) => method_index,
None => unreachable!(),
};
let byte_array = self.heap_area.byte_array_from_rust_string(string_entry, &self.class_store);
self.stack_frames.push(
StackFrame::new(
string_class_file,
string_class_index,
string_init_function_index as u16,
&[StackValue::Reference(byte_array)],
)
);
FieldValue::Reference(string_object)
} else {
todo!()
}
},
_ => {
println!("{:?}", field.descriptor.kind);
todo!()
},
};
self.heap_area.static_area.set(class_file.get_classname()?, &field.name, field_value)?;
}
} }
} }
} }
// TODO: Push clinit function // class object
self.make_class_class(&("L".to_owned() + &self.class_store.class_file_from_idx(class_idx).unwrap().get_classname()?.clone() + ";"));
// Push clinit function
let class_file = self.class_store.class_file_from_idx(class_idx).unwrap();
let clinit_idx = class_file.find_method_index(&"<clinit>".to_string());
if let Some(method_index) = clinit_idx {
let clinit_frame = StackFrame::new(
class_file,
class_idx,
method_index as u16,
&[],
);
self.stack_frames.push(clinit_frame);
}
// finish
self.class_store.set_init(class_idx, true); self.class_store.set_init(class_idx, true);
Ok(()) Ok(())
@ -312,7 +564,67 @@ impl JVM {
let (instruction, offset) = bytecode.next_instruction(frame.instruction_pointer as usize); let (instruction, offset) = bytecode.next_instruction(frame.instruction_pointer as usize);
frame.instruction_pointer += offset as u32; frame.instruction_pointer += offset as u32;
println!("{:25}.{:15}:{:<10}{instruction:?}", class.get_classname().unwrap(), method.name, frame.instruction_pointer);
match instruction { match instruction {
Instruction::Duplicate() => {
let popped_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_computational_1(0))?;
wrap_stackframe_error(class, method, frame.operand_stack.push(popped_value))?;
wrap_stackframe_error(class, method, frame.operand_stack.push(popped_value))?;
}
Instruction::InvokeSpecial(methodref_index) => {
let (supplied_class_name, supplied_method_name, supplied_descriptor_string) = class.gather_methodref(methodref_index)?;
if ! self.class_store.have_class(supplied_class_name) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::LoadClass(supplied_class_name.to_string()));
}
if ! self.class_store.was_init(supplied_class_name).unwrap() {
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::InitClass(supplied_class_name.to_string()));
}
let target_class_index = self.class_store.class_idx_from_name(supplied_class_name).unwrap();
let parsed_expected_descriptor: MethodDescriptor = MethodDescriptor::try_from(supplied_descriptor_string)?;
let (class_index, method_index, method_info) = match ClassMethodIterator::new(target_class_index, &self.class_store)
.filter(|(_cid, _mid, minfo)| minfo.name == *supplied_method_name)
.filter(|(_cid, _mid, minfo)| minfo.descriptor == parsed_expected_descriptor)
.next() {
Some(m) => m,
None => {
// TODO: Throw exception
return Err(Error::RunTimeError(format!("InvokeSpecial: Failed to find requested method '{}' with descriptor '{}' in the class '{}'", supplied_method_name, supplied_descriptor_string, supplied_class_name)));
}
};
let mut arguments = VecDeque::new();
fill_arguments(class, method, &mut arguments, &method_info.descriptor.argument_types, &mut frame.operand_stack)?;
// this
arguments.push_front(
StackValue::Reference(
wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?
)
);
let new_frame = StackFrame::new(
self.class_store.class_file_from_idx(class_index).unwrap(),
class_index,
method_index as u16,
&arguments.make_contiguous(),
);
return Ok(JVMCallbackOperation::PushFrame(new_frame));
},
Instruction::InvokeStatic(methodref_index) => { Instruction::InvokeStatic(methodref_index) => {
let (supplied_class_name, supplied_method_name, supplied_descriptor_string) = class.gather_methodref(methodref_index)?; let (supplied_class_name, supplied_method_name, supplied_descriptor_string) = class.gather_methodref(methodref_index)?;
@ -397,18 +709,159 @@ impl JVM {
load_local_int(class, method, frame, 3)?; load_local_int(class, method, frame, 3)?;
} }
Instruction::LoadLocalReference0() => {
load_local_reference(class, method, frame, 0)?;
}
Instruction::MultiplyInt() => { Instruction::MultiplyInt() => {
let factor_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let factor_1 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let factor_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?; let factor_2 = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(factor_1 * factor_2)))?; wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(factor_1 * factor_2)))?;
} }
Instruction::PushConstInt5() => { Instruction::NewArray(class_index) => {
let frame_result = frame.operand_stack.push(StackValue::Int(5)); // construct single level array
match frame_result { let class_name = class.gather_class(class_index)?;
Ok(_) => (),
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))), if ! self.class_store.have_class(class_name) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::LoadClass(class_name.to_string()));
} }
if ! self.class_store.was_init(class_name).unwrap() {
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::InitClass(class_name.to_string()));
}
let class_descriptor = AbstractTypeDescription {
array_level: 0,
kind: match class_name {
_ => AbstractTypeKind::Classname(class_name.to_string())
}
};
let array_descriptor = AbstractTypeDescription {
array_level: 1,
kind: class_descriptor.kind.clone(),
};
if let None = self.class_store.get_array_class_ref(&array_descriptor) {
let complete_type_descriptor = format!("L{};", class_name);
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::MakeArrayClass(complete_type_descriptor));
}
let array_capacity = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
let array_ref = self.heap_area.make_empty_array(&self.class_store, class_descriptor, array_capacity as usize);
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(array_ref)))?;
}
Instruction::NewObject(class_index) => {
let class_name = class.gather_class(class_index)?;
if ! self.class_store.have_class(class_name) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::LoadClass(class_name.to_string()));
}
if ! self.class_store.was_init(class_name).unwrap() {
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::InitClass(class_name.to_string()));
}
let class_index = self.class_store.class_idx_from_name(class_name).unwrap();
let new_object = self.heap_area.make_object(&self.class_store, class_index);
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(new_object)))?;
},
Instruction::PushConstInt0() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(0)))?;
}
Instruction::PushConstInt1() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(1)))?;
}
Instruction::PushConstInt2() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(2)))?;
}
Instruction::PushConstInt3() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(3)))?;
}
Instruction::PushConstInt4() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(4)))?;
}
Instruction::PushConstInt5() => {
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(5)))?;
}
Instruction::PutStatic(fieldref_index) => {
let (target_class_name, target_field_name, expected_field_descriptor) = class.gather_fieldref(fieldref_index)?;
if ! self.class_store.have_class(target_class_name) {
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::LoadClass(target_class_name.to_string()));
}
if ! self.class_store.was_init(target_class_name).unwrap() {
// rewind the bytecode offset, I'll need to execute this instruction again
frame.instruction_pointer -= offset as u32;
return Ok(JVMCallbackOperation::InitClass(target_class_name.to_string()));
}
let matched_field = match ClassFieldIterator::new(self.class_store.class_idx_from_name(target_class_name).unwrap(), &self.class_store)
.filter(|f| f.name == *target_field_name)
.filter(|f| f.access_flags & FieldAccessFlag::Static)
.next() {
Some(f) => f,
None => return Err(Error::RunTimeError(format!("PutStatic: Trying to set field '{}' on class '{}' but there is no such static field", target_field_name, target_class_name)))
};
let (consumed_chars, expected_descriptor) = AbstractTypeDescription::parse_first(expected_field_descriptor)?;
assert!(expected_field_descriptor.len() == consumed_chars);
// TODO: Throw exception on fail
if matched_field.descriptor != expected_descriptor {
return Err(Error::RunTimeError(format!("PutStatic: Field descriptor mismatch: '{expected_descriptor:?}' but found '{:?}'", matched_field.descriptor)))
}
let set_value = match (matched_field.descriptor.array_level, &matched_field.descriptor.kind) {
(0, AbstractTypeKind::Boolean()) => {
let int_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
FieldValue::Boolean((int_value & 1) != 0)
},
(0..=255, AbstractTypeKind::Classname(_field_type_name)) => {
let ref_value = wrap_stackframe_error(class, method, frame.operand_stack.pop_reference(0))?;
let value_native_name = self.heap_area.object_area.get_reference_native_class_name(ref_value, &self.class_store);
let parsed_native_name = AbstractTypeDescription::parse_first(value_native_name).unwrap().1;
if ! self.class_store.are_types_compatible(&matched_field.descriptor, &parsed_native_name) {
return Err(Error::RunTimeError(format!("PutStatic: Trying to set a value with type '{parsed_native_name:?}' on a field with type '{:?}'", matched_field.descriptor)));
}
FieldValue::Reference(ref_value)
}
_ => {
println!("{:?}", matched_field);
todo!()
},
};
self.heap_area.static_area.set(target_class_name, target_field_name, set_value)?;
} }
Instruction::ReturnInt() => { Instruction::ReturnInt() => {
@ -443,19 +896,19 @@ impl JVM {
wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Int(int)))?; wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Int(int)))?;
}, },
Instruction::StoreLocalInt1() => { Instruction::StoreLocalInt1() => {
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(1))?; let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Int(int)))?; wrap_stackframe_error(class, method, frame.store_local(1, StackValue::Int(int)))?;
}, },
Instruction::StoreLocalInt2() => { Instruction::StoreLocalInt2() => {
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(2))?; let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Int(int)))?; wrap_stackframe_error(class, method, frame.store_local(2, StackValue::Int(int)))?;
}, },
Instruction::StoreLocalInt3() => { Instruction::StoreLocalInt3() => {
let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(3))?; let int = wrap_stackframe_error(class, method, frame.operand_stack.pop_int(0))?;
wrap_stackframe_error(class, method, frame.store_local(0, StackValue::Int(int)))?; wrap_stackframe_error(class, method, frame.store_local(3, StackValue::Int(int)))?;
}, },
_ => { _ => {
@ -477,22 +930,23 @@ enum JVMCallbackOperation {
PushFrame(StackFrame), PushFrame(StackFrame),
LoadClass(String), LoadClass(String),
InitClass(String), InitClass(String),
MakeArrayClass(String),
}
fn load_local_reference(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> {
let loaded_value = wrap_stackframe_error(class, method, frame.load_local_reference(index as u16))?;
wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Reference(loaded_value)))?;
Ok(())
} }
fn load_local_int(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> { fn load_local_int(class: &JavaClassFile, method: &MethodInfo, frame: &mut StackFrame, index: usize) -> Result<(), Error> {
let frame_result = frame.load_local_int(index as u16); let loaded_value = wrap_stackframe_error(class, method, frame.load_local_int(index as u16))?;
let local_int = match frame_result {
Ok(i) => {
i
},
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))),
};
let frame_result = frame.operand_stack.push(StackValue::Int(local_int)); wrap_stackframe_error(class, method, frame.operand_stack.push(StackValue::Int(loaded_value)))?;
match frame_result {
Ok(_) => Ok(()), Ok(())
Err(err) => return Err(Error::StackFrameError(err, format!("in '{}', in class '{}'", method.name, class.get_classname().unwrap()))),
}
} }
fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut VecDeque<StackValue>, argument_types: &Box<[AbstractTypeDescription]>, stack: &mut OperandStack) -> Result<(), Error> { fn fill_arguments(class: &JavaClassFile, method: &MethodInfo, arguments: &mut VecDeque<StackValue>, argument_types: &Box<[AbstractTypeDescription]>, stack: &mut OperandStack) -> Result<(), Error> {

View file

@ -6,26 +6,32 @@ mod stackframe;
mod accessmasks; mod accessmasks;
mod constantpool; mod constantpool;
mod heap_area; mod heap_area;
mod iterators;
use std::fs::File; use std::fs::File;
//
use crate::stackframe::StackValue; use crate::accessmasks::FieldAccessFlag;
//use crate::stackframe::StackValue;
use crate::classfile::JavaClassFile; use crate::classfile::JavaClassFile;
fn main() { fn main() {
//println!("{:#?}", JavaClassFile::new(&mut File::open("java/Main.class").unwrap()).unwrap());
let mut jvm = jvm::JVM::new(); let mut jvm = jvm::JVM::new();
jvm.entrypoint( match jvm.entrypoint(
&"java/Math".to_string(), &"java/Math".to_string(),
&"v".to_string(), &"v".to_string(),
&[]//&[Value::Int(1), Value::Int(2)], &["Hello World"],
).expect("failed to call main() on supplied class"); ) {
match jvm.run() {
Ok(()) => (), Ok(()) => (),
Err(e) => println!("{:#?}", e), Err(e) => println!("{:#?}", e),
}; }
//println!("{:#?}", jvm.heap_area); // match jvm.run() {
//println!("{:#?}", JavaClassFile::new(&mut File::open("java/Class.class").unwrap())); // Ok(()) => (),
// Err(e) => println!("{:#?}", e),
// };
//println!("{:#?}", jvm.heap_area.static_area);
} }

View file

@ -49,6 +49,19 @@ impl OperandStack {
Ok(()) Ok(())
} }
pub fn pop_computational_1(&mut self, index: usize) -> Result<StackValue, Error> {
let absolute_index = self.depth as usize - 1 - index;
let value = self.stack[absolute_index];
self.depth -= 1;
match value {
StackValue::Long0(_) | StackValue::Long1(_) | StackValue::Double0(_) | StackValue::Double1(_) => {
Err(Error::LocalError(format!("Mismatched type at index {} of the function operand stack, expected type with computational type 1 but found '{:?}'", index, value)))
},
_ => Ok(value),
}
}
pub fn pop_boolean(&mut self, index: usize) -> Result<bool, Error> { pub fn pop_boolean(&mut self, index: usize) -> Result<bool, Error> {
let absolute_index = self.depth as usize - 1 - index; let absolute_index = self.depth as usize - 1 - index;
let value = self.stack[absolute_index]; let value = self.stack[absolute_index];
@ -239,6 +252,14 @@ impl StackFrame {
} }
} }
pub fn load_local_reference(&self, index: u16) -> Result<ObjectReference, Error> {
let local = self.locals[index as usize];
match local {
StackValue::Reference(r) => Ok(r),
_ => Err(Error::LocalError(format!("Mismatched type at index {} of the function locals, expected Reference but found '{:?}'", index, local)))
}
}
pub fn store_local(&mut self, index: u16, value: StackValue) -> Result<(), Error> { pub fn store_local(&mut self, index: u16, value: StackValue) -> Result<(), Error> {
let field = self.locals.get_mut(index as usize); let field = self.locals.get_mut(index as usize);
match field { match field {