├── .gitignore ├── jni ├── src │ └── lib.rs └── Cargo.toml ├── java_test ├── NewObject.java ├── World.java ├── OOP.java ├── ExtendTestVTable.java ├── InitialOnLoad.java ├── TestVTable.java ├── java │ └── math │ │ └── BigDecimal.java ├── ArrayTest.java ├── InvokeAsync.java ├── Simple.java └── HelloWorld.java ├── src ├── lib.rs ├── ani │ └── typedef.rs ├── bytecode │ ├── interface.rs │ ├── atom.rs │ ├── class.rs │ ├── field.rs │ ├── mod.rs │ ├── method.rs │ ├── attribute.rs │ └── constant_pool.rs ├── mem │ ├── strings.rs │ ├── mod.rs │ ├── metaspace.rs │ ├── heap.rs │ ├── stack.rs │ └── klass.rs ├── gc │ └── mod.rs ├── main.rs ├── interpreter │ ├── thread.rs │ └── mod.rs └── classpath │ └── mod.rs ├── Cargo.toml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Cargo.lock 3 | /target/ 4 | **/*.rs.bk 5 | *.class 6 | /.idea -------------------------------------------------------------------------------- /jni/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | assert_eq!(2 + 2, 4); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /java_test/NewObject.java: -------------------------------------------------------------------------------- 1 | public class NewObject { 2 | 3 | public static void main(String[] args) { 4 | Object a = new Object(); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /java_test/World.java: -------------------------------------------------------------------------------- 1 | 2 | public class World { 3 | 4 | int world; 5 | String name = "whoami"; 6 | double hi = 0.00000008; 7 | long ai = 11111111L; 8 | } 9 | -------------------------------------------------------------------------------- /java_test/OOP.java: -------------------------------------------------------------------------------- 1 | 2 | public class OOP { 3 | 4 | public static void main() { 5 | new OOP(); 6 | } 7 | } 8 | 9 | interface RootInterface { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /java_test/ExtendTestVTable.java: -------------------------------------------------------------------------------- 1 | public class ExtendTestVTable extends TestVTable { 2 | 3 | int a; 4 | 5 | boolean b; 6 | 7 | long c; 8 | 9 | short s; 10 | 11 | String str; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(weak_into_raw)] 2 | #![feature(map_first_last)] 3 | pub mod bytecode; 4 | pub mod classpath; 5 | #[macro_use] 6 | pub mod mem; 7 | #[macro_use] 8 | pub mod interpreter; 9 | pub mod gc; 10 | -------------------------------------------------------------------------------- /java_test/InitialOnLoad.java: -------------------------------------------------------------------------------- 1 | public class InitialOnLoad { 2 | static { 3 | System.out.println("Class initialized."); 4 | } 5 | 6 | public static int load = 0; 7 | 8 | public static void test() {} 9 | } 10 | -------------------------------------------------------------------------------- /java_test/TestVTable.java: -------------------------------------------------------------------------------- 1 | 2 | public class TestVTable { 3 | 4 | int i; 5 | 6 | boolean b; 7 | 8 | long l; 9 | 10 | public String toString() { 11 | return ""; 12 | } 13 | 14 | public void test(int a) { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /java_test/java/math/BigDecimal.java: -------------------------------------------------------------------------------- 1 | package java.math; 2 | 3 | public class BigDecimal { 4 | 5 | public void test() { 6 | 7 | } 8 | 9 | public static void main(String[] args) { 10 | 11 | new BigDecimal().test(); 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /jni/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "azeroth-jni" 3 | version = "0.1.0" 4 | authors = ["Zhang Yu "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /java_test/ArrayTest.java: -------------------------------------------------------------------------------- 1 | 2 | public class ArrayTest { 3 | 4 | public static void main(String[] args) { 5 | int[] a = new int[1]; 6 | int[][] aa = new int[2][]; 7 | long[] l = new long[2]; 8 | String[] s = new String[2]; 9 | String[][] ss = new String[3][]; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /java_test/InvokeAsync.java: -------------------------------------------------------------------------------- 1 | 2 | public class InvokeAsync { 3 | 4 | public static void main(String[] args) { 5 | invokeasync(1, 1); 6 | invokestatic(1, 1); 7 | } 8 | 9 | public static void invokestatic(int a, int b) { 10 | int c = a + b; 11 | } 12 | 13 | public static /** async **/ void invokeasync(int a, int b) { 14 | int c = a + b; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ani/typedef.rs: -------------------------------------------------------------------------------- 1 | pub struct JClass { 2 | 3 | } 4 | 5 | pub struct JObject { 6 | 7 | } 8 | 9 | pub type JRef = u32; 10 | pub type JInt = i32; 11 | pub type JFloat = f32; 12 | pub type JLong = i64; 13 | pub type JDouble = f64; 14 | pub type JShort = i16; 15 | pub type JByte = i8; 16 | pub type JChar = char; 17 | pub type JBoolean = bool; 18 | pub type JString = String; 19 | -------------------------------------------------------------------------------- /java_test/Simple.java: -------------------------------------------------------------------------------- 1 | public class Simple { 2 | 3 | public static void test(int a, long b, float c, double d, boolean f) { 4 | int aa = a + 1; 5 | long bb = b - 1; 6 | float cc = c * 1.0f; 7 | if (f) { 8 | double dd = d / 1.0d; 9 | } 10 | } 11 | 12 | public static void main(String[] args) { 13 | test(1, 1L, 1.5f, 0.5d, true); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "azeroth-vm" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["Zhang Yu "] 6 | 7 | [dependencies] 8 | regex = "0.2" 9 | zip = "0.3" 10 | log = "0.4" 11 | argparse = "0.2.2" 12 | chashmap = "2.2.0" 13 | base64 = "0.11.0" 14 | libloading = "0.5" 15 | lazy_static = "1.4.0" 16 | azeroth-jni = { package = "azeroth-jni", path = "./jni" } 17 | 18 | [lib] 19 | name = "azerothvm" 20 | path = "src/lib.rs" 21 | 22 | [[bin]] 23 | name = "java" 24 | path = "src/main.rs" -------------------------------------------------------------------------------- /src/bytecode/interface.rs: -------------------------------------------------------------------------------- 1 | use super::{atom::*, constant_pool::ConstantPool, Traveler}; 2 | 3 | pub type Interfaces = Vec; 4 | 5 | impl Traveler for Interfaces { 6 | fn read(seq: &mut I, constants: Option<&ConstantPool>) -> Interfaces 7 | where 8 | I: Iterator, 9 | { 10 | let size = U2::read(seq, None); 11 | let mut interfaces = Vec::::with_capacity(size as usize); 12 | if let Some(pool) = constants { 13 | for _x in 0..size { 14 | let idx = U2::read(seq, None); 15 | interfaces.push(pool.get_str(idx).to_string()); 16 | } 17 | return interfaces; 18 | } 19 | panic!("need constant pool to resolve interfaces"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /java_test/HelloWorld.java: -------------------------------------------------------------------------------- 1 | 2 | public class HelloWorld implements A { 3 | 4 | private int a; 5 | 6 | public void incr() { 7 | a = a + 1; 8 | } 9 | 10 | public void decr() { 11 | a = a - 1; 12 | } 13 | 14 | static int sum; 15 | 16 | static { 17 | sum = HelloRust.count; 18 | for (int i = 0; i < 5; i++) { 19 | sum += i; 20 | } 21 | } 22 | 23 | public static void main(String[] args) { 24 | HelloWorld s = new HelloWorld(); 25 | s.incr(); 26 | s.decr(); 27 | A a = new HelloRust(); 28 | a.decr(); 29 | HelloRust.say(1, sum); 30 | int[] array = new int[10]; 31 | int[][] _2darray = new int[10][]; 32 | String[] sarray = new String[10]; 33 | array[0] = 0xcafebabe; 34 | int tmp = array[0]; 35 | String hello = "Hello, World."; 36 | } 37 | 38 | 39 | public static class HelloRust extends HelloWorld { 40 | 41 | static int count = 100; 42 | 43 | public void incr() { 44 | super.incr(); 45 | count += 1; 46 | } 47 | 48 | public static int say(int i, int sum) { 49 | return i + sum; 50 | } 51 | } 52 | } 53 | 54 | interface A { 55 | 56 | void decr(); 57 | } 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AzerothVM 2 | 3 | JNI is still working in progress, the code snippet below works just fine. 4 | 5 | ``` 6 | public class HelloWorld implements A { 7 | 8 | private int a; 9 | 10 | public void incr() { 11 | a = a + 1; 12 | } 13 | 14 | public void decr() { 15 | a = a - 1; 16 | } 17 | 18 | static int sum; 19 | 20 | static { 21 | sum = HelloRust.count; 22 | for (int i = 0; i < 5; i++) { 23 | sum += i; 24 | } 25 | } 26 | 27 | public static void main(String[] args) { 28 | HelloWorld s = new HelloWorld(); 29 | s.incr(); 30 | s.decr(); 31 | A a = new HelloRust(); 32 | a.decr(); 33 | HelloRust.say(1, sum); 34 | int[] array = new int[10]; 35 | int[][] _2darray = new int[10][]; 36 | String[] sarray = new String[10]; 37 | array[0] = 0xcafebabe; 38 | int tmp = array[0]; 39 | String hello = "Hello, World."; 40 | } 41 | 42 | 43 | public static class HelloRust extends HelloWorld { 44 | 45 | static int count = 100; 46 | 47 | public void incr() { 48 | } 49 | 50 | public static int say(int i, int sum) { 51 | return i + sum; 52 | } 53 | } 54 | } 55 | 56 | interface A { 57 | 58 | void decr(); 59 | } 60 | ``` 61 | 62 | Compile and run 63 | 64 | ``` 65 | cargo build 66 | export JAVA_HOME=${...} 67 | cd java_test && javac *.java 68 | ../target/debug/java --classpath . HelloWorld 69 | ``` 70 | -------------------------------------------------------------------------------- /src/bytecode/atom.rs: -------------------------------------------------------------------------------- 1 | use super::{constant_pool::ConstantPool, Traveler}; 2 | use std::mem::transmute; 3 | 4 | pub type U1 = u8; 5 | pub type U2 = u16; 6 | pub type U4 = u32; 7 | pub type U8 = u64; 8 | 9 | impl Traveler for U1 { 10 | fn read(seq: &mut I, _constants: Option<&ConstantPool>) -> U1 11 | where 12 | I: Iterator, 13 | { 14 | seq.next().unwrap() 15 | } 16 | } 17 | 18 | impl Traveler for U2 { 19 | fn read(seq: &mut I, _constants: Option<&ConstantPool>) -> U2 20 | where 21 | I: Iterator, 22 | { 23 | let u0 = seq.next().unwrap(); 24 | let u1 = seq.next().unwrap(); 25 | let u = [u1, u0]; 26 | unsafe { transmute::<[u8; 2], u16>(u) } 27 | } 28 | } 29 | 30 | impl Traveler for U4 { 31 | fn read(seq: &mut I, _constants: Option<&ConstantPool>) -> U4 32 | where 33 | I: Iterator, 34 | { 35 | let u0 = seq.next().unwrap(); 36 | let u1 = seq.next().unwrap(); 37 | let u2 = seq.next().unwrap(); 38 | let u3 = seq.next().unwrap(); 39 | let u = [u3, u2, u1, u0]; 40 | unsafe { transmute::<[u8; 4], u32>(u) } 41 | } 42 | } 43 | 44 | impl Traveler for U8 { 45 | fn read(seq: &mut I, _constants: Option<&ConstantPool>) -> U8 46 | where 47 | I: Iterator, 48 | { 49 | let u0 = seq.next().unwrap(); 50 | let u1 = seq.next().unwrap(); 51 | let u2 = seq.next().unwrap(); 52 | let u3 = seq.next().unwrap(); 53 | let u4 = seq.next().unwrap(); 54 | let u5 = seq.next().unwrap(); 55 | let u6 = seq.next().unwrap(); 56 | let u7 = seq.next().unwrap(); 57 | let u = [u7, u6, u5, u4, u3, u2, u1, u0]; 58 | unsafe { transmute::<[u8; 8], u64>(u) } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/mem/strings.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | interpreter::thread::ThreadContext, 3 | mem::{heap::Heap, metaspace::ClassArena, Ref}, 4 | }; 5 | use std::{collections::HashMap, sync::RwLock}; 6 | 7 | pub struct Strings(RwLock>); 8 | 9 | static mut STRINGS: Option = None; 10 | 11 | #[macro_export] 12 | macro_rules! strings { 13 | () => { 14 | unsafe { 15 | match STRINGS { 16 | Some(ref v) => v, 17 | None => panic!("StringConstants not initialized"), 18 | } 19 | } 20 | }; 21 | } 22 | 23 | impl Strings { 24 | pub fn init() { 25 | unsafe { 26 | STRINGS.replace(Strings(RwLock::new(HashMap::with_capacity(4096)))); 27 | } 28 | } 29 | 30 | pub fn get(constant: &str, context: &mut ThreadContext) -> Ref { 31 | { 32 | let constants = strings!().0.read().unwrap(); 33 | if constants.contains_key(constant) { 34 | return *constants.get(constant).unwrap(); 35 | } 36 | } 37 | let mut constants = strings!().0.write().unwrap(); 38 | if constants.contains_key(constant) { 39 | return *constants.get(constant).unwrap(); 40 | } 41 | let (klass, _) = 42 | ClassArena::load_class("java/lang/String", context).expect("jre_not_found"); 43 | let obj = Heap::allocate_object_directly(&klass); 44 | // let bytearray = Heap::allocate_bytes_directly(constant); 45 | // let (content_field, len) = klass.layout.get(&("java/lang/String", "value", "[B")).unwrap(); 46 | // unsafe { 47 | // let target = Heap::ptr(obj as usize + OBJ_HEADER_SIZE + *content_field); 48 | // target.copy_from(bytearray, *len); 49 | // } 50 | constants.insert(constant.to_owned(), obj); 51 | obj 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/gc/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{interpreter::thread::*, jvm_heap, mem::heap::Heap, mem::*}; 2 | 3 | use lazy_static::lazy_static; 4 | use std::collections::HashMap; 5 | use std::sync::{mpsc, Arc, RwLock}; 6 | use std::thread; 7 | 8 | lazy_static! { 9 | static ref ROOTS: Arc>> = Arc::new(RwLock::new(vec![])); 10 | } 11 | 12 | pub static mut GC_TX: Option> = None; 13 | 14 | #[macro_export] 15 | macro_rules! gc { 16 | () => { 17 | unsafe { 18 | match gc::GC_TX { 19 | Some(ref sender) => sender.send(0).unwrap(), 20 | None => panic!("GC not initialized"), 21 | } 22 | } 23 | }; 24 | } 25 | 26 | pub fn init() { 27 | let (tx, rx) = mpsc::channel(); 28 | thread::spawn(move || loop { 29 | let _ = rx.recv().unwrap(); 30 | gc(); 31 | }); 32 | unsafe { 33 | GC_TX.replace(tx); 34 | } 35 | } 36 | 37 | fn copy_young(roots: &mut Vec<*mut Ref>) { 38 | let mut to = jvm_heap!().to.write().unwrap(); 39 | let mut forwarding = HashMap::::new(); 40 | while !roots.is_empty() { 41 | let obj_ref = roots.pop().unwrap(); 42 | let origin_addr = unsafe { *obj_ref }; 43 | let mut obj = Heap::as_obj(origin_addr); 44 | if Heap::is_young_object(origin_addr) && !Heap::is_null(origin_addr) { 45 | Heap::copy_object_to_region(obj_ref, &mut obj, &mut to); 46 | obj.set_gc(); 47 | forwarding.insert(origin_addr, unsafe { *obj_ref }); 48 | let refs = unsafe { &*obj.klass }.get_holding_refs(unsafe { *obj_ref }); 49 | for r in refs { 50 | if Heap::is_young_object(unsafe { *r }) && !Heap::is_null(unsafe { *r }) { 51 | let gc_forwarding = forwarding.get(&unsafe { *r }); 52 | if gc_forwarding.is_some() { 53 | unsafe { r.write(*gc_forwarding.unwrap()) }; 54 | } else { 55 | roots.push(r); 56 | break; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | Heap::swap_from_and_to(); 63 | } 64 | 65 | pub fn gc() { 66 | let mut roots = ThreadGroup::collect_roots(); 67 | copy_young(&mut roots); 68 | ThreadGroup::notify_all(); 69 | } 70 | -------------------------------------------------------------------------------- /src/bytecode/class.rs: -------------------------------------------------------------------------------- 1 | use super::{atom::*, attribute::*, constant_pool::*, field::*, interface::*, method::*, *}; 2 | use std::sync::Arc; 3 | 4 | pub struct Class { 5 | pub constant_pool: ConstantPool, 6 | pub access_flag: U2, 7 | pub this_class_name: String, 8 | pub super_class_name: String, 9 | pub interfaces: Interfaces, 10 | pub fields: Fields, 11 | pub methods: Methods, 12 | pub attributes: Attributes, 13 | } 14 | 15 | impl Class { 16 | pub fn from_vec(bytes: Vec) -> Class { 17 | let seq = &mut bytes.into_iter(); 18 | U4::read(seq, None); 19 | U2::read(seq, None); 20 | U2::read(seq, None); 21 | let constants = ConstantPool::read(seq, None); 22 | let access_flag = U2::read(seq, None); 23 | let this_class = U2::read(seq, None); 24 | let super_class = U2::read(seq, None); 25 | let this_class_name = constants.get_str(this_class).to_string(); 26 | let super_class_name = constants.get_str(super_class).to_string(); 27 | let interfaces = Interfaces::read(seq, Some(&constants)); 28 | let fields = Fields::read(seq, Some(&constants)); 29 | let methods = Methods::read(seq, Some(&constants)); 30 | let attributes = Attributes::read(seq, Some(&constants)); 31 | Class { 32 | constant_pool: constants, 33 | access_flag: access_flag, 34 | this_class_name: this_class_name, 35 | super_class_name: super_class_name, 36 | interfaces: interfaces, 37 | fields: fields, 38 | methods: methods, 39 | attributes: attributes, 40 | } 41 | } 42 | 43 | pub fn get_method(&self, method_name: &str, method_descriptor: &str) -> Option> { 44 | for ref m in &self.methods { 45 | if m.descriptor == method_descriptor && m.name == method_name { 46 | return Some(Arc::clone(m)); 47 | } 48 | } 49 | None 50 | } 51 | 52 | pub fn get_field(&self, field_name: &str, field_descriptor: &str) -> Option> { 53 | for ref f in &self.fields { 54 | if f.name == field_name && f.descriptor == field_descriptor { 55 | return Some(Arc::clone(f)); 56 | } 57 | } 58 | None 59 | } 60 | 61 | pub fn get_name(&self) -> &str { 62 | self.this_class_name.as_ref() 63 | } 64 | 65 | pub fn get_super_class(&self) -> &str { 66 | self.super_class_name.as_ref() 67 | } 68 | 69 | pub fn get_interfaces(&self) -> &Vec { 70 | self.interfaces.as_ref() 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // #![feature(weak_into_raw)] 2 | use azerothvm::{ 3 | gc, 4 | interpreter::thread::ThreadGroup, 5 | mem::{ 6 | heap::Heap, 7 | metaspace::{ClassArena, *}, 8 | strings::Strings, 9 | }, 10 | }; 11 | 12 | fn main() { 13 | match std::env::current_dir() { 14 | Ok(dir) => { 15 | if let Some(cp) = dir.to_str() { 16 | let mut main_class = String::new(); 17 | let mut cp = cp.to_string(); 18 | { 19 | let mut args = argparse::ArgumentParser::new(); 20 | args.refer(&mut cp) 21 | .add_option(&["--classpath"], argparse::Store, ""); 22 | args.refer(&mut main_class) 23 | .add_argument("", argparse::Store, ""); 24 | args.parse_args_or_exit(); 25 | } 26 | match std::env::var("JAVA_HOME") { 27 | Ok(home) => start_vm(&main_class, &cp, &home), 28 | Err(_) => panic!("JAVA_HOME not set"), 29 | } 30 | } 31 | } 32 | Err(_) => panic!("can't read file"), 33 | } 34 | } 35 | 36 | fn resolve_system_classpath(java_home: &str) -> Vec { 37 | let mut java_home_dir = std::path::PathBuf::from(java_home); 38 | java_home_dir.push("jre/lib"); 39 | let mut paths = Vec::::new(); 40 | if let Ok(sysjars) = std::fs::read_dir(&java_home_dir) { 41 | paths.append( 42 | &mut sysjars 43 | .map(|f| f.unwrap().path()) 44 | .filter(|f| f.extension() == Some("jar".as_ref())) 45 | .map(|f| f.to_str().unwrap().to_string()) 46 | .collect::>(), 47 | ); 48 | java_home_dir.push("ext"); 49 | if let Ok(extjars) = std::fs::read_dir(&java_home_dir) { 50 | paths.append( 51 | &mut extjars 52 | .map(|f| f.unwrap().path()) 53 | .filter(|f| f.extension() == Some("jar".as_ref())) 54 | .map(|f| f.to_str().unwrap().to_string()) 55 | .collect::>(), 56 | ); 57 | } 58 | paths 59 | } else { 60 | panic!("JAVA_HOME not recognized"); 61 | } 62 | } 63 | 64 | fn resolve_user_classpath(user_classpath: &str) -> Vec { 65 | return user_classpath 66 | .split(":") 67 | .map(|p| p.to_string()) 68 | .collect::>(); 69 | } 70 | 71 | fn start_vm(class_name: &str, user_classpath: &str, java_home: &str) { 72 | let system_paths = resolve_system_classpath(java_home); 73 | let user_paths = resolve_user_classpath(user_classpath); 74 | ClassArena::init(user_paths, system_paths); 75 | Heap::init(10 * 1024 * 1024, 1024 * 1024, 1024 * 1024); 76 | Strings::init(); 77 | ThreadGroup::init(); 78 | gc::init(); 79 | ThreadGroup::new_thread( 80 | ROOT_CLASSLOADER, 81 | class_name, 82 | "main", 83 | "([Ljava/lang/String;)V", 84 | true, 85 | ); 86 | } 87 | -------------------------------------------------------------------------------- /src/bytecode/field.rs: -------------------------------------------------------------------------------- 1 | use super::{atom::*, attribute::*, constant_pool::ConstantPool, Traveler}; 2 | use crate::mem::Value; 3 | use std::cell::Cell; 4 | use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; 5 | use std::sync::Arc; 6 | 7 | pub type Fields = Vec>; 8 | 9 | const ACC_STATIC: u16 = 0x0008; 10 | 11 | const ACC_PUBLIC: u16 = 0x0001; 12 | 13 | const ACC_PROTECTED: u16 = 0x0004; 14 | 15 | const ACC_PRIVATE: u16 = 0x0002; 16 | 17 | const ACC_FINAL: u16 = 0x0010; 18 | 19 | pub struct Field { 20 | pub access_flag: U2, 21 | pub name: String, 22 | pub descriptor: String, 23 | pub attributes: Attributes, 24 | pub value: Cell>, 25 | } 26 | 27 | impl Field { 28 | pub fn memory_size(&self) -> usize { 29 | match self.descriptor.as_str() { 30 | "J" | "D" => 8, 31 | _ => 4, 32 | } 33 | } 34 | 35 | pub fn is_static(&self) -> bool { 36 | self.access_flag & ACC_STATIC == ACC_STATIC 37 | } 38 | 39 | pub fn is_public(&self) -> bool { 40 | self.access_flag & ACC_PUBLIC == ACC_PUBLIC 41 | } 42 | 43 | pub fn is_protected(&self) -> bool { 44 | self.access_flag & ACC_PROTECTED == ACC_PROTECTED 45 | } 46 | 47 | pub fn is_private(&self) -> bool { 48 | self.access_flag & ACC_PRIVATE == ACC_PRIVATE 49 | } 50 | 51 | pub fn is_final(&self) -> bool { 52 | self.access_flag & ACC_FINAL == ACC_FINAL 53 | } 54 | } 55 | 56 | impl Ord for Field { 57 | fn cmp(&self, other: &Self) -> Ordering { 58 | self.memory_size().cmp(&other.memory_size()) 59 | } 60 | } 61 | 62 | impl PartialOrd for Field { 63 | fn partial_cmp(&self, other: &Self) -> Option { 64 | Some(self.cmp(other)) 65 | } 66 | } 67 | 68 | impl Eq for Field {} 69 | 70 | impl PartialEq for Field { 71 | fn eq(&self, other: &Self) -> bool { 72 | self.access_flag == other.access_flag 73 | && self.name == other.name 74 | && self.descriptor == other.descriptor 75 | } 76 | } 77 | 78 | impl Traveler for Fields { 79 | fn read(seq: &mut I, constants: Option<&ConstantPool>) -> Fields 80 | where 81 | I: Iterator, 82 | { 83 | let size = U2::read(seq, None); 84 | let mut fields = Vec::>::with_capacity(size as usize); 85 | for _x in 0..size { 86 | fields.push(Arc::new(Field::read(seq, constants))); 87 | } 88 | fields 89 | } 90 | } 91 | 92 | // TODO 93 | fn init_value(access_flag: u16, descriptor: &str) -> Option { 94 | if access_flag & ACC_STATIC == ACC_STATIC { 95 | match descriptor { 96 | "D" | "J" => Some(Value::DWord(0)), 97 | _ => Some(Value::Word(0)), 98 | } 99 | } else { 100 | None 101 | } 102 | } 103 | 104 | impl Traveler for Field { 105 | fn read(seq: &mut I, constants: Option<&ConstantPool>) -> Field 106 | where 107 | I: Iterator, 108 | { 109 | let access_flag = U2::read(seq, None); 110 | let name_idx = U2::read(seq, None); 111 | let descriptor_idx = U2::read(seq, None); 112 | if let Some(pool) = constants { 113 | let descriptor = pool.get_str(descriptor_idx).to_string(); 114 | return Field { 115 | access_flag: access_flag, 116 | name: pool.get_str(name_idx).to_string(), 117 | value: Cell::new(None), 118 | descriptor: descriptor, 119 | attributes: Attributes::read(seq, Some(pool)), 120 | }; 121 | } 122 | panic!("need constant pool to resolve fields") 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/mem/mod.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Borrow; 2 | use std::hash::{Hash, Hasher}; 3 | 4 | use crate::bytecode::class::Class; 5 | use crate::classpath::Classpath; 6 | 7 | use chashmap::CHashMap; 8 | use regex::Regex; 9 | 10 | pub mod heap; 11 | pub mod metaspace; 12 | pub mod klass; 13 | pub mod stack; 14 | pub mod strings; 15 | 16 | // pub const PTR_SIZE: usize = std::mem::size_of::(); 17 | 18 | // 32-bit vm 19 | pub const PTR_SIZE: usize = 4; 20 | 21 | pub const NULL: Slot = [0x00; PTR_SIZE]; 22 | pub const LONG_NULL: WideSlot = [0x00; PTR_SIZE * 2]; 23 | 24 | pub type Slot = [u8; PTR_SIZE]; 25 | pub type WideSlot = [u8; PTR_SIZE * 2]; 26 | 27 | pub type Ref = u32; 28 | 29 | pub trait ToRef { 30 | fn from_slot(slot: Slot) -> Ref; 31 | } 32 | 33 | impl ToRef for Ref { 34 | fn from_slot(slot: Slot) -> Ref { 35 | Ref::from_le_bytes(slot) 36 | } 37 | } 38 | 39 | #[derive(Copy, Clone, Debug)] 40 | pub enum Value { 41 | Byte(u8), 42 | DByte(u16), 43 | Word(u32), 44 | DWord(u64), 45 | } 46 | 47 | impl Value { 48 | pub fn of(v: Value) -> Slot { 49 | match v { 50 | Value::Byte(vv) => [vv, 0, 0, 0], 51 | Value::DByte(vv) => { 52 | let most = ((vv & 0xf0u16) >> 8) as u8; 53 | let least = (vv & 0x0fu16) as u8; 54 | [most, least, 0, 0] 55 | } 56 | Value::Word(vv) => vv.to_le_bytes(), 57 | _ => panic!(""), 58 | } 59 | } 60 | 61 | pub fn of_w(v: Value) -> WideSlot { 62 | match v { 63 | Value::DWord(vv) => vv.to_le_bytes(), 64 | _ => panic!(""), 65 | } 66 | } 67 | 68 | pub fn eval(v: Slot, descriptor: &str) -> Value { 69 | let ch = descriptor.chars().next().unwrap(); 70 | match ch { 71 | 'D' | 'J' => { 72 | let mut vv = [0u8; 8]; 73 | &vv[..].copy_from_slice(&v); 74 | Value::DWord(u64::from_le_bytes(vv)) 75 | } 76 | 'Z' | 'B' => Value::Byte(v[0]), 77 | 'S' | 'C' => { 78 | let mut vv = [0u8; 2]; 79 | &vv[..].copy_from_slice(&v); 80 | Value::DByte(u16::from_le_bytes(vv)) 81 | } 82 | _ => { 83 | let mut vv = [0u8; 4]; 84 | &vv[..].copy_from_slice(&v); 85 | Value::Word(u32::from_le_bytes(vv)) 86 | } 87 | } 88 | } 89 | 90 | pub fn eval_w(v: WideSlot) -> Value { 91 | Value::DWord(u64::from_le_bytes(v)) 92 | } 93 | } 94 | 95 | #[derive(Debug)] 96 | pub struct RefKey { 97 | key: (String, String, String), 98 | key_ptr: ((*const u8, usize), (*const u8, usize), (*const u8, usize)), 99 | } 100 | 101 | impl RefKey { 102 | pub fn new(key0: String, key1: String, key2: String) -> Self { 103 | Self { 104 | key_ptr: ( 105 | (key0.as_bytes().as_ptr(), key0.len()), 106 | (key1.as_bytes().as_ptr(), key1.len()), 107 | (key2.as_bytes().as_ptr(), key2.len()), 108 | ), 109 | key: (key0, key1, key2), 110 | } 111 | } 112 | } 113 | 114 | impl Hash for RefKey { 115 | fn hash(&self, state: &mut H) { 116 | self.key.0.hash(state); 117 | self.key.1.hash(state); 118 | self.key.2.hash(state); 119 | } 120 | } 121 | 122 | impl PartialEq for RefKey { 123 | fn eq(&self, other: &Self) -> bool { 124 | self.key.0 == other.key.0 && self.key.1 == other.key.1 && self.key.2 == other.key.2 125 | } 126 | } 127 | 128 | impl<'a> Borrow<(&'a str, &'a str, &'a str)> for RefKey 129 | where 130 | Self: 'a, 131 | { 132 | fn borrow(&self) -> &(&'a str, &'a str, &'a str) { 133 | unsafe { std::mem::transmute(&self.key_ptr) } 134 | } 135 | } 136 | 137 | impl Eq for RefKey {} 138 | 139 | impl Clone for RefKey { 140 | fn clone(&self) -> Self { 141 | Self::new(self.key.0.clone(), self.key.1.clone(), self.key.2.clone()) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/bytecode/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod atom; 2 | pub mod attribute; 3 | pub mod class; 4 | pub mod constant_pool; 5 | pub mod field; 6 | pub mod interface; 7 | pub mod method; 8 | 9 | use self::atom::*; 10 | use self::constant_pool::ConstantPool; 11 | 12 | trait Traveler { 13 | fn read(seq: &mut I, constants: Option<&ConstantPool>) -> T 14 | where 15 | I: Iterator; 16 | } 17 | 18 | pub const METHOD_ACC_STATIC: U2 = 0x0008; 19 | 20 | pub fn resolve_method_descriptor( 21 | descriptor: &str, 22 | access_flag: U2, 23 | ) -> (Vec, usize, String) { 24 | let t = descriptor 25 | .chars() 26 | .into_iter() 27 | .map(|x| x.to_string()) 28 | .collect::>(); 29 | let mut params: Vec = vec![]; 30 | let mut expect_type: bool = false; 31 | let mut expect_semicolon: bool = false; 32 | let mut token: String = String::new(); 33 | let instance = if access_flag & METHOD_ACC_STATIC == METHOD_ACC_STATIC { 34 | 0 35 | } else { 36 | 1 37 | }; 38 | for (i, ch) in descriptor.chars().enumerate() { 39 | if expect_semicolon { 40 | token.push(ch); 41 | if ch == ';' { 42 | expect_semicolon = false; 43 | expect_type = false; 44 | params.push(token.clone()); 45 | token.clear(); 46 | } 47 | continue; 48 | } 49 | match ch { 50 | '(' => { 51 | if expect_type { 52 | panic!(format!("Illegal method descriptor: {}", descriptor)); 53 | } 54 | continue; 55 | } 56 | ')' => { 57 | if expect_type { 58 | panic!(format!("Illegal method descriptor: {}", descriptor)); 59 | } 60 | let slots = params 61 | .iter() 62 | .map(|x| match x.as_ref() { 63 | "D" | "J" => 2, 64 | _ => 1, 65 | }) 66 | .sum::() 67 | + instance; 68 | return (params, slots, t[i + 1..].join("")); 69 | } 70 | '[' => { 71 | expect_type = true; 72 | token.push('['); 73 | } 74 | 'L' => { 75 | expect_semicolon = true; 76 | token.push('L'); 77 | } 78 | 'I' | 'J' | 'S' | 'B' | 'C' | 'F' | 'D' | 'Z' => { 79 | if expect_type { 80 | token.push(ch); 81 | params.push(token.clone()); 82 | token.clear(); 83 | expect_type = false; 84 | } else { 85 | params.push(ch.to_string()); 86 | } 87 | } 88 | _ => { 89 | if expect_semicolon { 90 | token.push(ch); 91 | } else { 92 | panic!(format!("Illegal method descriptor: {}", descriptor)); 93 | } 94 | } 95 | } 96 | } 97 | panic!(format!("Illegal method descriptor: {}", descriptor)); 98 | } 99 | 100 | #[test] 101 | pub fn test_resolve_method() { 102 | let (params, slots, ret) = 103 | resolve_method_descriptor("(Ljava/lang/String;IJ)V", METHOD_ACC_STATIC); 104 | assert_eq!(ret, "V"); 105 | assert_eq!(slots, 4); 106 | assert_eq!(params, vec!["Ljava/lang/String;", "I", "J"]); 107 | let (params, slots, ret) = 108 | resolve_method_descriptor("([[I[J[[Ljava/lang/IString;)[Ljava/lang/String;", 0); 109 | assert_eq!(ret, "[Ljava/lang/String;"); 110 | assert_eq!(slots, 4); 111 | assert_eq!(params, vec!["[[I", "[J", "[[Ljava/lang/IString;"]); 112 | let (params, slots, ret) = 113 | resolve_method_descriptor("([Ljava/lang/String;)V", METHOD_ACC_STATIC); 114 | assert_eq!(params, vec!["[Ljava/lang/String;"]); 115 | assert_eq!(slots, 1); 116 | assert_eq!(ret, "V"); 117 | } 118 | -------------------------------------------------------------------------------- /src/interpreter/thread.rs: -------------------------------------------------------------------------------- 1 | use crate::interpreter; 2 | use crate::mem::{metaspace::*, stack::*, *}; 3 | use std::cell::RefCell; 4 | use std::collections::BTreeMap; 5 | use std::ops::{Deref, DerefMut}; 6 | use std::rc::Rc; 7 | use std::sync::atomic::AtomicU32; 8 | use std::sync::mpsc::{channel, Receiver, Sender}; 9 | use std::sync::{Arc, Mutex}; 10 | 11 | pub struct ThreadGroup { 12 | threads: 13 | Arc>, Sender, Receiver>)>>>, 14 | } 15 | 16 | static mut THREADS: Option = None; 17 | 18 | pub const THREAD_RUNNING: u32 = 1; 19 | pub const THREAD_WAIT: u32 = 2; 20 | 21 | #[macro_export] 22 | macro_rules! jvm_threads { 23 | () => { 24 | unsafe { 25 | match THREADS { 26 | Some(ref threads) => threads, 27 | None => panic!("ThreadGroup not initialized"), 28 | } 29 | } 30 | }; 31 | } 32 | 33 | impl ThreadGroup { 34 | pub fn init() { 35 | unsafe { 36 | THREADS.replace(ThreadGroup { 37 | threads: Arc::new(Mutex::new(BTreeMap::new())), 38 | }); 39 | } 40 | } 41 | 42 | pub fn new_thread(classloader: Ref, class_name: &str, method_name: &str, method_descriptor: &str, init: bool) { 43 | let context = { 44 | let mut threads = jvm_threads!().threads.lock().unwrap(); 45 | let id = *threads.deref().keys().last().unwrap_or(&0); 46 | let (sig_tx, sig_rx) = channel(); 47 | let (col_tx, col_rx) = channel(); 48 | let thread = ThreadContext::new(id, classloader, sig_rx, col_tx); 49 | threads 50 | .deref_mut() 51 | .insert(id, (Rc::new(RefCell::new(thread)), sig_tx, col_rx)); 52 | threads.deref().get(&id).unwrap().0.clone() 53 | }; 54 | let mut context = context.borrow_mut(); 55 | let class = match ClassArena::load_class(class_name, &mut context) { 56 | Err(no_class) => panic!(format!("ClassNotFoundException: {}", no_class)), 57 | Ok((class, _)) => class, 58 | }; 59 | if init { 60 | interpreter::execute(&mut context); 61 | } 62 | let method = class 63 | .bytecode 64 | .as_ref() 65 | .unwrap() 66 | .get_method(method_name, method_descriptor) 67 | .expect("Method not found"); 68 | context.stack.invoke( 69 | Arc::as_ptr(&class.bytecode.as_ref().unwrap()), 70 | Arc::as_ptr(&method), 71 | 0, 72 | 1, 73 | ); 74 | interpreter::execute(&mut context); 75 | Self::remove_thread(context.id); 76 | } 77 | 78 | pub fn remove_thread(id: u32) { 79 | let mut threads = jvm_threads!().threads.lock().unwrap(); 80 | threads.deref_mut().remove(&id); 81 | } 82 | 83 | pub fn collect_roots() -> Vec<*mut Ref> { 84 | let threads = jvm_threads!().threads.lock().unwrap(); 85 | threads 86 | .deref() 87 | .values() 88 | .map(|t| { 89 | t.1.send(THREAD_WAIT).unwrap(); 90 | t.2.recv().unwrap() 91 | }) 92 | .flatten() 93 | .collect::>() 94 | } 95 | 96 | pub fn notify_all() { 97 | let threads = jvm_threads!().threads.lock().unwrap(); 98 | threads 99 | .deref() 100 | .values() 101 | .for_each(|t| t.1.send(THREAD_RUNNING).unwrap()); 102 | } 103 | } 104 | 105 | pub struct ThreadContext { 106 | pub pc: usize, 107 | pub stack: JavaStack, 108 | pub classloader: Ref, 109 | pub exception_pending: bool, 110 | pub throwable_initialized: bool, 111 | pub status: AtomicU32, 112 | pub id: u32, 113 | pub rx: Receiver, 114 | pub tx: Sender>, 115 | } 116 | 117 | impl ThreadContext { 118 | fn new(id: u32, classloader: Ref, rx: Receiver, tx: Sender>) -> Self { 119 | Self { 120 | pc: 0, 121 | stack: JavaStack::new(), 122 | classloader: classloader, 123 | exception_pending: false, 124 | throwable_initialized: false, 125 | status: AtomicU32::new(THREAD_RUNNING), 126 | id: id, 127 | rx: rx, 128 | tx: tx, 129 | } 130 | } 131 | 132 | pub fn roots(&self) -> Vec<*mut Ref> { 133 | self.stack.collect_tracing_roots() 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/bytecode/method.rs: -------------------------------------------------------------------------------- 1 | use super::{atom::*, attribute::*, constant_pool::ConstantPool, Traveler}; 2 | 3 | use std::sync::Arc; 4 | 5 | pub type Methods = Vec>; 6 | 7 | const ACC_PUBLIC: U2 = 0x0001; // Declared public; may be accessed from outside its package. 8 | 9 | const ACC_PRIVATE: U2 = 0x0002; // Declared private; accessible only within the defining class. 10 | 11 | const ACC_PROTECTED: U2 = 0x0004; // Declared protected; may be accessed within subclasses. 12 | 13 | const ACC_STATIC: U2 = 0x0008; // Declared static. 14 | 15 | const ACC_FINAL: U2 = 0x0010; // Declared final; must not be overridden (§5.4.5). 16 | 17 | const ACC_SYNCHRONIZED: U2 = 0x0020; // Declared synchronized; invocation is wrapped by a monitor use. 18 | 19 | const ACC_BRIDGE: U2 = 0x0040; // A bridge method, generated by the compiler. 20 | 21 | const ACC_VARARGS: U2 = 0x0080; // Declared with variable number of arguments. 22 | 23 | const ACC_NATIVE: U2 = 0x0100; // Declared native; implemented in a language other than Java. 24 | 25 | const ACC_ABSTRACT: U2 = 0x0400; // Declared abstract; no implementation is provided. 26 | 27 | const ACC_STRICT: U2 = 0x0800; // Declared strictfp; floating-point mode is FPstrict. 28 | 29 | const ACC_SYNTHETIC: U2 = 0x1000; // Declared synthetic; not present in the source code. 30 | 31 | pub struct Method { 32 | pub access_flag: U2, 33 | pub name: String, 34 | pub descriptor: String, 35 | pub attributes: Attributes, 36 | } 37 | 38 | impl Traveler for Method { 39 | fn read(seq: &mut I, constants: Option<&ConstantPool>) -> Method 40 | where 41 | I: Iterator, 42 | { 43 | let access_flag = U2::read(seq, None); 44 | if let Some(pool) = constants { 45 | return Method { 46 | access_flag: access_flag, 47 | name: pool.get_str(U2::read(seq, None)).to_string(), 48 | descriptor: pool.get_str(U2::read(seq, None)).to_string(), 49 | attributes: Attributes::read(seq, Some(pool)), 50 | }; 51 | } 52 | panic!("need constant pool to resolve methods"); 53 | } 54 | } 55 | 56 | pub type CodeSegment = ( 57 | U2, 58 | U2, 59 | Arc>, 60 | Arc>, 61 | Arc, 62 | ); 63 | 64 | impl Method { 65 | pub fn get_code(&self) -> Option { 66 | for attr in &self.attributes { 67 | match attr { 68 | Attribute::Code(stacks, locals, code, exception, attribute) => { 69 | return Some(( 70 | *stacks, 71 | *locals, 72 | Arc::clone(code), 73 | Arc::clone(exception), 74 | Arc::clone(attribute), 75 | )); 76 | } 77 | _ => continue, 78 | } 79 | } 80 | return None; 81 | } 82 | 83 | pub fn get_name_and_descriptor(&self) -> (&str, &str, U2) { 84 | ( 85 | self.name.as_ref(), 86 | self.descriptor.as_ref(), 87 | self.access_flag, 88 | ) 89 | } 90 | 91 | pub fn is_public(&self) -> bool { 92 | self.access_flag & ACC_PUBLIC == ACC_PUBLIC 93 | } 94 | 95 | pub fn is_protected(&self) -> bool { 96 | self.access_flag & ACC_PROTECTED == ACC_PROTECTED 97 | } 98 | 99 | pub fn is_final(&self) -> bool { 100 | self.access_flag & ACC_FINAL == ACC_FINAL 101 | } 102 | 103 | pub fn is_static(&self) -> bool { 104 | self.access_flag & ACC_STATIC == ACC_STATIC 105 | } 106 | 107 | pub fn is_native(&self) -> bool { 108 | self.access_flag & ACC_NATIVE == ACC_NATIVE 109 | } 110 | 111 | pub fn is_synchronized(&self) -> bool { 112 | self.access_flag & ACC_SYNCHRONIZED == ACC_SYNCHRONIZED 113 | } 114 | } 115 | 116 | impl Traveler for Methods { 117 | fn read(seq: &mut I, constants: Option<&ConstantPool>) -> Methods 118 | where 119 | I: Iterator, 120 | { 121 | let size = U2::read(seq, None); 122 | let mut methods = Vec::>::with_capacity(size as usize); 123 | for _x in 0..size { 124 | let method = Method::read(seq, constants); 125 | methods.push(Arc::new(method)); 126 | } 127 | methods 128 | } 129 | } 130 | 131 | // impl Methods { 132 | // pub fn find(&self, name: &str, descriptor: &str) -> Option> { 133 | // for m in &self { 134 | // if m.descriptor == descriptor && m.name == name { 135 | // return Some(Arc::clone(m)); 136 | // } 137 | // } 138 | // None 139 | // } 140 | // } 141 | -------------------------------------------------------------------------------- /src/classpath/mod.rs: -------------------------------------------------------------------------------- 1 | use regex::Regex; 2 | use std::{ 3 | fs::File, 4 | io::Read, 5 | path::{Path, PathBuf}, 6 | }; 7 | use log::trace; 8 | 9 | enum ClassEntry { 10 | Jar(String), 11 | Dir(String), 12 | } 13 | 14 | impl ClassEntry { 15 | // class_file format: java/lang/String.class 16 | fn find_class(&self, class_file: &str) -> Option> { 17 | match self { 18 | &ClassEntry::Dir(ref dir) => { 19 | let mut abs_path = PathBuf::from(&dir); 20 | abs_path.push(class_file); 21 | if abs_path.exists() && abs_path.is_file() { 22 | let mut f = File::open(abs_path).unwrap(); 23 | let meta = f.metadata().unwrap(); 24 | let mut buf = Vec::::with_capacity(meta.len() as usize); 25 | f.read_to_end(&mut buf).unwrap(); 26 | trace!("find class {} from {}", class_file, dir); 27 | Some(buf) 28 | } else { 29 | None 30 | } 31 | } 32 | &ClassEntry::Jar(ref jar) => { 33 | let jar_file = File::open(&jar).unwrap(); 34 | let mut archive = zip::ZipArchive::new(&jar_file).unwrap(); 35 | for i in 0..archive.len() { 36 | let mut file = archive.by_index(i).unwrap(); 37 | if file.name() == class_file { 38 | let mut buf = Vec::::with_capacity(file.size() as usize); 39 | file.read_to_end(&mut buf).unwrap(); 40 | trace!("find class {} from {}", class_file, jar); 41 | return Some(buf); 42 | } 43 | } 44 | None 45 | } 46 | } 47 | } 48 | } 49 | 50 | pub struct Classpath { 51 | bootstrap: Vec, 52 | ext: Vec, 53 | app: Vec, 54 | } 55 | 56 | impl Classpath { 57 | pub fn init() -> Classpath { 58 | Classpath { 59 | bootstrap: Vec::::new(), 60 | ext: Vec::::new(), 61 | app: Vec::::new(), 62 | } 63 | } 64 | 65 | pub fn find_bootstrap_class(&self, class_name: &str) -> Option> { 66 | Classpath::find_class(&self.bootstrap, class_name) 67 | } 68 | 69 | pub fn find_ext_class(&self, class_name: &str) -> Option> { 70 | Classpath::find_class(&self.ext, class_name) 71 | } 72 | 73 | pub fn find_app_class(&self, class_name: &str) -> Option> { 74 | Classpath::find_class(&self.app, class_name) 75 | } 76 | 77 | pub fn find_resource(&self, resource_name: &str) -> Option { 78 | for entry in &self.app { 79 | match entry { 80 | &ClassEntry::Dir(ref dir) => match std::fs::read_dir(dir) { 81 | Err(_) => panic!("bootstrap classpath read error."), 82 | Ok(paths) => { 83 | let f = paths 84 | .map(|f| f.unwrap().path()) 85 | .filter(|f| f.ends_with(resource_name)) 86 | .map(|f| File::open(f).unwrap()) 87 | .find(|_| true); 88 | if let Some(res) = f { 89 | return Some(res); 90 | } 91 | } 92 | }, 93 | &ClassEntry::Jar(_) => {} 94 | } 95 | } 96 | None 97 | } 98 | 99 | fn find_class(entries: &Vec, class_name: &str) -> Option> { 100 | let mut class_file = Regex::new(r"\.") 101 | .unwrap() 102 | .replace_all(class_name, "/") 103 | .into_owned(); 104 | class_file.push_str(".class"); 105 | for entry in entries { 106 | match entry.find_class(&class_file) { 107 | None => {} 108 | Some(class) => { 109 | return Some(class); 110 | } 111 | } 112 | } 113 | None 114 | } 115 | 116 | pub fn get_classpath(&self) -> String { 117 | self.bootstrap.iter() 118 | .chain(self.ext.iter()) 119 | .chain(self.app.iter()) 120 | .map(|e| { 121 | match e { 122 | &ClassEntry::Jar(ref s) => s, 123 | &ClassEntry::Dir(ref d) => d, 124 | }}) 125 | .fold("".to_owned(), |cp, en| cp + ":" + en) 126 | } 127 | 128 | pub fn append_bootstrap_classpath(&mut self, path: String) { 129 | Classpath::append_classpath(&mut self.bootstrap, path); 130 | } 131 | 132 | pub fn append_ext_classpath(&mut self, path: String) { 133 | Classpath::append_classpath(&mut self.ext, path); 134 | } 135 | 136 | pub fn append_app_classpath(&mut self, path: String) { 137 | Classpath::append_classpath(&mut self.app, path); 138 | } 139 | 140 | fn append_classpath(entries: &mut Vec, path_str: String) { 141 | let s = &path_str.clone(); 142 | let path = Path::new(s); 143 | if path.is_dir() { 144 | entries.push(ClassEntry::Dir(path_str)); 145 | } else if path.extension() == Some("jar".as_ref()) { 146 | entries.push(ClassEntry::Jar(path_str)); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/mem/metaspace.rs: -------------------------------------------------------------------------------- 1 | use crate::interpreter::thread::ThreadContext; 2 | use crate::mem::{klass::Klass, *}; 3 | use log::trace; 4 | use std::sync::{Arc, Mutex}; 5 | 6 | pub struct ClassArena { 7 | pub cp: Classpath, 8 | // TODO allow a class been loaded by different classloader instances 9 | pub classes: CHashMap>, 10 | mutex: Mutex, 11 | } 12 | 13 | // pub enum Classloader { 14 | // ROOT, 15 | // EXT, 16 | // APP(Ref), 17 | // } 18 | 19 | pub const ROOT_CLASSLOADER: Ref = 0; 20 | 21 | static mut CLASSES: Option> = None; 22 | 23 | #[macro_export] 24 | macro_rules! class_arena { 25 | () => { 26 | unsafe { 27 | match CLASSES { 28 | Some(ref classes) => classes, 29 | None => panic!("ClassArena not initialized"), 30 | } 31 | } 32 | }; 33 | } 34 | 35 | impl ClassArena { 36 | pub fn init(app_paths: Vec, bootstrap_paths: Vec) { 37 | let mut cp = Classpath::init(); 38 | for path in bootstrap_paths { 39 | cp.append_bootstrap_classpath(path); 40 | } 41 | for path in app_paths { 42 | cp.append_app_classpath(path); 43 | } 44 | let classes = CHashMap::new(); 45 | classes.insert("I".to_owned(), Arc::new(Klass::new_phantom_klass("I"))); 46 | classes.insert("J".to_owned(), Arc::new(Klass::new_phantom_klass("J"))); 47 | classes.insert("F".to_owned(), Arc::new(Klass::new_phantom_klass("F"))); 48 | classes.insert("D".to_owned(), Arc::new(Klass::new_phantom_klass("D"))); 49 | classes.insert("S".to_owned(), Arc::new(Klass::new_phantom_klass("S"))); 50 | classes.insert("C".to_owned(), Arc::new(Klass::new_phantom_klass("C"))); 51 | classes.insert("Z".to_owned(), Arc::new(Klass::new_phantom_klass("Z"))); 52 | classes.insert("B".to_owned(), Arc::new(Klass::new_phantom_klass("B"))); 53 | classes.insert("V".to_owned(), Arc::new(Klass::new_phantom_klass("V"))); 54 | let arena = ClassArena { 55 | cp: cp, 56 | classes: classes, 57 | mutex: Mutex::new(0), 58 | }; 59 | unsafe { CLASSES.replace(Arc::new(arena)) }; 60 | } 61 | 62 | fn parse_class(class_name: &str) -> Option { 63 | if let Some(bytecode) = class_arena!().cp.find_app_class(class_name) { 64 | return Some(Class::from_vec(bytecode)); 65 | } 66 | if let Some(bytecode) = class_arena!().cp.find_bootstrap_class(class_name) { 67 | return Some(Class::from_vec(bytecode)); 68 | } 69 | if let Some(bytecode) = class_arena!().cp.find_ext_class(class_name) { 70 | return Some(Class::from_vec(bytecode)); 71 | } 72 | None 73 | } 74 | 75 | pub fn load_class( 76 | class_name: &str, 77 | context: &mut ThreadContext, 78 | ) -> Result<(Arc, bool), String> { 79 | let class_name = Regex::new(r"\.") 80 | .unwrap() 81 | .replace_all(class_name, "/") 82 | .into_owned(); 83 | match class_arena!().classes.get(&class_name) { 84 | Some(klass) => Ok((Arc::clone(&klass), true)), 85 | None => { 86 | let _ = class_arena!().mutex.lock().unwrap(); 87 | if let Some(loaded) = class_arena!().classes.get(&class_name) { 88 | return Ok((loaded.clone(), true)); 89 | } 90 | if &class_name[..1] == "[" { 91 | let (_, initialized) = Self::load_class(&class_name[1..], context)?; 92 | let array_klass = Arc::new(Klass::new_phantom_klass(&class_name)); 93 | class_arena!() 94 | .classes 95 | .insert(class_name, array_klass.clone()); 96 | return Ok((array_klass, initialized)); 97 | } 98 | let class = match Self::parse_class(&class_name) { 99 | Some(class) => Arc::new(class), 100 | None => { 101 | return Err(class_name.to_owned()); 102 | } 103 | }; 104 | let superclass = if !class.get_super_class().is_empty() { 105 | Some(Self::load_class(class.get_super_class(), context)?.0) 106 | } else { 107 | None 108 | }; 109 | let mut interfaces: Vec> = vec![]; 110 | for interface in class.get_interfaces() { 111 | interfaces.push(Self::load_class(interface, context)?.0); 112 | } 113 | initialize_class(&class, context); 114 | let klass = Arc::new(Klass::new(class, ROOT_CLASSLOADER, superclass, interfaces)); 115 | class_arena!().classes.insert(class_name, klass.clone()); 116 | Ok((klass, false)) 117 | } 118 | } 119 | } 120 | } 121 | 122 | fn initialize_class(class: &Arc, context: &mut ThreadContext) { 123 | trace!("initializing class {}", class.get_name()); 124 | match class.get_method("", "()V") { 125 | Some(clinit) => { 126 | context.pc = 127 | context 128 | .stack 129 | .invoke(Arc::as_ptr(&class), Arc::as_ptr(&clinit), context.pc, 0); 130 | } 131 | None => {} 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/bytecode/attribute.rs: -------------------------------------------------------------------------------- 1 | use super::{atom::*, constant_pool::ConstantPool, Traveler}; 2 | use std::sync::Arc; 3 | 4 | pub type Attributes = Vec; 5 | 6 | pub struct ExceptionHandler { 7 | pub start_pc: U2, 8 | pub end_pc: U2, 9 | pub handler_pc: U2, 10 | pub catch_type: Option, 11 | } 12 | 13 | pub enum Attribute { 14 | ConstantValue(Arc>), 15 | Code( 16 | U2, 17 | U2, 18 | Arc>, 19 | Arc>, 20 | Arc, 21 | ), 22 | StackMapTable(Arc>), 23 | Exceptions(Arc>), 24 | BootstrapMethods(Arc>), 25 | // above for JVM 26 | InnerClasses(Vec), 27 | EnclosingMethod(Vec), 28 | Synthetic(Vec), 29 | Signature(Vec), 30 | RuntimeVisibleAnnotations(Vec), 31 | RuntimeInvisibleAnnotations(Vec), 32 | RuntimeVisibleParameterAnnotations(Vec), 33 | RuntimeInvisibleParameterAnnotations(Vec), 34 | RuntimeVisibleTypeAnnotations(Vec), 35 | RuntimeInvisibleTypeAnnotations(Vec), 36 | AnnotationDefault(Vec), 37 | MethodParameters(Vec), 38 | // above for Java SE 39 | } 40 | 41 | pub const CONSTANT_VALUE: &'static str = "ConstantValue"; 42 | pub const CODE: &'static str = "Code"; 43 | pub const STACK_MAP_TABLE: &'static str = "StackMapTable"; 44 | pub const EXCEPTIONS: &'static str = "Exceptions"; 45 | pub const BOOTSTRAP_METHODS: &'static str = "BootstrapMethods"; 46 | pub const INNER_CLASSES: &'static str = "InnerClasses"; 47 | pub const ENCLOSING_METHOD: &'static str = "EnclosingMethod"; 48 | pub const SYNTHETIC: &'static str = "Synthetic"; 49 | pub const SIGNATURE: &'static str = "Signature"; 50 | pub const RUNTIME_VISIBLE_ANNOTATIONS: &'static str = "RuntimeVisibleAnnotations"; 51 | pub const RUNTIME_INVISIBLE_ANNOTATIONS: &'static str = "RuntimeInvisibleAnnotations"; 52 | pub const RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS: &'static str = 53 | "RuntimeVisibleParameterAnnotations"; 54 | pub const RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS: &'static str = 55 | "RuntimeInvisibleParameterAnnotations"; 56 | pub const RUNTIME_VISIBLE_TYPE_ANNOTATIONS: &'static str = "RuntimeVisibleTypeAnnotations"; 57 | pub const RUNTIME_INVISIBLE_TYPE_ANNOTATIONS: &'static str = "RuntimeInvisibleTypeAnnotations"; 58 | pub const ANNOTATION_DEFAULT: &'static str = "AnnotationDefault"; 59 | pub const METHOD_PARAMETERS: &'static str = "MethodParameters"; 60 | 61 | impl Traveler for Attributes { 62 | fn read(seq: &mut I, constants: Option<&ConstantPool>) -> Attributes 63 | where 64 | I: Iterator, 65 | { 66 | let attribute_count = U2::read(seq, None) as usize; 67 | let mut attributes = Vec::::with_capacity(attribute_count); 68 | for _x in 0..attribute_count { 69 | attributes.push(Attribute::read(seq, constants)); 70 | } 71 | attributes 72 | } 73 | } 74 | 75 | impl Traveler for Attribute { 76 | fn read(seq: &mut I, constants: Option<&ConstantPool>) -> Attribute 77 | where 78 | I: Iterator, 79 | { 80 | let name_idx = U2::read(seq, None); 81 | let length = U4::read(seq, None) as usize; 82 | if let Some(pool) = constants { 83 | match pool.get_str(name_idx) { 84 | CODE => { 85 | let max_stacks = U2::read(seq, None); 86 | let max_locals = U2::read(seq, None); 87 | let code_length = U4::read(seq, None); 88 | let mut code = Vec::::with_capacity(code_length as usize); 89 | for _x in 0..code_length { 90 | code.push(U1::read(seq, None)); 91 | } 92 | let exception_handler_count = U2::read(seq, None); 93 | let mut exception_handlers = 94 | Vec::::with_capacity(exception_handler_count as usize); 95 | for _x in 0..exception_handler_count { 96 | let start_pc = U2::read(seq, None); 97 | let end_pc = U2::read(seq, None); 98 | let handler_pc = U2::read(seq, None); 99 | let catch_type_idx = U2::read(seq, Some(pool)); 100 | let catch_type = match catch_type_idx { 101 | 0 => None, 102 | _ => Some(pool.get_str(catch_type_idx).to_string()), 103 | }; 104 | exception_handlers.push(ExceptionHandler { 105 | start_pc: start_pc, 106 | end_pc: end_pc, 107 | handler_pc: handler_pc, 108 | catch_type: catch_type, 109 | }) 110 | } 111 | return Attribute::Code( 112 | max_stacks, 113 | max_locals, 114 | Arc::new(code), 115 | Arc::new(exception_handlers), 116 | Arc::new(Attributes::read(seq, Some(pool))), 117 | ); 118 | } 119 | _ => { 120 | let mut content = Vec::::with_capacity(length); 121 | for _x in 0..length { 122 | content.push(U1::read(seq, None)); 123 | } 124 | return Attribute::ConstantValue(Arc::new(content)); 125 | } 126 | } 127 | } 128 | panic!("need constant pool to resolve attributes"); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/bytecode/constant_pool.rs: -------------------------------------------------------------------------------- 1 | use super::{atom::*, Traveler}; 2 | use std::mem::transmute; 3 | 4 | #[derive(Debug)] 5 | pub struct ConstantPool(Vec); 6 | 7 | #[derive(Debug, Clone)] 8 | pub enum ConstantItem { 9 | UTF8(String), 10 | Integer(i32), 11 | Float(f32), 12 | Long(i64), 13 | Double(f64), 14 | Class(U2), 15 | String(U2), 16 | FieldRef(U2, U2), 17 | MethodRef(U2, U2), 18 | InterfaceMethodRef(U2, U2), 19 | NameAndType(U2, U2), 20 | MethodHandle(U1, U2), 21 | MethodType(U2), 22 | InvokeDynamic(U2, U2), 23 | NIL, 24 | PADDING, 25 | } 26 | 27 | impl ConstantPool { 28 | pub fn get(&self, idx: U2) -> &ConstantItem { 29 | match self.0.get(idx as usize) { 30 | None => panic!("Illegal runtime constant pool"), 31 | Some(item) => item, 32 | } 33 | } 34 | 35 | pub fn get_integer(&self, idx: U2) -> i32 { 36 | match self.get(idx) { 37 | ConstantItem::Integer(i) => *i, 38 | _ => panic!("invalid class file"), 39 | } 40 | } 41 | 42 | pub fn get_float(&self, idx: U2) -> f32 { 43 | match self.get(idx) { 44 | ConstantItem::Float(f) => *f, 45 | _ => panic!("invalid class file"), 46 | } 47 | } 48 | 49 | pub fn get_long(&self, idx: U2) -> i64 { 50 | match self.get(idx) { 51 | ConstantItem::Long(l) => *l, 52 | _ => panic!("invalid class file"), 53 | } 54 | } 55 | 56 | pub fn get_double(&self, idx: U2) -> f64 { 57 | match self.get(idx) { 58 | ConstantItem::Double(d) => *d, 59 | _ => panic!("invalid class file"), 60 | } 61 | } 62 | 63 | pub fn get_name_and_type(&self, idx: U2) -> (&str, &str) { 64 | match self.get(idx) { 65 | ConstantItem::NameAndType(n_idx, t_idx) => (self.get_str(*n_idx), self.get_str(*t_idx)), 66 | _ => panic!("invalid class file"), 67 | } 68 | } 69 | 70 | pub fn get_javaref(&self, idx: U2) -> (&str, (&str, &str)) { 71 | match self.get(idx) { 72 | ConstantItem::InterfaceMethodRef(c, nt) => (self.get_str(*c), self.get_name_and_type(*nt)), 73 | ConstantItem::MethodRef(c, nt) => (self.get_str(*c), self.get_name_and_type(*nt)), 74 | ConstantItem::FieldRef(c, f) => (self.get_str(*c), self.get_name_and_type(*f)), 75 | _ => panic!("invalid class file"), 76 | } 77 | } 78 | 79 | pub fn get_str(&self, idx: U2) -> &str { 80 | if idx == 0 { 81 | return ""; 82 | } 83 | if let Some(item) = self.0.get(idx as usize) { 84 | match item { 85 | &ConstantItem::String(offset) => { 86 | return self.get_str(offset); 87 | } 88 | &ConstantItem::UTF8(ref s) => { 89 | return s; 90 | } 91 | &ConstantItem::Class(offset) => { 92 | return self.get_str(offset); 93 | } 94 | _ => { 95 | panic!("invalid class file"); 96 | } 97 | } 98 | } 99 | panic!("invalid class file"); 100 | } 101 | } 102 | 103 | impl Traveler for ConstantPool { 104 | fn read(seq: &mut I, _constants: Option<&ConstantPool>) -> ConstantPool 105 | where 106 | I: Iterator, 107 | { 108 | let size = U2::read(seq, None); 109 | let mut pool = Vec::::with_capacity(size as usize); 110 | pool.push(ConstantItem::NIL); 111 | let mut offset = 1; 112 | while offset < size { 113 | let tag = U1::read(seq, None); 114 | let ele = match tag { 115 | INVOKEDYNAMIC_TAG => { 116 | let bootstrap_method_attr_idx = U2::read(seq, None); 117 | let name_and_type_idx = U2::read(seq, None); 118 | ConstantItem::InvokeDynamic(bootstrap_method_attr_idx, name_and_type_idx) 119 | } 120 | METHODTYPE_TAG => { 121 | let desc_idx = U2::read(seq, None); 122 | ConstantItem::MethodType(desc_idx) 123 | } 124 | METHODHANDLE_TAG => { 125 | let ref_type = U1::read(seq, None); 126 | let ref_idx = U2::read(seq, None); 127 | ConstantItem::MethodHandle(ref_type, ref_idx) 128 | } 129 | INTERFACEMETHODREF_TAG => { 130 | let class_idx = U2::read(seq, None); 131 | let name_and_type_idx = U2::read(seq, None); 132 | ConstantItem::InterfaceMethodRef(class_idx, name_and_type_idx) 133 | } 134 | STRING_TAG => { 135 | let string_idx = U2::read(seq, None); 136 | ConstantItem::String(string_idx) 137 | } 138 | CLASS_TAG => { 139 | let name_idx = U2::read(seq, None); 140 | ConstantItem::Class(name_idx) 141 | } 142 | METHODREF_TAG => { 143 | let class_idx = U2::read(seq, None); 144 | let name_and_type_idx = U2::read(seq, None); 145 | ConstantItem::MethodRef(class_idx, name_and_type_idx) 146 | } 147 | FIELDREF_TAG => { 148 | let class_idx = U2::read(seq, None); 149 | let name_and_type_idx = U2::read(seq, None); 150 | ConstantItem::FieldRef(class_idx, name_and_type_idx) 151 | } 152 | UTF8_TAG => { 153 | let length = U2::read(seq, None); 154 | let mut buf = Vec::::with_capacity(length as usize); 155 | for _x in 0..length { 156 | buf.push(U1::read(seq, None)); 157 | } 158 | // TODO MUTF-8 encode 159 | let s = std::str::from_utf8(&buf).unwrap(); 160 | ConstantItem::UTF8(s.to_string()) 161 | } 162 | INTEGER_TAG => { 163 | let v = U4::read(seq, None); 164 | let i: i32 = unsafe { transmute::(v) }; 165 | ConstantItem::Integer(i) 166 | } 167 | FLOAT_TAG => { 168 | let v = U4::read(seq, None); 169 | let i: f32 = unsafe { transmute::(v) }; 170 | ConstantItem::Float(i) 171 | } 172 | LONG_TAG => { 173 | let v = U8::read(seq, None); 174 | let i: i64 = unsafe { transmute::(v) }; 175 | offset = offset + 1; 176 | pool.push(ConstantItem::Long(i)); 177 | ConstantItem::PADDING 178 | } 179 | DOUBLE_TAG => { 180 | let v = U8::read(seq, None); 181 | let i: f64 = unsafe { transmute::(v) }; 182 | offset = offset + 1; 183 | pool.push(ConstantItem::Double(i)); 184 | ConstantItem::PADDING 185 | } 186 | NAMEANDTYPE_TAG => { 187 | let name_idx = U2::read(seq, None); 188 | let desc_idx = U2::read(seq, None); 189 | ConstantItem::NameAndType(name_idx, desc_idx) 190 | } 191 | _ => panic!("invalid classfile"), 192 | }; 193 | offset = offset + 1; 194 | pool.push(ele); 195 | } 196 | ConstantPool(pool) 197 | } 198 | } 199 | 200 | const UTF8_TAG: u8 = 1; 201 | const INTEGER_TAG: u8 = 3; 202 | const FLOAT_TAG: u8 = 4; 203 | const LONG_TAG: u8 = 5; 204 | const DOUBLE_TAG: u8 = 6; 205 | const CLASS_TAG: u8 = 7; 206 | const STRING_TAG: u8 = 8; 207 | const FIELDREF_TAG: u8 = 9; 208 | const METHODREF_TAG: u8 = 10; 209 | const INTERFACEMETHODREF_TAG: u8 = 11; 210 | const NAMEANDTYPE_TAG: u8 = 12; 211 | const METHODHANDLE_TAG: u8 = 15; 212 | const METHODTYPE_TAG: u8 = 16; 213 | const INVOKEDYNAMIC_TAG: u8 = 18; 214 | -------------------------------------------------------------------------------- /src/mem/heap.rs: -------------------------------------------------------------------------------- 1 | use crate::gc; 2 | use crate::jvm_heap; 3 | use crate::mem::{ 4 | klass::{Klass, ObjHeader, OBJ_HEADER_SIZE}, 5 | *, 6 | }; 7 | use std::sync::{Arc, RwLock}; 8 | 9 | pub struct Heap { 10 | _data: Vec, 11 | pub base: *mut u8, 12 | pub oldgen: Arc>, 13 | pub from: Arc>, 14 | pub to: Arc>, 15 | pub eden: Arc>, 16 | pub young_capacity: u32, 17 | pub eden_size: u32, 18 | pub survivor_size: u32, 19 | pub old_size: u32, 20 | } 21 | 22 | pub struct Region { 23 | pub offset: Ref, 24 | pub limit: Ref, 25 | } 26 | 27 | impl Region { 28 | fn new(start: Ref, limit: Ref) -> Region { 29 | Region { 30 | offset: start, 31 | limit: limit, 32 | } 33 | } 34 | } 35 | 36 | impl Heap { 37 | pub fn init(old_size: u32, survivor_size: u32, eden_size: u32) { 38 | let mut data = 39 | Vec::::with_capacity(PTR_SIZE + (old_size + eden_size + survivor_size) as usize); 40 | let ptr = data.as_mut_ptr(); 41 | let mut offset = PTR_SIZE as u32; 42 | let eden = Region::new(offset, eden_size); 43 | offset += eden_size; 44 | let from = Region::new(offset, survivor_size); 45 | offset += survivor_size; 46 | let to = Region::new(offset, survivor_size); 47 | offset += survivor_size; 48 | let oldgen = Region::new(offset, old_size); 49 | unsafe { 50 | HEAP.replace(Heap { 51 | _data: data, 52 | base: ptr, 53 | from: Arc::new(RwLock::new(from)), 54 | to: Arc::new(RwLock::new(to)), 55 | eden: Arc::new(RwLock::new(eden)), 56 | oldgen: Arc::new(RwLock::new(oldgen)), 57 | young_capacity: offset, 58 | eden_size: eden_size, 59 | survivor_size: survivor_size, 60 | old_size: old_size, 61 | }); 62 | } 63 | } 64 | 65 | pub fn is_young_object(addr: Ref) -> bool { 66 | addr < jvm_heap!().young_capacity 67 | } 68 | 69 | pub fn is_null(addr: Ref) -> bool { 70 | addr == 0 71 | } 72 | 73 | pub fn copy_object_to_region(obj_ref: *mut Ref, obj: &mut ObjHeader, region: &mut Region) { 74 | // let native_ptr = Heap::ptr(addr as usize); 75 | // let mut obj = ObjHeader::from_vm_raw(native_ptr); 76 | if obj.incr_gc_age() { 77 | // TODO copy to old generation 78 | } 79 | // array and instance 80 | let instance_len = match obj.is_instance() { 81 | true => unsafe { &*obj.klass }.len as usize, 82 | false => obj.size.unwrap() as usize * unsafe { &*obj.klass }.len, 83 | } + OBJ_HEADER_SIZE; 84 | let free = Heap::ptr(region.offset as usize); 85 | unsafe { free.copy_from(Heap::ptr(*obj_ref as usize), instance_len) }; 86 | let addr = region.offset; 87 | region.offset = addr + instance_len as u32; 88 | unsafe { obj_ref.write(addr) }; 89 | } 90 | 91 | pub fn swap_from_and_to() { 92 | let mut from = jvm_heap!().from.write().unwrap(); 93 | let mut to = jvm_heap!().to.write().unwrap(); 94 | let mut eden = jvm_heap!().eden.write().unwrap(); 95 | eden.offset = PTR_SIZE as u32; 96 | let offset = from.offset; 97 | from.offset = to.offset; 98 | to.offset = offset; 99 | } 100 | 101 | pub fn allocate_object(klass: &Arc) -> Ref { 102 | if let Some(addr) = Self::allocate_object_in_region(klass, &jvm_heap!().eden) { 103 | return addr; 104 | } else if let Some(addr) = Self::allocate_object_in_region(klass, &jvm_heap!().oldgen) { 105 | return addr; 106 | } 107 | panic!("OutOfMemoryError"); 108 | } 109 | 110 | pub fn allocate_object_directly(klass: &Arc) -> Ref { 111 | if let Some(addr) = Self::allocate_object_in_region(klass, &jvm_heap!().oldgen) { 112 | return addr; 113 | } 114 | panic!("OutOfMemoryError"); 115 | } 116 | 117 | fn allocate_object_in_region(klass: &Arc, region: &Arc>) -> Option { 118 | let mut region = region.write().unwrap(); 119 | let instance_len = OBJ_HEADER_SIZE + klass.len; 120 | if region.offset + instance_len as u32 >= region.limit { 121 | return None; 122 | } 123 | let obj_header = ObjHeader::new_instance(Arc::as_ptr(klass)); 124 | let obj_ptr = obj_header.into_vm_raw().as_ptr(); 125 | let free = Heap::ptr(region.offset as usize); 126 | unsafe { free.copy_from(obj_ptr, OBJ_HEADER_SIZE) }; 127 | let addr = region.offset; 128 | region.offset = addr + instance_len as u32; 129 | Some(addr) 130 | } 131 | 132 | fn allocate_array_in_region( 133 | klass: &Arc, 134 | region: &Arc>, 135 | size: u32, 136 | ) -> Option { 137 | let mut region = region.write().unwrap(); 138 | let array_len = OBJ_HEADER_SIZE + klass.ref_len * size as usize; 139 | if region.offset + array_len as u32 >= region.limit { 140 | return None; 141 | } 142 | let array_header = ObjHeader::new_array(Arc::as_ptr(klass), size); 143 | let array_ptr = array_header.into_vm_raw().as_ptr(); 144 | let free = Heap::ptr(region.offset as usize); 145 | unsafe { free.copy_from(array_ptr, OBJ_HEADER_SIZE) }; 146 | let addr = region.offset; 147 | region.offset = region.offset + array_len as u32; 148 | Some(addr) 149 | } 150 | 151 | pub fn allocate_array(klass: &Arc, size: u32) -> Option { 152 | let array_len = OBJ_HEADER_SIZE + klass.ref_len * size as usize; 153 | let mut eden = jvm_heap!().eden.write().unwrap(); 154 | // ensure enough space to allocate object 155 | if eden.offset + array_len as u32 >= eden.limit { 156 | return None; 157 | } 158 | let array_header = ObjHeader::new_array(Arc::as_ptr(klass), size); 159 | unsafe { 160 | let eden_ptr = jvm_heap!().base.add(eden.offset as usize); 161 | let array_header_ptr = array_header.into_vm_raw().as_ptr(); 162 | eden_ptr.copy_from(array_header_ptr, OBJ_HEADER_SIZE); 163 | let addr = eden.offset; 164 | eden.offset = eden.offset + array_len as u32; 165 | Some(addr) 166 | } 167 | } 168 | 169 | pub fn ptr(offset: usize) -> *mut u8 { 170 | unsafe { jvm_heap!().base.add(offset) } 171 | } 172 | 173 | pub fn as_obj(addr: Ref) -> ObjHeader { 174 | ObjHeader::from_vm_raw(Heap::ptr(addr as usize)) 175 | } 176 | } 177 | 178 | pub static mut HEAP: Option = None; 179 | 180 | #[macro_export] 181 | macro_rules! jvm_heap { 182 | () => { 183 | unsafe { 184 | match heap::HEAP { 185 | Some(ref heap) => heap, 186 | None => panic!("Heap not initialized"), 187 | } 188 | } 189 | }; 190 | } 191 | 192 | #[cfg(test)] 193 | mod test { 194 | 195 | use crate::mem::heap; 196 | use std::sync::Arc; 197 | 198 | #[test] 199 | pub fn test() { 200 | super::Heap::init(10 * 1024 * 1024, 1024 * 1024, 1024 * 1024); 201 | let java_lang_object = "yv66vgAAADQATgcAMQoAAQAyCgARADMKADQANQoAAQA2CAA3CgARADgKADkAOgoAAQA7BwA8CAA9CgAKAD4DAA9CPwgAPwoAEQBACgARAEEHAEIBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAPcmVnaXN0ZXJOYXRpdmVzAQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQAJU2lnbmF0dXJlAQAWKClMamF2YS9sYW5nL0NsYXNzPCo+OwEACGhhc2hDb2RlAQADKClJAQAGZXF1YWxzAQAVKExqYXZhL2xhbmcvT2JqZWN0OylaAQANU3RhY2tNYXBUYWJsZQEABWNsb25lAQAUKClMamF2YS9sYW5nL09iamVjdDsBAApFeGNlcHRpb25zBwBDAQAIdG9TdHJpbmcBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABm5vdGlmeQEACW5vdGlmeUFsbAEABHdhaXQBAAQoSilWBwBEAQAFKEpJKVYBAAhmaW5hbGl6ZQcARQEACDxjbGluaXQ+AQAKU291cmNlRmlsZQEAC09iamVjdC5qYXZhAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIMABIAEwwAFwAYBwBGDABHACUMAEgASQEAAUAMABsAHAcASgwASwBMDAAkACUBACJqYXZhL2xhbmcvSWxsZWdhbEFyZ3VtZW50RXhjZXB0aW9uAQAZdGltZW91dCB2YWx1ZSBpcyBuZWdhdGl2ZQwAEgBNAQAlbmFub3NlY29uZCB0aW1lb3V0IHZhbHVlIG91dCBvZiByYW5nZQwAKAApDAAWABMBABBqYXZhL2xhbmcvT2JqZWN0AQAkamF2YS9sYW5nL0Nsb25lTm90U3VwcG9ydGVkRXhjZXB0aW9uAQAeamF2YS9sYW5nL0ludGVycnVwdGVkRXhjZXB0aW9uAQATamF2YS9sYW5nL1Rocm93YWJsZQEAD2phdmEvbGFuZy9DbGFzcwEAB2dldE5hbWUBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBABFqYXZhL2xhbmcvSW50ZWdlcgEAC3RvSGV4U3RyaW5nAQAVKEkpTGphdmEvbGFuZy9TdHJpbmc7AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEAEQAAAAAAAAAOAAEAEgATAAEAFAAAABkAAAABAAAAAbEAAAABABUAAAAGAAEAAAAlAQoAFgATAAABEQAXABgAAQAZAAAAAgAaAQEAGwAcAAAAAQAdAB4AAQAUAAAALgACAAIAAAALKiumAAcEpwAEA6wAAAACABUAAAAGAAEAAACVAB8AAAAFAAIJQAEBBAAgACEAAQAiAAAABAABACMAAQAkACUAAQAUAAAAPAACAAEAAAAkuwABWbcAAiq2AAO2AAS2AAUSBrYABSq2AAe4AAi2AAW2AAmwAAAAAQAVAAAABgABAAAA7AERACYAEwAAAREAJwATAAABEQAoACkAAQAiAAAABAABACoAEQAoACsAAgAUAAAAcgAEAAQAAAAyHwmUnAANuwAKWRILtwAMvx2bAAkdEg2kAA27AApZEg63AAy/HZ4ABx8KYUAqH7YAD7EAAAACABUAAAAiAAgAAAG/AAYBwAAQAcMAGgHEACQByAAoAckALAHMADEBzQAfAAAABgAEEAkJBwAiAAAABAABACoAEQAoABMAAgAUAAAAIgADAAEAAAAGKgm2AA+xAAAAAQAVAAAACgACAAAB9gAFAfcAIgAAAAQAAQAqAAQALAATAAIAFAAAABkAAAABAAAAAbEAAAABABUAAAAGAAEAAAIrACIAAAAEAAEALQAIAC4AEwABABQAAAAgAAAAAAAAAAS4ABCxAAAAAQAVAAAACgACAAAAKQADACoAAQAvAAAAAgAw"; 202 | let class_vec = base64::decode(java_lang_object).unwrap(); 203 | let bytecode = super::Class::from_vec(class_vec); 204 | let klass = super::Klass::new( 205 | Arc::new(bytecode), 206 | super::metaspace::ROOT_CLASSLOADER, 207 | None, 208 | vec![], 209 | ); 210 | let klass = super::Arc::new(klass); 211 | let obj0 = super::Heap::allocate_object(&klass); 212 | assert_eq!(super::PTR_SIZE as u32, obj0); 213 | let obj1 = super::Heap::allocate_object(&klass); 214 | assert_eq!( 215 | super::OBJ_HEADER_SIZE + klass.len + obj0 as usize, 216 | obj1 as usize 217 | ); 218 | 219 | let obj0_ptr = unsafe { jvm_heap!().base.add(obj0 as usize) }; 220 | let obj_header: super::ObjHeader = super::klass::ObjHeader::from_vm_raw(obj0_ptr); 221 | let java_lang_object_klass = unsafe { &*obj_header.klass }; 222 | assert_eq!("java/lang/Object", java_lang_object_klass.name); 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /src/mem/stack.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | bytecode, 3 | bytecode::{class::Class, method::Method}, 4 | mem::{klass::*, *}, 5 | }; 6 | 7 | const DEFAULT_STACK_LEN: usize = 128 * 1024; 8 | 9 | pub struct JavaStack { 10 | data: Vec, 11 | frames: Vec, 12 | max_stack_size: usize, 13 | } 14 | 15 | pub struct JavaFrame { 16 | locals: *mut u8, 17 | operands: *mut u8, 18 | class: *const Class, 19 | method: *const Method, 20 | pc: usize, 21 | max_locals: usize, 22 | active_refs: Vec<*mut Ref>, 23 | } 24 | 25 | impl JavaStack { 26 | pub fn new() -> Self { 27 | Self { 28 | data: vec![0u8; DEFAULT_STACK_LEN], 29 | frames: Vec::::with_capacity(256), 30 | max_stack_size: DEFAULT_STACK_LEN, 31 | } 32 | } 33 | 34 | pub fn frame(&self) -> &JavaFrame { 35 | self.frames.last().expect("empty_stack") 36 | } 37 | 38 | pub fn mut_frame(&mut self) -> &mut JavaFrame { 39 | self.frames.last_mut().expect("empty_stack") 40 | } 41 | 42 | pub fn operands(&self) -> *mut u8 { 43 | self.frame().operands 44 | } 45 | 46 | pub fn locals(&self) -> *mut u8 { 47 | self.frame().locals 48 | } 49 | 50 | pub fn update(&mut self, operands: *mut u8) { 51 | self.mut_frame().operands = operands; 52 | } 53 | 54 | pub fn upward(&mut self, n: usize) { 55 | unsafe { 56 | self.update(self.operands().add(n * PTR_SIZE)); 57 | } 58 | } 59 | 60 | pub fn downward(&mut self, n: usize) { 61 | unsafe { 62 | self.update(self.operands().sub(n * PTR_SIZE)); 63 | } 64 | } 65 | 66 | pub fn has_next(&self, pc: usize) -> bool { 67 | match self.frames.last() { 68 | None => false, 69 | Some(ref f) => { 70 | pc < unsafe { &*f.method } 71 | .get_code() 72 | .expect("null_code_attribute") 73 | .2 74 | .len() 75 | } 76 | } 77 | } 78 | 79 | pub fn method(&self) -> &Method { 80 | unsafe { &*self.frame().method } 81 | } 82 | 83 | pub fn class(&self) -> &Class { 84 | unsafe { &*self.frame().class } 85 | } 86 | 87 | pub fn method_ptr(&self) -> *const Method { 88 | self.frame().method 89 | } 90 | 91 | pub fn class_ptr(&self) -> *const Class { 92 | self.frame().class 93 | } 94 | 95 | pub fn is_empty(&self) -> bool { 96 | self.frames.is_empty() 97 | } 98 | 99 | pub fn append_ref_to_roots(&mut self, ref_ptr: *mut Ref) { 100 | self.mut_frame().active_refs.push(ref_ptr); 101 | } 102 | 103 | pub fn collect_tracing_roots(&self) -> Vec<*mut Ref> { 104 | self.frames 105 | .iter() 106 | .flat_map(|f| f.active_refs.iter()) 107 | .map(|p| *p) 108 | .collect::>() 109 | } 110 | 111 | pub fn invoke( 112 | &mut self, 113 | class: *const Class, 114 | method: *const Method, 115 | pc: usize, 116 | locals: usize, 117 | ) -> usize { 118 | let m = unsafe { &*method }; 119 | let (_, desc, access_flag) = m.get_name_and_descriptor(); 120 | let (params, slots, ret) = bytecode::resolve_method_descriptor(desc, access_flag); 121 | // -------- drop this after implements native method ----------- 122 | if m.is_native() { 123 | let ret: usize = match ret.as_ref() { 124 | "D" | "J" => 2, 125 | "V" => 0, 126 | _ => 1, 127 | }; 128 | self.downward(slots - ret); 129 | return pc; 130 | } 131 | // ------------------------------------------------------------- 132 | let locals = unsafe { 133 | if self.is_empty() { 134 | self.data.as_mut_ptr().add(locals * PTR_SIZE) 135 | } else { 136 | self.operands().sub(locals * PTR_SIZE) 137 | } 138 | }; 139 | let mut active_refs = Vec::new(); 140 | let mut index = 0usize; 141 | for p in params { 142 | if p.starts_with("L") || p.starts_with("[") { 143 | let reference = unsafe { locals.add(index * PTR_SIZE).cast::() }; 144 | if unsafe { *reference != 0 } { 145 | active_refs.push(reference); 146 | } 147 | } 148 | if p == "D" || p == "J" { 149 | index += 2; 150 | } else { 151 | index += 1; 152 | } 153 | } 154 | let method_ref = unsafe { &*method }; 155 | match method_ref.get_code() { 156 | None => panic!("AbstractMethod"), 157 | Some((_, max_locals, _, _, _)) => self.frames.push(JavaFrame { 158 | locals: locals, 159 | operands: unsafe { locals.add(max_locals as usize * PTR_SIZE) }, 160 | class: class, 161 | method: method, 162 | pc: pc, 163 | max_locals: max_locals as usize, 164 | active_refs: active_refs, 165 | }), 166 | } 167 | 0 168 | } 169 | 170 | pub fn return_normal(&mut self) -> usize { 171 | let frame = self.frames.pop().expect("empty_stack"); 172 | if !self.is_empty() { 173 | let (_, descriptor, access_flag) = &self.method().get_name_and_descriptor(); 174 | let (_, _, ret) = bytecode::resolve_method_descriptor(descriptor, *access_flag); 175 | let slots: usize = match ret.as_ref() { 176 | "D" | "J" => 2, 177 | "V" => 0, 178 | _ => 1, 179 | }; 180 | unsafe { 181 | let val = frame.operands.sub(slots * PTR_SIZE); 182 | self.operands().copy_from(val, slots * PTR_SIZE); 183 | self.update(self.operands().add(slots * PTR_SIZE)); 184 | } 185 | } 186 | frame.pc 187 | } 188 | 189 | pub fn fire_exception(&mut self) -> usize { 190 | let frame = self.frames.pop().expect("empty_stack"); 191 | if !self.is_empty() { 192 | unsafe { 193 | let error = frame.operands.sub(PTR_SIZE); 194 | self.operands().copy_from(error, PTR_SIZE); 195 | self.update(self.operands().add(PTR_SIZE)); 196 | } 197 | } 198 | frame.pc 199 | } 200 | 201 | pub fn match_exception_table(&self, pc: usize, klass: &Klass) -> Option { 202 | let exception_table = self.method().get_code().unwrap().3; 203 | for handler in exception_table.as_slice() { 204 | if pc >= handler.start_pc as usize && pc < handler.end_pc as usize { 205 | match &handler.catch_type { 206 | Some(exception_type) => { 207 | if klass.is_superclass(&exception_type) { 208 | return Some(handler.handler_pc as usize); 209 | } 210 | } 211 | None => return Some(handler.handler_pc as usize), 212 | } 213 | } 214 | } 215 | None 216 | } 217 | 218 | pub fn code_at(&self, pc: usize) -> u8 { 219 | self.method().get_code().unwrap().2[pc] 220 | } 221 | 222 | pub fn load(&mut self, offset: usize, count: usize) { 223 | unsafe { 224 | self.operands() 225 | .copy_from(self.locals().add(offset * PTR_SIZE), count * PTR_SIZE); 226 | self.update(self.operands().add(count * PTR_SIZE)); 227 | } 228 | } 229 | 230 | pub fn store(&mut self, offset: usize, count: usize) { 231 | unsafe { 232 | self.update(self.operands().sub(count * PTR_SIZE)); 233 | self.locals() 234 | .add(offset * PTR_SIZE) 235 | .copy_from(self.operands(), count * PTR_SIZE); 236 | } 237 | } 238 | 239 | pub fn get(&self, offset: usize) -> Slot { 240 | unsafe { *self.locals().add(offset * PTR_SIZE).cast::() } 241 | } 242 | 243 | pub fn get_w(&self, offset: usize) -> WideSlot { 244 | unsafe { *self.locals().add(offset * PTR_SIZE).cast::() } 245 | } 246 | 247 | pub fn set(&self, offset: usize, v: &Slot) { 248 | unsafe { 249 | self.locals() 250 | .add(offset * PTR_SIZE) 251 | .copy_from(v.as_ptr(), PTR_SIZE); 252 | } 253 | } 254 | 255 | pub fn set_w(&self, offset: usize, v: &WideSlot) { 256 | unsafe { 257 | self.locals() 258 | .add(offset * PTR_SIZE) 259 | .copy_from(v.as_ptr(), PTR_SIZE * 2); 260 | } 261 | } 262 | 263 | pub fn push(&mut self, v: &Slot) { 264 | unsafe { 265 | self.operands().copy_from(v.as_ptr(), PTR_SIZE); 266 | self.update(self.operands().add(PTR_SIZE)); 267 | } 268 | } 269 | 270 | pub fn push_w(&mut self, v: &WideSlot) { 271 | unsafe { 272 | self.operands().copy_from(v.as_ptr(), PTR_SIZE * 2); 273 | self.update(self.operands().add(PTR_SIZE * 2)); 274 | } 275 | } 276 | 277 | pub fn pop(&mut self) -> Slot { 278 | unsafe { 279 | self.update(self.operands().sub(PTR_SIZE)); 280 | *self.operands().cast::() 281 | } 282 | } 283 | 284 | pub fn pop_w(&mut self) -> WideSlot { 285 | unsafe { 286 | self.update(self.operands().sub(PTR_SIZE * 2)); 287 | *self.operands().cast::() 288 | } 289 | } 290 | 291 | pub fn bi_op(&mut self, f: F) 292 | where 293 | F: Fn(Slot, Slot) -> Slot, 294 | { 295 | let left = self.pop(); 296 | let right = self.pop(); 297 | self.push(&f(left, right)); 298 | } 299 | 300 | pub fn bi_op_w(&mut self, f: F) 301 | where 302 | F: Fn(WideSlot, WideSlot) -> WideSlot, 303 | { 304 | let left = self.pop_w(); 305 | let right = self.pop_w(); 306 | self.push_w(&f(left, right)); 307 | } 308 | 309 | pub fn un_op(&mut self, f: F) 310 | where 311 | F: Fn(Slot) -> Slot, 312 | { 313 | let opr = self.pop(); 314 | self.push(&f(opr)); 315 | } 316 | 317 | pub fn un_op_w(&mut self, f: F) 318 | where 319 | F: Fn(WideSlot) -> WideSlot, 320 | { 321 | let opr = self.pop_w(); 322 | self.push_w(&f(opr)); 323 | } 324 | 325 | pub fn top(&self) -> &Slot { 326 | unsafe { &*self.operands().sub(PTR_SIZE).cast::() } 327 | } 328 | 329 | pub fn top_w(&self) -> &WideSlot { 330 | unsafe { &*self.operands().sub(2 * PTR_SIZE).cast::() } 331 | } 332 | 333 | pub fn top_n(&self, n: usize) -> &Slot { 334 | unsafe { &*self.operands().sub(PTR_SIZE * n).cast::() } 335 | } 336 | 337 | pub fn dump(&self, pc: usize) { 338 | let (name, descriptor, _) = self.method().get_name_and_descriptor(); 339 | println!("method layer: {}", self.frames.len() - 1); 340 | println!("current class: {:?}", self.class().get_name()); 341 | println!("current method: {:?} {:?}", name, descriptor); 342 | let locals_offset = self.locals() as usize - self.data.as_ptr() as usize; 343 | println!( 344 | "locals: {:02x?}", 345 | &self.data[locals_offset..locals_offset + self.frame().max_locals * PTR_SIZE] 346 | ); 347 | let operands_offset = self.operands() as usize - self.data.as_ptr() as usize; 348 | println!( 349 | "operands: {:02x?}", 350 | &self.data[locals_offset + self.frame().max_locals * PTR_SIZE..operands_offset] 351 | ); 352 | println!("pc: {:?}", pc); 353 | println!("[pc]: {:02x?}", self.code_at(pc)); 354 | println!("code: {:02x?}", self.method().get_code().unwrap().2); 355 | println!(); 356 | } 357 | } 358 | 359 | fn is_subclass(klass: &Klass, target: &str) -> bool { 360 | let mut thisclass = klass; 361 | loop { 362 | if &thisclass.name == target { 363 | return true; 364 | } 365 | if thisclass.superclass.is_none() { 366 | break; 367 | } 368 | thisclass = thisclass.superclass.as_ref().unwrap(); 369 | } 370 | false 371 | } 372 | -------------------------------------------------------------------------------- /src/mem/klass.rs: -------------------------------------------------------------------------------- 1 | use super::RefKey; 2 | use crate::bytecode::{class::Class, method::Method}; 3 | use crate::mem::{metaspace::*, Ref, PTR_SIZE}; 4 | use std::collections::HashMap; 5 | use std::mem::{size_of, transmute}; 6 | use std::sync::{atomic::AtomicBool, Arc, Mutex}; 7 | 8 | pub type MethodRef = (*const Class, *const Method); 9 | 10 | pub struct Klass { 11 | pub bytecode: Option>, 12 | pub name: String, 13 | pub classloader: Ref, 14 | pub vtable: HashMap, 15 | pub itable: HashMap, 16 | pub layout: HashMap, 17 | pub len: usize, 18 | pub ref_len: usize, 19 | pub superclass: Option>, 20 | pub superinterfaces: Vec>, 21 | pub initialized: AtomicBool, 22 | pub mutex: Mutex, 23 | } 24 | 25 | #[derive(Clone)] 26 | pub struct ObjHeader { 27 | pub mark: u32, 28 | pub size: Option, 29 | pub klass: *const Klass, 30 | } 31 | 32 | pub const OBJ_HEADER_SIZE: usize = size_of::(); 33 | 34 | pub const OBJ_HEADER_PADDING: usize = OBJ_HEADER_SIZE % PTR_SIZE; 35 | 36 | pub type ObjHeaderRaw = [u8; OBJ_HEADER_SIZE]; 37 | 38 | const LOCK_STATE_MASK: u32 = 0x07; 39 | 40 | const GC_STATE_MASK: u32 = 0x03; 41 | 42 | const LOCK_FREE_FLAG: u32 = 0x01; 43 | 44 | const GC_AGE_MASK: u32 = 0x78; 45 | 46 | impl ObjHeader { 47 | 48 | pub fn is_lock_free(&self) -> bool { 49 | self.mark & LOCK_STATE_MASK == LOCK_FREE_FLAG 50 | } 51 | 52 | pub fn is_gc_status(&self) -> bool { 53 | self.mark & GC_STATE_MASK == GC_STATE_MASK 54 | } 55 | 56 | pub fn set_gc(&mut self) { 57 | self.mark &= GC_STATE_MASK; 58 | } 59 | 60 | pub fn get_gc_age(&self) -> u32 { 61 | (self.mark & GC_AGE_MASK) >> 3 62 | } 63 | 64 | pub fn is_instance(&self) -> bool { 65 | self.size.is_none() 66 | } 67 | 68 | pub fn incr_gc_age(&mut self) -> bool { 69 | if self.mark & GC_AGE_MASK == GC_AGE_MASK { 70 | return true; 71 | } 72 | self.mark += 0x08; 73 | return false; 74 | } 75 | 76 | pub fn new_instance(klass: *const Klass) -> Self { 77 | Self { 78 | mark: 0, 79 | size: None, 80 | klass: klass, 81 | } 82 | } 83 | 84 | pub fn new_array(klass: *const Klass, size: u32) -> Self { 85 | Self { 86 | mark: 0, 87 | size: Some(size), 88 | klass: klass, 89 | } 90 | } 91 | 92 | pub fn into_vm_raw(self) -> ObjHeaderRaw { 93 | unsafe { transmute::(self) } 94 | } 95 | 96 | pub fn from_vm_raw(ptr: *const u8) -> Self { 97 | let mut obj_header_raw = [0u8; OBJ_HEADER_SIZE]; 98 | let obj_header_ptr = obj_header_raw.as_mut_ptr(); 99 | unsafe { 100 | obj_header_ptr.copy_from(ptr, OBJ_HEADER_SIZE); 101 | transmute::(obj_header_raw) 102 | } 103 | } 104 | } 105 | 106 | impl Klass { 107 | pub fn new( 108 | bytecode: Arc, 109 | classloader: Ref, 110 | superclass: Option>, 111 | interfaces: Vec>, 112 | ) -> Self { 113 | let name = bytecode.get_name().to_owned(); 114 | let mut klass = Klass { 115 | bytecode: Some(bytecode), 116 | name: name, 117 | classloader: classloader, 118 | vtable: HashMap::new(), 119 | itable: HashMap::new(), 120 | layout: HashMap::new(), 121 | len: 0, 122 | ref_len: PTR_SIZE, 123 | superclass: superclass, 124 | superinterfaces: interfaces, 125 | initialized: AtomicBool::new(false), 126 | mutex: Mutex::::new(0), 127 | }; 128 | &klass.build_vtable(); 129 | &klass.build_itable(); 130 | &klass.build_layout(); 131 | klass 132 | } 133 | 134 | pub fn new_phantom_klass(name: &str) -> Self { 135 | Klass { 136 | bytecode: None, 137 | name: name.to_owned(), 138 | classloader: ROOT_CLASSLOADER, 139 | vtable: HashMap::new(), 140 | itable: HashMap::new(), 141 | layout: HashMap::new(), 142 | len: match name { 143 | "I" | "F" | "Z" | "B" | "S" | "C" => PTR_SIZE, 144 | "D" | "J" => 2 * PTR_SIZE, 145 | _ => PTR_SIZE, 146 | }, 147 | ref_len: match name { 148 | "I" | "F" | "Z" | "B" | "S" | "C" => PTR_SIZE, 149 | "D" | "J" => 2 * PTR_SIZE, 150 | _ => PTR_SIZE, 151 | }, 152 | superclass: None, 153 | superinterfaces: vec![], 154 | initialized: AtomicBool::new(true), 155 | mutex: Mutex::::new(0), 156 | } 157 | } 158 | 159 | pub fn is_superclass(&self, target: &str) -> bool { 160 | let mut thisclass = self; 161 | loop { 162 | if &thisclass.name == target { 163 | return true; 164 | } 165 | if thisclass.superclass.is_none() { 166 | break; 167 | } 168 | thisclass = thisclass.superclass.as_ref().unwrap(); 169 | } 170 | false 171 | } 172 | 173 | pub fn get_method_in_vtable(&self, name: &str, desc: &str) -> Option<&MethodRef> { 174 | self.vtable.get(&("", name, desc)) 175 | } 176 | 177 | pub fn get_method_in_itable(&self, ifs: &str, name: &str, desc: &str) -> Option<&MethodRef> { 178 | self.itable.get(&(ifs, name, desc)) 179 | } 180 | 181 | pub fn get_holding_refs(&self, obj: Ref) -> Vec<*mut Ref> { 182 | self.layout.iter() 183 | .filter(|(k, _)| (&k.key.2).starts_with("L") || (&k.key.2).starts_with("[")) 184 | .map(|(_, v)| v.0 as u32 + obj) 185 | .map(|mut r| &mut r as *mut u32) 186 | .collect::<_>() 187 | } 188 | 189 | fn build_vtable(&mut self) { 190 | match &self.superclass { 191 | Some(klass) => { 192 | for (k, v) in &klass.vtable { 193 | self.vtable.insert(k.clone(), v.clone()); 194 | } 195 | } 196 | None => {} 197 | } 198 | for m in &self.bytecode.as_ref().unwrap().methods { 199 | if (m.is_public() || m.is_protected()) 200 | && !m.is_final() 201 | && !m.is_static() 202 | && m.name != "" 203 | { 204 | self.vtable.insert( 205 | RefKey::new("".to_string(), m.name.clone(), m.descriptor.clone()), 206 | ( 207 | Arc::as_ptr(&self.bytecode.as_ref().unwrap()), 208 | Arc::as_ptr(m), 209 | ), 210 | ); 211 | } 212 | } 213 | } 214 | 215 | fn build_itable(&mut self) { 216 | match &self.superclass { 217 | Some(klass) => { 218 | for (k, v) in &klass.itable { 219 | self.itable.insert(k.clone(), v.clone()); 220 | } 221 | } 222 | None => {} 223 | } 224 | let current = &*self.bytecode.as_ref().unwrap(); 225 | for ifs in &self.superinterfaces { 226 | for m in ¤t.methods { 227 | if let Some(implement) = current.get_method(&m.name, &m.descriptor) { 228 | self.itable.insert( 229 | RefKey::new(ifs.name.clone(), m.name.clone(), m.descriptor.clone()), 230 | ( 231 | Arc::as_ptr(&self.bytecode.as_ref().unwrap()), 232 | Arc::as_ptr(&implement), 233 | ), 234 | ); 235 | } 236 | } 237 | } 238 | } 239 | 240 | fn build_layout(&mut self) { 241 | let (len, size) = match &self.superclass { 242 | Some(klass) => { 243 | let mut max = 0usize; 244 | for (k, v) in &klass.layout { 245 | self.layout.insert(k.clone(), (v.0, v.1)); 246 | max = std::cmp::max(max, v.0 + v.1); 247 | } 248 | (klass.len, max) 249 | } 250 | None => (0, 0), 251 | }; 252 | let mut len = std::cmp::min(len, size); 253 | let current = &*self.bytecode.as_ref().unwrap(); 254 | for f in ¤t.fields { 255 | self.layout.insert( 256 | RefKey::new( 257 | current.get_name().to_string(), 258 | f.name.clone(), 259 | f.descriptor.clone(), 260 | ), 261 | (len, f.memory_size()), 262 | ); 263 | len = len + f.memory_size(); 264 | } 265 | self.len = len; 266 | } 267 | } 268 | 269 | #[cfg(test)] 270 | pub mod test { 271 | 272 | use crate::bytecode::class::Class; 273 | use std::sync::Arc; 274 | 275 | const JAVA_LANG_OBJECT: &'static str = "yv66vgAAADQATgcAMQoAAQAyCgARADMKADQANQoAAQA2CAA3CgARADgKADkAOgoAAQA7BwA8CAA9CgAKAD4DAA9CPwgAPwoAEQBACgARAEEHAEIBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAPcmVnaXN0ZXJOYXRpdmVzAQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQAJU2lnbmF0dXJlAQAWKClMamF2YS9sYW5nL0NsYXNzPCo+OwEACGhhc2hDb2RlAQADKClJAQAGZXF1YWxzAQAVKExqYXZhL2xhbmcvT2JqZWN0OylaAQANU3RhY2tNYXBUYWJsZQEABWNsb25lAQAUKClMamF2YS9sYW5nL09iamVjdDsBAApFeGNlcHRpb25zBwBDAQAIdG9TdHJpbmcBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABm5vdGlmeQEACW5vdGlmeUFsbAEABHdhaXQBAAQoSilWBwBEAQAFKEpJKVYBAAhmaW5hbGl6ZQcARQEACDxjbGluaXQ+AQAKU291cmNlRmlsZQEAC09iamVjdC5qYXZhAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIMABIAEwwAFwAYBwBGDABHACUMAEgASQEAAUAMABsAHAcASgwASwBMDAAkACUBACJqYXZhL2xhbmcvSWxsZWdhbEFyZ3VtZW50RXhjZXB0aW9uAQAZdGltZW91dCB2YWx1ZSBpcyBuZWdhdGl2ZQwAEgBNAQAlbmFub3NlY29uZCB0aW1lb3V0IHZhbHVlIG91dCBvZiByYW5nZQwAKAApDAAWABMBABBqYXZhL2xhbmcvT2JqZWN0AQAkamF2YS9sYW5nL0Nsb25lTm90U3VwcG9ydGVkRXhjZXB0aW9uAQAeamF2YS9sYW5nL0ludGVycnVwdGVkRXhjZXB0aW9uAQATamF2YS9sYW5nL1Rocm93YWJsZQEAD2phdmEvbGFuZy9DbGFzcwEAB2dldE5hbWUBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBABFqYXZhL2xhbmcvSW50ZWdlcgEAC3RvSGV4U3RyaW5nAQAVKEkpTGphdmEvbGFuZy9TdHJpbmc7AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEAEQAAAAAAAAAOAAEAEgATAAEAFAAAABkAAAABAAAAAbEAAAABABUAAAAGAAEAAAAlAQoAFgATAAABEQAXABgAAQAZAAAAAgAaAQEAGwAcAAAAAQAdAB4AAQAUAAAALgACAAIAAAALKiumAAcEpwAEA6wAAAACABUAAAAGAAEAAACVAB8AAAAFAAIJQAEBBAAgACEAAQAiAAAABAABACMAAQAkACUAAQAUAAAAPAACAAEAAAAkuwABWbcAAiq2AAO2AAS2AAUSBrYABSq2AAe4AAi2AAW2AAmwAAAAAQAVAAAABgABAAAA7AERACYAEwAAAREAJwATAAABEQAoACkAAQAiAAAABAABACoAEQAoACsAAgAUAAAAcgAEAAQAAAAyHwmUnAANuwAKWRILtwAMvx2bAAkdEg2kAA27AApZEg63AAy/HZ4ABx8KYUAqH7YAD7EAAAACABUAAAAiAAgAAAG/AAYBwAAQAcMAGgHEACQByAAoAckALAHMADEBzQAfAAAABgAEEAkJBwAiAAAABAABACoAEQAoABMAAgAUAAAAIgADAAEAAAAGKgm2AA+xAAAAAQAVAAAACgACAAAB9gAFAfcAIgAAAAQAAQAqAAQALAATAAIAFAAAABkAAAABAAAAAbEAAAABABUAAAAGAAEAAAIrACIAAAAEAAEALQAIAC4AEwABABQAAAAgAAAAAAAAAAS4ABCxAAAAAQAVAAAACgACAAAAKQADACoAAQAvAAAAAgAw"; 276 | 277 | const DEFAULT_SIMPLE: &'static str = "yv66vgAAADQAEAoAAwANBwAOBwAPAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABHRlc3QBAAgoSUpGRFopVgEADVN0YWNrTWFwVGFibGUBAApTb3VyY2VGaWxlAQALU2ltcGxlLmphdmEMAAQABQEABlNpbXBsZQEAEGphdmEvbGFuZy9PYmplY3QAIQACAAMAAAAAAAIAAQAEAAUAAQAGAAAAHQABAAEAAAAFKrcAAbEAAAABAAcAAAAGAAEAAAABAAkACAAJAAEABgAAAFUABAANAAAAGxoEYDYHHwplNwglDGo4ChUGmQAJGAQPbzkLsQAAAAIABwAAABoABgAAAAQABQAFAAoABgAPAAcAFAAIABoACgAKAAAACAAB/gAaAQQCAAEACwAAAAIADA=="; 278 | 279 | const DEFAULT_TEST: &'static str = "yv66vgAAADQAGQoABAAVCAAWBwAXBwAYAQABaQEAAUkBAAFiAQABWgEAAWwBAAFKAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAR0ZXN0AQAEKEkpVgEAClNvdXJjZUZpbGUBAA9UZXN0VlRhYmxlLmphdmEMAAsADAEAAAEAClRlc3RWVGFibGUBABBqYXZhL2xhbmcvT2JqZWN0ACEAAwAEAAAAAwAAAAUABgAAAAAABwAIAAAAAAAJAAoAAAADAAEACwAMAAEADQAAAB0AAQABAAAABSq3AAGxAAAAAQAOAAAABgABAAAAAgABAA8AEAABAA0AAAAbAAEAAQAAAAMSArAAAAABAA4AAAAGAAEAAAALAAEAEQASAAEADQAAABkAAAACAAAAAbEAAAABAA4AAAAGAAEAAAAQAAEAEwAAAAIAFA=="; 280 | 281 | const DEFAULT_EXTENDS_TEST: &'static str = "yv66vgAAADQAFwoAAwAUBwAVBwAWAQABYQEAAUkBAAFiAQABWgEAAWMBAAFKAQABcwEAAVMBAANzdHIBABJMamF2YS9sYW5nL1N0cmluZzsBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKU291cmNlRmlsZQEAFUV4dGVuZFRlc3RWVGFibGUuamF2YQwADgAPAQAQRXh0ZW5kVGVzdFZUYWJsZQEAClRlc3RWVGFibGUAIQACAAMAAAAFAAAABAAFAAAAAAAGAAcAAAAAAAgACQAAAAAACgALAAAAAAAMAA0AAAABAAEADgAPAAEAEAAAAB0AAQABAAAABSq3AAGxAAAAAQARAAAABgABAAAAAQABABIAAAACABM="; 282 | 283 | fn parse_class(bytecode: &str) -> Class { 284 | let class_vec = base64::decode(bytecode).unwrap(); 285 | Class::from_vec(class_vec) 286 | } 287 | 288 | #[test] 289 | pub fn test_vtable() { 290 | let bytecode = parse_class(JAVA_LANG_OBJECT); 291 | let java_lang_object_klass = super::Klass::new( 292 | Arc::new(bytecode), 293 | crate::mem::metaspace::ROOT_CLASSLOADER, 294 | None, 295 | vec![], 296 | ); 297 | let java_lang_object_klass = Arc::new(java_lang_object_klass); 298 | assert_eq!(5, java_lang_object_klass.vtable.len()); 299 | let bytecode = parse_class(DEFAULT_SIMPLE); 300 | let default_simple_klass = super::Klass::new( 301 | Arc::new(bytecode), 302 | crate::mem::metaspace::ROOT_CLASSLOADER, 303 | Some(java_lang_object_klass.clone()), 304 | vec![], 305 | ); 306 | assert_eq!(5, default_simple_klass.vtable.len()); 307 | let to_string_method0 = java_lang_object_klass 308 | .vtable 309 | .get(&("", "toString", "()Ljava/lang/String;")) 310 | .unwrap(); 311 | let to_string_method1 = default_simple_klass 312 | .vtable 313 | .get(&("", "toString", "()Ljava/lang/String;")) 314 | .unwrap(); 315 | assert_eq!( 316 | true, 317 | std::ptr::eq((*to_string_method0).0, (*to_string_method1).0) 318 | ); 319 | assert_eq!( 320 | true, 321 | std::ptr::eq((*to_string_method0).1, (*to_string_method1).1) 322 | ); 323 | let bytecode = parse_class(DEFAULT_TEST); 324 | let default_test_klass = super::Klass::new( 325 | Arc::new(bytecode), 326 | crate::mem::metaspace::ROOT_CLASSLOADER, 327 | Some(java_lang_object_klass.clone()), 328 | vec![], 329 | ); 330 | assert_eq!(6, default_test_klass.vtable.len()); 331 | let to_string_method2 = default_test_klass 332 | .vtable 333 | .get(&("", "toString", "()Ljava/lang/String;")) 334 | .unwrap(); 335 | assert_eq!( 336 | false, 337 | std::ptr::eq((*to_string_method0).0, (*to_string_method2).0) 338 | ); 339 | assert_eq!( 340 | false, 341 | std::ptr::eq((*to_string_method0).1, (*to_string_method2).1) 342 | ); 343 | } 344 | 345 | #[test] 346 | pub fn test_itable() {} 347 | 348 | #[test] 349 | pub fn test_layout() { 350 | let java_lang_object = parse_class(JAVA_LANG_OBJECT); 351 | let java_lang_object_klass = super::Klass::new( 352 | Arc::new(java_lang_object), 353 | crate::mem::metaspace::ROOT_CLASSLOADER, 354 | None, 355 | vec![], 356 | ); 357 | assert_eq!(0, java_lang_object_klass.len); 358 | let java_lang_object_klass = Arc::new(java_lang_object_klass); 359 | let default_test = parse_class(DEFAULT_TEST); 360 | let default_test_klass = super::Klass::new( 361 | Arc::new(default_test), 362 | crate::mem::metaspace::ROOT_CLASSLOADER, 363 | Some(java_lang_object_klass.clone()), 364 | vec![], 365 | ); 366 | assert_eq!(16, default_test_klass.len); 367 | assert_eq!(3, default_test_klass.layout.len()); 368 | let default_extends_test = parse_class(DEFAULT_EXTENDS_TEST); 369 | let default_extends_test_klass = super::Klass::new( 370 | Arc::new(default_extends_test), 371 | crate::mem::metaspace::ROOT_CLASSLOADER, 372 | Some(Arc::new(default_test_klass)), 373 | vec![], 374 | ); 375 | assert_eq!(40, default_extends_test_klass.len); 376 | assert_eq!(8, default_extends_test_klass.layout.len()); 377 | } 378 | } 379 | -------------------------------------------------------------------------------- /src/interpreter/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod thread; 2 | 3 | use self::thread::ThreadContext; 4 | use crate::{ 5 | bytecode, 6 | bytecode::{atom::*, constant_pool::ConstantItem}, 7 | gc, 8 | mem::{heap::Heap, klass::*, metaspace::*, strings::Strings, *}, 9 | }; 10 | use std::sync::Arc; 11 | use std::thread::Thread; 12 | 13 | use log::trace; 14 | 15 | macro_rules! math_bi { 16 | ($l: tt, $r: tt, $op: tt) => { 17 | |a, b| ($l::from_le_bytes(a) $op $r::from_le_bytes(b)).to_le_bytes() 18 | } 19 | } 20 | 21 | macro_rules! math_un { 22 | ($t: tt, $op: tt) => { 23 | |a| ($op $t::from_le_bytes(a)).to_le_bytes() 24 | } 25 | } 26 | 27 | pub fn execute(context: &mut ThreadContext) { 28 | while context.stack.has_next(context.pc) { 29 | let pause = context.rx.try_recv(); 30 | if pause.is_ok() { 31 | context.tx.send(context.roots()).unwrap(); 32 | // waiting signal 33 | let _ = context.rx.recv().unwrap(); 34 | } 35 | // handle_exception 36 | if context.exception_pending { 37 | handle_exception(context); 38 | } 39 | let instruction = context.stack.code_at(context.pc); 40 | context.stack.dump(context.pc); 41 | match instruction { 42 | // nop 43 | 0x00 => { 44 | context.pc = context.pc + 1; 45 | } 46 | // aconst_null 47 | 0x01 => { 48 | context.stack.push(&NULL); 49 | context.pc = context.pc + 1; 50 | } 51 | // iconst -1 ~ 5 52 | 0x02..=0x08 => { 53 | let opr = context.stack.code_at(context.pc) as i32 - 3; 54 | context.stack.push(&opr.to_le_bytes()); 55 | context.pc = context.pc + 1; 56 | } 57 | // lconst 0 ~ 1 58 | 0x09..=0x0a => { 59 | let opr = context.stack.code_at(context.pc) as i64 - 9; 60 | context.stack.push_w(&opr.to_le_bytes()); 61 | context.pc = context.pc + 1; 62 | } 63 | // fconst 0 ~ 2 64 | 0x0b..=0x0d => { 65 | let opr = context.stack.code_at(context.pc) as f32 - 11.0; 66 | context.stack.push(&opr.to_le_bytes()); 67 | context.pc = context.pc + 1; 68 | } 69 | // dconst 0 ~ 1 70 | 0x0e..=0x0f => { 71 | let opr = context.stack.code_at(context.pc) as f64 - 14.0; 72 | context.stack.push_w(&opr.to_le_bytes()); 73 | context.pc = context.pc + 1; 74 | } 75 | // bipush 76 | 0x10 => { 77 | context 78 | .stack 79 | .push(&(context.stack.code_at(context.pc + 1) as i32).to_le_bytes()); 80 | context.pc = context.pc + 2; 81 | } 82 | // sipush 83 | 0x11 => { 84 | let opr = (context.stack.code_at(context.pc + 1) as i32) << 8 85 | | (context.stack.code_at(context.pc + 2) as i32); 86 | context.stack.push(&opr.to_le_bytes()); 87 | context.pc = context.pc + 3; 88 | } 89 | // ldc 90 | 0x12 => { 91 | let v = match context 92 | .stack 93 | .class() 94 | .constant_pool 95 | .get(context.stack.code_at(context.pc + 1) as U2) 96 | { 97 | ConstantItem::Float(f) => f.to_le_bytes(), 98 | ConstantItem::Integer(i) => i.to_le_bytes(), 99 | ConstantItem::String(r) => { 100 | let utf8 = context.stack.class().constant_pool.get(*r).clone(); 101 | match utf8 { 102 | ConstantItem::UTF8(s) => Strings::get(&s, context).to_le_bytes(), 103 | _ => panic!(""), 104 | } 105 | } 106 | _ => unreachable!(), 107 | }; 108 | context.stack.push(&v); 109 | context.pc = context.pc + 2; 110 | } 111 | // ldc2w 112 | 0x14 => { 113 | let opr = (context.stack.code_at(context.pc + 1) as U2) << 8 114 | | context.stack.code_at(context.pc + 2) as U2; 115 | let v = match context.stack.class().constant_pool.get(opr) { 116 | ConstantItem::Double(d) => d.to_le_bytes(), 117 | ConstantItem::Long(l) => l.to_le_bytes(), 118 | _ => panic!(""), 119 | }; 120 | context.stack.push_w(&v); 121 | context.pc = context.pc + 3; 122 | } 123 | // iload/fload 124 | 0x15 | 0x17 => { 125 | let opr = context.stack.code_at(context.pc + 1) as usize; 126 | context.stack.load(opr, 1); 127 | context.pc = context.pc + 2; 128 | } 129 | // lload/dload 130 | 0x16 | 0x18 => { 131 | let opr = context.stack.code_at(context.pc + 1) as usize; 132 | context.stack.load(opr, 2); 133 | context.pc = context.pc + 2; 134 | } 135 | // iload 0 ~ 3 136 | 0x1a..=0x1d => { 137 | let opr = context.stack.code_at(context.pc) as usize - 0x1a; 138 | context.stack.load(opr, 1); 139 | context.pc = context.pc + 1; 140 | } 141 | // lload 0 ~ 3 142 | 0x1e..=0x21 => { 143 | let opr = context.stack.code_at(context.pc) as usize - 0x1e; 144 | context.stack.load(opr, 2); 145 | context.pc = context.pc + 1; 146 | } 147 | // fload 0 ~ 3 148 | 0x22..=0x25 => { 149 | let opr = context.stack.code_at(context.pc) as usize - 0x22; 150 | context.stack.load(opr, 1); 151 | context.pc = context.pc + 1; 152 | } 153 | // dload 0 ~ 3 154 | 0x26..=0x29 => { 155 | let opr = context.stack.code_at(context.pc) as usize - 0x26; 156 | context.stack.load(opr, 2); 157 | context.pc = context.pc + 1; 158 | } 159 | // aload 0 ~ 3 160 | 0x2a..=0x2d => { 161 | let opr = context.stack.code_at(context.pc) as usize - 0x2a; 162 | context.stack.load(opr, 1); 163 | context.pc = context.pc + 1; 164 | } 165 | // iaload 166 | 0x2e => { 167 | let array_idx = u32::from_le_bytes(context.stack.pop()) as usize; 168 | let arrayref = u32::from_le_bytes(context.stack.pop()) as usize; 169 | // let current = context.stack.mut_frame(); 170 | unsafe { 171 | let header = ObjHeader::from_vm_raw(Heap::ptr(arrayref)); 172 | if array_idx >= header.size.unwrap() as usize { 173 | context 174 | .stack 175 | .update(context.stack.operands().add(2 * PTR_SIZE)); 176 | throw_vm_exception(context, "java/lang/ArrayIndexOutOfBoundsException"); 177 | continue; 178 | } 179 | // FIXME heap -> stack 180 | let offset = (&*header.klass).len * array_idx; 181 | context.stack.operands().copy_from( 182 | Heap::ptr(arrayref + OBJ_HEADER_SIZE + offset), 183 | (&*header.klass).len, 184 | ); 185 | context 186 | .stack 187 | .update(context.stack.operands().add((&*header.klass).len)); 188 | } 189 | context.pc = context.pc + 1; 190 | } 191 | // istore/fstore/astore 192 | 0x36 | 0x38 | 0x3a => { 193 | let opr = context.stack.code_at(context.pc + 1) as usize; 194 | context.stack.store(opr, 1); 195 | context.pc = context.pc + 2; 196 | } 197 | // lstore/dstore 198 | 0x37 | 0x39 => { 199 | let opr = context.stack.code_at(context.pc + 1) as usize; 200 | context.stack.store(opr, 2); 201 | context.pc = context.pc + 2; 202 | } 203 | // istore 0 ~ 3 204 | 0x3b..=0x3e => { 205 | let opr = context.stack.code_at(context.pc) as usize - 0x3b; 206 | context.stack.store(opr, 1); 207 | context.pc = context.pc + 1; 208 | } 209 | // lstore 0 ~ 3 210 | 0x3f..=0x42 => { 211 | let opr = context.stack.code_at(context.pc) as usize - 0x3f; 212 | context.stack.store(opr, 2); 213 | context.pc = context.pc + 1; 214 | } 215 | // fstore 0 ~ 3 216 | 0x43..=0x46 => { 217 | let opr = context.stack.code_at(context.pc) as usize - 0x43; 218 | context.stack.store(opr, 1); 219 | context.pc = context.pc + 1; 220 | } 221 | // dstore 0 ~ 3 222 | 0x47..=0x4a => { 223 | let opr = context.stack.code_at(context.pc) as usize - 0x47; 224 | context.stack.store(opr, 2); 225 | context.pc = context.pc + 1; 226 | } 227 | // astore 0 ~ 3 228 | 0x4b..=0x4e => { 229 | let opr = context.stack.code_at(context.pc) as usize - 0x4b; 230 | context.stack.store(opr, 1); 231 | context.pc = context.pc + 1; 232 | } 233 | // iastore 234 | 0x4f => { 235 | let v = context.stack.pop(); 236 | let array_idx = u32::from_le_bytes(context.stack.pop()) as usize; 237 | let arrayref = u32::from_le_bytes(context.stack.pop()) as usize; 238 | unsafe { 239 | let header = ObjHeader::from_vm_raw(Heap::ptr(arrayref)); 240 | if array_idx >= header.size.unwrap() as usize { 241 | context.stack.upward(3); 242 | throw_vm_exception(context, "java/lang/ArrayIndexOutOfBoundsException"); 243 | continue; 244 | } 245 | let offset = (&*header.klass).len * array_idx; 246 | Heap::ptr(arrayref + OBJ_HEADER_SIZE + offset) 247 | .copy_from(v.as_ptr(), (&*header.klass).len); 248 | } 249 | context.pc = context.pc + 1; 250 | } 251 | // pop 252 | 0x57 => { 253 | context.stack.pop(); 254 | context.pc = context.pc + 1; 255 | } 256 | // pop2 257 | 0x58 => { 258 | context.stack.pop_w(); 259 | context.pc = context.pc + 1; 260 | } 261 | // dup 262 | 0x59 => { 263 | unsafe { 264 | context 265 | .stack 266 | .operands() 267 | .copy_from(context.stack.operands().sub(PTR_SIZE), PTR_SIZE); 268 | } 269 | context.stack.upward(1); 270 | context.pc = context.pc + 1; 271 | } 272 | // i/l/f/d +,-,*,/,%,<<,>>,>>> 273 | 0x60..=0x83 => { 274 | let code = context.stack.code_at(context.pc); 275 | match code { 276 | 0x60 => context.stack.bi_op(math_bi!(i32, i32, +)), 277 | 0x61 => context.stack.bi_op_w(math_bi!(i64, i64, +)), 278 | 0x62 => context.stack.bi_op(math_bi!(f32, f32, +)), 279 | 0x63 => context.stack.bi_op_w(math_bi!(f64, f64, +)), 280 | 0x64 => context.stack.bi_op(math_bi!(i32, i32, -)), 281 | 0x65 => context.stack.bi_op_w(math_bi!(i64, i64, -)), 282 | 0x66 => context.stack.bi_op(math_bi!(f32, f32, -)), 283 | 0x67 => context.stack.bi_op_w(math_bi!(f64, f64, -)), 284 | 0x68 => context.stack.bi_op(math_bi!(i32, i32, *)), 285 | 0x69 => context.stack.bi_op_w(math_bi!(i64, i64, *)), 286 | 0x6a => context.stack.bi_op(math_bi!(f32, f32, *)), 287 | 0x6b => context.stack.bi_op_w(math_bi!(f64, f64, *)), 288 | 0x6c => context.stack.bi_op(math_bi!(i32, i32, /)), 289 | 0x6d => context.stack.bi_op_w(math_bi!(i64, i64, /)), 290 | 0x6e => context.stack.bi_op(math_bi!(f32, f32, /)), 291 | 0x6f => context.stack.bi_op_w(math_bi!(f64, f64, /)), 292 | 0x70 => context.stack.bi_op(math_bi!(i32, i32, %)), 293 | 0x71 => context.stack.bi_op_w(math_bi!(i64, i64, %)), 294 | 0x72 => context.stack.bi_op(math_bi!(f32, f32, %)), 295 | 0x73 => context.stack.bi_op_w(math_bi!(f64, f64, %)), 296 | 0x74 => context.stack.un_op(math_un!(i32, -)), 297 | 0x75 => context.stack.un_op_w(math_un!(i64, -)), 298 | 0x76 => context.stack.un_op(math_un!(f32, -)), 299 | 0x77 => context.stack.un_op_w(math_un!(f64, -)), 300 | 0x78 => context.stack.bi_op(math_bi!(i32, i32, <<)), 301 | 0x7a => context.stack.bi_op(math_bi!(u32, u32, >>)), 302 | 0x7c => context.stack.bi_op(math_bi!(i32, i32, >>)), 303 | 0x79 => { 304 | let s = u32::from_le_bytes(context.stack.pop()); 305 | context 306 | .stack 307 | .un_op_w(|d| (i64::from_le_bytes(d) << s).to_le_bytes()); 308 | } 309 | 0x7b => { 310 | let s = u32::from_le_bytes(context.stack.pop()); 311 | context 312 | .stack 313 | .un_op_w(|d| (u64::from_le_bytes(d) << s).to_le_bytes()); 314 | } 315 | 0x7d => { 316 | let s = u32::from_le_bytes(context.stack.pop()); 317 | context 318 | .stack 319 | .un_op_w(|d| (i64::from_le_bytes(d) << s).to_le_bytes()); 320 | } 321 | 0x7e => context.stack.bi_op(math_bi!(i32, i32, &)), 322 | 0x7f => context.stack.bi_op_w(math_bi!(i64, i64, &)), 323 | 0x80 => context.stack.bi_op(math_bi!(i32, i32, |)), 324 | 0x81 => context.stack.bi_op_w(math_bi!(i64, i64, |)), 325 | 0x82 => context.stack.bi_op(math_bi!(i32, i32, ^)), 326 | 0x83 => context.stack.bi_op_w(math_bi!(i64, i64, ^)), 327 | _ => unreachable!(), 328 | } 329 | context.pc = context.pc + 1; 330 | } 331 | // iinc 332 | 0x84 => { 333 | let index = context.stack.code_at(context.pc + 1) as usize; 334 | let cst = context.stack.code_at(context.pc + 2) as i32; 335 | let new = i32::from_le_bytes(context.stack.get(index)) + cst; 336 | context.stack.set(index, &new.to_le_bytes()); 337 | context.pc = context.pc + 3; 338 | } 339 | // i2l,i2f,i2d,l2i,l2f,l2d,f2i,f2l,f2d,d2i,d2l,d2f,i2b,i2c,i2s 340 | 0x85..=0x93 => { 341 | let code = context.stack.code_at(context.pc); 342 | match code { 343 | // i2f, l2d, f2i, d2l, i2b, i2c, i2s 344 | 0x86 | 0x8a | 0x8b | 0x8f | 0x91 | 0x92 | 0x93 => {} 345 | // i2l 346 | 0x85 => { 347 | let v = i32::from_le_bytes(context.stack.pop()); 348 | context.stack.push_w(&(v as i64).to_le_bytes()); 349 | } 350 | // i2d 351 | 0x87 => { 352 | let v = i32::from_le_bytes(context.stack.pop()); 353 | context.stack.push_w(&(v as f64).to_le_bytes()); 354 | } 355 | // l2i 356 | 0x88 => { 357 | let v = i64::from_le_bytes(context.stack.pop_w()); 358 | context.stack.push(&(v as i32).to_le_bytes()); 359 | } 360 | // l2f 361 | 0x89 => { 362 | let v = i64::from_le_bytes(context.stack.pop_w()); 363 | context.stack.push(&(v as f32).to_le_bytes()); 364 | } 365 | // f2l 366 | 0x8c => { 367 | let v = f32::from_le_bytes(context.stack.pop()); 368 | context.stack.push_w(&(v as i64).to_le_bytes()); 369 | } 370 | // f2d 371 | 0x8d => { 372 | let v = f32::from_le_bytes(context.stack.pop()); 373 | context.stack.push_w(&(v as f64).to_le_bytes()); 374 | } 375 | // d2i 376 | 0x8e => { 377 | let v = f64::from_le_bytes(context.stack.pop_w()); 378 | context.stack.push(&(v as i32).to_le_bytes()); 379 | } 380 | // d2f 381 | 0x90 => { 382 | let v = f64::from_le_bytes(context.stack.pop_w()); 383 | context.stack.push(&(v as f32).to_le_bytes()); 384 | } 385 | _ => unreachable!(), 386 | } 387 | context.pc = context.pc + 1; 388 | } 389 | // ifeq, ifne, iflt, ifge, ifgt, ifle 390 | 0x99..=0x9e => { 391 | let opr = i32::from_le_bytes(context.stack.pop()); 392 | if opr == 0 && instruction == 0x99 393 | || opr != 0 && instruction == 0x9a 394 | || opr < 0 && instruction == 0x9b 395 | || opr >= 0 && instruction == 0x9c 396 | || opr > 0 && instruction == 0x9d 397 | || opr <= 0 && instruction == 0x9e 398 | { 399 | let jump = (context.stack.code_at(context.pc + 1) as U2) << 8 400 | | context.stack.code_at(context.pc + 2) as U2; 401 | context.pc = jump as usize; 402 | } else { 403 | context.pc = context.pc + 3; 404 | } 405 | } 406 | // if_icmp eq,ne,lt,ge,gt,le 407 | 0x9f..=0xa4 => { 408 | let (v1, v2) = { 409 | let v2 = i32::from_le_bytes(context.stack.pop()); 410 | let v1 = i32::from_le_bytes(context.stack.pop()); 411 | (v1, v2) 412 | }; 413 | let code = context.stack.code_at(context.pc); 414 | let offset = if code == 0x9f && v1 == v2 415 | || code == 0xa0 && v1 != v2 416 | || code == 0xa1 && v1 < v2 417 | || code == 0xa2 && v1 >= v2 418 | || code == 0xa3 && v1 > v2 419 | || code == 0xa4 && v1 <= v2 420 | { 421 | ((context.stack.code_at(context.pc + 1) as i16) << 8 422 | | context.stack.code_at(context.pc + 2) as i16) as isize 423 | } else { 424 | 3 425 | }; 426 | context.pc = (context.pc as isize + offset) as usize; 427 | } 428 | // if_acmpeq, if_acmpne 429 | 0xa5 | 0xa6 => { 430 | // TODO reference as u32 431 | let (v1, v2) = { 432 | let v2 = Ref::from_le_bytes(context.stack.pop()); 433 | let v1 = Ref::from_le_bytes(context.stack.pop()); 434 | (v1, v2) 435 | }; 436 | let code = context.stack.code_at(context.pc); 437 | let offset = if code == 0xa5 && v1 == v2 || code == 0xa6 && v1 != v2 { 438 | ((context.stack.code_at(context.pc + 1) as i16) << 8 439 | | context.stack.code_at(context.pc + 2) as i16) as isize 440 | } else { 441 | 3 442 | }; 443 | context.pc = (context.pc as isize + offset) as usize; 444 | } 445 | // goto 446 | 0xa7 => { 447 | let offset = ((context.stack.code_at(context.pc + 1) as i16) << 8 448 | | context.stack.code_at(context.pc + 2) as i16) 449 | as i16; 450 | context.pc = (context.pc as isize + offset as isize) as usize; 451 | } 452 | // ireturn/lreturn/freturn/dreturn/areturn/return 453 | 0xac..=0xb1 => { 454 | context.pc = context.stack.return_normal(); 455 | } 456 | // getstatic 457 | 0xb2 => { 458 | let field_idx = (context.stack.code_at(context.pc + 1) as U2) << 8 459 | | context.stack.code_at(context.pc + 2) as U2; 460 | let class = unsafe { context.stack.class_ptr().as_ref() } 461 | .expect("stack_class_pointer_null"); 462 | let (c, (f, t)) = class.constant_pool.get_javaref(field_idx); 463 | let found = ClassArena::load_class(c, context); 464 | if found.is_err() { 465 | throw_vm_exception(context, "java/lang/ClassNotFoundException"); 466 | continue; 467 | } 468 | let (klass, initialized) = found.unwrap(); 469 | if !initialized { 470 | continue; 471 | } 472 | if let Some(ref field) = klass.bytecode.as_ref().unwrap().get_field(f, t) { 473 | match &field.value.get() { 474 | None => { 475 | throw_vm_exception(context, "java/lang/IncompatibleClassChangeError"); 476 | continue; 477 | } 478 | Some(value) => match value { 479 | Value::DWord(_) => context.stack.push_w(&Value::of_w(*value)), 480 | _ => context.stack.push(&Value::of(*value)), 481 | }, 482 | } 483 | context.pc = context.pc + 3; 484 | } else { 485 | throw_vm_exception(context, "java/lang/NoSuchFieldError"); 486 | } 487 | } 488 | // putstatic 489 | 0xb3 => { 490 | let field_idx = (context.stack.code_at(context.pc + 1) as U2) << 8 491 | | context.stack.code_at(context.pc + 2) as U2; 492 | let (c, (f, t)) = context.stack.class().constant_pool.get_javaref(field_idx); 493 | let (c, f, t) = (c.to_string(), f.to_string(), t.to_string()); 494 | let found = ClassArena::load_class(&c, context); 495 | if found.is_err() { 496 | throw_vm_exception(context, "java/lang/ClassNotFoundException"); 497 | continue; 498 | } 499 | let (klass, initialized) = found.unwrap(); 500 | if !initialized { 501 | continue; 502 | } 503 | if let Some(ref field) = klass.bytecode.as_ref().unwrap().get_field(&f, &t) { 504 | &field.value.set(match t.as_ref() { 505 | "D" | "J" => Some(Value::eval_w(context.stack.pop_w())), 506 | _ => Some(Value::eval(context.stack.pop(), &t)), 507 | }); 508 | context.pc = context.pc + 3; 509 | } else { 510 | throw_vm_exception(context, "java/lang/NoSuchFieldError"); 511 | } 512 | } 513 | // getfield 514 | 0xb4 => { 515 | let field_idx = (context.stack.code_at(context.pc + 1) as U2) << 8 516 | | context.stack.code_at(context.pc + 2) as U2; 517 | let (c, (f, t)) = context.stack.class().constant_pool.get_javaref(field_idx); 518 | let (c, f, t) = (c.to_string(), f.to_string(), t.to_string()); 519 | let found = ClassArena::load_class(&c, context); 520 | if found.is_err() { 521 | throw_vm_exception(context, "java/lang/ClassNotFoundException"); 522 | continue; 523 | } 524 | let klass = found.unwrap().0; 525 | let objref = context.stack.pop(); 526 | if objref == NULL { 527 | throw_vm_exception(context, "java/lang/NullPointerException"); 528 | continue; 529 | } 530 | let objref = u32::from_le_bytes(objref) as usize; 531 | let found = klass.layout.get(&(c.as_ref(), f.as_ref(), t.as_ref())); 532 | if found.is_none() { 533 | throw_vm_exception(context, "java/lang/NoSuchFieldError"); 534 | continue; 535 | } 536 | let (offset, len) = found.unwrap(); 537 | unsafe { 538 | let target = Heap::ptr(objref + OBJ_HEADER_SIZE + *offset); 539 | context.stack.operands().copy_from(target, *len); 540 | context.stack.upward(*len / PTR_SIZE); 541 | } 542 | context.pc = context.pc + 3; 543 | } 544 | // putfield 545 | 0xb5 => { 546 | let field_idx = (context.stack.code_at(context.pc + 1) as U2) << 8 547 | | context.stack.code_at(context.pc + 2) as U2; 548 | let (c, (f, t)) = context.stack.class().constant_pool.get_javaref(field_idx); 549 | let (c, f, t) = (c.to_string(), f.to_string(), t.to_string()); 550 | let found = ClassArena::load_class(&c, context); 551 | if found.is_err() { 552 | throw_vm_exception(context, "java/lang/ClassNotFoundException"); 553 | continue; 554 | } 555 | let klass = found.unwrap().0; 556 | let objref = context.stack.pop(); 557 | if objref == NULL { 558 | context.stack.upward(PTR_SIZE); 559 | throw_vm_exception(context, "java/lang/NullPointerException"); 560 | continue; 561 | } 562 | let objref = u32::from_le_bytes(objref) as usize; 563 | let found = klass.layout.get(&(c.as_ref(), f.as_ref(), t.as_ref())); 564 | if found.is_none() { 565 | throw_vm_exception(context, "java/lang/NoSuchFieldError"); 566 | continue; 567 | } 568 | // FIXME stack -> heap 569 | let (offset, len) = found.unwrap(); 570 | unsafe { 571 | let target = Heap::ptr(objref + OBJ_HEADER_SIZE + *offset); 572 | context.stack.downward(*len / PTR_SIZE); 573 | target.copy_from(context.stack.operands(), *len); 574 | } 575 | context.pc = context.pc + 3; 576 | } 577 | // invokevirtual 578 | 0xb6 => invoke_virtual(context), 579 | // invokespecial 580 | 0xb7 => invoke_special(context), 581 | // invokestatic 582 | 0xb8 => invoke_static(context), 583 | // invokeinterface 584 | 0xb9 => invoke_interface(context), 585 | // invokeasync 586 | 0xd3 => { 587 | let method_idx = (context.stack.code_at(context.pc + 1) as U2) << 8 588 | | context.stack.code_at(context.pc + 2) as U2; 589 | let class = 590 | unsafe { context.stack.class_ptr().as_ref() }.expect("class_pointer_null"); 591 | let (c, (m, t)) = class.constant_pool.get_javaref(method_idx); 592 | let found = ClassArena::load_class(c, context); 593 | if found.is_err() { 594 | throw_vm_exception(context, "java/lang/ClassNotFoundException"); 595 | continue; 596 | } 597 | let (klass, initialized) = found.unwrap(); 598 | if !initialized { 599 | continue; 600 | } 601 | let ctx_classloader = context.classloader; 602 | std::thread::spawn(move || { 603 | thread::ThreadGroup::new_thread(ctx_classloader, c, m, t, true); 604 | }); 605 | context.pc = context.pc + 3; 606 | } 607 | // new 608 | 0xbb => { 609 | let class_index = (context.stack.code_at(context.pc + 1) as U2) << 8 610 | | context.stack.code_at(context.pc + 2) as U2; 611 | let class_name = context 612 | .stack 613 | .class() 614 | .constant_pool 615 | .get_str(class_index) 616 | .to_owned(); 617 | let found = ClassArena::load_class(&class_name, context); 618 | if found.is_err() { 619 | throw_vm_exception(context, "java/lang/ClassNotFoundException"); 620 | continue; 621 | } 622 | let (klass, initialized) = found.unwrap(); 623 | if !initialized { 624 | continue; 625 | } 626 | let obj = Heap::allocate_object(&klass); 627 | let v = obj.to_le_bytes(); 628 | context.stack.push(&v); 629 | trace!("allocate object, addr: {}", obj); 630 | context.pc = context.pc + 3; 631 | } 632 | // newarray 633 | 0xbc => { 634 | let atype = match context.stack.code_at(context.pc + 1) { 635 | 4 => "[Z", 636 | 5 => "[C", 637 | 6 => "[F", 638 | 7 => "[D", 639 | 8 => "[B", 640 | 9 => "[S", 641 | 10 => "[I", 642 | 11 => "[J", 643 | _ => unreachable!(), 644 | }; 645 | let (klass, _) = 646 | ClassArena::load_class(atype, context).expect("primitive_types_array"); 647 | let size = u32::from_le_bytes(context.stack.pop()); 648 | let array = Heap::allocate_array(&klass, size); 649 | if array.is_none() { 650 | gc::gc(); 651 | continue; 652 | } 653 | let array = array.unwrap(); 654 | let v = array.to_le_bytes(); 655 | context.stack.push(&v); 656 | trace!("allocate array {}, addr:{}, size:{}", atype, array, size); 657 | context.pc = context.pc + 2; 658 | } 659 | // anewarray 660 | 0xbd => { 661 | let class_index = (context.stack.code_at(context.pc + 1) as U2) << 8 662 | | context.stack.code_at(context.pc + 2) as U2; 663 | let class_name = 664 | "[".to_owned() + context.stack.class().constant_pool.get_str(class_index); 665 | let found = ClassArena::load_class(&class_name, context); 666 | if found.is_err() { 667 | throw_vm_exception(context, "java/lang/ClassNotFoundException"); 668 | continue; 669 | } 670 | let (klass, initialized) = found.unwrap(); 671 | if !initialized { 672 | continue; 673 | } 674 | let size = u32::from_le_bytes(context.stack.pop()); 675 | let array = Heap::allocate_array(&klass, size); 676 | if array.is_none() { 677 | gc::gc(); 678 | continue; 679 | } 680 | let array = array.unwrap(); 681 | let v = array.to_le_bytes(); 682 | context.stack.push(&v); 683 | trace!( 684 | "allocate array {}, addr:{}, size:{}", 685 | class_name, 686 | array, 687 | size 688 | ); 689 | context.pc = context.pc + 3; 690 | } 691 | // arraylength 692 | 0xbe => { 693 | let addr = context.stack.pop(); 694 | if addr == NULL { 695 | throw_vm_exception(context, "java/lang/NullPointerException"); 696 | return; 697 | } 698 | let array = ObjHeader::from_vm_raw(Heap::ptr(u32::from_le_bytes(addr) as usize)); 699 | context.stack.push(&array.size.unwrap().to_le_bytes()); 700 | context.pc = context.pc + 1; 701 | } 702 | // athrow 703 | 0xbf => { 704 | context.exception_pending = true; 705 | context.throwable_initialized = true; 706 | } 707 | _ => panic!(format!( 708 | "Instruction 0x{:2x?} not implemented yet.", 709 | instruction 710 | )), 711 | } 712 | } 713 | } 714 | 715 | fn invoke_virtual(context: &mut ThreadContext) { 716 | let method_idx = (context.stack.code_at(context.pc + 1) as U2) << 8 717 | | context.stack.code_at(context.pc + 2) as U2; 718 | let (_, (m, t)) = context.stack.class().constant_pool.get_javaref(method_idx); 719 | // 0 for indicating non-static method 720 | let (_, slots, _) = bytecode::resolve_method_descriptor(t, 0); 721 | 722 | let addr = *context.stack.top_n(slots); 723 | if addr == NULL { 724 | throw_vm_exception(context, "java/lang/NullPointerException"); 725 | return; 726 | } 727 | let obj = ObjHeader::from_vm_raw(Heap::ptr(u32::from_le_bytes(addr) as usize)); 728 | let klass = unsafe { obj.klass.as_ref() }.expect("obj_klass_pointer_null"); 729 | if let Some(method) = klass.get_method_in_vtable(m, t) { 730 | context.pc = context 731 | .stack 732 | .invoke((*method).0, (*method).1, context.pc + 3, slots); 733 | return; 734 | } 735 | if let Some(method) = klass.bytecode.as_ref().unwrap().get_method(m, t) { 736 | if !method.is_final() { 737 | throw_vm_exception(context, "java/lang/IncompatibleClassChangeError"); 738 | return; 739 | } 740 | let class = Arc::as_ptr(&klass.bytecode.as_ref().unwrap()); 741 | let method = Arc::as_ptr(&method); 742 | context.pc = context.stack.invoke(class, method, context.pc + 3, slots); 743 | return; 744 | } 745 | throw_vm_exception(context, "java/lang/NoSuchMethodError"); 746 | } 747 | 748 | fn invoke_interface(context: &mut ThreadContext) { 749 | let method_idx = (context.stack.code_at(context.pc + 1) as U2) << 8 750 | | context.stack.code_at(context.pc + 2) as U2; 751 | let (c, (m, t)) = context.stack.class().constant_pool.get_javaref(method_idx); 752 | let (_, slots, _) = bytecode::resolve_method_descriptor(t, 0); 753 | let addr = *context.stack.top_n(slots); 754 | if addr == NULL { 755 | throw_vm_exception(context, "java/lang/NullPointerException"); 756 | return; 757 | } 758 | let addr = u32::from_le_bytes(addr); 759 | let obj = ObjHeader::from_vm_raw(Heap::ptr(addr as usize)); 760 | let klass = unsafe { obj.klass.as_ref() }.expect("obj_klass_pointer_null"); 761 | if let Some(method) = klass.get_method_in_itable(c, m, t) { 762 | context.pc = context 763 | .stack 764 | .invoke((*method).0, (*method).1, context.pc + 5, slots); 765 | return; 766 | } 767 | throw_vm_exception(context, "java/lang/NoSuchMethodError"); 768 | } 769 | 770 | fn invoke_static(context: &mut ThreadContext) { 771 | let method_idx = (context.stack.code_at(context.pc + 1) as U2) << 8 772 | | context.stack.code_at(context.pc + 2) as U2; 773 | let class = unsafe { context.stack.class_ptr().as_ref() }.expect("class_pointer_null"); 774 | let (c, (m, t)) = class.constant_pool.get_javaref(method_idx); 775 | let found = ClassArena::load_class(c, context); 776 | if found.is_err() { 777 | throw_vm_exception(context, "java/lang/ClassNotFoundException"); 778 | return; 779 | } 780 | let (klass, initialized) = found.unwrap(); 781 | if !initialized { 782 | return; 783 | } 784 | let method = klass.bytecode.as_ref().unwrap().get_method(m, t); 785 | if method.is_none() { 786 | throw_vm_exception(context, "java/lang/NoSuchMethodError"); 787 | return; 788 | } 789 | let method = method.unwrap(); 790 | if !method.is_static() { 791 | throw_vm_exception(context, "java/lang/IncompatibleClassChangeError"); 792 | return; 793 | } 794 | let (_, desc, access_flag) = method.get_name_and_descriptor(); 795 | let (_, slots, _) = bytecode::resolve_method_descriptor(desc, access_flag); 796 | let class = Arc::as_ptr(&klass.bytecode.as_ref().unwrap()); 797 | let method = Arc::as_ptr(&method); 798 | context.pc = context.stack.invoke(class, method, context.pc + 3, slots); 799 | } 800 | 801 | fn invoke_special(context: &mut ThreadContext) { 802 | let method_idx = (context.stack.code_at(context.pc + 1) as U2) << 8 803 | | context.stack.code_at(context.pc + 2) as U2; 804 | let class = unsafe { context.stack.class_ptr().as_ref() }.expect("class_pointer_null"); 805 | let (c, (m, t)) = class.constant_pool.get_javaref(method_idx); 806 | let found = ClassArena::load_class(c, context); 807 | if found.is_err() { 808 | throw_vm_exception(context, "java/lang/ClassNotFoundException"); 809 | return; 810 | } 811 | let (klass, initialized) = found.unwrap(); 812 | // redundant check 813 | if !initialized { 814 | return; 815 | } 816 | let method = klass.bytecode.as_ref().unwrap().get_method(m, t); 817 | if method.is_none() { 818 | throw_vm_exception(context, "java/lang/NoSuchMethodError"); 819 | return; 820 | } 821 | let method = method.unwrap(); 822 | let (_, desc, access_flag) = method.get_name_and_descriptor(); 823 | let (_, slots, _) = bytecode::resolve_method_descriptor(desc, access_flag); 824 | let class = Arc::as_ptr(&klass.bytecode.as_ref().unwrap()); 825 | let method = Arc::as_ptr(&method); 826 | context.pc = context.stack.invoke(class, method, context.pc + 3, slots); 827 | } 828 | 829 | fn throw_vm_exception(context: &mut ThreadContext, error_class: &str) { 830 | let (error, initialized) = ClassArena::load_class(error_class, context).expect("jre_not_found"); 831 | if !initialized { 832 | return; 833 | } 834 | let exception = Heap::allocate_object(&error).to_le_bytes(); 835 | context.stack.push(&exception); 836 | context.exception_pending = true; 837 | context.throwable_initialized = false; 838 | } 839 | 840 | fn handle_exception(context: &mut ThreadContext) { 841 | if !context.throwable_initialized { 842 | context.throwable_initialized = true; 843 | } 844 | if context.stack.is_empty() { 845 | return; 846 | } 847 | let error_ref = Ref::from_le_bytes(*context.stack.top()); 848 | let header = ObjHeader::from_vm_raw(Heap::ptr(error_ref as usize)); 849 | let error_klass = unsafe { &*header.klass }; 850 | match context.stack.match_exception_table(context.pc, error_klass) { 851 | Some(pc) => { 852 | context.pc = pc; 853 | context.exception_pending = false; 854 | } 855 | None => context.pc = context.stack.fire_exception(), 856 | } 857 | } 858 | 859 | #[test] 860 | pub fn test_shift() { 861 | let u = 1i32; 862 | assert_eq!(0, u >> 1); 863 | assert_eq!(2, u << 1); 864 | let nu = i32::MIN; 865 | let sfr = unsafe { std::mem::transmute::(std::mem::transmute::(nu) >> 1) }; 866 | let test: u32 = 0x80000001 >> 1; 867 | assert_eq!(test as i32, sfr); 868 | assert_eq!(0x80000000, i32::MIN as u32); 869 | } 870 | --------------------------------------------------------------------------------