diff --git a/Dummy.class b/Dummy.class index 17b5c76..2c18fc4 100644 Binary files a/Dummy.class and b/Dummy.class differ diff --git a/Dummy.java b/Dummy.java index 0c9c2f9..6b17104 100644 --- a/Dummy.java +++ b/Dummy.java @@ -1,22 +1,6 @@ -package dummy; - public class Dummy { - private final static String constant = "meh"; - private final int integer = 57; - - private final String name; - - public Dummy(String name) { - this.name = name; + public static int get(){ + return 42; } - - public String getName() { - return name; - } - - public void print(){ - System.out.println(name); - } - } diff --git a/src/lib.rs b/src/lib.rs index 12eb869..e3eeec6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ pub mod types; mod io; +pub mod opcodes; +use std::collections::HashMap; use std::rc::Rc; use crate::io::{read_f32, read_f64, read_i32, read_i64, read_u16, read_u32}; use crate::types::{AttributeType, Class, MethodCode, Exception, Field, Method}; @@ -38,18 +40,19 @@ pub fn get_class(bytecode: Vec) -> Option { let methods_count = read_u16(&bytecode, index); index += 2; - let mut methods = vec![]; + let mut methods = HashMap::new(); for _ in 0..methods_count { - methods.push(read_method(constant_pool.clone(), &mut index, &bytecode)); + let m = read_method(constant_pool.clone(), &mut index, &bytecode); + methods.insert(m.name(), m); } let attributes_count = read_u16(&bytecode, index); index += 2; - let mut attributes = vec![]; + let mut attributes = HashMap::new(); for _ in 0..attributes_count { let some = read_attribute(constant_pool.clone(), &bytecode, &mut index); if let Some(att) = some { - attributes.push(att); + attributes.insert(att.0, att.1); } else { panic!(); // bug/not-implemented } @@ -154,10 +157,10 @@ fn read_field(constant_pool: Rc>, index: &mut usize, bytecode: &[u8 let descriptor_index = read_u16(bytecode, *index + 4) as usize; let attributes_count = read_u16(bytecode, *index + 6); *index += 8; - let mut attributes = vec![]; + let mut attributes = HashMap::new(); for _ in 0..attributes_count { if let Some(att) = read_attribute(constant_pool.clone(), bytecode, index) { - attributes.push(att); + attributes.insert(att.0, att.1); } else { panic!(); // bug/not-implemented } @@ -178,10 +181,10 @@ fn read_method(constant_pool: Rc>, index: &mut usize, bytecode: &[u let attributes_count = read_u16(bytecode, *index + 6); *index += 8; - let mut attributes = vec![]; + let mut attributes = HashMap::new(); for _ in 0..attributes_count { if let Some(att) = read_attribute(constant_pool.clone(), bytecode, index) { - attributes.push(att); + attributes.insert(att.0, att.1); } } @@ -194,7 +197,7 @@ fn read_method(constant_pool: Rc>, index: &mut usize, bytecode: &[u ) } -fn read_attribute(constant_pool: Rc>, bytecode: &[u8], index: &mut usize) -> Option { +fn read_attribute(constant_pool: Rc>, bytecode: &[u8], index: &mut usize) -> Option<(String, AttributeType)> { let attribute_name_index = read_u16(bytecode, *index) as usize; *index += 2; let attribute_length = read_u32(bytecode, *index) as usize; @@ -208,7 +211,7 @@ fn read_attribute(constant_pool: Rc>, bytecode: &[u8], index: &mut return match s.as_str() { "ConstantValue" => { assert_eq!(info.len(), 2); - Some(AttributeType::ConstantValue(read_u16(&info, 0))) + Some(("ConstantValue".into(), AttributeType::ConstantValue(read_u16(&info, 0)))) } "Code" => { let max_stack = read_u16(&info, 0); @@ -225,15 +228,15 @@ fn read_attribute(constant_pool: Rc>, bytecode: &[u8], index: &mut } let attribute_count = read_u16(&info, code_index); code_index += 2; - let mut code_attributes = vec![]; + let mut code_attributes = HashMap::new(); for _ in 0..attribute_count { if let Some(att) = read_attribute(constant_pool.clone(), &info, &mut code_index) { - code_attributes.push(att); + code_attributes.insert(att.0, att.1); } } - Some(AttributeType::Code(MethodCode::new(max_stack, max_locals, code, exception_table, code_attributes))) + Some(("Code".into(), AttributeType::Code(MethodCode::new(max_stack, max_locals, code, exception_table, code_attributes)))) } - "SourceFile" => Some(AttributeType::SourceFile), + "SourceFile" => Some(("SourceFile".into(), AttributeType::SourceFile)), _ => None }; } diff --git a/src/main.rs b/src/main.rs index 113026a..37a303f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,8 +4,10 @@ use std::io::Read; fn main() { let bytecode = read_class_file("./Dummy.class"); if let Some(class) = classfile_reader::get_class(bytecode){ - println!("{:?}", class); + let ret = class.execute("public static get()I"); + println!("{:?}", ret); } + } fn read_class_file(name: &str) -> Vec { diff --git a/src/opcodes.rs b/src/opcodes.rs new file mode 100644 index 0000000..1b332aa --- /dev/null +++ b/src/opcodes.rs @@ -0,0 +1,97 @@ +pub const aconst_null: u8 = 1; // (0x01) + +pub const fconst_0: u8 = 11; // (0xb) Push float 0 +pub const fconst_1: u8 = 12; // (0xc) Push float 1 +pub const fconst_2: u8 = 13; // (0xd) Push float 2 +pub const dconst_0:u8 = 14; // (0xe) push double 0 +pub const dconst_1:u8 = 15; // (0xf) push double 1 +pub const bipush:u8 = 16; // (0x10) Push byte + +pub const ldc: u8 = 18; // (0x12) Push item from run-time pub constant pool +pub const fload:u8 = 23; // (0x17) Load float from local variable +pub const dload:u8 = 24; // (0x18) load double from local variable +pub const aload:u8 = 25; //0x19 + +pub const fload_0:u8 = 34; // (0x22) Load float 0 from local variable +pub const fload_1:u8 = 35; // (0x23) Load float 1 from local variable +pub const fload_2:u8 = 36; // (0x24) Load float 2 from local variable +pub const fload_3:u8 = 37; // (0x25) Load float 3 from local variable +pub const dload_0:u8 = 38; // (0x26) Load double 0 from local variable +pub const dload_1:u8 = 39; // (0x27) Load double 1 from local variable +pub const dload_2:u8 = 40; // (0x28) Load double 2 from local variable +pub const dload_3:u8 = 41; // (0x29) Load double 3 from local variable +pub const aload_0:u8 = 42;// (0x2a) +pub const aload_1:u8 = 43;// (0x2a) +pub const aload_2:u8 = 44;// (0x2b) +pub const aload_3:u8 = 45;// (0x2c) + +pub const faload: u8 = 48; // (0x30) Load float from array +pub const daload:u8 = 49; // (0x31) load double from array +pub const aaload: u8 = 50; // (0x3d) +pub const baload: u8 = 51; //(0x33) +pub const caload: u8 = 52; // (0x34) + +pub const fstore: u8 = 56; // (0x38) Store float into local variable +pub const dstore: u8 = 57; // (0x39) store double in local variable +pub const astore:u8 = 58; // (0x3a) + +pub const dstore_0: u8 = 71; // (0x47) store double 0 in local variable +pub const dstore_1: u8 = 72; // (0x48) store double 1 in local variable +pub const dstore_2: u8 = 73; // (0x49) store double 2 in local variable +pub const dstore_3: u8 = 74; // (0x4a) store double 3 in local variable +pub const astore_0: u8 = 75; // (0x4b) +pub const astore_1: u8 = 76; // (0x4c) +pub const astore_2: u8 = 77; // (0x4d) +pub const astore_3: u8 = 78; // (0x4e) +pub const fastore: u8 = 81; // (0x51) Store into float array +pub const dastore:u8 = 82; //(0x52) store into double array +pub const aastore: u8 = 83; // (0x53) + +pub const bastore:u8 = 84; // (0x54) + +pub const castore:u8 = 85; // (0x55) +pub const dup:u8 = 89; // (0x59) duplicate the top operand stack value +pub const dup_x1: u8 = 90; // (0x5a) Duplicate the top operand stack value and insert two values down +pub const dup_x2: u8 = 91; // (0x5b) Duplicate the top operand stack value and insert two or three values down +pub const dup2: u8 = 92; // (0x5c) Duplicate the top one or two operand stack values +pub const dup2_x1: u8 = 93; //(0x5d) Duplicate the top one or two operand stack values and insert two or three values down +pub const dup2_x2:u8 = 94; // (0x5e) Duplicate the top one or two operand stack values and insert two, three, or four values down +pub const fadd: u8 = 98; // (0x62) Add float +pub const dadd: u8 = 99; // (0x63) add double + +pub const dsub:u8 = 103; // (0x67) subtract double +pub const fmul: u8 = 106; // (0x6a) Multiply float +pub const dmul: u8 = 107; // (0x6b) Multiply double + +pub const fdiv: u8 = 110; // (0x6e) Divide float +pub const ddiv:u8 = 111; // (0x6f) divide double +pub const frem: u8 = 114; // (0x72) Remainder float +pub const drem: u8 = 115; // (0x73) remainder double +pub const fneg: u8 = 118; // (0x76) Negate float +pub const dneg: u8 = 119; // (0x77) Negate double +pub const f2i: u8 = 139; // (0x8b) Convert float to int +pub const f2l: u8 = 140; // (0x8c) Convert float to long +pub const f2d: u8 = 141; // (0x8d) Convert float to double +pub const d2i:u8 = 142; // (0x8e) double to int +pub const d2l:u8 = 143; // (0x8f) double to long +pub const d2f: u8 = 144; // (0x90) double to float +pub const fcmpl:u8 = 149; // (0x95) Compare float (less than) +pub const fcmpg: u8 = 150; // (0x96) Compare float (greater than) +pub const dcmpl:u8 = 151; // (0x97) compare double (less than) +pub const dcmpg:u8 = 152; // (0x98) compare double (greater than) + +pub const ireturn: u8 = 172; // (0xac) ireturn +pub const freturn: u8 = 174; // (0xae) Return float from method +pub const dreturn: u8 = 175; // (0xaf) Return double from method +pub const areturn: u8 = 176; //(0xb0) return reference +pub const return_v: u8 = 177; // (0xb1) Return void from method (actually 'return' but that's a keyword) +pub const invokevirtual: u8 = 182; // (0xb6) Invoke instance method; dispatch based on class + +pub const getstatic: u8 = 178; // (0xb2) Get static field from class +pub const anewarray: u8 = 189; // (0xbd) + +pub const arraylength: u8 = 190; // (0xbe) + +pub const athrow: u8 = 191; // (0xbf) + +pub const checkcast: u8 = 192; // (0xc0) diff --git a/src/types.rs b/src/types.rs index dd1999a..ab7daff 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,5 +1,6 @@ +use std::collections::HashMap; use std::rc::Rc; -use crate::CpEntry; +use crate::{CpEntry, opcodes}; #[derive(Debug)] //TODO create factory function @@ -12,14 +13,19 @@ pub struct Class { pub super_class: u16, pub interfaces: Vec, pub fields: Vec, - pub methods: Vec, - pub attributes: Vec, + pub methods: HashMap, + pub attributes: HashMap, } impl Class { pub fn get_version(&self) -> (u16, u16) { (self.major_version, self.minor_version) } + + pub fn execute(&self, method_name: &str) -> Value { + let m = self.methods.get(method_name).unwrap(); + m.execute().unwrap() //TODO remove unwrap + } } pub struct Method { @@ -27,7 +33,7 @@ pub struct Method { access_flags: u16, name_index: usize, descriptor_index: usize, - attributes: Vec, + attributes: HashMap, } impl fmt::Debug for Method { @@ -42,7 +48,7 @@ impl Method { access_flags: u16, name_index: usize, descriptor_index: usize, - attributes: Vec, ) -> Self { + attributes: HashMap, ) -> Self { Method { constant_pool, access_flags, name_index, descriptor_index, attributes } } @@ -59,16 +65,29 @@ impl Method { full_name } - // pub fn get_code(&self) { - // for att in &self.attributes { - // if let CpEntry::Utf8(_, str) = &self.constant_pool[&att.attribute_name_index - 1] { - // println!("{}", str); - // if str == "Code" { - // println!("{:?}", att.info); - // } - // } - // } - // } + pub fn execute(&self) -> Option { + if let AttributeType::Code(code) = self.attributes.get("Code").unwrap() { + let mut stack = Stack::new(); + let mut pc: usize = 0; + while pc < code.opcodes.len() { + let opcode = &code.opcodes[pc]; + match opcode { + &opcodes::bipush => { + pc += 1; + let c = code.opcodes[pc] as i32; + stack.push(Value::I32(c)); + }, + &opcodes::ireturn => { + return stack.pop(); + }, + //TODO implement all opcodes + _ => {} + } + pc += 1; + } + } + None // TODO error situation + } } pub struct Field { @@ -76,10 +95,11 @@ pub struct Field { access_flags: u16, name_index: usize, descriptor_index: usize, - attributes: Vec, + attributes: HashMap, } use std::fmt; +use std::hash::Hash; use crate::io::read_u16; impl fmt::Debug for Field { @@ -94,7 +114,7 @@ impl Field { access_flags: u16, name_index: usize, descriptor_index: usize, - attributes: Vec, ) -> Self { + attributes: HashMap, ) -> Self { Field { constant_pool, access_flags, name_index, descriptor_index, attributes: attributes } } @@ -193,16 +213,42 @@ impl Exception { pub struct MethodCode { max_stack: u16, max_locals: u16, - code: Vec, + opcodes: Vec, exception_table: Vec, - code_attributes: Vec, + code_attributes: HashMap, } impl MethodCode { pub(crate) fn new(max_stack: u16, max_locals: u16, code: Vec, exception_table: Vec, - code_attributes: Vec) -> Self { - Self { max_stack, max_locals, code, exception_table, code_attributes } + code_attributes: HashMap) -> Self { + Self { max_stack, max_locals, opcodes: code, exception_table, code_attributes } } +} + +struct Stack { + data: Vec, +} + +impl Stack { + fn new() -> Self { + Self { + data: vec![] + } + } + + fn push(&mut self, val: Value) { + self.data.push(val); + } + + fn pop(&mut self) -> Option { + self.data.pop() + } +} + +#[derive(Debug)] +pub enum Value { + Void, + I32(i32), } \ No newline at end of file