bug fix array arg

This commit is contained in:
Shautvast 2023-11-05 09:09:44 +01:00
parent ceeec215e4
commit 769800ff71
8 changed files with 56 additions and 35 deletions

View file

@ -5,15 +5,16 @@ use std::io::Read;
use std::rc::Rc; use std::rc::Rc;
use anyhow::Error; 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::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}; use crate::classloader::classdef::{AttributeType, ClassDef, CpEntry, Exception, Field, Method, MethodCode};
pub(crate) mod classdef; pub mod classdef;
pub(crate) mod io; pub(crate) mod io;
pub(crate) fn get_classdef(classpath: &Vec<String>, class_name: &str) -> Result<ClassDef,Error> { pub(crate) fn get_classdef(classpath: &Vec<String>, class_name: &str) -> Result<ClassDef,Error> {
println!("read class {} ", class_name); debug!("read class {} ", class_name);
let resolved_path = find_class(classpath, class_name)?; let resolved_path = find_class(classpath, class_name)?;
let bytecode = read_bytecode(resolved_path)?; let bytecode = read_bytecode(resolved_path)?;
load_class(bytecode) load_class(bytecode)

View file

@ -1,4 +1,5 @@
use std::collections::{HashMap, LinkedList}; use std::collections::{HashMap, LinkedList};
use log::debug;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use crate::class::{Class, ClassId, ObjectRef, TypeIndex, Value::*, Value}; use crate::class::{Class, ClassId, ObjectRef, TypeIndex, Value::*, Value};
@ -200,8 +201,8 @@ impl ClassManager {
self.names.get(name) self.names.get(name)
.and_then(|id| .and_then(|id|
self.classes.insert(*id, Class { self.classes.insert(this_classid, Class {
id: *id, id: this_classid,
initialized: false, initialized: false,
name: name.into(), name: name.into(),
superclass: superclass_id, superclass: superclass_id,
@ -258,6 +259,8 @@ impl ClassManager {
classes_to_load.append(&mut self.load_class_and_deps(classname.as_str()).1); classes_to_load.append(&mut self.load_class_and_deps(classname.as_str()).1);
} }
} }
debug!("new class {} -> {}", name, id);
id id
} }

View file

@ -1,4 +1,4 @@
mod classloader; pub mod classloader;
pub mod classmanager; pub mod classmanager;
pub mod class; pub mod class;
pub mod vm; pub mod vm;

View file

@ -1,7 +1,7 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use anyhow::Error; use anyhow::Error;
use log::{info}; use log::{debug, info};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use crate::class::{ObjectRef, Value}; use crate::class::{ObjectRef, Value};
@ -12,7 +12,7 @@ use crate::vm::stack::StackFrame;
use crate::vm::Vm; use crate::vm::Vm;
pub fn invoke_native(vm: &mut Vm, stackframes: &mut Vec<StackFrame>, class_name: &String, method_name: &str, _args: Vec<Value>) -> Result<Value, Error> { pub fn invoke_native(vm: &mut Vm, stackframes: &mut Vec<StackFrame>, class_name: &String, method_name: &str, _args: Vec<Value>) -> Result<Value, Error> {
info!("native {}.{}", class_name, method_name); debug!("native {}.{}", class_name, method_name);
match class_name.as_str() { match class_name.as_str() {
"java/lang/Class" => java_lang_class(vm, method_name), "java/lang/Class" => java_lang_class(vm, method_name),

View file

@ -293,6 +293,7 @@ pub const _ATHROW: u8 = 191;
pub const _CHECKCAST: u8 = 192; pub const _CHECKCAST: u8 = 192;
// (0xc0) // (0xc0)
pub const MONITORENTER: u8 = 194; pub const MONITORENTER: u8 = 194;
pub const MONITOREXIT: u8 = 195;
pub const IFNULL: u8 = 198; pub const IFNULL: u8 = 198;
pub const IFNONNULL: u8 = 199; pub const IFNONNULL: u8 = 199;
@ -445,6 +446,7 @@ pub const OPCODES:Lazy<Vec<&str>> = Lazy::new(|| {
opcodes[_ATHROW as usize] = "_ATHROW" ; opcodes[_ATHROW as usize] = "_ATHROW" ;
opcodes[_CHECKCAST as usize] = "_CHECKCAST" ; opcodes[_CHECKCAST as usize] = "_CHECKCAST" ;
opcodes[MONITORENTER as usize] = "MONITORENTER" ; opcodes[MONITORENTER as usize] = "MONITORENTER" ;
opcodes[MONITOREXIT as usize] = "MONITOREXIT" ;
opcodes[IFNULL as usize] = "IFNULL" ; opcodes[IFNULL as usize] = "IFNULL" ;
opcodes[IFNONNULL as usize] = "IFNONNULL" ; opcodes[IFNONNULL as usize] = "IFNONNULL" ;
opcodes opcodes

View file

@ -81,6 +81,8 @@ fn get_num_args(signature: &str) -> usize {
num += 1; num += 1;
} else if chars[i] == ')' { } else if chars[i] == ')' {
break; break;
} else if chars[i] == '[' {
i += 1;
} else { } else {
i += 1; i += 1;
num += 1; num += 1;
@ -88,3 +90,14 @@ fn get_num_args(signature: &str) -> usize {
} }
num 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)
}
}

View file

@ -28,7 +28,6 @@ const PATH_SEPARATOR: char = ';';
//TODO goto //TODO goto
//TODO error handling //TODO error handling
impl Vm { impl Vm {
/// for running static initializers /// for running static initializers
pub fn new_internal() -> Self { pub fn new_internal() -> Self {
Self {} Self {}
@ -48,12 +47,10 @@ impl Vm {
fn init(vm: &mut Vm, stack: &mut Vec<StackFrame>) { fn init(vm: &mut Vm, stack: &mut Vec<StackFrame>) {
classmanager::load_class_by_name("java/lang/Class"); 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<StackFrame>, class: &str) {
vm.execute_static(stack, class, "initPhase1()V", vec![]).expect("cannot create VM");
}
fn current_frame(stackframes: &mut Vec<StackFrame>) -> &mut StackFrame { fn current_frame(stackframes: &mut Vec<StackFrame>) -> &mut StackFrame {
let i = stackframes.len() - 1; let i = stackframes.len() - 1;
@ -74,9 +71,9 @@ impl Vm {
) -> Result<Value, Error> { ) -> Result<Value, Error> {
for arg in &args { for arg in &args {
if let Ref(r) = arg { if let Ref(r) = arg {
info!("arg {:?}",r); debug!("arg {:?}",r);
} else { } else {
info!("arg {:?}",arg); debug!("arg {:?}",arg);
} }
} }
@ -153,7 +150,7 @@ impl Vm {
method_name: &str, method_name: &str,
args: Vec<Value>, args: Vec<Value>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
info!("execute {}.{}", this_class.name, method_name); debug!("execute {}.{}", this_class.name, method_name);
//TODO implement dynamic dispatch -> get method from instance //TODO implement dynamic dispatch -> get method from instance
let method = classmanager::get_classdef(&this_class.id).get_method(method_name).unwrap(); let method = classmanager::get_classdef(&this_class.id).get_method(method_name).unwrap();
@ -170,7 +167,7 @@ impl Vm {
while *pc < code.opcodes.len() { while *pc < code.opcodes.len() {
let opcode = read_u8(&code.opcodes, pc); let opcode = read_u8(&code.opcodes, pc);
let cur_frame = Self::current_frame(stackframes); 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 { match opcode {
ACONST_NULL => { ACONST_NULL => {
Self::current_frame(stackframes).push(Value::Null); Self::current_frame(stackframes).push(Value::Null);
@ -245,11 +242,9 @@ impl Vm {
let stringinstance = let stringinstance =
Ref(ObjectRef::Object(Vm::new_instance(stringclass))); Ref(ObjectRef::Object(Vm::new_instance(stringclass)));
debug!("class id {}", this_class.id);
let string: Vec<u8> = let string: Vec<u8> =
classmanager::get_classdef(&this_class.id).cp_utf8(utf8) classmanager::get_classdef(&this_class.id).cp_utf8(utf8).as_bytes().into();
.to_owned()
.as_bytes()
.into();
self.execute_special(stackframes, self.execute_special(stackframes,
"java/lang/String", "java/lang/String",
@ -493,6 +488,7 @@ impl Vm {
if let Some(invocation) = if let Some(invocation) =
get_signature_for_invoke(&method.constant_pool, cp_index) get_signature_for_invoke(&method.constant_pool, cp_index)
{ {
debug!("invoke {:?}", invocation);
let mut args = Vec::with_capacity(invocation.method.num_args); let mut args = Vec::with_capacity(invocation.method.num_args);
for _ in 0..invocation.method.num_args { for _ in 0..invocation.method.num_args {
args.insert(0, Self::current_frame(stackframes).pop()?.clone()); args.insert(0, Self::current_frame(stackframes).pop()?.clone());
@ -505,10 +501,10 @@ impl Vm {
)?; )?;
if let Ref(objectref) = &return_value { if let Ref(objectref) = &return_value {
if let ObjectRef::Object(object) = objectref { if let ObjectRef::Object(object) = objectref {
info!("return {:?}", object); debug!("return {:?}", object);
} }
} else { } else {
info!("return {:?}", return_value); debug!("return {:?}", return_value);
} }
match return_value { match return_value {
Void => {} Void => {}
@ -540,10 +536,10 @@ impl Vm {
)?; )?;
if let Ref(objectref) = &return_value { if let Ref(objectref) = &return_value {
if let ObjectRef::Object(object) = objectref { if let ObjectRef::Object(object) = objectref {
info!("return {:?}", object); debug!("return {:?}", object);
} }
} else { } else {
info!("return {:?}", return_value); debug!("return {:?}", return_value);
} }
match return_value { match return_value {
Void => {} Void => {}
@ -571,10 +567,10 @@ impl Vm {
)?; )?;
if let Ref(objectref) = &return_value { if let Ref(objectref) = &return_value {
if let ObjectRef::Object(object) = objectref { if let ObjectRef::Object(object) = objectref {
info!("return {:?}", object); debug!("return {:?}", object);
} }
} else { } else {
info!("return {:?}", return_value); debug!("return {:?}", return_value);
} }
match return_value { match return_value {
Void => {} Void => {}
@ -622,7 +618,7 @@ impl Vm {
Self::current_frame(stackframes).push(I32(val.get_array_length() as i32)); Self::current_frame(stackframes).push(I32(val.get_array_length() as i32));
} }
} }
MONITORENTER => { MONITORENTER | MONITOREXIT => {
Self::current_frame(stackframes).pop()?; Self::current_frame(stackframes).pop()?;
} //TODO implement } //TODO implement
IFNULL | IFNONNULL => { IFNULL | IFNONNULL => {
@ -631,21 +627,21 @@ impl Vm {
let its_null = if let Null = value { true } else { false }; let its_null = if let Null = value { true } else { false };
if its_null && opcode == IFNULL { 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; *pc += jmp_to as usize;
} }
if !its_null && opcode == IFNONNULL { 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; *pc += jmp_to as usize;
} }
//debug info //debug info
if !its_null && opcode == IFNULL { if !its_null && opcode == IFNULL {
info!("\t\tIF NULL =>false: NO JMP"); debug!("\t\tIF NULL =>false: NO JMP");
} }
if its_null && opcode == IFNONNULL { if its_null && opcode == IFNONNULL {
info!("\t\tIF NONNULL =>false: NO JMP"); debug!("\t\tIF NONNULL =>false: NO JMP");
} }
}, }
//TODO implement all opcodes //TODO implement all opcodes
_ => { _ => {
panic!("opcode {} not implemented {:?}", opcode, stackframes) panic!("opcode {} not implemented {:?}", opcode, stackframes)
@ -670,10 +666,10 @@ impl Vm {
_ => false, _ => false,
}; };
if jump { 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; *pc += jmp_to as usize;
} else { } 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 { pub(crate) struct Invocation {
class_name: String, class_name: String,
method: MethodSignature, method: MethodSignature,
@ -710,6 +707,7 @@ impl Invocation {
} }
} }
#[derive(Debug)]
pub(crate) struct MethodSignature { pub(crate) struct MethodSignature {
name: String, name: String,
num_args: usize, num_args: usize,

View file

@ -1,7 +1,7 @@
mod test { mod test {
use java_rs::class::{Method, Modifier};
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use java_rs::classloader::classdef::{Method, Modifier};
#[test] #[test]
fn access_flags() { fn access_flags() {
@ -16,4 +16,8 @@ mod test {
assert!(m.is(Modifier::Static)); assert!(m.is(Modifier::Static));
assert!(!m.is(Modifier::Private)); assert!(!m.is(Modifier::Private));
} }
} }