fixed jumping

This commit is contained in:
Shautvast 2023-11-26 19:08:52 +01:00
parent 715fa29cfd
commit dae02cec32
2 changed files with 154 additions and 23 deletions

View file

@ -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<Opcode> {
let mut code: BTreeMap<u16, (u16, Opcode)> = 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<Opcode> {
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
}

View file

@ -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<Stackframe>,
}
@ -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<u16, CpEntry>, 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;