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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,7 +6,7 @@ fn main() -> Result<(), Error> {
// TODO build index for package -> jarfile? // TODO build index for package -> jarfile?
let mut vm = Vm::new("tests"); let mut vm = Vm::new("tests");
let main_class = "Main"; let main_class = "Inheritance";
vm.execute(main_class, "main([Ljava/lang/String;)V", vec![]) vm.execute(main_class, "main([Ljava/lang/String;)V", vec![])
.unwrap(); .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_3: u8 = 6; // (0x6) Push int constant 3
pub const ICONST_4: u8 = 7; // (0x7) Push int constant 4 pub const ICONST_4: u8 = 7; // (0x7) Push int constant 4
pub const ICONST_5: u8 = 8; // (0x8) Push int constant 5 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_0: u8 = 9; // (0x9) Push long constant 0
pub const LCONST_1: u8 = 10; // (0xa) Push long constant 1 pub const LCONST_1: u8 = 10; // (0xa) Push long constant 1
pub const FCONST_0: u8 = 11; // (0xb) Push float 0 pub const FCONST_0: u8 = 11; // (0xb) Push float 0
pub const FCONST_1: u8 = 12; // (0xc) Push float 1 pub const FCONST_1: u8 = 12; // (0xc) Push float 1
pub const FCONST_2: u8 = 13; // (0xd) Push float 2 pub const FCONST_2: u8 = 13; // (0xd) Push float 2
pub const DCONST_0 :u8 = 14; // (0xe) push double 0 pub const DCONST_0: u8 = 14; // (0xe) push double 0
pub const DCONST_1 :u8 = 15; // (0xe) push double 1 pub const DCONST_1: u8 = 15; // (0xe) push double 1
pub const BIPUSH: u8 = 16; // (0x10) Push byte pub const BIPUSH: u8 = 16; // (0x10) Push byte
pub const SIPUSH: u8 = 17; // (0x11) Push short pub const SIPUSH: u8 = 17; // (0x11) Push short
pub const LDC: u8 = 18; // (0x12) Push item from run-time pub constant pool 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 SASTORE: u8 = 86; // (0x56) Store into short array
pub const POP: u8 = 87; // (0x57) Pop the top operand stack value 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: 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_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 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: 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_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 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 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 dsub: u8 = 103; // (0x67) subtract double
// pub const dmul: u8 = 107; // (0x6b) Multiply 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 fdiv: u8 = 110; // (0x6e) Divide float
// pub const frem: u8 = 114; // (0x72) Remainder float pub const ddiv: u8 = 111; // (0x6f) divide double
// pub const drem: u8 = 115; // (0x73) remainder double pub const frem: u8 = 114; // (0x72) Remainder float
// pub const fneg: u8 = 118; // (0x76) Negate float pub const drem: u8 = 115; // (0x73) remainder double
// pub const dneg: u8 = 119; // (0x77) Negate double pub const fneg: u8 = 118; // (0x76) Negate float
// pub const f2i: u8 = 139; // (0x8b) Convert float to int pub const dneg: u8 = 119; // (0x77) Negate double
// pub const f2l: u8 = 140; // (0x8c) Convert float to long
// pub const f2d: u8 = 141; // (0x8d) Convert float to double pub const f2i: u8 = 139; // (0x8b) Convert float to int
// pub const d2i:u8 = 142; // (0x8e) double to int pub const f2l: u8 = 140; // (0x8c) Convert float to long
// pub const d2l:u8 = 143; // (0x8f) double to long pub const f2d: u8 = 141; // (0x8d) Convert float to double
// pub const d2f: u8 = 144; // (0x90) double to float pub const d2i: u8 = 142; // (0x8e) double to int
// pub const fcmpl:u8 = 149; // (0x95) Compare float (less than) pub const d2l: u8 = 143; // (0x8f) double to long
// pub const fcmpg: u8 = 150; // (0x96) Compare float (greater than) pub const d2f: u8 = 144; // (0x90) double to float
// pub const dcmpl:u8 = 151; // (0x97) compare double (less than)
// pub const dcmpg:u8 = 152; // (0x98) compare double (greater than) 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 IRETURN: u8 = 172; // (0xac) ireturn
pub const FRETURN: u8 = 174; // (0xae) Return float from method pub const FRETURN: u8 = 174; // (0xae) Return float from method
pub const DRETURN: u8 = 175; // (0xaf) Return double 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 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 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 INVOKESPECIAL: u8 = 183; // (0xb7) // nvoke instance method; direct invocation of instance initialization methods and methods of the current class and its supertypes 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 INVOKESTATIC: u8 = 184; // (0xb8) Invoke a class (static) method
// pub const NEW: u8 = 187; // (0xbb) Create new object
// pub const arraylength: u8 = 190; // (0xbe) pub const anewarray: u8 = 189; // (0xbd)
// pub const arraylength: u8 = 190; // (0xbe)
// pub const athrow: u8 = 191; // (0xbf) pub const athrow: u8 = 191; // (0xbf)
// pub const checkcast: u8 = 192; // (0xc0)
// 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 anyhow::{anyhow, Error};
use once_cell::unsync::Lazy; use once_cell::unsync::Lazy;
use crate::class::{AttributeType, Class, Value};
use crate::class::Value::Void; 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::heap::{Heap, Object, ObjectRef};
use crate::io::*; use crate::io::*;
use crate::native::invoke_native;
use crate::opcodes::*; use crate::opcodes::*;
#[derive(Debug)] #[derive(Debug)]
struct StackFrame { struct StackFrame {
at: String, at: String,
data: Vec<Arc<UnsafeCell<Value>>>, data: Vec<UnsafeValue>,
} }
// maybe just call frame // maybe just call frame
@ -32,11 +33,11 @@ impl StackFrame {
self.data.push(Arc::new(UnsafeCell::new(val))); 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); 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()) Ok(self.data.pop().unwrap())
} }
} }
@ -67,7 +68,10 @@ impl Vm {
pub fn new(classpath: &'static str) -> Self { pub fn new(classpath: &'static str) -> Self {
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(), heap: Heap::new(),
stack: vec![], stack: vec![],
} }
@ -81,7 +85,7 @@ impl Vm {
unsafe { unsafe {
let entry = CLASSDEFS.entry(class_name.into()); let entry = CLASSDEFS.entry(class_name.into());
let entry = entry.or_insert_with(|| { 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(); let resolved_path = find_class(&self.classpath, class_name).unwrap();
// println!("full path {}", resolved_path); // println!("full path {}", resolved_path);
let bytecode = read_bytecode(resolved_path).unwrap(); let bytecode = read_bytecode(resolved_path).unwrap();
@ -106,19 +110,31 @@ impl Vm {
instance instance
} }
/// execute the bytecode /// execute the bytecode
/// contains unsafe, as I think that mimics not-synchronized memory access in the original JVM /// contains unsafe, as I think that mimics not-synchronized memory access in the original JVM
pub fn execute( pub fn execute(
&mut self, &mut self,
class_name: &str, class_name: &str,
method_name: &str, method_name: &str,
args: Vec<Arc<UnsafeCell<Value>>>, args: Vec<UnsafeValue>,
) -> Result<Arc<UnsafeCell<Value>>, Error> { ) -> Result<UnsafeValue, Error> {
let mut local_params: Vec<Option<Arc<UnsafeCell<Value>>>> = args.clone().iter().map(|e| Some(e.clone())).collect(); let mut local_params: Vec<Option<UnsafeValue>> =
args.clone().iter().map(|e| Some(e.clone())).collect();
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 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() { if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() {
let stackframe = StackFrame::new(class_name, method_name); let stackframe = StackFrame::new(class_name, method_name);
self.stack.push(stackframe); 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; 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 => { 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 => { 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 => { 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 => { 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 { IALOAD | LALOAD | FALOAD | DALOAD | AALOAD | BALOAD | CALOAD | SALOAD => unsafe {
self.array_load()?; self.array_load()?;
} },
ISTORE | LSTORE | FSTORE | DSTORE | ASTORE => { ISTORE | LSTORE | FSTORE | DSTORE | ASTORE => {
let index = read_u8(&code.opcodes, pc) as usize; let index = read_u8(&code.opcodes, pc) as usize;
self.store(&mut local_params, index)?; self.store(&mut local_params, index)?;
@ -256,7 +278,8 @@ impl Vm {
ISTORE_3 | LSTORE_3 | DSTORE_3 | ASTORE_3 | FSTORE_3 => { ISTORE_3 | LSTORE_3 | DSTORE_3 | ASTORE_3 | FSTORE_3 => {
self.store(&mut local_params, 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 => { POP => {
self.local_stack().pop()?; self.local_stack().pop()?;
} }
@ -271,41 +294,44 @@ impl Vm {
} }
RETURN_VOID => { RETURN_VOID => {
self.stack.pop(); // Void is also returned as a value self.stack.pop(); // Void is also returned as a value
return Ok(Arc::new(UnsafeCell::new(Void))); return Ok(Value::void());
} }
GETSTATIC => { GETSTATIC => {
let cp_index = read_u16(&code.opcodes, pc); 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_index, _field_name_and_type_index) =
let class_name_index = class.get_class_ref(class_index).unwrap(); class.cp_field_ref(&cp_index).unwrap(); // all these unwraps are safe as long as the class is valid
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.as_str())?; let class = self.get_class(class_name.as_str())?;
println!("{:?}", class); //TODO // println!("{:?}", class); //TODO
} }
GETFIELD => { GETFIELD => unsafe {
unsafe { let cp_index = read_u16(&code.opcodes, pc);
let cp_index = read_u16(&code.opcodes, pc); let (class_index, field_name_and_type_index) =
let (class_index, field_name_and_type_index) = class.get_field_ref(&cp_index).unwrap(); class.cp_field_ref(&cp_index).unwrap();
let (field_name_index, _) = class.get_name_and_type(field_name_and_type_index).unwrap(); let (field_name_index, _) =
let class_name_index = class.get_class_ref(class_index).unwrap(); class.cp_name_and_type(field_name_and_type_index).unwrap();
let class_name = class.get_utf8(class_name_index).unwrap(); let class_name_index = class.cp_class_ref(class_index).unwrap();
let field_name = class.get_utf8(field_name_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()?; let mut objectref = self.local_stack().pop()?;
if let Value::Ref(instance) = &mut *objectref.get() { if let Value::Ref(instance) = &mut *objectref.get() {
if let ObjectRef::Object(ref mut object) = &mut *instance.get() { if let ObjectRef::Object(ref mut object) = &mut *instance.get() {
let value = object.get(class_name, field_name); let value = object.get(class_name, field_name);
self.local_stack().push_arc(Arc::clone(value)); self.local_stack().push_arc(Arc::clone(value));
}
} }
} }
} },
PUTFIELD => unsafe { PUTFIELD => unsafe {
let cp_index = read_u16(&code.opcodes, pc); let cp_index = read_u16(&code.opcodes, pc);
let (class_index, field_name_and_type_index) = class.get_field_ref(&cp_index).unwrap(); let (class_index, field_name_and_type_index) =
let (field_name_index, _) = class.get_name_and_type(field_name_and_type_index).unwrap(); class.cp_field_ref(&cp_index).unwrap();
let class_name_index = class.get_class_ref(class_index).unwrap(); let (field_name_index, _) =
let class_name = class.get_utf8(class_name_index).unwrap(); class.cp_name_and_type(field_name_and_type_index).unwrap();
let field_name = class.get_utf8(field_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 field_name = class.cp_utf8(field_name_index).unwrap();
let value = self.local_stack().pop()?; let value = self.local_stack().pop()?;
let mut objectref = self.local_stack().pop()?; let mut objectref = self.local_stack().pop()?;
@ -314,29 +340,61 @@ impl Vm {
object.set(class_name, field_name, value); object.set(class_name, field_name, value);
} }
} }
} },
INVOKEVIRTUAL | INVOKESPECIAL => unsafe { INVOKEVIRTUAL | INVOKESPECIAL => unsafe {
let cp_index = read_u16(&code.opcodes, pc); 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); let mut args = Vec::with_capacity(invocation.method.num_args);
for _ in 0..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()?);
} }
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)?; let mut return_value = self.execute(
match *returnvalue.get() { &invocation.class_name,
&invocation.method.name,
args,
)?;
match *return_value.get() {
Void => {} 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 => { NEW => {
let class_index = &read_u16(&code.opcodes, pc); let class_index = &read_u16(&code.opcodes, pc);
let class_name_index = class.get_class_ref(class_index).unwrap(); let class_name_index = class.cp_class_ref(class_index).unwrap();
let class_name = class.get_utf8(class_name_index).unwrap(); let class_name = class.cp_utf8(class_name_index).unwrap();
let class = self.get_class(class_name)?; 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.local_stack().push(Value::Ref(Arc::clone(&object)));
self.heap.new_object(object); self.heap.new_object(object);
} }
@ -386,7 +444,8 @@ impl Vm {
self.local_stack().push(Value::F64(array[index])); self.local_stack().push(Value::F64(array[index]));
} }
ObjectRef::ObjectArray(ref array) => { 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? ObjectRef::Object(_) => {} //throw error?
} }
@ -408,12 +467,14 @@ impl Vm {
if let Value::Ref(ref mut objectref) = arrayref { if let Value::Ref(ref mut objectref) = arrayref {
match &mut *objectref.get() { match &mut *objectref.get() {
ObjectRef::ByteArray(ref mut array) => { 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; array[*index as usize] = value as i8;
} }
} }
ObjectRef::ShortArray(ref mut array) => { 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; array[*index as usize] = value as i16;
} }
} }
@ -452,14 +513,18 @@ impl Vm {
array[*index as usize] = value.clone(); array[*index as usize] = value.clone();
} }
} }
ObjectRef::Object(_) => {}//throw error? ObjectRef::Object(_) => {} //throw error?
} }
} }
} }
Ok(()) 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()?; let value = self.local_stack().pop()?;
while local_params.len() < index + 1 { while local_params.len() < index + 1 {
local_params.push(None); local_params.push(None);
@ -469,7 +534,6 @@ impl Vm {
} }
} }
struct Invocation { struct Invocation {
class_name: String, class_name: String,
method: MethodSignature, method: MethodSignature,
@ -480,8 +544,11 @@ struct MethodSignature {
num_args: usize, 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> { 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 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() {
if let CpEntry::Utf8(class_name) = cp.get(class_name_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 mut method_signature: String = method_name.into();
let num_args = get_hum_args(signature); let num_args = get_hum_args(signature);
method_signature.push_str(signature); method_signature.push_str(signature);
return Some(MethodSignature { name: method_signature, num_args }); return Some(MethodSignature {
name: method_signature,
num_args,
});
} }
} }
} }
None None
} }
fn get_hum_args(signature: &str) -> usize { fn get_hum_args(signature: &str) -> usize {
let mut num = 0; let mut num = 0;
let mut i = 1; let mut i = 1;
@ -531,4 +600,4 @@ fn get_hum_args(signature: &str) -> usize {
} }
} }
num num
} }

View file

@ -1,8 +1,6 @@
mod test { mod test {
use classfile_reader::class::Value; use java_rs::class::Value;
use classfile_reader::vm::Vm; use java_rs::vm::Vm;
use classfile_reader::{classloader::load_class, io};
use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
#[test] #[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));
}
}