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">
|
<profile version="1.0">
|
||||||
<option name="myName" value="Project Default" />
|
<option name="myName" value="Project Default" />
|
||||||
<inspection_tool class="IncorrectFormatting" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
<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>
|
</profile>
|
||||||
</component>
|
</component>
|
||||||
@ -21,7 +21,8 @@ roast-vm-core = { path = "crates/core" }
|
|||||||
colored = "3.0.0"
|
colored = "3.0.0"
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
cesu8 = "1.1.0"
|
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]
|
[profile.dev-opt]
|
||||||
inherits = "dev"
|
inherits = "dev"
|
||||||
opt-level = 2 # 0=none, 1=basic, 2=good, 3=aggressive
|
opt-level = 2 # 0=none, 1=basic, 2=good, 3=aggressive
|
||||||
|
|||||||
@ -19,6 +19,7 @@ colored = { workspace = true }
|
|||||||
parking_lot = { workspace = true }
|
parking_lot = { workspace = true }
|
||||||
cesu8 = { workspace = true }
|
cesu8 = { workspace = true }
|
||||||
windows = { workspace = true }
|
windows = { workspace = true }
|
||||||
|
libc = { workspace = true }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
use crate::class_file::attributes::BootstrapMethodsAttribute;
|
use crate::class_file::attributes::BootstrapMethodsAttribute;
|
||||||
use crate::class_file::{ClassFlags, ConstantPoolEntry, FieldData, MethodData};
|
use crate::class_file::{ClassFlags, ConstantPoolEntry, FieldData, MethodData};
|
||||||
use crate::error::VmError;
|
use crate::error::VmError;
|
||||||
use crate::{FieldType, MethodDescriptor};
|
use crate::{FieldType, MethodDescriptor, ThreadId};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::{Arc, OnceLock};
|
use std::sync::{Arc, OnceLock};
|
||||||
use std::thread::ThreadId;
|
|
||||||
|
|
||||||
/// JVM Spec 5.5: Initialization states for a class
|
/// JVM Spec 5.5: Initialization states for a class
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use crate::class_file::attributes::{
|
|||||||
Attribute, AttributeInfo, CodeAttribute, LineNumberTableEntry,
|
Attribute, AttributeInfo, CodeAttribute, LineNumberTableEntry,
|
||||||
};
|
};
|
||||||
use crate::class_file::constant_pool::{ConstantPoolExt, ConstantPoolOwned};
|
use crate::class_file::constant_pool::{ConstantPoolExt, ConstantPoolOwned};
|
||||||
|
use crate::class_file::resolved::{InterfaceMethodRef, MethodRef};
|
||||||
use crate::instructions::Ops;
|
use crate::instructions::Ops;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::{BaseType, FieldType, MethodDescriptor};
|
use crate::{BaseType, FieldType, MethodDescriptor};
|
||||||
@ -17,6 +18,8 @@ use std::ops::Deref;
|
|||||||
use std::str::Chars;
|
use std::str::Chars;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub type FieldDescriptor = FieldType;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, DekuRead)]
|
#[derive(Debug, PartialEq, DekuRead)]
|
||||||
#[deku(magic = b"\xCA\xFE\xBA\xBE", endian = "big")]
|
#[deku(magic = b"\xCA\xFE\xBA\xBE", endian = "big")]
|
||||||
pub struct ClassFile {
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MethodData {
|
pub struct MethodData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -669,41 +666,6 @@ pub struct MethodData {
|
|||||||
// pub method_parameters: Option<_>
|
// 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)]
|
#[derive(Debug)]
|
||||||
pub struct FieldData {
|
pub struct FieldData {
|
||||||
pub name: String,
|
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::{
|
use crate::class_file::attributes::{
|
||||||
Attribute, AttributeInfo, BootstrapMethodsAttribute, CodeAttribute, LineNumberTableAttribute,
|
Attribute, AttributeInfo, BootstrapMethodsAttribute, CodeAttribute, LineNumberTableAttribute,
|
||||||
LocalVariableTableAttribute,
|
LocalVariableTableAttribute,
|
||||||
};
|
};
|
||||||
|
use crate::class_file::resolved::{
|
||||||
|
BootstrapMethod, Dynamic, FieldRef, InterfaceMethodRef, InterfaceOrMethod, Loadable,
|
||||||
|
MethodHandleKind, MethodRef, MethodType,
|
||||||
|
};
|
||||||
use crate::class_file::{
|
use crate::class_file::{
|
||||||
ConstantClassInfo, ConstantDynamicInfo, ConstantFieldrefInfo, ConstantInterfaceMethodrefInfo,
|
ConstantClassInfo, ConstantDynamicInfo, ConstantFieldrefInfo, ConstantInterfaceMethodrefInfo,
|
||||||
ConstantInvokeDynamicInfo, ConstantMethodHandleInfo, ConstantMethodTypeInfo,
|
ConstantInvokeDynamicInfo, ConstantMethodHandleInfo, ConstantMethodTypeInfo,
|
||||||
ConstantMethodrefInfo, ConstantModuleInfo, ConstantNameAndTypeInfo, ConstantPackageInfo,
|
ConstantMethodrefInfo, ConstantModuleInfo, ConstantNameAndTypeInfo, ConstantPackageInfo,
|
||||||
ConstantPoolEntry, ConstantStringInfo, ConstantUtf8Info, DescParseError, FieldInfo, FieldRef,
|
ConstantPoolEntry, ConstantStringInfo, ConstantUtf8Info, DescParseError, FieldDescriptor,
|
||||||
MethodRef,
|
FieldInfo,
|
||||||
};
|
};
|
||||||
use crate::error::VmError;
|
use crate::error::VmError;
|
||||||
use crate::{FieldType, MethodDescriptor, pool_get_impl};
|
use crate::{FieldType, MethodDescriptor, pool_get_impl};
|
||||||
use cesu8::{Cesu8DecodingError, from_java_cesu8};
|
use cesu8::{Cesu8DecodingError, from_java_cesu8};
|
||||||
use deku::DekuContainerRead;
|
use deku::DekuContainerRead;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub type ConstantPoolSlice = [ConstantPoolEntry];
|
pub type ConstantPoolSlice = [ConstantPoolEntry];
|
||||||
pub type ConstantPoolOwned = Vec<ConstantPoolEntry>;
|
pub type ConstantPoolOwned = Vec<ConstantPoolEntry>;
|
||||||
@ -99,14 +105,17 @@ pub trait ConstantPoolExt: ConstantPoolGet {
|
|||||||
Ok(MethodRef { class, name, desc })
|
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 mr = self.get_interface_method_ref(index)?;
|
||||||
let class = self.resolve_class_name(mr.class_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_and_type = self.get_name_and_type_info(mr.name_and_type_index)?;
|
||||||
let name = self.get_string(name_and_type.name_index)?;
|
let name = self.get_string(name_and_type.name_index)?;
|
||||||
let desc = self.get_string(name_and_type.descriptor_index)?;
|
let desc = self.get_string(name_and_type.descriptor_index)?;
|
||||||
let desc = MethodDescriptor::parse(&desc)?;
|
let desc = MethodDescriptor::parse(&desc)?;
|
||||||
Ok(MethodRef { class, name, desc })
|
Ok(InterfaceMethodRef { class, name, desc })
|
||||||
}
|
}
|
||||||
|
|
||||||
/*// (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> {
|
fn parse_attribute(&self, a: AttributeInfo) -> Result<Attribute, VmError> {
|
||||||
let name = self.get_string(a.attribute_name_index)?;
|
let name = self.get_string(a.attribute_name_index)?;
|
||||||
// trace!("Parsing attribute with name: {}", name);
|
// trace!("Parsing attribute with name: {}", name);
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use crate::class_file::{
|
|||||||
ClassFile, ClassFlags, Constant, FieldData, FieldFlags, MethodData, MethodFlags,
|
ClassFile, ClassFlags, Constant, FieldData, FieldFlags, MethodData, MethodFlags,
|
||||||
};
|
};
|
||||||
use crate::error::VmError;
|
use crate::error::VmError;
|
||||||
use crate::{FieldType, MethodDescriptor};
|
use crate::{FieldType, MethodDescriptor, VmSymbols};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use deku::DekuContainerRead;
|
use deku::DekuContainerRead;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
@ -250,8 +250,8 @@ impl ClassLoader {
|
|||||||
name
|
name
|
||||||
};
|
};
|
||||||
let super_class = {
|
let super_class = {
|
||||||
if this_class.eq("java/lang/Object") {
|
if this_class.eq(VmSymbols::OBJECT) {
|
||||||
debug_assert_eq!(this_class, "java/lang/Object");
|
debug_assert_eq!(this_class, VmSymbols::OBJECT);
|
||||||
debug_assert_eq!(class_file.super_class, 0u16);
|
debug_assert_eq!(class_file.super_class, 0u16);
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@ -424,11 +424,10 @@ impl ClassLoader {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
pub fn create_array_class(&mut self, component: Arc<RuntimeClass>) -> Arc<RuntimeClass> {
|
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(VmSymbols::OBJECT, None).unwrap();
|
||||||
let object_class: Arc<RuntimeClass> = self.get_or_load("java/lang/Object", None).unwrap();
|
let cloneable: Arc<RuntimeClass> = self.get_or_load(VmSymbols::CLONEABLE, None).unwrap();
|
||||||
let cloneable: Arc<RuntimeClass> = self.get_or_load("java/lang/Cloneable", None).unwrap();
|
|
||||||
let serializable: Arc<RuntimeClass> =
|
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() {
|
let name = match component.this_class.as_str() {
|
||||||
"byte" => "[B".to_string(),
|
"byte" => "[B".to_string(),
|
||||||
"char" => "[C".to_string(),
|
"char" => "[C".to_string(),
|
||||||
|
|||||||
@ -7,7 +7,7 @@ pub enum VmError {
|
|||||||
ConstantPoolError(String),
|
ConstantPoolError(String),
|
||||||
StackError(String),
|
StackError(String),
|
||||||
InvariantError(String),
|
InvariantError(String),
|
||||||
Debug(&'static str),
|
Debug(String),
|
||||||
DekuError(DekuError),
|
DekuError(DekuError),
|
||||||
LoaderError(String),
|
LoaderError(String),
|
||||||
ExecutionError,
|
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 {
|
impl From<ConstantPoolError> for VmError {
|
||||||
fn from(value: ConstantPoolError) -> Self {
|
fn from(value: ConstantPoolError) -> Self {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::class::RuntimeClass;
|
use crate::class::RuntimeClass;
|
||||||
use crate::class_file::attributes::{CodeAttribute, LineNumberTableEntry};
|
use crate::class_file::attributes::{CodeAttribute, LineNumberTableEntry};
|
||||||
use crate::class_file::constant_pool::{ConstantPoolError, ConstantPoolExt, ConstantPoolGet};
|
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::error::{StackTraceElement, VmError};
|
||||||
use crate::instructions::{Ops, WideData};
|
use crate::instructions::{Ops, WideData};
|
||||||
use crate::objects::ReferenceKind;
|
use crate::objects::ReferenceKind;
|
||||||
@ -10,17 +10,21 @@ use crate::prim::*;
|
|||||||
use crate::value::{Primitive, Value};
|
use crate::value::{Primitive, Value};
|
||||||
use crate::vm::Vm;
|
use crate::vm::Vm;
|
||||||
use crate::{
|
use crate::{
|
||||||
BaseType, FieldType, MethodDescriptor, VmThread, array_store, array_store_cast, binary_op,
|
BaseType, FieldType, VmSymbols, 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,
|
convert_float_to_int, convert_int_narrow, convert_simple, error, float_cmp, if_int_cmp,
|
||||||
int_div_rem, load, shift_op, store, unary_op,
|
if_int_zero, int_div_rem, jsr292, load, shift_op, store, unary_op,
|
||||||
};
|
};
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
use deku::DekuContainerRead;
|
use deku::DekuContainerRead;
|
||||||
use log::{trace, warn};
|
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::local_vars::LocalVariables;
|
||||||
use crate::frame::operand_stack::OperandStack;
|
use crate::frame::operand_stack::OperandStack;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::process::id;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Represents a JVM stack frame for method execution.
|
/// Represents a JVM stack frame for method execution.
|
||||||
@ -47,7 +51,7 @@ pub struct Frame {
|
|||||||
bytecode: Bytecode,
|
bytecode: Bytecode,
|
||||||
|
|
||||||
/// The thread executing this frame
|
/// The thread executing this frame
|
||||||
thread: Arc<VmThread>,
|
pub(crate) thread: Arc<VmThread>,
|
||||||
// The mod being invoked
|
// The mod being invoked
|
||||||
pub method_ref: MethodRef,
|
pub method_ref: MethodRef,
|
||||||
|
|
||||||
@ -114,7 +118,7 @@ impl Frame {
|
|||||||
line_number_table: Option<Vec<LineNumberTableEntry>>,
|
line_number_table: Option<Vec<LineNumberTableEntry>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Get current thread from thread-local storage
|
// 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_stack = code_attr.max_stack as usize;
|
||||||
let max_local = code_attr.max_locals as usize;
|
let max_local = code_attr.max_locals as usize;
|
||||||
@ -1124,7 +1128,7 @@ impl Frame {
|
|||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.thread
|
.thread
|
||||||
.invoke_virtual(method_ref, class.clone(), args)?;
|
.invoke_virtual(method_ref.into(), class.clone(), args)?;
|
||||||
if let Some(val) = result {
|
if let Some(val) = result {
|
||||||
self.push(val)
|
self.push(val)
|
||||||
}
|
}
|
||||||
@ -1134,17 +1138,14 @@ impl Frame {
|
|||||||
|
|
||||||
Ops::invokespecial(index) => {
|
Ops::invokespecial(index) => {
|
||||||
// todo verify change to interface method ref
|
// todo verify change to interface method ref
|
||||||
let method_ref = self
|
let either = self.pool.resolve_either_ref(index)?;
|
||||||
.pool
|
|
||||||
.resolve_method_ref(index)
|
|
||||||
.or_else(|e| self.pool.resolve_interface_method_ref(index).map_err(|_| e))?;
|
|
||||||
|
|
||||||
// the 1 represents the receiver
|
// the 1 represents the receiver
|
||||||
// arg width??????
|
// 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 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 {
|
if let Some(val) = result {
|
||||||
self.push(val)
|
self.push(val)
|
||||||
}
|
}
|
||||||
@ -1153,17 +1154,14 @@ impl Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ops::invokestatic(index) => {
|
Ops::invokestatic(index) => {
|
||||||
let method_ref = self
|
let either = self.pool.resolve_either_ref(index)?;
|
||||||
.pool
|
let class = self.thread.get_class(&either.class())?;
|
||||||
.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)?;
|
|
||||||
self.thread.ensure_initialised(&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 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 {
|
if let Some(val) = result {
|
||||||
self.push(val)
|
self.push(val)
|
||||||
}
|
}
|
||||||
@ -1171,10 +1169,10 @@ impl Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ops::invokeinterface(index, _count, _zero) => {
|
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
|
// 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 args = self.stack.pop_n(args_count)?;
|
||||||
let refe = args
|
let refe = args
|
||||||
.first()
|
.first()
|
||||||
@ -1183,9 +1181,9 @@ impl Frame {
|
|||||||
.expect("Must be ref");
|
.expect("Must be ref");
|
||||||
let class = refe.class();
|
let class = refe.class();
|
||||||
|
|
||||||
let result = self
|
let result =
|
||||||
.thread
|
self.thread
|
||||||
.invoke_virtual(method_ref, class.clone(), args)?;
|
.invoke_virtual(interface_method_ref.into(), class.clone(), args)?;
|
||||||
if let Some(val) = result {
|
if let Some(val) = result {
|
||||||
self.push(val)
|
self.push(val)
|
||||||
}
|
}
|
||||||
@ -1195,9 +1193,9 @@ impl Frame {
|
|||||||
|
|
||||||
Ops::invokedynamic(index, _b) => {
|
Ops::invokedynamic(index, _b) => {
|
||||||
debug_assert_eq!(_b, 0u16);
|
debug_assert_eq!(_b, 0u16);
|
||||||
|
/*
|
||||||
|
|
||||||
// Check if already resolved (you'll want to cache this)
|
// TODO: Cache resolved CallSites
|
||||||
// For now, let's just resolve it every time
|
|
||||||
|
|
||||||
let dyninfo = self.pool.get_invoke_dynamic_info(index)?;
|
let dyninfo = self.pool.get_invoke_dynamic_info(index)?;
|
||||||
let bootstrap_attr = self.class.bootstrap_attribute.as_ref().unwrap();
|
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)
|
let call_site_method_type = MethodDescriptor::parse(&call_site_desc)
|
||||||
.map_err(ConstantPoolError::DescriptorParseError)?;
|
.map_err(ConstantPoolError::DescriptorParseError)?;
|
||||||
|
|
||||||
// The bootstrap method handle reference
|
// 1. Lookup
|
||||||
let bsm_handle = self.pool.get_method_handle_info(bsm.bootstrap_method_ref)?;
|
let lookup = {
|
||||||
let kind = bsm_handle.reference_kind;
|
let refe = MethodRef {
|
||||||
let heck = self.pool.resolve_method_ref(bsm_handle.reference_index)?;
|
class: "java/lang/invoke/MethodHandles".to_string(),
|
||||||
println!("Bootstrap method handle: kind={:?}, ref={:?}", kind, heck);
|
name: "lookup".to_string(),
|
||||||
// Resolve static arguments from constant pool
|
desc: MethodDescriptor::parse("()Ljava/lang/invoke/MethodHandles$Lookup;")
|
||||||
let static_args: Vec<Value> = Vec::new();
|
.unwrap(),
|
||||||
for arg_index in &bsm.bootstrap_arguments {
|
};
|
||||||
let info = self.pool.get_string_info(*arg_index)?;
|
self.thread.invoke(refe, vec![])?.unwrap()
|
||||||
let string = self.pool.get_string(info.string_index)?;
|
};
|
||||||
println!("{}", string);
|
|
||||||
// static_args.push(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
let class_objects = call_site_method_type
|
// 2. Call site name as String
|
||||||
.parameters
|
let name_string = self.thread.intern_string(&call_site_name);
|
||||||
.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::<Result<Vec<Option<ReferenceKind>>, VmError>>()?;
|
|
||||||
let class_array_class = self.thread.get_class("[Ljava/lang/Class;")?;
|
|
||||||
|
|
||||||
let ptypes = self
|
// 3. Call site MethodType
|
||||||
|
let call_site_mt: Value = {
|
||||||
|
let class_objects: Vec<Option<ReferenceKind>> = 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::<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 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::parse(
|
||||||
|
"(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
};
|
||||||
|
self.thread
|
||||||
|
.invoke(mt_ref, vec![rtype, ptypes.into()])?
|
||||||
|
.unwrap()
|
||||||
|
.into()
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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
|
||||||
|
.gc
|
||||||
|
.read()
|
||||||
|
.get(*bsm_class.mirror.get().unwrap())
|
||||||
|
.into();
|
||||||
|
|
||||||
|
let bsm_name: Value = self.thread.intern_string(&method_ref.name).into();
|
||||||
|
|
||||||
|
// 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>>()?;
|
||||||
|
|
||||||
|
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 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
|
.thread
|
||||||
.gc
|
.gc
|
||||||
.write()
|
.write()
|
||||||
.new_object_array_from(class_array_class, class_objects.into_boxed_slice());
|
.new_object_array_from(obj_array_class, boxed_args.into_boxed_slice());
|
||||||
let pval: Value = ptypes.clone().into();
|
|
||||||
|
|
||||||
println!("==================");
|
// 7. Invoke bootstrap: bsm.invokeWithArguments(Object[])
|
||||||
println!("{}", pval);
|
let invoke_ref = MethodRef {
|
||||||
println!("==================");
|
class: "java/lang/invoke/MethodHandle".to_string(),
|
||||||
let return_type = call_site_method_type.return_type.unwrap();
|
name: "invokeWithArguments".to_string(),
|
||||||
let ret = return_type.as_class_name();
|
desc: MethodDescriptor::parse("([Ljava/lang/Object;)Ljava/lang/Object;")
|
||||||
let ret_klass = self.thread.get_class(&ret)?;
|
.unwrap(),
|
||||||
let rtype = self.thread.gc.read().get(*ret_klass.mirror.get().unwrap());
|
|
||||||
let mt_cn_ref = MethodRef {
|
|
||||||
class: "java/lang/invoke/MethodType".to_string(),
|
|
||||||
name: "methodType".to_string(),
|
|
||||||
desc: MethodDescriptor::method_type(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mt = self
|
let call_site = self
|
||||||
.thread
|
.thread
|
||||||
.invoke(mt_cn_ref, vec![rtype.into(), ptypes.into()])?
|
.invoke_virtual(invoke_ref, bsm_handle, vec![args_array.into()])?
|
||||||
.unwrap();
|
.ok_or_else(|| VmError::InvariantError("Bootstrap returned null".into()))?;
|
||||||
|
|
||||||
// Pop runtime arguments from stack (based on call site descriptor)
|
// 8. Get target handle: callSite.getTarget()
|
||||||
let runtime_arg_count = call_site_method_type.parameters.len();
|
let get_target = MethodRef {
|
||||||
let runtime_args = self.stack.pop_n(runtime_arg_count)?;
|
class: "java/lang/invoke/CallSite".to_string(),
|
||||||
|
name: "getTarget".to_string(),
|
||||||
// Now we need to:
|
desc: MethodDescriptor::parse("()Ljava/lang/invoke/MethodHandle;").unwrap(),
|
||||||
// 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
|
|
||||||
|
|
||||||
//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 target_handle = self
|
||||||
|
.thread
|
||||||
|
.invoke_virtual(get_target, call_site, vec![])?
|
||||||
|
.ok_or_else(|| VmError::InvariantError("getTarget returned null".into()))?;
|
||||||
|
|
||||||
let lookup = self.thread.invoke(refe, Vec::new())?.unwrap();
|
// 9. Pop runtime arguments
|
||||||
// Full implementation requires MethodHandle invocation support
|
let runtime_arg_count = call_site_method_type.parameters.len();
|
||||||
println!("{}", lookup);
|
let runtime_args: Vec<Value> = self.stack.pop_n(runtime_arg_count)?;
|
||||||
todo!(
|
|
||||||
// "Full invokedynamic - bootstrap: {}::{}",
|
// 10. Invoke target with runtime args
|
||||||
// bsm_handle.class_name,
|
let boxed_runtime: Vec<Option<ReferenceKind>> = runtime_args
|
||||||
// bsm_handle.method_name
|
.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> {
|
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())?;
|
let thing = self.pool.get_constant(index.to_owned())?;
|
||||||
trace!("\tLoading constant: {}", thing);
|
trace!("\tLoading constant: {}", thing);
|
||||||
let resolved = match thing {
|
let resolved = match thing {
|
||||||
@ -1583,6 +1801,90 @@ impl Frame {
|
|||||||
self.push(resolved);
|
self.push(resolved);
|
||||||
Ok(ExecutionResult::Continue)
|
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)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
//! - [`MethodDescriptor`] - Method signature information
|
//! - [`MethodDescriptor`] - Method signature information
|
||||||
//! - [`FieldType`] - Field type information
|
//! - [`FieldType`] - Field type information
|
||||||
|
|
||||||
use crate::class_file::MethodRef;
|
use crate::class_file::resolved::MethodRef;
|
||||||
pub use crate::thread::VmThread;
|
pub use crate::thread::VmThread;
|
||||||
use deku_derive::{DekuRead, DekuWrite};
|
use deku_derive::{DekuRead, DekuWrite};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -24,6 +24,7 @@ use std::cell::RefCell;
|
|||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use value::Value;
|
use value::Value;
|
||||||
|
use windows::Win32::System::Threading::GetCurrentThreadId;
|
||||||
|
|
||||||
mod bimage;
|
mod bimage;
|
||||||
mod class;
|
mod class;
|
||||||
@ -32,15 +33,18 @@ mod class_loader;
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
mod frame;
|
mod frame;
|
||||||
mod instructions;
|
mod instructions;
|
||||||
|
mod jsr292;
|
||||||
mod macros;
|
mod macros;
|
||||||
pub mod native;
|
pub mod native;
|
||||||
pub mod objects;
|
pub mod objects;
|
||||||
mod prim;
|
mod prim;
|
||||||
mod rng;
|
mod rng;
|
||||||
|
mod symbols;
|
||||||
mod thread;
|
mod thread;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
|
|
||||||
|
pub use symbols::vm_symbols as VmSymbols;
|
||||||
/// Unique identifier for a VM thread.
|
/// Unique identifier for a VM thread.
|
||||||
///
|
///
|
||||||
/// Each VmThread is assigned a unique ThreadId when created. This ID is used to:
|
/// 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
|
/// - Support future multi-threading when Java threads map to OS threads
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
pub struct ThreadId(pub u64);
|
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.
|
/// Represents JVM primitive types used in field and method descriptors.
|
||||||
///
|
///
|
||||||
@ -138,7 +147,24 @@ pub struct MethodDescriptor {
|
|||||||
// none = void/v
|
// none = void/v
|
||||||
pub return_type: Option<FieldType>,
|
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 {
|
impl MethodDescriptor {
|
||||||
pub fn void() -> Self {
|
pub fn void() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -146,14 +172,12 @@ impl MethodDescriptor {
|
|||||||
return_type: None,
|
return_type: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn method_type() -> Self {
|
pub fn from_symbols(parameters: &[&str], return_type: Option<&str>) -> Self {
|
||||||
MethodDescriptor::parse(
|
let ret = return_type.unwrap_or("V");
|
||||||
"(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;",
|
let return_type = sanitise(ret);
|
||||||
)
|
let parameters = parameters.iter().map(|p| sanitise(p)).join("");
|
||||||
.unwrap()
|
let desc: String = format!("({parameters}){return_type}");
|
||||||
}
|
MethodDescriptor::parse(&desc).unwrap()
|
||||||
pub fn lookup() -> Self {
|
|
||||||
MethodDescriptor::parse("()Ljava/lang/invoke/MethodHandles$Lookup;").unwrap()
|
|
||||||
}
|
}
|
||||||
pub fn psvmsa() -> Self {
|
pub fn psvmsa() -> Self {
|
||||||
MethodDescriptor::parse("([Ljava/lang/String;)V").unwrap()
|
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 {
|
impl Display for BaseType {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
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 {
|
pub fn stack_used() -> usize {
|
||||||
static STACK_BASE: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
|
static STACK_BASE: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
|
||||||
let local = 0u8;
|
let local = 0u8;
|
||||||
@ -233,10 +247,23 @@ pub enum FieldType {
|
|||||||
ArrayType(Box<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 {
|
impl FieldType {
|
||||||
pub fn bool() -> Self {
|
pub fn bool() -> Self {
|
||||||
Self::Base(BaseType::Boolean)
|
Self::Base(BaseType::Boolean)
|
||||||
}
|
}
|
||||||
|
pub fn from_symbols(class_name: &str) -> Self {
|
||||||
|
Self::parse(&sanitise(class_name)).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FieldType {
|
impl FieldType {
|
||||||
@ -336,3 +363,13 @@ fn set_last_native(name: &str) {
|
|||||||
pub fn get_last_native() -> String {
|
pub fn get_last_native() -> String {
|
||||||
LAST_NATIVE_SYMBOL.with(|cell| cell.borrow().clone())
|
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)
|
Ok(ExecutionResult::Continue)
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! location {
|
||||||
|
() => {
|
||||||
|
format!("{}:{}:{}", file!(), line!(), column!())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -17,13 +17,13 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run() {
|
fn run() {
|
||||||
env_logger::Builder::from_default_env()
|
// env_logger::Builder::from_default_env()
|
||||||
.filter_level(LevelFilter::Trace)
|
// .filter_level(LevelFilter::Trace)
|
||||||
.filter_module("deku", LevelFilter::Warn)
|
// .filter_module("deku", LevelFilter::Warn)
|
||||||
.filter_module("roast_vm_core::class_file::class_file", LevelFilter::Info)
|
// .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::class_file::attributes", LevelFilter::Info)
|
||||||
.filter_module("roast_vm_core::instructions", LevelFilter::Info)
|
// .filter_module("roast_vm_core::instructions", LevelFilter::Info)
|
||||||
.init();
|
// .init();
|
||||||
stack_used();
|
stack_used();
|
||||||
let vm = Vm::new();
|
let vm = Vm::new();
|
||||||
fetch_libs(&vm);
|
fetch_libs(&vm);
|
||||||
|
|||||||
@ -3,13 +3,14 @@
|
|||||||
#![feature(c_variadic)]
|
#![feature(c_variadic)]
|
||||||
#![allow(unsafe_op_in_unsafe_fn)]
|
#![allow(unsafe_op_in_unsafe_fn)]
|
||||||
use crate::class::RuntimeClass;
|
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::array::ArrayReference;
|
||||||
use crate::objects::object::{ObjectReference, ReferenceKind};
|
use crate::objects::object::{ObjectReference, ReferenceKind};
|
||||||
use crate::prim::jboolean;
|
use crate::prim::jboolean;
|
||||||
use crate::thread::VmThread;
|
use crate::thread::VmThread;
|
||||||
use crate::value::{Primitive, Value};
|
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::*;
|
||||||
use jni::sys::{JNIEnv, jstring};
|
use jni::sys::{JNIEnv, jstring};
|
||||||
use jni::sys::{JNINativeInterface_, jclass, jint, jobject};
|
use jni::sys::{JNINativeInterface_, jclass, jint, jobject};
|
||||||
@ -321,7 +322,7 @@ unsafe extern "system" fn get_string_utfchars(
|
|||||||
|
|
||||||
let obj = obj_ref.lock();
|
let obj = obj_ref.lock();
|
||||||
let field_ref = FieldRef {
|
let field_ref = FieldRef {
|
||||||
class: "java/lang/String".to_string(),
|
class: VmSymbols::STRING.to_string(),
|
||||||
name: "value".to_string(),
|
name: "value".to_string(),
|
||||||
desc: FieldType::ArrayType(Box::new(FieldType::Base(BaseType::Byte))),
|
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 {
|
let str_ref = if intern {
|
||||||
thread.intern_string(str)
|
thread.intern_string(str)
|
||||||
} else {
|
} 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();
|
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();
|
return ptr::null_mut();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use crate::class::RuntimeClass;
|
|||||||
use crate::error::VmError;
|
use crate::error::VmError;
|
||||||
use crate::objects::object::{Reference, ReferenceKind};
|
use crate::objects::object::{Reference, ReferenceKind};
|
||||||
use crate::prim::Primitive;
|
use crate::prim::Primitive;
|
||||||
|
use crate::value::ClassName;
|
||||||
use jni::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort};
|
use jni::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
@ -90,6 +91,12 @@ pub struct Array<T: ArrayValue> {
|
|||||||
pub backing: Box<[T]>,
|
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>
|
impl<T> Array<T>
|
||||||
where
|
where
|
||||||
T: ArrayValue + Clone + Default,
|
T: ArrayValue + Clone + Default,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
|
use crate::VmSymbols;
|
||||||
use crate::class::RuntimeClass;
|
use crate::class::RuntimeClass;
|
||||||
use crate::class_file::FieldRef;
|
use crate::class_file::resolved::FieldRef;
|
||||||
use crate::error::VmError;
|
use crate::error::VmError;
|
||||||
use crate::objects::array::{ArrayReference, ObjectArrayReference, PrimitiveArrayReference};
|
use crate::objects::array::{ArrayReference, ObjectArrayReference, PrimitiveArrayReference};
|
||||||
use crate::prim::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort};
|
use crate::prim::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort};
|
||||||
@ -46,7 +47,7 @@ impl Object {
|
|||||||
|
|
||||||
impl Display for Object {
|
impl Display for Object {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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)
|
write!(f, "Object[id={}, class={}]", self.id, self.class.this_class)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,7 +122,7 @@ impl Display for ReferenceKind {
|
|||||||
let id = match self {
|
let id = match self {
|
||||||
ReferenceKind::ObjectReference(x) => unsafe {
|
ReferenceKind::ObjectReference(x) => unsafe {
|
||||||
let guard = x.make_guard_unchecked();
|
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 Some(field) = guard.fields.get("value")
|
||||||
&& let Value::Reference(Some(ReferenceKind::ArrayReference(
|
&& let Value::Reference(Some(ReferenceKind::ArrayReference(
|
||||||
ArrayReference::Byte(actual),
|
ArrayReference::Byte(actual),
|
||||||
|
|||||||
@ -7,7 +7,7 @@ use crate::objects::object::{
|
|||||||
Object, ObjectReference, Reference, ReferenceKind, string_from_bytes,
|
Object, ObjectReference, Reference, ReferenceKind, string_from_bytes,
|
||||||
};
|
};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::{BaseType, ThreadId};
|
use crate::{BaseType, ThreadId, VmSymbols};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use jni::sys::{jint, jlong};
|
use jni::sys::{jint, jlong};
|
||||||
use parking_lot::{Condvar, Mutex};
|
use parking_lot::{Condvar, Mutex};
|
||||||
@ -403,7 +403,7 @@ impl ObjectManager {
|
|||||||
ReferenceKind::ArrayReference(arr) => self.clone_array(arr),
|
ReferenceKind::ArrayReference(arr) => self.clone_array(arr),
|
||||||
ReferenceKind::ObjectReference(obj) => {
|
ReferenceKind::ObjectReference(obj) => {
|
||||||
let class = obj.lock().class.clone();
|
let class = obj.lock().class.clone();
|
||||||
if !class.implements("java/lang/Cloneable") {
|
if !class.implements(VmSymbols::CLONEABLE) {
|
||||||
return Err(VmError::InvariantError("CloneNotSupported".to_string()));
|
return Err(VmError::InvariantError("CloneNotSupported".to_string()));
|
||||||
}
|
}
|
||||||
self.clone_instance(obj)
|
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::{ClassRef, InitState, RuntimeClass};
|
||||||
use crate::class_file::{MethodData, MethodRef};
|
use crate::class_file::MethodData;
|
||||||
use crate::class_loader::{ClassLoader, LoaderRef};
|
use crate::class_loader::{ClassLoader, LoaderRef};
|
||||||
use crate::error::VmError;
|
use crate::error::VmError;
|
||||||
use crate::frame::Frame;
|
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::{ObjectReference, ReferenceKind};
|
||||||
use crate::objects::object_manager::ObjectManager;
|
use crate::objects::object_manager::ObjectManager;
|
||||||
use crate::value::{Primitive, Value};
|
use crate::value::{Primitive, Value};
|
||||||
use crate::vm::Vm;
|
use crate::vm::{Init, Vm};
|
||||||
use crate::{
|
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 jni::sys::{JNIEnv, jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jobject, jshort};
|
||||||
use libffi::middle::*;
|
use libffi::middle::*;
|
||||||
@ -22,7 +24,7 @@ use std::collections::VecDeque;
|
|||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::{Arc, OnceLock};
|
use std::sync::{Arc, OnceLock};
|
||||||
|
|
||||||
use std::thread;
|
use crate::class_file::resolved::{InterfaceOrMethod, MethodRef};
|
||||||
|
|
||||||
static INIT_LOGGER: Once = Once::new();
|
static INIT_LOGGER: Once = Once::new();
|
||||||
type MethodCallResult = Result<Option<Value>, VmError>;
|
type MethodCallResult = Result<Option<Value>, VmError>;
|
||||||
@ -48,7 +50,8 @@ pub struct VmThread {
|
|||||||
|
|
||||||
impl VmThread {
|
impl VmThread {
|
||||||
pub fn new(vm: Arc<Vm>, loader: Option<LoaderRef>) -> Arc<Self> {
|
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 loader = loader.unwrap_or(vm.loader.clone());
|
||||||
let gc = vm.gc.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 {
|
pub fn current_id() -> ThreadId {
|
||||||
CURRENT_THREAD_ID.with(|cell| cell.borrow().expect("No current thread set"))
|
CURRENT_THREAD_ID.with(|cell| cell.borrow().expect("No current thread set"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set current thread ID for this OS thread
|
/// Set current thread ID for this OS thread
|
||||||
pub fn set_current(id: ThreadId) {
|
pub fn set_current(id: ThreadId) {
|
||||||
CURRENT_THREAD_ID.with(|cell| {
|
CURRENT_THREAD_ID.set(Some(id));
|
||||||
*cell.borrow_mut() = 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> {
|
pub fn current(vm: &Arc<Vm>) -> Arc<VmThread> {
|
||||||
let id = Self::current_id();
|
let id = Self::current_id();
|
||||||
vm.threads.get(&id).unwrap().clone()
|
vm.threads.get(&id).unwrap().clone()
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/*/// Get or resolve a class, ensuring it and its dependencies are initialised.
|
/*/// Get or resolve a class, ensuring it and its dependencies are initialised.
|
||||||
/// Follows JVM Spec 5.5 for recursive initialisation handling.
|
/// 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> {
|
pub fn get_class(&self, what: &str) -> Result<Arc<RuntimeClass>, VmError> {
|
||||||
let class = self.loader.lock().get_or_load(what, None)?;
|
let class = self.loader.lock().get_or_load(what, None)?;
|
||||||
self.create_mirror_class(&class)?;
|
if self.vm.phase.load(Ordering::Acquire) >= Init::PRIMITIVES {
|
||||||
|
self.create_mirror_class(&class)?;
|
||||||
|
}
|
||||||
Ok(class)
|
Ok(class)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a class following JVM Spec 5.5.
|
/// Initialize a class following JVM Spec 5.5.
|
||||||
/// Handles recursive initialization by tracking which thread is initializing.
|
/// Handles recursive initialization by tracking which thread is initializing.
|
||||||
pub fn init(&self, class: Arc<RuntimeClass>) -> Result<(), VmError> {
|
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
|
// Check and update initialization state
|
||||||
{
|
{
|
||||||
@ -195,7 +199,7 @@ impl VmThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensure_initialised(&self, class: &Arc<RuntimeClass>) -> Result<(), VmError> {
|
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();
|
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
|
/// 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) {
|
if class.mirror.get().is_some() || class.mirror_in_progress.swap(true, Ordering::SeqCst) {
|
||||||
return Ok(()); // already has a mirror
|
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)
|
Arc::clone(class)
|
||||||
} else {
|
} 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 string = self.intern_string(&class.this_class);
|
||||||
let component_type = if (class.this_class.starts_with("[")) {
|
let component_type = if (class.this_class.starts_with("[")) {
|
||||||
@ -295,17 +300,18 @@ impl VmThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn invoke_main(&self, what: &str) -> Result<(), VmError> {
|
pub fn invoke_main(&self, what: &str) -> Result<(), VmError> {
|
||||||
let method_ref = MethodRef {
|
let method_ref = MethodRef::from_symbols(what, "main", &[], None);
|
||||||
class: what.to_string(),
|
|
||||||
name: "main".to_string(),
|
|
||||||
desc: MethodDescriptor::psvm(),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.invoke(method_ref, Vec::new())?;
|
self.invoke(method_ref, Vec::new())?;
|
||||||
Ok(())
|
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 {
|
if self.gc.read().objects.len() > 2350 {
|
||||||
INIT_LOGGER.call_once(|| {
|
INIT_LOGGER.call_once(|| {
|
||||||
env_logger::Builder::from_default_env()
|
env_logger::Builder::from_default_env()
|
||||||
@ -318,8 +324,8 @@ impl VmThread {
|
|||||||
});
|
});
|
||||||
// println!("heap length {}", self.gc.read().objects.len())
|
// println!("heap length {}", self.gc.read().objects.len())
|
||||||
}
|
}
|
||||||
let class = self.get_class(&method_reference.class)?;
|
let class = self.get_class(&either.class())?;
|
||||||
let method = class.find_method(&method_reference.name, &method_reference.desc)?;
|
let method = class.find_method(&either.name(), &either.desc())?;
|
||||||
let class = self.loader.lock().get_or_load(&*method.class, None)?;
|
let class = self.loader.lock().get_or_load(&*method.class, None)?;
|
||||||
|
|
||||||
self.execute_method(&class, &method, args)
|
self.execute_method(&class, &method, args)
|
||||||
@ -327,11 +333,11 @@ impl VmThread {
|
|||||||
|
|
||||||
pub fn invoke_virtual(
|
pub fn invoke_virtual(
|
||||||
&self,
|
&self,
|
||||||
method_reference: MethodRef,
|
method_reference: InterfaceOrMethod,
|
||||||
class: Arc<RuntimeClass>,
|
class: Arc<RuntimeClass>,
|
||||||
args: Vec<Value>,
|
args: Vec<Value>,
|
||||||
) -> MethodCallResult {
|
) -> 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)?;
|
let class = self.loader.lock().get_or_load(&*method.class, None)?;
|
||||||
self.execute_method(&class, &method, args)
|
self.execute_method(&class, &method, args)
|
||||||
@ -340,11 +346,11 @@ impl VmThread {
|
|||||||
pub fn invoke_native(&self, method: &MethodRef, args: Vec<Value>) -> MethodCallResult {
|
pub fn invoke_native(&self, method: &MethodRef, args: Vec<Value>) -> MethodCallResult {
|
||||||
let symbol_name = generate_jni_method_name(method, false);
|
let symbol_name = generate_jni_method_name(method, false);
|
||||||
|
|
||||||
if symbol_name.contains("Java_java_lang_reflect_Array_newArray") {
|
// if symbol_name.contains("Java_java_lang_reflect_Array_newArray") {
|
||||||
return Err(VmError::Debug(
|
// return Err(VmError::Debug(
|
||||||
"RoastVM specific implementation required for Java_java_lang_reflect_Array_newArray",
|
// "RoastVM specific implementation required for Java_java_lang_reflect_Array_newArray",
|
||||||
));
|
// ));
|
||||||
}
|
// }
|
||||||
|
|
||||||
let result = unsafe {
|
let result = unsafe {
|
||||||
let p = self
|
let p = self
|
||||||
@ -501,7 +507,7 @@ impl VmThread {
|
|||||||
let method_ref = class.find_method("<init>", &desc)?;
|
let method_ref = class.find_method("<init>", &desc)?;
|
||||||
let mut args = args.to_vec();
|
let mut args = args.to_vec();
|
||||||
args.insert(0, obj.clone().into());
|
args.insert(0, obj.clone().into());
|
||||||
let _ = self.invoke(method_ref.into(), args)?;
|
let _ = self.invoke(MethodRef::from(method_ref), args)?;
|
||||||
Ok(obj)
|
Ok(obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -603,12 +609,13 @@ impl VmThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn bootstrap_mirror(&self) {
|
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 main = self.intern_string("main");
|
||||||
let system = self.intern_string("system");
|
let system = self.intern_string("system");
|
||||||
let thread_klass = self.get_class("java/lang/Thread").unwrap();
|
let thread_klass = self.get_class(VmSymbols::THREAD).unwrap();
|
||||||
let thread_group_klass = self.get_class("java/lang/ThreadGroup").unwrap();
|
let thread_group_klass = self.get_class(VmSymbols::THREAD_GROUP).unwrap();
|
||||||
let field_holder_klass = self.get_class("java/lang/Thread$FieldHolder").unwrap();
|
let field_holder_klass = self.get_class(VmSymbols::THREAD_FIELD_HOLDER).unwrap();
|
||||||
let group = self
|
let group = self
|
||||||
.gc
|
.gc
|
||||||
.write()
|
.write()
|
||||||
@ -623,6 +630,16 @@ impl VmThread {
|
|||||||
.new_thread(thread_klass, thread_id, thread_id, main, holder);
|
.new_thread(thread_klass, thread_id, thread_id, main, holder);
|
||||||
self.mirror.set(thread.lock().id).unwrap();
|
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:
|
// SAFETY:
|
||||||
// - jni_env pointer is owned by this VmThread and only used by its OS thread
|
// - 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 {
|
impl Display for Primitive {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
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))]
|
#[cfg(all(windows))]
|
||||||
use libloading::os::windows as imp;
|
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::class_loader::ClassLoader;
|
||||||
use crate::error::VmError;
|
use crate::error::VmError;
|
||||||
use crate::native::r#unsafe::UnsafeSupport;
|
use crate::native::r#unsafe::UnsafeSupport;
|
||||||
use crate::objects::object::ReferenceKind;
|
use crate::objects::object::ReferenceKind;
|
||||||
use crate::objects::object_manager::ObjectManager;
|
use crate::objects::object_manager::ObjectManager;
|
||||||
use crate::thread::VmThread;
|
use crate::thread::VmThread;
|
||||||
use crate::value::Value;
|
use crate::{MethodDescriptor, ThreadId, VmSymbols, os_thread_id};
|
||||||
use crate::{MethodDescriptor, ThreadId};
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use imp::Library;
|
use imp::Library;
|
||||||
use log::{info, trace};
|
use log::{info, trace};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use std::sync::atomic::AtomicU64;
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
use std::sync::{Arc, LazyLock};
|
use std::sync::{Arc, LazyLock};
|
||||||
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
type NativeLibraries = Arc<RwLock<Vec<(String, Library)>>>;
|
type NativeLibraries = Arc<RwLock<Vec<(String, Library)>>>;
|
||||||
|
|
||||||
pub static LIB_RESOLVE_COUNTS: LazyLock<DashMap<String, u32>> = LazyLock::new(DashMap::new);
|
pub static LIB_RESOLVE_COUNTS: LazyLock<DashMap<String, u32>> = LazyLock::new(DashMap::new);
|
||||||
// struct AbstractObject<'a> {}
|
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
// Thread registry - maps ThreadId to VmThread
|
// Thread registry - maps ThreadId to VmThread
|
||||||
pub threads: DashMap<ThreadId, Arc<VmThread>>,
|
pub threads: DashMap<ThreadId, Arc<VmThread>>,
|
||||||
@ -36,6 +37,7 @@ pub struct Vm {
|
|||||||
pub gc: Arc<RwLock<ObjectManager>>,
|
pub gc: Arc<RwLock<ObjectManager>>,
|
||||||
pub safent: RwLock<UnsafeSupport>,
|
pub safent: RwLock<UnsafeSupport>,
|
||||||
pub next_id: AtomicU64,
|
pub next_id: AtomicU64,
|
||||||
|
pub phase: AtomicU64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
@ -43,24 +45,24 @@ impl Vm {
|
|||||||
pub fn new() -> Arc<Self> {
|
pub fn new() -> Arc<Self> {
|
||||||
let vm = Arc::new(Self {
|
let vm = Arc::new(Self {
|
||||||
threads: DashMap::new(),
|
threads: DashMap::new(),
|
||||||
main_thread_id: ThreadId(0),
|
main_thread_id: os_thread_id().into(),
|
||||||
loader: Arc::new(Mutex::from(ClassLoader::with_bimage())),
|
loader: Arc::new(Mutex::from(ClassLoader::with_bimage())),
|
||||||
native_methods: DashMap::new(),
|
native_methods: DashMap::new(),
|
||||||
native_libraries: Arc::new(RwLock::new(Vec::new())),
|
native_libraries: Arc::new(RwLock::new(Vec::new())),
|
||||||
gc: Default::default(),
|
gc: Default::default(),
|
||||||
safent: Default::default(),
|
safent: Default::default(),
|
||||||
next_id: AtomicU64::new(0),
|
next_id: AtomicU64::new(0),
|
||||||
|
phase: AtomicU64::new(Init::STARTING),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create main thread
|
// Create main thread
|
||||||
let thread = VmThread::new(vm.clone(), None);
|
let main_thread = VmThread::new(vm.clone(), None);
|
||||||
let thread_id = thread.id;
|
|
||||||
|
|
||||||
// Store in VM
|
// Store in VM
|
||||||
vm.threads.insert(thread_id, thread.clone());
|
vm.threads.insert(main_thread.id, main_thread.clone());
|
||||||
|
|
||||||
// Set as current thread
|
// Set as current thread
|
||||||
VmThread::set_current(thread_id);
|
// VmThread::set_current(thread_id);
|
||||||
vm
|
vm
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +78,7 @@ impl Vm {
|
|||||||
gc: Default::default(),
|
gc: Default::default(),
|
||||||
safent: Default::default(),
|
safent: Default::default(),
|
||||||
next_id: AtomicU64::new(0),
|
next_id: AtomicU64::new(0),
|
||||||
|
phase: AtomicU64::new(Init::STARTING),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create main thread
|
// Create main thread
|
||||||
@ -119,23 +122,16 @@ impl Vm {
|
|||||||
|
|
||||||
pub fn boot_strap(&self) -> Result<(), VmError> {
|
pub fn boot_strap(&self) -> Result<(), VmError> {
|
||||||
let thread = self.threads.get(&self.main_thread_id).unwrap();
|
let thread = self.threads.get(&self.main_thread_id).unwrap();
|
||||||
let classes = vec![
|
|
||||||
"java/lang/String",
|
// Load core trio first
|
||||||
"java/lang/System",
|
let core_classes = vec![VmSymbols::OBJECT, VmSymbols::STRING, VmSymbols::CLASS];
|
||||||
"java/lang/Class",
|
let mut core_loaded = Vec::new();
|
||||||
"java/lang/ThreadGroup",
|
for name in core_classes {
|
||||||
"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 {
|
|
||||||
let class = thread.loader.lock().get_or_load(name, None)?;
|
let class = thread.loader.lock().get_or_load(name, None)?;
|
||||||
loaded.push(class);
|
core_loaded.push(class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Primitives
|
||||||
let prims = vec![
|
let prims = vec![
|
||||||
("byte", "B"),
|
("byte", "B"),
|
||||||
("char", "C"),
|
("char", "C"),
|
||||||
@ -147,14 +143,13 @@ impl Vm {
|
|||||||
("boolean", "Z"),
|
("boolean", "Z"),
|
||||||
("void", "V"),
|
("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 {
|
for prim in prims {
|
||||||
let klass = self.loader.lock().primitive_class(prim.0);
|
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 name_obj = thread.intern_string(&prim.0);
|
||||||
let flags = ClassFlags::from(1041u16);
|
|
||||||
let class_obj = self.gc.write().new_class(
|
let class_obj = self.gc.write().new_class(
|
||||||
class_class.clone(),
|
class_class.clone(),
|
||||||
Some(ReferenceKind::ObjectReference(name_obj)),
|
Some(ReferenceKind::ObjectReference(name_obj)),
|
||||||
@ -163,12 +158,12 @@ impl Vm {
|
|||||||
true,
|
true,
|
||||||
None,
|
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 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_name_obj = thread.intern_string(&prim_array_klass.this_class);
|
||||||
let arr_class_obj = self.gc.write().new_class(
|
let arr_class_obj = self.gc.write().new_class(
|
||||||
class_class,
|
class_class.clone(),
|
||||||
Some(ReferenceKind::ObjectReference(arr_name_obj)),
|
Some(ReferenceKind::ObjectReference(arr_name_obj)),
|
||||||
None,
|
None,
|
||||||
flags,
|
flags,
|
||||||
@ -180,24 +175,57 @@ impl Vm {
|
|||||||
.set(arr_class_obj.lock().id)
|
.set(arr_class_obj.lock().id)
|
||||||
.unwrap();
|
.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 {
|
for class in loaded {
|
||||||
println!("bootstrap init {}", class.this_class);
|
println!("bootstrap init {}", class.this_class);
|
||||||
thread.ensure_initialised(&class)?;
|
thread.ensure_initialised(&class)?;
|
||||||
}
|
}
|
||||||
|
self.phase.store(Init::JAVA_CLASSES, Ordering::Release);
|
||||||
|
|
||||||
let phase1ref = MethodRef {
|
// let phase1ref = MethodRef {
|
||||||
class: "java/lang/System".to_string(),
|
// class: "java/lang/System".to_string(),
|
||||||
name: "initPhase1".to_string(),
|
// name: "initPhase1".to_string(),
|
||||||
desc: MethodDescriptor::void(),
|
// desc: MethodDescriptor::void(),
|
||||||
};
|
// };
|
||||||
|
|
||||||
|
let phase1ref = MethodRef::from_symbols(VmSymbols::SYSTEM, "initPhase1", &vec![], None);
|
||||||
self.threads
|
self.threads
|
||||||
.get(&self.main_thread_id)
|
.get(&self.main_thread_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.bootstrap_mirror();
|
.bootstrap_mirror();
|
||||||
thread.invoke(phase1ref, Vec::new())?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,6 +239,14 @@ impl Vm {
|
|||||||
let thread = self.threads.get(&self.main_thread_id).unwrap().clone();
|
let thread = self.threads.get(&self.main_thread_id).unwrap().clone();
|
||||||
thread.invoke_main(what)
|
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:
|
// SAFETY:
|
||||||
@ -218,3 +254,13 @@ impl Vm {
|
|||||||
// - All mutable state is behind DashMap/RwLock/Mutex
|
// - All mutable state is behind DashMap/RwLock/Mutex
|
||||||
unsafe impl Send for Vm {}
|
unsafe impl Send for Vm {}
|
||||||
unsafe impl Sync 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::{JNIEnv, jint};
|
||||||
use jni::sys::{jobjectArray, jstring};
|
use jni::sys::{jobjectArray, jstring};
|
||||||
use log::trace;
|
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::ReferenceKind;
|
||||||
use roast_vm_core::objects::array::ArrayReference;
|
|
||||||
use roast_vm_core::value::Value;
|
|
||||||
use roast_vm_core::{BaseType, FieldType};
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[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 {
|
unsafe fn get_thread(env: *mut jni::sys::JNIEnv) -> *const VmThread {
|
||||||
let thread = (**env).reserved0 as *const VmThread;
|
let thread = (**env).reserved0 as *const VmThread;
|
||||||
VmThread::set_current((*thread).id);
|
|
||||||
thread
|
thread
|
||||||
}
|
}
|
||||||
fn resolve_object(thread: &VmThread, obj: jobject) -> Option<ObjectReference> {
|
fn resolve_object(thread: &VmThread, obj: jobject) -> Option<ObjectReference> {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::get_thread;
|
use crate::get_thread;
|
||||||
use jni::sys::{JNI_TRUE, JNIEnv, jclass, jint, jobject};
|
use jni::sys::{JNI_TRUE, JNIEnv, jclass, jint, jobject};
|
||||||
use roast_vm_core::FieldType;
|
use roast_vm_core::FieldType;
|
||||||
use roast_vm_core::class_file::FieldRef;
|
use roast_vm_core::class_file::resolved::FieldRef;
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "system" fn Java_java_lang_reflect_Array_newArray(
|
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()))
|
.get_field(&FieldRef::new("Class", "primitive", FieldType::bool()))
|
||||||
.try_into_jboolean()
|
.try_into_jboolean()
|
||||||
.unwrap();
|
.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 {
|
let refe = if prim == JNI_TRUE {
|
||||||
thread.gc.write().new_primitive_array(comp, length)
|
thread.gc.write().new_primitive_array(array_class, length)
|
||||||
} else {
|
} else {
|
||||||
thread.gc.write().new_object_array(comp, length)
|
thread.gc.write().new_object_array(array_class, length)
|
||||||
};
|
};
|
||||||
refe.id() as jobject
|
refe.id() as jobject
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use crate::get_thread;
|
use crate::get_thread;
|
||||||
use jni::sys::{JNIEnv, jclass, jint, jobject, jobjectArray};
|
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::objects::array::ArrayReference;
|
||||||
use roast_vm_core::value::Value;
|
use roast_vm_core::value::Value;
|
||||||
use roast_vm_core::{BaseType, FieldType};
|
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());
|
let instance = thread.gc.write().new_object(klass.clone());
|
||||||
values.insert(0, instance.clone().into());
|
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
|
instance.lock().id as jobject
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use jni::JNIEnv;
|
use jni::JNIEnv;
|
||||||
use jni::objects::{JClass, JObject};
|
use jni::objects::{JClass, JObject};
|
||||||
use jni::sys::jobjectArray;
|
use jni::sys::jobjectArray;
|
||||||
|
use roast_vm_core::VmSymbols;
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub extern "system" fn Java_jdk_internal_util_SystemProps_00024Raw_vmProperties<'local>(
|
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
|
// +1 for null terminator
|
||||||
let arr = env
|
let arr = env
|
||||||
.new_object_array((props.len() + 1) as i32, string_class, JObject::null())
|
.new_object_array((props.len() + 1) as i32, string_class, JObject::null())
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use crate::get_thread;
|
use crate::get_thread;
|
||||||
use jni::sys::{JNIEnv, jclass, jint, jlong, jobject};
|
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::value::Value;
|
||||||
use roast_vm_core::{MethodDescriptor, VmThread};
|
use roast_vm_core::{MethodDescriptor, VmSymbols, VmThread};
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
unsafe extern "system" fn Java_java_lang_Thread_currentThread(
|
unsafe extern "system" fn Java_java_lang_Thread_currentThread(
|
||||||
@ -30,6 +30,7 @@ unsafe extern "system" fn Java_java_lang_Thread_setPriority0(
|
|||||||
_this: jobject,
|
_this: jobject,
|
||||||
priority: jint,
|
priority: jint,
|
||||||
) {
|
) {
|
||||||
|
// todo
|
||||||
// Get the current thread and update its priority
|
// Get the current thread and update its priority
|
||||||
// let thread = &*get_thread(env);
|
// let thread = &*get_thread(env);
|
||||||
// Store priority in thread state (implementation depends on thread structure)
|
// 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());
|
vm.threads.insert(thread_id, new_thread.clone());
|
||||||
|
|
||||||
// Set as current thread for this OS thread
|
// Set as current thread for this OS thread
|
||||||
VmThread::set_current(thread_id);
|
// VmThread::set_current(thread_id);
|
||||||
|
|
||||||
// Call this.run()
|
// Call this.run()
|
||||||
// let thread_class = new_thread.get_class("java/lang/Thread").unwrap();
|
// let thread_class = new_thread.get_class("java/lang/Thread").unwrap();
|
||||||
let run_ref = MethodRef {
|
let run_ref = MethodRef::from_symbols(VmSymbols::THREAD, "run", &Vec)
|
||||||
class: "java/lang/Thread".to_string(),
|
|
||||||
name: "run".to_string(),
|
|
||||||
desc: MethodDescriptor::void(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the Thread object as a Value
|
// Get the Thread object as a Value
|
||||||
let thread_value = Value::Reference(Some(new_thread.gc.read().get(thread_obj_id)));
|
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]) {
|
if let Err(e) = new_thread.invoke(run_ref.into(), vec![thread_value]) {
|
||||||
eprintln!("Thread {} died with: {:?}", thread_id.0, e);
|
eprintln!("Thread {:?} died with: {:?}", thread_id, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup: remove from VM thread registry
|
// Cleanup: remove from VM thread registry
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user