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 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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -81,10 +81,23 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
52
src/vm/vm.rs
52
src/vm/vm.rs
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue