almost there, it seems...
This commit is contained in:
parent
98300a1532
commit
715fa29cfd
10 changed files with 286 additions and 68 deletions
|
|
@ -318,13 +318,13 @@ impl Field {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Method {
|
pub struct Method {
|
||||||
pub(crate) constant_pool: Rc<HashMap<u16, CpEntry>>,
|
pub(crate) constant_pool: Rc<HashMap<u16, CpEntry>>,
|
||||||
access_flags: u16,
|
pub access_flags: u16,
|
||||||
name_index: u16,
|
name_index: u16,
|
||||||
descriptor_index: u16,
|
descriptor_index: u16,
|
||||||
pub(crate) attributes: HashMap<String, AttributeType>,
|
pub(crate) attributes: HashMap<String, AttributeType>,
|
||||||
pub code: Vec<Opcode>,
|
pub(crate) code: Vec<Opcode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Method {
|
impl Debug for Method {
|
||||||
|
|
@ -338,7 +338,7 @@ impl Debug for Method {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Method {
|
impl Method {
|
||||||
pub fn new(
|
pub(crate) fn new(
|
||||||
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
constant_pool: Rc<HashMap<u16, CpEntry>>,
|
||||||
access_flags: u16,
|
access_flags: u16,
|
||||||
name_index: u16,
|
name_index: u16,
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::{BTreeMap};
|
||||||
|
|
||||||
use log::debug;
|
use crate::classloader::io::{read_i16, read_i32, read_lookupswitch, read_tableswitch, read_u16, read_u8, read_wide_opcode};
|
||||||
|
|
||||||
use crate::classloader::io::{read_i32, read_lookupswitch, read_tableswitch, read_u16, read_u8, read_wide_opcode};
|
|
||||||
use crate::vm::opcodes::Opcode::{self, *};
|
use crate::vm::opcodes::Opcode::{self, *};
|
||||||
|
|
||||||
pub(crate) fn parse_code(opcodes: &[u8]) -> Vec<Opcode> {
|
pub(crate) fn parse_code(opcodes: &[u8]) -> Vec<Opcode> {
|
||||||
let mut code: HashMap<u16, (u16, Opcode)> = HashMap::new();
|
let mut code: BTreeMap<u16, (u16, Opcode)> = BTreeMap::new();
|
||||||
let mut c = 0;
|
let mut c = 0;
|
||||||
let mut opcode_index: u16 = 0;
|
let mut opcode_index: u16 = 0;
|
||||||
// debug!("len {:?}", opcodes.len());
|
|
||||||
while c < opcodes.len() {
|
while c < opcodes.len() {
|
||||||
let opcode = get_opcode(opcodes, &mut c);
|
let opcode = get_opcode(opcodes, &mut c);
|
||||||
code.insert(c as u16, (opcode_index, opcode));
|
code.insert(c as u16, (opcode_index, opcode));
|
||||||
|
|
@ -21,13 +18,9 @@ pub(crate) fn parse_code(opcodes: &[u8]) -> Vec<Opcode> {
|
||||||
code.into_iter().map(|(_, (_, opcode))|
|
code.into_iter().map(|(_, (_, opcode))|
|
||||||
match opcode {
|
match opcode {
|
||||||
IFNULL(goto) => {
|
IFNULL(goto) => {
|
||||||
debug!("goto {:?}", goto);
|
|
||||||
debug!("{:?}", code2);
|
|
||||||
IFNULL(code2.get(&goto).unwrap().0)
|
IFNULL(code2.get(&goto).unwrap().0)
|
||||||
}
|
}
|
||||||
IFNONNULL(goto) => {
|
IFNONNULL(goto) => {
|
||||||
debug!("goto {:?}", &goto);
|
|
||||||
debug!("{:?}", code2);
|
|
||||||
IFNONNULL(code2.get(&goto).unwrap().0)
|
IFNONNULL(code2.get(&goto).unwrap().0)
|
||||||
}
|
}
|
||||||
//TODO more jump instructions
|
//TODO more jump instructions
|
||||||
|
|
@ -162,6 +155,8 @@ fn get_opcode(opcodes: &[u8], c: &mut usize) -> Opcode {
|
||||||
121 => LSHL,
|
121 => LSHL,
|
||||||
122 => ISHR,
|
122 => ISHR,
|
||||||
123 => LSHR,
|
123 => LSHR,
|
||||||
|
124 => IUSHR,
|
||||||
|
125 => LUSHR,
|
||||||
126 => IAND,
|
126 => IAND,
|
||||||
127 => LAND,
|
127 => LAND,
|
||||||
128 => IOR,
|
128 => IOR,
|
||||||
|
|
@ -209,6 +204,7 @@ fn get_opcode(opcodes: &[u8], c: &mut usize) -> Opcode {
|
||||||
170 => TABLESWITCH(read_tableswitch(opcodes, c)),
|
170 => TABLESWITCH(read_tableswitch(opcodes, c)),
|
||||||
171 => LOOKUPSWITCH(read_lookupswitch(opcodes, c)),
|
171 => LOOKUPSWITCH(read_lookupswitch(opcodes, c)),
|
||||||
172 => IRETURN,
|
172 => IRETURN,
|
||||||
|
173 => LRETURN,
|
||||||
174 => FRETURN,
|
174 => FRETURN,
|
||||||
175 => DRETURN,
|
175 => DRETURN,
|
||||||
176 => ARETURN,
|
176 => ARETURN,
|
||||||
|
|
@ -243,14 +239,12 @@ fn get_opcode(opcodes: &[u8], c: &mut usize) -> Opcode {
|
||||||
196 => WIDE(Box::new(read_wide_opcode(opcodes, c))),
|
196 => WIDE(Box::new(read_wide_opcode(opcodes, c))),
|
||||||
197 => MULTIANEWARRAY(read_u16(opcodes, c), read_u8(opcodes, c)),
|
197 => MULTIANEWARRAY(read_u16(opcodes, c), read_u8(opcodes, c)),
|
||||||
198 => {
|
198 => {
|
||||||
let j = read_u16(opcodes, c);
|
let j = read_i16(opcodes, c);
|
||||||
debug!("ifnull {}",*c as u16 + j - 3);
|
IFNULL((*c as i16 + j - 3) as u16)
|
||||||
IFNULL(*c as u16 + j - 3)
|
|
||||||
}
|
}
|
||||||
199 => {
|
199 => {
|
||||||
let j = read_u16(opcodes, c);
|
let j = read_i16(opcodes, c);
|
||||||
debug!("ifnonnull {} ", *c as u16 + j - 3);
|
IFNONNULL((*c as i16 + j - 3) as u16)
|
||||||
IFNONNULL(*c as u16 + j - 3)
|
|
||||||
}
|
}
|
||||||
200 => GOTOW(read_i32(opcodes, c)),
|
200 => GOTOW(read_i32(opcodes, c)),
|
||||||
201 => JSR_W(read_i32(opcodes, c)),
|
201 => JSR_W(read_i32(opcodes, c)),
|
||||||
|
|
@ -258,5 +252,6 @@ fn get_opcode(opcodes: &[u8], c: &mut usize) -> Opcode {
|
||||||
|
|
||||||
_ => panic!("{}", opcode_u8),
|
_ => panic!("{}", opcode_u8),
|
||||||
};
|
};
|
||||||
|
|
||||||
opcode
|
opcode
|
||||||
}
|
}
|
||||||
|
|
@ -17,7 +17,6 @@ pub const PATH_SEPARATOR: char = ';';
|
||||||
/// * [jar/zip]#[package_path]/[class].class
|
/// * [jar/zip]#[package_path]/[class].class
|
||||||
/// * [dir]/[package_path]/[class].class
|
/// * [dir]/[package_path]/[class].class
|
||||||
pub fn find_class(classpath: &Vec<String>, class_name: &str) -> Result<String, Error> {
|
pub fn find_class(classpath: &Vec<String>, class_name: &str) -> Result<String, Error> {
|
||||||
let class_name = &class_name.to_owned().replace(".", "/");
|
|
||||||
if class_name.starts_with("java")
|
if class_name.starts_with("java")
|
||||||
|| class_name.starts_with("sun/")
|
|| class_name.starts_with("sun/")
|
||||||
|| class_name.starts_with("com/sun/")
|
|| class_name.starts_with("com/sun/")
|
||||||
|
|
@ -73,6 +72,15 @@ pub(crate) fn read_u16(data: &[u8], pos: &mut usize) -> u16 {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_i16(data: &[u8], pos: &mut usize) -> i16 {
|
||||||
|
*pos += 2;
|
||||||
|
i16::from_be_bytes(
|
||||||
|
data[*pos - 2..*pos]
|
||||||
|
.try_into()
|
||||||
|
.expect("slice with incorrect length"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn read_i32(data: &[u8], pos: &mut usize) -> i32 {
|
pub(crate) fn read_i32(data: &[u8], pos: &mut usize) -> i32 {
|
||||||
*pos += 4;
|
*pos += 4;
|
||||||
i32::from_be_bytes(
|
i32::from_be_bytes(
|
||||||
|
|
@ -119,8 +127,9 @@ pub(crate) fn read_f64(data: &[u8], pos: &mut usize) -> f64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_tableswitch(data: &[u8], pos: &mut usize) -> Tableswitch {
|
pub(crate) fn read_tableswitch(data: &[u8], pos: &mut usize) -> Tableswitch {
|
||||||
while read_u8(data, pos) == 0 {}
|
while *pos % 4 != 0 {
|
||||||
*pos -= 1;
|
*pos += 1;
|
||||||
|
}
|
||||||
let default = read_i32(data, pos);
|
let default = read_i32(data, pos);
|
||||||
let low = read_i32(data, pos);
|
let low = read_i32(data, pos);
|
||||||
let high = read_i32(data, pos);
|
let high = read_i32(data, pos);
|
||||||
|
|
@ -132,8 +141,9 @@ pub(crate) fn read_tableswitch(data: &[u8], pos: &mut usize) -> Tableswitch {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_lookupswitch(data: &[u8], pos: &mut usize) -> Lookupswitch {
|
pub(crate) fn read_lookupswitch(data: &[u8], pos: &mut usize) -> Lookupswitch {
|
||||||
while read_u8(data, pos) == 0 {}
|
while *pos % 4 != 0 {
|
||||||
*pos -= 1;
|
*pos += 1;
|
||||||
|
}
|
||||||
let default = read_i32(data, pos);
|
let default = read_i32(data, pos);
|
||||||
let npairs = read_i32(data, pos);
|
let npairs = read_i32(data, pos);
|
||||||
let mut match_offset_pairs = vec![];
|
let mut match_offset_pairs = vec![];
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,7 @@ fn read_method(
|
||||||
) -> Method {
|
) -> Method {
|
||||||
let access_flags = read_u16(bytecode, index);
|
let access_flags = read_u16(bytecode, index);
|
||||||
let name_index = read_u16(bytecode, index);
|
let name_index = read_u16(bytecode, index);
|
||||||
|
let name = constant_pool.get(&name_index);
|
||||||
let descriptor_index = read_u16(bytecode, index);
|
let descriptor_index = read_u16(bytecode, index);
|
||||||
let attributes_count = read_u16(bytecode, index);
|
let attributes_count = read_u16(bytecode, index);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,11 +99,11 @@ impl ClassManager {
|
||||||
if !PRIMITIVES.contains(&type_name.as_str()) {
|
if !PRIMITIVES.contains(&type_name.as_str()) {
|
||||||
type_name = type_name[1..type_name.len()].to_owned();
|
type_name = type_name[1..type_name.len()].to_owned();
|
||||||
}
|
}
|
||||||
let id = self.get_or_new_id(name);
|
let id = self.get_or_new_id(name.into());
|
||||||
if !self.class_objects.contains_key(&id) {
|
if !self.class_objects.contains_key(&id) {
|
||||||
let cls = self.get_class_by_name("java/lang/Class").unwrap();
|
let cls = self.get_class_by_name("java/lang/Class").unwrap();
|
||||||
let mut instance = Object::new(cls);
|
let mut instance = Object::new(cls);
|
||||||
instance.set(cls, "java/lang/Class", "name", Value::Utf8(name.into()));
|
instance.set(cls, "java/lang/Class", "name", Utf8(name.into()));
|
||||||
let instance = Ref(ObjectRef::Object(Rc::new(RefCell::new(instance))));
|
let instance = Ref(ObjectRef::Object(Rc::new(RefCell::new(instance))));
|
||||||
|
|
||||||
self.class_objects.insert(id, instance);
|
self.class_objects.insert(id, instance);
|
||||||
|
|
@ -135,6 +135,7 @@ impl ClassManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_class_by_name(&self, name: &str) -> Option<&Class> {
|
pub fn get_class_by_name(&self, name: &str) -> Option<&Class> {
|
||||||
|
debug!("{}", name);
|
||||||
let id = self.names.get(name);
|
let id = self.names.get(name);
|
||||||
self.classes.get(id.unwrap())
|
self.classes.get(id.unwrap())
|
||||||
}
|
}
|
||||||
|
|
@ -252,18 +253,19 @@ impl ClassManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// loads the class and returns it's dependencies
|
/// loads the class and returns it's dependencies
|
||||||
fn load_class_and_deps(&mut self, name: &str) -> (ClassId, Vec<String>) {
|
fn load_class_and_deps(&mut self, class_name: &str) -> (ClassId, Vec<String>) {
|
||||||
debug!("load {}", name);
|
debug!("load {}", class_name);
|
||||||
let id = self.get_or_new_id(name);
|
let class_name = class_name.to_owned().replace(".", "/");
|
||||||
|
let id = self.get_or_new_id(class_name.clone());
|
||||||
|
|
||||||
let classdef = self.classdefs
|
let classdef = self.classdefs
|
||||||
.entry(id)
|
.entry(id)
|
||||||
.or_insert_with(|| classloader::get_classdef(&self.classpath, name).expect("ClassNotFound"));
|
.or_insert_with(|| classloader::get_classdef(&self.classpath, class_name.as_str()).expect("ClassNotFound"));
|
||||||
(id, inspect_dependencies(classdef))
|
(id, inspect_dependencies(classdef))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_or_new_id(&mut self, name: &str) -> ClassId {
|
fn get_or_new_id(&mut self, name: String) -> ClassId {
|
||||||
let id = *self.names.entry(name.to_string()).or_insert_with(|| {
|
let id = *self.names.entry(name).or_insert_with(|| {
|
||||||
self.current_id += 1;
|
self.current_id += 1;
|
||||||
self.current_id
|
self.current_id
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use java_rs::vm::runtime::Vm;
|
use java_rs::vm::runtime::Vm;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let vm = Vm::new();
|
let mut vm = Vm::new();
|
||||||
vm.run("/Users/Shautvast/dev/java/tests", "testclasses.Main", "main([Ljava/lang/String;)V");
|
vm.run("/Users/Shautvast/dev/java.rs/tests", "testclasses/Main", "main([Ljava/lang/String;)V");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@ mod array;
|
||||||
pub(crate) mod object;
|
pub(crate) mod object;
|
||||||
pub(crate) mod opcodes;
|
pub(crate) mod opcodes;
|
||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
|
mod native;
|
||||||
161
src/vm/native.rs
Normal file
161
src/vm/native.rs
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use anyhow::Error;
|
||||||
|
use log::debug;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use crate::classmanager::ClassManager;
|
||||||
|
use crate::value::Value;
|
||||||
|
use crate::value::Value::{I32, Void};
|
||||||
|
use crate::vm::object::ObjectRef;
|
||||||
|
use crate::vm::object::ObjectRef::Object;
|
||||||
|
use crate::vm::runtime::{Stackframe, Vm};
|
||||||
|
|
||||||
|
|
||||||
|
pub fn invoke_native(class_manager: &mut ClassManager, class_name: &str, method_name: &str, _args: Vec<Value>) -> Result<Value, Error> {
|
||||||
|
debug!("native {}.{}", class_name, method_name);
|
||||||
|
|
||||||
|
match class_name {
|
||||||
|
"java/lang/Class" => java_lang_Class(method_name),
|
||||||
|
"java/lang/System" => java_lang_System(method_name),
|
||||||
|
"jdk/internal/misc/Unsafe" => jdk_internal_misc_Unsafe(method_name),
|
||||||
|
"jdk/internal/util/SystemProps$Raw" => jdk_internal_util_SystemProps_Raw(class_manager, method_name),
|
||||||
|
_ => unimplemented!("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn java_lang_Class(method_name: &str) -> Result<Value, Error> {
|
||||||
|
Ok(match method_name {
|
||||||
|
"desiredAssertionStatus0(Ljava/lang/Class;)Z" => Value::BOOL(false),
|
||||||
|
_ => Void
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn java_lang_System(method_name: &str) -> Result<Value, Error> {
|
||||||
|
Ok(match method_name {
|
||||||
|
_ => Void
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jdk_internal_misc_Unsafe(method_name: &str) -> Result<Value, Error> {
|
||||||
|
Ok(match method_name {
|
||||||
|
"arrayBaseOffset0(Ljava/lang/Class;)I" => I32(0), //TODO surely this is not right
|
||||||
|
"arrayIndexScale0(Ljava/lang/Class;)I" => I32(0), //TODO surely this is not right
|
||||||
|
_ => Void
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jdk_internal_util_SystemProps_Raw(class_manager: &mut ClassManager, method_name: &str) -> Result<Value, Error> {
|
||||||
|
match method_name {
|
||||||
|
"platformProperties()[Ljava/lang/String;" => platformProperties(),
|
||||||
|
"cmdProperties()Ljava/util/HashMap;" => cmdProps(class_manager), //TODO ability to instantiate classes here
|
||||||
|
"vmProperties()[Ljava/lang/String;" => vmProperties(),
|
||||||
|
_ => Ok(Void)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmdProps(class_manager: &mut ClassManager) -> Result<Value, Error> {
|
||||||
|
class_manager.load_class_by_name("java/util/HashMap");
|
||||||
|
let hashmap_class = class_manager.get_class_by_name("java/util/HashMap").unwrap();
|
||||||
|
let hashmap = Value::Ref(Object(Rc::new(RefCell::new(crate::vm::object::Object::new(hashmap_class))))); // this is convoluted
|
||||||
|
Stackframe::new(vec![hashmap.clone()]).run(class_manager, hashmap_class.id, "<init>()V");
|
||||||
|
Ok(hashmap)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vmProperties() -> Result<Value, Error> {
|
||||||
|
let props: Lazy<Vec<String>> = Lazy::new(|| {
|
||||||
|
let vec: Vec<String> = Vec::new();
|
||||||
|
//TODO insert some values
|
||||||
|
vec
|
||||||
|
});
|
||||||
|
Ok(Value::Ref(ObjectRef::StringArray(props.to_vec())))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn platformProperties() -> Result<Value, Error> {
|
||||||
|
let props: Lazy<Vec<String>> = Lazy::new(|| {
|
||||||
|
let mut vec: Vec<String> = Vec::new();
|
||||||
|
//TODO set correct values
|
||||||
|
vec.push("display_country".into()); //null in jdk21
|
||||||
|
vec.push("display_language".into()); //null in jdk21
|
||||||
|
vec.push("display_script".into()); //null in jdk21
|
||||||
|
vec.push("display_variant".into()); //null in jdk21
|
||||||
|
vec.push("UTF-8".into());
|
||||||
|
|
||||||
|
{
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
vec.push("/".into());
|
||||||
|
#[cfg(target_family = "windows")]
|
||||||
|
vec.push("\\");
|
||||||
|
}
|
||||||
|
vec.push("format_country".into()); //null in jdk21
|
||||||
|
vec.push("format_language".into()); //null in jdk21
|
||||||
|
vec.push("format_script".into()); //null in jdk21
|
||||||
|
vec.push("format_variant".into()); //null in jdk21
|
||||||
|
vec.push("ftp_nonProxyHosts".into());
|
||||||
|
if let Ok(ftp_proxy) = std::env::var("ftp_proxy") {
|
||||||
|
vec.push(ftp_proxy.to_owned());//TODO
|
||||||
|
vec.push(ftp_proxy);
|
||||||
|
} else {
|
||||||
|
vec.push("".to_owned());
|
||||||
|
vec.push("".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
vec.push("http_nonProxyHosts".into());
|
||||||
|
if let Ok(http_proxy) = std::env::var("http_proxy") {
|
||||||
|
vec.push(http_proxy.to_owned());
|
||||||
|
vec.push(http_proxy);//TODO
|
||||||
|
} else {
|
||||||
|
vec.push("".to_owned());
|
||||||
|
vec.push("".to_owned());
|
||||||
|
}
|
||||||
|
if let Ok(https_proxy) = std::env::var("https_proxy") {
|
||||||
|
vec.push(https_proxy.to_owned());
|
||||||
|
vec.push(https_proxy);
|
||||||
|
} else {
|
||||||
|
vec.push("".to_owned());
|
||||||
|
vec.push("".to_owned());
|
||||||
|
}
|
||||||
|
vec.push(std::env::temp_dir().display().to_string());
|
||||||
|
|
||||||
|
{
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
vec.push("\n".into());
|
||||||
|
#[cfg(target_family = "windows")]
|
||||||
|
vec.push("\r\n");
|
||||||
|
}
|
||||||
|
vec.push(whoami::platform().to_string());
|
||||||
|
vec.push(whoami::devicename());
|
||||||
|
vec.push("os_version".into());
|
||||||
|
{
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
vec.push(":".into());
|
||||||
|
#[cfg(target_family = "windows")]
|
||||||
|
vec.push(";".into());
|
||||||
|
}
|
||||||
|
vec.push("socksNonProxyHosts".into());
|
||||||
|
vec.push("socksProxyHost".into());
|
||||||
|
vec.push("socksProxyPort".into());
|
||||||
|
vec.push("UTF-8".into());
|
||||||
|
vec.push("UTF-8".into());
|
||||||
|
vec.push("sun_arch_abi".into());
|
||||||
|
vec.push("sun_arch_data_model".into());
|
||||||
|
vec.push("sun_cpu_endian".into()); //null in jdk21
|
||||||
|
vec.push("sun_cpu_isalist".into()); //null in jdk21
|
||||||
|
vec.push("sun_io_unicode_encoding".into()); //null in jdk21
|
||||||
|
vec.push("sun_jnu_encoding".into()); //null in jdk21
|
||||||
|
vec.push("sun_os_patch_level".into()); //null in jdk21
|
||||||
|
if let Ok(curdir) = std::env::current_dir() {
|
||||||
|
vec.push(curdir.display().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let home = std::env::home_dir().unwrap();
|
||||||
|
vec.push(home.display().to_string());
|
||||||
|
vec.push(whoami::username());
|
||||||
|
vec.push("FIXED_LENGTH".into());
|
||||||
|
|
||||||
|
vec
|
||||||
|
});
|
||||||
|
Ok(Value::Ref(ObjectRef::StringArray(props.to_vec())))
|
||||||
|
}
|
||||||
|
|
@ -85,6 +85,8 @@ pub(crate) enum Opcode {
|
||||||
LSHL,
|
LSHL,
|
||||||
ISHR,
|
ISHR,
|
||||||
LSHR,
|
LSHR,
|
||||||
|
IUSHR,
|
||||||
|
LUSHR,
|
||||||
IAND,
|
IAND,
|
||||||
LAND,
|
LAND,
|
||||||
IOR,
|
IOR,
|
||||||
|
|
@ -134,6 +136,7 @@ pub(crate) enum Opcode {
|
||||||
TABLESWITCH(Tableswitch),
|
TABLESWITCH(Tableswitch),
|
||||||
LOOKUPSWITCH(Lookupswitch),
|
LOOKUPSWITCH(Lookupswitch),
|
||||||
IRETURN,
|
IRETURN,
|
||||||
|
LRETURN,
|
||||||
FRETURN,
|
FRETURN,
|
||||||
DRETURN,
|
DRETURN,
|
||||||
ARETURN,
|
ARETURN,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use anyhow::Error;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
use crate::class::ClassId;
|
use crate::class::ClassId;
|
||||||
use crate::classloader::classdef::CpEntry;
|
use crate::classloader::classdef::{CpEntry, Modifier};
|
||||||
use crate::classloader::io::PATH_SEPARATOR;
|
use crate::classloader::io::PATH_SEPARATOR;
|
||||||
use crate::classmanager::ClassManager;
|
use crate::classmanager::ClassManager;
|
||||||
use crate::value::Value::{self, *};
|
use crate::value::Value::{self, *};
|
||||||
|
|
@ -17,6 +17,8 @@ use crate::vm::object::ObjectRef::Object;
|
||||||
use crate::vm::opcodes::Opcode;
|
use crate::vm::opcodes::Opcode;
|
||||||
use crate::vm::opcodes::Opcode::*;
|
use crate::vm::opcodes::Opcode::*;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use crate::vm::native::invoke_native;
|
||||||
|
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
pub stack: Vec<Stackframe>,
|
pub stack: Vec<Stackframe>,
|
||||||
}
|
}
|
||||||
|
|
@ -33,23 +35,26 @@ impl Vm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(self, classpath: &str, class_name: &str, method_name: &str) {
|
pub fn run(mut self, classpath: &str, class_name: &str, method_name: &str) {
|
||||||
|
|
||||||
let classpath = classpath.split(PATH_SEPARATOR).map(|s| s.into())
|
let classpath = classpath.split(PATH_SEPARATOR).map(|s| s.into())
|
||||||
.collect();
|
.collect();
|
||||||
let mut class_manager = ClassManager::new(classpath);
|
let mut class_manager = ClassManager::new(classpath);
|
||||||
|
|
||||||
class_manager.load_class_by_name("java/lang/Class");
|
class_manager.load_class_by_name("java/lang/Class");
|
||||||
|
class_manager.load_class_by_name("java/lang/System");
|
||||||
class_manager.load_class_by_name("java/lang/String");
|
class_manager.load_class_by_name("java/lang/String");
|
||||||
class_manager.load_class_by_name("java/util/Collections");
|
class_manager.load_class_by_name("java/util/Collections");
|
||||||
|
|
||||||
|
|
||||||
class_manager.load_class_by_name(class_name);
|
class_manager.load_class_by_name(class_name);
|
||||||
let class_id = *class_manager.get_classid(class_name);
|
let system_id = *class_manager.get_classid("java/lang/System");
|
||||||
self.run2(&mut class_manager, class_id, method_name);
|
self.run2(&mut class_manager, system_id, "initPhase1()V");
|
||||||
|
// let class_id = *class_manager.get_classid(class_name);
|
||||||
|
// self.run2(&mut class_manager, class_id, method_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn run2(self, class_manager: &mut ClassManager, class_id: ClassId, method_name: &str) {
|
pub(crate) fn run2(&mut self, class_manager: &mut ClassManager, class_id: ClassId, method_name: &str) {
|
||||||
Stackframe::new().run(class_manager, class_id, method_name);
|
Stackframe::default().run(class_manager, class_id, method_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,10 +65,10 @@ pub struct Stackframe {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stackframe {
|
impl Stackframe {
|
||||||
pub fn new() -> Self {
|
pub fn new(args: Vec<Value>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pc: 0,
|
pc: 0,
|
||||||
locals: vec![],
|
locals: args,
|
||||||
stack: vec![],
|
stack: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -84,15 +89,16 @@ impl Stackframe {
|
||||||
self.stack.pop().unwrap()
|
self.stack.pop().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self, class_manager: &mut ClassManager, class_id: ClassId, method_name: &str) {
|
pub fn run(&mut self, class_manager: &mut ClassManager, class_id: ClassId, method_name: &str) -> Value {
|
||||||
let classname = class_manager.get_class_by_id(&class_id).unwrap().name.to_owned();
|
let classname = class_manager.get_class_by_id(&class_id).unwrap().name.to_owned();
|
||||||
|
|
||||||
let code = class_manager.get_classdef(&class_id).get_method(method_name).unwrap().code.clone();
|
let code = class_manager.get_classdef(&class_id).get_method(method_name).unwrap().code.clone();
|
||||||
let constant_pool = class_manager.get_classdef(&class_id).get_method(method_name).unwrap().constant_pool.clone();
|
let constant_pool = class_manager.get_classdef(&class_id).get_method(method_name).unwrap().constant_pool.clone();
|
||||||
|
|
||||||
let len = code.len();
|
let len = code.len();
|
||||||
while self.pc < len {
|
while self.pc < len {
|
||||||
let opcode: &Opcode = code.get(self.pc).unwrap();
|
let opcode: &Opcode = code.get(self.pc).unwrap();
|
||||||
debug!("\tat {}.{}: {} #{:?} {:?}", classname, method_name, self.pc, opcode, self.stack);
|
debug!("\tat {}.{}: {} #{:?} - {:?}", classname, method_name, self.pc, opcode, self.stack);
|
||||||
match opcode {
|
match opcode {
|
||||||
NOP => {}
|
NOP => {}
|
||||||
ACONST_NULL => {
|
ACONST_NULL => {
|
||||||
|
|
@ -173,11 +179,22 @@ impl Stackframe {
|
||||||
if let Some(invocation) =
|
if let Some(invocation) =
|
||||||
get_signature_for_invoke(&constant_pool, *c)
|
get_signature_for_invoke(&constant_pool, *c)
|
||||||
{
|
{
|
||||||
// debug!("invoke {:?}", invocation);
|
let mut args = Vec::with_capacity(invocation.method.num_args);
|
||||||
|
for _ in 0..invocation.method.num_args {
|
||||||
|
args.insert(0, self.pop().clone());
|
||||||
|
}
|
||||||
|
let this_ref = self.pop();
|
||||||
|
args.insert(0, this_ref.clone());
|
||||||
|
|
||||||
|
|
||||||
|
debug!("invoke {:?}", invocation);
|
||||||
let mut invoke_class: Option<ClassId> = None;
|
let mut invoke_class: Option<ClassId> = None;
|
||||||
if let Ref(this) = &self.locals[0] {
|
if let Null = this_ref {
|
||||||
|
panic!("NullPointer Exception");
|
||||||
|
}
|
||||||
|
if let Ref(this) = this_ref {
|
||||||
if let Object(this) = this {
|
if let Object(this) = this {
|
||||||
let invoke_classdef = class_manager.get_classdef(&class_id);
|
let invoke_classdef = class_manager.get_classdef(&this.borrow().class_id);
|
||||||
let invoke_method = invoke_classdef.get_method(&invocation.method.name);
|
let invoke_method = invoke_classdef.get_method(&invocation.method.name);
|
||||||
if invoke_method.is_some() {
|
if invoke_method.is_some() {
|
||||||
class_manager.load_class_by_name(&invocation.class_name);
|
class_manager.load_class_by_name(&invocation.class_name);
|
||||||
|
|
@ -204,20 +221,21 @@ impl Stackframe {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if invoke_class.is_none() {
|
if invoke_class.is_none() {
|
||||||
panic!();
|
panic!("method {:?}.{} not found", invocation.class_name, invocation.method.name);
|
||||||
}
|
}
|
||||||
let mut args = Vec::with_capacity(invocation.method.num_args);
|
|
||||||
for _ in 0..invocation.method.num_args {
|
|
||||||
args.insert(0, self.pop().clone());
|
|
||||||
}
|
|
||||||
args.insert(0, self.pop());
|
|
||||||
|
|
||||||
let mut new_stackframe = Stackframe {
|
let return_value =
|
||||||
pc: 0,
|
if class_manager.get_classdef(&invoke_class.unwrap()).get_method(&invocation.method.name).unwrap().is(Modifier::Native) {
|
||||||
locals: args,
|
invoke_native(class_manager, invocation.class_name.as_str(), invocation.method.name.as_str(), args).unwrap()
|
||||||
stack: vec![],
|
// TODO remove unwrap in line above, error handling
|
||||||
};
|
} else {
|
||||||
new_stackframe.run(class_manager, invoke_class.unwrap(), &invocation.method.name);
|
let mut new_stackframe = Stackframe::new(args);
|
||||||
|
new_stackframe.run(class_manager, invoke_class.unwrap(), &invocation.method.name)
|
||||||
|
};
|
||||||
|
match return_value {
|
||||||
|
Void => {}
|
||||||
|
_ => self.push(return_value)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
@ -226,17 +244,31 @@ impl Stackframe {
|
||||||
if let Some(invocation) =
|
if let Some(invocation) =
|
||||||
get_signature_for_invoke(&constant_pool, *c)
|
get_signature_for_invoke(&constant_pool, *c)
|
||||||
{
|
{
|
||||||
|
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.pop().clone());
|
args.insert(0, self.pop().clone());
|
||||||
}
|
}
|
||||||
let mut new_stackframe = Stackframe {
|
if let INVOKESPECIAL(_) = opcode {
|
||||||
pc: 0,
|
args.insert(0, self.pop());
|
||||||
locals: args,
|
}
|
||||||
stack: vec![],
|
|
||||||
};
|
class_manager.load_class_by_name(invocation.class_name.as_str());
|
||||||
let invoke_class = class_manager.get_classid(invocation.class_name.as_str());
|
let invoke_class = class_manager.get_classid(invocation.class_name.as_str());
|
||||||
new_stackframe.run(class_manager, *invoke_class, &invocation.method.name);
|
|
||||||
|
let return_value =
|
||||||
|
if class_manager.get_classdef(&invoke_class).get_method(&invocation.method.name).unwrap().is(Modifier::Native) {
|
||||||
|
invoke_native(class_manager, invocation.class_name.as_str(), invocation.method.name.as_str(), args).unwrap()
|
||||||
|
// TODO remove unwrap in line above, error handling
|
||||||
|
} else {
|
||||||
|
let mut new_stackframe = Stackframe::new(args);
|
||||||
|
new_stackframe.run(class_manager, *invoke_class, &invocation.method.name)
|
||||||
|
};
|
||||||
|
debug!("returning {:?}", return_value);
|
||||||
|
match return_value {
|
||||||
|
Void => {}
|
||||||
|
_ => self.push(return_value)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
@ -369,9 +401,22 @@ impl Stackframe {
|
||||||
_ => if let IFNONNULL(goto) = opcode { self.pc = *goto as usize; }
|
_ => if let IFNONNULL(goto) = opcode { self.pc = *goto as usize; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
DUP => {
|
||||||
|
let value = self.pop();
|
||||||
|
self.push(value.clone());
|
||||||
|
self.push(value.clone());
|
||||||
|
}
|
||||||
|
IRETURN | LRETURN | FRETURN | DRETURN | ARETURN => {
|
||||||
|
return self.pop();
|
||||||
|
}
|
||||||
|
RETURN_VOID => {
|
||||||
|
return Void;
|
||||||
|
}
|
||||||
_ => { panic!("opcode not implemented") }
|
_ => { panic!("opcode not implemented") }
|
||||||
}
|
}
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
|
Void
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store(
|
fn store(
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue