From 769800ff71c5f1bc8b1565e85f49fca85e2df7b5 Mon Sep 17 00:00:00 2001 From: Shautvast Date: Sun, 5 Nov 2023 09:09:44 +0100 Subject: [PATCH] bug fix array arg --- src/classloader/mod.rs | 5 ++-- src/classmanager.rs | 7 ++++-- src/lib.rs | 2 +- src/vm/native.rs | 4 ++-- src/vm/opcodes.rs | 2 ++ src/vm/operations.rs | 13 +++++++++++ src/vm/vm.rs | 52 ++++++++++++++++++++---------------------- tests/method_tests.rs | 6 ++++- 8 files changed, 56 insertions(+), 35 deletions(-) diff --git a/src/classloader/mod.rs b/src/classloader/mod.rs index 17083de..57461e1 100644 --- a/src/classloader/mod.rs +++ b/src/classloader/mod.rs @@ -5,15 +5,16 @@ use std::io::Read; use std::rc::Rc; use anyhow::Error; +use log::debug; use crate::classloader::io::{find_class, read_bytes, read_f32, read_f64, read_i32, read_i64, read_u16, read_u32, read_u8}; use crate::classloader::classdef::{AttributeType, ClassDef, CpEntry, Exception, Field, Method, MethodCode}; -pub(crate) mod classdef; +pub mod classdef; pub(crate) mod io; pub(crate) fn get_classdef(classpath: &Vec, class_name: &str) -> Result { - println!("read class {} ", class_name); + debug!("read class {} ", class_name); let resolved_path = find_class(classpath, class_name)?; let bytecode = read_bytecode(resolved_path)?; load_class(bytecode) diff --git a/src/classmanager.rs b/src/classmanager.rs index 378bc1d..2661fd7 100644 --- a/src/classmanager.rs +++ b/src/classmanager.rs @@ -1,4 +1,5 @@ use std::collections::{HashMap, LinkedList}; +use log::debug; use once_cell::sync::Lazy; use crate::class::{Class, ClassId, ObjectRef, TypeIndex, Value::*, Value}; @@ -200,8 +201,8 @@ impl ClassManager { self.names.get(name) .and_then(|id| - self.classes.insert(*id, Class { - id: *id, + self.classes.insert(this_classid, Class { + id: this_classid, initialized: false, name: name.into(), superclass: superclass_id, @@ -258,6 +259,8 @@ impl ClassManager { classes_to_load.append(&mut self.load_class_and_deps(classname.as_str()).1); } } + + debug!("new class {} -> {}", name, id); id } diff --git a/src/lib.rs b/src/lib.rs index 42a3200..21e2c80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -mod classloader; +pub mod classloader; pub mod classmanager; pub mod class; pub mod vm; diff --git a/src/vm/native.rs b/src/vm/native.rs index 68eb474..8969e92 100644 --- a/src/vm/native.rs +++ b/src/vm/native.rs @@ -1,7 +1,7 @@ #![allow(non_snake_case)] use anyhow::Error; -use log::{info}; +use log::{debug, info}; use once_cell::sync::Lazy; use crate::class::{ObjectRef, Value}; @@ -12,7 +12,7 @@ use crate::vm::stack::StackFrame; use crate::vm::Vm; pub fn invoke_native(vm: &mut Vm, stackframes: &mut Vec, class_name: &String, method_name: &str, _args: Vec) -> Result { - info!("native {}.{}", class_name, method_name); + debug!("native {}.{}", class_name, method_name); match class_name.as_str() { "java/lang/Class" => java_lang_class(vm, method_name), diff --git a/src/vm/opcodes.rs b/src/vm/opcodes.rs index e1c7628..adab1ae 100644 --- a/src/vm/opcodes.rs +++ b/src/vm/opcodes.rs @@ -293,6 +293,7 @@ pub const _ATHROW: u8 = 191; pub const _CHECKCAST: u8 = 192; // (0xc0) pub const MONITORENTER: u8 = 194; +pub const MONITOREXIT: u8 = 195; pub const IFNULL: u8 = 198; pub const IFNONNULL: u8 = 199; @@ -445,6 +446,7 @@ pub const OPCODES:Lazy> = Lazy::new(|| { opcodes[_ATHROW as usize] = "_ATHROW" ; opcodes[_CHECKCAST as usize] = "_CHECKCAST" ; opcodes[MONITORENTER as usize] = "MONITORENTER" ; + opcodes[MONITOREXIT as usize] = "MONITOREXIT" ; opcodes[IFNULL as usize] = "IFNULL" ; opcodes[IFNONNULL as usize] = "IFNONNULL" ; opcodes diff --git a/src/vm/operations.rs b/src/vm/operations.rs index f949760..402ef5e 100644 --- a/src/vm/operations.rs +++ b/src/vm/operations.rs @@ -81,10 +81,23 @@ fn get_num_args(signature: &str) -> usize { num += 1; } else if chars[i] == ')' { break; + } else if chars[i] == '[' { + i += 1; } else { i += 1; num += 1; } } num +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn num_args() { + let n = get_num_args("(Ljava/nio/charset/Charset;[BII)V"); + assert_eq!(n, 4) + } } \ No newline at end of file diff --git a/src/vm/vm.rs b/src/vm/vm.rs index 69e5991..fdda18a 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -28,7 +28,6 @@ const PATH_SEPARATOR: char = ';'; //TODO goto //TODO error handling impl Vm { - /// for running static initializers pub fn new_internal() -> Self { Self {} @@ -48,12 +47,10 @@ impl Vm { fn init(vm: &mut Vm, stack: &mut Vec) { classmanager::load_class_by_name("java/lang/Class"); - Self::initialize_class(vm, stack, "java/lang/System"); + vm.execute_static(stack, "java/lang/System", "initPhase1()V", vec![]).expect("cannot create VM"); + classmanager::load_class_by_name("java/lang/String"); } - fn initialize_class(vm: &mut Vm, stack: &mut Vec, class: &str) { - vm.execute_static(stack, class, "initPhase1()V", vec![]).expect("cannot create VM"); - } fn current_frame(stackframes: &mut Vec) -> &mut StackFrame { let i = stackframes.len() - 1; @@ -74,9 +71,9 @@ impl Vm { ) -> Result { for arg in &args { if let Ref(r) = arg { - info!("arg {:?}",r); + debug!("arg {:?}",r); } else { - info!("arg {:?}",arg); + debug!("arg {:?}",arg); } } @@ -153,7 +150,7 @@ impl Vm { method_name: &str, args: Vec, ) -> Result { - info!("execute {}.{}", this_class.name, method_name); + debug!("execute {}.{}", this_class.name, method_name); //TODO implement dynamic dispatch -> get method from instance let method = classmanager::get_classdef(&this_class.id).get_method(method_name).unwrap(); @@ -170,7 +167,7 @@ impl Vm { while *pc < code.opcodes.len() { let opcode = read_u8(&code.opcodes, pc); let cur_frame = Self::current_frame(stackframes); - info!("\t{} #{} {} - {}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.len()); + debug!("\t{} #{} {} - {}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.len()); match opcode { ACONST_NULL => { Self::current_frame(stackframes).push(Value::Null); @@ -245,11 +242,9 @@ impl Vm { let stringinstance = Ref(ObjectRef::Object(Vm::new_instance(stringclass))); + debug!("class id {}", this_class.id); let string: Vec = - classmanager::get_classdef(&this_class.id).cp_utf8(utf8) - .to_owned() - .as_bytes() - .into(); + classmanager::get_classdef(&this_class.id).cp_utf8(utf8).as_bytes().into(); self.execute_special(stackframes, "java/lang/String", @@ -493,6 +488,7 @@ impl Vm { if let Some(invocation) = get_signature_for_invoke(&method.constant_pool, cp_index) { + debug!("invoke {:?}", invocation); let mut args = Vec::with_capacity(invocation.method.num_args); for _ in 0..invocation.method.num_args { args.insert(0, Self::current_frame(stackframes).pop()?.clone()); @@ -505,10 +501,10 @@ impl Vm { )?; if let Ref(objectref) = &return_value { if let ObjectRef::Object(object) = objectref { - info!("return {:?}", object); + debug!("return {:?}", object); } } else { - info!("return {:?}", return_value); + debug!("return {:?}", return_value); } match return_value { Void => {} @@ -540,10 +536,10 @@ impl Vm { )?; if let Ref(objectref) = &return_value { if let ObjectRef::Object(object) = objectref { - info!("return {:?}", object); + debug!("return {:?}", object); } } else { - info!("return {:?}", return_value); + debug!("return {:?}", return_value); } match return_value { Void => {} @@ -571,10 +567,10 @@ impl Vm { )?; if let Ref(objectref) = &return_value { if let ObjectRef::Object(object) = objectref { - info!("return {:?}", object); + debug!("return {:?}", object); } } else { - info!("return {:?}", return_value); + debug!("return {:?}", return_value); } match return_value { Void => {} @@ -622,7 +618,7 @@ impl Vm { Self::current_frame(stackframes).push(I32(val.get_array_length() as i32)); } } - MONITORENTER => { + MONITORENTER | MONITOREXIT => { Self::current_frame(stackframes).pop()?; } //TODO implement IFNULL | IFNONNULL => { @@ -631,21 +627,21 @@ impl Vm { let its_null = if let Null = value { true } else { false }; if its_null && opcode == IFNULL { - info!("\t\tIF NULL =>{}: JMP {}", its_null, *pc + jmp_to as usize); + debug!("\t\tIF NULL =>{}: JMP {}", its_null, *pc + jmp_to as usize); *pc += jmp_to as usize; } if !its_null && opcode == IFNONNULL { - info!("\t\tIF NOT NULL =>{}: JMP {}", its_null, *pc + jmp_to as usize); + debug!("\t\tIF NOT NULL =>{}: JMP {}", its_null, *pc + jmp_to as usize); *pc += jmp_to as usize; } //debug info if !its_null && opcode == IFNULL { - info!("\t\tIF NULL =>false: NO JMP"); + debug!("\t\tIF NULL =>false: NO JMP"); } if its_null && opcode == IFNONNULL { - info!("\t\tIF NONNULL =>false: NO JMP"); + debug!("\t\tIF NONNULL =>false: NO JMP"); } - }, + } //TODO implement all opcodes _ => { panic!("opcode {} not implemented {:?}", opcode, stackframes) @@ -670,10 +666,10 @@ impl Vm { _ => false, }; if jump { - info!("\t\tIF({}) JMP {}", jump, *pc + jmp_to as usize); + debug!("\t\tIF({}) JMP {}", jump, *pc + jmp_to as usize); *pc += jmp_to as usize; } else { - info!("\t\tIF({}) NO JMP", jump); + debug!("\t\tIF({}) NO JMP", jump); } } } @@ -696,6 +692,7 @@ impl Vm { } } +#[derive(Debug)] pub(crate) struct Invocation { class_name: String, method: MethodSignature, @@ -710,6 +707,7 @@ impl Invocation { } } +#[derive(Debug)] pub(crate) struct MethodSignature { name: String, num_args: usize, diff --git a/tests/method_tests.rs b/tests/method_tests.rs index 1f58d08..f3ef655 100644 --- a/tests/method_tests.rs +++ b/tests/method_tests.rs @@ -1,7 +1,7 @@ mod test { - use java_rs::class::{Method, Modifier}; use std::collections::HashMap; use std::rc::Rc; + use java_rs::classloader::classdef::{Method, Modifier}; #[test] fn access_flags() { @@ -16,4 +16,8 @@ mod test { assert!(m.is(Modifier::Static)); assert!(!m.is(Modifier::Private)); } + + + + }