More Bytecode and Attributes support

This commit is contained in:
VegOwOtenks 2024-08-29 18:33:03 +02:00
parent 8a79a28b5f
commit b751fc3588
3 changed files with 274 additions and 22 deletions

68
src/bytecode.rs Normal file
View file

@ -0,0 +1,68 @@
use core::fmt::Debug;
use core::fmt;
pub struct Bytecode {
pub code: Box<[u8]>
}
impl Bytecode {
pub fn opcodes(&self) -> Box<[Instruction]> {
let mut v = Vec::with_capacity(self.code.len());
let mut i = 0;
while i < self.code.len() {
let opcode = self.code[i];
let (instruction, offset) = match opcode {
0x12 => (Instruction::LoadConstant(self.code[i+1]), 2),
0x2A => (Instruction::LoadReference0(), 1),
0x2B => (Instruction::LoadReference1(), 1),
0x2C => (Instruction::LoadReference2(), 1),
0x2D => (Instruction::LoadReference3(), 1),
0x59 => (Instruction::Duplicate(), 1),
0xB0 => (Instruction::ReturnReference(), 1),
0xB1 => (Instruction::ReturnVoid(), 1),
0xB2 => (Instruction::GetStatic(self.code[i+1], self.code[i+2]), 3),
0xB4 => (Instruction::GetField(self.code[i+1], self.code[i+2]), 3),
0xB5 => (Instruction::PutField(self.code[i+1], self.code[i+2]), 3),
0xB6 => (Instruction::InvokeVirtual(self.code[i+1], self.code[i+2]), 3),
0xB7 => (Instruction::InvokeSpecial(self.code[i+1], self.code[i+2]), 3),
0xBB => (Instruction::NewObject(self.code[i+1], self.code[i+2]), 3),
_ => (Instruction::Unknown(opcode), 1)
};
v.push(instruction);
i += offset;
}
v.into_boxed_slice()
}
}
impl Debug for Bytecode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.debug_list()
.entries(self.opcodes())
.finish()
}
}
#[derive(Debug)]
#[repr(u8)]
pub enum Instruction {
LoadConstant(u8) = 0x12, // Push from constant pool
LoadReference0() = 0x2A, // Load local variable reference onto stack
LoadReference1() = 0x2B, // Load local variable reference onto stack
LoadReference2() = 0x2C, // Load local variable reference onto stack
LoadReference3() = 0x2D, // Load local variable reference onto stack
Duplicate() = 0x59, // duplicate top stack value
ReturnReference() = 0xB0, // return top-ref from current function
ReturnVoid() = 0xB1, // return void from function
GetStatic(u8, u8) = 0xB2, // get static field from class
GetField(u8, u8) = 0xB4, // get field from class
PutField(u8, u8) = 0xB5, // set field to a value
InvokeVirtual(u8, u8) = 0xB6, // invoke function on a class
InvokeSpecial(u8, u8) = 0xB7, // invoke instance method
NewObject(u8, u8) = 0xBB, // Create a new object from a constant-pool reference
Unknown(u8),
}

View file

