diff --git a/Cargo.lock b/Cargo.lock index 04166b4..4835131 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index a361b28..0645efe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,6 @@ edition = "2021" [dependencies] anyhow = { version = "1.0", features = ["default"] } once_cell = { version = "1.18.0", features = [] } -zip = { version = "0.6", features = ["zstd"] } \ No newline at end of file +zip = { version = "0.6", features = ["zstd"] } +log = "0.4" +env_logger = "0.10" \ No newline at end of file diff --git a/src/class.rs b/src/class.rs index f7db82a..cd855a7 100644 --- a/src/class.rs +++ b/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>>> = 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>, Error> { - println!("get_class {}", class_name); +pub fn get_class( + vm: &mut Vm, + _calling_class_name: Option<&str>, + class_name: &str, +) -> Result>, 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)) }); - // not sure why I have to create the clones first - let clone1 = class.clone(); - let clone2 = class.clone(); - let clone3 = class.clone(); - + let clone = class.clone(); let inited = class.borrow().inited; if !inited { - // must not enter here twice! - clone1.borrow_mut().inited = true; + // not sure why I have to create the clones first + let clone2 = class.clone(); + let clone3 = class.clone(); - let super_class_name = class.clone().borrow().super_class_name.as_ref().map(|n| n.to_owned()); + // must not enter here twice! + clone2.borrow_mut().inited = true; + + 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,18 +61,15 @@ 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("()V"); - if clinit{ - vm.execute_class(clone1, "()V", vec![]).unwrap(); + let clinit = clone2.borrow().methods.contains_key("()V"); + if clinit { + vm.execute_class(clone2, "()V", vec![]).unwrap(); } - println!("end clinit"); - } - Ok(clone2) + Ok(clone) } } - /// the class definition as read from the class file + derived values // TODO implement call to static initializers #[derive(Debug)] @@ -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>, - static_field_mapping: &mut HashMap>, - class: Arc>, - 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); + fn add_field_mappings( + this_field_mapping: &mut HashMap>, + static_field_mapping: &mut HashMap>, + class: Arc>, + 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, + ); 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>, object_field_map_index: &mut usize, static_field_map_index: &mut usize, - ) -> (HashMap, HashMap) { + ) -> ( + HashMap, + HashMap, + ) { 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, - 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 "), diff --git a/src/classloader.rs b/src/classloader.rs index 4becf48..6c46ef4 100644 --- a/src/classloader.rs +++ b/src/classloader.rs @@ -273,8 +273,8 @@ fn read_attribute( "NestMembers" => Some(("".into(), AttributeType::NestMembers)), //stub "BootstrapMethods" => Some(("".into(), AttributeType::BootstrapMethods)), //stub "InnerClasses" => Some(("".into(), AttributeType::InnerClasses)), //stub - "Signature" => Some(("".into(), AttributeType::Signature)), //stub - "NestHost" => Some(("".into(), AttributeType::NestHost)), //stub + "Signature" => Some(("".into(), AttributeType::Signature)), //stub + "NestHost" => Some(("".into(), AttributeType::NestHost)), //stub //TODO more actual attribute implementations _ => None, }; diff --git a/src/heap.rs b/src/heap.rs index b0ce044..f390134 100644 --- a/src/heap.rs +++ b/src/heap.rs @@ -51,7 +51,7 @@ impl ObjectRef { } } -impl Debug for ObjectRef{ +impl Debug for ObjectRef { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { ObjectRef::BooleanArray(d) => write!(f, "[Z;{}]", d.len()), @@ -61,9 +61,9 @@ impl Debug for ObjectRef{ ObjectRef::FloatArray(d) => write!(f, "[F;{}]", d.len()), ObjectRef::IntArray(d) => write!(f, "[I;{}]", d.len()), ObjectRef::LongArray(d) => write!(f, "[J;{}]", d.len()), - ObjectRef::ObjectArray(t, d) => write!(f,"[L{};{}]", t.borrow().name,d.len()), - ObjectRef::ShortArray( d) => write!(f, "[S;{}]", d.len()), - ObjectRef::Object( r) => write!(f,"{}{{ {:?} }}", r.class.borrow().name, r.data), + ObjectRef::ObjectArray(t, d) => write!(f, "[L{};{}]", t.borrow().name, d.len()), + ObjectRef::ShortArray(d) => write!(f, "[S;{}]", d.len()), + ObjectRef::Object(r) => write!(f, "{}{{ {:?} }}", r.class.borrow().name, r.data), } } } diff --git a/src/io.rs b/src/io.rs index 073e662..0208b6c 100644 --- a/src/io.rs +++ b/src/io.rs @@ -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, class_name: &str) -> Result { + 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"); diff --git a/src/lib.rs b/src/lib.rs index afd036b..56b7999 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ pub mod class; pub mod classloader; -mod heap; +pub mod heap; pub mod io; pub mod opcodes; pub mod vm; diff --git a/src/main.rs b/src/main.rs index 94df0b8..85e6db3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,9 +7,9 @@ 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![]) + vm.execute(None, main_class, "main([Ljava/lang/String;)V", vec![]) .unwrap(); Ok(()) } diff --git a/src/native.rs b/src/native.rs index 09c6e65..8223cb0 100644 --- a/src/native.rs +++ b/src/native.rs @@ -1,9 +1,7 @@ -use std::rc::Rc; use crate::class::{Method, UnsafeValue, Value}; +use std::rc::Rc; -pub fn invoke_native(method: Rc, args: Vec) -> UnsafeValue { +pub fn invoke_native(method: Rc, _args: Vec) -> UnsafeValue { println!("native {}", method.name()); Value::void() } - - diff --git a/src/opcodes.rs b/src/opcodes.rs index 030bcb9..99b29c5 100644 --- a/src/opcodes.rs +++ b/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> = 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 +}); \ No newline at end of file diff --git a/src/vm.rs b/src/vm.rs index 7da9156..a32b5da 100644 --- a/src/vm.rs +++ b/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,13 +45,8 @@ impl StackFrame { fn pop(&mut self) -> Result { Ok(self.data.pop().unwrap()) } - - fn len(&self) -> usize { - self.data.len() - } } - pub struct Vm { pub classpath: Vec, heap: Heap, @@ -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>) -> 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> = 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 = 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 = this_class + .borrow() + .cp_utf8(utf8) + .unwrap() + .to_owned() + .as_bytes() + .into(); - self.execute_class(stringclass, "([B)V", - vec![stringinstance.clone(), - unsafe_val(Value::Ref(ObjectRef::new_byte_array(string)))])?; + self.execute_class( + stringclass, + "([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 value = self.current_frame().pop()?; - borrow.static_data[val_index] = Some(value); + 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(); // 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); - } + 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); } 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>, 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), diff --git a/tests/Double.class b/tests/Double.class deleted file mode 100644 index 3ec3dce..0000000 Binary files a/tests/Double.class and /dev/null differ diff --git a/tests/Father.class b/tests/Father.class deleted file mode 100644 index 46ad955..0000000 Binary files a/tests/Father.class and /dev/null differ diff --git a/tests/FloatBean.class b/tests/FloatBean.class deleted file mode 100644 index 85d4711..0000000 Binary files a/tests/FloatBean.class and /dev/null differ diff --git a/tests/Int.class b/tests/Int.class deleted file mode 100644 index d876839..0000000 Binary files a/tests/Int.class and /dev/null differ diff --git a/tests/Main.class b/tests/Main.class deleted file mode 100644 index b03b41f..0000000 Binary files a/tests/Main.class and /dev/null differ diff --git a/tests/Son.class b/tests/Son.class deleted file mode 100644 index ab15140..0000000 Binary files a/tests/Son.class and /dev/null differ diff --git a/tests/class_tests.rs b/tests/class_tests.rs index cf01887..508e24c 100644 --- a/tests/class_tests.rs +++ b/tests/class_tests.rs @@ -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"); - // } + 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 { + println!("{:?}", *ret.get()); + assert!(false) + } + } } #[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); - } else { - panic!("fail"); + 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) + } } } } diff --git a/tests/testclasses/Const.java b/tests/testclasses/Const.java new file mode 100644 index 0000000..0f32e10 --- /dev/null +++ b/tests/testclasses/Const.java @@ -0,0 +1,10 @@ +package testclasses; + +public class Const { + + private static final String s = "hello world"; + + public static String hello(){ + return s; + } +} diff --git a/tests/testclasses/Double.class b/tests/testclasses/Double.class new file mode 100644 index 0000000..16592dc Binary files /dev/null and b/tests/testclasses/Double.class differ diff --git a/tests/Double.java b/tests/testclasses/Double.java similarity index 84% rename from tests/Double.java rename to tests/testclasses/Double.java index 4083041..54501ac 100644 --- a/tests/Double.java +++ b/tests/testclasses/Double.java @@ -1,3 +1,5 @@ +package testclasses; + public class Double { private final static double d =42.0D; diff --git a/tests/testclasses/Father.class b/tests/testclasses/Father.class new file mode 100644 index 0000000..7fc810a Binary files /dev/null and b/tests/testclasses/Father.class differ diff --git a/tests/Float.class b/tests/testclasses/Float.class similarity index 100% rename from tests/Float.class rename to tests/testclasses/Float.class diff --git a/tests/testclasses/FloatBean.class b/tests/testclasses/FloatBean.class new file mode 100644 index 0000000..d2a5a5b Binary files /dev/null and b/tests/testclasses/FloatBean.class differ diff --git a/tests/FloatBean.java b/tests/testclasses/FloatBean.java similarity index 89% rename from tests/FloatBean.java rename to tests/testclasses/FloatBean.java index f112ddf..8df65fa 100644 --- a/tests/FloatBean.java +++ b/tests/testclasses/FloatBean.java @@ -1,3 +1,5 @@ +package testclasses; + public class FloatBean { private float value; diff --git a/tests/testclasses/IfCmp.java b/tests/testclasses/IfCmp.java new file mode 100644 index 0000000..ed7cee0 --- /dev/null +++ b/tests/testclasses/IfCmp.java @@ -0,0 +1,10 @@ +package testclasses; + +public class IfCmp { + + private static int i; + + public static boolean i_is_1(){ + return i==1; + } +} diff --git a/tests/Inheritance.class b/tests/testclasses/Inheritance.class similarity index 51% rename from tests/Inheritance.class rename to tests/testclasses/Inheritance.class index da8c82f..6271c2d 100644 Binary files a/tests/Inheritance.class and b/tests/testclasses/Inheritance.class differ diff --git a/tests/Inheritance.java b/tests/testclasses/Inheritance.java similarity index 97% rename from tests/Inheritance.java rename to tests/testclasses/Inheritance.java index 0a7b427..4db5e36 100644 --- a/tests/Inheritance.java +++ b/tests/testclasses/Inheritance.java @@ -1,3 +1,5 @@ +package testclasses; + public class Inheritance { public static void main(String[] args) { diff --git a/tests/testclasses/Int.class b/tests/testclasses/Int.class new file mode 100644 index 0000000..7337a6d Binary files /dev/null and b/tests/testclasses/Int.class differ diff --git a/tests/Int.java b/tests/testclasses/Int.java similarity index 77% rename from tests/Int.java rename to tests/testclasses/Int.java index 5b40836..b7dd764 100644 --- a/tests/Int.java +++ b/tests/testclasses/Int.java @@ -1,3 +1,5 @@ +package testclasses; + public class Int { public static int get() { diff --git a/tests/testclasses/Main.class b/tests/testclasses/Main.class new file mode 100644 index 0000000..c8e0bae Binary files /dev/null and b/tests/testclasses/Main.class differ diff --git a/tests/Main.java b/tests/testclasses/Main.java similarity index 90% rename from tests/Main.java rename to tests/testclasses/Main.java index 1c2e17e..3cf02e0 100644 --- a/tests/Main.java +++ b/tests/testclasses/Main.java @@ -1,3 +1,5 @@ +package testclasses ; + public class Main { final static String a; diff --git a/tests/testclasses/Son.class b/tests/testclasses/Son.class new file mode 100644 index 0000000..a51c8c7 Binary files /dev/null and b/tests/testclasses/Son.class differ