sanitized logging, more opcodes, bugfixing

This commit is contained in:
Shautvast 2023-10-21 10:18:14 +02:00
parent 736a13a2d0
commit ae143cd50d
33 changed files with 989 additions and 369 deletions

229
Cargo.lock generated
View file

@ -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"

View file

@ -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"

View file

@ -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 "),

View file

@ -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");

View file

@ -1,6 +1,6 @@
pub mod class;
pub mod classloader;
mod heap;
pub mod heap;
pub mod io;
pub mod opcodes;
pub mod vm;

View file

@ -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();

View file

@ -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()
}

View file

@ -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
View file

@ -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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -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)
}
}
}
}

View file

@ -0,0 +1,10 @@
package testclasses;
public class Const {
private static final String s = "hello world";
public static String hello(){
return s;
}
}

Binary file not shown.

View file

@ -1,3 +1,5 @@
package testclasses;
public class Double {
private final static double d =42.0D;

Binary file not shown.

Binary file not shown.

View file

@ -1,3 +1,5 @@
package testclasses;
public class FloatBean {
private float value;

View file

@ -0,0 +1,10 @@
package testclasses;
public class IfCmp {
private static int i;
public static boolean i_is_1(){
return i==1;
}
}

View file

@ -1,3 +1,5 @@
package testclasses;
public class Inheritance {
public static void main(String[] args) {

BIN
tests/testclasses/Int.class Normal file

Binary file not shown.

View file

@ -1,3 +1,5 @@
package testclasses;
public class Int {
public static int get() {

Binary file not shown.

View file

@ -1,3 +1,5 @@
package testclasses ;
public class Main {
final static String a;

BIN
tests/testclasses/Son.class Normal file

Binary file not shown.