arguments in method calls
This commit is contained in:
parent
d4a0767c07
commit
fe8f9f1370
7 changed files with 107 additions and 29 deletions
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
//
|
//
|
||||||
|
|
|
||||||
105
src/vm.rs
105
src/vm.rs
|
|
@ -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,16 +167,34 @@ 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 => {
|
ALOAD_1 => {
|
||||||
panic!("static context")
|
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 => {
|
POP => {
|
||||||
self.local_stack().pop().expect("Stack empty");
|
self.local_stack().pop().expect("Stack empty");
|
||||||
|
|
@ -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.
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
tests/Main.class
BIN
tests/Main.class
Binary file not shown.
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue