From 6c0fbd179a2b94c824a1ef000ccd98c015eb17dc Mon Sep 17 00:00:00 2001 From: VegOwOtenks Date: Mon, 2 Sep 2024 17:44:59 +0200 Subject: [PATCH] Static object creation --- src/accessmasks.rs | 30 ++++++++++++++-- src/classfile.rs | 88 ++++++++++++++++++++++++++++++++++++---------- src/heap_area.rs | 38 ++++++++++++++++++-- src/jvm.rs | 11 ++++-- src/main.rs | 3 +- src/stackframe.rs | 19 +++++++++- 6 files changed, 160 insertions(+), 29 deletions(-) diff --git a/src/accessmasks.rs b/src/accessmasks.rs index 398fbdc..641b967 100644 --- a/src/accessmasks.rs +++ b/src/accessmasks.rs @@ -130,9 +130,33 @@ pub enum FieldAccessFlag { Enum = 0x4000, // Declared as an element of an enum class. } - pub struct FieldAccessFlagMask { - pub mask: u16 - } +#[derive(Clone, Copy)] +pub struct FieldAccessFlagMask { + pub mask: u16 +} + +impl FieldAccessFlag { + pub fn discriminant(&self) -> u16 { + return match self { + Self::Public => 0x0001, + Self::Private => 0x0002, + Self::Protected => 0x0004, + Self::Static => 0x0008, + Self::Final => 0x0010, + Self::Volatile => 0x0040, + Self::Transient => 0x0080, + Self::Synthetic => 0x1000, + Self::Enum => 0x4000, + } + } +} + +impl BitAnd for FieldAccessFlagMask { + type Output=bool; + fn bitand(self, f: FieldAccessFlag) -> bool { + return (self.mask & f.discriminant()) != 0; + } +} impl Debug for FieldAccessFlagMask { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { diff --git a/src/classfile.rs b/src/classfile.rs index 2a55654..46b6c59 100644 --- a/src/classfile.rs +++ b/src/classfile.rs @@ -266,10 +266,10 @@ impl JavaClassFile { #[derive(Debug)] pub struct FieldInfo { - access_flags: FieldAccessFlagMask, - name: String, - descriptor: AbstractTypeDescription, - attributes: Box<[AttributeInfo]>, + pub access_flags: FieldAccessFlagMask, + pub name: String, + pub descriptor: AbstractTypeDescription, + pub attributes: Box<[AttributeInfo]>, } impl FieldInfo { @@ -535,11 +535,15 @@ impl NestMembersAttributeData { pub enum AttributeData { Code(CodeAttributeData), Signature(SignatureAttributeData), + Synthetic(), + Exceptions(ExceptionAttributeData), NestMembers(NestMembersAttributeData), SourceFile(SourceFileAttributeData), InnerClasses(InnerClassesAttributeData), ConstantValue(ConstantValueAttributeData), + DebugExtension(DebugExtensionAttributeData), LineNumberTable(LineNumberTableAttributeData), + EnclosingMethod(EnclosingMethodAttributeData), Unknown(UnknownAttributeData), } @@ -564,7 +568,7 @@ impl AttributeInfo { fn from_reader(reader: &mut dyn Read, pool: &Box<[ConstantPoolInfo]>, allow_code_attr: bool) -> Result { let attribute_name_index: u16 = read_u16(reader)? - 1; - let _attribute_byte_size: usize = read_u32(reader)?.try_into()?; + let attribute_byte_size: usize = read_u32(reader)?.try_into()?; let data = { let name_entry = &pool[attribute_name_index as usize]; @@ -574,35 +578,47 @@ impl AttributeInfo { }; match &utf8[..] { - "ConstantValue" => AttributeData::ConstantValue( + "ConstantValue" => AttributeData::ConstantValue( ConstantValueAttributeData { constant_value_index: read_u16(reader)?, } - ), + ), - "LineNumberTable" => AttributeData::LineNumberTable( + "LineNumberTable" => AttributeData::LineNumberTable( LineNumberTableAttributeData::from_reader(reader)? - ), + ), - "Code" => if allow_code_attr { + "Code" => if allow_code_attr { AttributeData::Code( CodeAttributeData::from_reader(reader, pool)? ) - } else { + } else { return Err(Error::BadFileError("Nested Code attributes are forbidden.".to_string())); - }, + }, - "SourceFile" => AttributeData::SourceFile(SourceFileAttributeData::from_reader(reader)?), + "SourceFile" => AttributeData::SourceFile(SourceFileAttributeData::from_reader(reader)?), - "Signature" => AttributeData::Signature(SignatureAttributeData::from_reader(reader)?), + "Signature" => AttributeData::Signature(SignatureAttributeData::from_reader(reader)?), - "InnerClasses" => AttributeData::InnerClasses(InnerClassesAttributeData::from_reader(reader)?), + "InnerClasses" => AttributeData::InnerClasses(InnerClassesAttributeData::from_reader(reader)?), - "NestMembers" => AttributeData::NestMembers(NestMembersAttributeData::from_reader(reader)?), + "NestMembers" => AttributeData::NestMembers(NestMembersAttributeData::from_reader(reader)?), + + "Exceptions" => AttributeData::Exceptions(ExceptionAttributeData::from_reader(reader)?), + + "EnclosingMethod" => AttributeData::EnclosingMethod(EnclosingMethodAttributeData {class_index: read_u16(reader)?, method_index: read_u16(reader)?}), + + "Synthetic" => AttributeData::Synthetic(), + + "DebugExtension" => AttributeData::DebugExtension( + DebugExtensionAttributeData { + utf8: std::str::from_utf8(&(read_buffer(reader, attribute_byte_size)?))?.to_string(), + } + ), &_ => AttributeData::Unknown( UnknownAttributeData { - info: read_buffer(reader, _attribute_byte_size)?, + info: read_buffer(reader, attribute_byte_size)?, } ) } @@ -617,8 +633,42 @@ impl AttributeInfo { } } +#[derive(Debug)] +pub struct DebugExtensionAttributeData { + utf8: String, +} + +#[derive(Debug)] +pub struct EnclosingMethodAttributeData { + class_index: u16, + method_index: u16, +} + +// for use on methods, what exception can be thrown by this +#[derive(Debug)] +pub struct ExceptionAttributeData { + exception_indices: Box<[u16]>, +} + +impl ExceptionAttributeData { + fn from_reader(reader: &mut dyn Read) -> Result { + let length = read_u16(reader)?; + let mut exception_vector = Vec::with_capacity(length as usize); + + for _ in 0..length { + exception_vector.push(read_u16(reader)?); + } + + Ok( + ExceptionAttributeData { + exception_indices: exception_vector.into_boxed_slice() + } + ) + } +} + #[repr(u8)] -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Clone)] pub enum AbstractTypeKind { Void() = b'V', // void Byte() = b'B', // signed byte @@ -649,7 +699,7 @@ impl Into for &AbstractTypeKind { } } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Clone)] pub struct AbstractTypeDescription { pub array_level: u8, pub kind: AbstractTypeKind, diff --git a/src/heap_area.rs b/src/heap_area.rs index 70d7092..7ddd4d0 100644 --- a/src/heap_area.rs +++ b/src/heap_area.rs @@ -1,7 +1,8 @@ use std::collections::HashMap; +use crate::accessmasks::FieldAccessFlag; use crate::stackframe::Value; -use crate::classfile::{ AbstractTypeDescription, MethodInfo }; +use crate::classfile::{ JavaClassFile, AbstractTypeDescription, MethodInfo }; #[derive(Debug)] pub struct HeapArea { @@ -54,13 +55,46 @@ pub struct StaticArea { static_objects: HashMap, } +impl StaticArea { + pub fn make(&mut self, class: &JavaClassFile, class_index: usize) { + let mut fields = Vec::new(); + + for field in &class.fields { + if field.access_flags & FieldAccessFlag::Static { + fields.push( + StaticField { + name: field.name.clone(), + type_description: field.descriptor.clone(), + value: Value::default_for(field.descriptor), + } + ) + } + } + + let new_object = StaticObject { + class_index, + fields: fields.into_boxed_slice(), + methods: Box::new([]), + }; + + let _ = self.static_objects.insert(class.get_classname().unwrap(), new_object); + } +} + #[derive(Debug)] pub struct StaticObject { pub class_index: usize, - pub fields: Box<[ObjectField]>, + pub fields: Box<[StaticField]>, pub methods: Box<[MethodInfo]>, } +#[derive(Debug)] +pub struct StaticField { + pub name: String, + pub type_description: AbstractTypeDescription, + pub value: Value, +} + #[derive(Debug)] pub struct ObjectField { pub type_description: AbstractTypeDescription, diff --git a/src/jvm.rs b/src/jvm.rs index 8125e8a..cb8de55 100644 --- a/src/jvm.rs +++ b/src/jvm.rs @@ -161,7 +161,7 @@ impl JVM { }, JVMCallbackOperation::InitClass(name) => { - self.init_class(*self.class_store.class_idx_from_name(&name).unwrap()); + self.init_class(*self.class_store.class_idx_from_name(&name).unwrap())?; } } } @@ -169,14 +169,19 @@ impl JVM { Ok(()) } - pub fn init_class(&mut self, class_idx: usize) { + pub 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(&"".to_string()); - // TODO: ConstantValue Attributes (final) // TODO: Static Stuff + self.heap_area.static_area.make(class_file, class_idx); + + // TODO: ConstantValue Attributes (final) + // TODO: Push clinit function self.class_store.set_init(class_idx, true); + + Ok(()) } fn prepare_invoke_static(&mut self, class_index: usize, method_name: &String, arguments: &[Value]) -> Result<(), Error> { diff --git a/src/main.rs b/src/main.rs index fd80f00..a82cc32 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,5 +26,6 @@ fn main() { Err(e) => println!("{:#?}", e), }; - println!("{:#?}", jvm.stack_frames); + println!("{:#?}", jvm); + //println!("{:#?}", JavaClassFile::new(&mut File::open("java/Class.class").unwrap())); } diff --git a/src/stackframe.rs b/src/stackframe.rs index 5539fbc..bb8404a 100644 --- a/src/stackframe.rs +++ b/src/stackframe.rs @@ -1,4 +1,4 @@ -use crate::classfile::{ JavaClassFile, AttributeData }; +use crate::classfile::{ JavaClassFile, AttributeData, AbstractTypeDescription }; use crate::heap_area::ObjectReference; #[derive(Copy, Clone, Debug)] @@ -18,6 +18,23 @@ pub enum Value { Empty(), } +impl Value { + fn default_for(t: AbstractTypeDescription) -> Self { + match t { + AbstractTypeDescription::Void() => unreachable!(), + AbstractTypeDescription::Byte() => Value::Byte(0), + AbstractTypeDescription::Char() => Value::Char(0), + AbstractTypeDescription::Double() => Value::Double(0), + AbstractTypeDescription::Float() => , + AbstractTypeDescription::Int() => , + AbstractTypeDescription::Long() => , + AbstractTypeDescription::Classname(String) => , + AbstractTypeDescription::Short() => , + AbstractTypeDescription::Boolean() => , + } + } +} + #[derive(Debug)] pub struct OperandStack { stack: Box<[Value]>,