diff --git a/src/classloader/code_parser.rs b/src/classloader/code_parser.rs index cefdb7d..e60908f 100644 --- a/src/classloader/code_parser.rs +++ b/src/classloader/code_parser.rs @@ -1,4 +1,5 @@ use std::collections::{BTreeMap}; +use log::debug; use crate::classloader::io::{read_i16, read_i32, read_lookupswitch, read_tableswitch, read_u16, read_u8, read_wide_opcode}; use crate::vm::opcodes::Opcode::{self, *}; @@ -7,14 +8,17 @@ pub(crate) fn parse_code(opcodes: &[u8]) -> Vec { let mut code: BTreeMap = BTreeMap::new(); let mut c = 0; let mut opcode_index: u16 = 0; + let mut index_before_read: u16; while c < opcodes.len() { + index_before_read = c as u16; let opcode = get_opcode(opcodes, &mut c); - code.insert(c as u16, (opcode_index, opcode)); + code.insert(index_before_read, (opcode_index, opcode)); opcode_index += 1; } let code2 = code.clone(); //clone to look up // for jumps, map index of opcode as u8 to index of opcode as enum + debug!("{:?}", code); code.into_iter().map(|(_, (_, opcode))| match opcode { IFNULL(goto) => { @@ -23,6 +27,44 @@ pub(crate) fn parse_code(opcodes: &[u8]) -> Vec { IFNONNULL(goto) => { IFNONNULL(code2.get(&goto).unwrap().0) } + + IF_ICMPEQ(goto) => { + IF_ICMPEQ(code2.get(&goto).unwrap().0) + } + IF_ICMPNE(goto) => { + IF_ICMPNE(code2.get(&goto).unwrap().0) + } + IF_ICMPGT(goto) => { + IF_ICMPGT(code2.get(&goto).unwrap().0) + } + IF_ICMPGE(goto) => { + IF_ICMPGE(code2.get(&goto).unwrap().0) + } + IF_ICMPLT(goto) => { + IF_ICMPLT(code2.get(&goto).unwrap().0) + } + IF_ICMPLE(goto) => { + IF_ICMPLE(code2.get(&goto).unwrap().0) + } + IFEQ(goto) => { + IFEQ(code2.get(&goto).unwrap().0) + } + IFNE(goto) => { + IFNE(code2.get(&goto).unwrap().0) + } + IFGT(goto) => { + IFGT(code2.get(&goto).unwrap().0) + } + IFGE(goto) => { + IFGE(code2.get(&goto).unwrap().0) + } + IFLT(goto) => { + IFLT(code2.get(&goto).unwrap().0) + } + IFLE(goto) => { + IFLE(code2.get(&goto).unwrap().0) + } + //TODO more jump instructions _ => opcode } @@ -184,20 +226,20 @@ fn get_opcode(opcodes: &[u8], c: &mut usize) -> Opcode { 150 => FCMPG, 151 => DCMPL, 152 => DCMPG, - 153 => IFEQ(read_u16(opcodes, c)), - 154 => IFNE(read_u16(opcodes, c)), - 155 => IFLT(read_u16(opcodes, c)), - 156 => IFGE(read_u16(opcodes, c)), - 157 => IFGT(read_u16(opcodes, c)), - 158 => IFLE(read_u16(opcodes, c)), - 159 => IF_ICMPEQ(read_u16(opcodes, c)), - 160 => IF_ICMPNE(read_u16(opcodes, c)), - 161 => IF_ICMPLT(read_u16(opcodes, c)), - 162 => IF_ICMPGE(read_u16(opcodes, c)), - 163 => IF_ICMPGT(read_u16(opcodes, c)), - 164 => IF_ICMPLE(read_u16(opcodes, c)), - 165 => IF_ACMPEQ(read_u16(opcodes, c)), - 166 => IF_ACMPNE(read_u16(opcodes, c)), + 153 => IFEQ(offset(opcodes, c)), + 154 => IFNE(offset(opcodes, c)), + 155 => IFLT(offset(opcodes, c)), + 156 => IFGE(offset(opcodes, c)), + 157 => IFGT(offset(opcodes, c)), + 158 => IFLE(offset(opcodes, c)), + 159 => IF_ICMPEQ(offset(opcodes, c)), + 160 => IF_ICMPNE(offset(opcodes, c)), + 161 => IF_ICMPLT(offset(opcodes, c)), + 162 => IF_ICMPGE(offset(opcodes, c)), + 163 => IF_ICMPGT(offset(opcodes, c)), + 164 => IF_ICMPLE(offset(opcodes, c)), + 165 => IF_ACMPEQ(offset(opcodes, c)), + 166 => IF_ACMPNE(offset(opcodes, c)), 167 => GOTO(read_u16(opcodes, c)), 168 => JSR(read_u16(opcodes, c)), 169 => RET(read_u8(opcodes, c)), @@ -239,19 +281,22 @@ fn get_opcode(opcodes: &[u8], c: &mut usize) -> Opcode { 196 => WIDE(Box::new(read_wide_opcode(opcodes, c))), 197 => MULTIANEWARRAY(read_u16(opcodes, c), read_u8(opcodes, c)), 198 => { - let j = read_i16(opcodes, c); - IFNULL((*c as i16 + j - 3) as u16) + IFNULL(offset(opcodes, c)) } 199 => { - let j = read_i16(opcodes, c); - IFNONNULL((*c as i16 + j - 3) as u16) + IFNONNULL(offset(opcodes, c)) } 200 => GOTOW(read_i32(opcodes, c)), 201 => JSR_W(read_i32(opcodes, c)), - _ => panic!("{}", opcode_u8), }; - + debug!("{}: {:?}", c, opcode); opcode +} + +fn offset(opcodes: &[u8], c: &mut usize) -> u16 { + let j = read_i16(opcodes, c); + debug!("JUMP TO {} + {}",c, j); + (*c as i16 + j - 3) as u16 } \ No newline at end of file diff --git a/src/vm/runtime.rs b/src/vm/runtime.rs index 46b7b7a..b27f95e 100644 --- a/src/vm/runtime.rs +++ b/src/vm/runtime.rs @@ -10,7 +10,7 @@ use crate::classloader::classdef::{CpEntry, Modifier}; use crate::classloader::io::PATH_SEPARATOR; use crate::classmanager::ClassManager; use crate::value::Value::{self, *}; -use crate::vm::array::array_load; +use crate::vm::array::{array_load, array_store}; use crate::vm::object; use crate::vm::object::ObjectRef; use crate::vm::object::ObjectRef::Object; @@ -19,6 +19,8 @@ use crate::vm::opcodes::Opcode::*; use std::io::Write; use crate::vm::native::invoke_native; +const MASK_LOWER_5BITS: i32 = 0b00011111; + pub struct Vm { pub stack: Vec, } @@ -99,6 +101,7 @@ impl Stackframe { while self.pc < len { let opcode: &Opcode = code.get(self.pc).unwrap(); debug!("\tat {}.{}: {} #{:?} - {:?}", classname, method_name, self.pc, opcode, self.stack); + self.pc += 1; match opcode { NOP => {} ACONST_NULL => { @@ -175,6 +178,64 @@ impl Stackframe { ISTORE(c) | LSTORE(c) | FSTORE(c) | DSTORE(c) | ASTORE(c) => { self.store(*c).unwrap(); } + BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE + | AASTORE => { + let value = self.pop(); + let index = self.pop(); + let arrayref = self.pop(); + array_store(value, index, arrayref).unwrap()//TODO + } + POP => { + self.pop(); + } + DUP => { + let value = self.pop(); + self.push(value.clone()); + self.push(value); + } + IADD => { + let value2 = self.pop(); + let value1 = self.pop(); + debug!("{:?}+{:?}", value1, value2); + self.push(I32(value1.into_i32() + value2.into_i32())); + } + ISUB => { + let value2 = self.pop(); + let value1 = self.pop(); + debug!("{:?}-{:?}", value1, value2); + self.push(I32(value1.into_i32() - value2.into_i32())); + } + IDIV => { + let value2 = self.pop(); + let value1 = self.pop(); + self.push(I32(value1.into_i32() / value2.into_i32())); + } + ISHL => { + let value2 = self.pop(); + let value1 = self.pop(); + debug!("{:?} shl {:?}", value1, value2); + self.push(I32(value1.into_i32() << (value2.into_i32() & MASK_LOWER_5BITS))); + } + ISHR => { + let value2 = self.pop(); + let value1 = self.pop(); + debug!("{:?} shr {:?}", value1, value2); + self.push(I32(value1.into_i32() >> (value2.into_i32() & MASK_LOWER_5BITS))); + } + IFEQ(jmp_to) | IFNE(jmp_to) | IFLT(jmp_to) | IFGE(jmp_to) | IFGT(jmp_to) | IFLE(jmp_to) => { + let value = self.pop(); + if_cmp(&mut self.pc, opcode, jmp_to, &value, &I32(0)); + } + + IF_ICMPEQ(jmp_to) | IF_ICMPNE(jmp_to) | IF_ICMPGT(jmp_to) | IF_ICMPGE(jmp_to) | IF_ICMPLT(jmp_to) | IF_ICMPLE(jmp_to) => { + let value1 = self.pop(); + let value2 = self.pop(); + if_cmp(&mut self.pc, opcode, jmp_to, &value1, &value2); + } + GOTO(jmp_to) => { + self.pc += *jmp_to as usize; + // debug!("GOTO {}", *pc) + } INVOKEVIRTUAL(c) => { if let Some(invocation) = get_signature_for_invoke(&constant_pool, *c) @@ -391,6 +452,10 @@ impl Stackframe { unreachable!("array length {:?}", val); } } + ATHROW => { + let value = self.pop(); + panic!("{:?}", value); + } MONITORENTER | MONITOREXIT => { self.pop(); } //TODO implement @@ -414,7 +479,6 @@ impl Stackframe { } _ => { panic!("opcode not implemented") } } - self.pc += 1; } Void } @@ -465,6 +529,28 @@ pub(crate) fn get_name_and_type(cp: &HashMap, index: u16) -> Optio None } +fn if_cmp(pc: &mut usize, opcode: &Opcode, jmp_to: &u16, value1: &Value, value2: &Value) { + if let I32(value1) = value1 { + if let I32(value2) = value2 { + let jump = match opcode { + IF_ICMPEQ(_) | IFEQ(_) => value1 == value2, + IF_ICMPNE(_) | IFNE(_) => value1 != value2, + IF_ICMPGT(_) | IFGT(_) => value1 > value2, + IF_ICMPGE(_) | IFGE(_) => value1 >= value2, + IF_ICMPLT(_) | IFLT(_) => value1 < value2, + IF_ICMPLE(_) | IFLE(_) => value1 <= value2, + _ => false, + }; + if jump { + debug!("\t\tIF({}) JMP {}", jump, *jmp_to as usize); + *pc = *jmp_to as usize; + } else { + debug!("\t\tIF({}) NO JMP", jump); + } + } + } +} + fn get_num_args(signature: &str) -> usize { let mut num = 0; let mut i = 1;