Sync for jsr 292
This commit is contained in:
parent
24939df1b7
commit
911bb1be82
7
.idea/dictionaries/project.xml
generated
Normal file
7
.idea/dictionaries/project.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="project">
|
||||
<words>
|
||||
<w>stacktraceelement</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
6
.idea/inspectionProfiles/Project_Default.xml
generated
6
.idea/inspectionProfiles/Project_Default.xml
generated
@ -2,5 +2,11 @@
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="IncorrectFormatting" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SSBasedInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<searchConfiguration name="jay el" text="java/lang" recursive="true" caseInsensitive="false">
|
||||
<constraint name="__context__" within="" contains="" />
|
||||
</searchConfiguration>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="b5f914b3-9c2e-37bf-aba7-3845b009e991" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
@ -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
|
||||
|
||||
@ -19,6 +19,7 @@ colored = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
cesu8 = { workspace = true }
|
||||
windows = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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<MethodData> 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<MethodData> 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<MethodHandleKind> for MethodHandle {
|
||||
fn from(kind: MethodHandleKind) -> Self {
|
||||
Self { kind }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MethodType {
|
||||
pub desc: MethodDescriptor,
|
||||
}
|
||||
impl From<MethodDescriptor> 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<Loadable>,
|
||||
}
|
||||
|
||||
#[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<MethodRef> for InterfaceOrMethod {
|
||||
fn from(value: MethodRef) -> Self {
|
||||
Self::Method(value)
|
||||
}
|
||||
}
|
||||
impl From<InterfaceMethodRef> 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<MethodHandle> for Loadable {
|
||||
fn from(handle: MethodHandle) -> Self {
|
||||
Self::MethodHandle(handle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<ConstantPoolEntry>;
|
||||
@ -99,14 +105,17 @@ pub trait ConstantPoolExt: ConstantPoolGet {
|
||||
Ok(MethodRef { class, name, desc })
|
||||
}
|
||||
|
||||
fn resolve_interface_method_ref(&self, index: u16) -> Result<MethodRef, ConstantPoolError> {
|
||||
fn resolve_interface_method_ref(
|
||||
&self,
|
||||
index: u16,
|
||||
) -> Result<InterfaceMethodRef, ConstantPoolError> {
|
||||
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<InterfaceOrMethod, ConstantPoolError> {
|
||||
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<RuntimeClass>,
|
||||
) -> Result<Loadable, ConstantPoolError> {
|
||||
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::<Result<_, _>>()?;
|
||||
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<MethodHandleKind, ConstantPoolError> {
|
||||
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<Attribute, VmError> {
|
||||
let name = self.get_string(a.attribute_name_index)?;
|
||||
// trace!("Parsing attribute with name: {}", name);
|
||||
|
||||
@ -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<RuntimeClass>) -> Arc<RuntimeClass> {
|
||||
// let name = format!("[{}", component.descriptor()); // e.g., "[Ljava/lang/String;"
|
||||
let object_class: Arc<RuntimeClass> = self.get_or_load("java/lang/Object", None).unwrap();
|
||||
let cloneable: Arc<RuntimeClass> = self.get_or_load("java/lang/Cloneable", None).unwrap();
|
||||
let object_class: Arc<RuntimeClass> = self.get_or_load(VmSymbols::OBJECT, None).unwrap();
|
||||
let cloneable: Arc<RuntimeClass> = self.get_or_load(VmSymbols::CLONEABLE, None).unwrap();
|
||||
let serializable: Arc<RuntimeClass> =
|
||||
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(),
|
||||
|
||||
@ -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<ConstantPoolError> for VmError {
|
||||
fn from(value: ConstantPoolError) -> Self {
|
||||
|
||||
@ -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<VmThread>,
|
||||
pub(crate) thread: Arc<VmThread>,
|
||||
// The mod being invoked
|
||||
pub method_ref: MethodRef,
|
||||
|
||||
@ -114,7 +118,7 @@ impl Frame {
|
||||
line_number_table: Option<Vec<LineNumberTableEntry>>,
|
||||
) -> 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,21 +1210,23 @@ 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<Value> = 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
|
||||
// 2. Call site name as String
|
||||
let name_string = self.thread.intern_string(&call_site_name);
|
||||
|
||||
// 3. Call site MethodType
|
||||
let call_site_mt: Value = {
|
||||
let class_objects: Vec<Option<ReferenceKind>> = call_site_method_type
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|param| {
|
||||
@ -1235,61 +1235,241 @@ impl Frame {
|
||||
let obj = self.thread.gc.read().get(*klass.mirror.get().unwrap());
|
||||
Ok(Some(obj))
|
||||
})
|
||||
.collect::<Result<Vec<Option<ReferenceKind>>, VmError>>()?;
|
||||
let class_array_class = self.thread.get_class("[Ljava/lang/Class;")?;
|
||||
.collect::<Result<_, VmError>>()?;
|
||||
|
||||
let class_array_class = self.thread.get_class("[Ljava/lang/Class;")?;
|
||||
let ptypes = self
|
||||
.thread
|
||||
.gc
|
||||
.write()
|
||||
.new_object_array_from(class_array_class, class_objects.into_boxed_slice());
|
||||
let pval: Value = ptypes.clone().into();
|
||||
|
||||
println!("==================");
|
||||
println!("{}", pval);
|
||||
println!("==================");
|
||||
let return_type = call_site_method_type.return_type.unwrap();
|
||||
let ret = return_type.as_class_name();
|
||||
let ret_klass = self.thread.get_class(&ret)?;
|
||||
let rtype = self.thread.gc.read().get(*ret_klass.mirror.get().unwrap());
|
||||
let mt_cn_ref = MethodRef {
|
||||
let rtype: Value = match &call_site_method_type.return_type {
|
||||
Some(rt) => {
|
||||
let klass = self.thread.get_class(&rt.as_class_name())?;
|
||||
self.thread
|
||||
.gc
|
||||
.read()
|
||||
.get(*klass.mirror.get().unwrap())
|
||||
.into()
|
||||
}
|
||||
None => {
|
||||
let void_class = self.thread.get_class("void")?;
|
||||
self.thread
|
||||
.gc
|
||||
.read()
|
||||
.get(*void_class.mirror.get().unwrap())
|
||||
.into()
|
||||
}
|
||||
};
|
||||
|
||||
let mt_ref = MethodRef {
|
||||
class: "java/lang/invoke/MethodType".to_string(),
|
||||
name: "methodType".to_string(),
|
||||
desc: MethodDescriptor::method_type(),
|
||||
desc: MethodDescriptor::parse(
|
||||
"(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;",
|
||||
)
|
||||
.unwrap(),
|
||||
};
|
||||
self.thread
|
||||
.invoke(mt_ref, vec![rtype, ptypes.into()])?
|
||||
.unwrap()
|
||||
.into()
|
||||
};
|
||||
|
||||
let mt = self
|
||||
// 4. Bootstrap MethodHandle
|
||||
let bsm_method_handle: Value = {
|
||||
let bsm_handle_info =
|
||||
self.pool.get_method_handle_info(bsm.bootstrap_method_ref)?;
|
||||
let kind = bsm_handle_info.reference_kind;
|
||||
let method_ref = self
|
||||
.pool
|
||||
.resolve_method_ref(bsm_handle_info.reference_index)?;
|
||||
|
||||
let bsm_class = self.thread.get_class(&method_ref.class)?;
|
||||
let bsm_class_mirror: Value = self
|
||||
.thread
|
||||
.invoke(mt_cn_ref, vec![rtype.into(), ptypes.into()])?
|
||||
.unwrap();
|
||||
.gc
|
||||
.read()
|
||||
.get(*bsm_class.mirror.get().unwrap())
|
||||
.into();
|
||||
|
||||
// Pop runtime arguments from stack (based on call site descriptor)
|
||||
let runtime_arg_count = call_site_method_type.parameters.len();
|
||||
let runtime_args = self.stack.pop_n(runtime_arg_count)?;
|
||||
let bsm_name: Value = self.thread.intern_string(&method_ref.name).into();
|
||||
|
||||
// Now we need to:
|
||||
// 1. Create a MethodHandles.Lookup for current class ---
|
||||
// 2. Create a MethodType from call_site_desc
|
||||
// 3. Invoke the bootstrap method with (Lookup, String name, MethodType, ...static_args)
|
||||
// 4. Get back a CallSite
|
||||
// 5. Extract the MethodHandle from CallSite.getTarget()
|
||||
// 6. Invoke that MethodHandle with runtime_args
|
||||
// MethodType for the bootstrap method itself
|
||||
let bsm_desc = method_ref.desc;
|
||||
let bsm_mt: Value = {
|
||||
let params: Vec<Option<ReferenceKind>> = bsm_desc
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|p| {
|
||||
let klass = self.thread.get_class(&p.as_class_name())?;
|
||||
Ok(Some(
|
||||
self.thread.gc.read().get(*klass.mirror.get().unwrap()),
|
||||
))
|
||||
})
|
||||
.collect::<Result<_, VmError>>()?;
|
||||
|
||||
//wait i think i can just call jvm methods here
|
||||
let mhc = self.thread.get_class("java/lang/invoke/MethodHandles")?;
|
||||
let refe = MethodRef {
|
||||
class: "java/lang/invoke/MethodHandles".to_string(),
|
||||
name: "lookup".to_string(),
|
||||
desc: MethodDescriptor::lookup(),
|
||||
let class_array_class = self.thread.get_class("[Ljava/lang/Class;")?;
|
||||
let ptypes = self
|
||||
.thread
|
||||
.gc
|
||||
.write()
|
||||
.new_object_array_from(class_array_class, params.into_boxed_slice());
|
||||
|
||||
let rtype: Value = match &bsm_desc.return_type {
|
||||
Some(rt) => {
|
||||
let klass = self.thread.get_class(&rt.as_class_name())?;
|
||||
self.thread
|
||||
.gc
|
||||
.read()
|
||||
.get(*klass.mirror.get().unwrap())
|
||||
.into()
|
||||
}
|
||||
None => {
|
||||
let void_class = self.thread.get_class("void")?;
|
||||
self.thread
|
||||
.gc
|
||||
.read()
|
||||
.get(*void_class.mirror.get().unwrap())
|
||||
.into()
|
||||
}
|
||||
};
|
||||
|
||||
let lookup = self.thread.invoke(refe, Vec::new())?.unwrap();
|
||||
// Full implementation requires MethodHandle invocation support
|
||||
println!("{}", lookup);
|
||||
todo!(
|
||||
// "Full invokedynamic - bootstrap: {}::{}",
|
||||
// bsm_handle.class_name,
|
||||
// bsm_handle.method_name
|
||||
let mt_ref = MethodRef {
|
||||
class: "java/lang/invoke/MethodType".to_string(),
|
||||
name: "methodType".to_string(),
|
||||
desc: MethodDescriptor::parse(
|
||||
"(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;",
|
||||
)
|
||||
.unwrap(),
|
||||
};
|
||||
self.thread
|
||||
.invoke(mt_ref, vec![rtype, ptypes.into()])?
|
||||
.unwrap()
|
||||
.into()
|
||||
};
|
||||
|
||||
// Call appropriate Lookup.findXxx based on kind
|
||||
match kind {
|
||||
6 => {
|
||||
// REF_invokeStatic
|
||||
let find_static = MethodRef {
|
||||
class: "java/lang/invoke/MethodHandles$Lookup".to_string(),
|
||||
name: "findStatic".to_string(),
|
||||
desc: MethodDescriptor::parse("(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;").unwrap(),
|
||||
};
|
||||
self.thread
|
||||
.invoke_virtual(
|
||||
find_static,
|
||||
lookup.clone(),
|
||||
vec![bsm_class_mirror, bsm_name, bsm_mt],
|
||||
)?
|
||||
.unwrap()
|
||||
.into()
|
||||
}
|
||||
5 | 9 => {
|
||||
// REF_invokeVirtual | REF_invokeInterface
|
||||
let find_virtual = MethodRef {
|
||||
class: "java/lang/invoke/MethodHandles$Lookup".to_string(),
|
||||
name: "findVirtual".to_string(),
|
||||
desc: MethodDescriptor::parse("(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;").unwrap(),
|
||||
};
|
||||
self.thread
|
||||
.invoke_virtual(
|
||||
find_virtual,
|
||||
lookup.clone(),
|
||||
vec![bsm_class_mirror, bsm_name, bsm_mt],
|
||||
)?
|
||||
.unwrap()
|
||||
.into()
|
||||
}
|
||||
// Add other kinds as needed
|
||||
_ => todo!("MethodHandle reference kind {}", kind),
|
||||
}
|
||||
};
|
||||
|
||||
// 5. Static arguments
|
||||
let static_args = self.resolve_bootstrap_args(&bsm.bootstrap_arguments)?;
|
||||
|
||||
// 6. Build args array for invokeWithArguments: [lookup, name, methodType, ...staticArgs]
|
||||
let mut all_bsm_args: Vec<Value> =
|
||||
vec![lookup.into(), name_string.into(), call_site_mt];
|
||||
all_bsm_args.extend(static_args);
|
||||
|
||||
// Box primitives and create Object[]
|
||||
let boxed_args: Vec<Option<ReferenceKind>> = all_bsm_args
|
||||
.into_iter()
|
||||
.map(|v| self.box_value(v))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let obj_array_class = self.thread.get_class("[Ljava/lang/Object;")?;
|
||||
let args_array = self
|
||||
.thread
|
||||
.gc
|
||||
.write()
|
||||
.new_object_array_from(obj_array_class, boxed_args.into_boxed_slice());
|
||||
|
||||
// 7. Invoke bootstrap: bsm.invokeWithArguments(Object[])
|
||||
let invoke_ref = MethodRef {
|
||||
class: "java/lang/invoke/MethodHandle".to_string(),
|
||||
name: "invokeWithArguments".to_string(),
|
||||
desc: MethodDescriptor::parse("([Ljava/lang/Object;)Ljava/lang/Object;")
|
||||
.unwrap(),
|
||||
};
|
||||
|
||||
let call_site = self
|
||||
.thread
|
||||
.invoke_virtual(invoke_ref, bsm_handle, vec![args_array.into()])?
|
||||
.ok_or_else(|| VmError::InvariantError("Bootstrap returned null".into()))?;
|
||||
|
||||
// 8. Get target handle: callSite.getTarget()
|
||||
let get_target = MethodRef {
|
||||
class: "java/lang/invoke/CallSite".to_string(),
|
||||
name: "getTarget".to_string(),
|
||||
desc: MethodDescriptor::parse("()Ljava/lang/invoke/MethodHandle;").unwrap(),
|
||||
};
|
||||
let target_handle = self
|
||||
.thread
|
||||
.invoke_virtual(get_target, call_site, vec![])?
|
||||
.ok_or_else(|| VmError::InvariantError("getTarget returned null".into()))?;
|
||||
|
||||
// 9. Pop runtime arguments
|
||||
let runtime_arg_count = call_site_method_type.parameters.len();
|
||||
let runtime_args: Vec<Value> = self.stack.pop_n(runtime_arg_count)?;
|
||||
|
||||
// 10. Invoke target with runtime args
|
||||
let boxed_runtime: Vec<Option<ReferenceKind>> = runtime_args
|
||||
.into_iter()
|
||||
.map(|v| self.box_value(v))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let runtime_array = self
|
||||
.thread
|
||||
.gc
|
||||
.write()
|
||||
.new_object_array_from(obj_array_class, boxed_runtime.into_boxed_slice());
|
||||
|
||||
let result = self.thread.invoke_virtual(
|
||||
invoke_ref.clone(),
|
||||
target_handle,
|
||||
vec![runtime_array.into()],
|
||||
)?;
|
||||
|
||||
// 11. Push result (unboxing if needed)
|
||||
if let Some(return_type) = &call_site_method_type.return_type {
|
||||
let result_val = result
|
||||
.ok_or_else(|| VmError::InternalError("Expected return value".into()))?;
|
||||
let unboxed = self.unbox_if_primitive(result_val, return_type)?;
|
||||
self.push(unboxed);
|
||||
}
|
||||
|
||||
Ok(ExecutionResult::Continue)*/
|
||||
// todo!(
|
||||
// "Invoke dynamic needs major constant pool and vm invoke method handle support"
|
||||
// );
|
||||
error::dbg_panic!(
|
||||
"Invoke dynamic needs major constant pool and vm invoke method handle support"
|
||||
)
|
||||
}
|
||||
|
||||
@ -1516,6 +1696,44 @@ impl Frame {
|
||||
}
|
||||
|
||||
fn load_constant(&mut self, index: u16) -> Result<ExecutionResult, VmError> {
|
||||
let thing = self.pool.resolve_loadable(index, self.class.clone())?;
|
||||
let resolved = match thing {
|
||||
Loadable::Integer(x) => Value::from(x),
|
||||
Loadable::Float(x) => Value::from(x),
|
||||
Loadable::Long(x) => Value::from(x),
|
||||
Loadable::Double(x) => Value::from(x),
|
||||
Loadable::Class(name) => {
|
||||
let class = self.thread.get_class(&name)?;
|
||||
let class_ref = self.thread.gc.read().get(
|
||||
*class
|
||||
.mirror
|
||||
.get()
|
||||
.expect(&format!("Mirror unintialised {}", class.this_class)),
|
||||
);
|
||||
Value::from(class_ref)
|
||||
}
|
||||
Loadable::String(string) => Value::from(self.thread.intern_string(&string)),
|
||||
Loadable::MethodHandle(handle_info) => {
|
||||
let method_handle = jsr292::MethodHandle::from_info(self, handle_info)?;
|
||||
method_handle.into()
|
||||
}
|
||||
Loadable::MethodType(x) => {
|
||||
let refe = MethodRef::from_symbols(
|
||||
VmSymbols::CLASS,
|
||||
"fromDescriptor",
|
||||
&vec![VmSymbols::STRING, VmSymbols::CLASSLOADER],
|
||||
Some(VmSymbols::METHOD_TYPE),
|
||||
);
|
||||
let string = self.thread.intern_string(&*x.desc.param_string());
|
||||
let thing = self
|
||||
.thread
|
||||
.invoke(refe, vec![Value::from(string), Value::NULL])?
|
||||
.unwrap();
|
||||
Value::from(thing)
|
||||
}
|
||||
Loadable::Dynamic(dynamic_info) => error::dbg_panic!("Dynamic, more so")?,
|
||||
};
|
||||
|
||||
let thing = self.pool.get_constant(index.to_owned())?;
|
||||
trace!("\tLoading constant: {}", thing);
|
||||
let resolved = match thing {
|
||||
@ -1583,6 +1801,90 @@ impl Frame {
|
||||
self.push(resolved);
|
||||
Ok(ExecutionResult::Continue)
|
||||
}
|
||||
|
||||
fn resolve_loadable(&self, loadable: Loadable) -> Result<Value, VmError> {
|
||||
match loadable {
|
||||
Loadable::Integer(i) => Ok(Value::from(i)),
|
||||
Loadable::Float(f) => Ok(Value::from(f)),
|
||||
Loadable::Long(l) => Ok(Value::from(l)),
|
||||
Loadable::Double(d) => Ok(Value::from(d)),
|
||||
Loadable::Class(class_name) => {
|
||||
let class = self.thread.get_class(&class_name)?;
|
||||
let class_ref = self.thread.gc.read().get(
|
||||
*class
|
||||
.mirror
|
||||
.get()
|
||||
.expect(&format!("Mirror unintialised {}", class.this_class)),
|
||||
);
|
||||
Ok(Value::from(class_ref))
|
||||
}
|
||||
Loadable::String(string) => Ok(Value::from(self.thread.intern_string(&string))),
|
||||
Loadable::MethodHandle(handle_info) => {
|
||||
let method_handle = jsr292::MethodHandle::from_info(self, handle_info)?;
|
||||
Ok(method_handle.into())
|
||||
}
|
||||
Loadable::MethodType(method_type_info) => {
|
||||
let refe = MethodRef::from_symbols(
|
||||
VmSymbols::CLASS,
|
||||
"fromDescriptor",
|
||||
&vec![VmSymbols::STRING, VmSymbols::CLASSLOADER],
|
||||
Some(VmSymbols::METHOD_TYPE),
|
||||
);
|
||||
let string = self
|
||||
.thread
|
||||
.intern_string(&*method_type_info.desc.param_string());
|
||||
let thing = self
|
||||
.thread
|
||||
.invoke(refe, vec![Value::from(string), Value::NULL])?
|
||||
.unwrap();
|
||||
Ok(thing)
|
||||
}
|
||||
Loadable::Dynamic(dynamic_info) => {
|
||||
// first r is examined to determine bootstrap method and args
|
||||
|
||||
// second args are packed into an array and the bootstrap method is invoked
|
||||
// args[0] is the Lookup
|
||||
// args[1] is the name
|
||||
// args[2] methodType
|
||||
|
||||
//third the result is validated and used as the result of resolution
|
||||
|
||||
let method_handle =
|
||||
jsr292::MethodHandle::from_info(self, dynamic_info.method.handle)?;
|
||||
let args: Vec<Value> = dynamic_info
|
||||
.method
|
||||
.args
|
||||
.into_iter()
|
||||
.map(|loadable| self.resolve_loadable(loadable))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let lookup = {
|
||||
let method_ref = MethodRef::from_symbols(
|
||||
VmSymbols::METHOD_HANDLES,
|
||||
"lookup",
|
||||
&vec![],
|
||||
Some(VmSymbols::METHOD_HANDLES_LOOKUP),
|
||||
);
|
||||
let lookup = self.thread.invoke(method_ref, vec![])?;
|
||||
lookup.unwrap()
|
||||
};
|
||||
|
||||
let name = {
|
||||
let name = self.thread.intern_string(&dynamic_info.name);
|
||||
Value::from(name)
|
||||
};
|
||||
|
||||
let method_type = {
|
||||
// gotta like smash this into a method type or sumthin
|
||||
dynamic_info.desc
|
||||
}
|
||||
|
||||
Err(VmError::Debug(
|
||||
"Dynamic loading not yet implemented".to_string(),
|
||||
))?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
//! - [`MethodDescriptor`] - Method signature information
|
||||
//! - [`FieldType`] - Field type information
|
||||
|
||||
use crate::class_file::MethodRef;
|
||||
use crate::class_file::resolved::MethodRef;
|
||||
pub use crate::thread::VmThread;
|
||||
use deku_derive::{DekuRead, DekuWrite};
|
||||
use itertools::Itertools;
|
||||
@ -24,6 +24,7 @@ use std::cell::RefCell;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
use value::Value;
|
||||
use windows::Win32::System::Threading::GetCurrentThreadId;
|
||||
|
||||
mod bimage;
|
||||
mod class;
|
||||
@ -32,15 +33,18 @@ mod class_loader;
|
||||
pub mod error;
|
||||
mod frame;
|
||||
mod instructions;
|
||||
mod jsr292;
|
||||
mod macros;
|
||||
pub mod native;
|
||||
pub mod objects;
|
||||
mod prim;
|
||||
mod rng;
|
||||
mod symbols;
|
||||
mod thread;
|
||||
pub mod value;
|
||||
pub mod vm;
|
||||
|
||||
pub use symbols::vm_symbols as VmSymbols;
|
||||
/// Unique identifier for a VM thread.
|
||||
///
|
||||
/// Each VmThread is assigned a unique ThreadId when created. This ID is used to:
|
||||
@ -49,6 +53,11 @@ pub mod vm;
|
||||
/// - Support future multi-threading when Java threads map to OS threads
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct ThreadId(pub u64);
|
||||
impl From<u64> for ThreadId {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents JVM primitive types used in field and method descriptors.
|
||||
///
|
||||
@ -138,7 +147,24 @@ pub struct MethodDescriptor {
|
||||
// none = void/v
|
||||
pub return_type: Option<FieldType>,
|
||||
}
|
||||
fn sanitise(name: &str) -> Cow<'_, str> {
|
||||
match name {
|
||||
"int" => "I".into(),
|
||||
"long" => "J".into(),
|
||||
"short" => "S".into(),
|
||||
"char" => "C".into(),
|
||||
"byte" => "B".into(),
|
||||
"float" => "F".into(),
|
||||
"double" => "D".into(),
|
||||
"boolean" => "Z".into(),
|
||||
"void" => "V".into(),
|
||||
|
||||
// Already a descriptor
|
||||
s if s.starts_with('[') || s.starts_with('L') || s.len() == 1 => name.into(),
|
||||
|
||||
_ => format!("L{name};").into(),
|
||||
}
|
||||
}
|
||||
impl MethodDescriptor {
|
||||
pub fn void() -> Self {
|
||||
Self {
|
||||
@ -146,14 +172,12 @@ impl MethodDescriptor {
|
||||
return_type: None,
|
||||
}
|
||||
}
|
||||
pub fn method_type() -> Self {
|
||||
MethodDescriptor::parse(
|
||||
"(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;",
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
pub fn lookup() -> Self {
|
||||
MethodDescriptor::parse("()Ljava/lang/invoke/MethodHandles$Lookup;").unwrap()
|
||||
pub fn from_symbols(parameters: &[&str], return_type: Option<&str>) -> Self {
|
||||
let ret = return_type.unwrap_or("V");
|
||||
let return_type = sanitise(ret);
|
||||
let parameters = parameters.iter().map(|p| sanitise(p)).join("");
|
||||
let desc: String = format!("({parameters}){return_type}");
|
||||
MethodDescriptor::parse(&desc).unwrap()
|
||||
}
|
||||
pub fn psvmsa() -> Self {
|
||||
MethodDescriptor::parse("([Ljava/lang/String;)V").unwrap()
|
||||
@ -167,6 +191,20 @@ impl MethodDescriptor {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MethodDescriptor {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "(")?;
|
||||
for param in &self.parameters {
|
||||
write!(f, "{}", param)?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
match &self.return_type {
|
||||
Some(ret) => write!(f, "{}", ret),
|
||||
None => write!(f, "V"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BaseType {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
@ -182,30 +220,6 @@ impl Display for BaseType {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FieldType {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
FieldType::Base(base) => write!(f, "{}", base),
|
||||
FieldType::ClassType(name) => write!(f, "L{};", name),
|
||||
FieldType::ArrayType(component) => write!(f, "[{}", component),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MethodDescriptor {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "(")?;
|
||||
for param in &self.parameters {
|
||||
write!(f, "{}", param)?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
match &self.return_type {
|
||||
Some(ret) => write!(f, "{}", ret),
|
||||
None => write!(f, "V"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stack_used() -> usize {
|
||||
static STACK_BASE: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
|
||||
let local = 0u8;
|
||||
@ -233,10 +247,23 @@ pub enum FieldType {
|
||||
ArrayType(Box<FieldType>),
|
||||
}
|
||||
|
||||
impl Display for FieldType {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
FieldType::Base(base) => write!(f, "{}", base),
|
||||
FieldType::ClassType(name) => write!(f, "L{};", name),
|
||||
FieldType::ArrayType(inner) => write!(f, "[{}", inner),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldType {
|
||||
pub fn bool() -> Self {
|
||||
Self::Base(BaseType::Boolean)
|
||||
}
|
||||
pub fn from_symbols(class_name: &str) -> Self {
|
||||
Self::parse(&sanitise(class_name)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldType {
|
||||
@ -336,3 +363,13 @@ fn set_last_native(name: &str) {
|
||||
pub fn get_last_native() -> String {
|
||||
LAST_NATIVE_SYMBOL.with(|cell| cell.borrow().clone())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn os_thread_id() -> u64 {
|
||||
unsafe { libc::pthread_self() as u64 }
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn os_thread_id() -> u64 {
|
||||
unsafe { GetCurrentThreadId() as u64 }
|
||||
}
|
||||
|
||||
@ -295,3 +295,9 @@ macro_rules! shift_op {
|
||||
Ok(ExecutionResult::Continue)
|
||||
}};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! location {
|
||||
() => {
|
||||
format!("{}:{}:{}", file!(), line!(), column!())
|
||||
};
|
||||
}
|
||||
|
||||
@ -17,13 +17,13 @@ fn main() {
|
||||
}
|
||||
|
||||
fn run() {
|
||||
env_logger::Builder::from_default_env()
|
||||
.filter_level(LevelFilter::Trace)
|
||||
.filter_module("deku", LevelFilter::Warn)
|
||||
.filter_module("roast_vm_core::class_file::class_file", LevelFilter::Info)
|
||||
.filter_module("roast_vm_core::class_file::attributes", LevelFilter::Info)
|
||||
.filter_module("roast_vm_core::instructions", LevelFilter::Info)
|
||||
.init();
|
||||
// env_logger::Builder::from_default_env()
|
||||
// .filter_level(LevelFilter::Trace)
|
||||
// .filter_module("deku", LevelFilter::Warn)
|
||||
// .filter_module("roast_vm_core::class_file::class_file", LevelFilter::Info)
|
||||
// .filter_module("roast_vm_core::class_file::attributes", LevelFilter::Info)
|
||||
// .filter_module("roast_vm_core::instructions", LevelFilter::Info)
|
||||
// .init();
|
||||
stack_used();
|
||||
let vm = Vm::new();
|
||||
fetch_libs(&vm);
|
||||
|
||||
@ -3,13 +3,14 @@
|
||||
#![feature(c_variadic)]
|
||||
#![allow(unsafe_op_in_unsafe_fn)]
|
||||
use crate::class::RuntimeClass;
|
||||
use crate::class_file::{FieldData, FieldRef};
|
||||
use crate::class_file::FieldData;
|
||||
use crate::class_file::resolved::FieldRef;
|
||||
use crate::objects::array::ArrayReference;
|
||||
use crate::objects::object::{ObjectReference, ReferenceKind};
|
||||
use crate::prim::jboolean;
|
||||
use crate::thread::VmThread;
|
||||
use crate::value::{Primitive, Value};
|
||||
use crate::{BaseType, FieldType, MethodDescriptor, generate_jni_short_name};
|
||||
use crate::{BaseType, FieldType, MethodDescriptor, VmSymbols, generate_jni_short_name};
|
||||
use jni::sys::*;
|
||||
use jni::sys::{JNIEnv, jstring};
|
||||
use jni::sys::{JNINativeInterface_, jclass, jint, jobject};
|
||||
@ -321,7 +322,7 @@ unsafe extern "system" fn get_string_utfchars(
|
||||
|
||||
let obj = obj_ref.lock();
|
||||
let field_ref = FieldRef {
|
||||
class: "java/lang/String".to_string(),
|
||||
class: VmSymbols::STRING.to_string(),
|
||||
name: "value".to_string(),
|
||||
desc: FieldType::ArrayType(Box::new(FieldType::Base(BaseType::Byte))),
|
||||
};
|
||||
@ -1706,11 +1707,11 @@ unsafe extern "system" fn new_string_utf(env: *mut JNIEnv, utf: *const c_char) -
|
||||
let str_ref = if intern {
|
||||
thread.intern_string(str)
|
||||
} else {
|
||||
let Ok(string_class) = thread.get_class("java/lang/String") else {
|
||||
let Ok(string_class) = thread.get_class(VmSymbols::STRING) else {
|
||||
return ptr::null_mut();
|
||||
};
|
||||
|
||||
let Ok(byte_array_class) = thread.get_class("[B") else {
|
||||
let Ok(byte_array_class) = thread.get_class(VmSymbols::BYTE_ARRAY) else {
|
||||
return ptr::null_mut();
|
||||
};
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ use crate::class::RuntimeClass;
|
||||
use crate::error::VmError;
|
||||
use crate::objects::object::{Reference, ReferenceKind};
|
||||
use crate::prim::Primitive;
|
||||
use crate::value::ClassName;
|
||||
use jni::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort};
|
||||
use parking_lot::Mutex;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
@ -90,6 +91,12 @@ pub struct Array<T: ArrayValue> {
|
||||
pub backing: Box<[T]>,
|
||||
}
|
||||
|
||||
impl<T: ArrayValue> ClassName for Array<T> {
|
||||
fn class_name(&self) -> String {
|
||||
self.class.this_class.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Array<T>
|
||||
where
|
||||
T: ArrayValue + Clone + Default,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use crate::VmSymbols;
|
||||
use crate::class::RuntimeClass;
|
||||
use crate::class_file::FieldRef;
|
||||
use crate::class_file::resolved::FieldRef;
|
||||
use crate::error::VmError;
|
||||
use crate::objects::array::{ArrayReference, ObjectArrayReference, PrimitiveArrayReference};
|
||||
use crate::prim::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort};
|
||||
@ -46,7 +47,7 @@ impl Object {
|
||||
|
||||
impl Display for Object {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.class.this_class == "java/lang/String" {}
|
||||
if self.class.this_class == VmSymbols::STRING {}
|
||||
write!(f, "Object[id={}, class={}]", self.id, self.class.this_class)
|
||||
}
|
||||
}
|
||||
@ -121,7 +122,7 @@ impl Display for ReferenceKind {
|
||||
let id = match self {
|
||||
ReferenceKind::ObjectReference(x) => unsafe {
|
||||
let guard = x.make_guard_unchecked();
|
||||
if guard.class.this_class == "java/lang/String"
|
||||
if guard.class.this_class == VmSymbols::STRING
|
||||
&& let Some(field) = guard.fields.get("value")
|
||||
&& let Value::Reference(Some(ReferenceKind::ArrayReference(
|
||||
ArrayReference::Byte(actual),
|
||||
|
||||
@ -7,7 +7,7 @@ use crate::objects::object::{
|
||||
Object, ObjectReference, Reference, ReferenceKind, string_from_bytes,
|
||||
};
|
||||
use crate::value::Value;
|
||||
use crate::{BaseType, ThreadId};
|
||||
use crate::{BaseType, ThreadId, VmSymbols};
|
||||
use dashmap::DashMap;
|
||||
use jni::sys::{jint, jlong};
|
||||
use parking_lot::{Condvar, Mutex};
|
||||
@ -403,7 +403,7 @@ impl ObjectManager {
|
||||
ReferenceKind::ArrayReference(arr) => self.clone_array(arr),
|
||||
ReferenceKind::ObjectReference(obj) => {
|
||||
let class = obj.lock().class.clone();
|
||||
if !class.implements("java/lang/Cloneable") {
|
||||
if !class.implements(VmSymbols::CLONEABLE) {
|
||||
return Err(VmError::InvariantError("CloneNotSupported".to_string()));
|
||||
}
|
||||
self.clone_instance(obj)
|
||||
|
||||
103
crates/core/src/symbols.rs
Normal file
103
crates/core/src/symbols.rs
Normal file
@ -0,0 +1,103 @@
|
||||
pub mod vm_symbols {
|
||||
// Core
|
||||
pub const OBJECT: &str = "java/lang/Object";
|
||||
pub const CLASS: &str = "java/lang/Class";
|
||||
pub const STRING: &str = "java/lang/String";
|
||||
pub const SYSTEM: &str = "java/lang/System";
|
||||
pub const THREAD: &str = "java/lang/Thread";
|
||||
pub const THREAD_GROUP: &str = "java/lang/ThreadGroup";
|
||||
pub const THREAD_FIELD_HOLDER: &str = "java/lang/Thread$FieldHolder";
|
||||
pub const CLASSLOADER: &str = "java/lang/ClassLoader";
|
||||
pub const THROWABLE: &str = "java/lang/Throwable";
|
||||
pub const MODULE: &str = "java/lang/Module";
|
||||
|
||||
// Boxed primitives
|
||||
pub const BOOLEAN: &str = "java/lang/Boolean";
|
||||
pub const BYTE: &str = "java/lang/Byte";
|
||||
pub const CHARACTER: &str = "java/lang/Character";
|
||||
pub const SHORT: &str = "java/lang/Short";
|
||||
pub const INTEGER: &str = "java/lang/Integer";
|
||||
pub const LONG: &str = "java/lang/Long";
|
||||
pub const FLOAT: &str = "java/lang/Float";
|
||||
pub const DOUBLE: &str = "java/lang/Double";
|
||||
pub const VOID: &str = "java/lang/Void";
|
||||
pub const NUMBER: &str = "java/lang/Number";
|
||||
|
||||
// Exceptions
|
||||
pub const EXCEPTION: &str = "java/lang/Exception";
|
||||
pub const RUNTIME_EXCEPTION: &str = "java/lang/RuntimeException";
|
||||
pub const NULL_POINTER_EXCEPTION: &str = "java/lang/NullPointerException";
|
||||
pub const ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION: &str =
|
||||
"java/lang/ArrayIndexOutOfBoundsException";
|
||||
pub const CLASS_NOT_FOUND_EXCEPTION: &str = "java/lang/ClassNotFoundException";
|
||||
pub const ILLEGAL_ARGUMENT_EXCEPTION: &str = "java/lang/IllegalArgumentException";
|
||||
pub const ILLEGAL_STATE_EXCEPTION: &str = "java/lang/IllegalStateException";
|
||||
pub const UNSUPPORTED_OPERATION_EXCEPTION: &str = "java/lang/UnsupportedOperationException";
|
||||
pub const CLASS_CAST_EXCEPTION: &str = "java/lang/ClassCastException";
|
||||
pub const ARITHMETIC_EXCEPTION: &str = "java/lang/ArithmeticException";
|
||||
pub const INDEX_OUT_OF_BOUNDS_EXCEPTION: &str = "java/lang/IndexOutOfBoundsException";
|
||||
|
||||
// Errors
|
||||
pub const ERROR: &str = "java/lang/Error";
|
||||
pub const LINKAGE_ERROR: &str = "java/lang/LinkageError";
|
||||
pub const NO_CLASS_DEF_FOUND_ERROR: &str = "java/lang/NoClassDefFoundError";
|
||||
pub const NO_SUCH_METHOD_ERROR: &str = "java/lang/NoSuchMethodError";
|
||||
pub const NO_SUCH_FIELD_ERROR: &str = "java/lang/NoSuchFieldError";
|
||||
pub const OUT_OF_MEMORY_ERROR: &str = "java/lang/OutOfMemoryError";
|
||||
pub const STACK_OVERFLOW_ERROR: &str = "java/lang/StackOverflowError";
|
||||
pub const ABSTRACT_METHOD_ERROR: &str = "java/lang/AbstractMethodError";
|
||||
pub const INCOMPATIBLE_CLASS_CHANGE_ERROR: &str = "java/lang/IncompatibleClassChangeError";
|
||||
pub const EXCEPTION_IN_INITIALIZER_ERROR: &str = "java/lang/ExceptionInInitializerError";
|
||||
pub const VERIFY_ERROR: &str = "java/lang/VerifyError";
|
||||
pub const INTERNAL_ERROR: &str = "java/lang/InternalError";
|
||||
|
||||
// Reflection
|
||||
pub const FIELD: &str = "java/lang/reflect/Field";
|
||||
pub const METHOD: &str = "java/lang/reflect/Method";
|
||||
pub const CONSTRUCTOR: &str = "java/lang/reflect/Constructor";
|
||||
|
||||
// IO
|
||||
pub const SERIALIZABLE: &str = "java/io/Serializable";
|
||||
pub const PRINT_STREAM: &str = "java/io/PrintStream";
|
||||
pub const INPUT_STREAM: &str = "java/io/InputStream";
|
||||
pub const OUTPUT_STREAM: &str = "java/io/OutputStream";
|
||||
pub const FILE_DESCRIPTOR: &str = "java/io/FileDescriptor";
|
||||
|
||||
// Other commonly needed
|
||||
pub const CLONEABLE: &str = "java/lang/Cloneable";
|
||||
pub const COMPARABLE: &str = "java/lang/Comparable";
|
||||
pub const ENUM: &str = "java/lang/Enum";
|
||||
pub const RECORD: &str = "java/lang/Record";
|
||||
pub const STACKTRACEELEMENT: &str = "java/lang/StackTraceElement";
|
||||
|
||||
// Primitive array descriptors
|
||||
pub const BOOLEAN_ARRAY: &str = "[Z";
|
||||
pub const BYTE_ARRAY: &str = "[B";
|
||||
pub const CHAR_ARRAY: &str = "[C";
|
||||
pub const SHORT_ARRAY: &str = "[S";
|
||||
pub const INT_ARRAY: &str = "[I";
|
||||
pub const LONG_ARRAY: &str = "[J";
|
||||
pub const FLOAT_ARRAY: &str = "[F";
|
||||
pub const DOUBLE_ARRAY: &str = "[D";
|
||||
|
||||
// Object array (common one)
|
||||
pub const OBJECT_ARRAY: &str = "[Ljava/lang/Object;";
|
||||
pub const STRING_ARRAY: &str = "[Ljava/lang/String;";
|
||||
|
||||
// java/lang/invoke
|
||||
pub const METHOD_HANDLE: &str = "java/lang/invoke/MethodHandle";
|
||||
pub const METHOD_HANDLES: &str = "java/lang/invoke/MethodHandles";
|
||||
pub const METHOD_HANDLES_LOOKUP: &str = "java/lang/invoke/MethodHandles$Lookup";
|
||||
pub const METHOD_TYPE: &str = "java/lang/invoke/MethodType";
|
||||
pub const CALL_SITE: &str = "java/lang/invoke/CallSite";
|
||||
|
||||
// java/lang/constant
|
||||
pub const CONSTANT_METHOD_HANDLE_DESC: &str = "java/lang/constant/MethodHandleDesc";
|
||||
pub const CONSTANT_METHOD_TYPE: &str = "java/lang/constant/MethodTypeDesc";
|
||||
pub const CONSTANT_CLASS_DESC: &str = "java/lang/constant/ClassDesc";
|
||||
pub const CONSTANT_STRING_DESC: &str = "java/lang/constant/StringDesc";
|
||||
pub const CONSTANT_DIRECT_METHOD_HANDLE_DESC_KIND: &str =
|
||||
"java/lang/constant/DirectMethodHandleDesc$Kind";
|
||||
pub const CONSTANT_DIRECT_METHOD_HANDLE_DESC: &str =
|
||||
"java/lang/constant/DirectMethodHandleDesc";
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
#![feature(thread_id_value)]
|
||||
use crate::class::{ClassRef, InitState, RuntimeClass};
|
||||
use crate::class_file::{MethodData, MethodRef};
|
||||
use crate::class_file::MethodData;
|
||||
use crate::class_loader::{ClassLoader, LoaderRef};
|
||||
use crate::error::VmError;
|
||||
use crate::frame::Frame;
|
||||
@ -7,9 +8,10 @@ use crate::native::jni::create_jni_function_table;
|
||||
use crate::objects::object::{ObjectReference, ReferenceKind};
|
||||
use crate::objects::object_manager::ObjectManager;
|
||||
use crate::value::{Primitive, Value};
|
||||
use crate::vm::Vm;
|
||||
use crate::vm::{Init, Vm};
|
||||
use crate::{
|
||||
BaseType, FieldType, MethodDescriptor, ThreadId, generate_jni_method_name, set_last_native,
|
||||
BaseType, FieldType, MethodDescriptor, ThreadId, VmSymbols, generate_jni_method_name,
|
||||
os_thread_id, set_last_native,
|
||||
};
|
||||
use jni::sys::{JNIEnv, jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jobject, jshort};
|
||||
use libffi::middle::*;
|
||||
@ -22,7 +24,7 @@ use std::collections::VecDeque;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
|
||||
use std::thread;
|
||||
use crate::class_file::resolved::{InterfaceOrMethod, MethodRef};
|
||||
|
||||
static INIT_LOGGER: Once = Once::new();
|
||||
type MethodCallResult = Result<Option<Value>, VmError>;
|
||||
@ -48,7 +50,8 @@ pub struct VmThread {
|
||||
|
||||
impl VmThread {
|
||||
pub fn new(vm: Arc<Vm>, loader: Option<LoaderRef>) -> Arc<Self> {
|
||||
let id = ThreadId(vm.next_id.fetch_add(1, Ordering::SeqCst));
|
||||
// let id = ThreadId(vm.next_id.fetch_add(1, Ordering::SeqCst));
|
||||
let id = os_thread_id().into();
|
||||
|
||||
let loader = loader.unwrap_or(vm.loader.clone());
|
||||
let gc = vm.gc.clone();
|
||||
@ -67,23 +70,22 @@ impl VmThread {
|
||||
})
|
||||
}
|
||||
|
||||
/// Get current thread ID from thread-local storage
|
||||
/*/// Get current thread ID from thread-local storage
|
||||
pub fn current_id() -> ThreadId {
|
||||
CURRENT_THREAD_ID.with(|cell| cell.borrow().expect("No current thread set"))
|
||||
}
|
||||
|
||||
/// Set current thread ID for this OS thread
|
||||
pub fn set_current(id: ThreadId) {
|
||||
CURRENT_THREAD_ID.with(|cell| {
|
||||
*cell.borrow_mut() = Some(id);
|
||||
});
|
||||
}
|
||||
CURRENT_THREAD_ID.set(Some(id));
|
||||
}*/
|
||||
|
||||
/// Get current thread from VM using thread-local storage
|
||||
// put this on the vm lol.
|
||||
/*/// Get current thread from VM using thread-local storage
|
||||
pub fn current(vm: &Arc<Vm>) -> Arc<VmThread> {
|
||||
let id = Self::current_id();
|
||||
vm.threads.get(&id).unwrap().clone()
|
||||
}
|
||||
}*/
|
||||
|
||||
/*/// Get or resolve a class, ensuring it and its dependencies are initialised.
|
||||
/// Follows JVM Spec 5.5 for recursive initialisation handling.
|
||||
@ -109,14 +111,16 @@ impl VmThread {
|
||||
|
||||
pub fn get_class(&self, what: &str) -> Result<Arc<RuntimeClass>, VmError> {
|
||||
let class = self.loader.lock().get_or_load(what, None)?;
|
||||
if self.vm.phase.load(Ordering::Acquire) >= Init::PRIMITIVES {
|
||||
self.create_mirror_class(&class)?;
|
||||
}
|
||||
Ok(class)
|
||||
}
|
||||
|
||||
/// Initialize a class following JVM Spec 5.5.
|
||||
/// Handles recursive initialization by tracking which thread is initializing.
|
||||
pub fn init(&self, class: Arc<RuntimeClass>) -> Result<(), VmError> {
|
||||
let current_thread = thread::current().id();
|
||||
let current_thread = os_thread_id().into();
|
||||
|
||||
// Check and update initialization state
|
||||
{
|
||||
@ -195,7 +199,7 @@ impl VmThread {
|
||||
}
|
||||
|
||||
pub fn ensure_initialised(&self, class: &Arc<RuntimeClass>) -> Result<(), VmError> {
|
||||
let current_thread = thread::current().id();
|
||||
let current_thread = os_thread_id().into();
|
||||
|
||||
{
|
||||
let mut state = class.init_state.lock();
|
||||
@ -265,14 +269,15 @@ impl VmThread {
|
||||
}
|
||||
|
||||
/// creates a mirror java/lang/Class Object and binds it to this RuntimeClass
|
||||
fn create_mirror_class(&self, class: &Arc<RuntimeClass>) -> Result<(), VmError> {
|
||||
pub(crate) fn create_mirror_class(&self, class: &Arc<RuntimeClass>) -> Result<(), VmError> {
|
||||
if class.mirror.get().is_some() || class.mirror_in_progress.swap(true, Ordering::SeqCst) {
|
||||
return Ok(()); // already has a mirror
|
||||
}
|
||||
let class_class = if class.this_class == "java/lang/Class" {
|
||||
let class_class = if class.this_class == VmSymbols::CLASS {
|
||||
Arc::clone(class)
|
||||
} else {
|
||||
self.get_class("java/lang/Class")?
|
||||
// self.get_class("java/lang/Class")?
|
||||
self.get_class(VmSymbols::CLASS)?
|
||||
};
|
||||
let string = self.intern_string(&class.this_class);
|
||||
let component_type = if (class.this_class.starts_with("[")) {
|
||||
@ -295,17 +300,18 @@ impl VmThread {
|
||||
}
|
||||
|
||||
pub fn invoke_main(&self, what: &str) -> Result<(), VmError> {
|
||||
let method_ref = MethodRef {
|
||||
class: what.to_string(),
|
||||
name: "main".to_string(),
|
||||
desc: MethodDescriptor::psvm(),
|
||||
};
|
||||
let method_ref = MethodRef::from_symbols(what, "main", &[], None);
|
||||
|
||||
self.invoke(method_ref, Vec::new())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn invoke(&self, method_reference: MethodRef, args: Vec<Value>) -> MethodCallResult {
|
||||
pub fn invoke(
|
||||
&self,
|
||||
either: impl Into<InterfaceOrMethod>,
|
||||
args: Vec<Value>,
|
||||
) -> MethodCallResult {
|
||||
let either = either.into();
|
||||
if self.gc.read().objects.len() > 2350 {
|
||||
INIT_LOGGER.call_once(|| {
|
||||
env_logger::Builder::from_default_env()
|
||||
@ -318,8 +324,8 @@ impl VmThread {
|
||||
});
|
||||
// println!("heap length {}", self.gc.read().objects.len())
|
||||
}
|
||||
let class = self.get_class(&method_reference.class)?;
|
||||
let method = class.find_method(&method_reference.name, &method_reference.desc)?;
|
||||
let class = self.get_class(&either.class())?;
|
||||
let method = class.find_method(&either.name(), &either.desc())?;
|
||||
let class = self.loader.lock().get_or_load(&*method.class, None)?;
|
||||
|
||||
self.execute_method(&class, &method, args)
|
||||
@ -327,11 +333,11 @@ impl VmThread {
|
||||
|
||||
pub fn invoke_virtual(
|
||||
&self,
|
||||
method_reference: MethodRef,
|
||||
method_reference: InterfaceOrMethod,
|
||||
class: Arc<RuntimeClass>,
|
||||
args: Vec<Value>,
|
||||
) -> MethodCallResult {
|
||||
let method = class.find_method(&method_reference.name, &method_reference.desc)?;
|
||||
let method = class.find_method(&method_reference.name(), &method_reference.desc())?;
|
||||
|
||||
let class = self.loader.lock().get_or_load(&*method.class, None)?;
|
||||
self.execute_method(&class, &method, args)
|
||||
@ -340,11 +346,11 @@ impl VmThread {
|
||||
pub fn invoke_native(&self, method: &MethodRef, args: Vec<Value>) -> MethodCallResult {
|
||||
let symbol_name = generate_jni_method_name(method, false);
|
||||
|
||||
if symbol_name.contains("Java_java_lang_reflect_Array_newArray") {
|
||||
return Err(VmError::Debug(
|
||||
"RoastVM specific implementation required for Java_java_lang_reflect_Array_newArray",
|
||||
));
|
||||
}
|
||||
// if symbol_name.contains("Java_java_lang_reflect_Array_newArray") {
|
||||
// return Err(VmError::Debug(
|
||||
// "RoastVM specific implementation required for Java_java_lang_reflect_Array_newArray",
|
||||
// ));
|
||||
// }
|
||||
|
||||
let result = unsafe {
|
||||
let p = self
|
||||
@ -501,7 +507,7 @@ impl VmThread {
|
||||
let method_ref = class.find_method("<init>", &desc)?;
|
||||
let mut args = args.to_vec();
|
||||
args.insert(0, obj.clone().into());
|
||||
let _ = self.invoke(method_ref.into(), args)?;
|
||||
let _ = self.invoke(MethodRef::from(method_ref), args)?;
|
||||
Ok(obj)
|
||||
}
|
||||
}
|
||||
@ -603,12 +609,13 @@ impl VmThread {
|
||||
}
|
||||
|
||||
pub fn bootstrap_mirror(&self) {
|
||||
let thread_id = self.id.0 as jlong;
|
||||
let thread_id: u64 = unsafe { std::mem::transmute(self.id) };
|
||||
let thread_id = thread_id as jlong;
|
||||
let main = self.intern_string("main");
|
||||
let system = self.intern_string("system");
|
||||
let thread_klass = self.get_class("java/lang/Thread").unwrap();
|
||||
let thread_group_klass = self.get_class("java/lang/ThreadGroup").unwrap();
|
||||
let field_holder_klass = self.get_class("java/lang/Thread$FieldHolder").unwrap();
|
||||
let thread_klass = self.get_class(VmSymbols::THREAD).unwrap();
|
||||
let thread_group_klass = self.get_class(VmSymbols::THREAD_GROUP).unwrap();
|
||||
let field_holder_klass = self.get_class(VmSymbols::THREAD_FIELD_HOLDER).unwrap();
|
||||
let group = self
|
||||
.gc
|
||||
.write()
|
||||
@ -623,6 +630,16 @@ impl VmThread {
|
||||
.new_thread(thread_klass, thread_id, thread_id, main, holder);
|
||||
self.mirror.set(thread.lock().id).unwrap();
|
||||
}
|
||||
|
||||
pub fn get_class_mirror(&self, name: &str) -> Result<Value, VmError> {
|
||||
let class = self.get_class(&name)?;
|
||||
let mirror_id = *class
|
||||
.mirror
|
||||
.get()
|
||||
.ok_or_else(|| VmError::InvariantError(format!("Mirror uninitialized: {}", name)))?;
|
||||
let class_ref = self.gc.read().get(mirror_id);
|
||||
Ok(Value::from(class_ref))
|
||||
}
|
||||
}
|
||||
// SAFETY:
|
||||
// - jni_env pointer is owned by this VmThread and only used by its OS thread
|
||||
|
||||
@ -193,6 +193,22 @@ impl Primitive {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ClassName for Primitive {
|
||||
fn class_name(&self) -> String {
|
||||
match self {
|
||||
Primitive::Int(_) => "int".to_string(),
|
||||
Primitive::Long(_) => "long".to_string(),
|
||||
Primitive::Short(_) => "short".to_string(),
|
||||
Primitive::Char(_) => "char".to_string(),
|
||||
Primitive::Byte(_) => "byte".to_string(),
|
||||
|
||||
Primitive::Float(_) => "float".to_string(),
|
||||
Primitive::Double(_) => "double".to_string(),
|
||||
|
||||
Primitive::Boolean(_) => "boolean".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Primitive {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
@ -313,3 +329,7 @@ impl PartialEq<FieldType> for Value {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ClassName {
|
||||
fn class_name(&self) -> String;
|
||||
}
|
||||
|
||||
@ -5,27 +5,28 @@ use libloading::os::unix as imp;
|
||||
#[cfg(all(windows))]
|
||||
use libloading::os::windows as imp;
|
||||
|
||||
use crate::class_file::{ClassFlags, MethodRef};
|
||||
use crate::class_file::ClassFlags;
|
||||
use crate::class_file::resolved::MethodRef;
|
||||
use crate::class_loader::ClassLoader;
|
||||
use crate::error::VmError;
|
||||
use crate::native::r#unsafe::UnsafeSupport;
|
||||
use crate::objects::object::ReferenceKind;
|
||||
use crate::objects::object_manager::ObjectManager;
|
||||
use crate::thread::VmThread;
|
||||
use crate::value::Value;
|
||||
use crate::{MethodDescriptor, ThreadId};
|
||||
use crate::{MethodDescriptor, ThreadId, VmSymbols, os_thread_id};
|
||||
use dashmap::DashMap;
|
||||
use imp::Library;
|
||||
use log::{info, trace};
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use std::sync::atomic::AtomicU64;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::{Arc, LazyLock};
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
type NativeLibraries = Arc<RwLock<Vec<(String, Library)>>>;
|
||||
|
||||
pub static LIB_RESOLVE_COUNTS: LazyLock<DashMap<String, u32>> = LazyLock::new(DashMap::new);
|
||||
// struct AbstractObject<'a> {}
|
||||
|
||||
pub struct Vm {
|
||||
// Thread registry - maps ThreadId to VmThread
|
||||
pub threads: DashMap<ThreadId, Arc<VmThread>>,
|
||||
@ -36,6 +37,7 @@ pub struct Vm {
|
||||
pub gc: Arc<RwLock<ObjectManager>>,
|
||||
pub safent: RwLock<UnsafeSupport>,
|
||||
pub next_id: AtomicU64,
|
||||
pub phase: AtomicU64,
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
@ -43,24 +45,24 @@ impl Vm {
|
||||
pub fn new() -> Arc<Self> {
|
||||
let vm = Arc::new(Self {
|
||||
threads: DashMap::new(),
|
||||
main_thread_id: ThreadId(0),
|
||||
main_thread_id: os_thread_id().into(),
|
||||
loader: Arc::new(Mutex::from(ClassLoader::with_bimage())),
|
||||
native_methods: DashMap::new(),
|
||||
native_libraries: Arc::new(RwLock::new(Vec::new())),
|
||||
gc: Default::default(),
|
||||
safent: Default::default(),
|
||||
next_id: AtomicU64::new(0),
|
||||
phase: AtomicU64::new(Init::STARTING),
|
||||
});
|
||||
|
||||
// Create main thread
|
||||
let thread = VmThread::new(vm.clone(), None);
|
||||
let thread_id = thread.id;
|
||||
let main_thread = VmThread::new(vm.clone(), None);
|
||||
|
||||
// Store in VM
|
||||
vm.threads.insert(thread_id, thread.clone());
|
||||
vm.threads.insert(main_thread.id, main_thread.clone());
|
||||
|
||||
// Set as current thread
|
||||
VmThread::set_current(thread_id);
|
||||
// VmThread::set_current(thread_id);
|
||||
vm
|
||||
}
|
||||
|
||||
@ -76,6 +78,7 @@ impl Vm {
|
||||
gc: Default::default(),
|
||||
safent: Default::default(),
|
||||
next_id: AtomicU64::new(0),
|
||||
phase: AtomicU64::new(Init::STARTING),
|
||||
});
|
||||
|
||||
// Create main thread
|
||||
@ -119,23 +122,16 @@ impl Vm {
|
||||
|
||||
pub fn boot_strap(&self) -> Result<(), VmError> {
|
||||
let thread = self.threads.get(&self.main_thread_id).unwrap();
|
||||
let classes = vec![
|
||||
"java/lang/String",
|
||||
"java/lang/System",
|
||||
"java/lang/Class",
|
||||
"java/lang/ThreadGroup",
|
||||
"java/lang/Thread",
|
||||
"java/lang/Module",
|
||||
//unsafe internal?
|
||||
"jdk/internal/misc/UnsafeConstants",
|
||||
"java/lang/reflect/Method",
|
||||
"java/lang/ref/Finalizer",
|
||||
];
|
||||
let mut loaded = Vec::new();
|
||||
for name in classes {
|
||||
|
||||
// Load core trio first
|
||||
let core_classes = vec![VmSymbols::OBJECT, VmSymbols::STRING, VmSymbols::CLASS];
|
||||
let mut core_loaded = Vec::new();
|
||||
for name in core_classes {
|
||||
let class = thread.loader.lock().get_or_load(name, None)?;
|
||||
loaded.push(class);
|
||||
core_loaded.push(class);
|
||||
}
|
||||
|
||||
// Primitives
|
||||
let prims = vec![
|
||||
("byte", "B"),
|
||||
("char", "C"),
|
||||
@ -147,14 +143,13 @@ impl Vm {
|
||||
("boolean", "Z"),
|
||||
("void", "V"),
|
||||
];
|
||||
let thread = self.threads.get(&self.main_thread_id).unwrap();
|
||||
|
||||
let class_class = thread.loader.lock().get_or_load(VmSymbols::CLASS, None)?;
|
||||
let flags = ClassFlags::from(1041u16);
|
||||
|
||||
for prim in prims {
|
||||
let klass = self.loader.lock().primitive_class(prim.0);
|
||||
|
||||
let class_class = thread.loader.lock().get_or_load("java/lang/Class", None)?;
|
||||
let name_obj = thread.intern_string(&prim.0);
|
||||
let flags = ClassFlags::from(1041u16);
|
||||
let class_obj = self.gc.write().new_class(
|
||||
class_class.clone(),
|
||||
Some(ReferenceKind::ObjectReference(name_obj)),
|
||||
@ -163,12 +158,12 @@ impl Vm {
|
||||
true,
|
||||
None,
|
||||
);
|
||||
// klass.mirror.set(class_obj.lock().id).unwrap();
|
||||
klass.mirror.set(class_obj.lock().id).unwrap();
|
||||
|
||||
let prim_array_klass = self.loader.lock().create_array_class(klass.clone());
|
||||
let arr_name_obj = thread.intern_string(&prim_array_klass.this_class);
|
||||
let arr_class_obj = self.gc.write().new_class(
|
||||
class_class,
|
||||
class_class.clone(),
|
||||
Some(ReferenceKind::ObjectReference(arr_name_obj)),
|
||||
None,
|
||||
flags,
|
||||
@ -180,24 +175,57 @@ impl Vm {
|
||||
.set(arr_class_obj.lock().id)
|
||||
.unwrap();
|
||||
}
|
||||
self.phase.store(Init::PRIMITIVES, Ordering::Release);
|
||||
|
||||
//woops forgot to init
|
||||
// Remaining bootstrap classes
|
||||
let classes = vec![
|
||||
VmSymbols::SYSTEM,
|
||||
VmSymbols::THREAD_GROUP,
|
||||
VmSymbols::THREAD,
|
||||
VmSymbols::MODULE,
|
||||
"jdk/internal/misc/UnsafeConstants",
|
||||
"java/lang/reflect/Method",
|
||||
"java/lang/ref/Finalizer",
|
||||
];
|
||||
let mut loaded = Vec::new();
|
||||
for name in classes {
|
||||
let class = thread.get_class(name)?;
|
||||
loaded.push(class);
|
||||
}
|
||||
|
||||
// Now mirrors and init
|
||||
for class in &core_loaded {
|
||||
thread.create_mirror_class(&class)?;
|
||||
}
|
||||
for class in &loaded {
|
||||
thread.create_mirror_class(&class)?;
|
||||
}
|
||||
for class in core_loaded {
|
||||
println!("bootstrap init {}", class.this_class);
|
||||
thread.ensure_initialised(&class)?;
|
||||
}
|
||||
for class in loaded {
|
||||
println!("bootstrap init {}", class.this_class);
|
||||
thread.ensure_initialised(&class)?;
|
||||
}
|
||||
self.phase.store(Init::JAVA_CLASSES, Ordering::Release);
|
||||
|
||||
let phase1ref = MethodRef {
|
||||
class: "java/lang/System".to_string(),
|
||||
name: "initPhase1".to_string(),
|
||||
desc: MethodDescriptor::void(),
|
||||
};
|
||||
// let phase1ref = MethodRef {
|
||||
// class: "java/lang/System".to_string(),
|
||||
// name: "initPhase1".to_string(),
|
||||
// desc: MethodDescriptor::void(),
|
||||
// };
|
||||
|
||||
let phase1ref = MethodRef::from_symbols(VmSymbols::SYSTEM, "initPhase1", &vec![], None);
|
||||
self.threads
|
||||
.get(&self.main_thread_id)
|
||||
.unwrap()
|
||||
.bootstrap_mirror();
|
||||
thread.invoke(phase1ref, Vec::new())?;
|
||||
// panic!("HOLY FUCKING SHIT, DID WE PHASE 1!?");
|
||||
self.phase
|
||||
.store(Init::SYSTEM_INIT_PHASE_1, Ordering::Release);
|
||||
|
||||
self.phase.store(Init::UP, Ordering::Release);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -211,6 +239,14 @@ impl Vm {
|
||||
let thread = self.threads.get(&self.main_thread_id).unwrap().clone();
|
||||
thread.invoke_main(what)
|
||||
}
|
||||
|
||||
pub fn current_thread(&self) -> Arc<VmThread> {
|
||||
let id: ThreadId = os_thread_id().into();
|
||||
self.threads
|
||||
.get((&id).into())
|
||||
.expect(format!("Did not find thread: {:?}", id).as_str())
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY:
|
||||
@ -218,3 +254,13 @@ impl Vm {
|
||||
// - All mutable state is behind DashMap/RwLock/Mutex
|
||||
unsafe impl Send for Vm {}
|
||||
unsafe impl Sync for Vm {}
|
||||
|
||||
pub struct Init;
|
||||
|
||||
impl Init {
|
||||
pub const STARTING: u64 = 0;
|
||||
pub const PRIMITIVES: u64 = 1;
|
||||
pub const JAVA_CLASSES: u64 = 2;
|
||||
pub const SYSTEM_INIT_PHASE_1: u64 = 3;
|
||||
pub const UP: u64 = 4;
|
||||
}
|
||||
|
||||
@ -3,11 +3,8 @@ use jni::sys::{JNI_FALSE, JNI_TRUE, jboolean, jclass, jobject};
|
||||
use jni::sys::{JNIEnv, jint};
|
||||
use jni::sys::{jobjectArray, jstring};
|
||||
use log::trace;
|
||||
use roast_vm_core::class_file::FieldRef;
|
||||
use roast_vm_core::FieldType;
|
||||
use roast_vm_core::objects::ReferenceKind;
|
||||
use roast_vm_core::objects::array::ArrayReference;
|
||||
use roast_vm_core::value::Value;
|
||||
use roast_vm_core::{BaseType, FieldType};
|
||||
use std::ptr;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
|
||||
@ -69,7 +69,6 @@ pub extern "system" fn Java_org_example_MockIO_println<'local>(
|
||||
|
||||
unsafe fn get_thread(env: *mut jni::sys::JNIEnv) -> *const VmThread {
|
||||
let thread = (**env).reserved0 as *const VmThread;
|
||||
VmThread::set_current((*thread).id);
|
||||
thread
|
||||
}
|
||||
fn resolve_object(thread: &VmThread, obj: jobject) -> Option<ObjectReference> {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::get_thread;
|
||||
use jni::sys::{JNI_TRUE, JNIEnv, jclass, jint, jobject};
|
||||
use roast_vm_core::FieldType;
|
||||
use roast_vm_core::class_file::FieldRef;
|
||||
use roast_vm_core::class_file::resolved::FieldRef;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "system" fn Java_java_lang_reflect_Array_newArray(
|
||||
@ -28,11 +28,12 @@ pub unsafe extern "system" fn Java_java_lang_reflect_Array_newArray(
|
||||
.get_field(&FieldRef::new("Class", "primitive", FieldType::bool()))
|
||||
.try_into_jboolean()
|
||||
.unwrap();
|
||||
|
||||
let array_class_name = format!("[L{};", comp.this_class);
|
||||
let array_class = thread.get_class(&array_class_name).unwrap();
|
||||
let refe = if prim == JNI_TRUE {
|
||||
thread.gc.write().new_primitive_array(comp, length)
|
||||
thread.gc.write().new_primitive_array(array_class, length)
|
||||
} else {
|
||||
thread.gc.write().new_object_array(comp, length)
|
||||
thread.gc.write().new_object_array(array_class, length)
|
||||
};
|
||||
refe.id() as jobject
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use crate::get_thread;
|
||||
use jni::sys::{JNIEnv, jclass, jint, jobject, jobjectArray};
|
||||
use roast_vm_core::class_file::FieldRef;
|
||||
|
||||
use roast_vm_core::class_file::resolved::{FieldRef, MethodRef};
|
||||
use roast_vm_core::objects::array::ArrayReference;
|
||||
use roast_vm_core::value::Value;
|
||||
use roast_vm_core::{BaseType, FieldType};
|
||||
@ -89,7 +90,9 @@ pub unsafe extern "system" fn Java_jdk_internal_reflect_DirectConstructorHandleA
|
||||
let instance = thread.gc.write().new_object(klass.clone());
|
||||
values.insert(0, instance.clone().into());
|
||||
|
||||
thread.invoke(method.clone().into(), values).unwrap();
|
||||
thread
|
||||
.invoke(MethodRef::from(method).clone().into(), values)
|
||||
.unwrap();
|
||||
|
||||
instance.lock().id as jobject
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use jni::JNIEnv;
|
||||
use jni::objects::{JClass, JObject};
|
||||
use jni::sys::jobjectArray;
|
||||
use roast_vm_core::VmSymbols;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_jdk_internal_util_SystemProps_00024Raw_vmProperties<'local>(
|
||||
@ -34,7 +35,7 @@ pub extern "system" fn Java_jdk_internal_util_SystemProps_00024Raw_vmProperties<
|
||||
".",
|
||||
];
|
||||
|
||||
let string_class = env.find_class("java/lang/String").unwrap();
|
||||
let string_class = env.find_class(VmSymbols::STRING).unwrap();
|
||||
// +1 for null terminator
|
||||
let arr = env
|
||||
.new_object_array((props.len() + 1) as i32, string_class, JObject::null())
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use crate::get_thread;
|
||||
use jni::sys::{JNIEnv, jclass, jint, jlong, jobject};
|
||||
use roast_vm_core::class_file::MethodRef;
|
||||
use roast_vm_core::class_file::resolved::MethodRef;
|
||||
use roast_vm_core::value::Value;
|
||||
use roast_vm_core::{MethodDescriptor, VmThread};
|
||||
use roast_vm_core::{MethodDescriptor, VmSymbols, VmThread};
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
unsafe extern "system" fn Java_java_lang_Thread_currentThread(
|
||||
@ -30,6 +30,7 @@ unsafe extern "system" fn Java_java_lang_Thread_setPriority0(
|
||||
_this: jobject,
|
||||
priority: jint,
|
||||
) {
|
||||
// todo
|
||||
// Get the current thread and update its priority
|
||||
// let thread = &*get_thread(env);
|
||||
// Store priority in thread state (implementation depends on thread structure)
|
||||
@ -55,21 +56,17 @@ unsafe extern "system" fn Java_java_lang_Thread_start0(env: *mut JNIEnv, this: j
|
||||
vm.threads.insert(thread_id, new_thread.clone());
|
||||
|
||||
// Set as current thread for this OS thread
|
||||
VmThread::set_current(thread_id);
|
||||
// VmThread::set_current(thread_id);
|
||||
|
||||
// Call this.run()
|
||||
// let thread_class = new_thread.get_class("java/lang/Thread").unwrap();
|
||||
let run_ref = MethodRef {
|
||||
class: "java/lang/Thread".to_string(),
|
||||
name: "run".to_string(),
|
||||
desc: MethodDescriptor::void(),
|
||||
};
|
||||
let run_ref = MethodRef::from_symbols(VmSymbols::THREAD, "run", &Vec)
|
||||
|
||||
// Get the Thread object as a Value
|
||||
let thread_value = Value::Reference(Some(new_thread.gc.read().get(thread_obj_id)));
|
||||
|
||||
if let Err(e) = new_thread.invoke(run_ref, vec![thread_value]) {
|
||||
eprintln!("Thread {} died with: {:?}", thread_id.0, e);
|
||||
if let Err(e) = new_thread.invoke(run_ref.into(), vec![thread_value]) {
|
||||
eprintln!("Thread {:?} died with: {:?}", thread_id, e);
|
||||
}
|
||||
|
||||
// Cleanup: remove from VM thread registry
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user