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::fmt::Display;
|
||||||
use std::ops::Deref;
|
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)]
|
#[derive(Clone, PartialEq, Debug, DekuRead)]
|
||||||
#[deku(ctx = "_endian: deku::ctx::Endian", endian = "big")]
|
#[deku(ctx = "_endian: deku::ctx::Endian", endian = "big")]
|
||||||
@ -59,376 +59,6 @@ pub enum ArrayType {
|
|||||||
#[deku(id = "11")]
|
#[deku(id = "11")]
|
||||||
T_LONG,
|
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 {
|
// impl TryFrom<u8> for Ops {
|
||||||
// type Error = ();
|
// type Error = ();
|
||||||
@ -500,8 +130,10 @@ impl AttributeInfo {
|
|||||||
|
|
||||||
/// Get the interpreted attribute, parsing if necessary
|
/// Get the interpreted attribute, parsing if necessary
|
||||||
pub fn get(&self, class_file: &ClassFile) -> Option<Attribute> {
|
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 {
|
// if let Some(ref attr) = self.interpreted {
|
||||||
// Some(attr.clone())
|
// Some(attr.clone())
|
||||||
@ -511,15 +143,14 @@ impl AttributeInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LocalVariableTableAttribute {
|
impl LocalVariableTableAttribute {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for AttributeInfo {
|
impl Display for AttributeInfo {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
writeln!(f, "AttributeInfo {{ name_index: {}, length: {} }}",
|
writeln!(
|
||||||
self.attribute_name_index,
|
f,
|
||||||
self.attribute_length
|
"AttributeInfo {{ name_index: {}, length: {} }}",
|
||||||
|
self.attribute_name_index, self.attribute_length
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -530,20 +161,32 @@ impl Display for Attribute {
|
|||||||
Attribute::Code(code) => write!(f, "Code attribute: {}", code),
|
Attribute::Code(code) => write!(f, "Code attribute: {}", code),
|
||||||
Attribute::SourceFile(index) => write!(f, "SourceFile attribute, index: {}", index),
|
Attribute::SourceFile(index) => write!(f, "SourceFile attribute, index: {}", index),
|
||||||
Attribute::LineNumberTable(data) => write!(f, "LineNumberTable attribute: {}", data),
|
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::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::Signature(index) => write!(f, "Signature attribute, index: {}", index),
|
||||||
Attribute::LocalVariableTable(table) => write!(f, "LocalVariableTable attribute: {}", table),
|
Attribute::LocalVariableTable(table) => {
|
||||||
Attribute::Unknown(name, data) => write!(f, "Unknown attribute '{}', {} bytes", name, data.len()),
|
write!(f, "LocalVariableTable attribute: {}", table)
|
||||||
_ => { unreachable!() }
|
}
|
||||||
|
Attribute::Unknown(name, data) => {
|
||||||
|
write!(f, "Unknown attribute '{}', {} bytes", name, data.len())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for CodeAttribute {
|
impl Display for CodeAttribute {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "stack={}, locals={}, code={} bytes, exceptions={}, attributes={}",
|
write!(
|
||||||
|
f,
|
||||||
|
"stack={}, locals={}, code={} bytes, exceptions={}, attributes={}",
|
||||||
self.max_stack,
|
self.max_stack,
|
||||||
self.max_locals,
|
self.max_locals,
|
||||||
self.code_length,
|
self.code_length,
|
||||||
@ -598,14 +241,15 @@ pub struct LocalVariableTableEntry {
|
|||||||
|
|
||||||
impl Display for LocalVariableTableAttribute {
|
impl Display for LocalVariableTableAttribute {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "local_variable_table_length={}, entries={}",
|
write!(
|
||||||
|
f,
|
||||||
|
"local_variable_table_length={}, entries={}",
|
||||||
self.local_variable_table_length,
|
self.local_variable_table_length,
|
||||||
self.local_variable_table.len()
|
self.local_variable_table.len()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, DekuRead)]
|
#[derive(Clone, PartialEq, Debug, DekuRead)]
|
||||||
#[deku(endian = "big")]
|
#[deku(endian = "big")]
|
||||||
pub struct LineNumberTableAttribute {
|
pub struct LineNumberTableAttribute {
|
||||||
@ -614,8 +258,6 @@ pub struct LineNumberTableAttribute {
|
|||||||
pub line_number_table: Vec<LineNumberTableEntry>,
|
pub line_number_table: Vec<LineNumberTableEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, DekuRead)]
|
#[derive(Clone, PartialEq, Debug, DekuRead)]
|
||||||
#[deku(ctx = "_endian: deku::ctx::Endian", endian = "big")]
|
#[deku(ctx = "_endian: deku::ctx::Endian", endian = "big")]
|
||||||
pub struct LineNumberTableEntry {
|
pub struct LineNumberTableEntry {
|
||||||
@ -625,7 +267,9 @@ pub struct LineNumberTableEntry {
|
|||||||
|
|
||||||
impl Display for LineNumberTableAttribute {
|
impl Display for LineNumberTableAttribute {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "table_length={}, entries={}",
|
write!(
|
||||||
|
f,
|
||||||
|
"table_length={}, entries={}",
|
||||||
self.line_number_table_length,
|
self.line_number_table_length,
|
||||||
self.line_number_table.len()
|
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::class_file::constant_pool::{ConstantPoolError, ConstantPoolExt, ConstantPoolOwned};
|
||||||
|
use crate::instructions::Ops;
|
||||||
use crate::{BaseType, FieldType, MethodDescriptor, Value};
|
use crate::{BaseType, FieldType, MethodDescriptor, Value};
|
||||||
use deku::ctx::Endian::Big;
|
use deku::ctx::Endian::Big;
|
||||||
use deku::{DekuContainerRead, DekuError};
|
use deku::{DekuContainerRead, DekuError};
|
||||||
|
|||||||
@ -67,8 +67,7 @@ pub trait ConstantPoolExt: ConstantPoolGet {
|
|||||||
|
|
||||||
fn resolve_field(&self, index: u16) -> Result<FieldRef, ConstantPoolError> {
|
fn resolve_field(&self, index: u16) -> Result<FieldRef, ConstantPoolError> {
|
||||||
let fr = self.get_field_ref(index)?;
|
let fr = self.get_field_ref(index)?;
|
||||||
let class = self.get_class_info(fr.class_index)?;
|
let class = self.resolve_class_name(fr.class_index)?;
|
||||||
let class = self.get_string(class.name_index)?;
|
|
||||||
let name_and_type = self.get_name_and_type_info(fr.name_and_type_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 name = self.get_string(name_and_type.name_index)?;
|
||||||
let desc = self.get_string(name_and_type.descriptor_index)?;
|
let desc = self.get_string(name_and_type.descriptor_index)?;
|
||||||
@ -76,10 +75,24 @@ pub trait ConstantPoolExt: ConstantPoolGet {
|
|||||||
Ok(FieldRef { class, name, desc })
|
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> {
|
fn resolve_method_ref(&self, index: u16) -> Result<MethodRef, ConstantPoolError> {
|
||||||
let mr = self.get_method_ref(index)?;
|
let mr = self.get_method_ref(index)?;
|
||||||
let class = self.get_class_info(mr.class_index)?;
|
let class = self.resolve_class_name(mr.class_index)?;
|
||||||
let class = self.get_string(class.name_index)?;
|
|
||||||
let name_and_type = self.get_name_and_type_info(mr.name_and_type_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 name = self.get_string(name_and_type.name_index)?;
|
||||||
let desc = self.get_string(name_and_type.descriptor_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 crate::{FieldType, MethodDescriptor};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use deku::DekuContainerRead;
|
use deku::DekuContainerRead;
|
||||||
|
use itertools::Itertools;
|
||||||
use libloading::os::windows::Library;
|
use libloading::os::windows::Library;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use std::collections::hash_map::{Entry, Iter};
|
use std::collections::hash_map::{Entry, Iter};
|
||||||
@ -149,14 +150,10 @@ impl ClassLoader {
|
|||||||
|
|
||||||
fn load_class(&mut self, what: &str) -> Result<Arc<RuntimeClass>, String> {
|
fn load_class(&mut self, what: &str) -> Result<Arc<RuntimeClass>, String> {
|
||||||
let (module, class_fqn) = ("", what);
|
let (module, class_fqn) = ("", what);
|
||||||
let bytes = self.bimage.get_class(module, class_fqn).unwrap_or_else(|| {
|
let bytes = self
|
||||||
let path = format!("./data/{what}.class");
|
.bimage
|
||||||
log::info!("Loading class from path: {}", path);
|
.get_class(module, class_fqn)
|
||||||
let mut class_file = File::open(path).unwrap();
|
.unwrap_or_else(|| Self::load_class_from_disk(what));
|
||||||
let mut bytes = Vec::new();
|
|
||||||
class_file.read_to_end(&mut bytes).unwrap();
|
|
||||||
bytes
|
|
||||||
});
|
|
||||||
let (_, cf) = ClassFile::from_bytes((bytes.as_ref(), 0))
|
let (_, cf) = ClassFile::from_bytes((bytes.as_ref(), 0))
|
||||||
.map_err(|e| format!("failed to parse class file: {}", e))?;
|
.map_err(|e| format!("failed to parse class file: {}", e))?;
|
||||||
let runtime = self.runtime_class(cf);
|
let runtime = self.runtime_class(cf);
|
||||||
@ -168,6 +165,20 @@ impl ClassLoader {
|
|||||||
Ok(arced)
|
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 {
|
fn runtime_class(&mut self, class_file: ClassFile) -> RuntimeClass {
|
||||||
let constant_pool = class_file.constant_pool.clone();
|
let constant_pool = class_file.constant_pool.clone();
|
||||||
let access_flags = ClassFlags::from(class_file.access_flags);
|
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
|
//! - [`MethodDescriptor`] - Method signature information
|
||||||
//! - [`FieldType`] - Field type 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::ConstantPoolExt;
|
||||||
use crate::class_file::constant_pool::{ConstantPoolError, ConstantPoolGet};
|
use crate::class_file::constant_pool::{ConstantPoolError, ConstantPoolGet};
|
||||||
use crate::class_file::{Bytecode, ClassFile, ConstantPoolEntry, MethodData};
|
use crate::class_file::{Bytecode, ClassFile, ConstantPoolEntry, MethodData};
|
||||||
use crate::object::Object;
|
use crate::object::Object;
|
||||||
use crate::thread::VmThread;
|
use crate::thread::VmThread;
|
||||||
use crate::Value::Reference;
|
|
||||||
use deku::{DekuContainerRead, DekuError};
|
use deku::{DekuContainerRead, DekuError};
|
||||||
use deku_derive::{DekuRead, DekuWrite};
|
use deku_derive::{DekuRead, DekuWrite};
|
||||||
use env_logger::Builder;
|
use env_logger::Builder;
|
||||||
use log::{warn, LevelFilter};
|
use instructions::Ops;
|
||||||
|
use log::{trace, warn, LevelFilter};
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use vm::Vm;
|
use vm::Vm;
|
||||||
|
|
||||||
@ -37,10 +38,12 @@ mod bimage;
|
|||||||
mod class;
|
mod class;
|
||||||
mod class_file;
|
mod class_file;
|
||||||
mod class_loader;
|
mod class_loader;
|
||||||
|
mod instructions;
|
||||||
mod jni;
|
mod jni;
|
||||||
mod macros;
|
mod macros;
|
||||||
mod native_libraries;
|
mod native_libraries;
|
||||||
mod object;
|
mod object;
|
||||||
|
mod object_manager;
|
||||||
mod rng;
|
mod rng;
|
||||||
mod thread;
|
mod thread;
|
||||||
mod vm;
|
mod vm;
|
||||||
@ -55,6 +58,7 @@ pub fn run() {
|
|||||||
.filter_module("deku", LevelFilter::Warn)
|
.filter_module("deku", LevelFilter::Warn)
|
||||||
.filter_module("jvm_rs_core::class_file::class_file", LevelFilter::Info)
|
.filter_module("jvm_rs_core::class_file::class_file", LevelFilter::Info)
|
||||||
.filter_module("jvm_rs_core::attributes", LevelFilter::Info)
|
.filter_module("jvm_rs_core::attributes", LevelFilter::Info)
|
||||||
|
.filter_module("jvm_rs_core::instructions", LevelFilter::Info)
|
||||||
.init();
|
.init();
|
||||||
// let mut cl = ClassLoader::new().unwrap();
|
// let mut cl = ClassLoader::new().unwrap();
|
||||||
// cl.load_class("org.example.App").expect("TODO: panic message");
|
// cl.load_class("org.example.App").expect("TODO: panic message");
|
||||||
@ -118,7 +122,7 @@ enum Value {
|
|||||||
/// Boolean value (true/false)
|
/// Boolean value (true/false)
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
/// Unicode character
|
/// Unicode character
|
||||||
Char(char),
|
Char(u16),
|
||||||
/// 32-bit floating point
|
/// 32-bit floating point
|
||||||
Float(f32),
|
Float(f32),
|
||||||
/// 64-bit floating point
|
/// 64-bit floating point
|
||||||
@ -135,6 +139,23 @@ enum Value {
|
|||||||
Reference(Option<ObjectRef>),
|
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.
|
/// Represents a JVM stack frame for method execution.
|
||||||
///
|
///
|
||||||
/// A frame contains all the execution state needed to run a single method:
|
/// 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(ExecutionResult::ReturnValue(val)) => return Ok(Some(val)),
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
println!(
|
println!(
|
||||||
"State:\n\tStack: {:?}\n\tLocals :{:?}\n",
|
"State:\n\tStack: [{}]\n\tLocals: [{}]\n",
|
||||||
self.stack, self.vars
|
self.stack
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", "),
|
||||||
|
self.vars
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(x) => {
|
||||||
panic!("Mission failed, we'll get em next time")
|
panic!("Mission failed, we'll get em next time:\n{x}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,6 +335,25 @@ impl MethodDescriptor {
|
|||||||
fn psvm() -> Self {
|
fn psvm() -> Self {
|
||||||
MethodDescriptor::parse("([Ljava/lang/String;)V").unwrap()
|
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 {
|
impl Display for BaseType {
|
||||||
@ -405,6 +454,51 @@ impl From<DekuError> for VmError {
|
|||||||
impl Frame {
|
impl Frame {
|
||||||
fn execute_instruction(&mut self, op: &Ops) -> Result<ExecutionResult, VmError> {
|
fn execute_instruction(&mut self, op: &Ops) -> Result<ExecutionResult, VmError> {
|
||||||
match op {
|
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) => {
|
Ops::ldc(index) => {
|
||||||
let thing = self.pool.get_constant(index.to_owned() as u16)?;
|
let thing = self.pool.get_constant(index.to_owned() as u16)?;
|
||||||
println!("\tLoading constant: {}", thing);
|
println!("\tLoading constant: {}", thing);
|
||||||
@ -457,42 +551,44 @@ impl Frame {
|
|||||||
};
|
};
|
||||||
if let Some(x) = resolved {
|
if let Some(x) = resolved {
|
||||||
self.stack.push(x);
|
self.stack.push(x);
|
||||||
|
self.stack.push(Value::Reference(None));
|
||||||
};
|
};
|
||||||
Ok(ExecutionResult::Continue)
|
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) => {
|
Ops::fload(index) => {
|
||||||
load!(self, f, *index as usize)
|
load!(self, f, *index as usize)
|
||||||
}
|
}
|
||||||
@ -523,19 +619,82 @@ impl Frame {
|
|||||||
Ops::dload_3 => {
|
Ops::dload_3 => {
|
||||||
load!(self, d, 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 => {
|
// store
|
||||||
if let Value::Float(float) = self.stack.pop().expect("Stack must have value") {
|
Ops::fstore(index) => {
|
||||||
let double: f64 = float.into();
|
store!(self, f, *index as usize)
|
||||||
self.stack.push(Value::Double(double));
|
}
|
||||||
|
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)
|
Ok(ExecutionResult::Continue)
|
||||||
} else {
|
} else {
|
||||||
Err(VmError::StackError(
|
Err(VmError::StackError("Stack underflow".to_string()))
|
||||||
"Popped value was not float".to_string(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Math
|
||||||
Ops::dadd => {
|
Ops::dadd => {
|
||||||
let value1 = self.stack.pop().expect("Stack must have value");
|
let value1 = self.stack.pop().expect("Stack must have value");
|
||||||
let value2 = 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
|
// get static field
|
||||||
// can init the field
|
// can init the field
|
||||||
Ops::getstatic(index) => {
|
Ops::getstatic(index) => {
|
||||||
@ -571,44 +747,82 @@ impl Frame {
|
|||||||
.clone()
|
.clone()
|
||||||
.expect("Static field was not initialised");
|
.expect("Static field was not initialised");
|
||||||
self.stack.push(constant.into());
|
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)
|
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) => {
|
Ops::invokevirtual(index) => {
|
||||||
let meth = self.pool.resolve_method_ref(*index)?;
|
let method_ref = self.pool.resolve_method_ref(*index)?;
|
||||||
let params = meth.desc.num_arguments();
|
let args_count = method_ref.desc.arg_width();
|
||||||
let last = self.stack.len() - 1;
|
let args = self.stack.split_off(self.stack.len() - args_count);
|
||||||
let first = last - params + 1;
|
let result = self.thread.invoke(method_ref, args, self.thread.clone())?;
|
||||||
let slice = self.stack.get(first..last).unwrap().to_vec();
|
if let Some(val) = result {
|
||||||
//sub slice param length + one, throw it to frame new
|
self.stack.push(val)
|
||||||
let (code, pool) = {
|
}
|
||||||
let mut loader = self.thread.loader.lock().unwrap();
|
todo!("Finish invoke virtual");
|
||||||
let class = loader.get_or_load(&meth.class).unwrap();
|
Ok(ExecutionResult::Continue)
|
||||||
let pool = class.constant_pool.clone();
|
}
|
||||||
let code = class
|
|
||||||
.find_method(&meth.name, &meth.desc)
|
Ops::invokespecial(index) => {
|
||||||
.unwrap()
|
let method_ref = self.pool.resolve_method_ref(*index)?;
|
||||||
.code
|
let class = self
|
||||||
.clone()
|
.thread
|
||||||
.unwrap();
|
.get_or_resolve_class(&method_ref.class, self.thread.clone())?;
|
||||||
(code, pool)
|
|
||||||
};
|
// the 1 represents the receiver
|
||||||
// let code = class.get_code(meth)?;
|
let args_count = method_ref.desc.arg_width() + 1;
|
||||||
// let class = self.vm.loader.get_or_load(&meth.class).unwrap();
|
let args = self.stack.split_off(self.stack.len() - args_count);
|
||||||
// let pool = &class.constant_pool;
|
|
||||||
let vars = slice;
|
let result = self.thread.invoke(method_ref, args, self.thread.clone())?;
|
||||||
let frame = Frame::new(code, pool.clone(), vars, self.thread.clone());
|
if let Some(val) = result {
|
||||||
// println!("{:?}", meth);
|
self.stack.push(val)
|
||||||
// todo!("Finish invoke virtual");
|
}
|
||||||
|
// todo!("invoke special");
|
||||||
Ok(ExecutionResult::Continue)
|
Ok(ExecutionResult::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,40 +831,31 @@ impl Frame {
|
|||||||
let class = self
|
let class = self
|
||||||
.thread
|
.thread
|
||||||
.get_or_resolve_class(&method_ref.class, self.thread.clone())?;
|
.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 {
|
if let Some(val) = result {
|
||||||
self.stack.push(val)
|
self.stack.push(val)
|
||||||
}
|
}
|
||||||
// todo!("Implement invoke static {}", index)
|
warn!("invoke static not final {}", index);
|
||||||
Ok(ExecutionResult::Continue)
|
Ok(ExecutionResult::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
Ops::aconst_null => {
|
// can init class
|
||||||
self.stack.push(NULL);
|
Ops::new(index) => {
|
||||||
Ok(ExecutionResult::Continue)
|
let class = self.pool.resolve_class_name(*index)?;
|
||||||
}
|
|
||||||
|
|
||||||
Ops::putstatic(index) => {
|
|
||||||
let field_ref = self.pool.resolve_field(*index)?;
|
|
||||||
println!("Getting static field {field_ref:?}");
|
|
||||||
|
|
||||||
let init_class = self
|
let init_class = self
|
||||||
.thread
|
.thread
|
||||||
.get_or_resolve_class(&field_ref.class, self.thread.clone())
|
.get_or_resolve_class(&class, self.thread.clone())
|
||||||
.expect("TO hecken work");
|
.expect("TO hecken work");
|
||||||
let result = init_class
|
let object = self.thread.gc.write().unwrap().new(init_class);
|
||||||
.find_field(&field_ref.name, field_ref.desc)
|
self.stack.push(Value::Reference(Some(object)));
|
||||||
.expect("TO hecken work");
|
|
||||||
let value = self.stack.pop().expect("stack to have value");
|
|
||||||
*result.value.lock().unwrap() = Some(value);
|
|
||||||
Ok(ExecutionResult::Continue)
|
Ok(ExecutionResult::Continue)
|
||||||
|
// todo!("'New' instruction")
|
||||||
}
|
}
|
||||||
|
|
||||||
Ops::return_void => Ok(ExecutionResult::Return(())),
|
|
||||||
_ => {
|
_ => {
|
||||||
todo!("Unimplemented op: {:?}", op)
|
todo!("Unimplemented op: {:?}", op)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,43 +3,56 @@ use crate::Value;
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! store {
|
macro_rules! store {
|
||||||
($self:expr, l, $index:expr) => {
|
($self:expr, l, $index:expr) => {{
|
||||||
{{
|
{
|
||||||
let index: usize = $index;
|
let index: usize = $index;
|
||||||
let value = $self.stack.pop().expect("Must contain value on stack");
|
let value = $self.stack.pop().expect("Must contain value on stack");
|
||||||
println!("\tStoring: {value:?} into local[{index}]");
|
println!("\tStoring: {value:?} into local[{index}]");
|
||||||
$self.vars[index] = value;
|
$self.vars[index] = value;
|
||||||
$self.vars[index + 1] = Value::Reference(None);
|
$self.vars[index + 1] = Value::Reference(None);
|
||||||
Ok(ExecutionResult::Continue)
|
Ok(ExecutionResult::Continue)
|
||||||
}}
|
}
|
||||||
|
}};
|
||||||
|
($self:expr, d, $index:expr) => {
|
||||||
|
store!($self, l, $index)
|
||||||
};
|
};
|
||||||
($self:expr, d, $index:expr) => {store!($self, l, $index)};
|
($self:expr, i, $index:expr) => {{
|
||||||
($self:expr, i, $index:expr) => {
|
{
|
||||||
{{
|
|
||||||
let index: usize = $index;
|
let index: usize = $index;
|
||||||
let value = $self.stack.pop().expect("Must contain value on stack");
|
let value = $self.stack.pop().expect("Must contain value on stack");
|
||||||
println!("\tStoring: {value:?} into local[{index}]");
|
println!("\tStoring: {value:?} into local[{index}]");
|
||||||
$self.vars[index] = value;
|
$self.vars[index] = value;
|
||||||
Ok(ExecutionResult::Continue)
|
Ok(ExecutionResult::Continue)
|
||||||
}}
|
}
|
||||||
|
}};
|
||||||
|
($self:expr, f, $index:expr) => {
|
||||||
|
store!($self, i, $index)
|
||||||
};
|
};
|
||||||
($self:expr, f, $index:expr) => {store!($self, i, $index)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! load {
|
macro_rules! load {
|
||||||
($self:expr, i, $index:expr) => {
|
($self:expr, i, $index:expr) => {{
|
||||||
{{
|
{
|
||||||
let index: usize = $index;
|
let index: usize = $index;
|
||||||
let value = $self.vars.get(index).expect("Local var to exist");
|
let value = $self.vars.get(index).expect("Local var to exist");
|
||||||
println!("\tLoading: local[{index}] - {value:?} onto stack");
|
println!("\tLoading: local[{index}] - {value} onto stack");
|
||||||
$self.stack.push(value.clone());
|
$self.stack.push(value.clone());
|
||||||
Ok(ExecutionResult::Continue)
|
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)
|
||||||
};
|
};
|
||||||
($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)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
@ -49,7 +62,11 @@ macro_rules! pool_get_impl {
|
|||||||
let cp_entry = self.get_constant(index)?;
|
let cp_entry = self.get_constant(index)?;
|
||||||
match cp_entry {
|
match cp_entry {
|
||||||
ConstantPoolEntry::$variant(value) => Ok(value),
|
ConstantPoolEntry::$variant(value) => Ok(value),
|
||||||
_ => Err(ConstantPoolError(format!("Expected {} constant at index {}", stringify!($variant), index))),
|
_ => Err(ConstantPoolError(format!(
|
||||||
|
"Expected {} constant at index {}",
|
||||||
|
stringify!($variant),
|
||||||
|
index
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,13 +1,31 @@
|
|||||||
use std::cell::RefCell;
|
use crate::class::RuntimeClass;
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use crate::class_file::ClassFile;
|
use crate::class_file::ClassFile;
|
||||||
use crate::Value;
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
pub id: String,
|
pub id: u32,
|
||||||
pub class: Arc<ClassFile>,
|
pub class: Arc<RuntimeClass>,
|
||||||
fields: Arc<Mutex<Vec<Value>>>,
|
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 {
|
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_file::{ClassFile, MethodData, MethodRef};
|
||||||
use crate::class_loader::{ClassLoader, LoaderRef};
|
use crate::class_loader::{ClassLoader, LoaderRef};
|
||||||
use crate::jni::create_jni_function_table;
|
use crate::jni::create_jni_function_table;
|
||||||
|
use crate::object_manager::ObjectManager;
|
||||||
use crate::vm::Vm;
|
use crate::vm::Vm;
|
||||||
use crate::{BaseType, FieldType, Frame, MethodDescriptor, Value, VmError};
|
use crate::{BaseType, FieldType, Frame, MethodDescriptor, Value, VmError};
|
||||||
use deku::DekuError::Incomplete;
|
use deku::DekuError::Incomplete;
|
||||||
use jni::sys::jlong;
|
use jni::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jobject, jshort};
|
||||||
use jni::JNIEnv;
|
use jni::JNIEnv;
|
||||||
use libffi::low::call;
|
use libffi::low::call;
|
||||||
use libffi::middle::*;
|
use libffi::middle::*;
|
||||||
use log::{trace, warn};
|
use log::{trace, warn};
|
||||||
|
use std::any::Any;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
type MethodCallResult = Result<Option<Value>, VmError>;
|
type MethodCallResult = Result<Option<Value>, VmError>;
|
||||||
@ -22,15 +24,17 @@ pub struct VmThread {
|
|||||||
pub vm: Arc<Vm>,
|
pub vm: Arc<Vm>,
|
||||||
pub loader: Arc<Mutex<ClassLoader>>,
|
pub loader: Arc<Mutex<ClassLoader>>,
|
||||||
pub frame_stack: Vec<Frame>,
|
pub frame_stack: Vec<Frame>,
|
||||||
|
pub gc: Arc<RwLock<ObjectManager>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VmThread {
|
impl VmThread {
|
||||||
pub fn new(vm: Arc<Vm>, loader: Option<LoaderRef>) -> Self {
|
pub fn new(vm: Arc<Vm>, loader: Option<LoaderRef>) -> Self {
|
||||||
let loader = loader.unwrap_or(vm.loader.clone());
|
let loader = loader.unwrap_or(vm.loader.clone());
|
||||||
Self {
|
Self {
|
||||||
vm,
|
vm: vm.clone(),
|
||||||
loader,
|
loader,
|
||||||
frame_stack: Vec::new(),
|
frame_stack: Vec::new(),
|
||||||
|
gc: vm.gc.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +69,14 @@ impl VmThread {
|
|||||||
Ok(runtime_class)
|
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.
|
/// Initialize a class following JVM Spec 5.5.
|
||||||
/// Handles recursive initialization by tracking which thread is initializing.
|
/// Handles recursive initialization by tracking which thread is initializing.
|
||||||
fn init(&self, class: Arc<RuntimeClass>, thread: Arc<VmThread>) -> Result<(), VmError> {
|
fn init(&self, class: Arc<RuntimeClass>, thread: Arc<VmThread>) -> Result<(), VmError> {
|
||||||
@ -157,7 +169,8 @@ impl VmThread {
|
|||||||
desc: MethodDescriptor::psvm(),
|
desc: MethodDescriptor::psvm(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.invoke(method_ref, thread).expect("Main method died");
|
self.invoke(method_ref, Vec::new(), thread)
|
||||||
|
.expect("Main method died");
|
||||||
return ();
|
return ();
|
||||||
|
|
||||||
let class = self.get_or_resolve_class(what, thread.clone()).unwrap();
|
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 class = self.get_or_resolve_class(&method_reference.class, thread.clone())?;
|
||||||
let resolved_method = class
|
let resolved_method = class
|
||||||
.find_method(&method_reference.name, &method_reference.desc)
|
.find_method(&method_reference.name, &method_reference.desc)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("invoking {}: {}", method_reference.name, class.this_class);
|
trace!(
|
||||||
|
"invoking '{}' from {}",
|
||||||
|
method_reference.name,
|
||||||
|
class.this_class
|
||||||
|
);
|
||||||
if resolved_method.flags.ACC_NATIVE {
|
if resolved_method.flags.ACC_NATIVE {
|
||||||
unsafe {
|
return self.invoke_native(&method_reference, args);
|
||||||
return self.invoke_native(&method_reference);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let mut frame = Frame::new(
|
let mut frame = Frame::new(
|
||||||
resolved_method.code.clone().unwrap(),
|
resolved_method.code.clone().unwrap(),
|
||||||
class.constant_pool.clone(),
|
class.constant_pool.clone(),
|
||||||
vec![],
|
args,
|
||||||
thread.clone(),
|
thread.clone(),
|
||||||
);
|
);
|
||||||
frame.execute()
|
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);
|
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
|
// manually load relevant library for poc
|
||||||
let lib = libloading::os::windows::Library::new(
|
let lib = libloading::os::windows::Library::new(
|
||||||
"C:\\Program Files\\Java\\jdk-25\\bin\\jvm_rs.dll",
|
"C:\\Program Files\\Java\\jdk-25\\bin\\jvm_rs.dll",
|
||||||
@ -216,19 +236,88 @@ impl VmThread {
|
|||||||
);
|
);
|
||||||
// build actual JNI interface that forms the table of
|
// build actual JNI interface that forms the table of
|
||||||
// native functions that can be used to manipulate the JVM
|
// 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
|
// coerce my method descriptors into libffi C equivalents, then call
|
||||||
let l = method
|
// let l = method.build_cif().call::<jlong>(cp, args.as_ref());
|
||||||
.build_cif()
|
|
||||||
.call::<jlong>(cp, &*vec![arg(&JNIEnv), arg(&null_mut::<()>())]);
|
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
|
match &method.desc.return_type {
|
||||||
|
None => {
|
||||||
|
cif.call::<()>(cp, built_args.as_ref());
|
||||||
Ok(None)
|
Ok(None)
|
||||||
// todo!("Invoke native")
|
|
||||||
}
|
}
|
||||||
|
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 {
|
pub fn generate_jni_method_name(method_ref: &MethodRef) -> String {
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
use crate::class_file::ClassFile;
|
use crate::class_file::ClassFile;
|
||||||
use crate::class_loader::ClassLoader;
|
use crate::class_loader::ClassLoader;
|
||||||
|
use crate::object::Object;
|
||||||
|
use crate::object_manager::ObjectManager;
|
||||||
use crate::thread::VmThread;
|
use crate::thread::VmThread;
|
||||||
use crate::Frame;
|
use crate::Frame;
|
||||||
use libloading::os::windows::Symbol;
|
use libloading::os::windows::Symbol;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
|
||||||
// struct AbstractObject<'a> {}
|
// struct AbstractObject<'a> {}
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
@ -12,6 +14,7 @@ pub struct Vm {
|
|||||||
pub thread: Mutex<Vec<Arc<VmThread>>>,
|
pub thread: Mutex<Vec<Arc<VmThread>>>,
|
||||||
pub loader: Arc<Mutex<ClassLoader>>,
|
pub loader: Arc<Mutex<ClassLoader>>,
|
||||||
pub native_methods: HashMap<String, Symbol<()>>,
|
pub native_methods: HashMap<String, Symbol<()>>,
|
||||||
|
pub gc: Arc<RwLock<ObjectManager>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
@ -21,6 +24,7 @@ impl Vm {
|
|||||||
loader: Arc::new(Mutex::from(ClassLoader::default())),
|
loader: Arc::new(Mutex::from(ClassLoader::default())),
|
||||||
thread: Mutex::new(Vec::new()),
|
thread: Mutex::new(Vec::new()),
|
||||||
native_methods: Default::default(),
|
native_methods: Default::default(),
|
||||||
|
gc: Default::default(),
|
||||||
});
|
});
|
||||||
let thread = Arc::new(VmThread::new(vm.clone(), None));
|
let thread = Arc::new(VmThread::new(vm.clone(), None));
|
||||||
vm.thread.lock().unwrap().push(thread.clone());
|
vm.thread.lock().unwrap().push(thread.clone());
|
||||||
|
|||||||
@ -95,3 +95,16 @@ pub extern "system" fn Java_org_example_Main_getTime<'local>(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.as_millis() as jlong
|
.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