virtual methods, Class objects, some native methods
This commit is contained in:
parent
c47b7e9f50
commit
b6d7d9de4d
8 changed files with 280 additions and 93 deletions
BIN
jmods/java.base.jar
Normal file
BIN
jmods/java.base.jar
Normal file
Binary file not shown.
44
src/class.rs
44
src/class.rs
|
|
@ -4,16 +4,19 @@ use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::Error;
|
||||||
|
use log::info;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::classloader::{load_class, CpEntry};
|
use crate::classloader::{CpEntry, load_class};
|
||||||
use crate::heap::ObjectRef;
|
use crate::heap::{ObjectRef};
|
||||||
use crate::io::{find_class, read_bytecode, read_u16};
|
use crate::io::{find_class, read_bytecode, read_u16};
|
||||||
use crate::vm::Vm;
|
use crate::vm::Vm;
|
||||||
|
|
||||||
//trying to be ready for multithreaded as much as possible, using Arc's and all, but it will still require (a lot of) extra work
|
//trying to be ready for multithreaded as much as possible, using Arc's and all, but it will still require (a lot of) extra work
|
||||||
static mut CLASSDEFS: Lazy<HashMap<String, Arc<RefCell<Class>>>> = Lazy::new(|| HashMap::new()); //TODO add mutex..
|
pub static mut CLASSDEFS: Lazy<HashMap<String, Arc<RefCell<Class>>>> = Lazy::new(|| HashMap::new());
|
||||||
|
//TODO add mutex..
|
||||||
|
pub static mut CLASSES: Lazy<HashMap<String, UnsafeValue>> = Lazy::new(|| HashMap::new()); //TODO add mutex..
|
||||||
|
|
||||||
// gets the Class from cache, or reads it from classpath,
|
// gets the Class from cache, or reads it from classpath,
|
||||||
// then parses the binary data into a Class struct
|
// then parses the binary data into a Class struct
|
||||||
|
|
@ -22,7 +25,7 @@ pub fn get_class(
|
||||||
vm: &mut Vm,
|
vm: &mut Vm,
|
||||||
class_name: &str,
|
class_name: &str,
|
||||||
) -> Result<Arc<RefCell<Class>>, Error> {
|
) -> Result<Arc<RefCell<Class>>, Error> {
|
||||||
// println!("get_class {}", class_name);
|
info!("get_class {}", class_name);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let class = CLASSDEFS.entry(class_name.into()).or_insert_with(|| {
|
let class = CLASSDEFS.entry(class_name.into()).or_insert_with(|| {
|
||||||
|
|
@ -33,17 +36,29 @@ pub fn get_class(
|
||||||
Arc::new(RefCell::new(class))
|
Arc::new(RefCell::new(class))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
let clone = class.clone();
|
let clone = class.clone();
|
||||||
let inited = class.borrow().inited;
|
let inited = class.borrow().inited;
|
||||||
if !inited {
|
if !inited {
|
||||||
// not sure why I have to create the clones first
|
// not sure why I have to create the clones first
|
||||||
let clone2 = class.clone();
|
let clone2 = class.clone();
|
||||||
let clone3 = class.clone();
|
let clone3 = class.clone();
|
||||||
|
let mut some_class = class.clone();
|
||||||
|
|
||||||
|
if class_name != "java/lang/Class" {
|
||||||
|
let klazz = get_class(vm, "java/lang/Class")?;
|
||||||
|
let mut class_instance = Vm::new_instance(klazz);
|
||||||
|
class_instance.set(&"java/lang/Class".to_owned(), &"name".to_owned(), unsafe_val(Value::Utf8(class_name.into())));
|
||||||
|
CLASSES.insert(class_name.into(), unsafe_val(Value::Ref(unsafe_ref(ObjectRef::Object(Box::new(class_instance))))));
|
||||||
|
}
|
||||||
|
|
||||||
// must not enter here twice!
|
// must not enter here twice!
|
||||||
clone2.borrow_mut().inited = true;
|
clone2.borrow_mut().inited = true;
|
||||||
|
|
||||||
let super_class_name = class
|
let mut supers = vec![];
|
||||||
|
if class_name != "java/lang/Class" {
|
||||||
|
loop {
|
||||||
|
let super_class_name = some_class
|
||||||
.clone()
|
.clone()
|
||||||
.borrow()
|
.borrow()
|
||||||
.super_class_name
|
.super_class_name
|
||||||
|
|
@ -52,13 +67,18 @@ pub fn get_class(
|
||||||
{
|
{
|
||||||
if let Some(super_class_name) = super_class_name {
|
if let Some(super_class_name) = super_class_name {
|
||||||
if let Ok(super_class) = get_class(vm, &super_class_name) {
|
if let Ok(super_class) = get_class(vm, &super_class_name) {
|
||||||
|
supers.push(super_class.clone());
|
||||||
|
some_class = super_class.clone();
|
||||||
clone2.borrow_mut().super_class = Some(super_class);
|
clone2.borrow_mut().super_class = Some(super_class);
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Class::initialize_fields(clone3);
|
Class::initialize_fields(clone3);
|
||||||
let clinit = clone2.borrow().methods.contains_key("<clinit>()V");
|
let clinit = clone2.borrow().methods.contains_key("<clinit>()V");
|
||||||
let name = &clone2.borrow().name.to_owned();
|
let name = &clone2.borrow().name.to_owned();
|
||||||
|
|
@ -81,6 +101,7 @@ pub struct Class {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub super_class_name: Option<String>,
|
pub super_class_name: Option<String>,
|
||||||
pub super_class: Option<Type>,
|
pub super_class: Option<Type>,
|
||||||
|
pub super_classes: Vec<Type>,
|
||||||
pub interface_indices: Vec<u16>,
|
pub interface_indices: Vec<u16>,
|
||||||
pub interfaces: Vec<Class>,
|
pub interfaces: Vec<Class>,
|
||||||
pub fields: HashMap<String, Field>,
|
pub fields: HashMap<String, Field>,
|
||||||
|
|
@ -118,6 +139,7 @@ impl Class {
|
||||||
name,
|
name,
|
||||||
super_class_name,
|
super_class_name,
|
||||||
super_class: None, // has to be instantiated later, because it involves classloading. maybe not store it here
|
super_class: None, // has to be instantiated later, because it involves classloading. maybe not store it here
|
||||||
|
super_classes: vec![],
|
||||||
interface_indices,
|
interface_indices,
|
||||||
interfaces: vec![], // same
|
interfaces: vec![], // same
|
||||||
fields,
|
fields,
|
||||||
|
|
@ -237,10 +259,8 @@ impl Class {
|
||||||
(self.major_version, self.minor_version)
|
(self.major_version, self.minor_version)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_method(&self, name: &str) -> Result<&Rc<Method>, Error> {
|
pub fn get_method(&self, name: &str) -> Option<&Rc<Method>> {
|
||||||
self.methods
|
self.methods.get(name)
|
||||||
.get(name)
|
|
||||||
.ok_or(anyhow!("Method {} not found", name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn class_name(
|
fn class_name(
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,10 @@ pub fn load_class(bytecode: Vec<u8>) -> Result<Class, Error> {
|
||||||
let major_version = read_u16(&bytecode, pos);
|
let major_version = read_u16(&bytecode, pos);
|
||||||
|
|
||||||
let constant_pool_count = read_u16(&bytecode, pos);
|
let constant_pool_count = read_u16(&bytecode, pos);
|
||||||
// println!("cp count: {}", constant_pool_count);
|
|
||||||
let mut constant_pool: HashMap<u16, CpEntry> =
|
let mut constant_pool: HashMap<u16, CpEntry> =
|
||||||
HashMap::with_capacity(constant_pool_count as usize);
|
HashMap::with_capacity(constant_pool_count as usize);
|
||||||
let mut cp_index = 1;
|
let mut cp_index = 1;
|
||||||
while cp_index < constant_pool_count {
|
while cp_index < constant_pool_count {
|
||||||
// println!("cp#{}", cp_index);
|
|
||||||
constant_pool.insert(
|
constant_pool.insert(
|
||||||
cp_index,
|
cp_index,
|
||||||
read_constant_pool_entry(&mut cp_index, pos, &bytecode),
|
read_constant_pool_entry(&mut cp_index, pos, &bytecode),
|
||||||
|
|
@ -275,6 +273,7 @@ fn read_attribute(
|
||||||
"InnerClasses" => Some(("".into(), AttributeType::InnerClasses)), //stub
|
"InnerClasses" => Some(("".into(), AttributeType::InnerClasses)), //stub
|
||||||
"Signature" => Some(("".into(), AttributeType::Signature)), //stub
|
"Signature" => Some(("".into(), AttributeType::Signature)), //stub
|
||||||
"NestHost" => Some(("".into(), AttributeType::NestHost)), //stub
|
"NestHost" => Some(("".into(), AttributeType::NestHost)), //stub
|
||||||
|
"EnclosingMethod" => Some(("".into(), AttributeType::EnclosingMethod)), //stub
|
||||||
//TODO more actual attribute implementations
|
//TODO more actual attribute implementations
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
27
src/heap.rs
27
src/heap.rs
|
|
@ -1,10 +1,11 @@
|
||||||
use std::cell::{RefCell, UnsafeCell};
|
use std::cell::{RefCell, UnsafeCell};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter, write};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use ObjectRef::{BooleanArray, CharArray, DoubleArray, FloatArray, LongArray, ShortArray};
|
||||||
|
|
||||||
use crate::class::{Class, Type, UnsafeValue, Value};
|
use crate::class::{Class, Type, UnsafeValue, Value};
|
||||||
use crate::heap::ObjectRef::{ByteArray, IntArray, ObjectArray};
|
use crate::heap::ObjectRef::{ByteArray, IntArray, ObjectArray, StringArray};
|
||||||
|
|
||||||
// can contain object or array
|
// can contain object or array
|
||||||
pub enum ObjectRef {
|
pub enum ObjectRef {
|
||||||
|
|
@ -16,8 +17,10 @@ pub enum ObjectRef {
|
||||||
DoubleArray(Vec<f64>),
|
DoubleArray(Vec<f64>),
|
||||||
BooleanArray(Vec<bool>),
|
BooleanArray(Vec<bool>),
|
||||||
CharArray(Vec<char>),
|
CharArray(Vec<char>),
|
||||||
|
StringArray(Vec<String>),
|
||||||
ObjectArray(Type, Vec<Arc<UnsafeCell<ObjectRef>>>),
|
ObjectArray(Type, Vec<Arc<UnsafeCell<ObjectRef>>>),
|
||||||
Object(Box<Object>),
|
Object(Box<Object>),
|
||||||
|
Class(Arc<RefCell<Class>>)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_vec_i8(v: Vec<u8>) -> Vec<i8> {
|
fn into_vec_i8(v: Vec<u8>) -> Vec<i8> {
|
||||||
|
|
@ -54,16 +57,18 @@ impl ObjectRef {
|
||||||
impl Debug for ObjectRef {
|
impl Debug for ObjectRef {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
ObjectRef::BooleanArray(d) => write!(f, "[Z;{}]", d.len()),
|
BooleanArray(d) => write!(f, "[Z;{}]", d.len()),
|
||||||
ObjectRef::ByteArray(d) => write!(f, "[B;{}]", d.len()),
|
ByteArray(d) => write!(f, "[B;{}]", d.len()),
|
||||||
ObjectRef::CharArray(d) => write!(f, "[C;{}]", d.len()),
|
CharArray(d) => write!(f, "[C;{}]", d.len()),
|
||||||
ObjectRef::DoubleArray(d) => write!(f, "[D;{}]", d.len()),
|
DoubleArray(d) => write!(f, "[D;{}]", d.len()),
|
||||||
ObjectRef::FloatArray(d) => write!(f, "[F;{}]", d.len()),
|
FloatArray(d) => write!(f, "[F;{}]", d.len()),
|
||||||
ObjectRef::IntArray(d) => write!(f, "[I;{}]", d.len()),
|
IntArray(d) => write!(f, "[I;{}]", d.len()),
|
||||||
ObjectRef::LongArray(d) => write!(f, "[J;{}]", d.len()),
|
LongArray(d) => write!(f, "[J;{}]", d.len()),
|
||||||
ObjectRef::ObjectArray(t, d) => write!(f, "[L{};{}]", t.borrow().name, d.len()),
|
ObjectArray(t, d) => write!(f, "[L{};{}]", t.borrow().name, d.len()),
|
||||||
ObjectRef::ShortArray(d) => write!(f, "[S;{}]", d.len()),
|
ShortArray(d) => write!(f, "[S;{}]", d.len()),
|
||||||
|
StringArray(d) => write!(f, "[S;{}]", d.len()),
|
||||||
ObjectRef::Object(r) => write!(f, "{}{{ {:?} }}", r.class.borrow().name, r.data),
|
ObjectRef::Object(r) => write!(f, "{}{{ {:?} }}", r.class.borrow().name, r.data),
|
||||||
|
ObjectRef::Class(s) => write!(f, "Class {:?}", s.borrow().name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ fn main() -> Result<(), Error> {
|
||||||
// let main_class = "Inheritance";
|
// let main_class = "Inheritance";
|
||||||
let main_class = "testclasses.Main";
|
let main_class = "testclasses.Main";
|
||||||
|
|
||||||
vm.execute( main_class, "main([Ljava/lang/String;)V", vec![])
|
vm.execute_static( main_class, "main([Ljava/lang/String;)V", vec![])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,90 @@
|
||||||
use crate::class::{Method, UnsafeValue, Value};
|
#![allow(non_snake_case)]
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub fn invoke_native(method: Rc<Method>, _args: Vec<UnsafeValue>) -> UnsafeValue {
|
use log::info;
|
||||||
println!("native {}", method.name());
|
use once_cell::sync::Lazy;
|
||||||
Value::void()
|
|
||||||
|
use crate::class::{unsafe_ref, unsafe_val, UnsafeValue, Value};
|
||||||
|
use crate::class::Value::Void;
|
||||||
|
use crate::heap::ObjectRef;
|
||||||
|
|
||||||
|
pub fn invoke_native(class_name: &String, method_name: &String, _args: Vec<UnsafeValue>) -> UnsafeValue {
|
||||||
|
info!("native {}.{}", class_name, method_name);
|
||||||
|
|
||||||
|
unsafe_val(match class_name.as_str() {
|
||||||
|
"java/lang/Class" => java_lang_class(method_name),
|
||||||
|
"jdk/internal/util/SystemProps$Raw" => jdk_internal_util_SystemProps_Raw(method_name),
|
||||||
|
_ => Void
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn java_lang_class(method_name: &String) -> Value {
|
||||||
|
match method_name.as_str() {
|
||||||
|
"desiredAssertionStatus0(Ljava/lang/Class;)Z" => Value::BOOL(false),
|
||||||
|
_ => Void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jdk_internal_util_SystemProps_Raw(method_name: &String) -> Value {
|
||||||
|
match method_name.as_str() {
|
||||||
|
"platformProperties()[Ljava/lang/String;" => systemProps(),
|
||||||
|
"cmdProperties()Ljava/util/HashMap;" => cmdProps(), //TODO ability to instantiate classes here
|
||||||
|
"vmProperties()[Ljava/lang/String;" => cmdProps(),
|
||||||
|
_ => Void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmdProps() -> Value {
|
||||||
|
Value::Null
|
||||||
|
}
|
||||||
|
|
||||||
|
fn systemProps() -> Value {
|
||||||
|
unsafe {
|
||||||
|
let props: Lazy<Vec<String>> = Lazy::new(|| {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
//TODO set values
|
||||||
|
vec.push("display_country");
|
||||||
|
vec.push("display_language");
|
||||||
|
vec.push("display_script");
|
||||||
|
vec.push("display_variant");
|
||||||
|
vec.push("file_encoding");
|
||||||
|
vec.push("file_separator");
|
||||||
|
vec.push("format_country");
|
||||||
|
vec.push("format_language");
|
||||||
|
vec.push("format_script");
|
||||||
|
vec.push("format_variant");
|
||||||
|
vec.push("ftp_nonProxyHosts");
|
||||||
|
vec.push("ftp_proxyHost");
|
||||||
|
vec.push("ftp_proxyPort");
|
||||||
|
vec.push("http_nonProxyHosts");
|
||||||
|
vec.push("http_proxyHost");
|
||||||
|
vec.push("http_proxyPort");
|
||||||
|
vec.push("https_proxyHost");
|
||||||
|
vec.push("https_proxyPort");
|
||||||
|
vec.push("java_io_tmpdir");
|
||||||
|
vec.push("line_separator");
|
||||||
|
vec.push("os_arch");
|
||||||
|
vec.push("os_name");
|
||||||
|
vec.push("os_version");
|
||||||
|
vec.push("path_separator");
|
||||||
|
vec.push("socksNonProxyHosts");
|
||||||
|
vec.push("socksProxyHost");
|
||||||
|
vec.push("socksProxyPort");
|
||||||
|
vec.push("stderr_encoding");
|
||||||
|
vec.push("stdout_encoding");
|
||||||
|
vec.push("sun_arch_abi");
|
||||||
|
vec.push("sun_arch_data_model");
|
||||||
|
vec.push("sun_cpu_endian");
|
||||||
|
vec.push("sun_cpu_isalist");
|
||||||
|
vec.push("sun_io_unicode_encoding");
|
||||||
|
vec.push("sun_jnu_encoding");
|
||||||
|
vec.push("sun_os_patch_level");
|
||||||
|
vec.push("user_dir");
|
||||||
|
vec.push("user_home");
|
||||||
|
vec.push("user_name");
|
||||||
|
vec.push("FIXED_LENGTH");
|
||||||
|
|
||||||
|
vec.into_iter().map(|s| s.to_owned()).collect()
|
||||||
|
});
|
||||||
|
Value::Ref(unsafe_ref(ObjectRef::StringArray(props.to_vec())))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
179
src/vm.rs
179
src/vm.rs
|
|
@ -4,12 +4,12 @@ use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::{anyhow, Error};
|
||||||
use log::{info};
|
use log::{debug, info};
|
||||||
|
|
||||||
use Value::*;
|
use Value::*;
|
||||||
|
|
||||||
use crate::class::Value::{Null, Void};
|
use crate::class::Value::{Null, Void};
|
||||||
use crate::class::{get_class, unsafe_ref, unsafe_val, AttributeType, Class, Modifier, UnsafeValue, Value, Method};
|
use crate::class::{get_class, unsafe_ref, unsafe_val, AttributeType, Class, Modifier, UnsafeValue, Value, Method, CLASSES};
|
||||||
use crate::classloader::CpEntry;
|
use crate::classloader::CpEntry;
|
||||||
use crate::heap::{Heap, Object, ObjectRef};
|
use crate::heap::{Heap, Object, ObjectRef};
|
||||||
use crate::io::*;
|
use crate::io::*;
|
||||||
|
|
@ -39,7 +39,9 @@ impl StackFrame {
|
||||||
fn push_ref(&mut self, val: UnsafeValue) {
|
fn push_ref(&mut self, val: UnsafeValue) {
|
||||||
self.data.push(val);
|
self.data.push(val);
|
||||||
}
|
}
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.data.len()
|
||||||
|
}
|
||||||
fn pop(&mut self) -> Result<UnsafeValue, Error> {
|
fn pop(&mut self) -> Result<UnsafeValue, Error> {
|
||||||
Ok(self.data.pop().unwrap())
|
Ok(self.data.pop().unwrap())
|
||||||
}
|
}
|
||||||
|
|
@ -51,6 +53,16 @@ pub struct Vm {
|
||||||
pub(crate) stackframes: Vec<StackFrame>,
|
pub(crate) stackframes: Vec<StackFrame>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Vm {
|
||||||
|
fn init(vm: &mut Vm) {
|
||||||
|
Self::initialize_class(vm, "java/lang/System");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initialize_class(vm: &mut Vm, class: &str) {
|
||||||
|
vm.execute_static(class, "initPhase1()V", vec![]).expect("cannot create VM");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
const PATH_SEPARATOR: char = ':';
|
const PATH_SEPARATOR: char = ':';
|
||||||
|
|
||||||
|
|
@ -72,14 +84,18 @@ impl Vm {
|
||||||
writeln!(buf, "{}: {}", record.level(), record.args())
|
writeln!(buf, "{}: {}", record.level(), record.args())
|
||||||
})
|
})
|
||||||
.init();
|
.init();
|
||||||
Self {
|
let mut vm_instance = Self {
|
||||||
classpath: classpath
|
classpath: classpath
|
||||||
.split(PATH_SEPARATOR)
|
.split(PATH_SEPARATOR)
|
||||||
.map(|s| s.to_owned())
|
.map(|s| s.to_owned())
|
||||||
.collect(),
|
.collect(),
|
||||||
heap: Heap::new(),
|
heap: Heap::new(),
|
||||||
stackframes: vec![],
|
stackframes: vec![],
|
||||||
}
|
};
|
||||||
|
|
||||||
|
Vm::init(&mut vm_instance);
|
||||||
|
|
||||||
|
vm_instance
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_instance(class: Arc<RefCell<Class>>) -> Object {
|
pub fn new_instance(class: Arc<RefCell<Class>>) -> Object {
|
||||||
|
|
@ -88,26 +104,55 @@ impl Vm {
|
||||||
|
|
||||||
/// execute the bytecode
|
/// execute the bytecode
|
||||||
/// contains unsafe, as I think that mimics not-synchronized memory access in the original JVM
|
/// contains unsafe, as I think that mimics not-synchronized memory access in the original JVM
|
||||||
pub fn execute(
|
pub fn execute_virtual(
|
||||||
&mut self,
|
&mut self,
|
||||||
class_name: &str,
|
class_name: &str,
|
||||||
method_name: &str,
|
method_name: &str,
|
||||||
args: Vec<UnsafeValue>,
|
args: Vec<UnsafeValue>,
|
||||||
) -> Result<UnsafeValue, Error> {
|
) -> Result<UnsafeValue, Error> {
|
||||||
let class = get_class(self, class_name)?;
|
unsafe {
|
||||||
// let method = class.clone().borrow().get_method(method_name)?.clone();
|
for a in &args {
|
||||||
let classb = class.borrow();
|
let v = &*a.get();
|
||||||
|
if let Ref(r) = v {
|
||||||
|
info!("arg {:?}",&*r.get());
|
||||||
|
} else {
|
||||||
|
info!("arg {:?}",&*a.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let method = Self::get_method(&classb, method_name, &args).unwrap();
|
|
||||||
// let mut superclass = class.super_class.as_ref();
|
|
||||||
// while let Some(s) = superclass {
|
|
||||||
// if let Ok(m) = s.borrow().get_method(method_name) {
|
|
||||||
// return m;
|
|
||||||
// }
|
|
||||||
// superclass = s.borrow().super_class.as_ref();
|
|
||||||
// }
|
|
||||||
|
|
||||||
self.execute_class(class.clone(), method.clone(), args)
|
if let Null = &*args[0].get() {
|
||||||
|
panic!("NPE");
|
||||||
|
}
|
||||||
|
if let Ref(this) = &*args[0].get() {
|
||||||
|
if let ObjectRef::Object(this) = &*this.get() {
|
||||||
|
let class = &this.class;
|
||||||
|
let borrow = class.borrow();
|
||||||
|
let method = borrow.get_method(method_name);
|
||||||
|
if let Some(method) = method {
|
||||||
|
return self.execute_class(class.clone(), method.clone(), args);
|
||||||
|
} else {
|
||||||
|
for s in &borrow.super_classes {
|
||||||
|
let borrow2 = s.borrow();
|
||||||
|
let method = borrow2.get_method(method_name);
|
||||||
|
if let Some(method) = method {
|
||||||
|
return self.execute_class(class.clone(), method.clone(), args);
|
||||||
|
} else {
|
||||||
|
debug!("not {:?}", s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug!("not found {}", method_name);
|
||||||
|
}
|
||||||
|
} else if let ObjectRef::Class(class) = &*this.get() {
|
||||||
|
let klazz = get_class(self, "java/lang/Class")?;
|
||||||
|
let borrow = klazz.borrow();
|
||||||
|
let method = borrow.get_method(method_name).unwrap();
|
||||||
|
return self.execute_class(class.clone(), method.clone(), args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("this is not an object reference {}", class_name);
|
||||||
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute_special(
|
pub fn execute_special(
|
||||||
|
|
@ -117,23 +162,10 @@ impl Vm {
|
||||||
args: Vec<UnsafeValue>,
|
args: Vec<UnsafeValue>,
|
||||||
) -> Result<UnsafeValue, Error> {
|
) -> Result<UnsafeValue, Error> {
|
||||||
let class = get_class(self, class_name)?;
|
let class = get_class(self, class_name)?;
|
||||||
let method = class.clone().borrow().get_method(method_name)?.clone();
|
let method = class.clone().borrow().get_method(method_name).expect("execute special needs invoked method on the class").clone();
|
||||||
self.execute_class(class.clone(), method.clone(), args)
|
self.execute_class(class.clone(), method.clone(), args)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_method<'a>(class: &'a std::cell::Ref<Class>, method_name: &str, args: &Vec<UnsafeValue>) -> Option<&'a Rc<Method>> {
|
|
||||||
unsafe {
|
|
||||||
if let Ref(this) = &*args[0].get() {
|
|
||||||
if let ObjectRef::Object(this) = &*this.get() {
|
|
||||||
if let Ok(m) = class.get_method(method_name) {
|
|
||||||
return Some(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_static(
|
pub fn execute_static(
|
||||||
&mut self,
|
&mut self,
|
||||||
class_name: &str,
|
class_name: &str,
|
||||||
|
|
@ -141,7 +173,7 @@ impl Vm {
|
||||||
args: Vec<UnsafeValue>,
|
args: Vec<UnsafeValue>,
|
||||||
) -> Result<UnsafeValue, Error> {
|
) -> Result<UnsafeValue, Error> {
|
||||||
let class = get_class(self, class_name)?;
|
let class = get_class(self, class_name)?;
|
||||||
let method = class.clone().borrow().get_method(method_name)?.clone();
|
let method = class.clone().borrow().get_method(method_name).expect("execute static needs this method").clone();
|
||||||
self.execute_class(class, method, args)
|
self.execute_class(class, method, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,14 +184,14 @@ impl Vm {
|
||||||
args: Vec<UnsafeValue>,
|
args: Vec<UnsafeValue>,
|
||||||
) -> Result<UnsafeValue, Error> {
|
) -> Result<UnsafeValue, Error> {
|
||||||
let this_class = class;
|
let this_class = class;
|
||||||
println!("execute {}.{}", this_class.borrow().name, method.name());
|
info!("execute {}.{}", this_class.borrow().name, method.name());
|
||||||
|
|
||||||
//TODO implement dynamic dispatch -> get method from instance
|
//TODO implement dynamic dispatch -> get method from instance
|
||||||
|
|
||||||
let mut local_params: Vec<Option<UnsafeValue>> =
|
let mut local_params: Vec<Option<UnsafeValue>> =
|
||||||
args.clone().iter().map(|e| Some(e.clone())).collect();
|
args.clone().iter().map(|e| Some(e.clone())).collect();
|
||||||
if method.is(Modifier::Native) {
|
if method.is(Modifier::Native) {
|
||||||
return Ok(invoke_native(method, args));
|
return Ok(invoke_native(&this_class.borrow().name, &method.name(), args));
|
||||||
}
|
}
|
||||||
if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() {
|
if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() {
|
||||||
let stackframe = StackFrame::new(&this_class.borrow().name, &method.name());
|
let stackframe = StackFrame::new(&this_class.borrow().name, &method.name());
|
||||||
|
|
@ -168,8 +200,8 @@ impl Vm {
|
||||||
let pc = &mut 0;
|
let pc = &mut 0;
|
||||||
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 f = self.current_frame();
|
let cur_frame = self.current_frame();
|
||||||
info!("\t{} #{} {}", &f.at, &*pc - 1, opcodes::OPCODES[opcode as usize]);
|
info!("\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().push(Value::Null);
|
self.current_frame().push(Value::Null);
|
||||||
|
|
@ -270,8 +302,14 @@ impl Vm {
|
||||||
self.current_frame().push(Value::I64(*l));
|
self.current_frame().push(Value::I64(*l));
|
||||||
}
|
}
|
||||||
CpEntry::ClassRef(utf8) => {
|
CpEntry::ClassRef(utf8) => {
|
||||||
let string = this_class.borrow().cp_utf8(utf8).unwrap().to_owned();
|
let class_name = this_class.borrow().cp_utf8(utf8).unwrap().to_owned();
|
||||||
self.current_frame().push(Value::Utf8(string));
|
unsafe {
|
||||||
|
if let Some(class) = CLASSES.get(&class_name) {
|
||||||
|
self.current_frame().push_ref(class.clone());
|
||||||
|
} else {
|
||||||
|
unreachable!("should not be here");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("add variant {:?}", c)
|
panic!("add variant {:?}", c)
|
||||||
|
|
@ -280,14 +318,21 @@ impl Vm {
|
||||||
}
|
}
|
||||||
LDC_W => {
|
LDC_W => {
|
||||||
let cp_index = read_u16(&code.opcodes, pc);
|
let cp_index = read_u16(&code.opcodes, pc);
|
||||||
match method.constant_pool.get(&cp_index).unwrap() {
|
let cp_entry = method.constant_pool.get(&cp_index).unwrap();
|
||||||
|
match cp_entry {
|
||||||
CpEntry::Integer(i) => {
|
CpEntry::Integer(i) => {
|
||||||
self.current_frame().push(I32(*i));
|
self.current_frame().push(I32(*i));
|
||||||
}
|
}
|
||||||
CpEntry::Float(f) => {
|
CpEntry::Float(f) => {
|
||||||
self.current_frame().push(Value::F32(*f));
|
self.current_frame().push(F32(*f));
|
||||||
|
}
|
||||||
|
CpEntry::StringRef(utf8_index) => {
|
||||||
|
if let CpEntry::Utf8(s) = method.constant_pool.get(utf8_index).unwrap() {
|
||||||
|
self.current_frame().push(Value::Utf8(s.to_owned()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
println!("{:?}", cp_entry);
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -512,6 +557,13 @@ impl Vm {
|
||||||
&invocation.method.name,
|
&invocation.method.name,
|
||||||
args,
|
args,
|
||||||
)?;
|
)?;
|
||||||
|
if let Ref(r) = &*return_value.get() {
|
||||||
|
if let ObjectRef::Object(p) = &*r.get() {
|
||||||
|
info!("return {:?}", p);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!("return {:?}", &*return_value.get());
|
||||||
|
}
|
||||||
match *return_value.get() {
|
match *return_value.get() {
|
||||||
Void => {}
|
Void => {}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -534,11 +586,18 @@ impl Vm {
|
||||||
args.insert(0, copy(self.current_frame().pop()?));
|
args.insert(0, copy(self.current_frame().pop()?));
|
||||||
}
|
}
|
||||||
args.insert(0, self.current_frame().pop()?);
|
args.insert(0, self.current_frame().pop()?);
|
||||||
let return_value = self.execute(
|
let return_value = self.execute_virtual(
|
||||||
&invocation.class_name,
|
&invocation.class_name,
|
||||||
&invocation.method.name,
|
&invocation.method.name,
|
||||||
args,
|
args,
|
||||||
)?;
|
)?;
|
||||||
|
if let Ref(r) = &*return_value.get() {
|
||||||
|
if let ObjectRef::Object(p) = &*r.get() {
|
||||||
|
info!("return {:?}", p);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!("return {:?}", &*return_value.get());
|
||||||
|
}
|
||||||
match *return_value.get() {
|
match *return_value.get() {
|
||||||
Void => {}
|
Void => {}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -559,15 +618,22 @@ impl Vm {
|
||||||
for _ in 0..invocation.method.num_args {
|
for _ in 0..invocation.method.num_args {
|
||||||
args.insert(0, copy(self.current_frame().pop()?));
|
args.insert(0, copy(self.current_frame().pop()?));
|
||||||
}
|
}
|
||||||
let returnvalue = self.execute_static(
|
let return_value = self.execute_static(
|
||||||
&invocation.class_name,
|
&invocation.class_name,
|
||||||
&invocation.method.name,
|
&invocation.method.name,
|
||||||
args,
|
args,
|
||||||
)?;
|
)?;
|
||||||
match *returnvalue.get() {
|
if let Ref(r) = &*return_value.get() {
|
||||||
|
if let ObjectRef::Object(p) = &*r.get() {
|
||||||
|
info!("return {:?}", p);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
info!("return {:?}", &*return_value.get());
|
||||||
|
}
|
||||||
|
match *return_value.get() {
|
||||||
Void => {}
|
Void => {}
|
||||||
_ => {
|
_ => {
|
||||||
self.current_frame().push_ref(returnvalue.clone());
|
self.current_frame().push_ref(return_value.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -689,16 +755,22 @@ impl Vm {
|
||||||
self.current_frame().push(CHAR(array[index]));
|
self.current_frame().push(CHAR(array[index]));
|
||||||
}
|
}
|
||||||
ObjectRef::LongArray(array) => {
|
ObjectRef::LongArray(array) => {
|
||||||
self.current_frame().push(Value::I64(array[index]));
|
self.current_frame().push(I64(array[index]));
|
||||||
}
|
}
|
||||||
ObjectRef::FloatArray(array) => {
|
ObjectRef::FloatArray(array) => {
|
||||||
self.current_frame().push(Value::F32(array[index]));
|
self.current_frame().push(F32(array[index]));
|
||||||
}
|
}
|
||||||
ObjectRef::DoubleArray(array) => {
|
ObjectRef::DoubleArray(array) => {
|
||||||
self.current_frame().push(Value::F64(array[index]));
|
self.current_frame().push(F64(array[index]));
|
||||||
}
|
}
|
||||||
ObjectRef::ObjectArray(_arraytype, data) => {
|
ObjectRef::ObjectArray(_arraytype, data) => {
|
||||||
self.current_frame().push(Value::Ref(data[index].clone()));
|
self.current_frame().push(Ref(data[index].clone()));
|
||||||
|
}
|
||||||
|
ObjectRef::StringArray(array) =>{
|
||||||
|
self.current_frame().push(Utf8(array[index].to_owned()));
|
||||||
|
}
|
||||||
|
ObjectRef::Class(_) => {
|
||||||
|
panic!("should be array")
|
||||||
}
|
}
|
||||||
ObjectRef::Object(_) => {
|
ObjectRef::Object(_) => {
|
||||||
panic!("should be array")
|
panic!("should be array")
|
||||||
|
|
@ -786,7 +858,14 @@ impl Vm {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ObjectRef::Object(_) => {} //throw error?
|
ObjectRef::StringArray(ref mut array) => {
|
||||||
|
if let Utf8(ref value) = *value.get() {
|
||||||
|
array[*index as usize] = value.clone();
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ObjectRef::Object(_) | ObjectRef::Class(_) => {} //throw error?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
mod test {
|
mod test {
|
||||||
use java_rs::class::{get_class, Value};
|
use java_rs::class::Value;
|
||||||
use java_rs::heap::ObjectRef;
|
use java_rs::heap::ObjectRef;
|
||||||
use java_rs::vm::Vm;
|
use java_rs::vm::Vm;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn if_cmp() {
|
fn if_cmp() {
|
||||||
let mut vm = Vm::new("tests");
|
let mut vm = Vm::new("tests");
|
||||||
let ret = vm.execute("testclasses.IfCmp", "i_is_1()Z", vec![]).unwrap();
|
let ret = vm.execute_virtual("testclasses.IfCmp", "i_is_1()Z", vec![]).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Value::I32(b) = *ret.get() {
|
if let Value::I32(b) = *ret.get() {
|
||||||
// internally a boolean is an int
|
// internally a boolean is an int
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue