Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: use instruction enum instead of bytes for code #10

Merged
merged 4 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ dependent-version = "upgrade"
tag-name = "v{{version}}"

[profile.release]
#codegen-units = 1
codegen-units = 1
lto = true
opt-level = "z"
panic = "abort"
Expand Down
17 changes: 4 additions & 13 deletions examples/hello_world/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use ristretto_classfile::{
ClassAccessFlags, ClassFile, Constant, ConstantPool, Error, MethodAccessFlags, Result, Version,
};
use std::fs;
use std::io::Cursor;

/// Creates a simple "Hello, World!" class file equivalent to the following Java code:
///
Expand Down Expand Up @@ -60,11 +59,11 @@ fn main() -> Result<()> {
name_index: code_index,
max_stack: 1,
max_locals: 1,
code: instructions_as_bytes(&vec![
code: vec![
Instruction::Aload_0,
Instruction::Invokespecial(object_init),
Instruction::Return,
])?,
],
exceptions: Vec::new(),
attributes: Vec::new(),
});
Expand All @@ -80,12 +79,12 @@ fn main() -> Result<()> {
name_index: code_index,
max_stack: 2,
max_locals: 1,
code: instructions_as_bytes(&vec![
code: vec![
Instruction::Getstatic(println_field),
Instruction::Ldc(u8::try_from(hello_world_string)?),
Instruction::Invokevirtual(println_method),
Instruction::Return,
])?,
],
exceptions: Vec::new(),
attributes: Vec::new(),
});
Expand Down Expand Up @@ -121,14 +120,6 @@ fn main() -> Result<()> {
Ok(())
}

fn instructions_as_bytes(instructions: &Vec<Instruction>) -> Result<Vec<u8>> {
let mut bytes = Cursor::new(Vec::new());
for instruction in instructions {
instruction.to_bytes(&mut bytes)?;
}
Ok(bytes.into_inner())
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
52 changes: 36 additions & 16 deletions ristretto_classfile/src/attributes/attribute.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::attributes::bootstrap_method::BootstrapMethod;
use crate::attributes::inner_class::InnerClass;
use crate::attributes::instruction_utils;
use crate::attributes::line_number::LineNumber;
use crate::attributes::parameter_annotation::ParameterAnnotation;
use crate::attributes::{
Expand Down Expand Up @@ -42,7 +43,7 @@ pub enum Attribute {
name_index: u16,
max_stack: u16,
max_locals: u16,
code: Vec<u8>,
code: Vec<Instruction>,
exceptions: Vec<CodeException>,
attributes: Vec<Attribute>,
},
Expand Down Expand Up @@ -286,14 +287,7 @@ impl Attribute {
let code_length = bytes.read_u32::<BigEndian>()?;
let mut code = vec![0; code_length as usize];
bytes.read_exact(&mut code)?;

let code_length = u64::try_from(code.len())?;
let mut code_cursor = Cursor::new(code.clone());
let mut instructions = Vec::new();
while code_cursor.position() < code_length {
let instruction = Instruction::from_bytes(&mut code_cursor)?;
instructions.push(instruction);
}
let instructions = instruction_utils::from_bytes(&mut Cursor::new(code))?;

let exception_length = bytes.read_u16::<BigEndian>()?;
let mut exceptions = Vec::with_capacity(exception_length as usize);
Expand All @@ -311,7 +305,7 @@ impl Attribute {
name_index,
max_stack,
max_locals,
code,
code: instructions,
exceptions,
attributes,
}
Expand Down Expand Up @@ -678,9 +672,10 @@ impl Attribute {
bytes.write_u16::<BigEndian>(*max_stack)?;
bytes.write_u16::<BigEndian>(*max_locals)?;

let code_length = u32::try_from(code.len())?;
let code_bytes = instruction_utils::to_bytes(code)?;
let code_length = u32::try_from(code_bytes.len())?;
bytes.write_u32::<BigEndian>(code_length)?;
bytes.extend_from_slice(code.as_slice());
bytes.extend_from_slice(code_bytes.as_slice());

let exceptions_length = u16::try_from(exceptions.len())?;
bytes.write_u16::<BigEndian>(exceptions_length)?;
Expand Down Expand Up @@ -1022,12 +1017,37 @@ impl fmt::Display for Attribute {
writeln!(f, "Code:")?;
writeln!(f, " stack={max_stack}, locals={max_locals}")?;

let code_length = u64::try_from(code.len()).map_err(|_| fmt::Error)?;
let mut cursor = Cursor::new(code.clone());
let code_bytes = instruction_utils::to_bytes(code).map_err(|_| fmt::Error)?;
let code_length = u64::try_from(code_bytes.len()).map_err(|_| fmt::Error)?;
let mut cursor = Cursor::new(code_bytes.clone());
while cursor.position() < code_length {
let index = cursor.position();
let instruction =
let mut instruction =
Instruction::from_bytes(&mut cursor).map_err(|_| fmt::Error)?;
match instruction {
Instruction::Tableswitch {
ref mut default,
ref mut offsets,
..
} => {
let position = i32::try_from(index).map_err(|_| fmt::Error)?;
*default += position;
for offset in offsets {
*offset += position;
}
}
Instruction::Lookupswitch {
ref mut default,
ref mut pairs,
} => {
let position = i32::try_from(index).map_err(|_| fmt::Error)?;
*default += position;
for (_match, offset) in pairs {
*offset += position;
}
}
_ => {}
}
let value = instruction.to_string();
let (name, value) = value.split_once(' ').unwrap_or((value.as_str(), ""));
let value = format!("{name:<13} {value}");
Expand Down Expand Up @@ -1154,7 +1174,7 @@ mod test {
name_index: 1,
max_stack: 2,
max_locals: 3,
code: vec![4],
code: vec![Instruction::Iconst_1],
exceptions: vec![exception],
attributes: vec![constant.clone()],
};
Expand Down
4 changes: 1 addition & 3 deletions ristretto_classfile/src/attributes/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1137,10 +1137,8 @@ impl fmt::Display for Instruction {
write!(f, " }}")
}
Instruction::Lookupswitch { pairs, default } => {
let first_pair = pairs.first().unwrap_or(&(0, 0));
let (low, _) = first_pair;
let width = 12;
writeln!(f, "lookupswitch {{ // {low}")?;
writeln!(f, "lookupswitch {{ // {}", pairs.len())?;
for pair in pairs {
let (value, offset) = pair;
writeln!(f, " {value:>width$}: {offset}")?;
Expand Down
Loading