From c47b7e9f509f8033ae9ccd50600eab13af3d98b6 Mon Sep 17 00:00:00 2001 From: Shautvast Date: Sun, 22 Oct 2023 15:54:37 +0200 Subject: [PATCH] WIP virtual methods --- src/class.rs | 2 +- src/vm.rs | 82 +++++++++++++++++++++++++++++++++++++++++--- tests/class_tests.rs | 2 +- 3 files changed, 79 insertions(+), 7 deletions(-) diff --git a/src/class.rs b/src/class.rs index e5ae24a..4ce188e 100644 --- a/src/class.rs +++ b/src/class.rs @@ -63,7 +63,7 @@ pub fn get_class( let clinit = clone2.borrow().methods.contains_key("()V"); let name = &clone2.borrow().name.to_owned(); if clinit { - vm.execute(name, "()V", vec![]).unwrap(); + vm.execute_special(name, "()V", vec![]).unwrap(); } } Ok(clone) diff --git a/src/vm.rs b/src/vm.rs index 9feeeea..f0002e4 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -93,10 +93,55 @@ impl Vm { class_name: &str, method_name: &str, args: Vec, + ) -> Result { + let class = get_class(self, class_name)?; + // let method = class.clone().borrow().get_method(method_name)?.clone(); + let classb = class.borrow(); + + let method = Self::get_method(&classb, method_name, &args).unwrap(); + // let mut superclass = class.super_class.as_ref(); + // while let Some(s) = superclass { + // if let Ok(m) = s.borrow().get_method(method_name) { + // return m; + // } + // superclass = s.borrow().super_class.as_ref(); + // } + + self.execute_class(class.clone(), method.clone(), args) + } + + pub fn execute_special( + &mut self, + class_name: &str, + method_name: &str, + args: Vec, + ) -> Result { + let class = get_class(self, class_name)?; + let method = class.clone().borrow().get_method(method_name)?.clone(); + self.execute_class(class.clone(), method.clone(), args) + } + + fn get_method<'a>(class: &'a std::cell::Ref, method_name: &str, args: &Vec) -> Option<&'a Rc> { + unsafe { + if let Ref(this) = &*args[0].get() { + if let ObjectRef::Object(this) = &*this.get() { + if let Ok(m) = class.get_method(method_name) { + return Some(m); + } + } + } + } + None + } + + pub fn execute_static( + &mut self, + class_name: &str, + method_name: &str, + args: Vec, ) -> Result { let class = get_class(self, class_name)?; let method = class.clone().borrow().get_method(method_name)?.clone(); - //TODO implement dynamic dispatch -> get method from instance self.execute_class(class, method, args) } @@ -211,7 +256,7 @@ impl Vm { .as_bytes() .into(); - self.execute( + self.execute_special( "java/lang/String", "([B)V", vec![ @@ -394,7 +439,7 @@ impl Vm { .1 } else { let that = - get_class(self, that_class_name.as_str())?; + get_class(self, that_class_name.as_str())?; let that_borrow = that.borrow(); that_borrow .static_field_mapping @@ -451,7 +496,34 @@ impl Vm { unreachable!() } }, - INVOKEVIRTUAL | INVOKESPECIAL => unsafe { + INVOKESPECIAL => unsafe { + // TODO differentiate these opcodes + let cp_index = read_u16(&code.opcodes, pc); + if let Some(invocation) = + get_signature_for_invoke(&method.constant_pool, cp_index) + { + let mut args = Vec::with_capacity(invocation.method.num_args); + for _ in 0..invocation.method.num_args { + args.insert(0, copy(self.current_frame().pop()?)); + } + args.insert(0, self.current_frame().pop()?); + let return_value = self.execute_special( + &invocation.class_name, + &invocation.method.name, + args, + )?; + match *return_value.get() { + Void => {} + _ => { + self.current_frame().push_ref(return_value.clone()); + } + } + // println!("stack {} at {}", self.current_frame().len(), self.current_frame().at) + } else { + unreachable!() + } + }, + INVOKEVIRTUAL => unsafe { // TODO differentiate these opcodes let cp_index = read_u16(&code.opcodes, pc); if let Some(invocation) = @@ -487,7 +559,7 @@ impl Vm { for _ in 0..invocation.method.num_args { args.insert(0, copy(self.current_frame().pop()?)); } - let returnvalue = self.execute( + let returnvalue = self.execute_static( &invocation.class_name, &invocation.method.name, args, diff --git a/tests/class_tests.rs b/tests/class_tests.rs index 9eb3797..6f723b8 100644 --- a/tests/class_tests.rs +++ b/tests/class_tests.rs @@ -21,7 +21,7 @@ mod test { fn consts() { let mut vm = Vm::new("tests"); let ret = vm - .execute("testclasses.Const", "hello()Ljava/lang/String;", vec![]) + .execute_static("testclasses.Const", "hello()Ljava/lang/String;", vec![]) .unwrap(); unsafe { if let Value::Ref(s) = &*ret.get() {