Skip to content

Commit

Permalink
Start working on code writing
Browse files Browse the repository at this point in the history
  • Loading branch information
ExcaliburZero committed Feb 16, 2019
1 parent 612bc50 commit e93c3e6
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 1 deletion.
33 changes: 33 additions & 0 deletions src/attribute.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::io;
use std::io::Write;

use bytecode::*;
use parsing;
Expand Down Expand Up @@ -68,6 +69,38 @@ impl Code {
attributes,
})
}

pub fn to_bytes(&self) -> Vec<u8> {
let mut buffer = vec![];

let max_stack = u16::to_be_bytes(self.max_stack);
let max_locals = u16::to_be_bytes(self.max_locals);

buffer.write_all(&max_stack).unwrap();
buffer.write_all(&max_locals).unwrap();

let mut code: Vec<u8> = self.code.iter()
.map(|(_, bytecode)| bytecode)
.flat_map(Bytecode::to_bytes)
.collect();

let code_length = u32::to_be_bytes(code.len() as u32);

buffer.write_all(&code_length).unwrap();
buffer.write_all(&mut code).unwrap();

// TODO: implement writing of execption table and attributes
assert!(self.exception_table.len() == 0);
assert!(self.attributes.len() == 0);

let exception_table_length = u16::to_be_bytes(0);
let attributes_length = u16::to_be_bytes(0);

buffer.write_all(&exception_table_length).unwrap();
buffer.write_all(&attributes_length).unwrap();

buffer
}
}

#[derive(Debug)]
Expand Down
33 changes: 33 additions & 0 deletions src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,39 @@ impl Bytecode {
bytecode
}

/// Converts the bytecode into a vector of bytes.
///
/// ```
/// # use jvm_class_file_parser::Bytecode::*;
/// #
/// assert_eq!(Aconst_null.to_bytes(), vec![1]);
/// assert_eq!(Getstatic(2).to_bytes(), vec![178, 0, 2]);
/// ```
pub fn to_bytes(&self) -> Vec<u8> {
use Bytecode::*;

match self {
Aconst_null => vec![ACONST_NULL],
Ldc(constant_index) => {
let bytes = u8::to_be_bytes(*constant_index);

vec![LDC, bytes[0]]
},
Return => vec![RETURN],
Getstatic(field) => {
let bytes = u16::to_be_bytes(*field);

vec![GETSTATIC, bytes[0], bytes[1]]
},
Invokevirtual(method) => {
let bytes = u16::to_be_bytes(*method);

vec![INVOKEVIRTUAL, bytes[0], bytes[1]]
},
_ => panic!(),
}
}

/// Converts the bytecode into a String representation.
///
/// Takes in the index of the instruction so that it can be used to display
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ fn javap(filepath: &str) {

println!("{{");

for method in class_file.methods.iter() {
for method in &class_file.methods {
print_method(&class_file, method);
}

Expand Down
20 changes: 20 additions & 0 deletions src/writing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const MAGIC: u32 = 0xCAFE_BABE;

const CONSTANT_TAG_UTF8: u8 = 1;
const CONSTANT_TAG_CLASS: u8 = 7;
const CONSTANT_TAG_STRING: u8 = 8;
const CONSTANT_TAG_FIELDREF: u8 = 9;
const CONSTANT_TAG_METHODREF: u8 = 10;
const CONSTANT_TAG_NAME_AND_TYPE: u8 = 12;
Expand Down Expand Up @@ -68,6 +69,10 @@ fn write_constant_pool_entry<W: Write>(file: &mut W, entry: &Box<ConstantPoolEnt
match **entry {
ConstantUtf8 { ref string } => write_constant_utf8(file, &string)?,
ConstantClass { name_index } => write_constant_class(file, name_index)?,
ConstantString { string_index } =>
write_constant_string(file, string_index)?,
ConstantFieldref { class_index, name_and_type_index } =>
write_constant_fieldref(file, class_index, name_and_type_index)?,
ConstantMethodref { class_index, name_and_type_index } =>
write_constant_methodref(file, class_index, name_and_type_index)?,
ConstantNameAndType { name_index, descriptor_index } =>
Expand Down Expand Up @@ -95,6 +100,21 @@ fn write_constant_class<W: Write>(file: &mut W, name_index: u16) -> io::Result<(
Ok(())
}

fn write_constant_string<W: Write>(file: &mut W, string_index: u16) -> io::Result<()> {
write_u8(file, CONSTANT_TAG_STRING)?;
write_u16(file, string_index)?;

Ok(())
}

fn write_constant_fieldref<W: Write>(file: &mut W, class_index: u16, name_and_type_index: u16) -> io::Result<()> {
write_u8(file, CONSTANT_TAG_FIELDREF)?;
write_u16(file, class_index)?;
write_u16(file, name_and_type_index)?;

Ok(())
}

fn write_constant_methodref<W: Write>(file: &mut W, class_index: u16, name_and_type_index: u16) -> io::Result<()> {
write_u8(file, CONSTANT_TAG_METHODREF)?;
write_u16(file, class_index)?;
Expand Down
5 changes: 5 additions & 0 deletions tests/parse_and_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@ fn parse_and_write(filepath: &str) {
fn parse_and_write_class_dummy() {
parse_and_write("classes/Dummy.class");
}

#[test]
fn parse_and_write_class_helloworld() {
parse_and_write("classes/HelloWorld.class");
}

0 comments on commit e93c3e6

Please sign in to comment.