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::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, Error};
|
||||
use anyhow::Error;
|
||||
use log::info;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::classloader::{load_class, CpEntry};
|
||||
use crate::heap::ObjectRef;
|
||||
use crate::classloader::{CpEntry, load_class};
|
||||
use crate::heap::{ObjectRef};
|
||||
use crate::io::{find_class, read_bytecode, read_u16};
|
||||
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
|
||||
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,
|
||||
// then parses the binary data into a Class struct
|
||||
|
|
@ -22,7 +25,7 @@ pub fn get_class(
|
|||
vm: &mut Vm,
|
||||
class_name: &str,
|
||||
) -> Result<Arc<RefCell<Class>>, Error> {
|
||||
// println!("get_class {}", class_name);
|
||||
info!("get_class {}", class_name);
|
||||
|
||||
unsafe {
|
||||
let class = CLASSDEFS.entry(class_name.into()).or_insert_with(|| {
|
||||
|
|
@ -33,17 +36,29 @@ pub fn get_class(
|
|||
Arc::new(RefCell::new(class))
|
||||
});
|
||||
|
||||
|
||||
let clone = class.clone();
|
||||
let inited = class.borrow().inited;
|
||||
if !inited {
|
||||
// not sure why I have to create the clones first
|
||||
let clone2 = 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!
|
||||
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()
|
||||
.borrow()
|
||||
.super_class_name
|
||||
|
|
@ -52,13 +67,18 @@ pub fn get_class(
|
|||
{
|
||||
if let Some(super_class_name) = 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);
|
||||
} else {
|
||||
unreachable!()
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class::initialize_fields(clone3);
|
||||
let clinit = clone2.borrow().methods.contains_key("<clinit>()V");
|
||||
let name = &clone2.borrow().name.to_owned();
|
||||
|
|
@ -81,6 +101,7 @@ pub struct Class {
|
|||
pub name: String,
|
||||
pub super_class_name: Option<String>,
|
||||
pub super_class: Option<Type>,
|
||||
pub super_classes: Vec<Type>,
|
||||
pub interface_indices: Vec<u16>,
|
||||
pub interfaces: Vec<Class>,
|
||||
pub fields: HashMap<String, Field>,
|
||||
|
|
@ -118,6 +139,7 @@ impl Class {
|
|||
name,
|
||||
super_class_name,
|
||||
super_class: None, // has to be instantiated later, because it involves classloading. maybe not store it here
|
||||
super_classes: vec![],
|
||||
interface_indices,
|
||||
interfaces: vec![], // same
|
||||
fields,
|
||||
|
|
@ -237,10 +259,8 @@ impl Class {
|
|||
(self.major_version, self.minor_version)
|
||||
}
|
||||
|
||||
pub fn get_method(&self, name: &str) -> Result<&Rc<Method>, Error> {
|
||||
self.methods
|
||||
.get(name)
|
||||
.ok_or(anyhow!("Method {} not found", name))
|
||||
pub fn get_method(&self, name: &str) -> Option<&Rc<Method>> {
|
||||
self.methods.get(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 constant_pool_count = read_u16(&bytecode, pos);
|
||||
// println!("cp count: {}", constant_pool_count);
|
||||
let mut constant_pool: HashMap<u16, CpEntry> =
|
||||
HashMap::with_capacity(constant_pool_count as usize);
|
||||
let mut cp_index = 1;
|
||||
while cp_index < constant_pool_count {
|
||||
// println!("cp#{}", cp_index);
|
||||
constant_pool.insert(
|
||||
cp_index,
|
||||
read_constant_pool_entry(&mut cp_index, pos, &bytecode),
|
||||
|
|
@ -275,6 +273,7 @@ fn read_attribute(
|
|||
"InnerClasses" => Some(("".into(), AttributeType::InnerClasses)), //stub
|
||||
"Signature" => Some(("".into(), AttributeType::Signature)), //stub
|
||||
"NestHost" => Some(("".into(), AttributeType::NestHost)), //stub
|
||||
"EnclosingMethod" => Some(("".into(), AttributeType::EnclosingMethod)), //stub
|
||||
//TODO more actual attribute implementations
|
||||
_ => None,
|
||||
};
|
||||
|
|
|
|||
27
src/heap.rs
27
src/heap.rs
|
|
@ -1,10 +1,11 @@
|
|||
use std::cell::{RefCell, UnsafeCell};
|
||||
use std::fmt;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::fmt::{Debug, Formatter, write};
|
||||
use std::sync::Arc;
|
||||
use ObjectRef::{BooleanArray, CharArray, DoubleArray, FloatArray, LongArray, ShortArray};
|
||||
|
||||
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
|
||||
pub enum ObjectRef {
|
||||
|
|
@ -16,8 +17,10 @@ pub enum ObjectRef {
|
|||
DoubleArray(Vec<f64>),
|
||||
BooleanArray(Vec<bool>),
|
||||
CharArray(Vec<char>),
|
||||
StringArray(Vec<String>),
|
||||
ObjectArray(Type, Vec<Arc<UnsafeCell<ObjectRef>>>),
|
||||
Object(Box<Object>),
|
||||
Class(Arc<RefCell<Class>>)
|
||||
}
|
||||
|
||||
fn into_vec_i8(v: Vec<u8>) -> Vec<i8> {
|
||||
|
|
@ -54,16 +57,18 @@ impl ObjectRef {
|
|||
impl Debug for ObjectRef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ObjectRef::BooleanArray(d) => write!(f, "[Z;{}]", d.len()),
|
||||
ObjectRef::ByteArray(d) => write!(f, "[B;{}]", d.len()),
|
||||
ObjectRef::CharArray(d) => write!(f, "[C;{}]", d.len()),
|
||||
ObjectRef::DoubleArray(d) => write!(f, "[D;{}]", d.len()),
|
||||
ObjectRef::FloatArray(d) => write!(f, "[F;{}]", d.len()),
|
||||
ObjectRef::IntArray(d) => write!(f, "[I;{}]", d.len()),
|
||||
ObjectRef::LongArray(d) => write!(f, "[J;{}]", d.len()),
|
||||
ObjectRef::ObjectArray(t, d) => write!(f, "[L{};{}]", t.borrow().name, d.len()),
|
||||
ObjectRef::ShortArray(d) => write!(f, "[S;{}]", d.len()),
|
||||
BooleanArray(d) => write!(f, "[Z;{}]", d.len()),
|
||||
ByteArray(d) => write!(f, "[B;{}]", d.len()),
|
||||
CharArray(d) => write!(f, "[C;{}]", d.len()),
|
||||
DoubleArray(d) => write!(f, "[D;{}]", d.len()),
|
||||
FloatArray(d) => write!(f, "[F;{}]", d.len()),
|
||||
IntArray(d) => write!(f, "[I;{}]", d.len()),
|
||||
LongArray(d) => write!(f, "[J;{}]", d.len()),
|
||||
ObjectArray(t, d) => write!(f, "[L{};{}]", t.borrow().name, 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::Class(s) => write!(f, "Class {:?}", s.borrow().name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ fn main() -> Result<(), Error> {
|
|||
// let main_class = "Inheritance";
|
||||
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();
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,90 @@
|
|||
use crate::class::{Method, UnsafeValue, Value};
|
||||
use std::rc::Rc;
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
pub fn invoke_native(method: Rc<Method>, _args: Vec<UnsafeValue>) -> UnsafeValue {
|
||||
println!("native {}", method.name());
|
||||
Value::void()
|
||||
use log::info;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
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::io::Write;
|
||||
use anyhow::{anyhow, Error};
|
||||
use log::{info};
|
||||
use log::{debug, info};
|
||||
|
||||
use Value::*;
|
||||
|
||||
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::heap::{Heap, Object, ObjectRef};
|
||||
use crate::io::*;
|
||||
|
|
@ -39,7 +39,9 @@ impl StackFrame {
|
|||
fn push_ref(&mut self, val: UnsafeValue) {
|
||||
self.data.push(val);
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
fn pop(&mut self) -> Result<UnsafeValue, Error> {
|
||||
Ok(self.data.pop().unwrap())
|
||||
}
|
||||
|
|
@ -51,6 +53,16 @@ pub struct Vm {
|
|||
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")]
|
||||
const PATH_SEPARATOR: char = ':';
|
||||
|
||||
|
|
@ -72,14 +84,18 @@ impl Vm {
|
|||
writeln!(buf, "{}: {}", record.level(), record.args())
|
||||
})
|
||||
.init();
|
||||
Self {
|
||||
let mut vm_instance = Self {
|
||||
classpath: classpath
|
||||
.split(PATH_SEPARATOR)
|
||||
.map(|s| s.to_owned())
|
||||
.collect(),
|
||||
heap: Heap::new(),
|
||||
stackframes: vec![],
|
||||
}
|
||||
};
|
||||
|
||||
Vm::init(&mut vm_instance);
|
||||
|
||||
vm_instance
|
||||
}
|
||||
|
||||
pub fn new_instance(class: Arc<RefCell<Class>>) -> Object {
|
||||
|
|
@ -88,26 +104,55 @@ impl Vm {
|
|||
|
||||
/// execute the bytecode
|
||||
/// contains unsafe, as I think that mimics not-synchronized memory access in the original JVM
|
||||
pub fn execute(
|
||||
pub fn execute_virtual(
|
||||
&mut self,
|
||||
class_name: &str,
|
||||
method_name: &str,
|
||||
args: Vec<UnsafeValue>,
|
||||
) -> Result<UnsafeValue, Error> {
|
||||
let class = get_class(self, class_name)?;
|
||||
// let method = class.clone().borrow().get_method(method_name)?.clone();
|
||||
let classb = class.borrow();
|
||||
unsafe {
|
||||
for a in &args {
|
||||
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(
|
||||
|
|
@ -117,23 +162,10 @@ impl Vm {
|
|||
args: Vec<UnsafeValue>,
|
||||
) -> Result<UnsafeValue, Error> {
|
||||
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)
|
||||
}
|
||||
|
||||
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(
|
||||
&mut self,
|
||||
class_name: &str,
|
||||
|
|
@ -141,7 +173,7 @@ impl Vm {
|
|||
args: Vec<UnsafeValue>,
|
||||
) -> Result<UnsafeValue, Error> {
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
@ -152,14 +184,14 @@ impl Vm {
|
|||
args: Vec<UnsafeValue>,
|
||||
) -> Result<UnsafeValue, Error> {
|
||||
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
|
||||
|
||||
let mut local_params: Vec<Option<UnsafeValue>> =
|
||||
args.clone().iter().map(|e| Some(e.clone())).collect();
|
||||
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() {
|
||||
let stackframe = StackFrame::new(&this_class.borrow().name, &method.name());
|
||||
|
|
@ -168,8 +200,8 @@ impl Vm {
|
|||
let pc = &mut 0;
|
||||
while *pc < code.opcodes.len() {
|
||||
let opcode = read_u8(&code.opcodes, pc);
|
||||
let f = self.current_frame();
|
||||
info!("\t{} #{} {}", &f.at, &*pc - 1, opcodes::OPCODES[opcode as usize]);
|
||||
let cur_frame = self.current_frame();
|
||||
info!("\t{} #{} {} - {}", &cur_frame.at, &*pc - 1, opcodes::OPCODES[opcode as usize], cur_frame.len());
|
||||
match opcode {
|
||||
ACONST_NULL => {
|
||||
self.current_frame().push(Value::Null);
|
||||
|
|
@ -270,8 +302,14 @@ impl Vm {
|
|||
self.current_frame().push(Value::I64(*l));
|
||||
}
|
||||
CpEntry::ClassRef(utf8) => {
|
||||
let string = this_class.borrow().cp_utf8(utf8).unwrap().to_owned();
|
||||
self.current_frame().push(Value::Utf8(string));
|
||||
let class_name = this_class.borrow().cp_utf8(utf8).unwrap().to_owned();
|
||||
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)
|
||||
|
|
@ -280,14 +318,21 @@ impl Vm {
|
|||
}
|
||||
LDC_W => {
|
||||
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) => {
|
||||
self.current_frame().push(I32(*i));
|
||||
}
|
||||
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!()
|
||||
}
|
||||
}
|
||||
|
|
@ -512,6 +557,13 @@ impl Vm {
|
|||
&invocation.method.name,
|
||||
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() {
|
||||
Void => {}
|
||||
_ => {
|
||||
|
|
@ -534,11 +586,18 @@ impl Vm {
|
|||
args.insert(0, copy(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.method.name,
|
||||
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() {
|
||||
Void => {}
|
||||
_ => {
|
||||
|
|
@ -559,15 +618,22 @@ impl Vm {
|
|||
for _ in 0..invocation.method.num_args {
|
||||
args.insert(0, copy(self.current_frame().pop()?));
|
||||
}
|
||||
let returnvalue = self.execute_static(
|
||||
let return_value = self.execute_static(
|
||||
&invocation.class_name,
|
||||
&invocation.method.name,
|
||||
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 => {}
|
||||
_ => {
|
||||
self.current_frame().push_ref(returnvalue.clone());
|
||||
self.current_frame().push_ref(return_value.clone());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -689,16 +755,22 @@ impl Vm {
|
|||
self.current_frame().push(CHAR(array[index]));
|
||||
}
|
||||
ObjectRef::LongArray(array) => {
|
||||
self.current_frame().push(Value::I64(array[index]));
|
||||
self.current_frame().push(I64(array[index]));
|
||||
}
|
||||
ObjectRef::FloatArray(array) => {
|
||||
self.current_frame().push(Value::F32(array[index]));
|
||||
self.current_frame().push(F32(array[index]));
|
||||
}
|
||||
ObjectRef::DoubleArray(array) => {
|
||||
self.current_frame().push(Value::F64(array[index]));
|
||||
self.current_frame().push(F64(array[index]));
|
||||
}
|
||||
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(_) => {
|
||||
panic!("should be array")
|
||||
|
|
@ -786,7 +858,14 @@ impl Vm {
|
|||
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 {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
mod test {
|
||||
use java_rs::class::{get_class, Value};
|
||||
use java_rs::class::Value;
|
||||
use java_rs::heap::ObjectRef;
|
||||
use java_rs::vm::Vm;
|
||||
|
||||
#[test]
|
||||
fn if_cmp() {
|
||||
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 {
|
||||
if let Value::I32(b) = *ret.get() {
|
||||
// internally a boolean is an int
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue