stub native invoke, sugar, fmt

This commit is contained in:
Shautvast 2023-10-14 09:22:47 +02:00
parent 03732a3b73
commit 22a5ee8346
11 changed files with 348 additions and 187 deletions

View file

@ -32,16 +32,18 @@ pub struct Class {
}
impl Class {
pub fn new(minor_version: u16,
major_version: u16,
constant_pool: Rc<HashMap<u16, CpEntry>>,
access_flags: u16,
this_class: u16,
super_class_index: u16,
interface_indices: Vec<u16>,
fields: HashMap<String, Field>,
methods: HashMap<String, Method>,
attributes: HashMap<String, AttributeType>) -> Self {
pub fn new(
minor_version: u16,
major_version: u16,
constant_pool: Rc<HashMap<u16, CpEntry>>,
access_flags: u16,
this_class: u16,
super_class_index: u16,
interface_indices: Vec<u16>,
fields: HashMap<String, Field>,
methods: HashMap<String, Method>,
attributes: HashMap<String, AttributeType>,
) -> Self {
let name = Class::class_name(this_class, constant_pool.clone()).unwrap();
let super_class_name = Class::class_name(super_class_index, constant_pool.clone());
@ -88,10 +90,17 @@ impl Class {
}
// part of the initialize procedure
fn map_fields(field_mapping: &mut HashMap<String, HashMap<String, (String, usize)>>, class: &Class, field_map_index: &mut usize) {
fn map_fields(
field_mapping: &mut HashMap<String, HashMap<String, (String, usize)>>,
class: &Class,
field_map_index: &mut usize,
) {
let mut this_fields = HashMap::new(); //fields in class are stored per class and every superclass.
for field in &class.fields {
this_fields.insert(field.0.to_owned(), (field.1.type_of().to_owned(), *field_map_index)); //name => (type,index)
this_fields.insert(
field.0.to_owned(),
(field.1.type_of().to_owned(), *field_map_index),
); //name => (type,index)
*field_map_index += 1;
}
let this_name = class.name.to_owned();
@ -108,10 +117,14 @@ impl Class {
.ok_or(anyhow!("Method {} not found", name))
}
fn class_name(super_class_index: u16, constant_pool: Rc<HashMap<u16, CpEntry>>) -> Option<String> {
fn class_name(
super_class_index: u16,
constant_pool: Rc<HashMap<u16, CpEntry>>,
) -> Option<String> {
if super_class_index == 0 {
None
} else if let CpEntry::ClassRef(name_index) = constant_pool.get(&super_class_index).unwrap() {
} else if let CpEntry::ClassRef(name_index) = constant_pool.get(&super_class_index).unwrap()
{
if let CpEntry::Utf8(name) = constant_pool.get(name_index).unwrap() {
Some(name.to_owned())
} else {
@ -124,15 +137,30 @@ impl Class {
// convienence methods for data from the constantpool
pub fn get_field_ref(&self, index: &u16) -> Option<(&u16, &u16)> {
if let CpEntry::Fieldref(class_index, name_and_type_index) = self.constant_pool.get(index).unwrap() {
pub fn cp_field_ref(&self, index: &u16) -> Option<(&u16, &u16)> {
if let CpEntry::Fieldref(class_index, name_and_type_index) =
self.constant_pool.get(index).unwrap()
{
Some((class_index, name_and_type_index))
} else {
None
}
}
pub fn get_class_ref(&self, index: &u16) -> Option<&u16> {
/// both methodRef and InterfaceMethodRef
/// returns (class_index, name_and_type_index)
pub fn cp_method_ref(&self, index: &u16) -> Option<(&u16, &u16)> {
if let CpEntry::MethodRef(class_index, name_and_type_index)
| CpEntry::InterfaceMethodref(class_index, name_and_type_index) =
self.constant_pool.get(index).unwrap()
{
Some((class_index, name_and_type_index))
} else {
None
}
}
pub fn cp_class_ref(&self, index: &u16) -> Option<&u16> {
if let CpEntry::ClassRef(name_index) = self.constant_pool.get(index).unwrap() {
Some(name_index)
} else {
@ -140,7 +168,7 @@ impl Class {
}
}
pub fn get_utf8(&self, index: &u16) -> Option<&String> {
pub fn cp_utf8(&self, index: &u16) -> Option<&String> {
if let CpEntry::Utf8(utf8) = self.constant_pool.get(index).unwrap() {
Some(utf8)
} else {
@ -148,14 +176,14 @@ impl Class {
}
}
pub fn get_name_and_type(&self, index: &u16) -> Option<(&u16, &u16)> {
if let CpEntry::NameAndType(name_index, type_index) = self.constant_pool.get(index).unwrap(){
pub fn cp_name_and_type(&self, index: &u16) -> Option<(&u16, &u16)> {
if let CpEntry::NameAndType(name_index, type_index) = self.constant_pool.get(index).unwrap()
{
Some((name_index, type_index))
} else {
None
}
}
}
unsafe impl Send for Class {}
@ -208,6 +236,11 @@ impl Method {
full_name
}
pub fn is(&self, modifier: Modifier) -> bool {
let m = modifier as u16;
(self.access_flags & m) == m
}
}
pub struct Field {
@ -263,29 +296,34 @@ impl Field {
}
}
const MODIFIERS: [(u16, &str); 12] = [
(0x0001, "public "),
(0x0002, "private "),
(0x0004, "protected "),
(0x0008, "static "),
(0x0010, "final "),
(0x0020, "synchronized "),
(0x0040, "volatile "),
(0x0080, "transient "),
(0x0100, "native "),
(0x0200, "interface "),
(0x0400, "interface "),
(0x0800, "strict "),
const MODIFIERS: [(Modifier, &str); 12] = [
(Modifier::Public, "public "),
(Modifier::Private, "private "),
(Modifier::Protected, "protected "),
(Modifier::Static, "static "),
(Modifier::Final, "final "),
(Modifier::Synchronized, "synchronized "),
(Modifier::Volatile, "volatile "),
(Modifier::Transient, "transient "),
(Modifier::Native, "native "),
(Modifier::Abstract, "abstract"),
(Modifier::Strict, "strict"),
(Modifier::Synthetic, "synthetic"),
];
pub fn get_modifier(modifier: u16) -> String {
let mut output = String::new();
for m in MODIFIERS {
if modifier & m.0 == m.0 {
output.push_str(m.1)
}
}
output
pub enum Modifier {
Public = 0x0001,
Private = 0x0002,
Protected = 0x0004,
Static = 0x0008,
Final = 0x0010,
Synchronized = 0x0020,
Volatile = 0x0040,
Transient = 0x0080,
Native = 0x0100,
Abstract = 0x0400,
Strict = 0x0800,
Synthetic = 0x1000,
}
//TODO implement more types
@ -384,6 +422,20 @@ pub enum Value {
Ref(Arc<UnsafeCell<ObjectRef>>),
}
impl Value {
pub fn void() -> UnsafeValue {
Arc::new(UnsafeCell::new(Value::Void))
}
}
impl Into<UnsafeValue> for Value {
fn into(self) -> UnsafeValue {
Arc::new(UnsafeCell::new(self))
}
}
pub type UnsafeValue = Arc<UnsafeCell<Value>>;
unsafe impl Send for Value {}
unsafe impl Sync for Value {}

View file

@ -4,7 +4,6 @@ use anyhow::Error;
use std::collections::HashMap;
use std::rc::Rc;
// The native classoader
pub fn load_class(bytecode: Vec<u8>) -> Result<Class, Error> {
let pos = &mut 0;
@ -141,7 +140,7 @@ fn read_constant_pool_entry(cp_index: &mut u16, index: &mut usize, bytecode: &[u
let descriptor_index = read_u16(bytecode, index);
CpEntry::NameAndType(name_index, descriptor_index)
}
15 =>{
15 => {
let reference_kind = read_u8(bytecode, index);
let reference_index = read_u16(bytecode, index);
CpEntry::MethodHandle(reference_kind, reference_index)
@ -227,7 +226,7 @@ fn read_attribute(
*index += attribute_length;
if let CpEntry::Utf8(s) = &constant_pool.get(&attribute_name_index).unwrap() {
println!("Att [{}]", s);
// println!("Att [{}]", s);
return match s.as_str() {
"ConstantValue" => {
assert_eq!(info.len(), 2);
@ -251,8 +250,7 @@ fn read_attribute(
let attribute_count = read_u16(&info, ci);
let mut code_attributes = HashMap::new();
for _ in 0..attribute_count {
if let Some(att) = read_attribute(constant_pool.clone(), &info, ci)
{
if let Some(att) = read_attribute(constant_pool.clone(), &info, ci) {
code_attributes.insert(att.0, att.1);
}
}
@ -267,12 +265,14 @@ fn read_attribute(
))),
))
}
"SourceFile" => Some(("SourceFile".into(), AttributeType::SourceFile)),
"LineNumberTable" => Some(("SourceFile".into(), AttributeType::LineNumberTable)),
"RuntimeVisibleAnnotations" => Some(("".into(), AttributeType::RuntimeInvisibleAnnotations)), //stub
"NestMembers" => Some(("".into(), AttributeType::NestMembers)),//stub
"BootstrapMethods" => Some(("".into(), AttributeType::BootstrapMethods)),//stub
"InnerClasses" => Some(("".into(), AttributeType::InnerClasses)),//stub
"SourceFile" => Some(("SourceFile".into(), AttributeType::SourceFile)), //stub
"LineNumberTable" => Some(("SourceFile".into(), AttributeType::LineNumberTable)), //stub
"RuntimeVisibleAnnotations" => {
Some(("".into(), AttributeType::RuntimeInvisibleAnnotations))
} //stub
"NestMembers" => Some(("".into(), AttributeType::NestMembers)), //stub
"BootstrapMethods" => Some(("".into(), AttributeType::BootstrapMethods)), //stub
"InnerClasses" => Some(("".into(), AttributeType::InnerClasses)), //stub
//TODO more actual attribute implementations
_ => None,
};
@ -287,12 +287,12 @@ pub enum CpEntry {
Float(f32),
Long(i64),
Double(f64),
ClassRef(u16),
StringRef(u16),
Fieldref(u16, u16),
MethodRef(u16, u16),
InterfaceMethodref(u16, u16),
NameAndType(u16, u16),
ClassRef(u16), // (utf8)
StringRef(u16), // (utf8)
Fieldref(u16, u16), // (class, name_and_type)
MethodRef(u16, u16), // (class, name_and_type)
InterfaceMethodref(u16, u16), // (class, name_and_type)
NameAndType(u16, u16), // (name, descriptor)
MethodHandle(u8, u16),
MethodType(u16),
InvokeDynamic(u16, u16),

View file

@ -2,7 +2,7 @@ use std::cell::UnsafeCell;
use std::fmt;
use std::sync::Arc;
use crate::class::{Class, Value};
use crate::class::{Class, UnsafeValue, Value};
use crate::classloader::CpEntry;
// trying to implement efficient object instance storage
@ -10,8 +10,8 @@ pub struct Object {
// locked: bool,
// hashcode: i32,
pub class: Arc<Class>,
pub data: Vec<Arc<UnsafeCell<Value>>>,
}//arrays
pub data: Vec<UnsafeValue>,
} //arrays
// can contain object or array
#[derive(Debug)]
@ -36,11 +36,14 @@ unsafe impl Sync for Object {}
impl Object {
pub fn new(class: Arc<Class>) -> Self {
let instance_data = Object::init_fields(&class);
Self { class, data: instance_data}
Self {
class,
data: instance_data,
}
}
// initializes all non-static fields to their default values
pub(crate) fn init_fields(class: &Class) -> Vec<Arc<UnsafeCell<Value>>>{
pub(crate) fn init_fields(class: &Class) -> Vec<UnsafeValue> {
let mut field_data = Vec::with_capacity(class.n_fields());
for (_, fields) in class.field_mapping.as_ref().unwrap() {
@ -56,20 +59,36 @@ impl Object {
"L" => Value::Null,
_ => Value::Void,
};
field_data.push(Arc::new(UnsafeCell::new(value)));
field_data.push(value.into());
}
}
field_data
}
pub fn set(&mut self, class_name: &String, field_name: &String, value: Arc<UnsafeCell<Value>>) {
let (_type, index) = self.class.field_mapping.as_ref().unwrap().get(class_name).unwrap().get(field_name).unwrap();
pub fn set(&mut self, class_name: &String, field_name: &String, value: UnsafeValue) {
let (_type, index) = self
.class
.field_mapping
.as_ref()
.unwrap()
.get(class_name)
.unwrap()
.get(field_name)
.unwrap();
self.data[*index] = value;
}
pub fn get(&mut self, class_name: &String, field_name: &String) -> &Arc<UnsafeCell<Value>> {
let (_type, index) = &self.class.field_mapping.as_ref().unwrap().get(class_name).unwrap().get(field_name).unwrap();
pub fn get(&mut self, class_name: &String, field_name: &String) -> &UnsafeValue {
let (_type, index) = &self
.class
.field_mapping
.as_ref()
.unwrap()
.get(class_name)
.unwrap()
.get(field_name)
.unwrap();
&self.data[*index]
}
@ -90,11 +109,7 @@ impl fmt::Debug for Object {
// // r
// }
// ).collect();
write!(
f,
"{}",
self.class.name
)
write!(f, "{}", self.class.name)
}
}

View file

@ -53,7 +53,6 @@ pub fn read_bytecode(name: String) -> Result<Vec<u8>, Error> {
Ok(buffer)
}
// methods to read values from big-endian binary data
pub(crate) fn read_u8(data: &[u8], pos: &mut usize) -> u8 {
@ -125,4 +124,3 @@ pub(crate) fn read_f64(data: &[u8], pos: &mut usize) -> f64 {
.expect("slice with incorrect length"),
)
}

View file

@ -4,3 +4,5 @@ mod heap;
pub mod io;
pub mod opcodes;
pub mod vm;
pub mod native;

View file

@ -6,7 +6,7 @@ fn main() -> Result<(), Error> {
// TODO build index for package -> jarfile?
let mut vm = Vm::new("tests");
let main_class = "Main";
let main_class = "Inheritance";
vm.execute(main_class, "main([Ljava/lang/String;)V", vec![])
.unwrap();

8
src/native.rs Normal file
View file

@ -0,0 +1,8 @@
use std::sync::Arc;
use crate::class::{Class, Method, UnsafeValue, Value};
pub fn invoke_native(class: Arc<Class>, method: &Method) -> UnsafeValue {
println!("invoke native {:?}.{:?}", class.name, method.name());
Value::void()
}

View file

@ -7,13 +7,13 @@ pub const ICONST_2: u8 = 5; // (0x5) Push int constant 2
pub const ICONST_3: u8 = 6; // (0x6) Push int constant 3
pub const ICONST_4: u8 = 7; // (0x7) Push int constant 4
pub const ICONST_5: u8 = 8; // (0x8) Push int constant 5
pub const LCONST_0: u8 = 9; // (0x9) Push long constant 0
pub const LCONST_1: u8 = 10; // (0xa) Push long constant 1
pub const LCONST_0: u8 = 9; // (0x9) Push long constant 0
pub const LCONST_1: u8 = 10; // (0xa) Push long constant 1
pub const FCONST_0: u8 = 11; // (0xb) Push float 0
pub const FCONST_1: u8 = 12; // (0xc) Push float 1
pub const FCONST_2: u8 = 13; // (0xd) Push float 2
pub const DCONST_0 :u8 = 14; // (0xe) push double 0
pub const DCONST_1 :u8 = 15; // (0xe) push double 1
pub const DCONST_0: u8 = 14; // (0xe) push double 0
pub const DCONST_1: u8 = 15; // (0xe) push double 1
pub const BIPUSH: u8 = 16; // (0x10) Push byte
pub const SIPUSH: u8 = 17; // (0x11) Push short
pub const LDC: u8 = 18; // (0x12) Push item from run-time pub constant pool
@ -87,51 +87,51 @@ pub const CASTORE: u8 = 85; // (0x55) Store into char array
pub const SASTORE: u8 = 86; // (0x56) Store into short array
pub const POP: u8 = 87; // (0x57) Pop the top operand stack value
pub const DUP: u8 = 89; // (0x59) duplicate the top operand stack value
// pub const dup_x1: u8 = 90; // (0x5a) Duplicate the top operand stack value and insert two values down
// pub const dup_x2: u8 = 91; // (0x5b) Duplicate the top operand stack value and insert two or three values down
// pub const dup2: u8 = 92; // (0x5c) Duplicate the top one or two operand stack values
// pub const dup2_x1: u8 = 93; //(0x5d) Duplicate the top one or two operand stack values and insert two or three values down
// pub const dup2_x2:u8 = 94; // (0x5e) Duplicate the top one or two operand stack values and insert two, three, or four values down
// pub const fadd: u8 = 98; // (0x62) Add float
// pub const dadd: u8 = 99; // (0x63) add double
//
// pub const dsub:u8 = 103; // (0x67) subtract double
// pub const fmul: u8 = 106; // (0x6a) Multiply float
// pub const dmul: u8 = 107; // (0x6b) Multiply double
//
// pub const fdiv: u8 = 110; // (0x6e) Divide float
// pub const ddiv:u8 = 111; // (0x6f) divide double
// pub const frem: u8 = 114; // (0x72) Remainder float
// pub const drem: u8 = 115; // (0x73) remainder double
// pub const fneg: u8 = 118; // (0x76) Negate float
// pub const dneg: u8 = 119; // (0x77) Negate double
// pub const f2i: u8 = 139; // (0x8b) Convert float to int
// pub const f2l: u8 = 140; // (0x8c) Convert float to long
// pub const f2d: u8 = 141; // (0x8d) Convert float to double
// pub const d2i:u8 = 142; // (0x8e) double to int
// pub const d2l:u8 = 143; // (0x8f) double to long
// pub const d2f: u8 = 144; // (0x90) double to float
// pub const fcmpl:u8 = 149; // (0x95) Compare float (less than)
// pub const fcmpg: u8 = 150; // (0x96) Compare float (greater than)
// pub const dcmpl:u8 = 151; // (0x97) compare double (less than)
// pub const dcmpg:u8 = 152; // (0x98) compare double (greater than)
//
pub const dup_x1: u8 = 90; // (0x5a) Duplicate the top operand stack value and insert two values down
pub const dup_x2: u8 = 91; // (0x5b) Duplicate the top operand stack value and insert two or three values down
pub const dup2: u8 = 92; // (0x5c) Duplicate the top one or two operand stack values
pub const dup2_x1: u8 = 93; //(0x5d) Duplicate the top one or two operand stack values and insert two or three values down
pub const dup2_x2: u8 = 94; // (0x5e) Duplicate the top one or two operand stack values and insert two, three, or four values down
pub const fadd: u8 = 98; // (0x62) Add float
pub const dadd: u8 = 99; // (0x63) add double
pub const dsub: u8 = 103; // (0x67) subtract double
pub const fmul: u8 = 106; // (0x6a) Multiply float
pub const dmul: u8 = 107; // (0x6b) Multiply double
pub const fdiv: u8 = 110; // (0x6e) Divide float
pub const ddiv: u8 = 111; // (0x6f) divide double
pub const frem: u8 = 114; // (0x72) Remainder float
pub const drem: u8 = 115; // (0x73) remainder double
pub const fneg: u8 = 118; // (0x76) Negate float
pub const dneg: u8 = 119; // (0x77) Negate double
pub const f2i: u8 = 139; // (0x8b) Convert float to int
pub const f2l: u8 = 140; // (0x8c) Convert float to long
pub const f2d: u8 = 141; // (0x8d) Convert float to double
pub const d2i: u8 = 142; // (0x8e) double to int
pub const d2l: u8 = 143; // (0x8f) double to long
pub const d2f: u8 = 144; // (0x90) double to float
pub const fcmpl: u8 = 149; // (0x95) Compare float (less than)
pub const fcmpg: u8 = 150; // (0x96) Compare float (greater than)
pub const dcmpl: u8 = 151; // (0x97) compare double (less than)
pub const dcmpg: u8 = 152; // (0x98) compare double (greater than)
pub const IRETURN: u8 = 172; // (0xac) ireturn
pub const FRETURN: u8 = 174; // (0xae) Return float from method
pub const DRETURN: u8 = 175; // (0xaf) Return double from method
// pub const areturn: u8 = 176; //(0xb0) return reference
pub const areturn: u8 = 176; //(0xb0) return reference
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
//
pub const INVOKESPECIAL: u8 = 183; // (0xb7) // nvoke instance method; direct invocation of instance initialization methods and methods of the current class and its supertypes
// pub const anewarray: u8 = 189; // (0xbd)
//
// pub const arraylength: u8 = 190; // (0xbe)
//
// pub const athrow: u8 = 191; // (0xbf)
//
// pub const checkcast: u8 = 192; // (0xc0)
pub const INVOKESTATIC: u8 = 184; // (0xb8) Invoke a class (static) method
pub const NEW: u8 = 187; // (0xbb) Create new object
pub const anewarray: u8 = 189; // (0xbd)
pub const arraylength: u8 = 190; // (0xbe)
pub const athrow: u8 = 191; // (0xbf)
pub const checkcast: u8 = 192; // (0xc0)

195
src/vm.rs
View file

@ -6,17 +6,18 @@ use std::sync::Arc;
use anyhow::{anyhow, Error};
use once_cell::unsync::Lazy;
use crate::class::{AttributeType, Class, Value};
use crate::class::Value::Void;
use crate::classloader::{CpEntry, load_class};
use crate::class::{AttributeType, Class, Modifier, UnsafeValue, Value};
use crate::classloader::{load_class, CpEntry};
use crate::heap::{Heap, Object, ObjectRef};
use crate::io::*;
use crate::native::invoke_native;
use crate::opcodes::*;
#[derive(Debug)]
struct StackFrame {
at: String,
data: Vec<Arc<UnsafeCell<Value>>>,
data: Vec<UnsafeValue>,
}
// maybe just call frame
@ -32,11 +33,11 @@ impl StackFrame {
self.data.push(Arc::new(UnsafeCell::new(val)));
}
fn push_arc(&mut self, val: Arc<UnsafeCell<Value>>) {
fn push_arc(&mut self, val: UnsafeValue) {
self.data.push(val);
}
fn pop(&mut self) -> Result<Arc<UnsafeCell<Value>>, Error> {
fn pop(&mut self) -> Result<UnsafeValue, Error> {
Ok(self.data.pop().unwrap())
}
}
@ -67,7 +68,10 @@ impl Vm {
pub fn new(classpath: &'static str) -> Self {
Self {
classpath: classpath.split(PATH_SEPARATOR).map(|s| s.to_owned()).collect(),
classpath: classpath
.split(PATH_SEPARATOR)
.map(|s| s.to_owned())
.collect(),
heap: Heap::new(),
stack: vec![],
}
@ -81,7 +85,7 @@ impl Vm {
unsafe {
let entry = CLASSDEFS.entry(class_name.into());
let entry = entry.or_insert_with(|| {
// print!("read class {} ", class_name);
println!("read class {} ", class_name);
let resolved_path = find_class(&self.classpath, class_name).unwrap();
// println!("full path {}", resolved_path);
let bytecode = read_bytecode(resolved_path).unwrap();
@ -106,19 +110,31 @@ impl Vm {
instance
}
/// execute the bytecode
/// contains unsafe, as I think that mimics not-synchronized memory access in the original JVM
pub fn execute(
&mut self,
class_name: &str,
method_name: &str,
args: Vec<Arc<UnsafeCell<Value>>>,
) -> Result<Arc<UnsafeCell<Value>>, Error> {
let mut local_params: Vec<Option<Arc<UnsafeCell<Value>>>> = args.clone().iter().map(|e| Some(e.clone())).collect();
args: Vec<UnsafeValue>,
) -> Result<UnsafeValue, Error> {
let mut local_params: Vec<Option<UnsafeValue>> =
args.clone().iter().map(|e| Some(e.clone())).collect();
println!("execute {}.{}", class_name, method_name);
let class = self.get_class(class_name)?;
let method = class.get_method(method_name)?;
if method.is(Modifier::Native) {
let return_value = invoke_native(class.clone(), method);
unsafe {
match *return_value.get() {
Void => {}
_ => {
self.local_stack().push_arc(return_value.clone());
}
}
}
}
if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() {
let stackframe = StackFrame::new(class_name, method_name);
self.stack.push(stackframe);
@ -221,25 +237,31 @@ impl Vm {
}
}
}
ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => { // omitting the type checks so far
ILOAD | LLOAD | FLOAD | DLOAD | ALOAD => {
// omitting the type checks so far
let n = read_u8(&code.opcodes, pc) as usize;
self.local_stack().push_arc(local_params[n].as_ref().unwrap().clone());
self.local_stack()
.push_arc(local_params[n].as_ref().unwrap().clone());
}
ILOAD_0 | LLOAD_0 | FLOAD_0 | DLOAD_0 | ALOAD_0 => {
self.local_stack().push_arc(local_params[0].as_ref().unwrap().clone());
self.local_stack()
.push_arc(local_params[0].as_ref().unwrap().clone());
}
ILOAD_1 | LLOAD_1 | FLOAD_1 | DLOAD_1 | ALOAD_1 => {
self.local_stack().push_arc(local_params[1].as_ref().unwrap().clone());
self.local_stack()
.push_arc(local_params[1].as_ref().unwrap().clone());
}
ILOAD_2 | LLOAD_2 | FLOAD_2 | DLOAD_2 | ALOAD_2 => {
self.local_stack().push_arc(local_params[2].as_ref().unwrap().clone());
self.local_stack()
.push_arc(local_params[2].as_ref().unwrap().clone());
}
ILOAD_3 | LLOAD_3 | FLOAD_3 | DLOAD_3 | ALOAD_3 => {
self.local_stack().push_arc(local_params[3].as_ref().unwrap().clone());
self.local_stack()
.push_arc(local_params[3].as_ref().unwrap().clone());
}
IALOAD | LALOAD | FALOAD | DALOAD | AALOAD | BALOAD | CALOAD | SALOAD => unsafe {
self.array_load()?;
}
},
ISTORE | LSTORE | FSTORE | DSTORE | ASTORE => {
let index = read_u8(&code.opcodes, pc) as usize;
self.store(&mut local_params, index)?;
@ -256,7 +278,8 @@ impl Vm {
ISTORE_3 | LSTORE_3 | DSTORE_3 | ASTORE_3 | FSTORE_3 => {
self.store(&mut local_params, 3)?;
}
BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE | AASTORE => unsafe { self.array_store()? }
BASTORE | IASTORE | LASTORE | CASTORE | SASTORE | FASTORE | DASTORE
| AASTORE => unsafe { self.array_store()? },
POP => {
self.local_stack().pop()?;
}
@ -271,41 +294,44 @@ impl Vm {
}
RETURN_VOID => {
self.stack.pop(); // Void is also returned as a value
return Ok(Arc::new(UnsafeCell::new(Void)));
return Ok(Value::void());
}
GETSTATIC => {
let cp_index = read_u16(&code.opcodes, pc);
let (class_index, _field_name_and_type_index) = class.get_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid
let class_name_index = class.get_class_ref(class_index).unwrap();
let class_name = class.get_utf8(class_name_index).unwrap();
let (class_index, _field_name_and_type_index) =
class.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid
let class_name_index = class.cp_class_ref(class_index).unwrap();
let class_name = class.cp_utf8(class_name_index).unwrap();
let class = self.get_class(class_name.as_str())?;
println!("{:?}", class); //TODO
// println!("{:?}", class); //TODO
}
GETFIELD => {
unsafe {
let cp_index = read_u16(&code.opcodes, pc);
let (class_index, field_name_and_type_index) = class.get_field_ref(&cp_index).unwrap();
let (field_name_index, _) = class.get_name_and_type(field_name_and_type_index).unwrap();
let class_name_index = class.get_class_ref(class_index).unwrap();
let class_name = class.get_utf8(class_name_index).unwrap();
let field_name = class.get_utf8(field_name_index).unwrap();
GETFIELD => unsafe {
let cp_index = read_u16(&code.opcodes, pc);
let (class_index, field_name_and_type_index) =
class.cp_field_ref(&cp_index).unwrap();
let (field_name_index, _) =
class.cp_name_and_type(field_name_and_type_index).unwrap();
let class_name_index = class.cp_class_ref(class_index).unwrap();
let class_name = class.cp_utf8(class_name_index).unwrap();
let field_name = class.cp_utf8(field_name_index).unwrap();
let mut objectref = self.local_stack().pop()?;
if let Value::Ref(instance) = &mut *objectref.get() {
if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
let value = object.get(class_name, field_name);
self.local_stack().push_arc(Arc::clone(value));
}
let mut objectref = self.local_stack().pop()?;
if let Value::Ref(instance) = &mut *objectref.get() {
if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
let value = object.get(class_name, field_name);
self.local_stack().push_arc(Arc::clone(value));
}
}
}
},
PUTFIELD => unsafe {
let cp_index = read_u16(&code.opcodes, pc);
let (class_index, field_name_and_type_index) = class.get_field_ref(&cp_index).unwrap();
let (field_name_index, _) = class.get_name_and_type(field_name_and_type_index).unwrap();
let class_name_index = class.get_class_ref(class_index).unwrap();
let class_name = class.get_utf8(class_name_index).unwrap();
let field_name = class.get_utf8(field_name_index).unwrap();
let (class_index, field_name_and_type_index) =
class.cp_field_ref(&cp_index).unwrap();
let (field_name_index, _) =
class.cp_name_and_type(field_name_and_type_index).unwrap();
let class_name_index = class.cp_class_ref(class_index).unwrap();
let class_name = class.cp_utf8(class_name_index).unwrap();
let field_name = class.cp_utf8(field_name_index).unwrap();
let value = self.local_stack().pop()?;
let mut objectref = self.local_stack().pop()?;
@ -314,29 +340,61 @@ impl Vm {
object.set(class_name, field_name, value);
}
}
}
},
INVOKEVIRTUAL | INVOKESPECIAL => unsafe {
let cp_index = read_u16(&code.opcodes, pc);
if let Some(invocation) = get_signature_for_invoke(&method.constant_pool, cp_index) {
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, self.local_stack().pop()?);
}
args.insert(0, self.local_stack().pop()?);
let mut returnvalue = self.execute(&invocation.class_name, &invocation.method.name, args)?;
match *returnvalue.get() {
let mut return_value = self.execute(
&invocation.class_name,
&invocation.method.name,
args,
)?;
match *return_value.get() {
Void => {}
_ => { self.local_stack().push_arc(returnvalue.clone()); }
_ => {
self.local_stack().push_arc(return_value.clone());
}
}
}
}
},
INVOKESTATIC => unsafe {
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, self.local_stack().pop()?);
}
let mut returnvalue = self.execute(
&invocation.class_name,
&invocation.method.name,
args,
)?;
match *returnvalue.get() {
Void => {}
_ => {
self.local_stack().push_arc(returnvalue.clone());
}
}
}
},
NEW => {
let class_index = &read_u16(&code.opcodes, pc);
let class_name_index = class.get_class_ref(class_index).unwrap();
let class_name = class.get_utf8(class_name_index).unwrap();
let class_name_index = class.cp_class_ref(class_index).unwrap();
let class_name = class.cp_utf8(class_name_index).unwrap();
let class = self.get_class(class_name)?;
let object = Arc::new(UnsafeCell::new(ObjectRef::Object(Box::new(Vm::new_instance(class)))));
let object = Arc::new(UnsafeCell::new(ObjectRef::Object(Box::new(
Vm::new_instance(class),
))));
self.local_stack().push(Value::Ref(Arc::clone(&object)));
self.heap.new_object(object);
}
@ -386,7 +444,8 @@ impl Vm {
self.local_stack().push(Value::F64(array[index]));
}
ObjectRef::ObjectArray(ref array) => {
self.local_stack().push(Value::Ref(array.get(index).unwrap().clone()));
self.local_stack()
.push(Value::Ref(array.get(index).unwrap().clone()));
}
ObjectRef::Object(_) => {} //throw error?
}
@ -408,12 +467,14 @@ impl Vm {
if let Value::Ref(ref mut objectref) = arrayref {
match &mut *objectref.get() {
ObjectRef::ByteArray(ref mut array) => {
if let Value::I32(value) = *value.get() { // is i32 correct?
if let Value::I32(value) = *value.get() {
// is i32 correct?
array[*index as usize] = value as i8;
}
}
ObjectRef::ShortArray(ref mut array) => {
if let Value::I32(value) = *value.get() { // is i32 correct?
if let Value::I32(value) = *value.get() {
// is i32 correct?
array[*index as usize] = value as i16;
}
}
@ -452,14 +513,18 @@ impl Vm {
array[*index as usize] = value.clone();
}
}
ObjectRef::Object(_) => {}//throw error?
ObjectRef::Object(_) => {} //throw error?
}
}
}
Ok(())
}
fn store(&mut self, local_params: &mut Vec<Option<Arc<UnsafeCell<Value>>>>, index: usize) -> Result<(), Error> {
fn store(
&mut self,
local_params: &mut Vec<Option<UnsafeValue>>,
index: usize,
) -> Result<(), Error> {
let value = self.local_stack().pop()?;
while local_params.len() < index + 1 {
local_params.push(None);
@ -469,7 +534,6 @@ impl Vm {
}
}
struct Invocation {
class_name: String,
method: MethodSignature,
@ -480,8 +544,11 @@ struct MethodSignature {
num_args: usize,
}
// TODO can be simplified now, using cp_ methods in Class
fn get_signature_for_invoke(cp: &Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<Invocation> {
if let CpEntry::MethodRef(class_index, name_and_type_index) = cp.get(&index).unwrap() {
if let CpEntry::MethodRef(class_index, name_and_type_index)
| CpEntry::InterfaceMethodref(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() {
if let CpEntry::Utf8(class_name) = cp.get(class_name_index).unwrap() {
@ -503,14 +570,16 @@ fn get_name_and_type(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<Method
let mut method_signature: String = method_name.into();
let num_args = get_hum_args(signature);
method_signature.push_str(signature);
return Some(MethodSignature { name: method_signature, num_args });
return Some(MethodSignature {
name: method_signature,
num_args,
});
}
}
}
None
}
fn get_hum_args(signature: &str) -> usize {
let mut num = 0;
let mut i = 1;
@ -531,4 +600,4 @@ fn get_hum_args(signature: &str) -> usize {
}
}
num
}
}

View file

@ -1,8 +1,6 @@
mod test {
use classfile_reader::class::Value;
use classfile_reader::vm::Vm;
use classfile_reader::{classloader::load_class, io};
use std::rc::Rc;
use java_rs::class::Value;
use java_rs::vm::Vm;
use std::sync::Arc;
#[test]

19
tests/method_tests.rs Normal file
View file

@ -0,0 +1,19 @@
mod test {
use java_rs::class::{Method, Modifier};
use std::collections::HashMap;
use std::rc::Rc;
#[test]
fn access_flags() {
let m = Method::new(
Rc::new(HashMap::new()),
Modifier::Public as u16 | Modifier::Static as u16,
0,
0,
HashMap::new(),
);
assert!(m.is(Modifier::Public));
assert!(m.is(Modifier::Static));
assert!(!m.is(Modifier::Private));
}
}