diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml
new file mode 100644
index 0000000..f26bfd0
--- /dev/null
+++ b/.idea/dictionaries/project.xml
@@ -0,0 +1,7 @@
+
+
+
+ stacktraceelement
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 146e386..cfd99d5 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -2,5 +2,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index 9f3192f..3049bbd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,7 +21,8 @@ roast-vm-core = { path = "crates/core" }
colored = "3.0.0"
parking_lot = "0.12"
cesu8 = "1.1.0"
-windows = { version = "0.62.0", features = ["Win32_System_Diagnostics_Debug", "Win32_System_Kernel"] }
+windows = { version = "0.62.0", features = ["Win32_System_Diagnostics_Debug", "Win32_System_Kernel", "Win32_System_Threading"] }
+libc = "0.2.178"
[profile.dev-opt]
inherits = "dev"
opt-level = 2 # 0=none, 1=basic, 2=good, 3=aggressive
diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml
index ac91bc0..60c7139 100644
--- a/crates/core/Cargo.toml
+++ b/crates/core/Cargo.toml
@@ -19,6 +19,7 @@ colored = { workspace = true }
parking_lot = { workspace = true }
cesu8 = { workspace = true }
windows = { workspace = true }
+libc = { workspace = true }
diff --git a/crates/core/src/class.rs b/crates/core/src/class.rs
index 114f5e8..8b14909 100644
--- a/crates/core/src/class.rs
+++ b/crates/core/src/class.rs
@@ -1,13 +1,12 @@
use crate::class_file::attributes::BootstrapMethodsAttribute;
use crate::class_file::{ClassFlags, ConstantPoolEntry, FieldData, MethodData};
use crate::error::VmError;
-use crate::{FieldType, MethodDescriptor};
+use crate::{FieldType, MethodDescriptor, ThreadId};
use log::trace;
use parking_lot::Mutex;
use std::hash::{Hash, Hasher};
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, OnceLock};
-use std::thread::ThreadId;
/// JVM Spec 5.5: Initialization states for a class
#[derive(Debug, Clone, PartialEq)]
diff --git a/crates/core/src/class_file/class_file.rs b/crates/core/src/class_file/class_file.rs
index d42938b..15048dc 100644
--- a/crates/core/src/class_file/class_file.rs
+++ b/crates/core/src/class_file/class_file.rs
@@ -2,6 +2,7 @@ use crate::class_file::attributes::{
Attribute, AttributeInfo, CodeAttribute, LineNumberTableEntry,
};
use crate::class_file::constant_pool::{ConstantPoolExt, ConstantPoolOwned};
+use crate::class_file::resolved::{InterfaceMethodRef, MethodRef};
use crate::instructions::Ops;
use crate::value::Value;
use crate::{BaseType, FieldType, MethodDescriptor};
@@ -17,6 +18,8 @@ use std::ops::Deref;
use std::str::Chars;
use std::sync::Arc;
+pub type FieldDescriptor = FieldType;
+
#[derive(Debug, PartialEq, DekuRead)]
#[deku(magic = b"\xCA\xFE\xBA\xBE", endian = "big")]
pub struct ClassFile {
@@ -648,12 +651,6 @@ pub(crate) struct Bytecode {
// }
// }
-#[derive(Debug, Clone)]
-pub struct MethodRef {
- pub class: String,
- pub name: String,
- pub desc: MethodDescriptor,
-}
#[derive(Debug, Clone)]
pub struct MethodData {
pub name: String,
@@ -669,41 +666,6 @@ pub struct MethodData {
// pub method_parameters: Option<_>
}
-impl From for MethodRef {
- fn from(value: MethodData) -> Self {
- Self {
- class: value.class,
- name: value.name,
- desc: value.desc,
- }
- }
-}
-
-impl From<&MethodData> for MethodRef {
- fn from(value: &MethodData) -> Self {
- value.clone().into()
- }
-}
-
-#[derive(Debug)]
-pub struct FieldRef {
- pub class: String,
- pub name: String,
- pub desc: FieldType,
-}
-
-impl FieldRef {
- pub fn new(class: &str, name: &str, field: FieldType) -> Self {
- let class = class.to_string();
- let name = name.to_string();
- Self {
- class,
- name,
- desc: field,
- }
- }
-}
-
#[derive(Debug)]
pub struct FieldData {
pub name: String,
@@ -1010,3 +972,255 @@ impl FieldType {
})
}
}
+
+pub mod resolved {
+ use crate::class_file::MethodData;
+ use crate::class_file::class_file::FieldDescriptor;
+ use crate::{FieldType, MethodDescriptor};
+
+ #[derive(Debug, Clone)]
+ pub struct FieldRef {
+ pub class: String,
+ pub name: String,
+ pub desc: FieldDescriptor,
+ }
+
+ impl FieldRef {
+ pub(crate) fn from_symbols(class: &str, name: &str, descriptor_class_name: &str) -> Self {
+ let class = class.to_string();
+ let name = name.to_string();
+ let desc = FieldDescriptor::from_symbols(descriptor_class_name);
+ Self { class, name, desc }
+ }
+ }
+
+ impl FieldRef {
+ pub fn new(class: &str, name: &str, field: FieldType) -> Self {
+ let class = class.to_string();
+ let name = name.to_string();
+ Self {
+ class,
+ name,
+ desc: field,
+ }
+ }
+ }
+
+ #[derive(Debug, Clone)]
+ pub struct MethodRef {
+ pub class: String,
+ pub name: String,
+ pub desc: MethodDescriptor,
+ }
+
+ impl MethodRef {
+ pub fn from_symbols(
+ class: &str,
+ name: &str,
+ params: &[&str],
+ return_type: Option<&str>,
+ ) -> Self {
+ let class = class.to_string();
+ let name = name.to_string();
+ let desc = MethodDescriptor::from_symbols(params, return_type);
+ Self { class, name, desc }
+ }
+ }
+
+ impl From<&MethodData> for MethodRef {
+ fn from(value: &MethodData) -> Self {
+ value.clone().into()
+ }
+ }
+
+ impl From for MethodRef {
+ fn from(value: MethodData) -> Self {
+ Self {
+ class: value.class,
+ name: value.name,
+ desc: value.desc,
+ }
+ }
+ }
+
+ #[derive(Debug, Clone)]
+ pub struct InterfaceMethodRef {
+ pub class: String,
+ pub name: String,
+ pub desc: MethodDescriptor,
+ }
+
+ #[derive(Debug, Clone)]
+ pub struct MethodHandle {
+ pub kind: MethodHandleKind,
+ }
+
+ impl From for MethodHandle {
+ fn from(kind: MethodHandleKind) -> Self {
+ Self { kind }
+ }
+ }
+
+ #[derive(Debug, Clone)]
+ pub struct MethodType {
+ pub desc: MethodDescriptor,
+ }
+ impl From for MethodType {
+ fn from(desc: MethodDescriptor) -> Self {
+ Self { desc }
+ }
+ }
+
+ #[derive(Debug, Clone)]
+ pub struct Dynamic {
+ pub method: BootstrapMethod,
+ pub name: String,
+ pub desc: FieldDescriptor,
+ }
+ #[derive(Debug, Clone)]
+ pub struct InvokeDynamic {
+ pub method: BootstrapMethod,
+ pub name: String,
+ pub desc: MethodDescriptor,
+ }
+ #[derive(Debug, Clone)]
+ pub struct BootstrapMethod {
+ pub handle: MethodHandle,
+ pub args: Vec,
+ }
+
+ #[derive(Debug, Clone)]
+ pub enum MethodHandleKind {
+ GetField(FieldRef),
+ GetStatic(FieldRef),
+ PutField(FieldRef),
+ PutStatic(FieldRef),
+ InvokeVirtual(MethodRef),
+ InvokeStatic(InterfaceOrMethod),
+ InvokeSpecial(InterfaceOrMethod),
+ NewInvokeSpecial(MethodRef),
+ InvokeInterface(InterfaceMethodRef),
+ }
+
+ impl MethodHandleKind {
+ pub fn lookup_descriptor(&self) -> String {
+ match self {
+ MethodHandleKind::GetField(fr) => fr.desc.to_string(),
+ MethodHandleKind::GetStatic(fr) => fr.desc.to_string(),
+ MethodHandleKind::PutField(fr) => fr.desc.to_string(),
+ MethodHandleKind::PutStatic(fr) => fr.desc.to_string(),
+ MethodHandleKind::InvokeVirtual(mr) => mr.desc.to_string(),
+ MethodHandleKind::InvokeStatic(iom) => iom.desc().to_string(),
+ MethodHandleKind::InvokeSpecial(iom) => iom.desc().to_string(),
+ MethodHandleKind::NewInvokeSpecial(mr) => mr.desc.to_string(),
+ MethodHandleKind::InvokeInterface(imf) => imf.desc.to_string(),
+ }
+ }
+
+ pub fn class(&self) -> String {
+ match self {
+ MethodHandleKind::GetField(fr) => fr.class.to_string(),
+ MethodHandleKind::GetStatic(fr) => fr.class.to_string(),
+ MethodHandleKind::PutField(fr) => fr.class.to_string(),
+ MethodHandleKind::PutStatic(fr) => fr.class.to_string(),
+ MethodHandleKind::InvokeVirtual(mr) => mr.class.to_string(),
+ MethodHandleKind::InvokeStatic(iom) => iom.class().to_string(),
+ MethodHandleKind::InvokeSpecial(iom) => iom.class().to_string(),
+ MethodHandleKind::NewInvokeSpecial(mr) => mr.class.to_string(),
+ MethodHandleKind::InvokeInterface(imf) => imf.class.to_string(),
+ }
+ }
+
+ pub fn name(&self) -> String {
+ match self {
+ MethodHandleKind::GetField(fr) => fr.name.to_string(),
+ MethodHandleKind::GetStatic(fr) => fr.name.to_string(),
+ MethodHandleKind::PutField(fr) => fr.name.to_string(),
+ MethodHandleKind::PutStatic(fr) => fr.name.to_string(),
+ MethodHandleKind::InvokeVirtual(mr) => mr.name.to_string(),
+ MethodHandleKind::InvokeStatic(iom) => iom.name().to_string(),
+ MethodHandleKind::InvokeSpecial(iom) => iom.name().to_string(),
+ MethodHandleKind::NewInvokeSpecial(mr) => mr.name.to_string(),
+ MethodHandleKind::InvokeInterface(imf) => imf.name.to_string(),
+ }
+ }
+
+ pub fn is_interface(&self) -> bool {
+ match self {
+ MethodHandleKind::InvokeStatic(InterfaceOrMethod::Interface(_)) => true,
+ MethodHandleKind::InvokeSpecial(InterfaceOrMethod::Interface(_)) => true,
+ MethodHandleKind::InvokeInterface(_) => true,
+ _ => false,
+ }
+ }
+
+ pub fn ordinal(&self) -> u8 {
+ match self {
+ MethodHandleKind::GetField(_) => 1,
+ MethodHandleKind::GetStatic(_) => 2,
+ MethodHandleKind::PutField(_) => 3,
+ MethodHandleKind::PutStatic(_) => 4,
+ MethodHandleKind::InvokeVirtual(_) => 5,
+ MethodHandleKind::InvokeStatic(_) => 6,
+ MethodHandleKind::InvokeSpecial(_) => 7,
+ MethodHandleKind::NewInvokeSpecial(_) => 8,
+ MethodHandleKind::InvokeInterface(_) => 9,
+ }
+ }
+ }
+ #[derive(Debug, Clone)]
+ pub enum InterfaceOrMethod {
+ Method(MethodRef),
+ Interface(InterfaceMethodRef),
+ }
+ impl InterfaceOrMethod {
+ pub fn name(&self) -> &String {
+ match self {
+ InterfaceOrMethod::Method(method_ref) => &method_ref.name,
+ InterfaceOrMethod::Interface(method_ref) => &method_ref.name,
+ }
+ }
+ pub fn class(&self) -> &String {
+ match self {
+ InterfaceOrMethod::Method(method_ref) => &method_ref.class,
+ InterfaceOrMethod::Interface(method_ref) => &method_ref.class,
+ }
+ }
+ pub fn desc(&self) -> &MethodDescriptor {
+ match self {
+ InterfaceOrMethod::Method(method_ref) => &method_ref.desc,
+ InterfaceOrMethod::Interface(method_ref) => &method_ref.desc,
+ }
+ }
+ }
+
+ impl From for InterfaceOrMethod {
+ fn from(value: MethodRef) -> Self {
+ Self::Method(value)
+ }
+ }
+ impl From for InterfaceOrMethod {
+ fn from(value: InterfaceMethodRef) -> Self {
+ Self::Interface(value)
+ }
+ }
+
+ #[derive(Debug, Clone)]
+ pub enum Loadable {
+ Integer(i32),
+ Float(f32),
+ Long(i64),
+ Double(f64),
+ Class(String),
+ String(String),
+ MethodHandle(MethodHandle),
+ MethodType(MethodType),
+ Dynamic(Dynamic),
+ }
+
+ impl From for Loadable {
+ fn from(handle: MethodHandle) -> Self {
+ Self::MethodHandle(handle)
+ }
+ }
+}
diff --git a/crates/core/src/class_file/constant_pool.rs b/crates/core/src/class_file/constant_pool.rs
index d8afa01..de403f8 100644
--- a/crates/core/src/class_file/constant_pool.rs
+++ b/crates/core/src/class_file/constant_pool.rs
@@ -1,19 +1,25 @@
+use crate::class::RuntimeClass;
use crate::class_file::attributes::{
Attribute, AttributeInfo, BootstrapMethodsAttribute, CodeAttribute, LineNumberTableAttribute,
LocalVariableTableAttribute,
};
+use crate::class_file::resolved::{
+ BootstrapMethod, Dynamic, FieldRef, InterfaceMethodRef, InterfaceOrMethod, Loadable,
+ MethodHandleKind, MethodRef, MethodType,
+};
use crate::class_file::{
ConstantClassInfo, ConstantDynamicInfo, ConstantFieldrefInfo, ConstantInterfaceMethodrefInfo,
ConstantInvokeDynamicInfo, ConstantMethodHandleInfo, ConstantMethodTypeInfo,
ConstantMethodrefInfo, ConstantModuleInfo, ConstantNameAndTypeInfo, ConstantPackageInfo,
- ConstantPoolEntry, ConstantStringInfo, ConstantUtf8Info, DescParseError, FieldInfo, FieldRef,
- MethodRef,
+ ConstantPoolEntry, ConstantStringInfo, ConstantUtf8Info, DescParseError, FieldDescriptor,
+ FieldInfo,
};
use crate::error::VmError;
use crate::{FieldType, MethodDescriptor, pool_get_impl};
use cesu8::{Cesu8DecodingError, from_java_cesu8};
use deku::DekuContainerRead;
use std::fmt::{Display, Formatter};
+use std::sync::Arc;
pub type ConstantPoolSlice = [ConstantPoolEntry];
pub type ConstantPoolOwned = Vec;
@@ -99,14 +105,17 @@ pub trait ConstantPoolExt: ConstantPoolGet {
Ok(MethodRef { class, name, desc })
}
- fn resolve_interface_method_ref(&self, index: u16) -> Result {
+ fn resolve_interface_method_ref(
+ &self,
+ index: u16,
+ ) -> Result {
let mr = self.get_interface_method_ref(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)?;
let desc = MethodDescriptor::parse(&desc)?;
- Ok(MethodRef { class, name, desc })
+ Ok(InterfaceMethodRef { class, name, desc })
}
/*// (name, desc)
@@ -133,6 +142,106 @@ pub trait ConstantPoolExt: ConstantPoolGet {
})
}
+ fn resolve_either_ref(&self, idx: u16) -> Result {
+ match self.get_constant(idx)? {
+ ConstantPoolEntry::MethodRef(_) => {
+ Ok(InterfaceOrMethod::Method(self.resolve_method_ref(idx)?))
+ }
+ ConstantPoolEntry::InterfaceMethodRef(_) => Ok(InterfaceOrMethod::Interface(
+ self.resolve_interface_method_ref(idx)?,
+ )),
+ _ => unreachable!(),
+ }
+ }
+
+ fn resolve_loadable(
+ &self,
+ idx: u16,
+ class: Arc,
+ ) -> Result {
+ match self.get_constant(idx)? {
+ ConstantPoolEntry::Integer(x) => Ok(Loadable::Integer(*x)),
+ ConstantPoolEntry::Float(f) => Ok(Loadable::Float(*f)),
+ ConstantPoolEntry::Long(j) => Ok(Loadable::Long(*j)),
+ ConstantPoolEntry::Double(d) => Ok(Loadable::Double(*d)),
+ ConstantPoolEntry::Class(s) => Ok(Loadable::Class(self.get_string(s.name_index)?)),
+ ConstantPoolEntry::String(s) => Ok(Loadable::String(self.get_string(s.string_index)?)),
+ ConstantPoolEntry::MethodHandle(_) => Ok(Loadable::MethodHandle(
+ self.resolve_handle_kind(idx)?.into(),
+ )),
+ ConstantPoolEntry::MethodType(t) => {
+ let desc = self.get_string(t.descriptor_index)?;
+ let desc = MethodDescriptor::parse(&desc)?;
+ let typ: MethodType = desc.into();
+ Ok(Loadable::MethodType(typ))
+ }
+ ConstantPoolEntry::Dynamic(d) => {
+ let name_and_type = self.get_name_and_type_info(d.name_and_type_index)?;
+ let name = self.get_string(name_and_type.name_index)?;
+ let desc =
+ FieldDescriptor::parse(&self.get_string(name_and_type.descriptor_index)?)?;
+ let boot_index = d.bootstrap_method_attr_index;
+ let boot_method_info = class
+ .bootstrap_attribute
+ .as_ref()
+ .unwrap()
+ .bootstrap_methods
+ .get(boot_index as usize)
+ .unwrap();
+ let args: Vec<_> = boot_method_info
+ .bootstrap_arguments
+ .iter()
+ .map(|idx| self.resolve_loadable(*idx, class.clone()))
+ .collect::>()?;
+ let boot_method = BootstrapMethod {
+ handle: self
+ .resolve_handle_kind(boot_method_info.bootstrap_method_ref)?
+ .into(),
+ args,
+ };
+
+ let dynamic = Dynamic {
+ method: boot_method,
+ name,
+ desc,
+ };
+ Ok(Loadable::Dynamic(dynamic))
+ }
+
+ _ => Err(ConstantPoolError::Generic("Not loadable".into())),
+ }
+ }
+
+ fn resolve_handle_kind(&self, idx: u16) -> Result {
+ let info = self.get_method_handle_info(idx)?;
+ let (kind, idx) = (info.reference_kind, info.reference_index);
+ match kind {
+ 1 => Ok(MethodHandleKind::GetField(self.resolve_field(idx)?)),
+ 2 => Ok(MethodHandleKind::GetStatic(self.resolve_field(idx)?)),
+ 3 => Ok(MethodHandleKind::PutField(self.resolve_field(idx)?)),
+ 4 => Ok(MethodHandleKind::PutStatic(self.resolve_field(idx)?)),
+ 5 => Ok(MethodHandleKind::InvokeVirtual(
+ self.resolve_method_ref(idx)?,
+ )),
+ 6 => Ok(MethodHandleKind::InvokeStatic(
+ self.resolve_method_ref(idx)?.into(),
+ )),
+ 7 => Ok(MethodHandleKind::InvokeSpecial(
+ self.resolve_method_ref(idx)?.into(),
+ )),
+ 8 => Ok(MethodHandleKind::NewInvokeSpecial(
+ self.resolve_method_ref(idx)?,
+ )),
+ 9 => Ok(MethodHandleKind::InvokeInterface(
+ self.resolve_interface_method_ref(idx)?,
+ )),
+ _ => Err(ConstantPoolError::Generic(format!(
+ "Invalid method handle kind: {}",
+ kind
+ ))),
+ }
+ }
+
fn parse_attribute(&self, a: AttributeInfo) -> Result {
let name = self.get_string(a.attribute_name_index)?;
// trace!("Parsing attribute with name: {}", name);
diff --git a/crates/core/src/class_loader.rs b/crates/core/src/class_loader.rs
index 5fb751d..4b7d552 100644
--- a/crates/core/src/class_loader.rs
+++ b/crates/core/src/class_loader.rs
@@ -6,7 +6,7 @@ use crate::class_file::{
ClassFile, ClassFlags, Constant, FieldData, FieldFlags, MethodData, MethodFlags,
};
use crate::error::VmError;
-use crate::{FieldType, MethodDescriptor};
+use crate::{FieldType, MethodDescriptor, VmSymbols};
use dashmap::DashMap;
use deku::DekuContainerRead;
use log::warn;
@@ -250,8 +250,8 @@ impl ClassLoader {
name
};
let super_class = {
- if this_class.eq("java/lang/Object") {
- debug_assert_eq!(this_class, "java/lang/Object");
+ if this_class.eq(VmSymbols::OBJECT) {
+ debug_assert_eq!(this_class, VmSymbols::OBJECT);
debug_assert_eq!(class_file.super_class, 0u16);
None
} else {
@@ -424,11 +424,10 @@ impl ClassLoader {
// }
pub fn create_array_class(&mut self, component: Arc) -> Arc {
- // let name = format!("[{}", component.descriptor()); // e.g., "[Ljava/lang/String;"
- let object_class: Arc = self.get_or_load("java/lang/Object", None).unwrap();
- let cloneable: Arc = self.get_or_load("java/lang/Cloneable", None).unwrap();
+ let object_class: Arc = self.get_or_load(VmSymbols::OBJECT, None).unwrap();
+ let cloneable: Arc = self.get_or_load(VmSymbols::CLONEABLE, None).unwrap();
let serializable: Arc =
- self.get_or_load("java/io/Serializable", None).unwrap();
+ self.get_or_load(VmSymbols::SERIALIZABLE, None).unwrap();
let name = match component.this_class.as_str() {
"byte" => "[B".to_string(),
"char" => "[C".to_string(),
diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs
index a2c3e71..a0de563 100644
--- a/crates/core/src/error.rs
+++ b/crates/core/src/error.rs
@@ -7,7 +7,7 @@ pub enum VmError {
ConstantPoolError(String),
StackError(String),
InvariantError(String),
- Debug(&'static str),
+ Debug(String),
DekuError(DekuError),
LoaderError(String),
ExecutionError,
@@ -43,6 +43,38 @@ impl Display for VmError {
}
}
}
+const CARGO_LINE: &str = "\n --> {}:{}:{}\n{}";
+const BARE_LINE: &str = "\n{}:{}:{}\n{}";
+const PANIC_LINE: &str = "\nthread '{}' panicked at {}:{}:{}\n{}";
+#[macro_export]
+macro_rules! dbg_panic {
+ ($msg:expr) => {
+ Result::Err(VmError::Debug(format!(
+ "\nthread '{}' panicked at {}:{}:{}\n{}",
+ thread::current().name().unwrap_or("unnamed"),
+ file!(),
+ line!(),
+ column!(),
+ $msg.to_string()
+ )))
+ };
+}
+
+#[macro_export]
+macro_rules! todoo {
+ ($msg:expr) => {
+ Result::Err(VmError::NotImplemented(format!(
+ "\n --> {}:{}:{}\n{}",
+ file!(),
+ line!(),
+ column!(),
+ $msg.to_string()
+ )))
+ };
+}
+
+pub use dbg_panic;
+pub use todoo;
impl From for VmError {
fn from(value: ConstantPoolError) -> Self {
diff --git a/crates/core/src/frame/frame.rs b/crates/core/src/frame/frame.rs
index aec5e72..0b8a692 100644
--- a/crates/core/src/frame/frame.rs
+++ b/crates/core/src/frame/frame.rs
@@ -1,7 +1,7 @@
use crate::class::RuntimeClass;
use crate::class_file::attributes::{CodeAttribute, LineNumberTableEntry};
use crate::class_file::constant_pool::{ConstantPoolError, ConstantPoolExt, ConstantPoolGet};
-use crate::class_file::{Bytecode, ConstantPoolEntry, MethodRef};
+use crate::class_file::{Bytecode, ConstantPoolEntry, FieldDescriptor};
use crate::error::{StackTraceElement, VmError};
use crate::instructions::{Ops, WideData};
use crate::objects::ReferenceKind;
@@ -10,17 +10,21 @@ use crate::prim::*;
use crate::value::{Primitive, Value};
use crate::vm::Vm;
use crate::{
- BaseType, FieldType, MethodDescriptor, VmThread, array_store, array_store_cast, binary_op,
- convert_float_to_int, convert_int_narrow, convert_simple, float_cmp, if_int_cmp, if_int_zero,
- int_div_rem, load, shift_op, store, unary_op,
+ BaseType, FieldType, VmSymbols, VmThread, array_store, array_store_cast, binary_op,
+ convert_float_to_int, convert_int_narrow, convert_simple, error, float_cmp, if_int_cmp,
+ if_int_zero, int_div_rem, jsr292, load, shift_op, store, unary_op,
};
+use std::thread;
use deku::DekuContainerRead;
use log::{trace, warn};
+use crate::class_file::resolved::InterfaceOrMethod::Method;
+use crate::class_file::resolved::{FieldRef, Loadable, MethodRef};
use crate::frame::local_vars::LocalVariables;
use crate::frame::operand_stack::OperandStack;
use std::fmt::{Display, Formatter};
+use std::process::id;
use std::sync::Arc;
/// Represents a JVM stack frame for method execution.
@@ -47,7 +51,7 @@ pub struct Frame {
bytecode: Bytecode,
/// The thread executing this frame
- thread: Arc,
+ pub(crate) thread: Arc,
// The mod being invoked
pub method_ref: MethodRef,
@@ -114,7 +118,7 @@ impl Frame {
line_number_table: Option>,
) -> Self {
// Get current thread from thread-local storage
- let thread = VmThread::current(&vm);
+ let thread = vm.current_thread();
let max_stack = code_attr.max_stack as usize;
let max_local = code_attr.max_locals as usize;
@@ -1124,7 +1128,7 @@ impl Frame {
let result = self
.thread
- .invoke_virtual(method_ref, class.clone(), args)?;
+ .invoke_virtual(method_ref.into(), class.clone(), args)?;
if let Some(val) = result {
self.push(val)
}
@@ -1134,17 +1138,14 @@ impl Frame {
Ops::invokespecial(index) => {
// todo verify change to interface method ref
- let method_ref = self
- .pool
- .resolve_method_ref(index)
- .or_else(|e| self.pool.resolve_interface_method_ref(index).map_err(|_| e))?;
+ let either = self.pool.resolve_either_ref(index)?;
// the 1 represents the receiver
// arg width??????
- let args_count = method_ref.desc.parameters.len() + 1;
+ let args_count = either.desc().parameters.len() + 1;
let args = self.stack.pop_n(args_count)?;
- let result = self.thread.invoke(method_ref, args)?;
+ let result = self.thread.invoke(either, args)?;
if let Some(val) = result {
self.push(val)
}
@@ -1153,17 +1154,14 @@ impl Frame {
}
Ops::invokestatic(index) => {
- let method_ref = self
- .pool
- .resolve_method_ref(index)
- .or_else(|e| self.pool.resolve_interface_method_ref(index).map_err(|_| e))?;
- let class = self.thread.get_class(&method_ref.class)?;
+ let either = self.pool.resolve_either_ref(index)?;
+ let class = self.thread.get_class(&either.class())?;
self.thread.ensure_initialised(&class)?;
- let args_count = method_ref.desc.parameters.len();
+ let args_count = either.desc().parameters.len();
let args = self.stack.pop_n(args_count)?;
- let result = self.thread.invoke(method_ref, args)?;
+ let result = self.thread.invoke(either, args)?;
if let Some(val) = result {
self.push(val)
}
@@ -1171,10 +1169,10 @@ impl Frame {
}
Ops::invokeinterface(index, _count, _zero) => {
- let method_ref = self.pool.resolve_interface_method_ref(index)?;
+ let interface_method_ref = self.pool.resolve_interface_method_ref(index)?;
// the 1 represents the receiver
- let args_count = method_ref.desc.parameters.len() + 1;
+ let args_count = interface_method_ref.desc.parameters.len() + 1;
let args = self.stack.pop_n(args_count)?;
let refe = args
.first()
@@ -1183,9 +1181,9 @@ impl Frame {
.expect("Must be ref");
let class = refe.class();
- let result = self
- .thread
- .invoke_virtual(method_ref, class.clone(), args)?;
+ let result =
+ self.thread
+ .invoke_virtual(interface_method_ref.into(), class.clone(), args)?;
if let Some(val) = result {
self.push(val)
}
@@ -1195,9 +1193,9 @@ impl Frame {
Ops::invokedynamic(index, _b) => {
debug_assert_eq!(_b, 0u16);
+ /*
- // Check if already resolved (you'll want to cache this)
- // For now, let's just resolve it every time
+ // TODO: Cache resolved CallSites
let dyninfo = self.pool.get_invoke_dynamic_info(index)?;
let bootstrap_attr = self.class.bootstrap_attribute.as_ref().unwrap();
@@ -1212,84 +1210,266 @@ impl Frame {
let call_site_method_type = MethodDescriptor::parse(&call_site_desc)
.map_err(ConstantPoolError::DescriptorParseError)?;
- // The bootstrap method handle reference
- let bsm_handle = self.pool.get_method_handle_info(bsm.bootstrap_method_ref)?;
- let kind = bsm_handle.reference_kind;
- let heck = self.pool.resolve_method_ref(bsm_handle.reference_index)?;
- println!("Bootstrap method handle: kind={:?}, ref={:?}", kind, heck);
- // Resolve static arguments from constant pool
- let static_args: Vec = Vec::new();
- for arg_index in &bsm.bootstrap_arguments {
- let info = self.pool.get_string_info(*arg_index)?;
- let string = self.pool.get_string(info.string_index)?;
- println!("{}", string);
- // static_args.push(arg);
- }
+ // 1. Lookup
+ let lookup = {
+ let refe = MethodRef {
+ class: "java/lang/invoke/MethodHandles".to_string(),
+ name: "lookup".to_string(),
+ desc: MethodDescriptor::parse("()Ljava/lang/invoke/MethodHandles$Lookup;")
+ .unwrap(),
+ };
+ self.thread.invoke(refe, vec![])?.unwrap()
+ };
- let class_objects = call_site_method_type
- .parameters
- .iter()
- .map(|param| {
- let name = param.as_class_name();
- let klass = self.thread.get_class(&name)?;
- let obj = self.thread.gc.read().get(*klass.mirror.get().unwrap());
- Ok(Some(obj))
- })
- .collect::>, VmError>>()?;
- let class_array_class = self.thread.get_class("[Ljava/lang/Class;")?;
+ // 2. Call site name as String
+ let name_string = self.thread.intern_string(&call_site_name);
- let ptypes = self
+ // 3. Call site MethodType
+ let call_site_mt: Value = {
+ let class_objects: Vec