added ldc variants

This commit is contained in:
Sander Hautvast 2023-09-26 18:56:16 +02:00
parent 0fbe00c157
commit 089ba025ea
7 changed files with 170 additions and 111 deletions

View file

@ -1,6 +1,10 @@
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::Read; 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 { 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")) u16::from_be_bytes(data[pos..pos + 2].try_into().expect("slice with incorrect length"))
} }

View file

@ -11,12 +11,12 @@ pub fn get_class(bytecode: Vec<u8>) -> Option<Class> {
check_magic(&bytecode); check_magic(&bytecode);
let constant_pool_count = read_u16(&bytecode, 8); 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 index = 10;
let mut constant_pool: HashMap<usize, CpEntry> = HashMap::with_capacity(constant_pool_count as usize); let mut constant_pool: HashMap<usize, CpEntry> = HashMap::with_capacity(constant_pool_count as usize);
let mut cp_index = 1; let mut cp_index = 1;
while cp_index < constant_pool_count as usize { 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)); constant_pool.insert(cp_index, read_constant_pool_entry(&mut cp_index, &mut index, &bytecode));
cp_index += 1; cp_index += 1;
} }
@ -28,7 +28,7 @@ pub fn get_class(bytecode: Vec<u8>) -> Option<Class> {
let super_class = read_u16(&bytecode, index + 4); let super_class = read_u16(&bytecode, index + 4);
let interfaces_count = read_u16(&bytecode, index + 6); let interfaces_count = read_u16(&bytecode, index + 6);
println!("interfaces count: {}", interfaces_count); // println!("interfaces count: {}", interfaces_count);
index += 8; index += 8;
let mut interfaces = vec![]; let mut interfaces = vec![];
for _ in 0..interfaces_count { 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 { fn read_constant_pool_entry(cp_index: &mut usize, index: &mut usize, bytecode: &[u8]) -> CpEntry {
let tag = bytecode[*index]; let tag = bytecode[*index];
println!("#{}: {}", cp_index, tag); // println!("#{}: {}", cp_index, tag);
match tag { match tag {
1 => { 1 => {
let len = read_u16(bytecode, *index + 1) as usize; let len = read_u16(bytecode, *index + 1) as usize;

View file

@ -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 faload: u8 = 48; // (0x30) Load float from array
pub const fconst_1: u8 = 12; // (0xc) Push float 1 // pub const daload:u8 = 49; // (0x31) load double from array
pub const fconst_2: u8 = 13; // (0xd) Push float 2 // pub const aaload: u8 = 50; // (0x3d)
pub const dconst_0:u8 = 14; // (0xe) push double 0 // pub const baload: u8 = 51; //(0x33)
pub const dconst_1:u8 = 15; // (0xf) push double 1 // pub const caload: u8 = 52; // (0x34)
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 fstore: u8 = 56; // (0x38) Store float into local variable
pub const ldc: u8 = 18; // (0x12) Push item from run-time pub constant pool // pub const dstore: u8 = 57; // (0x39) store double in local variable
pub const fload:u8 = 23; // (0x17) Load float from local variable // pub const astore:u8 = 58; // (0x3a)
pub const dload:u8 = 24; // (0x18) load double from local variable //
pub const aload:u8 = 25; //0x19 // 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 fload_0:u8 = 34; // (0x22) Load float 0 from local variable // pub const dstore_2: u8 = 73; // (0x49) store double 2 in local variable
pub const fload_1:u8 = 35; // (0x23) Load float 1 from local variable // pub const dstore_3: u8 = 74; // (0x4a) store double 3 in local variable
pub const fload_2:u8 = 36; // (0x24) Load float 2 from local variable // pub const astore_0: u8 = 75; // (0x4b)
pub const fload_3:u8 = 37; // (0x25) Load float 3 from local variable // pub const astore_1: u8 = 76; // (0x4c)
pub const dload_0:u8 = 38; // (0x26) Load double 0 from local variable // pub const astore_2: u8 = 77; // (0x4d)
pub const dload_1:u8 = 39; // (0x27) Load double 1 from local variable // pub const astore_3: u8 = 78; // (0x4e)
pub const dload_2:u8 = 40; // (0x28) Load double 2 from local variable // pub const fastore: u8 = 81; // (0x51) Store into float array
pub const dload_3:u8 = 41; // (0x29) Load double 3 from local variable // pub const dastore:u8 = 82; //(0x52) store into double array
pub const aload_0:u8 = 42;// (0x2a) // pub const aastore: u8 = 83; // (0x53)
pub const aload_1:u8 = 43;// (0x2a) //
pub const aload_2:u8 = 44;// (0x2b) // pub const bastore:u8 = 84; // (0x54)
pub const aload_3:u8 = 45;// (0x2c) //
// pub const castore:u8 = 85; // (0x55)
pub const faload: u8 = 48; // (0x30) Load float from array // pub const dup:u8 = 89; // (0x59) duplicate the top operand stack value
pub const daload:u8 = 49; // (0x31) load double from array // pub const dup_x1: u8 = 90; // (0x5a) Duplicate the top operand stack value and insert two values down
pub const aaload: u8 = 50; // (0x3d) // pub const dup_x2: u8 = 91; // (0x5b) Duplicate the top operand stack value and insert two or three values down
pub const baload: u8 = 51; //(0x33) // pub const dup2: u8 = 92; // (0x5c) Duplicate the top one or two operand stack values
pub const caload: u8 = 52; // (0x34) // 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 fstore: u8 = 56; // (0x38) Store float into local variable // pub const fadd: u8 = 98; // (0x62) Add float
pub const dstore: u8 = 57; // (0x39) store double in local variable // pub const dadd: u8 = 99; // (0x63) add double
pub const astore:u8 = 58; // (0x3a) //
// pub const dsub:u8 = 103; // (0x67) subtract double
pub const dstore_0: u8 = 71; // (0x47) store double 0 in local variable // pub const fmul: u8 = 106; // (0x6a) Multiply float
pub const dstore_1: u8 = 72; // (0x48) store double 1 in local variable // pub const dmul: u8 = 107; // (0x6b) Multiply double
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 fdiv: u8 = 110; // (0x6e) Divide float
pub const astore_0: u8 = 75; // (0x4b) // pub const ddiv:u8 = 111; // (0x6f) divide double
pub const astore_1: u8 = 76; // (0x4c) // pub const frem: u8 = 114; // (0x72) Remainder float
pub const astore_2: u8 = 77; // (0x4d) // pub const drem: u8 = 115; // (0x73) remainder double
pub const astore_3: u8 = 78; // (0x4e) // pub const fneg: u8 = 118; // (0x76) Negate float
pub const fastore: u8 = 81; // (0x51) Store into float array // pub const dneg: u8 = 119; // (0x77) Negate double
pub const dastore:u8 = 82; //(0x52) store into double array // pub const f2i: u8 = 139; // (0x8b) Convert float to int
pub const aastore: u8 = 83; // (0x53) // pub const f2l: u8 = 140; // (0x8c) Convert float to long
// pub const f2d: u8 = 141; // (0x8d) Convert float to double
pub const bastore:u8 = 84; // (0x54) // pub const d2i:u8 = 142; // (0x8e) double to int
// pub const d2l:u8 = 143; // (0x8f) double to long
pub const castore:u8 = 85; // (0x55) // pub const d2f: u8 = 144; // (0x90) double to float
pub const dup:u8 = 89; // (0x59) duplicate the top operand stack value // pub const fcmpl:u8 = 149; // (0x95) Compare float (less than)
pub const dup_x1: u8 = 90; // (0x5a) Duplicate the top operand stack value and insert two values down // pub const fcmpg: u8 = 150; // (0x96) Compare float (greater than)
pub const dup_x2: u8 = 91; // (0x5b) Duplicate the top operand stack value and insert two or three values down // pub const dcmpl:u8 = 151; // (0x97) compare double (less than)
pub const dup2: u8 = 92; // (0x5c) Duplicate the top one or two operand stack values // pub const dcmpg:u8 = 152; // (0x98) compare double (greater than)
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 IRETURN: u8 = 172; // (0xac) ireturn
pub const fadd: u8 = 98; // (0x62) Add float pub const FRETURN: u8 = 174; // (0xae) Return float from method
pub const dadd: u8 = 99; // (0x63) add double pub const DRETURN: u8 = 175; // (0xaf) Return double from method
// pub const areturn: u8 = 176; //(0xb0) return reference
pub const dsub:u8 = 103; // (0x67) subtract double // pub const return_v: u8 = 177; // (0xb1) Return void from method (actually 'return' but that's a keyword)
pub const fmul: u8 = 106; // (0x6a) Multiply float // pub const invokevirtual: u8 = 182; // (0xb6) Invoke instance method; dispatch based on class
pub const dmul: u8 = 107; // (0x6b) Multiply double //
// pub const getstatic: u8 = 178; // (0xb2) Get static field from class
pub const fdiv: u8 = 110; // (0x6e) Divide float // pub const anewarray: u8 = 189; // (0xbd)
pub const ddiv:u8 = 111; // (0x6f) divide double //
pub const frem: u8 = 114; // (0x72) Remainder float // pub const arraylength: u8 = 190; // (0xbe)
pub const drem: u8 = 115; // (0x73) remainder double //
pub const fneg: u8 = 118; // (0x76) Negate float // pub const athrow: u8 = 191; // (0xbf)
pub const dneg: u8 = 119; // (0x77) Negate double //
pub const f2i: u8 = 139; // (0x8b) Convert float to int // pub const checkcast: u8 = 192; // (0xc0)
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)

View file

@ -1,10 +1,9 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::hash::Hash;
use std::rc::Rc; use std::rc::Rc;
use crate::{CpEntry, opcodes}; use crate::{CpEntry, opcodes};
use crate::io::read_u16; use crate::io::{read_u8, read_u16};
#[derive(Debug)] #[derive(Debug)]
//TODO create factory function //TODO create factory function
@ -76,30 +75,66 @@ impl Method {
while pc < code.opcodes.len() { while pc < code.opcodes.len() {
let opcode = &code.opcodes[pc]; let opcode = &code.opcodes[pc];
pc += 1; pc += 1;
println!("{}", opcode); // println!("{}", opcode);
match opcode { match opcode {
&opcodes::bipush => { &opcodes::BIPUSH => {
let c = code.opcodes[pc] as i32; let c = code.opcodes[pc] as i32;
stack.push(Value::I32(c)); stack.push(Value::I32(c));
pc += 1; 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; let cp_index = read_u16(&code.opcodes, pc) as usize;
if let CpEntry::Double(d) = self.constant_pool.get(&cp_index).unwrap() { match self.constant_pool.get(&cp_index).unwrap() {
stack.push(Value::F64(*d)); CpEntry::Integer(i) => {
stack.push(Value::I32(*i));
}
CpEntry::Float(f) => {
stack.push(Value::F32(*f));
}
_ => { panic!("unexpected") }
} }
pc += 2; 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(); return stack.pop();
} }
&opcodes::dreturn => { &opcodes::DRETURN => {
return stack.pop();
}
&opcodes::FRETURN => {
return stack.pop(); return stack.pop();
} }
//TODO implement all opcodes //TODO implement all opcodes
_ => { panic!("opcode not implemented") } _ => { panic!("opcode not implemented") }
} }
} }
} }
None // TODO error situation None // TODO error situation
@ -263,5 +298,7 @@ impl Stack {
pub enum Value { pub enum Value {
Void, Void,
I32(i32), I32(i32),
I64(i64),
F32(f32),
F64(f64), F64(f64),
} }

BIN
tests/Float.class Normal file

Binary file not shown.

8
tests/Float.java Normal file
View file

@ -0,0 +1,8 @@
public class Float {
private final static float f =42.0F;
public static float get() {
return f;
}
}

View file

@ -1,6 +1,5 @@
mod test { mod test {
use classfile_reader::{get_class, io}; use classfile_reader::{get_class, io};
use classfile_reader::CpEntry::*;
use classfile_reader::types::Value; use classfile_reader::types::Value;
#[test] #[test]
@ -24,4 +23,15 @@ mod test {
panic!("fail"); 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");
}
}
} }