bug fix array arg
This commit is contained in:
parent
ceeec215e4
commit
769800ff71
8 changed files with 56 additions and 35 deletions
|
|
@ -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<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 bytecode = read_bytecode(resolved_path)?;
|
||||
load_class(bytecode)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
mod classloader;
|
||||
pub mod classloader;
|
||||
pub mod classmanager;
|
||||
pub mod class;
|
||||
pub mod vm;
|
||||
|
|
|
|||
|
|
@ -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<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() {
|
||||
"java/lang/Class" => java_lang_class(vm, method_name),
|
||||
|
|
|
|||
|
|
@ -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<Vec<&str>> = 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
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ 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;
|
||||
|
|
@ -88,3 +90,14 @@ fn get_num_args(signature: &str) -> usize {
|
|||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
52
src/vm/vm.rs
52
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<StackFrame>) {
|
||||
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 {
|
||||
let i = stackframes.len() - 1;
|
||||
|
|
@ -74,9 +71,9 @@ impl Vm {
|
|||
) -> Result<Value, Error> {
|
||||
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<Value>,
|
||||
) -> 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
|
||||
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<u8> =
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue