arguments in method calls

This commit is contained in:
Sander Hautvast 2023-10-01 09:34:09 +02:00
parent d4a0767c07
commit fe8f9f1370
7 changed files with 107 additions and 29 deletions

View file

@ -8,7 +8,7 @@ fn main() -> Result<(), Error> {
let mut vm = Vm::new("tests"); let mut vm = Vm::new("tests");
let main_class = "Main"; 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(); .unwrap();
Ok(()) Ok(())
} }

View file

@ -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 dload:u8 = 24; // (0x18) load double from local variable
// pub const aload:u8 = 25; //0x19 // pub const aload:u8 = 25; //0x19
// //
// pub const fload_0:u8 = 34; // (0x22) Load float 0 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 1 from local variable pub const FLOAD_1: &u8 = &35; // (0x23) Load float from local variable 1
// pub const fload_2:u8 = 36; // (0x24) Load float 2 from local variable pub const FLOAD_2: &u8 = &36; // (0x24) Load float from local variable 2
// pub const fload_3:u8 = 37; // (0x25) Load float 3 from local variable 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_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_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_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 dload_3:u8 = 41; // (0x29) Load double 3 from local variable
pub const ALOAD_0: &u8 = &42; // (0x2a) pub const ALOAD_0: &u8 = &42; // (0x2a)
// pub const aload_1:u8 = 43;// (0x2a) pub const ALOAD_1: &u8 = &43;// (0x2a)
// pub const aload_2:u8 = 44;// (0x2b) pub const ALOAD_2: &u8 = &44;// (0x2b)
// pub const aload_3:u8 = 45;// (0x2c) pub const ALOAD_3: &u8 = &45;// (0x2c)
// pub const faload: u8 = 48; // (0x30) Load float from array // pub const faload: u8 = 48; // (0x30) Load float from array
// pub const daload:u8 = 49; // (0x31) load double 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 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 getstatic: u8 = 178; // (0xb2) Get static field from class
pub const GETFIELD: &u8 = &180; // (0xb4) Fetch field from object3 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 INVOKEVIRTUAL: &u8 = &182; // (0xb6) Invoke instance method; dispatch based on class
pub const NEW: &u8 = &187; // (0xbb) Create new object pub const NEW: &u8 = &187; // (0xbb) Create new object
// //

113
src/vm.rs
View file

@ -13,12 +13,16 @@ use crate::opcodes::*;
#[derive(Debug)] #[derive(Debug)]
struct StackFrame { struct StackFrame {
at: String,
data: Vec<Arc<Value>>, data: Vec<Arc<Value>>,
} }
impl StackFrame { impl StackFrame {
fn new() -> Self { fn new(at_class: &str, at_method: &str) -> Self {
Self { data: vec![] } let mut at: String = at_class.into();
at.push('.');
at.push_str(at_method);
Self { at, data: vec![] }
} }
fn push(&mut self, val: Arc<Value>) { fn push(&mut self, val: Arc<Value>) {
@ -97,13 +101,13 @@ impl Vm {
&mut self, &mut self,
class_name: &str, class_name: &str,
method_name: &str, method_name: &str,
instance: Option<Arc<Value>>, args: Vec<Arc<Value>>,
) -> Result<Arc<Value>, Error> { ) -> Result<Arc<Value>, Error> {
println!("execute {}.{}", class_name, method_name); println!("execute {}.{}", class_name, method_name);
let class = self.get_class(class_name)?; let class = self.get_class(class_name)?;
let method = class.get_method(method_name)?; let method = class.get_method(method_name)?;
if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() { 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); self.stack.push(stackframe);
let mut pc: usize = 0; let mut pc: usize = 0;
@ -113,11 +117,13 @@ impl Vm {
println!("opcode {} ", opcode); println!("opcode {} ", opcode);
match opcode { match opcode {
BIPUSH => { BIPUSH => {
println!("BISPUSH");
let c = code.opcodes[pc] as i32; let c = code.opcodes[pc] as i32;
self.local_stack().push(Arc::new(Value::I32(c))); self.local_stack().push(Arc::new(Value::I32(c)));
pc += 1; pc += 1;
} }
LDC => { LDC => {
println!("LDC");
let cp_index = read_u8(&code.opcodes, pc) as u16; let cp_index = read_u8(&code.opcodes, pc) as u16;
match method.constant_pool.get(&cp_index).unwrap() { match method.constant_pool.get(&cp_index).unwrap() {
CpEntry::Integer(i) => { CpEntry::Integer(i) => {
@ -161,18 +167,36 @@ impl Vm {
pc += 2; 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 => { ALOAD_0 => {
println!("ALOAD_0"); println!("ALOAD_0");
match instance.clone() { self.local_stack().push(args[0].clone());
Some(instance) => {
self.local_stack().push(instance);
}
None => {
panic!("static context")
}
}
} }
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"); self.local_stack().pop().expect("Stack empty");
} }
DUP => { DUP => {
@ -218,11 +242,30 @@ impl Vm {
} }
pc += 2; 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 => { INVOKEVIRTUAL => {
let cp_index = read_u16(&code.opcodes, pc); 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) { 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? if let Void = *return_value {} else { // not let?
self.local_stack().push(return_value); self.local_stack().push(return_value);
} }
@ -233,9 +276,15 @@ impl Vm {
INVOKESPECIAL => { INVOKESPECIAL => {
println!("INVOKESPECIAL"); println!("INVOKESPECIAL");
let cp_index = read_u16(&code.opcodes, pc); 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) { 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? if let Void = *return_value {} else { // not let?
self.local_stack().push(return_value); self.local_stack().push(return_value);
} }
@ -275,7 +324,7 @@ impl Vm {
//TODO refs with lifetime //TODO refs with lifetime
fn get_signature_for_invoke(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<(String, String)> { fn get_signature_for_invoke(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<(String, (String, usize))> {
if let CpEntry::MethodRef(class_index, name_and_type_index) = cp.get(&index).unwrap() { 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 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() { if let CpEntry::ClassRef(class_name_index) = cp.get(class_index).unwrap() {
@ -288,15 +337,39 @@ fn get_signature_for_invoke(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option
None None
} }
fn get_name_and_type(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<String> { fn get_name_and_type(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<(String, usize)> {
if let CpEntry::NameAndType(method_name_index, signature_index) = cp.get(&index).unwrap() { 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(method_name) = cp.get(method_name_index).unwrap() {
if let CpEntry::Utf8(signature) = cp.get(signature_index).unwrap() { if let CpEntry::Utf8(signature) = cp.get(signature_index).unwrap() {
let mut method_signature: String = method_name.into(); let mut method_signature: String = method_name.into();
let num_args = get_hum_args(signature);
method_signature.push_str(signature); method_signature.push_str(signature);
return Some(method_signature);
return Some((method_signature, num_args));
} }
} }
} }
None None
} }
fn get_hum_args(signature: &str) -> usize {
let mut num = 0;
let mut i = 1;
let chars: Vec<char> = 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
}

Binary file not shown.

View file

@ -5,4 +5,8 @@ public class FloatBean {
public float getValue(){ public float getValue(){
return value; return value;
} }
public void setValue(float value){
this.value = value;
}
} }

Binary file not shown.

View file

@ -1,6 +1,6 @@
public class Main { public class Main {
public static void main(String[] args){ public static void main(String[] args){
new FloatBean().getValue(); new FloatBean().setValue(42F);
} }
} }