From fe8f9f13701dc5a55a26a1ce0f32aff5579b21ed Mon Sep 17 00:00:00 2001 From: Sander Hautvast Date: Sun, 1 Oct 2023 09:34:09 +0200 Subject: [PATCH] arguments in method calls --- src/main.rs | 2 +- src/opcodes.rs | 15 +++--- src/vm.rs | 113 ++++++++++++++++++++++++++++++++++-------- tests/FloatBean.class | Bin 282 -> 348 bytes tests/FloatBean.java | 4 ++ tests/Main.class | Bin 315 -> 322 bytes tests/Main.java | 2 +- 7 files changed, 107 insertions(+), 29 deletions(-) diff --git a/src/main.rs b/src/main.rs index b0229d5..08395cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ fn main() -> Result<(), Error> { let mut vm = Vm::new("tests"); let main_class = "Main"; - vm.execute(main_class, "main([Ljava/lang/String;)V", None) + vm.execute(main_class, "main([Ljava/lang/String;)V", vec![]) .unwrap(); Ok(()) } diff --git a/src/opcodes.rs b/src/opcodes.rs index b517260..e9474f1 100644 --- a/src/opcodes.rs +++ b/src/opcodes.rs @@ -13,18 +13,18 @@ pub const LDC2_W: &u8 = &20; // (0x14) Push long or double from run-time constan // pub const dload:u8 = 24; // (0x18) load double from local variable // pub const aload:u8 = 25; //0x19 // -// pub const fload_0:u8 = 34; // (0x22) Load float 0 from local variable -// pub const fload_1:u8 = 35; // (0x23) Load float 1 from local variable -// pub const fload_2:u8 = 36; // (0x24) Load float 2 from local variable -// pub const fload_3:u8 = 37; // (0x25) Load float 3 from local variable +pub const FLOAD_0: &u8 = &34; // (0x22) Load float from local variable 0 +pub const FLOAD_1: &u8 = &35; // (0x23) Load float from local variable 1 +pub const FLOAD_2: &u8 = &36; // (0x24) Load float from local variable 2 +pub const FLOAD_3: &u8 = &37; // (0x25) Load float from local variable 3 // pub const dload_0:u8 = 38; // (0x26) Load double 0 from local variable // pub const dload_1:u8 = 39; // (0x27) Load double 1 from local variable // pub const dload_2:u8 = 40; // (0x28) Load double 2 from local variable // pub const dload_3:u8 = 41; // (0x29) Load double 3 from local variable pub const ALOAD_0: &u8 = &42; // (0x2a) - // pub const aload_1:u8 = 43;// (0x2a) - // pub const aload_2:u8 = 44;// (0x2b) - // pub const aload_3:u8 = 45;// (0x2c) +pub const ALOAD_1: &u8 = &43;// (0x2a) +pub const ALOAD_2: &u8 = &44;// (0x2b) +pub const ALOAD_3: &u8 = &45;// (0x2c) // pub const faload: u8 = 48; // (0x30) Load float from array // pub const daload:u8 = 49; // (0x31) load double from array @@ -89,6 +89,7 @@ pub const DRETURN: &u8 = &175; // (0xaf) Return double from method pub const RETURN_VOID: &u8 = &177; // (0xb1) Return void from method (actually 'return' but that's a keyword) // pub const getstatic: u8 = 178; // (0xb2) Get static field from class pub const GETFIELD: &u8 = &180; // (0xb4) Fetch field from object3 +pub const PUTFIELD: &u8 = &181; // (0xb5) Set field in object pub const INVOKEVIRTUAL: &u8 = &182; // (0xb6) Invoke instance method; dispatch based on class pub const NEW: &u8 = &187; // (0xbb) Create new object // diff --git a/src/vm.rs b/src/vm.rs index 09157a5..5fefde7 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -13,12 +13,16 @@ use crate::opcodes::*; #[derive(Debug)] struct StackFrame { + at: String, data: Vec>, } impl StackFrame { - fn new() -> Self { - Self { data: vec![] } + fn new(at_class: &str, at_method: &str) -> Self { + let mut at: String = at_class.into(); + at.push('.'); + at.push_str(at_method); + Self { at, data: vec![] } } fn push(&mut self, val: Arc) { @@ -97,13 +101,13 @@ impl Vm { &mut self, class_name: &str, method_name: &str, - instance: Option>, + args: Vec>, ) -> Result, Error> { println!("execute {}.{}", class_name, method_name); let class = self.get_class(class_name)?; let method = class.get_method(method_name)?; if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() { - let stackframe = StackFrame::new(); + let stackframe = StackFrame::new(class_name, method_name); self.stack.push(stackframe); let mut pc: usize = 0; @@ -113,11 +117,13 @@ impl Vm { println!("opcode {} ", opcode); match opcode { BIPUSH => { + println!("BISPUSH"); let c = code.opcodes[pc] as i32; self.local_stack().push(Arc::new(Value::I32(c))); pc += 1; } LDC => { + println!("LDC"); let cp_index = read_u8(&code.opcodes, pc) as u16; match method.constant_pool.get(&cp_index).unwrap() { CpEntry::Integer(i) => { @@ -161,18 +167,36 @@ impl Vm { pc += 2; } + FLOAD_0 => { + self.local_stack().push(args[0].clone()); + } + FLOAD_1 => { + println!("FLOAD_1"); + self.local_stack().push(args[1].clone()); + } + FLOAD_2 => { + self.local_stack().push(args[2].clone()); + } + FLOAD_3 => { + self.local_stack().push(args[3].clone()); + } ALOAD_0 => { println!("ALOAD_0"); - match instance.clone() { - Some(instance) => { - self.local_stack().push(instance); - } - None => { - panic!("static context") - } - } + self.local_stack().push(args[0].clone()); } - POP =>{ + ALOAD_1 => { + println!("ALOAD_1"); + self.local_stack().push(args[1].clone()); + } + ALOAD_2 => { + println!("ALOAD_2"); + self.local_stack().push(args[2].clone()); + } + ALOAD_3 => { + println!("ALOAD_3"); + self.local_stack().push(args[3].clone()); + } + POP => { self.local_stack().pop().expect("Stack empty"); } DUP => { @@ -218,11 +242,30 @@ impl Vm { } pc += 2; } + PUTFIELD => { + println!("PUTFIELD"); + let cp_index = read_u16(&code.opcodes, pc); + if let CpEntry::Fieldref(_class_index, name_and_type_index) = + method.constant_pool.get(&cp_index).unwrap() + { + let value = self.local_stack().pop()?; + println!("value {:?}", value); + let objectref = self.local_stack().pop()?; + println!("objectref {:?}", objectref); + } + pc += 2; + } INVOKEVIRTUAL => { let cp_index = read_u16(&code.opcodes, pc); - let instance = self.local_stack().pop().unwrap(); if let Some((class, method)) = get_signature_for_invoke(Rc::clone(&method.constant_pool), cp_index) { - let return_value = self.execute(class.as_str(), method.as_str(), Some(instance))?; + let signature = method.0.as_str(); + let num_args = method.1; + let mut args = Vec::with_capacity(num_args); + for _ in 0..num_args { + args.insert(0, self.local_stack().pop()?); + } + args.insert(0, self.local_stack().pop()?); + let return_value = self.execute(class.as_str(), signature, args)?; if let Void = *return_value {} else { // not let? self.local_stack().push(return_value); } @@ -233,9 +276,15 @@ impl Vm { INVOKESPECIAL => { println!("INVOKESPECIAL"); let cp_index = read_u16(&code.opcodes, pc); - let instance = self.local_stack().pop().unwrap(); if let Some((class, method)) = get_signature_for_invoke(Rc::clone(&method.constant_pool), cp_index) { - let return_value = self.execute(class.as_str(), method.as_str(), Some(instance))?; + let signature = method.0.as_str(); + let num_args = method.1; + let mut args = vec![]; + for _ in 0..num_args { + args.insert(0, self.local_stack().pop()?); + } + args.insert(0, self.local_stack().pop()?); + let return_value = self.execute(class.as_str(), signature, args)?; if let Void = *return_value {} else { // not let? self.local_stack().push(return_value); } @@ -275,7 +324,7 @@ impl Vm { //TODO refs with lifetime -fn get_signature_for_invoke(cp: Rc>, index: u16) -> Option<(String, String)> { +fn get_signature_for_invoke(cp: Rc>, index: u16) -> Option<(String, (String, usize))> { if let CpEntry::MethodRef(class_index, name_and_type_index) = cp.get(&index).unwrap() { if let Some(method_signature) = get_name_and_type(Rc::clone(&cp), *name_and_type_index) { if let CpEntry::ClassRef(class_name_index) = cp.get(class_index).unwrap() { @@ -288,15 +337,39 @@ fn get_signature_for_invoke(cp: Rc>, index: u16) -> Option None } -fn get_name_and_type(cp: Rc>, index: u16) -> Option { +fn get_name_and_type(cp: Rc>, index: u16) -> Option<(String, usize)> { if let CpEntry::NameAndType(method_name_index, signature_index) = cp.get(&index).unwrap() { if let CpEntry::Utf8(method_name) = cp.get(method_name_index).unwrap() { if let CpEntry::Utf8(signature) = cp.get(signature_index).unwrap() { let mut method_signature: String = method_name.into(); + let num_args = get_hum_args(signature); method_signature.push_str(signature); - return Some(method_signature); + + return Some((method_signature, num_args)); } } } None +} + +fn get_hum_args(signature: &str) -> usize { + let mut num = 0; + let mut i = 1; + let chars: Vec = signature.chars().collect(); + + while i < chars.len() { + if chars[i] == 'L' { + i += 1; + while chars[i] != ';' { + i += 1; + } + num += 1; + } else if chars[i] == ')' { + break; + } else { + i += 1; + num += 1; + } + } + num } \ No newline at end of file diff --git a/tests/FloatBean.class b/tests/FloatBean.class index d24f713cb6caef45ef24b0712001b637c4b84998..85d4711af2eb2fddc516c8d45db4b808d80c7ac6 100644 GIT binary patch delta 113 zcmbQmbcadm)W2Q(7#JAL8AQ1lSQrF38JHP_*cpV`8AK*ZxeIU5!VeT- HVh{iT(`yh- delta 48 zcmcb^G>b{<)W2Q(7#JAL8HBkQSQz*@8JHOa*ck-b8H6TExlb&PU}TzjCYqIjfr)_+ E02N>frvLx| diff --git a/tests/FloatBean.java b/tests/FloatBean.java index a19b968..f112ddf 100644 --- a/tests/FloatBean.java +++ b/tests/FloatBean.java @@ -5,4 +5,8 @@ public class FloatBean { public float getValue(){ return value; } + + public void setValue(float value){ + this.value = value; + } } diff --git a/tests/Main.class b/tests/Main.class index 3ee664fad9615748b95be0a2af7c0548ead24773..0be53597f9eb2b086fffe7ab7f9e1cd73351a26f 100644 GIT binary patch delta 208 zcmYL@zYf7r6vlt|x^=abs$w#*P%mKb&_`%uY^0kosM#}g^cWTr5`)o0iBpR+e1A^P z_vJkFOV8h*`x96(_OJw&zK13-$pUH>S_YP=nr)&MuEI^X`@BqweAi*fs5(zhhoa2# z?XggpMH**JX-ZW+8ik|;J#iCZCG0G3sEY_iTd?_CN;4gN(e-Kki-P|^uWvL$bH({b P>c_xHz(KX>iqZ7GLx2}s delta 182 zcmX@aw3|uk)W2Q(7#JAL8N|34*ckZP83ec(m>Bp$gdjVE5IckLMD=75b_Nbc22Qt} z{KOKc)Wkd<1`!6)iSuMt(o;*q5_3vZ85x*0G~E~!8CZdafB+K%BLh$qkmQ{BK+Ky9 zD8vTjFn|OYxEXlBGy{VMSRn%g&u#{$$n6Zw+Zb5FH-c4xbbuVez`z1j&k9t}3uH4f G@Bsi9ffj23 diff --git a/tests/Main.java b/tests/Main.java index e7401e9..e6ef7a1 100644 --- a/tests/Main.java +++ b/tests/Main.java @@ -1,6 +1,6 @@ public class Main { public static void main(String[] args){ - new FloatBean().getValue(); + new FloatBean().setValue(42F); } }