stub native invoke, sugar, fmt
This commit is contained in:
parent
03732a3b73
commit
22a5ee8346
11 changed files with 348 additions and 187 deletions
136
src/class.rs
136
src/class.rs
|
|
@ -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 {}
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
45
src/heap.rs
45
src/heap.rs
|
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
8
src/native.rs
Normal 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()
|
||||||
|
}
|
||||||
|
|
@ -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)
|
|
||||||
|
|
|
||||||
193
src/vm.rs
193
src/vm.rs
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
19
tests/method_tests.rs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue