From 089ba025ea2911cceda6190e30f107b4b5579e73 Mon Sep 17 00:00:00 2001 From: Sander Hautvast Date: Tue, 26 Sep 2023 18:56:16 +0200 Subject: [PATCH] added ldc variants --- src/io.rs | 4 + src/lib.rs | 8 +- src/opcodes.rs | 192 +++++++++++++++++++++---------------------- src/types.rs | 57 ++++++++++--- tests/Float.class | Bin 0 -> 282 bytes tests/Float.java | 8 ++ tests/class_tests.rs | 12 ++- 7 files changed, 170 insertions(+), 111 deletions(-) create mode 100644 tests/Float.class create mode 100644 tests/Float.java diff --git a/src/io.rs b/src/io.rs index e0916ac..d4b8c65 100644 --- a/src/io.rs +++ b/src/io.rs @@ -1,6 +1,10 @@ use std::fs::{self, File}; use std::io::Read; +pub(crate) fn read_u8(data: &[u8], pos: usize) -> u8 { + u8::from_be_bytes(data[pos..pos + 1].try_into().expect("slice with incorrect length")) +} + pub(crate) fn read_u16(data: &[u8], pos: usize) -> u16 { u16::from_be_bytes(data[pos..pos + 2].try_into().expect("slice with incorrect length")) } diff --git a/src/lib.rs b/src/lib.rs index 1cabfc5..230b54b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,12 +11,12 @@ pub fn get_class(bytecode: Vec) -> Option { check_magic(&bytecode); let constant_pool_count = read_u16(&bytecode, 8); - println!("cp count: {}", constant_pool_count); + // println!("cp count: {}", constant_pool_count); let mut index = 10; let mut constant_pool: HashMap = HashMap::with_capacity(constant_pool_count as usize); let mut cp_index = 1; while cp_index < constant_pool_count as usize { - println!("cp#{}", cp_index); + // println!("cp#{}", cp_index); constant_pool.insert(cp_index, read_constant_pool_entry(&mut cp_index, &mut index, &bytecode)); cp_index += 1; } @@ -28,7 +28,7 @@ pub fn get_class(bytecode: Vec) -> Option { let super_class = read_u16(&bytecode, index + 4); let interfaces_count = read_u16(&bytecode, index + 6); - println!("interfaces count: {}", interfaces_count); + // println!("interfaces count: {}", interfaces_count); index += 8; let mut interfaces = vec![]; for _ in 0..interfaces_count { @@ -85,7 +85,7 @@ fn check_magic(bytecode: &[u8]) { fn read_constant_pool_entry(cp_index: &mut usize, index: &mut usize, bytecode: &[u8]) -> CpEntry { let tag = bytecode[*index]; - println!("#{}: {}", cp_index, tag); + // println!("#{}: {}", cp_index, tag); match tag { 1 => { let len = read_u16(bytecode, *index + 1) as usize; diff --git a/src/opcodes.rs b/src/opcodes.rs index 99fe366..79da924 100644 --- a/src/opcodes.rs +++ b/src/opcodes.rs @@ -1,97 +1,97 @@ -pub const aconst_null: u8 = 1; // (0x01) +// 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 LDC_W: u8 = 19; // (0x13) Push item from run-time constant pool (wide index) +pub const LDC2_W: u8 = 20; // (0x14) Push long or double from run-time constant pool (wide index) +// 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 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 ldc2_w:u8 = 20; // (0x14) Push long or double from run-time constant pool (wide index) -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) +// 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 85094b3..e734b86 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,10 +1,9 @@ use std::collections::HashMap; use std::fmt; -use std::hash::Hash; use std::rc::Rc; use crate::{CpEntry, opcodes}; -use crate::io::read_u16; +use crate::io::{read_u8, read_u16}; #[derive(Debug)] //TODO create factory function @@ -76,30 +75,66 @@ impl Method { while pc < code.opcodes.len() { let opcode = &code.opcodes[pc]; pc += 1; - println!("{}", opcode); + // println!("{}", opcode); match opcode { - &opcodes::bipush => { + &opcodes::BIPUSH => { let c = code.opcodes[pc] as i32; stack.push(Value::I32(c)); pc += 1; } - &opcodes::ldc2_w => { + &opcodes::LDC => { + let cp_index = read_u8(&code.opcodes, pc) as usize; + match self.constant_pool.get(&cp_index).unwrap() { + CpEntry::Integer(i) => { + stack.push(Value::I32(*i)); + } + CpEntry::Float(f) => { + stack.push(Value::F32(*f)); + } + _ => {} + } + pc += 1; + } + &opcodes::LDC_W => { let cp_index = read_u16(&code.opcodes, pc) as usize; - if let CpEntry::Double(d) = self.constant_pool.get(&cp_index).unwrap() { - stack.push(Value::F64(*d)); + match self.constant_pool.get(&cp_index).unwrap() { + CpEntry::Integer(i) => { + stack.push(Value::I32(*i)); + } + CpEntry::Float(f) => { + stack.push(Value::F32(*f)); + } + _ => { panic!("unexpected") } } pc += 2; } - &opcodes::ireturn => { + &opcodes::LDC2_W => { + let cp_index = read_u16(&code.opcodes, pc) as usize; + match self.constant_pool.get(&cp_index).unwrap() { + CpEntry::Double(d) => { + stack.push(Value::F64(*d)); + } + CpEntry::Long(l) => { + stack.push(Value::I64(*l)); + } + _ => { panic!("unexpected") } + } + + + pc += 2; + } + &opcodes::IRETURN => { return stack.pop(); } - &opcodes::dreturn => { + &opcodes::DRETURN => { + return stack.pop(); + } + &opcodes::FRETURN => { return stack.pop(); } //TODO implement all opcodes _ => { panic!("opcode not implemented") } } - } } None // TODO error situation @@ -263,5 +298,7 @@ impl Stack { pub enum Value { Void, I32(i32), + I64(i64), + F32(f32), F64(f64), } \ No newline at end of file diff --git a/tests/Float.class b/tests/Float.class new file mode 100644 index 0000000000000000000000000000000000000000..0f1d35d99b1612f583096bc955cbc2742e30952b GIT binary patch literal 282 zcmZ9Gv2MaZ5JYEvHUBnN_{g@n^YE+A~fD}otp(g#IGsA zU6n_s;X2o9Q+;IWx|dnOM4XkWO?)HRmDTm2lH4wWq$s7CUF4_ipotd2s|lfJ*}RbY zJl|#)bugH~;l}{N5FQ$=K2Ht=7uhiPfXSGZSiR{F=(`TIx!ZsZx6nbC)mle214Jag Mo{ZN1!puSV05QHP@c;k- literal 0 HcmV?d00001 diff --git a/tests/Float.java b/tests/Float.java new file mode 100644 index 0000000..bbf3d48 --- /dev/null +++ b/tests/Float.java @@ -0,0 +1,8 @@ +public class Float { + + private final static float f =42.0F; + + public static float get() { + return f; + } +} diff --git a/tests/class_tests.rs b/tests/class_tests.rs index 5b8a3d7..cc2fb49 100644 --- a/tests/class_tests.rs +++ b/tests/class_tests.rs @@ -1,6 +1,5 @@ mod test { use classfile_reader::{get_class, io}; - use classfile_reader::CpEntry::*; use classfile_reader::types::Value; #[test] @@ -24,4 +23,15 @@ mod test { panic!("fail"); } } + + #[test] + fn get_constant_foat() { + let class = get_class(io::read_class_file("tests/Float.class")).unwrap(); + assert_eq!((55, 0), class.get_version()); + if let Value::F32(v) = class.methods.get("public static get()F").unwrap().execute().unwrap() { + assert_eq!(v, 42.0); + } else { + panic!("fail"); + } + } } \ No newline at end of file