Object initialisation
This commit is contained in:
parent
78b17345b8
commit
065bd9f3c7
@ -1,10 +1,10 @@
|
||||
use crate::class_file::constant_pool::ConstantPoolExt;
|
||||
use crate::class_file::{ClassFile, Constant, ConstantPoolEntry};
|
||||
use deku::DekuContainerRead;
|
||||
use deku_derive::DekuRead;
|
||||
use log::trace;
|
||||
use std::fmt::Display;
|
||||
use std::ops::Deref;
|
||||
use deku_derive::DekuRead;
|
||||
use deku::DekuContainerRead;
|
||||
use log::trace;
|
||||
use crate::class_file::{ClassFile, Constant, ConstantPoolEntry};
|
||||
use crate::class_file::constant_pool::ConstantPoolExt;
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, DekuRead)]
|
||||
#[deku(ctx = "_endian: deku::ctx::Endian", endian = "big")]
|
||||
@ -59,376 +59,6 @@ pub enum ArrayType {
|
||||
#[deku(id = "11")]
|
||||
T_LONG,
|
||||
}
|
||||
//noinspection SpellCheckingInspection
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, PartialEq, Debug, DekuRead)]
|
||||
#[deku(id_type = "u8", ctx = "_endian: deku::ctx::Endian", endian = "big")]
|
||||
pub enum Ops {
|
||||
// Constants
|
||||
#[deku(id = 0x00)]
|
||||
nop,
|
||||
#[deku(id = 0x01)]
|
||||
aconst_null,
|
||||
#[deku(id = 0x02)]
|
||||
iconst_m1,
|
||||
#[deku(id = 0x03)]
|
||||
iconst_0,
|
||||
#[deku(id = 0x04)]
|
||||
iconst_1,
|
||||
#[deku(id = 0x05)]
|
||||
iconst_2,
|
||||
#[deku(id = 0x06)]
|
||||
iconst_3,
|
||||
#[deku(id = 0x07)]
|
||||
iconst_4,
|
||||
#[deku(id = 0x08)]
|
||||
iconst_5,
|
||||
#[deku(id = 0x09)]
|
||||
lconst_0,
|
||||
#[deku(id = 0x0a)]
|
||||
lconst_1,
|
||||
#[deku(id = 0x0b)]
|
||||
fconst_0,
|
||||
#[deku(id = 0x0c)]
|
||||
fconst_1,
|
||||
#[deku(id = 0x0d)]
|
||||
fconst_2,
|
||||
#[deku(id = 0x0e)]
|
||||
dconst_0,
|
||||
#[deku(id = 0x0f)]
|
||||
dconst_1,
|
||||
#[deku(id = 0x10)]
|
||||
bipush(u8),
|
||||
#[deku(id = 0x11)]
|
||||
sipush(u16),
|
||||
#[deku(id = 0x12)]
|
||||
ldc(u8),
|
||||
#[deku(id = 0x13)]
|
||||
ldc_w(u16),
|
||||
#[deku(id = 0x14)]
|
||||
ldc2_w(u16),
|
||||
|
||||
// Loads
|
||||
#[deku(id = 0x15)]
|
||||
iload(u8),
|
||||
#[deku(id = 0x16)]
|
||||
lload(u8),
|
||||
#[deku(id = 0x17)]
|
||||
fload(u8),
|
||||
#[deku(id = 0x18)]
|
||||
dload(u8),
|
||||
#[deku(id = 0x19)]
|
||||
aload(u8),
|
||||
#[deku(id = 0x1A)]
|
||||
iload_0,
|
||||
#[deku(id = 0x1B)]
|
||||
iload_1,
|
||||
#[deku(id = 0x1C)]
|
||||
iload_2,
|
||||
#[deku(id = 0x1D)]
|
||||
iload_3,
|
||||
#[deku(id = 0x1E)]
|
||||
lload_0,
|
||||
#[deku(id = 0x1F)]
|
||||
lload_1,
|
||||
#[deku(id = 0x20)]
|
||||
lload_2,
|
||||
#[deku(id = 0x21)]
|
||||
lload_3,
|
||||
#[deku(id = 0x22)]
|
||||
fload_0,
|
||||
#[deku(id = 0x23)]
|
||||
fload_1,
|
||||
#[deku(id = 0x24)]
|
||||
fload_2,
|
||||
#[deku(id = 0x25)]
|
||||
fload_3,
|
||||
#[deku(id = 0x26)]
|
||||
dload_0,
|
||||
#[deku(id = 0x27)]
|
||||
dload_1,
|
||||
#[deku(id = 0x28)]
|
||||
dload_2,
|
||||
#[deku(id = 0x29)]
|
||||
dload_3,
|
||||
#[deku(id = 0x2A)]
|
||||
aload_0,
|
||||
#[deku(id = 0x2B)]
|
||||
aload_1,
|
||||
#[deku(id = 0x2C)]
|
||||
aload_2,
|
||||
#[deku(id = 0x2D)]
|
||||
aload_3,
|
||||
#[deku(id = 0x2E)]
|
||||
iaload,
|
||||
#[deku(id = 0x2F)]
|
||||
laload,
|
||||
#[deku(id = 0x30)]
|
||||
faload,
|
||||
#[deku(id = 0x31)]
|
||||
daload,
|
||||
#[deku(id = 0x32)]
|
||||
aaload,
|
||||
#[deku(id = 0x33)]
|
||||
baload,
|
||||
#[deku(id = 0x34)]
|
||||
caload,
|
||||
#[deku(id = 0x35)]
|
||||
saload,
|
||||
|
||||
// Stores
|
||||
#[deku(id = 0x36)]
|
||||
istore(u8),
|
||||
#[deku(id = 0x37)]
|
||||
lstore(u8),
|
||||
#[deku(id = 0x38)]
|
||||
fstore(u8),
|
||||
#[deku(id = 0x39)]
|
||||
dstore(u8),
|
||||
#[deku(id = 0x3A)]
|
||||
astore(u8),
|
||||
#[deku(id = 0x3B)]
|
||||
istore_0,
|
||||
#[deku(id = 0x3C)]
|
||||
istore_1,
|
||||
#[deku(id = 0x3D)]
|
||||
istore_2,
|
||||
#[deku(id = 0x3E)]
|
||||
istore_3,
|
||||
#[deku(id = 0x3F)]
|
||||
lstore_0,
|
||||
#[deku(id = 0x40)]
|
||||
lstore_1,
|
||||
#[deku(id = 0x41)]
|
||||
lstore_2,
|
||||
#[deku(id = 0x42)]
|
||||
lstore_3,
|
||||
#[deku(id = 0x43)]
|
||||
fstore_0,
|
||||
#[deku(id = 0x44)]
|
||||
fstore_1,
|
||||
#[deku(id = 0x45)]
|
||||
fstore_2,
|
||||
#[deku(id = 0x46)]
|
||||
fstore_3,
|
||||
#[deku(id = 0x47)]
|
||||
dstore_0,
|
||||
#[deku(id = 0x48)]
|
||||
dstore_1,
|
||||
#[deku(id = 0x49)]
|
||||
dstore_2,
|
||||
#[deku(id = 0x4A)]
|
||||
dstore_3,
|
||||
#[deku(id = 0x4B)]
|
||||
astore_0,
|
||||
#[deku(id = 0x4C)]
|
||||
astore_1,
|
||||
#[deku(id = 0x4D)]
|
||||
astore_2,
|
||||
#[deku(id = 0x4E)]
|
||||
astore_3,
|
||||
#[deku(id = 0x4F)]
|
||||
iastore,
|
||||
#[deku(id = 0x50)]
|
||||
lastore,
|
||||
#[deku(id = 0x51)]
|
||||
fastore,
|
||||
#[deku(id = 0x52)]
|
||||
dastore,
|
||||
#[deku(id = 0x53)]
|
||||
aastore,
|
||||
#[deku(id = 0x54)]
|
||||
bastore,
|
||||
#[deku(id = 0x55)]
|
||||
castore,
|
||||
#[deku(id = 0x56)]
|
||||
sastore,
|
||||
|
||||
//stack
|
||||
|
||||
//math
|
||||
#[deku(id = 0x60)]
|
||||
iadd,
|
||||
#[deku(id = 0x61)]
|
||||
ladd,
|
||||
#[deku(id = 0x62)]
|
||||
fadd,
|
||||
#[deku(id = 0x63)]
|
||||
dadd,
|
||||
#[deku(id = 0x64)]
|
||||
isub,
|
||||
#[deku(id = 0x65)]
|
||||
lsub,
|
||||
#[deku(id = 0x66)]
|
||||
fsub,
|
||||
#[deku(id = 0x67)]
|
||||
dsub,
|
||||
#[deku(id = 0x68)]
|
||||
imul,
|
||||
#[deku(id = 0x69)]
|
||||
lmul,
|
||||
#[deku(id = 0x6a)]
|
||||
fmul,
|
||||
#[deku(id = 0x6b)]
|
||||
dmul,
|
||||
#[deku(id = 0x6c)]
|
||||
idiv,
|
||||
#[deku(id = 0x6d)]
|
||||
ldiv,
|
||||
#[deku(id = 0x6e)]
|
||||
fdiv,
|
||||
#[deku(id = 0x6f)]
|
||||
ddiv,
|
||||
#[deku(id = 0x70)]
|
||||
irem,
|
||||
#[deku(id = 0x71)]
|
||||
lrem,
|
||||
#[deku(id = 0x72)]
|
||||
frem,
|
||||
#[deku(id = 0x73)]
|
||||
drem,
|
||||
#[deku(id = 0x74)]
|
||||
ineg,
|
||||
#[deku(id = 0x75)]
|
||||
lneg,
|
||||
#[deku(id = 0x76)]
|
||||
fneg,
|
||||
#[deku(id = 0x77)]
|
||||
dneg,
|
||||
#[deku(id = 0x78)]
|
||||
ishl,
|
||||
#[deku(id = 0x79)]
|
||||
lshl,
|
||||
#[deku(id = 0x7a)]
|
||||
ishr,
|
||||
#[deku(id = 0x7b)]
|
||||
lshr,
|
||||
#[deku(id = 0x7c)]
|
||||
iushr,
|
||||
#[deku(id = 0x7d)]
|
||||
lushr,
|
||||
#[deku(id = 0x7e)]
|
||||
iand,
|
||||
#[deku(id = 0x7f)]
|
||||
land,
|
||||
#[deku(id = 0x80)]
|
||||
ior,
|
||||
#[deku(id = 0x81)]
|
||||
lor,
|
||||
#[deku(id = 0x82)]
|
||||
ixor,
|
||||
#[deku(id = 0x83)]
|
||||
lxor,
|
||||
#[deku(id = 0x84)]
|
||||
iinc(u8, i8),
|
||||
|
||||
//conversions
|
||||
#[deku(id = 0x85)]
|
||||
i2l,
|
||||
#[deku(id = 0x86)]
|
||||
i2f,
|
||||
#[deku(id = 0x87)]
|
||||
i2d,
|
||||
#[deku(id = 0x88)]
|
||||
l2i,
|
||||
#[deku(id = 0x89)]
|
||||
l2f,
|
||||
#[deku(id = 0x8a)]
|
||||
l2d,
|
||||
#[deku(id = 0x8b)]
|
||||
f2i,
|
||||
#[deku(id = 0x8c)]
|
||||
f2l,
|
||||
#[deku(id = 0x8d)]
|
||||
f2d,
|
||||
#[deku(id = 0x8e)]
|
||||
d2i,
|
||||
#[deku(id = 0x8f)]
|
||||
d2l,
|
||||
#[deku(id = 0x90)]
|
||||
d2f,
|
||||
#[deku(id = 0x91)]
|
||||
i2b,
|
||||
#[deku(id = 0x92)]
|
||||
i2c,
|
||||
#[deku(id = 0x93)]
|
||||
i2s,
|
||||
|
||||
// comparisons
|
||||
|
||||
// control
|
||||
#[deku(id = 0xa7)]
|
||||
goto(u16),
|
||||
|
||||
// discontinued
|
||||
#[deku(id = 0xa8)]
|
||||
jsr(u16),
|
||||
#[deku(id = 0xa9)]
|
||||
ret(u8),
|
||||
//
|
||||
|
||||
#[deku(id = 0xaa)]
|
||||
tableswitch,
|
||||
#[deku(id = 0xab)]
|
||||
lookupswitch,
|
||||
#[deku(id = 0xac)]
|
||||
ireturn,
|
||||
#[deku(id = 0xad)]
|
||||
lreturn,
|
||||
#[deku(id = 0xae)]
|
||||
freturn,
|
||||
#[deku(id = 0xaf)]
|
||||
dreturn,
|
||||
#[deku(id = 0xb0)]
|
||||
areturn,
|
||||
// return
|
||||
#[deku(id = 0xb1)]
|
||||
return_void,
|
||||
|
||||
// references
|
||||
#[deku(id = 0xB2)]
|
||||
getstatic(u16),
|
||||
#[deku(id = 0xB3)]
|
||||
putstatic(u16),
|
||||
#[deku(id = 0xB4)]
|
||||
getfield(u16),
|
||||
#[deku(id = 0xB5)]
|
||||
putfield(u16),
|
||||
#[deku(id = 0xB6)]
|
||||
invokevirtual(u16),
|
||||
#[deku(id = 0xB7)]
|
||||
invokespecial(u16),
|
||||
#[deku(id = 0xB8)]
|
||||
invokestatic(u16),
|
||||
// 4th byte always zero/0
|
||||
#[deku(id = 0xB9)]
|
||||
invokeinterface(u16, u8, u8),
|
||||
// 3rd, 4th must be zero/0
|
||||
#[deku(id = 0xBA)]
|
||||
invokedynamic(u16, u16),
|
||||
#[deku(id = 0xBB)]
|
||||
new(u16),
|
||||
#[deku(id = 0xBC)]
|
||||
newarray(ArrayType),
|
||||
#[deku(id = 0xBD)]
|
||||
anewarray(u16),
|
||||
#[deku(id = 0xBE)]
|
||||
arraylength,
|
||||
#[deku(id = 0xBF)]
|
||||
athrow,
|
||||
#[deku(id = 0xC0)]
|
||||
checkcast(u16),
|
||||
#[deku(id = 0xC1)]
|
||||
instanceof(u16),
|
||||
#[deku(id = 0xC2)]
|
||||
monitorenter,
|
||||
#[deku(id = 0xC3)]
|
||||
monitorexit,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// impl TryFrom<u8> for Ops {
|
||||
// type Error = ();
|
||||
@ -500,8 +130,10 @@ impl AttributeInfo {
|
||||
|
||||
/// Get the interpreted attribute, parsing if necessary
|
||||
pub fn get(&self, class_file: &ClassFile) -> Option<Attribute> {
|
||||
class_file.constant_pool.parse_attribute(self.deref().clone()).ok()
|
||||
|
||||
class_file
|
||||
.constant_pool
|
||||
.parse_attribute(self.deref().clone())
|
||||
.ok()
|
||||
|
||||
// if let Some(ref attr) = self.interpreted {
|
||||
// Some(attr.clone())
|
||||
@ -511,15 +143,14 @@ impl AttributeInfo {
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalVariableTableAttribute {
|
||||
|
||||
}
|
||||
impl LocalVariableTableAttribute {}
|
||||
|
||||
impl Display for AttributeInfo {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "AttributeInfo {{ name_index: {}, length: {} }}",
|
||||
self.attribute_name_index,
|
||||
self.attribute_length
|
||||
writeln!(
|
||||
f,
|
||||
"AttributeInfo {{ name_index: {}, length: {} }}",
|
||||
self.attribute_name_index, self.attribute_length
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -530,25 +161,37 @@ impl Display for Attribute {
|
||||
Attribute::Code(code) => write!(f, "Code attribute: {}", code),
|
||||
Attribute::SourceFile(index) => write!(f, "SourceFile attribute, index: {}", index),
|
||||
Attribute::LineNumberTable(data) => write!(f, "LineNumberTable attribute: {}", data),
|
||||
Attribute::StackMapTable(data) => write!(f, "StackMapTable attribute, {} bytes", data.len()),
|
||||
Attribute::StackMapTable(data) => {
|
||||
write!(f, "StackMapTable attribute, {} bytes", data.len())
|
||||
}
|
||||
Attribute::Exceptions(data) => write!(f, "Exceptions attribute, {} bytes", data.len()),
|
||||
Attribute::InnerClasses(data) => write!(f, "InnerClasses attribute, {} bytes", data.len()),
|
||||
Attribute::InnerClasses(data) => {
|
||||
write!(f, "InnerClasses attribute, {} bytes", data.len())
|
||||
}
|
||||
Attribute::Signature(index) => write!(f, "Signature attribute, index: {}", index),
|
||||
Attribute::LocalVariableTable(table) => write!(f, "LocalVariableTable attribute: {}", table),
|
||||
Attribute::Unknown(name, data) => write!(f, "Unknown attribute '{}', {} bytes", name, data.len()),
|
||||
_ => { unreachable!() }
|
||||
Attribute::LocalVariableTable(table) => {
|
||||
write!(f, "LocalVariableTable attribute: {}", table)
|
||||
}
|
||||
Attribute::Unknown(name, data) => {
|
||||
write!(f, "Unknown attribute '{}', {} bytes", name, data.len())
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for CodeAttribute {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "stack={}, locals={}, code={} bytes, exceptions={}, attributes={}",
|
||||
self.max_stack,
|
||||
self.max_locals,
|
||||
self.code_length,
|
||||
self.exception_table_length,
|
||||
self.attributes_count
|
||||
write!(
|
||||
f,
|
||||
"stack={}, locals={}, code={} bytes, exceptions={}, attributes={}",
|
||||
self.max_stack,
|
||||
self.max_locals,
|
||||
self.code_length,
|
||||
self.exception_table_length,
|
||||
self.attributes_count
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -598,14 +241,15 @@ pub struct LocalVariableTableEntry {
|
||||
|
||||
impl Display for LocalVariableTableAttribute {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "local_variable_table_length={}, entries={}",
|
||||
self.local_variable_table_length,
|
||||
self.local_variable_table.len()
|
||||
write!(
|
||||
f,
|
||||
"local_variable_table_length={}, entries={}",
|
||||
self.local_variable_table_length,
|
||||
self.local_variable_table.len()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, DekuRead)]
|
||||
#[deku(endian = "big")]
|
||||
pub struct LineNumberTableAttribute {
|
||||
@ -614,8 +258,6 @@ pub struct LineNumberTableAttribute {
|
||||
pub line_number_table: Vec<LineNumberTableEntry>,
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, DekuRead)]
|
||||
#[deku(ctx = "_endian: deku::ctx::Endian", endian = "big")]
|
||||
pub struct LineNumberTableEntry {
|
||||
@ -625,9 +267,11 @@ pub struct LineNumberTableEntry {
|
||||
|
||||
impl Display for LineNumberTableAttribute {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "table_length={}, entries={}",
|
||||
self.line_number_table_length,
|
||||
self.line_number_table.len()
|
||||
write!(
|
||||
f,
|
||||
"table_length={}, entries={}",
|
||||
self.line_number_table_length,
|
||||
self.line_number_table.len()
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
use crate::attributes::{Attribute, AttributeInfo, CodeAttribute, Ops};
|
||||
use crate::attributes::{Attribute, AttributeInfo, CodeAttribute};
|
||||
use crate::class_file::constant_pool::{ConstantPoolError, ConstantPoolExt, ConstantPoolOwned};
|
||||
use crate::instructions::Ops;
|
||||
use crate::{BaseType, FieldType, MethodDescriptor, Value};
|
||||
use deku::ctx::Endian::Big;
|
||||
use deku::{DekuContainerRead, DekuError};
|
||||
|
||||
@ -67,8 +67,7 @@ pub trait ConstantPoolExt: ConstantPoolGet {
|
||||
|
||||
fn resolve_field(&self, index: u16) -> Result<FieldRef, ConstantPoolError> {
|
||||
let fr = self.get_field_ref(index)?;
|
||||
let class = self.get_class_info(fr.class_index)?;
|
||||
let class = self.get_string(class.name_index)?;
|
||||
let class = self.resolve_class_name(fr.class_index)?;
|
||||
let name_and_type = self.get_name_and_type_info(fr.name_and_type_index)?;
|
||||
let name = self.get_string(name_and_type.name_index)?;
|
||||
let desc = self.get_string(name_and_type.descriptor_index)?;
|
||||
@ -76,10 +75,24 @@ pub trait ConstantPoolExt: ConstantPoolGet {
|
||||
Ok(FieldRef { class, name, desc })
|
||||
}
|
||||
|
||||
/// Resolves a class name from a constant pool class info entry
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `index` - Index into constant pool that must point to a CONSTANT_Class_info structure
|
||||
///
|
||||
/// # Returns
|
||||
/// * Binary class name in internal JVM format (e.g. "java/lang/Object")
|
||||
///
|
||||
/// # Errors
|
||||
/// * Returns ConstantPoolError if index is invalid or points to wrong type
|
||||
fn resolve_class_name(&self, index: u16) -> Result<String, ConstantPoolError> {
|
||||
let class_info = self.get_class_info(index)?;
|
||||
self.get_string(class_info.name_index)
|
||||
}
|
||||
|
||||
fn resolve_method_ref(&self, index: u16) -> Result<MethodRef, ConstantPoolError> {
|
||||
let mr = self.get_method_ref(index)?;
|
||||
let class = self.get_class_info(mr.class_index)?;
|
||||
let class = self.get_string(class.name_index)?;
|
||||
let class = self.resolve_class_name(mr.class_index)?;
|
||||
let name_and_type = self.get_name_and_type_info(mr.name_and_type_index)?;
|
||||
let name = self.get_string(name_and_type.name_index)?;
|
||||
let desc = self.get_string(name_and_type.descriptor_index)?;
|
||||
|
||||
@ -10,6 +10,7 @@ use crate::native_libraries::NativeLibraries;
|
||||
use crate::{FieldType, MethodDescriptor};
|
||||
use dashmap::DashMap;
|
||||
use deku::DekuContainerRead;
|
||||
use itertools::Itertools;
|
||||
use libloading::os::windows::Library;
|
||||
use log::warn;
|
||||
use std::collections::hash_map::{Entry, Iter};
|
||||
@ -149,14 +150,10 @@ impl ClassLoader {
|
||||
|
||||
fn load_class(&mut self, what: &str) -> Result<Arc<RuntimeClass>, String> {
|
||||
let (module, class_fqn) = ("", what);
|
||||
let bytes = self.bimage.get_class(module, class_fqn).unwrap_or_else(|| {
|
||||
let path = format!("./data/{what}.class");
|
||||
log::info!("Loading class from path: {}", path);
|
||||
let mut class_file = File::open(path).unwrap();
|
||||
let mut bytes = Vec::new();
|
||||
class_file.read_to_end(&mut bytes).unwrap();
|
||||
bytes
|
||||
});
|
||||
let bytes = self
|
||||
.bimage
|
||||
.get_class(module, class_fqn)
|
||||
.unwrap_or_else(|| Self::load_class_from_disk(what));
|
||||
let (_, cf) = ClassFile::from_bytes((bytes.as_ref(), 0))
|
||||
.map_err(|e| format!("failed to parse class file: {}", e))?;
|
||||
let runtime = self.runtime_class(cf);
|
||||
@ -168,6 +165,20 @@ impl ClassLoader {
|
||||
Ok(arced)
|
||||
}
|
||||
|
||||
fn load_class_from_disk(what: &str) -> Vec<u8> {
|
||||
let class_path = std::env::args()
|
||||
.nth(1)
|
||||
.unwrap_or("./data".to_string())
|
||||
.replace("\\", "/");
|
||||
|
||||
let path = format!("{class_path}/{what}.class");
|
||||
log::info!("Loading class from path: {}", path);
|
||||
let mut class_file = File::open(path).unwrap();
|
||||
let mut bytes = Vec::new();
|
||||
class_file.read_to_end(&mut bytes).unwrap();
|
||||
bytes
|
||||
}
|
||||
|
||||
fn runtime_class(&mut self, class_file: ClassFile) -> RuntimeClass {
|
||||
let constant_pool = class_file.constant_pool.clone();
|
||||
let access_flags = ClassFlags::from(class_file.access_flags);
|
||||
|
||||
386
crates/core/src/instructions.rs
Normal file
386
crates/core/src/instructions.rs
Normal file
@ -0,0 +1,386 @@
|
||||
use crate::attributes::ArrayType;
|
||||
use deku_derive::DekuRead;
|
||||
|
||||
//noinspection SpellCheckingInspection
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, PartialEq, Debug, DekuRead)]
|
||||
#[deku(id_type = "u8", ctx = "_endian: deku::ctx::Endian", endian = "big")]
|
||||
pub enum Ops {
|
||||
// Constants
|
||||
#[deku(id = 0x00)]
|
||||
nop,
|
||||
#[deku(id = 0x01)]
|
||||
aconst_null,
|
||||
#[deku(id = 0x02)]
|
||||
iconst_m1,
|
||||
#[deku(id = 0x03)]
|
||||
iconst_0,
|
||||
#[deku(id = 0x04)]
|
||||
iconst_1,
|
||||
#[deku(id = 0x05)]
|
||||
iconst_2,
|
||||
#[deku(id = 0x06)]
|
||||
iconst_3,
|
||||
#[deku(id = 0x07)]
|
||||
iconst_4,
|
||||
#[deku(id = 0x08)]
|
||||
iconst_5,
|
||||
#[deku(id = 0x09)]
|
||||
lconst_0,
|
||||
#[deku(id = 0x0a)]
|
||||
lconst_1,
|
||||
#[deku(id = 0x0b)]
|
||||
fconst_0,
|
||||
#[deku(id = 0x0c)]
|
||||
fconst_1,
|
||||
#[deku(id = 0x0d)]
|
||||
fconst_2,
|
||||
#[deku(id = 0x0e)]
|
||||
dconst_0,
|
||||
#[deku(id = 0x0f)]
|
||||
dconst_1,
|
||||
#[deku(id = 0x10)]
|
||||
bipush(u8),
|
||||
#[deku(id = 0x11)]
|
||||
sipush(u16),
|
||||
#[deku(id = 0x12)]
|
||||
ldc(u8),
|
||||
#[deku(id = 0x13)]
|
||||
ldc_w(u16),
|
||||
#[deku(id = 0x14)]
|
||||
ldc2_w(u16),
|
||||
|
||||
// Loads
|
||||
#[deku(id = 0x15)]
|
||||
iload(u8),
|
||||
#[deku(id = 0x16)]
|
||||
lload(u8),
|
||||
#[deku(id = 0x17)]
|
||||
fload(u8),
|
||||
#[deku(id = 0x18)]
|
||||
dload(u8),
|
||||
#[deku(id = 0x19)]
|
||||
aload(u8),
|
||||
#[deku(id = 0x1A)]
|
||||
iload_0,
|
||||
#[deku(id = 0x1B)]
|
||||
iload_1,
|
||||
#[deku(id = 0x1C)]
|
||||
iload_2,
|
||||
#[deku(id = 0x1D)]
|
||||
iload_3,
|
||||
#[deku(id = 0x1E)]
|
||||
lload_0,
|
||||
#[deku(id = 0x1F)]
|
||||
lload_1,
|
||||
#[deku(id = 0x20)]
|
||||
lload_2,
|
||||
#[deku(id = 0x21)]
|
||||
lload_3,
|
||||
#[deku(id = 0x22)]
|
||||
fload_0,
|
||||
#[deku(id = 0x23)]
|
||||
fload_1,
|
||||
#[deku(id = 0x24)]
|
||||
fload_2,
|
||||
#[deku(id = 0x25)]
|
||||
fload_3,
|
||||
#[deku(id = 0x26)]
|
||||
dload_0,
|
||||
#[deku(id = 0x27)]
|
||||
dload_1,
|
||||
#[deku(id = 0x28)]
|
||||
dload_2,
|
||||
#[deku(id = 0x29)]
|
||||
dload_3,
|
||||
#[deku(id = 0x2A)]
|
||||
aload_0,
|
||||
#[deku(id = 0x2B)]
|
||||
aload_1,
|
||||
#[deku(id = 0x2C)]
|
||||
aload_2,
|
||||
#[deku(id = 0x2D)]
|
||||
aload_3,
|
||||
#[deku(id = 0x2E)]
|
||||
iaload,
|
||||
#[deku(id = 0x2F)]
|
||||
laload,
|
||||
#[deku(id = 0x30)]
|
||||
faload,
|
||||
#[deku(id = 0x31)]
|
||||
daload,
|
||||
#[deku(id = 0x32)]
|
||||
aaload,
|
||||
#[deku(id = 0x33)]
|
||||
baload,
|
||||
#[deku(id = 0x34)]
|
||||
caload,
|
||||
#[deku(id = 0x35)]
|
||||
saload,
|
||||
|
||||
// Stores
|
||||
#[deku(id = 0x36)]
|
||||
istore(u8),
|
||||
#[deku(id = 0x37)]
|
||||
lstore(u8),
|
||||
#[deku(id = 0x38)]
|
||||
fstore(u8),
|
||||
#[deku(id = 0x39)]
|
||||
dstore(u8),
|
||||
#[deku(id = 0x3A)]
|
||||
astore(u8),
|
||||
#[deku(id = 0x3B)]
|
||||
istore_0,
|
||||
#[deku(id = 0x3C)]
|
||||
istore_1,
|
||||
#[deku(id = 0x3D)]
|
||||
istore_2,
|
||||
#[deku(id = 0x3E)]
|
||||
istore_3,
|
||||
#[deku(id = 0x3F)]
|
||||
lstore_0,
|
||||
#[deku(id = 0x40)]
|
||||
lstore_1,
|
||||
#[deku(id = 0x41)]
|
||||
lstore_2,
|
||||
#[deku(id = 0x42)]
|
||||
lstore_3,
|
||||
#[deku(id = 0x43)]
|
||||
fstore_0,
|
||||
#[deku(id = 0x44)]
|
||||
fstore_1,
|
||||
#[deku(id = 0x45)]
|
||||
fstore_2,
|
||||
#[deku(id = 0x46)]
|
||||
fstore_3,
|
||||
#[deku(id = 0x47)]
|
||||
dstore_0,
|
||||
#[deku(id = 0x48)]
|
||||
dstore_1,
|
||||
#[deku(id = 0x49)]
|
||||
dstore_2,
|
||||
#[deku(id = 0x4A)]
|
||||
dstore_3,
|
||||
#[deku(id = 0x4B)]
|
||||
astore_0,
|
||||
#[deku(id = 0x4C)]
|
||||
astore_1,
|
||||
#[deku(id = 0x4D)]
|
||||
astore_2,
|
||||
#[deku(id = 0x4E)]
|
||||
astore_3,
|
||||
#[deku(id = 0x4F)]
|
||||
iastore,
|
||||
#[deku(id = 0x50)]
|
||||
lastore,
|
||||
#[deku(id = 0x51)]
|
||||
fastore,
|
||||
#[deku(id = 0x52)]
|
||||
dastore,
|
||||
#[deku(id = 0x53)]
|
||||
aastore,
|
||||
#[deku(id = 0x54)]
|
||||
bastore,
|
||||
#[deku(id = 0x55)]
|
||||
castore,
|
||||
#[deku(id = 0x56)]
|
||||
sastore,
|
||||
|
||||
//stack
|
||||
#[deku(id = 0x57)]
|
||||
pop,
|
||||
#[deku(id = 0x58)]
|
||||
pop2,
|
||||
#[deku(id = 0x59)]
|
||||
dup,
|
||||
#[deku(id = 0x5a)]
|
||||
dup_x1,
|
||||
#[deku(id = 0x5b)]
|
||||
dup_x2,
|
||||
#[deku(id = 0x5c)]
|
||||
dup2,
|
||||
#[deku(id = 0x5d)]
|
||||
dup2_x1,
|
||||
#[deku(id = 0x5e)]
|
||||
dup2_x2,
|
||||
#[deku(id = 0x5f)]
|
||||
swap,
|
||||
|
||||
//math
|
||||
#[deku(id = 0x60)]
|
||||
iadd,
|
||||
#[deku(id = 0x61)]
|
||||
ladd,
|
||||
#[deku(id = 0x62)]
|
||||
fadd,
|
||||
#[deku(id = 0x63)]
|
||||
dadd,
|
||||
#[deku(id = 0x64)]
|
||||
isub,
|
||||
#[deku(id = 0x65)]
|
||||
lsub,
|
||||
#[deku(id = 0x66)]
|
||||
fsub,
|
||||
#[deku(id = 0x67)]
|
||||
dsub,
|
||||
#[deku(id = 0x68)]
|
||||
imul,
|
||||
#[deku(id = 0x69)]
|
||||
lmul,
|
||||
#[deku(id = 0x6a)]
|
||||
fmul,
|
||||
#[deku(id = 0x6b)]
|
||||
dmul,
|
||||
#[deku(id = 0x6c)]
|
||||
idiv,
|
||||
#[deku(id = 0x6d)]
|
||||
ldiv,
|
||||
#[deku(id = 0x6e)]
|
||||
fdiv,
|
||||
#[deku(id = 0x6f)]
|
||||
ddiv,
|
||||
#[deku(id = 0x70)]
|
||||
irem,
|
||||
#[deku(id = 0x71)]
|
||||
lrem,
|
||||
#[deku(id = 0x72)]
|
||||
frem,
|
||||
#[deku(id = 0x73)]
|
||||
drem,
|
||||
#[deku(id = 0x74)]
|
||||
ineg,
|
||||
#[deku(id = 0x75)]
|
||||
lneg,
|
||||
#[deku(id = 0x76)]
|
||||
fneg,
|
||||
#[deku(id = 0x77)]
|
||||
dneg,
|
||||
#[deku(id = 0x78)]
|
||||
ishl,
|
||||
#[deku(id = 0x79)]
|
||||
lshl,
|
||||
#[deku(id = 0x7a)]
|
||||
ishr,
|
||||
#[deku(id = 0x7b)]
|
||||
lshr,
|
||||
#[deku(id = 0x7c)]
|
||||
iushr,
|
||||
#[deku(id = 0x7d)]
|
||||
lushr,
|
||||
#[deku(id = 0x7e)]
|
||||
iand,
|
||||
#[deku(id = 0x7f)]
|
||||
land,
|
||||
#[deku(id = 0x80)]
|
||||
ior,
|
||||
#[deku(id = 0x81)]
|
||||
lor,
|
||||
#[deku(id = 0x82)]
|
||||
ixor,
|
||||
#[deku(id = 0x83)]
|
||||
lxor,
|
||||
#[deku(id = 0x84)]
|
||||
iinc(u8, i8),
|
||||
|
||||
//conversions
|
||||
#[deku(id = 0x85)]
|
||||
i2l,
|
||||
#[deku(id = 0x86)]
|
||||
i2f,
|
||||
#[deku(id = 0x87)]
|
||||
i2d,
|
||||
#[deku(id = 0x88)]
|
||||
l2i,
|
||||
#[deku(id = 0x89)]
|
||||
l2f,
|
||||
#[deku(id = 0x8a)]
|
||||
l2d,
|
||||
#[deku(id = 0x8b)]
|
||||
f2i,
|
||||
#[deku(id = 0x8c)]
|
||||
f2l,
|
||||
#[deku(id = 0x8d)]
|
||||
f2d,
|
||||
#[deku(id = 0x8e)]
|
||||
d2i,
|
||||
#[deku(id = 0x8f)]
|
||||
d2l,
|
||||
#[deku(id = 0x90)]
|
||||
d2f,
|
||||
#[deku(id = 0x91)]
|
||||
i2b,
|
||||
#[deku(id = 0x92)]
|
||||
i2c,
|
||||
#[deku(id = 0x93)]
|
||||
i2s,
|
||||
|
||||
// comparisons
|
||||
|
||||
// control
|
||||
#[deku(id = 0xa7)]
|
||||
goto(u16),
|
||||
|
||||
// discontinued
|
||||
#[deku(id = 0xa8)]
|
||||
jsr(u16),
|
||||
#[deku(id = 0xa9)]
|
||||
ret(u8),
|
||||
//
|
||||
#[deku(id = 0xaa)]
|
||||
tableswitch,
|
||||
#[deku(id = 0xab)]
|
||||
lookupswitch,
|
||||
#[deku(id = 0xac)]
|
||||
ireturn,
|
||||
#[deku(id = 0xad)]
|
||||
lreturn,
|
||||
#[deku(id = 0xae)]
|
||||
freturn,
|
||||
#[deku(id = 0xaf)]
|
||||
dreturn,
|
||||
#[deku(id = 0xb0)]
|
||||
areturn,
|
||||
// return
|
||||
#[deku(id = 0xb1)]
|
||||
return_void,
|
||||
|
||||
// references
|
||||
#[deku(id = 0xB2)]
|
||||
getstatic(u16),
|
||||
#[deku(id = 0xB3)]
|
||||
putstatic(u16),
|
||||
#[deku(id = 0xB4)]
|
||||
getfield(u16),
|
||||
#[deku(id = 0xB5)]
|
||||
putfield(u16),
|
||||
#[deku(id = 0xB6)]
|
||||
invokevirtual(u16),
|
||||
#[deku(id = 0xB7)]
|
||||
invokespecial(u16),
|
||||
#[deku(id = 0xB8)]
|
||||
invokestatic(u16),
|
||||
// 4th byte always zero/0
|
||||
#[deku(id = 0xB9)]
|
||||
invokeinterface(u16, u8, u8),
|
||||
// 3rd, 4th must be zero/0
|
||||
#[deku(id = 0xBA)]
|
||||
invokedynamic(u16, u16),
|
||||
#[deku(id = 0xBB)]
|
||||
new(u16),
|
||||
#[deku(id = 0xBC)]
|
||||
newarray(ArrayType),
|
||||
#[deku(id = 0xBD)]
|
||||
anewarray(u16),
|
||||
#[deku(id = 0xBE)]
|
||||
arraylength,
|
||||
#[deku(id = 0xBF)]
|
||||
athrow,
|
||||
#[deku(id = 0xC0)]
|
||||
checkcast(u16),
|
||||
#[deku(id = 0xC1)]
|
||||
instanceof(u16),
|
||||
#[deku(id = 0xC2)]
|
||||
monitorenter,
|
||||
#[deku(id = 0xC3)]
|
||||
monitorexit,
|
||||
}
|
||||
@ -15,20 +15,21 @@
|
||||
//! - [`MethodDescriptor`] - Method signature information
|
||||
//! - [`FieldType`] - Field type information
|
||||
|
||||
use crate::attributes::{Attribute, CodeAttribute, Ops};
|
||||
use crate::attributes::{Attribute, CodeAttribute};
|
||||
use crate::class_file::constant_pool::ConstantPoolExt;
|
||||
use crate::class_file::constant_pool::{ConstantPoolError, ConstantPoolGet};
|
||||
use crate::class_file::{Bytecode, ClassFile, ConstantPoolEntry, MethodData};
|
||||
use crate::object::Object;
|
||||
use crate::thread::VmThread;
|
||||
use crate::Value::Reference;
|
||||
use deku::{DekuContainerRead, DekuError};
|
||||
use deku_derive::{DekuRead, DekuWrite};
|
||||
use env_logger::Builder;
|
||||
use log::{warn, LevelFilter};
|
||||
use instructions::Ops;
|
||||
use log::{trace, warn, LevelFilter};
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use vm::Vm;
|
||||
|
||||
@ -37,10 +38,12 @@ mod bimage;
|
||||
mod class;
|
||||
mod class_file;
|
||||
mod class_loader;
|
||||
mod instructions;
|
||||
mod jni;
|
||||
mod macros;
|
||||
mod native_libraries;
|
||||
mod object;
|
||||
mod object_manager;
|
||||
mod rng;
|
||||
mod thread;
|
||||
mod vm;
|
||||
@ -55,6 +58,7 @@ pub fn run() {
|
||||
.filter_module("deku", LevelFilter::Warn)
|
||||
.filter_module("jvm_rs_core::class_file::class_file", LevelFilter::Info)
|
||||
.filter_module("jvm_rs_core::attributes", LevelFilter::Info)
|
||||
.filter_module("jvm_rs_core::instructions", LevelFilter::Info)
|
||||
.init();
|
||||
// let mut cl = ClassLoader::new().unwrap();
|
||||
// cl.load_class("org.example.App").expect("TODO: panic message");
|
||||
@ -118,7 +122,7 @@ enum Value {
|
||||
/// Boolean value (true/false)
|
||||
Boolean(bool),
|
||||
/// Unicode character
|
||||
Char(char),
|
||||
Char(u16),
|
||||
/// 32-bit floating point
|
||||
Float(f32),
|
||||
/// 64-bit floating point
|
||||
@ -135,6 +139,23 @@ enum Value {
|
||||
Reference(Option<ObjectRef>),
|
||||
}
|
||||
|
||||
impl Display for Value {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Value::Boolean(b) => write!(f, "bool({})", b),
|
||||
Value::Char(c) => write!(f, "char({})", char::from_u32(*c as u32).unwrap_or('?')),
|
||||
Value::Float(fl) => write!(f, "float({})", fl),
|
||||
Value::Double(d) => write!(f, "double({})", d),
|
||||
Value::Byte(b) => write!(f, "byte({})", b),
|
||||
Value::Short(s) => write!(f, "short({})", s),
|
||||
Value::Int(i) => write!(f, "int({})", i),
|
||||
Value::Long(l) => write!(f, "long({})", l),
|
||||
Value::Reference(Some(obj)) => write!(f, "Ref({})", obj.lock().unwrap().id),
|
||||
Value::Reference(None) => write!(f, "null"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a JVM stack frame for method execution.
|
||||
///
|
||||
/// A frame contains all the execution state needed to run a single method:
|
||||
@ -210,12 +231,21 @@ impl Frame {
|
||||
Ok(ExecutionResult::ReturnValue(val)) => return Ok(Some(val)),
|
||||
Ok(_) => {
|
||||
println!(
|
||||
"State:\n\tStack: {:?}\n\tLocals :{:?}\n",
|
||||
self.stack, self.vars
|
||||
"State:\n\tStack: [{}]\n\tLocals: [{}]\n",
|
||||
self.stack
|
||||
.iter()
|
||||
.map(|v| v.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
self.vars
|
||||
.iter()
|
||||
.map(|v| v.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
}
|
||||
Err(_) => {
|
||||
panic!("Mission failed, we'll get em next time")
|
||||
Err(x) => {
|
||||
panic!("Mission failed, we'll get em next time:\n{x}")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -305,6 +335,25 @@ impl MethodDescriptor {
|
||||
fn psvm() -> Self {
|
||||
MethodDescriptor::parse("([Ljava/lang/String;)V").unwrap()
|
||||
}
|
||||
|
||||
pub fn arg_width(&self) -> usize {
|
||||
self.parameters.iter().fold(0, |acc, e| {
|
||||
acc + match e {
|
||||
FieldType::Base(base) => match base {
|
||||
BaseType::Byte => 1,
|
||||
BaseType::Char => 1,
|
||||
BaseType::Double => 2,
|
||||
BaseType::Float => 1,
|
||||
BaseType::Int => 1,
|
||||
BaseType::Long => 2,
|
||||
BaseType::Short => 1,
|
||||
BaseType::Boolean => 1,
|
||||
},
|
||||
FieldType::ClassType(_) => 1,
|
||||
FieldType::ArrayType(_) => 1,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BaseType {
|
||||
@ -405,6 +454,51 @@ impl From<DekuError> for VmError {
|
||||
impl Frame {
|
||||
fn execute_instruction(&mut self, op: &Ops) -> Result<ExecutionResult, VmError> {
|
||||
match op {
|
||||
// Constants
|
||||
Ops::aconst_null => {
|
||||
self.stack.push(NULL);
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::iconst_m1 => {
|
||||
self.stack.push(Value::Int(-1));
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::iconst_0 => {
|
||||
self.stack.push(Value::Int(0));
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::iconst_1 => {
|
||||
self.stack.push(Value::Int(1));
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::iconst_2 => {
|
||||
self.stack.push(Value::Int(2));
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::iconst_3 => {
|
||||
self.stack.push(Value::Int(3));
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::iconst_4 => {
|
||||
self.stack.push(Value::Int(4));
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::iconst_5 => {
|
||||
self.stack.push(Value::Int(5));
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::bipush(byte) => {
|
||||
self.stack.push(Value::Int(*byte as i32));
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
Ops::ldc(index) => {
|
||||
let thing = self.pool.get_constant(index.to_owned() as u16)?;
|
||||
println!("\tLoading constant: {}", thing);
|
||||
@ -457,42 +551,44 @@ impl Frame {
|
||||
};
|
||||
if let Some(x) = resolved {
|
||||
self.stack.push(x);
|
||||
self.stack.push(Value::Reference(None));
|
||||
};
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
// store
|
||||
Ops::fstore(index) => {
|
||||
store!(self, f, *index as usize)
|
||||
}
|
||||
Ops::fstore_0 => {
|
||||
store!(self, f, 0)
|
||||
}
|
||||
Ops::fstore_1 => {
|
||||
store!(self, f, 1)
|
||||
}
|
||||
Ops::fstore_2 => {
|
||||
store!(self, f, 2)
|
||||
}
|
||||
Ops::fstore_3 => {
|
||||
store!(self, f, 3)
|
||||
}
|
||||
Ops::dstore(index) => {
|
||||
store!(self, d, *index as usize)
|
||||
}
|
||||
Ops::dstore_0 => {
|
||||
store!(self, d, 0)
|
||||
}
|
||||
Ops::dstore_1 => {
|
||||
store!(self, d, 1)
|
||||
}
|
||||
Ops::dstore_2 => {
|
||||
store!(self, d, 2)
|
||||
}
|
||||
Ops::dstore_3 => {
|
||||
store!(self, d, 3)
|
||||
}
|
||||
|
||||
// load
|
||||
// loads
|
||||
|
||||
//iload
|
||||
Ops::iload(index) => {
|
||||
load!(self, i, *index as usize)
|
||||
}
|
||||
Ops::iload_0 => {
|
||||
load!(self, i, 0)
|
||||
}
|
||||
Ops::iload_1 => {
|
||||
load!(self, i, 1)
|
||||
}
|
||||
Ops::iload_2 => {
|
||||
load!(self, i, 2)
|
||||
}
|
||||
Ops::iload_3 => {
|
||||
load!(self, i, 3)
|
||||
}
|
||||
Ops::lload(index) => {
|
||||
load!(self, l, *index as usize)
|
||||
}
|
||||
Ops::lload_0 => {
|
||||
load!(self, l, 0)
|
||||
}
|
||||
Ops::lload_1 => {
|
||||
load!(self, l, 1)
|
||||
}
|
||||
Ops::lload_2 => {
|
||||
load!(self, l, 2)
|
||||
}
|
||||
Ops::lload_3 => {
|
||||
load!(self, l, 3)
|
||||
}
|
||||
Ops::fload(index) => {
|
||||
load!(self, f, *index as usize)
|
||||
}
|
||||
@ -523,19 +619,82 @@ impl Frame {
|
||||
Ops::dload_3 => {
|
||||
load!(self, d, 3)
|
||||
}
|
||||
Ops::aload(index) => {
|
||||
load!(self, a, *index as usize)
|
||||
}
|
||||
Ops::aload_0 => {
|
||||
load!(self, a, 0)
|
||||
}
|
||||
Ops::aload_1 => {
|
||||
load!(self, a, 1)
|
||||
}
|
||||
Ops::aload_2 => {
|
||||
load!(self, a, 2)
|
||||
}
|
||||
Ops::aload_3 => {
|
||||
load!(self, a, 3)
|
||||
}
|
||||
|
||||
Ops::f2d => {
|
||||
if let Value::Float(float) = self.stack.pop().expect("Stack must have value") {
|
||||
let double: f64 = float.into();
|
||||
self.stack.push(Value::Double(double));
|
||||
// store
|
||||
Ops::fstore(index) => {
|
||||
store!(self, f, *index as usize)
|
||||
}
|
||||
Ops::fstore_0 => {
|
||||
store!(self, f, 0)
|
||||
}
|
||||
Ops::fstore_1 => {
|
||||
store!(self, f, 1)
|
||||
}
|
||||
Ops::fstore_2 => {
|
||||
store!(self, f, 2)
|
||||
}
|
||||
Ops::fstore_3 => {
|
||||
store!(self, f, 3)
|
||||
}
|
||||
Ops::dstore(index) => {
|
||||
store!(self, d, *index as usize)
|
||||
}
|
||||
Ops::dstore_0 => {
|
||||
store!(self, d, 0)
|
||||
}
|
||||
Ops::dstore_1 => {
|
||||
store!(self, d, 1)
|
||||
}
|
||||
Ops::dstore_2 => {
|
||||
store!(self, d, 2)
|
||||
}
|
||||
|
||||
Ops::dstore_3 => {
|
||||
store!(self, d, 3)
|
||||
}
|
||||
Ops::lstore(index) => {
|
||||
store!(self, l, *index as usize)
|
||||
}
|
||||
Ops::lstore_0 => {
|
||||
store!(self, l, 0)
|
||||
}
|
||||
Ops::lstore_1 => {
|
||||
store!(self, l, 1)
|
||||
}
|
||||
Ops::lstore_2 => {
|
||||
store!(self, l, 2)
|
||||
}
|
||||
|
||||
Ops::lstore_3 => {
|
||||
store!(self, l, 3)
|
||||
}
|
||||
|
||||
//Stack
|
||||
Ops::dup => {
|
||||
if let Some(value) = self.stack.last() {
|
||||
self.stack.push(value.clone());
|
||||
Ok(ExecutionResult::Continue)
|
||||
} else {
|
||||
Err(VmError::StackError(
|
||||
"Popped value was not float".to_string(),
|
||||
))
|
||||
Err(VmError::StackError("Stack underflow".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
// Math
|
||||
Ops::dadd => {
|
||||
let value1 = self.stack.pop().expect("Stack must have value");
|
||||
let value2 = self.stack.pop().expect("Stack must have value");
|
||||
@ -551,6 +710,23 @@ impl Frame {
|
||||
}
|
||||
}
|
||||
|
||||
//Conversions
|
||||
Ops::f2d => {
|
||||
if let Value::Float(float) = self.stack.pop().expect("Stack must have value") {
|
||||
let double: f64 = float.into();
|
||||
self.stack.push(Value::Double(double));
|
||||
Ok(ExecutionResult::Continue)
|
||||
} else {
|
||||
Err(VmError::StackError(
|
||||
"Popped value was not float".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
// Control
|
||||
Ops::return_void => Ok(ExecutionResult::Return(())),
|
||||
|
||||
// References
|
||||
|
||||
// get static field
|
||||
// can init the field
|
||||
Ops::getstatic(index) => {
|
||||
@ -571,44 +747,82 @@ impl Frame {
|
||||
.clone()
|
||||
.expect("Static field was not initialised");
|
||||
self.stack.push(constant.into());
|
||||
|
||||
// let (code, pool) = {
|
||||
// let mut loader = self.vm.loader.lock().unwrap();
|
||||
// let class = loader.get_or_load(&field.class).unwrap();
|
||||
// let field = class.get_static_field_value(&field)
|
||||
// // let code = class.get_code(meth)?;
|
||||
// (code, pool)
|
||||
// };
|
||||
// println!("{:?}", field);
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::putstatic(index) => {
|
||||
let field_ref = self.pool.resolve_field(*index)?;
|
||||
trace!("Getting static field {field_ref:?}");
|
||||
|
||||
let init_class = self
|
||||
.thread
|
||||
.get_or_resolve_class(&field_ref.class, self.thread.clone())
|
||||
.expect("TO hecken work");
|
||||
let static_field = init_class
|
||||
.find_field(&field_ref.name, field_ref.desc)
|
||||
.expect("TO hecken work");
|
||||
let value = self.stack.pop().expect("stack to have value");
|
||||
*static_field.value.lock().unwrap() = Some(value);
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::getfield(index) => {
|
||||
todo!("op getfield: index - {}", index)
|
||||
}
|
||||
|
||||
Ops::putfield(index) => {
|
||||
let field_ref = self.pool.resolve_field(*index)?;
|
||||
trace!("Setting field {field_ref:?}");
|
||||
let init_class = self
|
||||
.thread
|
||||
.get_class(&field_ref.class)
|
||||
.expect("pre initialised class");
|
||||
// let static_field = init_class
|
||||
// .find_field(&field_ref.name, field_ref.desc)
|
||||
// .expect("TO hecken work");
|
||||
let value = self.stack.pop().expect("value on stack");
|
||||
if let Value::Reference(reference) = self.stack.pop().expect("object on stack") {
|
||||
if let Some(object) = reference {
|
||||
object.lock().unwrap().set_field(&field_ref.name, value);
|
||||
Ok(ExecutionResult::Continue)
|
||||
} else {
|
||||
Err(VmError::StackError("Null pointer exception".to_string()))
|
||||
}
|
||||
} else {
|
||||
Err(VmError::StackError(
|
||||
"putfield tried to operate on a non object stack value".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
// todo!("op putfield: index - {}", index)
|
||||
}
|
||||
Ops::invokevirtual(index) => {
|
||||
let meth = self.pool.resolve_method_ref(*index)?;
|
||||
let params = meth.desc.num_arguments();
|
||||
let last = self.stack.len() - 1;
|
||||
let first = last - params + 1;
|
||||
let slice = self.stack.get(first..last).unwrap().to_vec();
|
||||
//sub slice param length + one, throw it to frame new
|
||||
let (code, pool) = {
|
||||
let mut loader = self.thread.loader.lock().unwrap();
|
||||
let class = loader.get_or_load(&meth.class).unwrap();
|
||||
let pool = class.constant_pool.clone();
|
||||
let code = class
|
||||
.find_method(&meth.name, &meth.desc)
|
||||
.unwrap()
|
||||
.code
|
||||
.clone()
|
||||
.unwrap();
|
||||
(code, pool)
|
||||
};
|
||||
// let code = class.get_code(meth)?;
|
||||
// let class = self.vm.loader.get_or_load(&meth.class).unwrap();
|
||||
// let pool = &class.constant_pool;
|
||||
let vars = slice;
|
||||
let frame = Frame::new(code, pool.clone(), vars, self.thread.clone());
|
||||
// println!("{:?}", meth);
|
||||
// todo!("Finish invoke virtual");
|
||||
let method_ref = self.pool.resolve_method_ref(*index)?;
|
||||
let args_count = method_ref.desc.arg_width();
|
||||
let args = self.stack.split_off(self.stack.len() - args_count);
|
||||
let result = self.thread.invoke(method_ref, args, self.thread.clone())?;
|
||||
if let Some(val) = result {
|
||||
self.stack.push(val)
|
||||
}
|
||||
todo!("Finish invoke virtual");
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::invokespecial(index) => {
|
||||
let method_ref = self.pool.resolve_method_ref(*index)?;
|
||||
let class = self
|
||||
.thread
|
||||
.get_or_resolve_class(&method_ref.class, self.thread.clone())?;
|
||||
|
||||
// the 1 represents the receiver
|
||||
let args_count = method_ref.desc.arg_width() + 1;
|
||||
let args = self.stack.split_off(self.stack.len() - args_count);
|
||||
|
||||
let result = self.thread.invoke(method_ref, args, self.thread.clone())?;
|
||||
if let Some(val) = result {
|
||||
self.stack.push(val)
|
||||
}
|
||||
// todo!("invoke special");
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
@ -617,40 +831,31 @@ impl Frame {
|
||||
let class = self
|
||||
.thread
|
||||
.get_or_resolve_class(&method_ref.class, self.thread.clone())?;
|
||||
// let method_data = class
|
||||
// .find_method(&method_ref.name, method_ref.desc)?
|
||||
// .clone();
|
||||
|
||||
let result = self.thread.invoke(method_ref, self.thread.clone())?;
|
||||
let args_count = method_ref.desc.parameters.len();
|
||||
let args = self.stack.split_off(self.stack.len() - args_count);
|
||||
|
||||
let result = self.thread.invoke(method_ref, args, self.thread.clone())?;
|
||||
if let Some(val) = result {
|
||||
self.stack.push(val)
|
||||
}
|
||||
// todo!("Implement invoke static {}", index)
|
||||
warn!("invoke static not final {}", index);
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::aconst_null => {
|
||||
self.stack.push(NULL);
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
Ops::putstatic(index) => {
|
||||
let field_ref = self.pool.resolve_field(*index)?;
|
||||
println!("Getting static field {field_ref:?}");
|
||||
// can init class
|
||||
Ops::new(index) => {
|
||||
let class = self.pool.resolve_class_name(*index)?;
|
||||
|
||||
let init_class = self
|
||||
.thread
|
||||
.get_or_resolve_class(&field_ref.class, self.thread.clone())
|
||||
.get_or_resolve_class(&class, self.thread.clone())
|
||||
.expect("TO hecken work");
|
||||
let result = init_class
|
||||
.find_field(&field_ref.name, field_ref.desc)
|
||||
.expect("TO hecken work");
|
||||
let value = self.stack.pop().expect("stack to have value");
|
||||
*result.value.lock().unwrap() = Some(value);
|
||||
let object = self.thread.gc.write().unwrap().new(init_class);
|
||||
self.stack.push(Value::Reference(Some(object)));
|
||||
Ok(ExecutionResult::Continue)
|
||||
// todo!("'New' instruction")
|
||||
}
|
||||
|
||||
Ops::return_void => Ok(ExecutionResult::Return(())),
|
||||
_ => {
|
||||
todo!("Unimplemented op: {:?}", op)
|
||||
}
|
||||
|
||||
@ -3,54 +3,71 @@ use crate::Value;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! store {
|
||||
($self:expr, l, $index:expr) => {
|
||||
{{
|
||||
let index: usize = $index;
|
||||
let value = $self.stack.pop().expect("Must contain value on stack");
|
||||
println!("\tStoring: {value:?} into local[{index}]");
|
||||
$self.vars[index] = value;
|
||||
$self.vars[index + 1] = Value::Reference(None);
|
||||
Ok(ExecutionResult::Continue)
|
||||
}}
|
||||
};
|
||||
($self:expr, d, $index:expr) => {store!($self, l, $index)};
|
||||
($self:expr, i, $index:expr) => {
|
||||
{{
|
||||
let index: usize = $index;
|
||||
let value = $self.stack.pop().expect("Must contain value on stack");
|
||||
println!("\tStoring: {value:?} into local[{index}]");
|
||||
$self.vars[index] = value;
|
||||
Ok(ExecutionResult::Continue)
|
||||
}}
|
||||
};
|
||||
($self:expr, f, $index:expr) => {store!($self, i, $index)};
|
||||
($self:expr, l, $index:expr) => {{
|
||||
{
|
||||
let index: usize = $index;
|
||||
let value = $self.stack.pop().expect("Must contain value on stack");
|
||||
println!("\tStoring: {value:?} into local[{index}]");
|
||||
$self.vars[index] = value;
|
||||
$self.vars[index + 1] = Value::Reference(None);
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
}};
|
||||
($self:expr, d, $index:expr) => {
|
||||
store!($self, l, $index)
|
||||
};
|
||||
($self:expr, i, $index:expr) => {{
|
||||
{
|
||||
let index: usize = $index;
|
||||
let value = $self.stack.pop().expect("Must contain value on stack");
|
||||
println!("\tStoring: {value:?} into local[{index}]");
|
||||
$self.vars[index] = value;
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
}};
|
||||
($self:expr, f, $index:expr) => {
|
||||
store!($self, i, $index)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! load {
|
||||
($self:expr, i, $index:expr) => {
|
||||
{{
|
||||
let index: usize = $index;
|
||||
let value = $self.vars.get(index).expect("Local var to exist");
|
||||
println!("\tLoading: local[{index}] - {value:?} onto stack");
|
||||
$self.stack.push(value.clone());
|
||||
Ok(ExecutionResult::Continue)
|
||||
}}
|
||||
};
|
||||
($self:expr, d, $index:expr) => {load!($self, l, $index)};
|
||||
($self:expr, l, $index:expr) => {load!($self, i, $index)};
|
||||
($self:expr, f, $index:expr) => {load!($self, i, $index)};
|
||||
($self:expr, i, $index:expr) => {{
|
||||
{
|
||||
let index: usize = $index;
|
||||
let value = $self.vars.get(index).expect("Local var to exist");
|
||||
println!("\tLoading: local[{index}] - {value} onto stack");
|
||||
$self.stack.push(value.clone());
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
}};
|
||||
($self:expr, d, $index:expr) => {
|
||||
load!($self, l, $index)
|
||||
};
|
||||
($self:expr, l, $index:expr) => {
|
||||
load!($self, i, $index)
|
||||
};
|
||||
($self:expr, f, $index:expr) => {
|
||||
load!($self, i, $index)
|
||||
};
|
||||
($self:expr, a, $index:expr) => {
|
||||
load!($self, i, $index)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! pool_get_impl {
|
||||
($fn_name:ident => $result:ty, $variant:ident) => {
|
||||
fn $fn_name(&self, index: u16) -> Result<&$result, ConstantPoolError> {
|
||||
let cp_entry = self.get_constant(index)?;
|
||||
match cp_entry {
|
||||
ConstantPoolEntry::$variant(value) => Ok(value),
|
||||
_ => Err(ConstantPoolError(format!("Expected {} constant at index {}", stringify!($variant), index))),
|
||||
}
|
||||
}
|
||||
};
|
||||
($fn_name:ident => $result:ty, $variant:ident) => {
|
||||
fn $fn_name(&self, index: u16) -> Result<&$result, ConstantPoolError> {
|
||||
let cp_entry = self.get_constant(index)?;
|
||||
match cp_entry {
|
||||
ConstantPoolEntry::$variant(value) => Ok(value),
|
||||
_ => Err(ConstantPoolError(format!(
|
||||
"Expected {} constant at index {}",
|
||||
stringify!($variant),
|
||||
index
|
||||
))),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,13 +1,31 @@
|
||||
use std::cell::RefCell;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use crate::class::RuntimeClass;
|
||||
use crate::class_file::ClassFile;
|
||||
use crate::Value;
|
||||
use dashmap::DashMap;
|
||||
use log::trace;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Display;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Object {
|
||||
pub id: String,
|
||||
pub class: Arc<ClassFile>,
|
||||
fields: Arc<Mutex<Vec<Value>>>,
|
||||
pub id: u32,
|
||||
pub class: Arc<RuntimeClass>,
|
||||
pub fields: DashMap<String, Value>,
|
||||
}
|
||||
|
||||
impl Object {
|
||||
pub fn set_field(&self, field_name: &str, value: Value) {
|
||||
trace!("Fields for object:\n\t{:?}", self.fields);
|
||||
trace!("Setting '{}' to '{}'", field_name, value);
|
||||
self.fields.insert(field_name.to_string(), value);
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Object {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Object[id={}, class={}]", self.id, self.class.this_class)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Object {
|
||||
|
||||
35
crates/core/src/object_manager.rs
Normal file
35
crates/core/src/object_manager.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use crate::class::RuntimeClass;
|
||||
use crate::object::Object;
|
||||
use crate::rng::generate_identity_hash;
|
||||
use crate::ObjectRef;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ObjectManager {
|
||||
objects: HashMap<u32, ObjectRef>,
|
||||
}
|
||||
|
||||
impl ObjectManager {
|
||||
pub fn new(&mut self, class: Arc<RuntimeClass>) -> ObjectRef {
|
||||
let id = generate_identity_hash();
|
||||
assert!(
|
||||
!self.objects.contains_key(&id),
|
||||
"Generated ID already exists!"
|
||||
);
|
||||
let object = Arc::new(Mutex::new(Object {
|
||||
id,
|
||||
class: class.clone(),
|
||||
fields: Default::default(),
|
||||
}));
|
||||
self.objects.insert(id, object.clone());
|
||||
object
|
||||
}
|
||||
|
||||
pub fn get(&self, id: u32) -> ObjectRef {
|
||||
self.objects
|
||||
.get(&id)
|
||||
.expect("Object must be present")
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
@ -2,17 +2,19 @@ use crate::class::RuntimeClass;
|
||||
use crate::class_file::{ClassFile, MethodData, MethodRef};
|
||||
use crate::class_loader::{ClassLoader, LoaderRef};
|
||||
use crate::jni::create_jni_function_table;
|
||||
use crate::object_manager::ObjectManager;
|
||||
use crate::vm::Vm;
|
||||
use crate::{BaseType, FieldType, Frame, MethodDescriptor, Value, VmError};
|
||||
use deku::DekuError::Incomplete;
|
||||
use jni::sys::jlong;
|
||||
use jni::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jobject, jshort};
|
||||
use jni::JNIEnv;
|
||||
use libffi::low::call;
|
||||
use libffi::middle::*;
|
||||
use log::{trace, warn};
|
||||
use std::any::Any;
|
||||
use std::ops::Add;
|
||||
use std::ptr::null_mut;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::vec::IntoIter;
|
||||
|
||||
type MethodCallResult = Result<Option<Value>, VmError>;
|
||||
@ -22,15 +24,17 @@ pub struct VmThread {
|
||||
pub vm: Arc<Vm>,
|
||||
pub loader: Arc<Mutex<ClassLoader>>,
|
||||
pub frame_stack: Vec<Frame>,
|
||||
pub gc: Arc<RwLock<ObjectManager>>,
|
||||
}
|
||||
|
||||
impl VmThread {
|
||||
pub fn new(vm: Arc<Vm>, loader: Option<LoaderRef>) -> Self {
|
||||
let loader = loader.unwrap_or(vm.loader.clone());
|
||||
Self {
|
||||
vm,
|
||||
vm: vm.clone(),
|
||||
loader,
|
||||
frame_stack: Vec::new(),
|
||||
gc: vm.gc.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,6 +69,14 @@ impl VmThread {
|
||||
Ok(runtime_class)
|
||||
}
|
||||
|
||||
pub fn get_class(&self, what: &str) -> Result<Arc<RuntimeClass>, VmError> {
|
||||
self.loader
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get_or_load(what)
|
||||
.map_err(VmError::LoaderError)
|
||||
}
|
||||
|
||||
/// Initialize a class following JVM Spec 5.5.
|
||||
/// Handles recursive initialization by tracking which thread is initializing.
|
||||
fn init(&self, class: Arc<RuntimeClass>, thread: Arc<VmThread>) -> Result<(), VmError> {
|
||||
@ -157,7 +169,8 @@ impl VmThread {
|
||||
desc: MethodDescriptor::psvm(),
|
||||
};
|
||||
|
||||
self.invoke(method_ref, thread).expect("Main method died");
|
||||
self.invoke(method_ref, Vec::new(), thread)
|
||||
.expect("Main method died");
|
||||
return ();
|
||||
|
||||
let class = self.get_or_resolve_class(what, thread.clone()).unwrap();
|
||||
@ -177,31 +190,38 @@ impl VmThread {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invoke(&self, method_reference: MethodRef, thread: Arc<VmThread>) -> MethodCallResult {
|
||||
pub fn invoke(
|
||||
&self,
|
||||
method_reference: MethodRef,
|
||||
args: Vec<Value>,
|
||||
thread: Arc<VmThread>,
|
||||
) -> MethodCallResult {
|
||||
let class = self.get_or_resolve_class(&method_reference.class, thread.clone())?;
|
||||
let resolved_method = class
|
||||
.find_method(&method_reference.name, &method_reference.desc)
|
||||
.unwrap();
|
||||
println!("invoking {}: {}", method_reference.name, class.this_class);
|
||||
trace!(
|
||||
"invoking '{}' from {}",
|
||||
method_reference.name,
|
||||
class.this_class
|
||||
);
|
||||
if resolved_method.flags.ACC_NATIVE {
|
||||
unsafe {
|
||||
return self.invoke_native(&method_reference);
|
||||
}
|
||||
return self.invoke_native(&method_reference, args);
|
||||
}
|
||||
let mut frame = Frame::new(
|
||||
resolved_method.code.clone().unwrap(),
|
||||
class.constant_pool.clone(),
|
||||
vec![],
|
||||
args,
|
||||
thread.clone(),
|
||||
);
|
||||
frame.execute()
|
||||
}
|
||||
|
||||
pub fn invoke_native(&self, method: &MethodRef) -> MethodCallResult {
|
||||
pub fn invoke_native(&self, method: &MethodRef, args: Vec<Value>) -> MethodCallResult {
|
||||
let symbol_name = generate_jni_method_name(method);
|
||||
println!("{:?}", &symbol_name);
|
||||
trace!("searching for native symbol: {:?}", &symbol_name);
|
||||
|
||||
unsafe {
|
||||
let result = unsafe {
|
||||
// manually load relevant library for poc
|
||||
let lib = libloading::os::windows::Library::new(
|
||||
"C:\\Program Files\\Java\\jdk-25\\bin\\jvm_rs.dll",
|
||||
@ -216,21 +236,90 @@ impl VmThread {
|
||||
);
|
||||
// build actual JNI interface that forms the table of
|
||||
// native functions that can be used to manipulate the JVM
|
||||
let JNIEnv = create_jni_function_table();
|
||||
let jnienv = create_jni_function_table();
|
||||
|
||||
// let args = build_args(args);
|
||||
|
||||
// coerce my method descriptors into libffi C equivalents, then call
|
||||
let l = method
|
||||
.build_cif()
|
||||
.call::<jlong>(cp, &*vec![arg(&JNIEnv), arg(&null_mut::<()>())]);
|
||||
// let l = method.build_cif().call::<jlong>(cp, args.as_ref());
|
||||
|
||||
println!("{l}");
|
||||
}
|
||||
let mut storage = Vec::new();
|
||||
trace!("passing {args:?} to native fn");
|
||||
let built_args = build_args(args, &mut storage);
|
||||
let cif = method.build_cif();
|
||||
|
||||
Ok(None)
|
||||
// todo!("Invoke native")
|
||||
match &method.desc.return_type {
|
||||
None => {
|
||||
cif.call::<()>(cp, built_args.as_ref());
|
||||
Ok(None)
|
||||
}
|
||||
Some(FieldType::Base(BaseType::Long)) => {
|
||||
let v = cif.call::<jlong>(cp, built_args.as_ref());
|
||||
Ok(Some(Value::Long(v)))
|
||||
}
|
||||
Some(FieldType::Base(BaseType::Int)) => {
|
||||
let v = cif.call::<jint>(cp, built_args.as_ref());
|
||||
Ok(Some(Value::Int(v)))
|
||||
}
|
||||
Some(FieldType::Base(BaseType::Float)) => {
|
||||
let v = cif.call::<jfloat>(cp, built_args.as_ref());
|
||||
Ok(Some(Value::Float(v)))
|
||||
}
|
||||
Some(FieldType::Base(BaseType::Double)) => {
|
||||
let v = cif.call::<jdouble>(cp, built_args.as_ref());
|
||||
Ok(Some(Value::Double(v)))
|
||||
}
|
||||
Some(FieldType::Base(BaseType::Boolean)) => {
|
||||
let v = cif.call::<jboolean>(cp, built_args.as_ref());
|
||||
Ok(Some(Value::Int(v as i32)))
|
||||
}
|
||||
Some(FieldType::Base(BaseType::Byte)) => {
|
||||
let v = cif.call::<jbyte>(cp, built_args.as_ref());
|
||||
Ok(Some(Value::Byte(v)))
|
||||
}
|
||||
Some(FieldType::Base(BaseType::Char)) => {
|
||||
let v = cif.call::<jchar>(cp, built_args.as_ref());
|
||||
Ok(Some(Value::Char(v)))
|
||||
}
|
||||
Some(FieldType::Base(BaseType::Short)) => {
|
||||
let v = cif.call::<jshort>(cp, built_args.as_ref());
|
||||
Ok(Some(Value::Short(v)))
|
||||
}
|
||||
Some(FieldType::ClassType(_)) | Some(FieldType::ArrayType(_)) => {
|
||||
let v = cif.call::<jobject>(cp, built_args.as_ref());
|
||||
// TODO: Convert jobject to Reference properly
|
||||
Ok(Some(Value::Reference(None)))
|
||||
}
|
||||
}
|
||||
};
|
||||
warn!("Invoke native not final");
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
fn build_args<'a>(params: Vec<Value>, storage: &'a mut Vec<Box<dyn Any>>) -> Vec<Arg<'a>> {
|
||||
// Store values in the provided storage
|
||||
storage.push(Box::new(create_jni_function_table()) as Box<dyn Any>);
|
||||
storage.push(Box::new(std::ptr::null_mut::<()>()) as Box<dyn Any>);
|
||||
|
||||
for value in params {
|
||||
match value {
|
||||
Value::Int(x) => storage.push(Box::new(x) as Box<dyn Any>),
|
||||
Value::Boolean(x) => storage.push(Box::new(x) as Box<dyn Any>),
|
||||
Value::Char(x) => storage.push(Box::new(x) as Box<dyn Any>),
|
||||
Value::Float(x) => storage.push(Box::new(x) as Box<dyn Any>),
|
||||
Value::Double(x) => storage.push(Box::new(x) as Box<dyn Any>),
|
||||
Value::Byte(x) => storage.push(Box::new(x) as Box<dyn Any>),
|
||||
Value::Short(x) => storage.push(Box::new(x) as Box<dyn Any>),
|
||||
Value::Long(x) => storage.push(Box::new(x) as Box<dyn Any>),
|
||||
Value::Reference(x) => storage.push(Box::new(x) as Box<dyn Any>),
|
||||
}
|
||||
}
|
||||
|
||||
// Create args referencing the storage
|
||||
storage.iter().map(|boxed| arg(&**boxed)).collect()
|
||||
}
|
||||
|
||||
pub fn generate_jni_method_name(method_ref: &MethodRef) -> String {
|
||||
let class_name = &method_ref.class.replace("/", "_");
|
||||
let method_name = &method_ref.name;
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
use crate::class_file::ClassFile;
|
||||
use crate::class_loader::ClassLoader;
|
||||
use crate::object::Object;
|
||||
use crate::object_manager::ObjectManager;
|
||||
use crate::thread::VmThread;
|
||||
use crate::Frame;
|
||||
use libloading::os::windows::Symbol;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
||||
// struct AbstractObject<'a> {}
|
||||
pub struct Vm {
|
||||
@ -12,6 +14,7 @@ pub struct Vm {
|
||||
pub thread: Mutex<Vec<Arc<VmThread>>>,
|
||||
pub loader: Arc<Mutex<ClassLoader>>,
|
||||
pub native_methods: HashMap<String, Symbol<()>>,
|
||||
pub gc: Arc<RwLock<ObjectManager>>,
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
@ -21,6 +24,7 @@ impl Vm {
|
||||
loader: Arc::new(Mutex::from(ClassLoader::default())),
|
||||
thread: Mutex::new(Vec::new()),
|
||||
native_methods: Default::default(),
|
||||
gc: Default::default(),
|
||||
});
|
||||
let thread = Arc::new(VmThread::new(vm.clone(), None));
|
||||
vm.thread.lock().unwrap().push(thread.clone());
|
||||
|
||||
@ -95,3 +95,16 @@ pub extern "system" fn Java_org_example_Main_getTime<'local>(
|
||||
.unwrap()
|
||||
.as_millis() as jlong
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_org_example_MockIO_println<'local>(
|
||||
mut env: JNIEnv<'local>,
|
||||
jclass: JClass<'local>,
|
||||
input: jlong,
|
||||
) {
|
||||
// let input: String = env
|
||||
// .get_string(&input)
|
||||
// .expect("Couldn't get java string!")
|
||||
// .into();
|
||||
println!("{input}")
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user