sanitized logging, more opcodes, bugfixing
This commit is contained in:
parent
736a13a2d0
commit
ae143cd50d
33 changed files with 989 additions and 369 deletions
229
Cargo.lock
generated
229
Cargo.lock
generated
|
|
@ -19,6 +19,15 @@ dependencies = [
|
|||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
|
|
@ -31,6 +40,12 @@ version = "1.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
|
|
@ -153,6 +168,29 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
|
||||
dependencies = [
|
||||
"humantime",
|
||||
"is-terminal",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.27"
|
||||
|
|
@ -173,6 +211,12 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
|
|
@ -182,6 +226,12 @@ dependencies = [
|
|||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
|
|
@ -191,11 +241,24 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "java_rs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"env_logger",
|
||||
"log",
|
||||
"once_cell",
|
||||
"zip",
|
||||
]
|
||||
|
|
@ -215,6 +278,24 @@ version = "0.2.148"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
|
|
@ -283,6 +364,48 @@ version = "0.6.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.188"
|
||||
|
|
@ -342,6 +465,15 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.29"
|
||||
|
|
@ -377,6 +509,103 @@ version = "0.9.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.6.6"
|
||||
|
|
|
|||
|
|
@ -7,3 +7,5 @@ edition = "2021"
|
|||
anyhow = { version = "1.0", features = ["default"] }
|
||||
once_cell = { version = "1.18.0", features = [] }
|
||||
zip = { version = "0.6", features = ["zstd"] }
|
||||
log = "0.4"
|
||||
env_logger = "0.10"
|
||||
96
src/class.rs
96
src/class.rs
|
|
@ -7,7 +7,7 @@ use std::sync::Arc;
|
|||
use anyhow::{anyhow, Error};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::classloader::{CpEntry, load_class};
|
||||
use crate::classloader::{load_class, CpEntry};
|
||||
use crate::heap::ObjectRef;
|
||||
use crate::io::{find_class, read_bytecode, read_u16};
|
||||
use crate::vm::Vm;
|
||||
|
|
@ -15,37 +15,45 @@ 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..
|
||||
|
||||
|
||||
// gets the Class from cache, or reads it from classpath,
|
||||
// then parses the binary data into a Class struct
|
||||
// Vm keeps ownership of the class and hands out Arc references to it
|
||||
pub fn get_class(vm: &mut Vm, _calling_class_name: Option<&str>, class_name: &str) -> Result<Arc<RefCell<Class>>, Error> {
|
||||
println!("get_class {}", class_name);
|
||||
pub fn get_class(
|
||||
vm: &mut Vm,
|
||||
_calling_class_name: Option<&str>,
|
||||
class_name: &str,
|
||||
) -> Result<Arc<RefCell<Class>>, Error> {
|
||||
// println!("get_class {}", class_name);
|
||||
|
||||
unsafe {
|
||||
let class = CLASSDEFS.entry(class_name.into()).or_insert_with(|| {
|
||||
println!("read class {} ", class_name);
|
||||
// println!("read class {} ", class_name);
|
||||
let resolved_path = find_class(&vm.classpath, class_name).unwrap();
|
||||
let bytecode = read_bytecode(resolved_path).unwrap();
|
||||
let class = load_class(bytecode).unwrap();
|
||||
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 clone1 = class.clone();
|
||||
let clone2 = class.clone();
|
||||
let clone3 = class.clone();
|
||||
|
||||
let inited = class.borrow().inited;
|
||||
if !inited {
|
||||
// must not enter here twice!
|
||||
clone1.borrow_mut().inited = true;
|
||||
clone2.borrow_mut().inited = true;
|
||||
|
||||
let super_class_name = class.clone().borrow().super_class_name.as_ref().map(|n| n.to_owned());
|
||||
let super_class_name = class
|
||||
.clone()
|
||||
.borrow()
|
||||
.super_class_name
|
||||
.as_ref()
|
||||
.map(|n| n.to_owned());
|
||||
{
|
||||
if let Some(super_class_name) = super_class_name {
|
||||
if let Ok(super_class) = get_class(vm, Some(class_name), &super_class_name) {
|
||||
clone1.borrow_mut().super_class = Some(super_class);
|
||||
clone2.borrow_mut().super_class = Some(super_class);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
|
|
@ -53,17 +61,14 @@ pub fn get_class(vm: &mut Vm, _calling_class_name: Option<&str>, class_name: &st
|
|||
}
|
||||
|
||||
Class::initialize_fields(clone3);
|
||||
let clinit = clone1.borrow().methods.contains_key("<clinit>()V");
|
||||
let clinit = clone2.borrow().methods.contains_key("<clinit>()V");
|
||||
if clinit {
|
||||
vm.execute_class(clone1, "<clinit>()V", vec![]).unwrap();
|
||||
}
|
||||
println!("end clinit");
|
||||
|
||||
}
|
||||
Ok(clone2)
|
||||
vm.execute_class(clone2, "<clinit>()V", vec![]).unwrap();
|
||||
}
|
||||
}
|
||||
Ok(clone)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// the class definition as read from the class file + derived values
|
||||
// TODO implement call to static initializers
|
||||
|
|
@ -126,11 +131,19 @@ impl Class {
|
|||
}
|
||||
|
||||
pub(crate) fn n_object_fields(&self) -> usize {
|
||||
self.object_field_mapping.iter().map(|(_, v)| v.len()).reduce(|acc, e| acc + e).unwrap()
|
||||
self.object_field_mapping
|
||||
.iter()
|
||||
.map(|(_, v)| v.len())
|
||||
.reduce(|acc, e| acc + e)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn n_static_fields(&self) -> usize {
|
||||
self.static_field_mapping.iter().map(|(_, v)| v.len()).reduce(|acc, e| acc + e).unwrap()
|
||||
self.static_field_mapping
|
||||
.iter()
|
||||
.map(|(_, v)| v.len())
|
||||
.reduce(|acc, e| acc + e)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
// Create a mapping per field(name) to an index in the storage vector that contains the instance data.
|
||||
|
|
@ -147,7 +160,13 @@ impl Class {
|
|||
let mut object_field_map_index: usize = 0;
|
||||
let mut static_field_map_index: usize = 0;
|
||||
|
||||
Class::add_field_mappings(&mut this_field_mapping, &mut static_field_mapping, class.clone(), &mut object_field_map_index, &mut static_field_map_index);
|
||||
Class::add_field_mappings(
|
||||
&mut this_field_mapping,
|
||||
&mut static_field_mapping,
|
||||
class.clone(),
|
||||
&mut object_field_map_index,
|
||||
&mut static_field_map_index,
|
||||
);
|
||||
|
||||
class.borrow_mut().object_field_mapping = this_field_mapping;
|
||||
class.borrow_mut().static_field_mapping = static_field_mapping;
|
||||
|
|
@ -156,19 +175,31 @@ impl Class {
|
|||
class.borrow_mut().static_data = static_data;
|
||||
}
|
||||
|
||||
fn add_field_mappings(this_field_mapping: &mut HashMap<String, HashMap<String, (String, usize)>>,
|
||||
fn add_field_mappings(
|
||||
this_field_mapping: &mut HashMap<String, HashMap<String, (String, usize)>>,
|
||||
static_field_mapping: &mut HashMap<String, HashMap<String, (String, usize)>>,
|
||||
class: Arc<RefCell<Class>>,
|
||||
object_field_map_index: &mut usize,
|
||||
static_field_map_index: &mut usize) {
|
||||
let (o, s) = Class::map_fields(class.clone(), object_field_map_index, static_field_map_index);
|
||||
static_field_map_index: &mut usize,
|
||||
) {
|
||||
let (o, s) = Class::map_fields(
|
||||
class.clone(),
|
||||
object_field_map_index,
|
||||
static_field_map_index,
|
||||
);
|
||||
let borrow = class.borrow();
|
||||
let name = &borrow.name;
|
||||
this_field_mapping.insert(name.to_owned(), o);
|
||||
static_field_mapping.insert(name.to_owned(), s);
|
||||
|
||||
if let Some(super_class) = class.borrow().super_class.as_ref() {
|
||||
Class::add_field_mappings(this_field_mapping, static_field_mapping, super_class.clone(), object_field_map_index, static_field_map_index);
|
||||
Class::add_field_mappings(
|
||||
this_field_mapping,
|
||||
static_field_mapping,
|
||||
super_class.clone(),
|
||||
object_field_map_index,
|
||||
static_field_map_index,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,7 +208,10 @@ impl Class {
|
|||
class: Arc<RefCell<Class>>,
|
||||
object_field_map_index: &mut usize,
|
||||
static_field_map_index: &mut usize,
|
||||
) -> (HashMap<String, (String, usize)>, HashMap<String, (String, usize)>) {
|
||||
) -> (
|
||||
HashMap<String, (String, usize)>,
|
||||
HashMap<String, (String, usize)>,
|
||||
) {
|
||||
let mut this_fields = HashMap::new(); //fields in class are stored per class and every superclass.
|
||||
let mut static_fields = HashMap::new(); //fields in class are stored per class and every superclass.
|
||||
|
||||
|
|
@ -231,7 +265,7 @@ impl Class {
|
|||
let mut field_data = vec![None; class.borrow().n_static_fields()];
|
||||
|
||||
for (_, this_class) in &class.borrow().static_field_mapping {
|
||||
for (name, (fieldtype, index)) in this_class {
|
||||
for (_name, (fieldtype, index)) in this_class {
|
||||
let value = match fieldtype.as_str() {
|
||||
"Z" => Value::BOOL(false),
|
||||
"B" => Value::I32(0),
|
||||
|
|
@ -364,7 +398,7 @@ pub struct Field {
|
|||
pub(crate) name_index: u16,
|
||||
descriptor_index: u16,
|
||||
attributes: HashMap<String, AttributeType>,
|
||||
index: u16,
|
||||
_index: u16,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Field {
|
||||
|
|
@ -392,7 +426,7 @@ impl Field {
|
|||
name_index,
|
||||
descriptor_index,
|
||||
attributes,
|
||||
index: field_index,
|
||||
_index: field_index,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -416,7 +450,7 @@ impl Field {
|
|||
}
|
||||
}
|
||||
|
||||
const MODIFIERS: [(Modifier, &str); 12] = [
|
||||
const _MODIFIERS: [(Modifier, &str); 12] = [
|
||||
(Modifier::Public, "public "),
|
||||
(Modifier::Private, "private "),
|
||||
(Modifier::Protected, "protected "),
|
||||
|
|
|
|||
|
|
@ -9,10 +9,12 @@ use std::io::Read;
|
|||
/// * [jar/zip]#[package_path]/[class].class
|
||||
/// * [dir]/[package_path]/[class].class
|
||||
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")
|
||||
|| class_name.starts_with("sun/")
|
||||
|| class_name.starts_with("com/sun/")
|
||||
|| class_name.starts_with("jdk/") {
|
||||
|| class_name.starts_with("jdk/")
|
||||
{
|
||||
let mut path: String = "jmods/java.base.jmod#classes/".into();
|
||||
path.push_str(class_name);
|
||||
path.push_str(".class");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
pub mod class;
|
||||
pub mod classloader;
|
||||
mod heap;
|
||||
pub mod heap;
|
||||
pub mod io;
|
||||
pub mod opcodes;
|
||||
pub mod vm;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ fn main() -> Result<(), Error> {
|
|||
|
||||
let mut vm = Vm::new("tests");
|
||||
// let main_class = "Inheritance";
|
||||
let main_class = "Main";
|
||||
let main_class = "testclasses.Main";
|
||||
|
||||
vm.execute(None, main_class, "main([Ljava/lang/String;)V", vec![])
|
||||
.unwrap();
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use std::rc::Rc;
|
||||
use crate::class::{Method, UnsafeValue, Value};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn invoke_native(method: Rc<Method>, args: Vec<UnsafeValue>) -> UnsafeValue {
|
||||
pub fn invoke_native(method: Rc<Method>, _args: Vec<UnsafeValue>) -> UnsafeValue {
|
||||
println!("native {}", method.name());
|
||||
Value::void()
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
581
src/opcodes.rs
581
src/opcodes.rs
|
|
@ -1,145 +1,450 @@
|
|||
pub const NOP: u8 = 0; // (0x0) Do nothing
|
||||
pub const ACONST_NULL: u8 = 1; // (0x01) Push null
|
||||
pub const ICONST_M1: u8 = 2; // (0x2) Push int constant -1
|
||||
pub const ICONST_0: u8 = 3; // (0x3) Push int constant 0
|
||||
pub const ICONST_1: u8 = 4; // (0x4) Push int constant 1
|
||||
pub const ICONST_2: u8 = 5; // (0x5) Push int constant 2
|
||||
pub const ICONST_3: u8 = 6; // (0x6) Push int constant 3
|
||||
pub const ICONST_4: u8 = 7; // (0x7) Push int constant 4
|
||||
pub const ICONST_5: u8 = 8; // (0x8) Push int constant 5
|
||||
pub const LCONST_0: u8 = 9; // (0x9) Push long constant 0
|
||||
pub const LCONST_1: u8 = 10; // (0xa) Push long constant 1
|
||||
pub const FCONST_0: u8 = 11; // (0xb) Push float 0
|
||||
pub const FCONST_1: u8 = 12; // (0xc) Push float 1
|
||||
pub const FCONST_2: u8 = 13; // (0xd) Push float 2
|
||||
pub const DCONST_0: u8 = 14; // (0xe) push double 0
|
||||
pub const DCONST_1: u8 = 15; // (0xe) push double 1
|
||||
pub const BIPUSH: u8 = 16; // (0x10) Push byte
|
||||
pub const SIPUSH: u8 = 17; // (0x11) Push short
|
||||
pub const LDC: u8 = 18; // (0x12) Push item from run-time pub constant pool
|
||||
pub const LDC_W: u8 = 19; // (0x13) Push item from run-time constant pool (wide index)
|
||||
pub const LDC2_W: u8 = 20; // (0x14) Push long or double from run-time constant pool (wide index)
|
||||
pub const ILOAD: u8 = 21; // (0x15) Load int from local variable
|
||||
pub const LLOAD: u8 = 22; // (0x16) Load long from local variable
|
||||
pub const FLOAD: u8 = 23; // (0x16) Load float from local variable
|
||||
pub const DLOAD: u8 = 24; // (0x18) load double from local variable
|
||||
pub const ALOAD: u8 = 25; // 0x19 Load reference from local variable
|
||||
pub const ILOAD_0: u8 = 26; // (0x1a) Load int from local variable 0
|
||||
pub const ILOAD_1: u8 = 27; // (0x1b) Load int from local variable 1
|
||||
pub const ILOAD_2: u8 = 28; // (0x1c) Load int from local variable 2
|
||||
pub const ILOAD_3: u8 = 29; // (0x1d) Load int from local variable 3
|
||||
pub const LLOAD_0: u8 = 30; // (0x1e) Load long from local variable 0
|
||||
pub const LLOAD_1: u8 = 31; // (0x1f) Load long from local variable 1
|
||||
pub const LLOAD_2: u8 = 32; // (0x20) Load long from local variable 2
|
||||
pub const LLOAD_3: u8 = 33; // (0x21) Load long from local variable 3
|
||||
pub const FLOAD_0: u8 = 34; // (0x22) Load float from local variable 0
|
||||
pub const FLOAD_1: u8 = 35; // (0x23) Load float from local variable 1
|
||||
pub const FLOAD_2: u8 = 36; // (0x24) Load float from local variable 2
|
||||
pub const FLOAD_3: u8 = 37; // (0x25) Load float from local variable 3
|
||||
pub const DLOAD_0: u8 = 38; // (0x26) Load double from local variable 0
|
||||
pub const DLOAD_1: u8 = 39; // (0x27) Load double from local variable 1
|
||||
pub const DLOAD_2: u8 = 40; // (0x28) Load double from local variable 2
|
||||
pub const DLOAD_3: u8 = 41; // (0x29) Load double from local variable 3
|
||||
pub const ALOAD_0: u8 = 42; // (0x2a) Load reference from local variable 0
|
||||
pub const ALOAD_1: u8 = 43; // (0x2b) Load reference from local variable 1
|
||||
pub const ALOAD_2: u8 = 44; // (0x2c) Load reference from local variable 2
|
||||
pub const ALOAD_3: u8 = 45; // (0x2d) Load reference from local variable 3
|
||||
pub const IALOAD: u8 = 46; // (0x2e) Load int from array
|
||||
pub const LALOAD: u8 = 47; // (0x2f) Load long from array
|
||||
pub const FALOAD: u8 = 48; // (0x30) Load float from array
|
||||
pub const DALOAD: u8 = 49; // (0x31) Load double from array
|
||||
pub const AALOAD: u8 = 50; // (0x3d) Load reference from array
|
||||
pub const BALOAD: u8 = 51; // (0x33) Load byte or boolean from array
|
||||
pub const CALOAD: u8 = 52; // (0x34) Load char from array
|
||||
pub const SALOAD: u8 = 53; // (0x34) Load short from array
|
||||
pub const ISTORE: u8 = 54; // (0x36) Store int into local variable
|
||||
pub const LSTORE: u8 = 55; // (0x37) Store long into local variable
|
||||
pub const FSTORE: u8 = 56; // (0x38) Store float into local variable
|
||||
pub const DSTORE: u8 = 57; // (0x39) store double in local variable
|
||||
pub const ASTORE: u8 = 58; // (0x3a)
|
||||
pub const ISTORE_0: u8 = 59; // (0x3b) Store int into local variable 0
|
||||
pub const ISTORE_1: u8 = 60; // (0x3c) Store int into local variable 1
|
||||
pub const ISTORE_2: u8 = 61; // (0x3d) Store int into local variable 2
|
||||
pub const ISTORE_3: u8 = 62; // (0x3e) Store int into local variable 3
|
||||
pub const LSTORE_0: u8 = 63; // (0x3f) Store long into local variable 0
|
||||
pub const LSTORE_1: u8 = 64; // (0x40) Store long into local variable 1
|
||||
pub const LSTORE_2: u8 = 65; // (0x41) Store long into local variable 2
|
||||
pub const LSTORE_3: u8 = 66; // (0x42) Store long into local variable 3
|
||||
pub const FSTORE_0: u8 = 67; // (0x43) Store float into local variable 0
|
||||
pub const FSTORE_1: u8 = 68; // (0x44) Store float into local variable 1
|
||||
pub const FSTORE_2: u8 = 69; // (0x45) Store float into local variable 2
|
||||
pub const FSTORE_3: u8 = 70; // (0x46) Store float into local variable 3
|
||||
pub const DSTORE_0: u8 = 71; // (0x47) store double in local variable 0
|
||||
pub const DSTORE_1: u8 = 72; // (0x48) store double in local variable 1
|
||||
pub const DSTORE_2: u8 = 73; // (0x49) store double in local variable 2
|
||||
pub const DSTORE_3: u8 = 74; // (0x4a) store double in local variable 3
|
||||
pub const ASTORE_0: u8 = 75; // (0x4b)
|
||||
pub const ASTORE_1: u8 = 76; // (0x4c)
|
||||
pub const ASTORE_2: u8 = 77; // (0x4d)
|
||||
pub const ASTORE_3: u8 = 78; // (0x4e)
|
||||
pub const IASTORE: u8 = 79; // (0x4f) Store into int array
|
||||
pub const LASTORE: u8 = 80; // (0x50) Store into long array
|
||||
pub const FASTORE: u8 = 81; // (0x51) Store into float array
|
||||
pub const DASTORE: u8 = 82; // (0x52) store into double array
|
||||
pub const AASTORE: u8 = 83; // (0x53) Store into object array
|
||||
pub const BASTORE: u8 = 84; // (0x54) Store into byte or boolean array
|
||||
pub const CASTORE: u8 = 85; // (0x55) Store into char array
|
||||
pub const SASTORE: u8 = 86; // (0x56) Store into short array
|
||||
pub const POP: u8 = 87; // (0x57) Pop the top operand stack value
|
||||
pub const DUP: u8 = 89; // (0x59) duplicate the top operand stack value
|
||||
pub const dup_x1: u8 = 90; // (0x5a) Duplicate the top operand stack value and insert two values down
|
||||
pub const dup_x2: u8 = 91; // (0x5b) Duplicate the top operand stack value and insert two or three values down
|
||||
pub const dup2: u8 = 92; // (0x5c) Duplicate the top one or two operand stack values
|
||||
pub const dup2_x1: u8 = 93; //(0x5d) Duplicate the top one or two operand stack values and insert two or three values down
|
||||
pub const dup2_x2: u8 = 94; // (0x5e) Duplicate the top one or two operand stack values and insert two, three, or four values down
|
||||
//comment line should be above declaration
|
||||
|
||||
pub const fadd: u8 = 98; // (0x62) Add float
|
||||
pub const dadd: u8 = 99; // (0x63) add double
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
pub const dsub: u8 = 103; // (0x67) subtract double
|
||||
pub const fmul: u8 = 106; // (0x6a) Multiply float
|
||||
pub const dmul: u8 = 107; // (0x6b) Multiply double
|
||||
pub const NOP: u8 = 0;
|
||||
// (0x0) Do nothing
|
||||
pub const ACONST_NULL: u8 = 1;
|
||||
// (0x01) Push null
|
||||
pub const ICONST_M1: u8 = 2;
|
||||
// (0x2) Push int constant -1
|
||||
pub const ICONST_0: u8 = 3;
|
||||
// (0x3) Push int constant 0
|
||||
pub const ICONST_1: u8 = 4;
|
||||
// (0x4) Push int constant 1
|
||||
pub const ICONST_2: u8 = 5;
|
||||
// (0x5) Push int constant 2
|
||||
pub const ICONST_3: u8 = 6;
|
||||
// (0x6) Push int constant 3
|
||||
pub const ICONST_4: u8 = 7;
|
||||
// (0x7) Push int constant 4
|
||||
pub const ICONST_5: u8 = 8;
|
||||
// (0x8) Push int constant 5
|
||||
pub const LCONST_0: u8 = 9;
|
||||
// (0x9) Push long constant 0
|
||||
pub const LCONST_1: u8 = 10;
|
||||
// (0xa) Push long constant 1
|
||||
pub const FCONST_0: u8 = 11;
|
||||
// (0xb) Push float 0
|
||||
pub const FCONST_1: u8 = 12;
|
||||
// (0xc) Push float 1
|
||||
pub const FCONST_2: u8 = 13;
|
||||
// (0xd) Push float 2
|
||||
pub const DCONST_0: u8 = 14;
|
||||
// (0xe) push double 0
|
||||
pub const DCONST_1: u8 = 15;
|
||||
// (0xe) push double 1
|
||||
pub const BIPUSH: u8 = 16;
|
||||
// (0x10) Push byte
|
||||
pub const SIPUSH: u8 = 17;
|
||||
// (0x11) Push short
|
||||
pub const LDC: u8 = 18;
|
||||
// (0x12) Push item from run-time pub constant pool
|
||||
pub const LDC_W: u8 = 19;
|
||||
// (0x13) Push item from run-time constant pool (wide index)
|
||||
pub const LDC2_W: u8 = 20;
|
||||
// (0x14) Push long or double from run-time constant pool (wide index)
|
||||
pub const ILOAD: u8 = 21;
|
||||
// (0x15) Load int from local variable
|
||||
pub const LLOAD: u8 = 22;
|
||||
// (0x16) Load long from local variable
|
||||
pub const FLOAD: u8 = 23;
|
||||
// (0x16) Load float from local variable
|
||||
pub const DLOAD: u8 = 24;
|
||||
// (0x18) load double from local variable
|
||||
pub const ALOAD: u8 = 25;
|
||||
// 0x19 Load reference from local variable
|
||||
pub const ILOAD_0: u8 = 26;
|
||||
// (0x1a) Load int from local variable 0
|
||||
pub const ILOAD_1: u8 = 27;
|
||||
// (0x1b) Load int from local variable 1
|
||||
pub const ILOAD_2: u8 = 28;
|
||||
// (0x1c) Load int from local variable 2
|
||||
pub const ILOAD_3: u8 = 29;
|
||||
// (0x1d) Load int from local variable 3
|
||||
pub const LLOAD_0: u8 = 30;
|
||||
// (0x1e) Load long from local variable 0
|
||||
pub const LLOAD_1: u8 = 31;
|
||||
// (0x1f) Load long from local variable 1
|
||||
pub const LLOAD_2: u8 = 32;
|
||||
// (0x20) Load long from local variable 2
|
||||
pub const LLOAD_3: u8 = 33;
|
||||
// (0x21) Load long from local variable 3
|
||||
pub const FLOAD_0: u8 = 34;
|
||||
// (0x22) Load float from local variable 0
|
||||
pub const FLOAD_1: u8 = 35;
|
||||
// (0x23) Load float from local variable 1
|
||||
pub const FLOAD_2: u8 = 36;
|
||||
// (0x24) Load float from local variable 2
|
||||
pub const FLOAD_3: u8 = 37;
|
||||
// (0x25) Load float from local variable 3
|
||||
pub const DLOAD_0: u8 = 38;
|
||||
// (0x26) Load double from local variable 0
|
||||
pub const DLOAD_1: u8 = 39;
|
||||
// (0x27) Load double from local variable 1
|
||||
pub const DLOAD_2: u8 = 40;
|
||||
// (0x28) Load double from local variable 2
|
||||
pub const DLOAD_3: u8 = 41;
|
||||
// (0x29) Load double from local variable 3
|
||||
pub const ALOAD_0: u8 = 42;
|
||||
// (0x2a) Load reference from local variable 0
|
||||
pub const ALOAD_1: u8 = 43;
|
||||
// (0x2b) Load reference from local variable 1
|
||||
pub const ALOAD_2: u8 = 44;
|
||||
// (0x2c) Load reference from local variable 2
|
||||
pub const ALOAD_3: u8 = 45;
|
||||
// (0x2d) Load reference from local variable 3
|
||||
pub const IALOAD: u8 = 46;
|
||||
// (0x2e) Load int from array
|
||||
pub const LALOAD: u8 = 47;
|
||||
// (0x2f) Load long from array
|
||||
pub const FALOAD: u8 = 48;
|
||||
// (0x30) Load float from array
|
||||
pub const DALOAD: u8 = 49;
|
||||
// (0x31) Load double from array
|
||||
pub const AALOAD: u8 = 50;
|
||||
// (0x3d) Load reference from array
|
||||
pub const BALOAD: u8 = 51;
|
||||
// (0x33) Load byte or boolean from array
|
||||
pub const CALOAD: u8 = 52;
|
||||
// (0x34) Load char from array
|
||||
pub const SALOAD: u8 = 53;
|
||||
// (0x34) Load short from array
|
||||
pub const ISTORE: u8 = 54;
|
||||
// (0x36) Store int into local variable
|
||||
pub const LSTORE: u8 = 55;
|
||||
// (0x37) Store long into local variable
|
||||
pub const FSTORE: u8 = 56;
|
||||
// (0x38) Store float into local variable
|
||||
pub const DSTORE: u8 = 57;
|
||||
// (0x39) store double in local variable
|
||||
pub const ASTORE: u8 = 58;
|
||||
// (0x3a)
|
||||
pub const ISTORE_0: u8 = 59;
|
||||
// (0x3b) Store int into local variable 0
|
||||
pub const ISTORE_1: u8 = 60;
|
||||
// (0x3c) Store int into local variable 1
|
||||
pub const ISTORE_2: u8 = 61;
|
||||
// (0x3d) Store int into local variable 2
|
||||
pub const ISTORE_3: u8 = 62;
|
||||
// (0x3e) Store int into local variable 3
|
||||
pub const LSTORE_0: u8 = 63;
|
||||
// (0x3f) Store long into local variable 0
|
||||
pub const LSTORE_1: u8 = 64;
|
||||
// (0x40) Store long into local variable 1
|
||||
pub const LSTORE_2: u8 = 65;
|
||||
// (0x41) Store long into local variable 2
|
||||
pub const LSTORE_3: u8 = 66;
|
||||
// (0x42) Store long into local variable 3
|
||||
pub const FSTORE_0: u8 = 67;
|
||||
// (0x43) Store float into local variable 0
|
||||
pub const FSTORE_1: u8 = 68;
|
||||
// (0x44) Store float into local variable 1
|
||||
pub const FSTORE_2: u8 = 69;
|
||||
// (0x45) Store float into local variable 2
|
||||
pub const FSTORE_3: u8 = 70;
|
||||
// (0x46) Store float into local variable 3
|
||||
pub const DSTORE_0: u8 = 71;
|
||||
// (0x47) store double in local variable 0
|
||||
pub const DSTORE_1: u8 = 72;
|
||||
// (0x48) store double in local variable 1
|
||||
pub const DSTORE_2: u8 = 73;
|
||||
// (0x49) store double in local variable 2
|
||||
pub const DSTORE_3: u8 = 74;
|
||||
// (0x4a) store double in local variable 3
|
||||
pub const ASTORE_0: u8 = 75;
|
||||
// (0x4b)
|
||||
pub const ASTORE_1: u8 = 76;
|
||||
// (0x4c)
|
||||
pub const ASTORE_2: u8 = 77;
|
||||
// (0x4d)
|
||||
pub const ASTORE_3: u8 = 78;
|
||||
// (0x4e)
|
||||
pub const IASTORE: u8 = 79;
|
||||
// (0x4f) Store into int array
|
||||
pub const LASTORE: u8 = 80;
|
||||
// (0x50) Store into long array
|
||||
pub const FASTORE: u8 = 81;
|
||||
// (0x51) Store into float array
|
||||
pub const DASTORE: u8 = 82;
|
||||
// (0x52) store into double array
|
||||
pub const AASTORE: u8 = 83;
|
||||
// (0x53) Store into object array
|
||||
pub const BASTORE: u8 = 84;
|
||||
// (0x54) Store into byte or boolean array
|
||||
pub const CASTORE: u8 = 85;
|
||||
// (0x55) Store into char array
|
||||
pub const SASTORE: u8 = 86;
|
||||
// (0x56) Store into short array
|
||||
pub const POP: u8 = 87;
|
||||
// (0x57) Pop the top operand stack value
|
||||
pub const DUP: u8 = 89;
|
||||
// (0x59) duplicate the top operand stack value
|
||||
pub const _DUP_X1: u8 = 90;
|
||||
// (0x5a) Duplicate the top operand stack value and insert two values down
|
||||
pub const _DUP_X2: u8 = 91;
|
||||
// (0x5b) Duplicate the top operand stack value and insert two or three values down
|
||||
pub const _DUP2: u8 = 92;
|
||||
// (0x5c) Duplicate the top one or two operand stack values
|
||||
pub const _DUP2_X1: u8 = 93;
|
||||
//(0x5d) Duplicate the top one or two operand stack values and insert two or three values down
|
||||
pub const _DUP2_X2: u8 = 94; // (0x5e) Duplicate the top one or two operand stack values and insert two, three, or four values down
|
||||
|
||||
pub const fdiv: u8 = 110; // (0x6e) Divide float
|
||||
pub const ddiv: u8 = 111; // (0x6f) divide double
|
||||
pub const frem: u8 = 114; // (0x72) Remainder float
|
||||
pub const drem: u8 = 115; // (0x73) remainder double
|
||||
pub const fneg: u8 = 118; // (0x76) Negate float
|
||||
pub const dneg: u8 = 119; // (0x77) Negate double
|
||||
pub const _FADD: u8 = 98;
|
||||
// (0x62) Add float
|
||||
pub const _DADD: u8 = 99; // (0x63) add double
|
||||
|
||||
pub const f2i: u8 = 139; // (0x8b) Convert float to int
|
||||
pub const f2l: u8 = 140; // (0x8c) Convert float to long
|
||||
pub const f2d: u8 = 141; // (0x8d) Convert float to double
|
||||
pub const d2i: u8 = 142; // (0x8e) double to int
|
||||
pub const d2l: u8 = 143; // (0x8f) double to long
|
||||
pub const d2f: u8 = 144; // (0x90) double to float
|
||||
pub const _DSUB: u8 = 103;
|
||||
// (0x67) subtract double
|
||||
pub const _FMUL: u8 = 106;
|
||||
// (0x6a) Multiply float
|
||||
pub const _DMUL: u8 = 107; // (0x6b) Multiply double
|
||||
|
||||
pub const fcmpl: u8 = 149; // (0x95) Compare float (less than)
|
||||
pub const fcmpg: u8 = 150; // (0x96) Compare float (greater than)
|
||||
pub const dcmpl: u8 = 151; // (0x97) compare double (less than)
|
||||
pub const dcmpg: u8 = 152; // (0x98) compare double (greater than)
|
||||
pub const IF_ICMPEQ:u8 = 159; // (0x9f) Branch if int comparison succeeds
|
||||
pub const IF_ICMPNE:u8 = 160; // (0x9f) Branch if int comparison succeeds
|
||||
pub const IF_ICMPLT:u8 = 161; // (0x9f) Branch if int comparison succeeds
|
||||
pub const IF_ICMPGE:u8 = 162; // (0x9f) Branch if int comparison succeeds
|
||||
pub const IF_ICMPGT:u8 = 163; // (0x9f) Branch if int comparison succeeds
|
||||
pub const IF_ICMPLE:u8 = 164; // (0x9f) Branch if int comparison succeeds
|
||||
pub const _FDIV: u8 = 110;
|
||||
// (0x6e) Divide float
|
||||
pub const _DDIV: u8 = 111;
|
||||
// (0x6f) divide double
|
||||
pub const _FREM: u8 = 114;
|
||||
// (0x72) Remainder float
|
||||
pub const _DREM: u8 = 115;
|
||||
// (0x73) remainder double
|
||||
pub const _FNEG: u8 = 118;
|
||||
// (0x76) Negate float
|
||||
pub const _DNEG: u8 = 119; // (0x77) Negate double
|
||||
|
||||
pub const _F2I: u8 = 139;
|
||||
// (0x8b) Convert float to int
|
||||
pub const _F2L: u8 = 140;
|
||||
// (0x8c) Convert float to long
|
||||
pub const _F2D: u8 = 141;
|
||||
// (0x8d) Convert float to double
|
||||
pub const _D2I: u8 = 142;
|
||||
// (0x8e) double to int
|
||||
pub const _D2L: u8 = 143;
|
||||
// (0x8f) double to long
|
||||
pub const _D2F: u8 = 144; // (0x90) double to float
|
||||
|
||||
pub const _FCMPL: u8 = 149;
|
||||
// (0x95) Compare float (less than)
|
||||
pub const _FCMPG: u8 = 150;
|
||||
// (0x96) Compare float (greater than)
|
||||
pub const _DCMPL: u8 = 151;
|
||||
// (0x97) compare double (less than)
|
||||
pub const _DCMPG: u8 = 152; // (0x98) compare double (greater than)
|
||||
|
||||
pub const IFEQ: u8 = 153;
|
||||
// (0x99)
|
||||
pub const IFNE: u8 = 154;
|
||||
// (0x9a)
|
||||
pub const IFLT: u8 = 155;
|
||||
// (0x9b)
|
||||
pub const IFGE: u8 = 156;
|
||||
// (0x9c)
|
||||
pub const IFGT: u8 = 157;
|
||||
// (0x9d)
|
||||
pub const IFLE: u8 = 158; // (0x9e)
|
||||
|
||||
pub const IF_ICMPEQ: u8 = 159;
|
||||
// (0x9f) Branch if int comparison succeeds
|
||||
pub const IF_ICMPNE: u8 = 160;
|
||||
// (0x9f) Branch if int comparison succeeds
|
||||
pub const IF_ICMPLT: u8 = 161;
|
||||
// (0x9f) Branch if int comparison succeeds
|
||||
pub const IF_ICMPGE: u8 = 162;
|
||||
// (0x9f) Branch if int comparison succeeds
|
||||
pub const IF_ICMPGT: u8 = 163;
|
||||
// (0x9f) Branch if int comparison succeeds
|
||||
pub const IF_ICMPLE: u8 = 164;
|
||||
// (0x9f) Branch if int comparison succeeds
|
||||
pub const GOTO: u8 = 167; // (0xa7) Branch always
|
||||
|
||||
pub const IRETURN: u8 = 172; // (0xac) ireturn
|
||||
pub const FRETURN: u8 = 174; // (0xae) Return float from method
|
||||
pub const DRETURN: u8 = 175; // (0xaf) Return double from method
|
||||
pub const areturn: u8 = 176; //(0xb0) return reference
|
||||
pub const RETURN_VOID: u8 = 177; // (0xb1) Return void from method (actually 'return' but that's a keyword)
|
||||
pub const GETSTATIC: u8 = 178; // (0xb2) Get static field from class
|
||||
pub const PUTSTATIC: u8 = 179; // (0xb3) Set static field in class
|
||||
pub const GETFIELD: u8 = 180; // (0xb4) Fetch field from object3
|
||||
pub const PUTFIELD: u8 = 181; // (0xb5) Set field in object
|
||||
pub const INVOKEVIRTUAL: u8 = 182; // (0xb6) Invoke instance method; dispatch based on class
|
||||
pub const INVOKESPECIAL: u8 = 183; // (0xb7) // nvoke instance method; direct invocation of instance initialization methods and methods of the current class and its supertypes
|
||||
pub const INVOKESTATIC: u8 = 184; // (0xb8) Invoke a class (static) method
|
||||
pub const NEW: u8 = 187; // (0xbb) Create new object
|
||||
pub const ANEWARRAY: u8 = 189; // (0xbd)
|
||||
pub const arraylength: u8 = 190; // (0xbe)
|
||||
pub const athrow: u8 = 191; // (0xbf)
|
||||
pub const checkcast: u8 = 192; // (0xc0)
|
||||
pub const IRETURN: u8 = 172;
|
||||
// (0xac) ireturn
|
||||
pub const FRETURN: u8 = 174;
|
||||
// (0xae) Return float from method
|
||||
pub const DRETURN: u8 = 175;
|
||||
// (0xaf) Return double from method
|
||||
pub const ARETURN: u8 = 176;
|
||||
//(0xb0) return reference
|
||||
pub const RETURN_VOID: u8 = 177;
|
||||
// (0xb1) Return void from method (actually 'return' but that's a keyword)
|
||||
pub const GETSTATIC: u8 = 178;
|
||||
// (0xb2) Get static field from class
|
||||
pub const PUTSTATIC: u8 = 179;
|
||||
// (0xb3) Set static field in class
|
||||
pub const GETFIELD: u8 = 180;
|
||||
// (0xb4) Fetch field from object3
|
||||
pub const PUTFIELD: u8 = 181;
|
||||
// (0xb5) Set field in object
|
||||
pub const INVOKEVIRTUAL: u8 = 182;
|
||||
// (0xb6) Invoke instance method; dispatch based on class
|
||||
pub const INVOKESPECIAL: u8 = 183;
|
||||
// (0xb7) // nvoke instance method; direct invocation of instance initialization methods and methods of the current class and its supertypes
|
||||
pub const INVOKESTATIC: u8 = 184;
|
||||
// (0xb8) Invoke a class (static) method
|
||||
pub const NEW: u8 = 187;
|
||||
// (0xbb) Create new object
|
||||
pub const ANEWARRAY: u8 = 189;
|
||||
// (0xbd)
|
||||
pub const _ARRAYLENGTH: u8 = 190;
|
||||
// (0xbe)
|
||||
pub const _ATHROW: u8 = 191;
|
||||
// (0xbf)
|
||||
pub const _CHECKCAST: u8 = 192;
|
||||
// (0xc0)
|
||||
pub const MONITORENTER: u8 = 194;
|
||||
pub const IFNULL: u8 = 198;
|
||||
pub const IFNONNULL: u8 = 199;
|
||||
|
||||
pub const OPCODES:Lazy<Vec<&str>> = Lazy::new(|| {
|
||||
let mut opcodes = vec!["";256];
|
||||
opcodes[NOP as usize] = "NOP" ;
|
||||
opcodes[ACONST_NULL as usize] = "ACONST_NULL" ;
|
||||
opcodes[ICONST_M1 as usize] = "ICONST_M1" ;
|
||||
opcodes[ICONST_0 as usize] = "ICONST_0" ;
|
||||
opcodes[ICONST_1 as usize] = "ICONST_1" ;
|
||||
opcodes[ICONST_2 as usize] = "ICONST_2" ;
|
||||
opcodes[ICONST_3 as usize] = "ICONST_3" ;
|
||||
opcodes[ICONST_4 as usize] = "ICONST_4" ;
|
||||
opcodes[ICONST_5 as usize] = "ICONST_5" ;
|
||||
opcodes[LCONST_0 as usize] = "LCONST_0" ;
|
||||
opcodes[LCONST_1 as usize] = "LCONST_1" ;
|
||||
opcodes[FCONST_0 as usize] = "FCONST_0" ;
|
||||
opcodes[FCONST_1 as usize] = "FCONST_1" ;
|
||||
opcodes[FCONST_2 as usize] = "FCONST_2" ;
|
||||
opcodes[DCONST_0 as usize] = "DCONST_0" ;
|
||||
opcodes[DCONST_1 as usize] = "DCONST_1" ;
|
||||
opcodes[BIPUSH as usize] = "BIPUSH" ;
|
||||
opcodes[SIPUSH as usize] = "SIPUSH" ;
|
||||
opcodes[LDC as usize] = "LDC" ;
|
||||
opcodes[LDC_W as usize] = "LDC_W" ;
|
||||
opcodes[LDC2_W as usize] = "LDC2_W" ;
|
||||
opcodes[ILOAD as usize] = "ILOAD" ;
|
||||
opcodes[LLOAD as usize] = "LLOAD" ;
|
||||
opcodes[FLOAD as usize] = "FLOAD" ;
|
||||
opcodes[DLOAD as usize] = "DLOAD" ;
|
||||
opcodes[ALOAD as usize] = "ALOAD" ;
|
||||
opcodes[ILOAD_0 as usize] = "ILOAD_0" ;
|
||||
opcodes[ILOAD_1 as usize] = "ILOAD_1" ;
|
||||
opcodes[ILOAD_2 as usize] = "ILOAD_2" ;
|
||||
opcodes[ILOAD_3 as usize] = "ILOAD_3" ;
|
||||
opcodes[LLOAD_0 as usize] = "LLOAD_0" ;
|
||||
opcodes[LLOAD_1 as usize] = "LLOAD_1" ;
|
||||
opcodes[LLOAD_2 as usize] = "LLOAD_2" ;
|
||||
opcodes[LLOAD_3 as usize] = "LLOAD_3" ;
|
||||
opcodes[FLOAD_0 as usize] = "FLOAD_0" ;
|
||||
opcodes[FLOAD_1 as usize] = "FLOAD_1" ;
|
||||
opcodes[FLOAD_2 as usize] = "FLOAD_2" ;
|
||||
opcodes[FLOAD_3 as usize] = "FLOAD_3" ;
|
||||
opcodes[DLOAD_0 as usize] = "DLOAD_0" ;
|
||||
opcodes[DLOAD_1 as usize] = "DLOAD_1" ;
|
||||
opcodes[DLOAD_2 as usize] = "DLOAD_2" ;
|
||||
opcodes[DLOAD_3 as usize] = "DLOAD_3" ;
|
||||
opcodes[ALOAD_0 as usize] = "ALOAD_0" ;
|
||||
opcodes[ALOAD_1 as usize] = "ALOAD_1" ;
|
||||
opcodes[ALOAD_2 as usize] = "ALOAD_2" ;
|
||||
opcodes[ALOAD_3 as usize] = "ALOAD_3" ;
|
||||
opcodes[IALOAD as usize] = "IALOAD" ;
|
||||
opcodes[LALOAD as usize] = "LALOAD" ;
|
||||
opcodes[FALOAD as usize] = "FALOAD" ;
|
||||
opcodes[DALOAD as usize] = "DALOAD" ;
|
||||
opcodes[AALOAD as usize] = "AALOAD" ;
|
||||
opcodes[BALOAD as usize] = "BALOAD" ;
|
||||
opcodes[CALOAD as usize] = "CALOAD" ;
|
||||
opcodes[SALOAD as usize] = "SALOAD" ;
|
||||
opcodes[ISTORE as usize] = "ISTORE" ;
|
||||
opcodes[LSTORE as usize] = "LSTORE" ;
|
||||
opcodes[FSTORE as usize] = "FSTORE" ;
|
||||
opcodes[DSTORE as usize] = "DSTORE" ;
|
||||
opcodes[ASTORE as usize] = "ASTORE" ;
|
||||
opcodes[ISTORE_0 as usize] = "ISTORE_0" ;
|
||||
opcodes[ISTORE_1 as usize] = "ISTORE_1" ;
|
||||
opcodes[ISTORE_2 as usize] = "ISTORE_2" ;
|
||||
opcodes[ISTORE_3 as usize] = "ISTORE_3" ;
|
||||
opcodes[LSTORE_0 as usize] = "LSTORE_0" ;
|
||||
opcodes[LSTORE_1 as usize] = "LSTORE_1" ;
|
||||
opcodes[LSTORE_2 as usize] = "LSTORE_2" ;
|
||||
opcodes[LSTORE_3 as usize] = "LSTORE_3" ;
|
||||
opcodes[FSTORE_0 as usize] = "FSTORE_0" ;
|
||||
opcodes[FSTORE_1 as usize] = "FSTORE_1" ;
|
||||
opcodes[FSTORE_2 as usize] = "FSTORE_2" ;
|
||||
opcodes[FSTORE_3 as usize] = "FSTORE_3" ;
|
||||
opcodes[DSTORE_0 as usize] = "DSTORE_0" ;
|
||||
opcodes[DSTORE_1 as usize] = "DSTORE_1" ;
|
||||
opcodes[DSTORE_2 as usize] = "DSTORE_2" ;
|
||||
opcodes[DSTORE_3 as usize] = "DSTORE_3" ;
|
||||
opcodes[ASTORE_0 as usize] = "ASTORE_0" ;
|
||||
opcodes[ASTORE_1 as usize] = "ASTORE_1" ;
|
||||
opcodes[ASTORE_2 as usize] = "ASTORE_2" ;
|
||||
opcodes[ASTORE_3 as usize] = "ASTORE_3" ;
|
||||
opcodes[IASTORE as usize] = "IASTORE" ;
|
||||
opcodes[LASTORE as usize] = "LASTORE" ;
|
||||
opcodes[FASTORE as usize] = "FASTORE" ;
|
||||
opcodes[DASTORE as usize] = "DASTORE" ;
|
||||
opcodes[AASTORE as usize] = "AASTORE" ;
|
||||
opcodes[BASTORE as usize] = "BASTORE" ;
|
||||
opcodes[CASTORE as usize] = "CASTORE" ;
|
||||
opcodes[SASTORE as usize] = "SASTORE" ;
|
||||
opcodes[POP as usize] = "POP" ;
|
||||
opcodes[DUP as usize] = "DUP" ;
|
||||
opcodes[_DUP_X1 as usize] = "_DUP_X1" ;
|
||||
opcodes[_DUP_X2 as usize] = "_DUP_X2" ;
|
||||
opcodes[_DUP2 as usize] = "_DUP2" ;
|
||||
opcodes[_DUP2_X1 as usize] = "_DUP2_X1" ;
|
||||
opcodes[_DUP2_X2 as usize] = "_DUP2_X2" ;
|
||||
opcodes[_FADD as usize] = "_FADD" ;
|
||||
opcodes[_DADD as usize] = "_DADD" ;
|
||||
opcodes[_DSUB as usize] = "_DSUB" ;
|
||||
opcodes[_FMUL as usize] = "_FMUL" ;
|
||||
opcodes[_DMUL as usize] = "_DMUL" ;
|
||||
opcodes[_FDIV as usize] = "_FDIV" ;
|
||||
opcodes[_DDIV as usize] = "_DDIV" ;
|
||||
opcodes[_FREM as usize] = "_FREM" ;
|
||||
opcodes[_DREM as usize] = "_DREM" ;
|
||||
opcodes[_FNEG as usize] = "_FNEG" ;
|
||||
opcodes[_DNEG as usize] = "_DNEG" ;
|
||||
opcodes[_F2I as usize] = "_F2I" ;
|
||||
opcodes[_F2L as usize] = "_F2L" ;
|
||||
opcodes[_F2D as usize] = "_F2D" ;
|
||||
opcodes[_D2I as usize] = "_D2I" ;
|
||||
opcodes[_D2L as usize] = "_D2L" ;
|
||||
opcodes[_D2F as usize] = "_D2F" ;
|
||||
opcodes[_FCMPL as usize] = "_FCMPL" ;
|
||||
opcodes[_FCMPG as usize] = "_FCMPG" ;
|
||||
opcodes[_DCMPL as usize] = "_DCMPL" ;
|
||||
opcodes[_DCMPG as usize] = "_DCMPG" ;
|
||||
opcodes[IFEQ as usize] = "IFEQ" ;
|
||||
opcodes[IFNE as usize] = "IFNE" ;
|
||||
opcodes[IFLT as usize] = "IFLT" ;
|
||||
opcodes[IFGE as usize] = "IFGE" ;
|
||||
opcodes[IFGT as usize] = "IFGT" ;
|
||||
opcodes[IFLE as usize] = "IFLE" ;
|
||||
opcodes[IF_ICMPEQ as usize] = "IF_ICMPEQ" ;
|
||||
opcodes[IF_ICMPNE as usize] = "IF_ICMPNE" ;
|
||||
opcodes[IF_ICMPLT as usize] = "IF_ICMPLT" ;
|
||||
opcodes[IF_ICMPGE as usize] = "IF_ICMPGE" ;
|
||||
opcodes[IF_ICMPGT as usize] = "IF_ICMPGT" ;
|
||||
opcodes[IF_ICMPLE as usize] = "IF_ICMPLE" ;
|
||||
opcodes[GOTO as usize] = "GOTO" ;
|
||||
opcodes[IRETURN as usize] = "IRETURN" ;
|
||||
opcodes[FRETURN as usize] = "FRETURN" ;
|
||||
opcodes[DRETURN as usize] = "DRETURN" ;
|
||||
opcodes[ARETURN as usize] = "ARETURN" ;
|
||||
opcodes[RETURN_VOID as usize] = "RETURN_VOID" ;
|
||||
opcodes[GETSTATIC as usize] = "GETSTATIC" ;
|
||||
opcodes[PUTSTATIC as usize] = "PUTSTATIC" ;
|
||||
opcodes[GETFIELD as usize] = "GETFIELD" ;
|
||||
opcodes[PUTFIELD as usize] = "PUTFIELD" ;
|
||||
opcodes[INVOKEVIRTUAL as usize] = "INVOKEVIRTUAL" ;
|
||||
opcodes[INVOKESPECIAL as usize] = "INVOKESPECIAL" ;
|
||||
opcodes[INVOKESTATIC as usize] = "INVOKESTATIC" ;
|
||||
opcodes[NEW as usize] = "NEW" ;
|
||||
opcodes[ANEWARRAY as usize] = "ANEWARRAY" ;
|
||||
opcodes[_ARRAYLENGTH as usize] = "_ARRAYLENGTH" ;
|
||||
opcodes[_ATHROW as usize] = "_ATHROW" ;
|
||||
opcodes[_CHECKCAST as usize] = "_CHECKCAST" ;
|
||||
opcodes[MONITORENTER as usize] = "MONITORENTER" ;
|
||||
opcodes[IFNULL as usize] = "IFNULL" ;
|
||||
opcodes[IFNONNULL as usize] = "IFNONNULL" ;
|
||||
opcodes
|
||||
});
|
||||
295
src/vm.rs
295
src/vm.rs
|
|
@ -2,17 +2,21 @@ use std::cell::RefCell;
|
|||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use std::io::Write;
|
||||
use anyhow::{anyhow, Error};
|
||||
use log::{info};
|
||||
|
||||
use Value::{*};
|
||||
use Value::*;
|
||||
|
||||
use crate::class::{AttributeType, Class, get_class, Modifier, unsafe_ref, unsafe_val, UnsafeValue, Value};
|
||||
use crate::class::Value::{Null, Void};
|
||||
use crate::class::{
|
||||
get_class, unsafe_ref, unsafe_val, AttributeType, Class, Modifier, UnsafeValue, Value,
|
||||
};
|
||||
use crate::classloader::CpEntry;
|
||||
use crate::heap::{Heap, Object, ObjectRef};
|
||||
use crate::io::*;
|
||||
use crate::native::invoke_native;
|
||||
use crate::opcodes;
|
||||
use crate::opcodes::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -41,12 +45,7 @@ impl StackFrame {
|
|||
fn pop(&mut self) -> Result<UnsafeValue, Error> {
|
||||
Ok(self.data.pop().unwrap())
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct Vm {
|
||||
pub classpath: Vec<String>,
|
||||
|
|
@ -70,6 +69,11 @@ impl Vm {
|
|||
}
|
||||
|
||||
pub fn new(classpath: &'static str) -> Self {
|
||||
env_logger::builder()
|
||||
.format(|buf, record| {
|
||||
writeln!(buf, "{}: {}", record.level(), record.args())
|
||||
})
|
||||
.init();
|
||||
Self {
|
||||
classpath: classpath
|
||||
.split(PATH_SEPARATOR)
|
||||
|
|
@ -80,10 +84,8 @@ impl Vm {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn new_instance(class: Arc<RefCell<Class>>) -> Object {
|
||||
let mut instance = Object::new(class.clone());
|
||||
instance
|
||||
Object::new(class.clone())
|
||||
}
|
||||
|
||||
/// execute the bytecode
|
||||
|
|
@ -109,6 +111,8 @@ impl Vm {
|
|||
println!("execute {}.{}", this_class.borrow().name, method_name);
|
||||
|
||||
let method = this_class.clone().borrow().get_method(method_name)?.clone();
|
||||
//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) {
|
||||
|
|
@ -118,87 +122,68 @@ impl Vm {
|
|||
let stackframe = StackFrame::new(&this_class.borrow().name, &method.name());
|
||||
self.stackframes.push(stackframe);
|
||||
|
||||
let mut pc = &mut 0;
|
||||
let pc = &mut 0;
|
||||
while *pc < code.opcodes.len() {
|
||||
let opcode = read_u8(&code.opcodes, pc);
|
||||
let f = self.current_frame();
|
||||
print!("at {}: stack {}, #{}: opcode {}: ", f.at, f.len(), *pc-1, opcode);
|
||||
info!("\t{} #{} {}", &f.at, &*pc - 1, opcodes::OPCODES[opcode as usize]);
|
||||
match opcode {
|
||||
ACONST_NULL => {
|
||||
println!("ACONST");
|
||||
self.current_frame().push(Value::Null);
|
||||
}
|
||||
ICONST_M1 => {
|
||||
println!("ICONST");
|
||||
self.current_frame().push(I32(-1));
|
||||
}
|
||||
ICONST_0 => {
|
||||
println!("ICONST");
|
||||
self.current_frame().push(I32(0));
|
||||
}
|
||||
ICONST_1 => {
|
||||
println!("ICONST");
|
||||
self.current_frame().push(I32(1));
|
||||
}
|
||||
ICONST_2 => {
|
||||
println!("ICONST");
|
||||
self.current_frame().push(I32(2));
|
||||
}
|
||||
ICONST_3 => {
|
||||
println!("ICONST");
|
||||
self.current_frame().push(I32(3));
|
||||
}
|
||||
ICONST_4 => {
|
||||
println!("ICONST");
|
||||
self.current_frame().push(I32(4));
|
||||
}
|
||||
ICONST_5 => {
|
||||
println!("ICONST");
|
||||
self.current_frame().push(I32(5));
|
||||
}
|
||||
LCONST_0 => {
|
||||
println!("LCONST");
|
||||
self.current_frame().push(Value::I64(0));
|
||||
}
|
||||
LCONST_1 => {
|
||||
println!("LCONST");
|
||||
self.current_frame().push(Value::I64(1));
|
||||
}
|
||||
FCONST_0 => {
|
||||
println!("FCONST");
|
||||
self.current_frame().push(Value::F32(0.0));
|
||||
}
|
||||
FCONST_1 => {
|
||||
println!("FCONST");
|
||||
self.current_frame().push(Value::F32(1.0));
|
||||
}
|
||||
FCONST_2 => {
|
||||
println!("FCONST");
|
||||
self.current_frame().push(Value::F32(2.0));
|
||||
}
|
||||
DCONST_0 => {
|
||||
println!("DCONST");
|
||||
self.current_frame().push(Value::F64(0.0));
|
||||
}
|
||||
DCONST_1 => {
|
||||
println!("DCONST");
|
||||
self.current_frame().push(Value::F64(1.0));
|
||||
}
|
||||
SIPUSH => {
|
||||
println!("SIPUSH");
|
||||
let s = read_u16(&code.opcodes, pc) as i32;
|
||||
self.current_frame().push(I32(s));
|
||||
}
|
||||
BIPUSH => {
|
||||
println!("BIPUSH");
|
||||
let c = read_u8(&code.opcodes, pc) as i32;
|
||||
self.current_frame().push(I32(c));
|
||||
}
|
||||
LDC => {
|
||||
println!("LDC");
|
||||
let cp_index = read_u8(&code.opcodes, pc) as u16;
|
||||
let c = method.constant_pool.get(&cp_index).unwrap();
|
||||
println!("{:?}", c);
|
||||
match c {
|
||||
CpEntry::Integer(i) => {
|
||||
self.current_frame().push(I32(*i));
|
||||
|
|
@ -211,25 +196,47 @@ impl Vm {
|
|||
}
|
||||
CpEntry::StringRef(utf8) => {
|
||||
//TODO
|
||||
let stringclass = get_class(self, Some(&this_class.borrow().name), "java/lang/String").unwrap();
|
||||
let stringinstance = unsafe_val(
|
||||
Value::Ref(unsafe_ref(ObjectRef::Object(Box::new(
|
||||
Vm::new_instance(stringclass.clone()))))));
|
||||
let string: Vec<u8> = this_class.borrow().cp_utf8(utf8).unwrap().to_owned().as_bytes().into();
|
||||
let stringclass = get_class(
|
||||
self,
|
||||
Some(&this_class.borrow().name),
|
||||
"java/lang/String",
|
||||
)
|
||||
.unwrap();
|
||||
let stringinstance =
|
||||
unsafe_val(Value::Ref(unsafe_ref(ObjectRef::Object(
|
||||
Box::new(Vm::new_instance(stringclass.clone())),
|
||||
))));
|
||||
let string: Vec<u8> = this_class
|
||||
.borrow()
|
||||
.cp_utf8(utf8)
|
||||
.unwrap()
|
||||
.to_owned()
|
||||
.as_bytes()
|
||||
.into();
|
||||
|
||||
self.execute_class(stringclass, "<init>([B)V",
|
||||
vec![stringinstance.clone(),
|
||||
unsafe_val(Value::Ref(ObjectRef::new_byte_array(string)))])?;
|
||||
self.execute_class(
|
||||
stringclass,
|
||||
"<init>([B)V",
|
||||
vec![
|
||||
stringinstance.clone(),
|
||||
unsafe_val(Value::Ref(ObjectRef::new_byte_array(string))),
|
||||
],
|
||||
)?;
|
||||
self.current_frame().push_ref(stringinstance);
|
||||
}
|
||||
CpEntry::Long(l) => {
|
||||
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));
|
||||
}
|
||||
_ => {
|
||||
panic!("add variant {:?}", c)
|
||||
}
|
||||
}
|
||||
}
|
||||
LDC_W => {
|
||||
println!("LDC_W");
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
match method.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Integer(i) => {
|
||||
|
|
@ -244,7 +251,6 @@ impl Vm {
|
|||
}
|
||||
}
|
||||
LDC2_W => {
|
||||
println!("LDC2_W");
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
match method.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Double(d) => {
|
||||
|
|
@ -259,158 +265,152 @@ impl Vm {
|
|||
}
|
||||
}
|
||||
ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => {
|
||||
println!("LOAD");
|
||||
// omitting the type checks so far
|
||||
let n = read_u8(&code.opcodes, pc) as usize;
|
||||
self.current_frame()
|
||||
.push_ref(local_params[n].as_ref().unwrap().clone());
|
||||
}
|
||||
ILOAD_0 | LLOAD_0 | FLOAD_0 | DLOAD_0 | ALOAD_0 => {
|
||||
println!("LOAD_0");
|
||||
self.current_frame()
|
||||
.push_ref(local_params[0].as_ref().unwrap().clone());
|
||||
}
|
||||
ILOAD_1 | LLOAD_1 | FLOAD_1 | DLOAD_1 | ALOAD_1 => {
|
||||
println!("LOAD_1");
|
||||
self.current_frame()
|
||||
.push_ref(local_params[1].as_ref().unwrap().clone());
|
||||
}
|
||||
ILOAD_2 | LLOAD_2 | FLOAD_2 | DLOAD_2 | ALOAD_2 => {
|
||||
println!("LOAD_2");
|
||||
self.current_frame()
|
||||
.push_ref(local_params[2].as_ref().unwrap().clone());
|
||||
}
|
||||
ILOAD_3 | LLOAD_3 | FLOAD_3 | DLOAD_3 | ALOAD_3 => {
|
||||
println!("LOAD_3");
|
||||
self.current_frame()
|
||||
.push_ref(local_params[3].as_ref().unwrap().clone());
|
||||
}
|
||||
IALOAD | LALOAD | FALOAD | DALOAD | AALOAD | BALOAD | CALOAD | SALOAD => unsafe {
|
||||
println!("ALOAD");
|
||||
self.array_load()?;
|
||||
},
|
||||
ISTORE | LSTORE | FSTORE | DSTORE | ASTORE => {
|
||||
println!("STORE");
|
||||
let index = read_u8(&code.opcodes, pc) as usize;
|
||||
self.store(&mut local_params, index)?;
|
||||
}
|
||||
ISTORE_0 | LSTORE_0 | DSTORE_0 | ASTORE_0 | FSTORE_0 => {
|
||||
println!("STORE_0");
|
||||
self.store(&mut local_params, 0)?;
|
||||
}
|
||||
ISTORE_1 | LSTORE_1 | DSTORE_1 | ASTORE_1 | FSTORE_1 => {
|
||||
println!("STORE_1");
|
||||
self.store(&mut local_params, 1)?;
|
||||
}
|
||||
ISTORE_2 | LSTORE_2 | DSTORE_2 | ASTORE_2 | FSTORE_2 => {
|
||||
println!("STORE_2");
|
||||
self.store(&mut local_params, 2)?;
|
||||
}
|
||||
ISTORE_3 | LSTORE_3 | DSTORE_3 | ASTORE_3 | FSTORE_3 => {
|
||||
println!("STORE_3");
|
||||
self.store(&mut local_params, 3)?;
|
||||
}
|
||||
BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE | AASTORE => unsafe {
|
||||
println!("ASTORE");
|
||||
BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE
|
||||
| AASTORE => unsafe {
|
||||
self.array_store()?
|
||||
},
|
||||
POP => {
|
||||
println!("POP");
|
||||
self.current_frame().pop()?;
|
||||
}
|
||||
DUP => {
|
||||
println!("DUP");
|
||||
let value = self.current_frame().pop()?;
|
||||
self.current_frame().push_ref(value.clone());
|
||||
self.current_frame().push_ref(value);
|
||||
}
|
||||
IF_ICMPEQ | IF_ICMPNE | IF_ICMPGT | IF_ICMPGE | IF_ICMPLT | IF_ICMPLE => {
|
||||
IFEQ | IFNE | IFLT | IFGE | IFGT | IFLE => {
|
||||
let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode
|
||||
let value = self.current_frame().pop()?;
|
||||
unsafe {
|
||||
Self::if_cmp(pc, opcode, jmp_to, &*value.get(), &I32(0));
|
||||
}
|
||||
}
|
||||
|
||||
let jmp_to = read_u16(&code.opcodes, pc);
|
||||
IF_ICMPEQ | IF_ICMPNE | IF_ICMPGT | IF_ICMPGE | IF_ICMPLT | IF_ICMPLE => {
|
||||
let jmp_to = read_u16(&code.opcodes, pc) - 3; // -3 so that offset = location of Cmp opcode
|
||||
let value1 = self.current_frame().pop()?;
|
||||
let value2 = self.current_frame().pop()?;
|
||||
unsafe {
|
||||
if let I32(value1) = *value1.get() {
|
||||
if let I32(value2) = *value2.get() {
|
||||
let jump = match opcode {
|
||||
IF_ICMPEQ => { value1 == value2 }
|
||||
IF_ICMPNE => { value1 != value2 }
|
||||
IF_ICMPGT => { value1 > value2 }
|
||||
IF_ICMPGE => { value1 >= value2 }
|
||||
IF_ICMPLT => { value1 < value2 }
|
||||
IF_ICMPLE => { value1 <= value2 }
|
||||
_ => { false }
|
||||
};
|
||||
if jump {
|
||||
println!("JMP {}", jmp_to);
|
||||
*pc = jmp_to as usize;
|
||||
} else {
|
||||
println!("NO JMP {}", jmp_to);
|
||||
}
|
||||
}
|
||||
}
|
||||
Self::if_cmp(pc, opcode, jmp_to, &*value1.get(), &*value2.get());
|
||||
}
|
||||
}
|
||||
GOTO => {
|
||||
let jmp_to = read_u16(&code.opcodes, pc);
|
||||
println!("GOTO {}", jmp_to);
|
||||
*pc = jmp_to as usize;
|
||||
let jmp_to = read_u16(&code.opcodes, pc) - 3;
|
||||
*pc += jmp_to as usize;
|
||||
}
|
||||
IRETURN | FRETURN | DRETURN => {
|
||||
println!("RETURN");
|
||||
IRETURN | FRETURN | DRETURN | ARETURN => {
|
||||
let result = self.current_frame().pop();
|
||||
self.stackframes.pop();
|
||||
return result;
|
||||
}
|
||||
RETURN_VOID => {
|
||||
println!("RETURN void");
|
||||
self.stackframes.pop();
|
||||
return Ok(Value::void());
|
||||
}
|
||||
GETSTATIC => {
|
||||
println!("GETSTATIC");
|
||||
let borrow = this_class.borrow();
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
let (class_index, field_name_and_type_index) =
|
||||
borrow.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid
|
||||
let (name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap();
|
||||
let (name) = borrow.cp_utf8(name_index).unwrap();
|
||||
let (name_index, _) =
|
||||
borrow.cp_name_and_type(field_name_and_type_index).unwrap();
|
||||
let name = borrow.cp_utf8(name_index).unwrap();
|
||||
|
||||
let that_class_name_index = borrow.cp_class_ref(class_index).unwrap();
|
||||
let that_class_name = borrow.cp_utf8(that_class_name_index).unwrap();
|
||||
let that = get_class(self, Some(&borrow.name), that_class_name.as_str())?;
|
||||
let that_borrow = that.borrow();
|
||||
let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
|
||||
println!("get static field {}", name);
|
||||
self.current_frame().push_ref(that_borrow.static_data.get(*val_index).unwrap().as_ref().unwrap().clone());
|
||||
let (_, val_index) = that_borrow
|
||||
.static_field_mapping
|
||||
.get(that_class_name)
|
||||
.unwrap()
|
||||
.get(name)
|
||||
.unwrap();
|
||||
self.current_frame().push_ref(
|
||||
that_borrow
|
||||
.static_data
|
||||
.get(*val_index)
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.clone(),
|
||||
);
|
||||
}
|
||||
PUTSTATIC => {
|
||||
println!("PUTSTATIC");
|
||||
let mut borrow = this_class.borrow_mut();
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
let (class_index, field_name_and_type_index) =
|
||||
borrow.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid
|
||||
let (name_index, _) = borrow.cp_name_and_type(field_name_and_type_index).unwrap();
|
||||
let (name) = borrow.cp_utf8(name_index).unwrap();
|
||||
let (name_index, _) =
|
||||
borrow.cp_name_and_type(field_name_and_type_index).unwrap();
|
||||
let name = borrow.cp_utf8(name_index).unwrap();
|
||||
let class_name_index = borrow.cp_class_ref(class_index).unwrap();
|
||||
println!("field {}", name);
|
||||
let that_class_name = borrow.cp_utf8(class_name_index).unwrap();
|
||||
|
||||
if &borrow.name == that_class_name {// may have to apply this in GETSTATIC too
|
||||
let (_, val_index) = borrow.static_field_mapping.get(that_class_name).unwrap().get(name).as_ref().unwrap();
|
||||
let val_index = *val_index;
|
||||
let val_index = if &borrow.name == that_class_name {
|
||||
// may have to apply this in GETSTATIC too
|
||||
borrow
|
||||
.static_field_mapping
|
||||
.get(that_class_name)
|
||||
.unwrap()
|
||||
.get(name)
|
||||
.unwrap()
|
||||
.1
|
||||
} else {
|
||||
let that =
|
||||
get_class(self, Some(&borrow.name), that_class_name.as_str())?;
|
||||
let that_borrow = that.borrow();
|
||||
that_borrow
|
||||
.static_field_mapping
|
||||
.get(that_class_name)
|
||||
.unwrap()
|
||||
.get(name)
|
||||
.unwrap()
|
||||
.1
|
||||
};
|
||||
let value = self.current_frame().pop()?;
|
||||
borrow.static_data[val_index] = Some(value);
|
||||
} else {
|
||||
let that = get_class(self, Some(&borrow.name), that_class_name.as_str())?;
|
||||
let that_borrow = that.borrow(); // if already borrowed, then that_class == this_class
|
||||
let (_, val_index) = that_borrow.static_field_mapping.get(that_class_name).unwrap().get(name).unwrap();
|
||||
let value = self.current_frame().pop()?;
|
||||
borrow.static_data[*val_index] = Some(value);
|
||||
}
|
||||
}
|
||||
GETFIELD => unsafe {
|
||||
println!("PUTFIELD");
|
||||
let borrow = this_class.borrow();
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
let (class_index, field_name_and_type_index) =
|
||||
|
|
@ -421,7 +421,7 @@ impl Vm {
|
|||
let class_name = borrow.cp_utf8(class_name_index).unwrap();
|
||||
let field_name = borrow.cp_utf8(field_name_index).unwrap();
|
||||
|
||||
let mut objectref = self.current_frame().pop()?;
|
||||
let objectref = self.current_frame().pop()?;
|
||||
if let Value::Ref(instance) = &mut *objectref.get() {
|
||||
if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
|
||||
let value = object.get(class_name, field_name);
|
||||
|
|
@ -434,7 +434,6 @@ impl Vm {
|
|||
}
|
||||
},
|
||||
PUTFIELD => unsafe {
|
||||
println!("PUTFIELD");
|
||||
let borrow = this_class.borrow();
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
let (class_index, field_name_and_type_index) =
|
||||
|
|
@ -446,7 +445,7 @@ impl Vm {
|
|||
let field_name = borrow.cp_utf8(field_name_index).unwrap();
|
||||
|
||||
let value = self.current_frame().pop()?;
|
||||
let mut objectref = self.current_frame().pop()?;
|
||||
let objectref = self.current_frame().pop()?;
|
||||
if let Value::Ref(instance) = &mut *objectref.get() {
|
||||
if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
|
||||
object.set(class_name, field_name, value);
|
||||
|
|
@ -456,7 +455,6 @@ impl Vm {
|
|||
}
|
||||
},
|
||||
INVOKEVIRTUAL | INVOKESPECIAL => unsafe {
|
||||
println!("INVOKE");
|
||||
// TODO differentiate these opcodes
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
if let Some(invocation) =
|
||||
|
|
@ -479,13 +477,12 @@ impl Vm {
|
|||
self.current_frame().push_ref(return_value.clone());
|
||||
}
|
||||
}
|
||||
println!("stack {} at {}", self.current_frame().len(), self.current_frame().at)
|
||||
// println!("stack {} at {}", self.current_frame().len(), self.current_frame().at)
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
INVOKESTATIC => unsafe {
|
||||
println!("INVOKESTATIC");
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
if let Some(invocation) =
|
||||
get_signature_for_invoke(&method.constant_pool, cp_index)
|
||||
|
|
@ -511,39 +508,60 @@ impl Vm {
|
|||
}
|
||||
},
|
||||
NEW => {
|
||||
println!("NEW");
|
||||
let class_index = &read_u16(&code.opcodes, pc);
|
||||
let borrow = this_class.borrow();
|
||||
let class_name_index = borrow.cp_class_ref(class_index).unwrap();
|
||||
let class_name = borrow.cp_utf8(class_name_index).unwrap();
|
||||
let class_to_instantiate = get_class(self, Some(&borrow.name), class_name)?;
|
||||
|
||||
let object = unsafe_ref(ObjectRef::Object(Box::new(
|
||||
Vm::new_instance(class_to_instantiate),
|
||||
)));
|
||||
let object = unsafe_ref(ObjectRef::Object(Box::new(Vm::new_instance(
|
||||
class_to_instantiate,
|
||||
))));
|
||||
self.current_frame().push(Value::Ref(Arc::clone(&object)));
|
||||
self.heap.new_object(object);
|
||||
}
|
||||
ANEWARRAY => unsafe {
|
||||
println!("ANEWARRAY");
|
||||
let class_index = &read_u16(&code.opcodes, pc);
|
||||
let borrow = this_class.borrow();
|
||||
let class_name_index = borrow.cp_class_ref(class_index).unwrap();
|
||||
let class_name = borrow.cp_utf8(class_name_index).unwrap();
|
||||
let arraytype = get_class(self, Some(&borrow.name), class_name)?;
|
||||
let count = self.current_frame().pop()?;
|
||||
if let I32(count) = *count.get() { // why does pop()?.get() give weird results?
|
||||
if let I32(count) = *count.get() {
|
||||
// why does pop()?.get() give weird results?
|
||||
let array = ObjectRef::new_object_array(arraytype, count as usize);
|
||||
let array = unsafe_ref(array);
|
||||
|
||||
self.current_frame().push(Value::Ref(Arc::clone(&array)));
|
||||
println!("{}", self.current_frame().len());
|
||||
self.heap.new_object(array);
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
},
|
||||
MONITORENTER => {
|
||||
self.current_frame().pop()?;
|
||||
} //TODO implement
|
||||
IFNULL | IFNONNULL => unsafe {
|
||||
let jmp_to = read_u16(&code.opcodes, pc) - 3;
|
||||
let value = self.current_frame().pop()?;
|
||||
let its_null = if let Null = *value.get() { true } else { false };
|
||||
|
||||
if its_null && opcode == IFNULL {
|
||||
info!("\t\tIF NULL =>{}: JMP {}", its_null, *pc + jmp_to as usize);
|
||||
*pc += jmp_to as usize;
|
||||
}
|
||||
if !its_null && opcode == IFNONNULL {
|
||||
info!("\t\tIF NOT NULL =>{}: JMP {}", its_null, *pc + jmp_to as usize);
|
||||
*pc += jmp_to as usize;
|
||||
}
|
||||
//debug info
|
||||
if !its_null && opcode == IFNULL {
|
||||
info!("\t\tIF NULL =>false: NO JMP");
|
||||
}
|
||||
if its_null && opcode == IFNONNULL {
|
||||
info!("\t\tIF NONNULL =>false: NO JMP");
|
||||
}
|
||||
},
|
||||
//TODO implement all opcodes
|
||||
_ => {
|
||||
panic!("opcode {} not implemented {:?}", opcode, self.stackframes)
|
||||
|
|
@ -555,6 +573,28 @@ impl Vm {
|
|||
panic!("should not happen")
|
||||
}
|
||||
|
||||
fn if_cmp(pc: &mut usize, opcode: u8, jmp_to: u16, value1: &Value, value2: &Value) {
|
||||
if let I32(value1) = value1 {
|
||||
if let I32(value2) = value2 {
|
||||
let jump = match opcode {
|
||||
IF_ICMPEQ => value1 == value2,
|
||||
IF_ICMPNE => value1 != value2,
|
||||
IF_ICMPGT => value1 > value2,
|
||||
IF_ICMPGE => value1 >= value2,
|
||||
IF_ICMPLT => value1 < value2,
|
||||
IF_ICMPLE => value1 <= value2,
|
||||
_ => false,
|
||||
};
|
||||
if jump {
|
||||
info!("\t\tIF({}) JMP {}", jump, *pc + jmp_to as usize);
|
||||
*pc += jmp_to as usize;
|
||||
} else {
|
||||
info!("\t\tIF({}) NO JMP", jump);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn array_load(&mut self) -> Result<(), Error> {
|
||||
let value = self.current_frame().pop()?;
|
||||
|
||||
|
|
@ -591,10 +631,11 @@ impl Vm {
|
|||
self.current_frame().push(Value::F64(array[index]));
|
||||
}
|
||||
ObjectRef::ObjectArray(_arraytype, data) => {
|
||||
self.current_frame()
|
||||
.push(Value::Ref(data[index].clone()));
|
||||
self.current_frame().push(Value::Ref(data[index].clone()));
|
||||
}
|
||||
ObjectRef::Object(_) => { panic!("should be array") } //throw error?
|
||||
ObjectRef::Object(_) => {
|
||||
panic!("should be array")
|
||||
} //throw error?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -604,7 +645,7 @@ impl Vm {
|
|||
unsafe fn array_store(&mut self) -> Result<(), Error> {
|
||||
let value = self.current_frame().pop()?;
|
||||
let index = &*self.current_frame().pop()?;
|
||||
let mut arrayref = &mut self.current_frame().pop()?;
|
||||
let arrayref = &mut self.current_frame().pop()?;
|
||||
|
||||
if let Value::Null = &*arrayref.get() {
|
||||
return Err(anyhow!("NullpointerException"));
|
||||
|
|
@ -671,8 +712,8 @@ impl Vm {
|
|||
unreachable!()
|
||||
}
|
||||
}
|
||||
ObjectRef::ObjectArray(arraytype, ref mut array) => {
|
||||
if let Value::Ref(ref value) = *value.get() {
|
||||
ObjectRef::ObjectArray(_arraytype, ref mut array) => {
|
||||
if let Ref(ref value) = *value.get() {
|
||||
array[*index as usize] = value.clone();
|
||||
} else {
|
||||
unreachable!()
|
||||
|
|
@ -731,7 +772,7 @@ fn get_signature_for_invoke(cp: &Rc<HashMap<u16, CpEntry>>, index: u16) -> Optio
|
|||
}
|
||||
|
||||
unsafe fn copy(value: UnsafeValue) -> UnsafeValue {
|
||||
unsafe_val(match (&*value.get()) {
|
||||
unsafe_val(match &*value.get() {
|
||||
Void => Void,
|
||||
Null => Null,
|
||||
BOOL(b) => BOOL(*b),
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
tests/Int.class
BIN
tests/Int.class
Binary file not shown.
BIN
tests/Main.class
BIN
tests/Main.class
Binary file not shown.
BIN
tests/Son.class
BIN
tests/Son.class
Binary file not shown.
|
|
@ -1,61 +1,40 @@
|
|||
mod test {
|
||||
use java_rs::class::Value;
|
||||
use java_rs::class::{get_class, Value};
|
||||
use java_rs::heap::ObjectRef;
|
||||
use java_rs::vm::Vm;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
fn get_constant_int() {
|
||||
// let mut vm = Vm::new(".");
|
||||
// let class = vm.get_class("Float").expect("ClassNotFound");
|
||||
// assert_eq!((55, 0), class.get_version());
|
||||
//
|
||||
//
|
||||
// if let Value::I32(v) = Vm::new("").execute("Float", "public static get()I", None).unwrap() {
|
||||
// assert_eq!(v, 42);
|
||||
// } else {
|
||||
// panic!("fail");
|
||||
// }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_constant_double() {
|
||||
// let mut vm = Vm::new(".");
|
||||
// let class = vm.get_class("Double").expect("ClassNotFound");
|
||||
// assert_eq!((55, 0), class.get_version());
|
||||
// if let Value::F64(v) = Vm::new("").execute("Double", "public static get()D", None).unwrap() {
|
||||
// assert_eq!(v, 42.0);
|
||||
// } else {
|
||||
// panic!("fail");
|
||||
// }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_constant_foat() {
|
||||
let mut vm = Vm::new(".");
|
||||
// vm.load_class("Float").expect("ClassNotFound");
|
||||
// assert_eq!((55, 0), class.get_version());
|
||||
// if let Value::F32(v) = Vm::new().execute(class.methods.get("public static getF()F").unwrap()).unwrap() {
|
||||
// assert_eq!(v, 42.0);
|
||||
// } else {
|
||||
// panic!("fail");
|
||||
// }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_float() {
|
||||
// assert_eq!((55, 0), class.get_version());
|
||||
|
||||
let mut vm = Vm::new("/Users/FJ19WK/RustroverProjects/java_rs/tests");
|
||||
|
||||
let c = vm.get_class("Float").unwrap();
|
||||
let object = Arc::new(vm.new_instance(c));
|
||||
if let Value::F32(v) = *vm
|
||||
.execute("Float", "public getF2()F", Some(object))
|
||||
.unwrap()
|
||||
{
|
||||
assert_eq!(v, 0.0);
|
||||
fn if_cmp() {
|
||||
let mut vm = Vm::new("tests");
|
||||
let c = get_class(&mut vm, None, "testclasses.IfCmp").unwrap();
|
||||
let ret = vm.execute_class(c, "i_is_1()Z", vec![]).unwrap();
|
||||
unsafe {
|
||||
if let Value::I32(b) = *ret.get() {
|
||||
// internally a boolean is an int
|
||||
assert_eq!(0, b);
|
||||
} else {
|
||||
panic!("fail");
|
||||
println!("{:?}", *ret.get());
|
||||
assert!(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn consts() {
|
||||
let mut vm = Vm::new("tests");
|
||||
let c = get_class(&mut vm, None, "testclasses.Const").unwrap();
|
||||
let ret = vm
|
||||
.execute_class(c, "hello()Ljava/lang/String;", vec![])
|
||||
.unwrap();
|
||||
unsafe {
|
||||
if let Value::Ref(s) = &*ret.get() {
|
||||
// internally a boolean is an int
|
||||
if let ObjectRef::Object(a) = &*s.get() {
|
||||
println!("{:?}", a);
|
||||
}
|
||||
} else {
|
||||
println!("{:?}", *ret.get());
|
||||
assert!(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
10
tests/testclasses/Const.java
Normal file
10
tests/testclasses/Const.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package testclasses;
|
||||
|
||||
public class Const {
|
||||
|
||||
private static final String s = "hello world";
|
||||
|
||||
public static String hello(){
|
||||
return s;
|
||||
}
|
||||
}
|
||||
BIN
tests/testclasses/Double.class
Normal file
BIN
tests/testclasses/Double.class
Normal file
Binary file not shown.
|
|
@ -1,3 +1,5 @@
|
|||
package testclasses;
|
||||
|
||||
public class Double {
|
||||
|
||||
private final static double d =42.0D;
|
||||
BIN
tests/testclasses/Father.class
Normal file
BIN
tests/testclasses/Father.class
Normal file
Binary file not shown.
BIN
tests/testclasses/FloatBean.class
Normal file
BIN
tests/testclasses/FloatBean.class
Normal file
Binary file not shown.
|
|
@ -1,3 +1,5 @@
|
|||
package testclasses;
|
||||
|
||||
public class FloatBean {
|
||||
|
||||
private float value;
|
||||
10
tests/testclasses/IfCmp.java
Normal file
10
tests/testclasses/IfCmp.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package testclasses;
|
||||
|
||||
public class IfCmp {
|
||||
|
||||
private static int i;
|
||||
|
||||
public static boolean i_is_1(){
|
||||
return i==1;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
|
@ -1,3 +1,5 @@
|
|||
package testclasses;
|
||||
|
||||
public class Inheritance {
|
||||
|
||||
public static void main(String[] args) {
|
||||
BIN
tests/testclasses/Int.class
Normal file
BIN
tests/testclasses/Int.class
Normal file
Binary file not shown.
|
|
@ -1,3 +1,5 @@
|
|||
package testclasses;
|
||||
|
||||
public class Int {
|
||||
|
||||
public static int get() {
|
||||
BIN
tests/testclasses/Main.class
Normal file
BIN
tests/testclasses/Main.class
Normal file
Binary file not shown.
|
|
@ -1,3 +1,5 @@
|
|||
package testclasses ;
|
||||
|
||||
public class Main {
|
||||
|
||||
final static String a;
|
||||
BIN
tests/testclasses/Son.class
Normal file
BIN
tests/testclasses/Son.class
Normal file
Binary file not shown.
Loading…
Add table
Reference in a new issue