@ -3,6 +3,7 @@ use std::error::Error as ErrorTrait;
use core::fmt::{Display, Formatter, Debug};
use core::str::Utf8Error;
use crate::bytecode::Bytecode;
#[derive(Debug)]
pub enum Error {
@ -135,7 +136,7 @@ impl JavaClassFile {
methods_vec.into_boxed_slice()
};
let attributes = AttributeInfo::array_from_reader(reader, &constant_pool)?;
let attributes = AttributeInfo::array_from_reader(reader, &constant_pool, true)?;
Ok(
JavaClassFile {
@ -472,7 +473,7 @@ impl FieldInfo {
access_flags: AccessFlagMask { mask: read_u16(reader)? },
name_index: read_u16(reader)?,
descriptor_index: read_u16(reader)?,
attributes: AttributeInfo::array_from_reader(reader, pool)?,
attributes: AttributeInfo::array_from_reader(reader, pool, true)?,
}
)
}
@ -530,11 +531,178 @@ impl LineNumberTableAttributeData {
}
}
#[derive(Debug)]
pub struct ExceptionTableEntry {
start_pc: u16,
end_pc: u16,
handler_pc: u16,
catch_type: u16,
}
impl ExceptionTableEntry {
fn from_reader(reader: &mut dyn Read) -> Result<Self, Error> {
Ok(
ExceptionTableEntry {
start_pc: read_u16(reader)?,
end_pc: read_u16(reader)?,
handler_pc: read_u16(reader)?,
catch_type: read_u16(reader)?,
}
)
}
}
#[derive(Debug)]
pub struct CodeAttributeData {
max_stack: u16,
max_locals: u16,
code: Bytecode,
exception_table: Box<[ExceptionTableEntry]>,
attributes: Box<[AttributeInfo]>,
}
impl CodeAttributeData {
fn from_reader(reader: &mut dyn Read, pool: &Box<[ConstantPoolInfo]>) -> Result<Self, Error> {
let max_stack = read_u16(reader)?;
let max_locals = read_u16(reader)?;
let code_length = read_u32(reader)?;
let code = read_buffer(reader, code_length.try_into()?)?;
let exception_length = read_u16(reader)?;
let exception_table = {
let mut v = Vec::with_capacity(exception_length.into());
for _i in 0..exception_length {
v.push(ExceptionTableEntry::from_reader(reader)?);
}
v.into_boxed_slice()
};
let attributes = AttributeInfo::array_from_reader(reader, pool, false)?;
Ok(
CodeAttributeData {
max_stack,
max_locals,
code: Bytecode { code },
exception_table,
attributes
}
)
}
}
#[derive(Debug)]
pub struct SourceFileAttributeData {
source_file_index: u16,
}
impl SourceFileAttributeData {
fn from_reader(reader: &mut dyn Read) -> Result<Self, Error> {
Ok(
SourceFileAttributeData {
source_file_index: read_u16(reader)?,
}
)
}
}
#[derive(Debug)]
pub struct SignatureAttributeData {
signature_index: u16,
}
impl SignatureAttributeData {
fn from_reader(reader: &mut dyn Read) -> Result<Self, Error> {
Ok(
SignatureAttributeData {
signature_index: read_u16(reader)?,
}
)
}
}
#[derive(Debug)]
pub struct InnerClassesAttributeEntry {
inner_class_info_index: u16,
outer_class_info_index: u16,
inner_name_index: u16,
outer_name_index: u16,
}
impl InnerClassesAttributeEntry {
fn from_reader(reader: &mut dyn Read) -> Result<Self, Error> {
Ok(
InnerClassesAttributeEntry {
inner_class_info_index: read_u16(reader)?,
outer_class_info_index: read_u16(reader)?,
inner_name_index: read_u16(reader)?,
outer_name_index: read_u16(reader)?,
}
)
}
}
#[derive(Debug)]
pub struct InnerClassesAttributeData {
classes: Box<[InnerClassesAttributeEntry]>
}
impl InnerClassesAttributeData {
fn from_reader(reader: &mut dyn Read) -> Result<Self, Error> {
Ok(
InnerClassesAttributeData {
classes: {
let length = read_u16(reader)?;
let mut v = Vec::with_capacity(length.into());
for _i in 0..length {
v.push(InnerClassesAttributeEntry::from_reader(reader)?);
}
v.into_boxed_slice()
}
}
)
}
}
#[derive(Debug)]
pub struct NestMembersAttributeData {
class_indices: Box<[u16]>
}
impl NestMembersAttributeData {
fn from_reader(reader: &mut dyn Read) -> Result<Self, Error> {
Ok(
NestMembersAttributeData {
class_indices: {
let length = read_u16(reader)?;
let mut v = Vec::with_capacity(length.into());
for _i in 0..length {
v.push(read_u16(reader)?);
}
v.into_boxed_slice()
}
}
)
}
}
#[derive(Debug)]
pub enum AttributeData {
Code(CodeAttributeData),
Signature(SignatureAttributeData),
NestMembers(NestMembersAttributeData),
SourceFile(SourceFileAttributeData),
InnerClasses(InnerClassesAttributeData),
ConstantValue(ConstantValueAttributeData),
LineNumberTable(LineNumberTableAttributeData),
UnknownAttribute(UnknownAttributeData),
Unknown(UnknownAttributeData),
}
#[derive(Debug)]
@ -544,22 +712,21 @@ pub struct AttributeInfo {
}
impl AttributeInfo {
fn array_from_reader(reader: &mut dyn Read, pool: &Box<[ConstantPoolInfo]>) -> Result<Box<[Self]>, Error> {
fn array_from_reader(reader: &mut dyn Read, pool: &Box<[ConstantPoolInfo]>, allow_code_attr: bool) -> Result<Box<[Self]>, Error> {
let length = read_u16(reader)?;
let mut attr_vec = Vec::with_capacity(length.into());
for _i in 0..length {
let attribute = AttributeInfo::from_reader(reader, &pool)?;
println!("{:#?}", attribute);
let attribute = AttributeInfo::from_reader(reader, &pool, allow_code_attr)?;
attr_vec.push(attribute);
}
Ok(attr_vec.into_boxed_slice())
}
fn from_reader(reader: &mut dyn Read, pool: &Box<[ConstantPoolInfo]>) -> Result<Self, Error> {
let attribute_name_index: u16 = read_u16(reader)?;
let attribute_byte_size: usize = read_u32(reader)?.try_into()?;
fn from_reader(reader: &mut dyn Read, pool: &Box<[ConstantPoolInfo]>, allow_code_attr: bool) -> Result<Self, Error> {
let attribute_name_index: u16 = read_u16(reader)? - 1;
let _attribute_byte_size: usize = read_u32(reader)?.try_into()?;
let data = {
let name_entry = &pool[attribute_name_index as usize];
@ -569,19 +736,35 @@ impl AttributeInfo {
};
match &utf8[..] {
// "ConstantValue" => AttributeData::ConstantValue(
// ConstantValueAttributeData {
// constant_value_index: read_u16(reader)?,
// }
// ),
//
// "LineNumberTable" => AttributeData::LineNumberTable(
// LineNumberTableAttributeData::from_reader(reader)?
// ),
"ConstantValue" => AttributeData::ConstantValue(
ConstantValueAttributeData {
constant_value_index: read_u16(reader)?,
}
),
&_ => AttributeData::UnknownAttribute(
"LineNumberTable" => AttributeData::LineNumberTable(
LineNumberTableAttributeData::from_reader(reader)?
),
"Code" => if allow_code_attr {
AttributeData::Code(
CodeAttributeData::from_reader(reader, pool)?
)
} else {
return Err(Error::BadFileError("Nested Code attributes are forbidden.".to_string()));
},
"SourceFile" => AttributeData::SourceFile(SourceFileAttributeData::from_reader(reader)?),
"Signature" => AttributeData::Signature(SignatureAttributeData::from_reader(reader)?),
"InnerClasses" => AttributeData::InnerClasses(InnerClassesAttributeData::from_reader(reader)?),
"NestMembers" => AttributeData::NestMembers(NestMembersAttributeData::from_reader(reader)?),
&_ => AttributeData::Unknown(
UnknownAttributeData {
info: read_buffer(reader, attribute_byte_size)?,
info: read_buffer(reader, _attribute_byte_size)?,
}
)
}
@ -611,7 +794,7 @@ impl MethodInfo {
access_flags: AccessFlagMask { mask: read_u16(reader)? },
name_index: read_u16(reader)?,
descriptor_index: read_u16(reader)?,
attributes: AttributeInfo::array_from_reader(reader, pool)?
attributes: AttributeInfo::array_from_reader(reader, pool, true)?
}
)
}

View file

@ -1,9 +1,10 @@
use std::fs::File;
mod classfile;
mod bytecode;
fn main() {
let class_file = classfile::JavaClassFile::new(&mut File::open("Main.class").unwrap()).unwrap();
let class_file = classfile::JavaClassFile::new(&mut File::open("class/HashMap.class").unwrap()).unwrap();
println!("{:#?}", class_file);
}