jni
This commit is contained in:
parent
7fd494d999
commit
78b17345b8
21
Cargo.toml
21
Cargo.toml
@ -1,18 +1,17 @@
|
|||||||
[package]
|
[workspace]
|
||||||
name = "jvm-rs"
|
members = [
|
||||||
version = "0.1.0"
|
"crates/*"
|
||||||
edition = "2024"
|
]
|
||||||
|
resolver = "3"
|
||||||
|
|
||||||
[dependencies]
|
[workspace.dependencies]
|
||||||
deku = { version = "0.20.0", features = ["logging"] }
|
deku = { version = "0.20.0", features = ["logging"] }
|
||||||
deku_derive = "0.20.0"
|
deku_derive = "0.20.0"
|
||||||
log = "0.4.28"
|
log = "0.4.28"
|
||||||
env_logger = "0.11.8"
|
env_logger = "0.11.8"
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
sevenz-rust2 = { version = "0.19.3", features = ["brotli", "zstd"] }
|
sevenz-rust2 = { version = "0.19.3", features = ["brotli", "zstd"] }
|
||||||
|
dashmap = "7.0.0-rc2"
|
||||||
[build-dependencies]
|
libloading = "0.8.9"
|
||||||
bindgen = "0.72.1"
|
libffi = "5.0.0"
|
||||||
|
jni = "0.21.1"
|
||||||
[lints.rust]
|
|
||||||
missing_docs = "warn"
|
|
||||||
23
crates/core/Cargo.toml
Normal file
23
crates/core/Cargo.toml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
[package]
|
||||||
|
name = "jvm-rs-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
publish = ["nexus"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
deku = { workspace = true }
|
||||||
|
deku_derive = { workspace = true }
|
||||||
|
log = { workspace = true }
|
||||||
|
env_logger = { workspace = true }
|
||||||
|
itertools = { workspace = true }
|
||||||
|
sevenz-rust2 = { workspace = true }
|
||||||
|
dashmap = { workspace = true }
|
||||||
|
libloading = { workspace = true }
|
||||||
|
libffi = { workspace = true }
|
||||||
|
jni = { workspace = true }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
bindgen = "0.72.1"
|
||||||
|
|
||||||
|
[lints.rust]
|
||||||
|
#missing_docs = "warn"
|
||||||
@ -4,7 +4,6 @@ use std::fs::File;
|
|||||||
|
|
||||||
const DEFAULT_LOCATION: &str = "./lib/modules";
|
const DEFAULT_LOCATION: &str = "./lib/modules";
|
||||||
|
|
||||||
|
|
||||||
pub struct Bimage {
|
pub struct Bimage {
|
||||||
image: ArchiveReader<File>,
|
image: ArchiveReader<File>,
|
||||||
modules: Vec<String>,
|
modules: Vec<String>,
|
||||||
@ -12,13 +11,18 @@ pub struct Bimage {
|
|||||||
|
|
||||||
impl Default for Bimage {
|
impl Default for Bimage {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let reader = ArchiveReader::open(DEFAULT_LOCATION, Default::default()).expect("No image location given, and unable to open/locate default image");
|
let reader = ArchiveReader::open(DEFAULT_LOCATION, Default::default())
|
||||||
|
.expect("No image location given, and unable to open/locate default image");
|
||||||
|
|
||||||
|
let mut modules = reader
|
||||||
let mut modules = reader.archive().files.iter().filter(|e|{
|
.archive()
|
||||||
e.is_directory &&
|
.files
|
||||||
e.name.split("/").count() == 1
|
.iter()
|
||||||
}).map(|e| { e.name.clone() }).collect::<HashSet<_>>().into_iter().collect::<Vec<_>>();
|
.filter(|e| e.is_directory && e.name.split("/").count() == 1)
|
||||||
|
.map(|e| e.name.clone())
|
||||||
|
.collect::<HashSet<_>>()
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
modules.sort();
|
modules.sort();
|
||||||
Self {
|
Self {
|
||||||
image: reader,
|
image: reader,
|
||||||
@ -27,19 +31,22 @@ impl Default for Bimage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Bimage {
|
impl Bimage {
|
||||||
pub fn new(path: impl AsRef<std::path::Path>) -> Self {
|
pub fn new(path: impl AsRef<std::path::Path>) -> Self {
|
||||||
let reader = ArchiveReader::open(path, Default::default()).expect("Unable to find specified bimage.");
|
let reader = ArchiveReader::open(path, Default::default())
|
||||||
|
.expect("Unable to find specified bimage.");
|
||||||
Self {
|
Self {
|
||||||
image: reader,
|
image: reader,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn resolve_path(module: &str, class: &str) -> String {
|
fn resolve_path(module: &str, class: &str) -> String {
|
||||||
let module = if module.is_empty() { "java.base" } else { module };
|
let module = if module.is_empty() {
|
||||||
|
"java.base"
|
||||||
|
} else {
|
||||||
|
module
|
||||||
|
};
|
||||||
let class = Self::d2s(class);
|
let class = Self::d2s(class);
|
||||||
format!("{module}/classes/{class}.class")
|
format!("{module}/classes/{class}.class")
|
||||||
}
|
}
|
||||||
@ -50,11 +57,13 @@ impl Bimage {
|
|||||||
slashes.replace("/", ".")
|
slashes.replace("/", ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn get_class(&mut self, module: &str, class: &str) -> Option<Vec<u8>> {
|
pub fn get_class(&mut self, module: &str, class: &str) -> Option<Vec<u8>> {
|
||||||
let path = Self::resolve_path(module, class);
|
let path = Self::resolve_path(module, class);
|
||||||
self.image.read_file(&path).map_err(|e| {
|
self.image
|
||||||
println!("{}", path);
|
.read_file(&path)
|
||||||
}).ok()
|
.map_err(|e| {
|
||||||
|
log::trace!("Class not found {}", path);
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,6 +4,7 @@ use crate::class_file::{
|
|||||||
MethodInfo, MethodRef,
|
MethodInfo, MethodRef,
|
||||||
};
|
};
|
||||||
use crate::{FieldType, MethodDescriptor, VmError};
|
use crate::{FieldType, MethodDescriptor, VmError};
|
||||||
|
use log::trace;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread::ThreadId;
|
use std::thread::ThreadId;
|
||||||
|
|
||||||
@ -20,6 +21,7 @@ pub enum InitState {
|
|||||||
Error(String),
|
Error(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct RuntimeClass {
|
pub struct RuntimeClass {
|
||||||
pub constant_pool: Arc<Vec<ConstantPoolEntry>>,
|
pub constant_pool: Arc<Vec<ConstantPoolEntry>>,
|
||||||
pub access_flags: ClassFlags,
|
pub access_flags: ClassFlags,
|
||||||
@ -33,20 +35,23 @@ pub struct RuntimeClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RuntimeClass {
|
impl RuntimeClass {
|
||||||
pub fn find_method(&self, name: &str, desc: MethodDescriptor) -> Result<&MethodData, VmError> {
|
pub fn find_method(&self, name: &str, desc: &MethodDescriptor) -> Result<&MethodData, VmError> {
|
||||||
println!("Finding method");
|
trace!(
|
||||||
|
"Finding in {}, method Name: {name} desc:{desc},",
|
||||||
|
self.this_class
|
||||||
|
);
|
||||||
if let Some(method) = self.methods.iter().find(|e| {
|
if let Some(method) = self.methods.iter().find(|e| {
|
||||||
println!("Method Name Needed: {name}, Checked:{}", e.name);
|
|
||||||
println!("Method type Needed: {desc:?}, Checked:{:?}", e.desc);
|
|
||||||
let name_match = e.name.eq(name);
|
let name_match = e.name.eq(name);
|
||||||
let param_match = desc.parameters == e.desc.parameters;
|
let param_match = desc.parameters == e.desc.parameters;
|
||||||
name_match && param_match
|
name_match && param_match
|
||||||
}) {
|
}) {
|
||||||
|
trace!("Found method: {name}");
|
||||||
return Ok(method);
|
return Ok(method);
|
||||||
};
|
};
|
||||||
|
|
||||||
// recurse super class
|
// recurse super class
|
||||||
if let Some(super_class) = &self.super_class {
|
if let Some(super_class) = &self.super_class {
|
||||||
|
trace!("Recursing for {name}");
|
||||||
return super_class.find_method(name, desc);
|
return super_class.find_method(name, desc);
|
||||||
}
|
}
|
||||||
// No method found, and we must be Object, as we don't have a superclass
|
// No method found, and we must be Object, as we don't have a superclass
|
||||||
@ -10,7 +10,7 @@ use std::fmt;
|
|||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::str::Chars;
|
use std::str::Chars;
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
#[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")]
|
||||||
@ -639,11 +639,12 @@ pub struct FieldRef {
|
|||||||
pub desc: FieldType,
|
pub desc: FieldType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct FieldData {
|
pub struct FieldData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub flags: FieldFlags,
|
pub flags: FieldFlags,
|
||||||
pub desc: FieldType,
|
pub desc: FieldType,
|
||||||
pub value: Option<Constant>,
|
pub value: Arc<Mutex<Option<Value>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
@ -655,6 +656,20 @@ pub enum Constant {
|
|||||||
String(String),
|
String(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Constant> for Value {
|
||||||
|
fn from(value: Constant) -> Self {
|
||||||
|
match value {
|
||||||
|
Constant::Int(x) => Value::Int(x),
|
||||||
|
Constant::Long(x) => Value::Long(x),
|
||||||
|
Constant::Float(x) => Value::Float(x),
|
||||||
|
Constant::Double(x) => Value::Double(x),
|
||||||
|
Constant::String(x) => {
|
||||||
|
todo!("Constant string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
|
#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
|
||||||
pub struct ClassFlags {
|
pub struct ClassFlags {
|
||||||
@ -1,12 +1,20 @@
|
|||||||
|
use crate::attributes::{
|
||||||
|
Attribute, AttributeInfo, CodeAttribute, LineNumberTableAttribute, LocalVariableTableAttribute,
|
||||||
|
};
|
||||||
|
use crate::class_file::{
|
||||||
|
ConstantClassInfo, ConstantDynamicInfo, ConstantFieldrefInfo, ConstantInterfaceMethodrefInfo,
|
||||||
|
ConstantInvokeDynamicInfo, ConstantMethodHandleInfo, ConstantMethodTypeInfo,
|
||||||
|
ConstantMethodrefInfo, ConstantModuleInfo, ConstantNameAndTypeInfo, ConstantPackageInfo,
|
||||||
|
ConstantPoolEntry, ConstantStringInfo, ConstantUtf8Info, DescParseError, FieldInfo, FieldRef,
|
||||||
|
MethodInfo, MethodRef,
|
||||||
|
};
|
||||||
|
use crate::{pool_get_impl, FieldType, MethodDescriptor, VmError};
|
||||||
|
use deku::DekuContainerRead;
|
||||||
|
use log::trace;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use deku::DekuContainerRead;
|
|
||||||
use log::trace;
|
|
||||||
use crate::class_file::{ConstantClassInfo, ConstantFieldrefInfo, ConstantNameAndTypeInfo, ConstantPoolEntry, FieldRef, FieldInfo, MethodRef, MethodInfo, ConstantUtf8Info, ConstantStringInfo, ConstantMethodrefInfo, ConstantInterfaceMethodrefInfo, ConstantMethodHandleInfo, ConstantMethodTypeInfo, ConstantDynamicInfo, ConstantInvokeDynamicInfo, ConstantModuleInfo, ConstantPackageInfo, DescParseError};
|
|
||||||
use crate::{pool_get_impl, FieldType, MethodDescriptor, VmError};
|
|
||||||
use crate::attributes::{Attribute, AttributeInfo, CodeAttribute, LineNumberTableAttribute, LocalVariableTableAttribute};
|
|
||||||
|
|
||||||
pub type ConstantPoolSlice = [ConstantPoolEntry];
|
pub type ConstantPoolSlice = [ConstantPoolEntry];
|
||||||
pub type ConstantPoolOwned = Vec<ConstantPoolEntry>;
|
pub type ConstantPoolOwned = Vec<ConstantPoolEntry>;
|
||||||
@ -31,7 +39,7 @@ pub trait ConstantPoolExt: ConstantPoolGet {
|
|||||||
fn get_string(&self, index: u16) -> Result<String, ConstantPoolError> {
|
fn get_string(&self, index: u16) -> Result<String, ConstantPoolError> {
|
||||||
let cp_entry = self.get_utf8_info(index)?;
|
let cp_entry = self.get_utf8_info(index)?;
|
||||||
|
|
||||||
String::from_utf8(cp_entry.bytes.clone()).map_err(|e| { e.to_string().into() })
|
String::from_utf8(cp_entry.bytes.clone()).map_err(|e| e.to_string().into())
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// fn get_field(&self, index: u16) -> Result<&ConstantFieldrefInfo, ()> {
|
// fn get_field(&self, index: u16) -> Result<&ConstantFieldrefInfo, ()> {
|
||||||
@ -65,11 +73,7 @@ pub trait ConstantPoolExt: ConstantPoolGet {
|
|||||||
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 = FieldType::parse(&desc)?;
|
let desc = FieldType::parse(&desc)?;
|
||||||
Ok(FieldRef {
|
Ok(FieldRef { class, name, desc })
|
||||||
class,
|
|
||||||
name,
|
|
||||||
desc,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_method_ref(&self, index: u16) -> Result<MethodRef, ConstantPoolError> {
|
fn resolve_method_ref(&self, index: u16) -> Result<MethodRef, ConstantPoolError> {
|
||||||
@ -80,11 +84,7 @@ pub trait ConstantPoolExt: ConstantPoolGet {
|
|||||||
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 {
|
Ok(MethodRef { class, name, desc })
|
||||||
class,
|
|
||||||
name,
|
|
||||||
desc,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*// (name, desc)
|
/*// (name, desc)
|
||||||
@ -111,12 +111,9 @@ pub trait ConstantPoolExt: ConstantPoolGet {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
||||||
match name.as_ref() {
|
match name.as_ref() {
|
||||||
"Code" => {
|
"Code" => {
|
||||||
@ -131,15 +128,9 @@ pub trait ConstantPoolExt: ConstantPoolGet {
|
|||||||
let (_, lnt) = LineNumberTableAttribute::from_bytes((&a.info.as_slice(), 0))?;
|
let (_, lnt) = LineNumberTableAttribute::from_bytes((&a.info.as_slice(), 0))?;
|
||||||
Ok(Attribute::LineNumberTable(lnt))
|
Ok(Attribute::LineNumberTable(lnt))
|
||||||
}
|
}
|
||||||
"StackMapTable" => {
|
"StackMapTable" => Ok(Attribute::StackMapTable(a.info.clone())),
|
||||||
Ok(Attribute::StackMapTable(a.info.clone()))
|
"Exceptions" => Ok(Attribute::Exceptions(a.info.clone())),
|
||||||
}
|
"InnerClasses" => Ok(Attribute::InnerClasses(a.info.clone())),
|
||||||
"Exceptions" => {
|
|
||||||
Ok(Attribute::Exceptions(a.info.clone()))
|
|
||||||
}
|
|
||||||
"InnerClasses" => {
|
|
||||||
Ok(Attribute::InnerClasses(a.info.clone()))
|
|
||||||
}
|
|
||||||
"Signature" => {
|
"Signature" => {
|
||||||
let signature_index = u16::from_be_bytes([a.info[0], a.info[1]]);
|
let signature_index = u16::from_be_bytes([a.info[0], a.info[1]]);
|
||||||
Ok(Attribute::Signature(signature_index))
|
Ok(Attribute::Signature(signature_index))
|
||||||
@ -1,23 +1,26 @@
|
|||||||
|
use crate::attributes::Attribute;
|
||||||
|
use crate::bimage::Bimage;
|
||||||
|
use crate::class::RuntimeClass;
|
||||||
|
use crate::class_file::constant_pool::{ConstantPoolExt, ConstantPoolGet};
|
||||||
|
use crate::class_file::{
|
||||||
|
ClassFile, ClassFlags, ConstantClassInfo, ConstantPoolEntry, FieldData, FieldFlags, MethodData,
|
||||||
|
MethodFlags,
|
||||||
|
};
|
||||||
|
use crate::native_libraries::NativeLibraries;
|
||||||
|
use crate::{FieldType, MethodDescriptor};
|
||||||
|
use dashmap::DashMap;
|
||||||
|
use deku::DekuContainerRead;
|
||||||
|
use libloading::os::windows::Library;
|
||||||
|
use log::warn;
|
||||||
use std::collections::hash_map::{Entry, Iter};
|
use std::collections::hash_map::{Entry, Iter};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use deku::DekuContainerRead;
|
|
||||||
use log::warn;
|
|
||||||
use crate::attributes::Attribute;
|
|
||||||
use crate::bimage::Bimage;
|
|
||||||
use crate::class::RuntimeClass;
|
|
||||||
use crate::class_file::{ClassFile, ClassFlags, ConstantClassInfo, ConstantPoolEntry, FieldData, FieldFlags, MethodData, MethodFlags};
|
|
||||||
use crate::class_file::constant_pool::{ConstantPoolExt, ConstantPoolGet};
|
|
||||||
use crate::{FieldType, MethodDescriptor};
|
|
||||||
|
|
||||||
pub type LoaderRef = Arc<Mutex<ClassLoader>>;
|
pub type LoaderRef = Arc<Mutex<ClassLoader>>;
|
||||||
|
|
||||||
#[deprecated(
|
#[deprecated(note = "This method is deprecated and will be removed in future versions")]
|
||||||
note = "This method is deprecated and will be removed in future versions"
|
|
||||||
)]
|
|
||||||
pub fn resolve_path(what: &str) -> Result<(PathBuf, String), String> {
|
pub fn resolve_path(what: &str) -> Result<(PathBuf, String), String> {
|
||||||
let (module, fqn) = what.split_once("/").unwrap_or(("", what));
|
let (module, fqn) = what.split_once("/").unwrap_or(("", what));
|
||||||
let module = dot_to_path(module);
|
let module = dot_to_path(module);
|
||||||
@ -36,15 +39,22 @@ pub fn resolve_path(what: &str) -> Result<(PathBuf, String), String> {
|
|||||||
|
|
||||||
let classes_path = module_path.join("jmod/classes");
|
let classes_path = module_path.join("jmod/classes");
|
||||||
if !classes_path.exists() {
|
if !classes_path.exists() {
|
||||||
return Err(format!("Could not find jmod/classes directory in module: {}", module));
|
return Err(format!(
|
||||||
|
"Could not find jmod/classes directory in module: {}",
|
||||||
|
module
|
||||||
|
));
|
||||||
}
|
}
|
||||||
classes_path
|
classes_path
|
||||||
} else { base.to_path_buf() };
|
} else {
|
||||||
|
base.to_path_buf()
|
||||||
|
};
|
||||||
|
|
||||||
let class_path = path.join(format!("{}.class", fqn));
|
let class_path = path.join(format!("{}.class", fqn));
|
||||||
if !class_path.exists() {
|
if !class_path.exists() {
|
||||||
return Err(format!("Could not find class: {} in module: {}", fqn, module));
|
return Err(format!(
|
||||||
|
"Could not find class: {} in module: {}",
|
||||||
|
fqn, module
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((class_path, path_to_dot(&fqn)))
|
Ok((class_path, path_to_dot(&fqn)))
|
||||||
@ -77,9 +87,10 @@ pub fn resolve_path(what: &str) -> Result<(PathBuf, String), String> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ClassLoader {
|
pub struct ClassLoader {
|
||||||
classes: HashMap<String, Arc<RuntimeClass>>,
|
classes: DashMap<String, Arc<RuntimeClass>>,
|
||||||
bimage: Bimage,
|
bimage: Bimage,
|
||||||
pub needs_init: Vec<Arc<RuntimeClass>>
|
pub needs_init: Vec<Arc<RuntimeClass>>,
|
||||||
|
native_libraries: NativeLibraries,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClassLoader {
|
impl ClassLoader {
|
||||||
@ -140,7 +151,7 @@ impl ClassLoader {
|
|||||||
let (module, class_fqn) = ("", what);
|
let (module, class_fqn) = ("", what);
|
||||||
let bytes = self.bimage.get_class(module, class_fqn).unwrap_or_else(|| {
|
let bytes = self.bimage.get_class(module, class_fqn).unwrap_or_else(|| {
|
||||||
let path = format!("./data/{what}.class");
|
let path = format!("./data/{what}.class");
|
||||||
println!("{}", path);
|
log::info!("Loading class from path: {}", path);
|
||||||
let mut class_file = File::open(path).unwrap();
|
let mut class_file = File::open(path).unwrap();
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
class_file.read_to_end(&mut bytes).unwrap();
|
class_file.read_to_end(&mut bytes).unwrap();
|
||||||
@ -151,28 +162,33 @@ impl ClassLoader {
|
|||||||
let runtime = self.runtime_class(cf);
|
let runtime = self.runtime_class(cf);
|
||||||
let arced = Arc::new(runtime);
|
let arced = Arc::new(runtime);
|
||||||
let option = self.classes.insert(class_fqn.to_string(), arced.clone());
|
let option = self.classes.insert(class_fqn.to_string(), arced.clone());
|
||||||
if option.is_some() { warn!("Replaced loaded class: {}", class_fqn) }
|
if option.is_some() {
|
||||||
|
warn!("Replaced loaded class: {}", class_fqn)
|
||||||
|
}
|
||||||
Ok(arced)
|
Ok(arced)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn runtime_class(&mut self, class_file: ClassFile) -> RuntimeClass {
|
fn runtime_class(&mut self, class_file: ClassFile) -> RuntimeClass {
|
||||||
let constant_pool = class_file.constant_pool.clone();
|
let constant_pool = class_file.constant_pool.clone();
|
||||||
let access_flags = ClassFlags::from(class_file.access_flags);
|
let access_flags = ClassFlags::from(class_file.access_flags);
|
||||||
let this_class = {
|
let this_class = {
|
||||||
let cl = class_file.constant_pool.get_class_info(class_file.this_class).unwrap();
|
let cl = class_file
|
||||||
|
.constant_pool
|
||||||
|
.get_class_info(class_file.this_class)
|
||||||
|
.unwrap();
|
||||||
let name = class_file.constant_pool.get_string(cl.name_index).unwrap();
|
let name = class_file.constant_pool.get_string(cl.name_index).unwrap();
|
||||||
name
|
name
|
||||||
};
|
};
|
||||||
let super_class = {
|
let super_class = {
|
||||||
if (this_class.eq("java/lang/Object"))
|
if (this_class.eq("java/lang/Object")) {
|
||||||
{
|
|
||||||
debug_assert_eq!(this_class, "java/lang/Object");
|
debug_assert_eq!(this_class, "java/lang/Object");
|
||||||
debug_assert_eq!(class_file.super_class, 0u16);
|
debug_assert_eq!(class_file.super_class, 0u16);
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
debug_assert_ne!(class_file.super_class, 0u16);
|
debug_assert_ne!(class_file.super_class, 0u16);
|
||||||
let super_info = constant_pool.get_class_info(class_file.super_class).unwrap();
|
let super_info = constant_pool
|
||||||
|
.get_class_info(class_file.super_class)
|
||||||
|
.unwrap();
|
||||||
let name = constant_pool.get_string(**super_info).unwrap();
|
let name = constant_pool.get_string(**super_info).unwrap();
|
||||||
Some(self.get_or_load(&*name).unwrap())
|
Some(self.get_or_load(&*name).unwrap())
|
||||||
}
|
}
|
||||||
@ -187,47 +203,60 @@ impl ClassLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let interfaces = class_file
|
let interfaces = class_file
|
||||||
.interfaces.iter().copied()
|
.interfaces
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
.map(|e| {
|
.map(|e| {
|
||||||
let interface_info = constant_pool.get_class_info(e).unwrap();
|
let interface_info = constant_pool.get_class_info(e).unwrap();
|
||||||
let name = constant_pool.get_string(interface_info.name_index).unwrap();
|
let name = constant_pool.get_string(interface_info.name_index).unwrap();
|
||||||
self.get_or_load(&name).unwrap()
|
self.get_or_load(&name).unwrap()
|
||||||
}).collect::<Vec<_>>();
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let fields = class_file
|
let fields = class_file
|
||||||
.fields.iter()
|
.fields
|
||||||
|
.iter()
|
||||||
.map(|e| {
|
.map(|e| {
|
||||||
let name = constant_pool.get_string(e.name_index).unwrap();
|
let name = constant_pool.get_string(e.name_index).unwrap();
|
||||||
let flags = FieldFlags::from(e.access_flags);
|
let flags = FieldFlags::from(e.access_flags);
|
||||||
let desc = constant_pool.get_string(e.descriptor_index).map(|e|{
|
let desc = constant_pool
|
||||||
FieldType::parse(&e)
|
.get_string(e.descriptor_index)
|
||||||
}).unwrap().unwrap();
|
.map(|e| FieldType::parse(&e))
|
||||||
let value = e.attributes.first()
|
.unwrap()
|
||||||
.and_then(|x| {
|
.unwrap();
|
||||||
if let Attribute::ConstantValue(val) = constant_pool.parse_attribute(x.clone()).unwrap() {
|
let value = e.attributes.first().and_then(|x| {
|
||||||
Some(val)
|
if let Attribute::ConstantValue(val) =
|
||||||
|
constant_pool.parse_attribute(x.clone()).unwrap()
|
||||||
|
{
|
||||||
|
Some(val.into())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
let value = Arc::new(Mutex::new(value));
|
||||||
FieldData {
|
FieldData {
|
||||||
name,
|
name,
|
||||||
flags,
|
flags,
|
||||||
desc,
|
desc,
|
||||||
value,
|
value,
|
||||||
}
|
}
|
||||||
}).collect::<Vec<_>>();
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let methods = class_file
|
||||||
let methods = class_file.methods.iter().map(|e| {
|
.methods
|
||||||
|
.iter()
|
||||||
|
.map(|e| {
|
||||||
let name = constant_pool.get_string(e.name_index).unwrap();
|
let name = constant_pool.get_string(e.name_index).unwrap();
|
||||||
let flags = MethodFlags::from(e.access_flags);
|
let flags = MethodFlags::from(e.access_flags);
|
||||||
let desc = constant_pool.get_string(e.descriptor_index).map(|e|{
|
let desc = constant_pool
|
||||||
MethodDescriptor::parse(&e)
|
.get_string(e.descriptor_index)
|
||||||
}).unwrap().unwrap();
|
.map(|e| MethodDescriptor::parse(&e))
|
||||||
let code = e.attributes.first()
|
.unwrap()
|
||||||
.and_then(|x| {
|
.unwrap();
|
||||||
if let Attribute::Code(val) = constant_pool.parse_attribute(x.clone()).unwrap() {
|
let code = e.attributes.first().and_then(|x| {
|
||||||
|
if let Attribute::Code(val) = constant_pool.parse_attribute(x.clone()).unwrap()
|
||||||
|
{
|
||||||
Some(val)
|
Some(val)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -239,8 +268,8 @@ impl ClassLoader {
|
|||||||
desc,
|
desc,
|
||||||
code,
|
code,
|
||||||
}
|
}
|
||||||
}).collect::<Vec<_>>();
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
RuntimeClass {
|
RuntimeClass {
|
||||||
constant_pool,
|
constant_pool,
|
||||||
@ -253,6 +282,13 @@ impl ClassLoader {
|
|||||||
init_state: Mutex::new(crate::class::InitState::NotInitialized),
|
init_state: Mutex::new(crate::class::InitState::NotInitialized),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn find_native<T>(&self, name: String) -> libloading::os::windows::Symbol<T> {
|
||||||
|
// for (key, value) in self.native_libraries.iter() {
|
||||||
|
// // value.get()
|
||||||
|
// }
|
||||||
|
todo!("class_loader find native")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dot_to_path(s: &str) -> String {
|
fn dot_to_path(s: &str) -> String {
|
||||||
257
crates/core/src/jni.rs
Normal file
257
crates/core/src/jni.rs
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
use jni::sys::JNIEnv;
|
||||||
|
use jni::sys::{jint, JNINativeInterface_};
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
const JNI_VERSION_1_1: jint = 0x00010001;
|
||||||
|
const JNI_VERSION_1_2: jint = 0x00010002;
|
||||||
|
const JNI_VERSION_1_4: jint = 0x00010004;
|
||||||
|
const JNI_VERSION_1_6: jint = 0x00010006;
|
||||||
|
const JNI_VERSION_1_8: jint = 0x00010008;
|
||||||
|
const JNI_VERSION_9: jint = 0x00090000;
|
||||||
|
const JNI_VERSION_10: jint = 0x000a0000;
|
||||||
|
const JNI_VERSION_19: jint = 0x00130000;
|
||||||
|
const JNI_VERSION_20: jint = 0x00140000;
|
||||||
|
const JNI_VERSION_21: jint = 0x00150000;
|
||||||
|
const JNI_VERSION_24: jint = 0x00180000;
|
||||||
|
|
||||||
|
pub fn create_jni_function_table() -> JNIEnv {
|
||||||
|
Box::into_raw(Box::new(JNINativeInterface_ {
|
||||||
|
reserved0: ptr::null_mut(),
|
||||||
|
reserved1: ptr::null_mut(),
|
||||||
|
reserved2: ptr::null_mut(),
|
||||||
|
reserved3: ptr::null_mut(),
|
||||||
|
GetVersion: Some(jni_get_version),
|
||||||
|
DefineClass: None,
|
||||||
|
FindClass: None,
|
||||||
|
FromReflectedMethod: None,
|
||||||
|
FromReflectedField: None,
|
||||||
|
ToReflectedMethod: None,
|
||||||
|
GetSuperclass: None,
|
||||||
|
IsAssignableFrom: None,
|
||||||
|
ToReflectedField: None,
|
||||||
|
Throw: None,
|
||||||
|
ThrowNew: None,
|
||||||
|
ExceptionOccurred: None,
|
||||||
|
ExceptionDescribe: None,
|
||||||
|
ExceptionClear: None,
|
||||||
|
FatalError: None,
|
||||||
|
PushLocalFrame: None,
|
||||||
|
PopLocalFrame: None,
|
||||||
|
NewGlobalRef: None,
|
||||||
|
DeleteGlobalRef: None,
|
||||||
|
DeleteLocalRef: None,
|
||||||
|
IsSameObject: None,
|
||||||
|
NewLocalRef: None,
|
||||||
|
EnsureLocalCapacity: None,
|
||||||
|
AllocObject: None,
|
||||||
|
NewObject: None,
|
||||||
|
NewObjectV: None,
|
||||||
|
NewObjectA: None,
|
||||||
|
GetObjectClass: None,
|
||||||
|
IsInstanceOf: None,
|
||||||
|
GetMethodID: None,
|
||||||
|
CallObjectMethod: None,
|
||||||
|
CallObjectMethodV: None,
|
||||||
|
CallObjectMethodA: None,
|
||||||
|
CallBooleanMethod: None,
|
||||||
|
CallBooleanMethodV: None,
|
||||||
|
CallBooleanMethodA: None,
|
||||||
|
CallByteMethod: None,
|
||||||
|
CallByteMethodV: None,
|
||||||
|
CallByteMethodA: None,
|
||||||
|
CallCharMethod: None,
|
||||||
|
CallCharMethodV: None,
|
||||||
|
CallCharMethodA: None,
|
||||||
|
CallShortMethod: None,
|
||||||
|
CallShortMethodV: None,
|
||||||
|
CallShortMethodA: None,
|
||||||
|
CallIntMethod: None,
|
||||||
|
CallIntMethodV: None,
|
||||||
|
CallIntMethodA: None,
|
||||||
|
CallLongMethod: None,
|
||||||
|
CallLongMethodV: None,
|
||||||
|
CallLongMethodA: None,
|
||||||
|
CallFloatMethod: None,
|
||||||
|
CallFloatMethodV: None,
|
||||||
|
CallFloatMethodA: None,
|
||||||
|
CallDoubleMethod: None,
|
||||||
|
CallDoubleMethodV: None,
|
||||||
|
CallDoubleMethodA: None,
|
||||||
|
CallVoidMethod: None,
|
||||||
|
CallVoidMethodV: None,
|
||||||
|
CallVoidMethodA: None,
|
||||||
|
CallNonvirtualObjectMethod: None,
|
||||||
|
CallNonvirtualObjectMethodV: None,
|
||||||
|
CallNonvirtualObjectMethodA: None,
|
||||||
|
CallNonvirtualBooleanMethod: None,
|
||||||
|
CallNonvirtualBooleanMethodV: None,
|
||||||
|
CallNonvirtualBooleanMethodA: None,
|
||||||
|
CallNonvirtualByteMethod: None,
|
||||||
|
CallNonvirtualByteMethodV: None,
|
||||||
|
CallNonvirtualByteMethodA: None,
|
||||||
|
CallNonvirtualCharMethod: None,
|
||||||
|
CallNonvirtualCharMethodV: None,
|
||||||
|
CallNonvirtualCharMethodA: None,
|
||||||
|
CallNonvirtualShortMethod: None,
|
||||||
|
CallNonvirtualShortMethodV: None,
|
||||||
|
CallNonvirtualShortMethodA: None,
|
||||||
|
CallNonvirtualIntMethod: None,
|
||||||
|
CallNonvirtualIntMethodV: None,
|
||||||
|
CallNonvirtualIntMethodA: None,
|
||||||
|
CallNonvirtualLongMethod: None,
|
||||||
|
CallNonvirtualLongMethodV: None,
|
||||||
|
CallNonvirtualLongMethodA: None,
|
||||||
|
CallNonvirtualFloatMethod: None,
|
||||||
|
CallNonvirtualFloatMethodV: None,
|
||||||
|
CallNonvirtualFloatMethodA: None,
|
||||||
|
CallNonvirtualDoubleMethod: None,
|
||||||
|
CallNonvirtualDoubleMethodV: None,
|
||||||
|
CallNonvirtualDoubleMethodA: None,
|
||||||
|
CallNonvirtualVoidMethod: None,
|
||||||
|
CallNonvirtualVoidMethodV: None,
|
||||||
|
CallNonvirtualVoidMethodA: None,
|
||||||
|
GetFieldID: None,
|
||||||
|
GetObjectField: None,
|
||||||
|
GetBooleanField: None,
|
||||||
|
GetByteField: None,
|
||||||
|
GetCharField: None,
|
||||||
|
GetShortField: None,
|
||||||
|
GetIntField: None,
|
||||||
|
GetLongField: None,
|
||||||
|
GetFloatField: None,
|
||||||
|
GetDoubleField: None,
|
||||||
|
SetObjectField: None,
|
||||||
|
SetBooleanField: None,
|
||||||
|
SetByteField: None,
|
||||||
|
SetCharField: None,
|
||||||
|
SetShortField: None,
|
||||||
|
SetIntField: None,
|
||||||
|
SetLongField: None,
|
||||||
|
SetFloatField: None,
|
||||||
|
SetDoubleField: None,
|
||||||
|
GetStaticMethodID: None,
|
||||||
|
CallStaticObjectMethod: None,
|
||||||
|
CallStaticObjectMethodV: None,
|
||||||
|
CallStaticObjectMethodA: None,
|
||||||
|
CallStaticBooleanMethod: None,
|
||||||
|
CallStaticBooleanMethodV: None,
|
||||||
|
CallStaticBooleanMethodA: None,
|
||||||
|
CallStaticByteMethod: None,
|
||||||
|
CallStaticByteMethodV: None,
|
||||||
|
CallStaticByteMethodA: None,
|
||||||
|
CallStaticCharMethod: None,
|
||||||
|
CallStaticCharMethodV: None,
|
||||||
|
CallStaticCharMethodA: None,
|
||||||
|
CallStaticShortMethod: None,
|
||||||
|
CallStaticShortMethodV: None,
|
||||||
|
CallStaticShortMethodA: None,
|
||||||
|
CallStaticIntMethod: None,
|
||||||
|
CallStaticIntMethodV: None,
|
||||||
|
CallStaticIntMethodA: None,
|
||||||
|
CallStaticLongMethod: None,
|
||||||
|
CallStaticLongMethodV: None,
|
||||||
|
CallStaticLongMethodA: None,
|
||||||
|
CallStaticFloatMethod: None,
|
||||||
|
CallStaticFloatMethodV: None,
|
||||||
|
CallStaticFloatMethodA: None,
|
||||||
|
CallStaticDoubleMethod: None,
|
||||||
|
CallStaticDoubleMethodV: None,
|
||||||
|
CallStaticDoubleMethodA: None,
|
||||||
|
CallStaticVoidMethod: None,
|
||||||
|
CallStaticVoidMethodV: None,
|
||||||
|
CallStaticVoidMethodA: None,
|
||||||
|
GetStaticFieldID: None,
|
||||||
|
GetStaticObjectField: None,
|
||||||
|
GetStaticBooleanField: None,
|
||||||
|
GetStaticByteField: None,
|
||||||
|
GetStaticCharField: None,
|
||||||
|
GetStaticShortField: None,
|
||||||
|
GetStaticIntField: None,
|
||||||
|
GetStaticLongField: None,
|
||||||
|
GetStaticFloatField: None,
|
||||||
|
GetStaticDoubleField: None,
|
||||||
|
SetStaticObjectField: None,
|
||||||
|
SetStaticBooleanField: None,
|
||||||
|
SetStaticByteField: None,
|
||||||
|
SetStaticCharField: None,
|
||||||
|
SetStaticShortField: None,
|
||||||
|
SetStaticIntField: None,
|
||||||
|
SetStaticLongField: None,
|
||||||
|
SetStaticFloatField: None,
|
||||||
|
SetStaticDoubleField: None,
|
||||||
|
NewString: None,
|
||||||
|
GetStringLength: None,
|
||||||
|
GetStringChars: None,
|
||||||
|
ReleaseStringChars: None,
|
||||||
|
NewStringUTF: None,
|
||||||
|
GetStringUTFLength: None,
|
||||||
|
GetStringUTFChars: None,
|
||||||
|
ReleaseStringUTFChars: None,
|
||||||
|
GetArrayLength: None,
|
||||||
|
NewObjectArray: None,
|
||||||
|
GetObjectArrayElement: None,
|
||||||
|
SetObjectArrayElement: None,
|
||||||
|
NewBooleanArray: None,
|
||||||
|
NewByteArray: None,
|
||||||
|
NewCharArray: None,
|
||||||
|
NewShortArray: None,
|
||||||
|
NewIntArray: None,
|
||||||
|
NewLongArray: None,
|
||||||
|
NewFloatArray: None,
|
||||||
|
NewDoubleArray: None,
|
||||||
|
GetBooleanArrayElements: None,
|
||||||
|
GetByteArrayElements: None,
|
||||||
|
GetCharArrayElements: None,
|
||||||
|
GetShortArrayElements: None,
|
||||||
|
GetIntArrayElements: None,
|
||||||
|
GetLongArrayElements: None,
|
||||||
|
GetFloatArrayElements: None,
|
||||||
|
GetDoubleArrayElements: None,
|
||||||
|
ReleaseBooleanArrayElements: None,
|
||||||
|
ReleaseByteArrayElements: None,
|
||||||
|
ReleaseCharArrayElements: None,
|
||||||
|
ReleaseShortArrayElements: None,
|
||||||
|
ReleaseIntArrayElements: None,
|
||||||
|
ReleaseLongArrayElements: None,
|
||||||
|
ReleaseFloatArrayElements: None,
|
||||||
|
ReleaseDoubleArrayElements: None,
|
||||||
|
GetBooleanArrayRegion: None,
|
||||||
|
GetByteArrayRegion: None,
|
||||||
|
GetCharArrayRegion: None,
|
||||||
|
GetShortArrayRegion: None,
|
||||||
|
GetIntArrayRegion: None,
|
||||||
|
GetLongArrayRegion: None,
|
||||||
|
GetFloatArrayRegion: None,
|
||||||
|
GetDoubleArrayRegion: None,
|
||||||
|
SetBooleanArrayRegion: None,
|
||||||
|
SetByteArrayRegion: None,
|
||||||
|
SetCharArrayRegion: None,
|
||||||
|
SetShortArrayRegion: None,
|
||||||
|
SetIntArrayRegion: None,
|
||||||
|
SetLongArrayRegion: None,
|
||||||
|
SetFloatArrayRegion: None,
|
||||||
|
SetDoubleArrayRegion: None,
|
||||||
|
RegisterNatives: None,
|
||||||
|
UnregisterNatives: None,
|
||||||
|
MonitorEnter: None,
|
||||||
|
MonitorExit: None,
|
||||||
|
GetJavaVM: None,
|
||||||
|
GetStringRegion: None,
|
||||||
|
GetStringUTFRegion: None,
|
||||||
|
GetPrimitiveArrayCritical: None,
|
||||||
|
ReleasePrimitiveArrayCritical: None,
|
||||||
|
GetStringCritical: None,
|
||||||
|
ReleaseStringCritical: None,
|
||||||
|
NewWeakGlobalRef: None,
|
||||||
|
DeleteWeakGlobalRef: None,
|
||||||
|
ExceptionCheck: None,
|
||||||
|
NewDirectByteBuffer: None,
|
||||||
|
GetDirectBufferAddress: None,
|
||||||
|
GetDirectBufferCapacity: None,
|
||||||
|
GetObjectRefType: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "system" fn jni_get_version(env: *mut JNIEnv) -> jint {
|
||||||
|
JNI_VERSION_24
|
||||||
|
}
|
||||||
@ -21,9 +21,11 @@ use crate::class_file::constant_pool::{ConstantPoolError, ConstantPoolGet};
|
|||||||
use crate::class_file::{Bytecode, ClassFile, ConstantPoolEntry, MethodData};
|
use crate::class_file::{Bytecode, ClassFile, ConstantPoolEntry, MethodData};
|
||||||
use crate::object::Object;
|
use crate::object::Object;
|
||||||
use crate::thread::VmThread;
|
use crate::thread::VmThread;
|
||||||
|
use crate::Value::Reference;
|
||||||
use deku::{DekuContainerRead, DekuError};
|
use deku::{DekuContainerRead, DekuError};
|
||||||
use deku_derive::{DekuRead, DekuWrite};
|
use deku_derive::{DekuRead, DekuWrite};
|
||||||
use log::warn;
|
use env_logger::Builder;
|
||||||
|
use log::{warn, LevelFilter};
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
@ -35,7 +37,9 @@ mod bimage;
|
|||||||
mod class;
|
mod class;
|
||||||
mod class_file;
|
mod class_file;
|
||||||
mod class_loader;
|
mod class_loader;
|
||||||
|
mod jni;
|
||||||
mod macros;
|
mod macros;
|
||||||
|
mod native_libraries;
|
||||||
mod object;
|
mod object;
|
||||||
mod rng;
|
mod rng;
|
||||||
mod thread;
|
mod thread;
|
||||||
@ -46,7 +50,12 @@ const NULL: Value = Value::Reference(None);
|
|||||||
// include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
// include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||||
/// pseudo main
|
/// pseudo main
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
env_logger::init();
|
Builder::from_default_env()
|
||||||
|
.filter_level(LevelFilter::Trace)
|
||||||
|
.filter_module("deku", LevelFilter::Warn)
|
||||||
|
.filter_module("jvm_rs_core::class_file::class_file", LevelFilter::Info)
|
||||||
|
.filter_module("jvm_rs_core::attributes", LevelFilter::Info)
|
||||||
|
.init();
|
||||||
// let mut cl = ClassLoader::new().unwrap();
|
// let mut cl = ClassLoader::new().unwrap();
|
||||||
// cl.load_class("org.example.App").expect("TODO: panic message");
|
// cl.load_class("org.example.App").expect("TODO: panic message");
|
||||||
// let clazz = cl.get_or_load("org.example.App").unwrap();
|
// let clazz = cl.get_or_load("org.example.App").unwrap();
|
||||||
@ -54,11 +63,11 @@ pub fn run() {
|
|||||||
// std::fs::write(format!("./output/{}-{}.txt", i, class_loader::path_to_dot(k)), format!("{}\n{}", k, v)).unwrap();
|
// std::fs::write(format!("./output/{}-{}.txt", i, class_loader::path_to_dot(k)), format!("{}\n{}", k, v)).unwrap();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let mut class_file = File::open("./data/org/example/App.class").unwrap();
|
/*let mut class_file = File::open("./data/org/example/Main.class").unwrap();
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
class_file.read_to_end(&mut bytes).unwrap();
|
class_file.read_to_end(&mut bytes).unwrap();
|
||||||
let (_rest, clazz) = ClassFile::from_bytes((bytes.as_ref(), 0)).unwrap();
|
let (_rest, clazz) = ClassFile::from_bytes((bytes.as_ref(), 0)).unwrap();
|
||||||
let method = clazz.methods.iter().nth(1).unwrap().clone();
|
let method = clazz.methods.get(1).unwrap().clone();
|
||||||
let code = method
|
let code = method
|
||||||
.attributes
|
.attributes
|
||||||
.iter()
|
.iter()
|
||||||
@ -88,9 +97,9 @@ pub fn run() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("{}", clazz);
|
println!("{}", clazz);*/
|
||||||
// let pool = clazz.constant_pool;
|
// let pool = clazz.constant_pool;
|
||||||
let mut vm = Vm::new("org/example/App");
|
let mut vm = Vm::new("org/example/Main");
|
||||||
|
|
||||||
// println!("{:?}", ops);
|
// println!("{:?}", ops);
|
||||||
// println!("{:?}", var_table.local_variable_table);
|
// println!("{:?}", var_table.local_variable_table);
|
||||||
@ -298,6 +307,45 @@ impl MethodDescriptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for BaseType {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
BaseType::Byte => write!(f, "B"),
|
||||||
|
BaseType::Char => write!(f, "C"),
|
||||||
|
BaseType::Double => write!(f, "D"),
|
||||||
|
BaseType::Float => write!(f, "F"),
|
||||||
|
BaseType::Int => write!(f, "I"),
|
||||||
|
BaseType::Long => write!(f, "J"),
|
||||||
|
BaseType::Short => write!(f, "S"),
|
||||||
|
BaseType::Boolean => write!(f, "Z"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents types that can be used for fields in the JVM.
|
/// Represents types that can be used for fields in the JVM.
|
||||||
///
|
///
|
||||||
/// Field types can be:
|
/// Field types can be:
|
||||||
@ -516,7 +564,13 @@ impl Frame {
|
|||||||
let result = init_class
|
let result = init_class
|
||||||
.find_field(&field_ref.name, field_ref.desc)
|
.find_field(&field_ref.name, field_ref.desc)
|
||||||
.expect("TO hecken work");
|
.expect("TO hecken work");
|
||||||
let constant = result.value.clone().unwrap();
|
let constant = result
|
||||||
|
.value
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.clone()
|
||||||
|
.expect("Static field was not initialised");
|
||||||
|
self.stack.push(constant.into());
|
||||||
|
|
||||||
// let (code, pool) = {
|
// let (code, pool) = {
|
||||||
// let mut loader = self.vm.loader.lock().unwrap();
|
// let mut loader = self.vm.loader.lock().unwrap();
|
||||||
@ -526,7 +580,6 @@ impl Frame {
|
|||||||
// (code, pool)
|
// (code, pool)
|
||||||
// };
|
// };
|
||||||
// println!("{:?}", field);
|
// println!("{:?}", field);
|
||||||
todo!("Finish get static");
|
|
||||||
Ok(ExecutionResult::Continue)
|
Ok(ExecutionResult::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,7 +595,7 @@ impl Frame {
|
|||||||
let class = loader.get_or_load(&meth.class).unwrap();
|
let class = loader.get_or_load(&meth.class).unwrap();
|
||||||
let pool = class.constant_pool.clone();
|
let pool = class.constant_pool.clone();
|
||||||
let code = class
|
let code = class
|
||||||
.find_method(&meth.name, meth.desc)
|
.find_method(&meth.name, &meth.desc)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.code
|
.code
|
||||||
.clone()
|
.clone()
|
||||||
@ -576,6 +629,27 @@ impl Frame {
|
|||||||
Ok(ExecutionResult::Continue)
|
Ok(ExecutionResult::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ops::aconst_null => {
|
||||||
|
self.stack.push(NULL);
|
||||||
|
Ok(ExecutionResult::Continue)
|
||||||
|
}
|
||||||
|
|
||||||
|
Ops::putstatic(index) => {
|
||||||
|
let field_ref = self.pool.resolve_field(*index)?;
|
||||||
|
println!("Getting static field {field_ref:?}");
|
||||||
|
|
||||||
|
let init_class = self
|
||||||
|
.thread
|
||||||
|
.get_or_resolve_class(&field_ref.class, self.thread.clone())
|
||||||
|
.expect("TO hecken work");
|
||||||
|
let result = init_class
|
||||||
|
.find_field(&field_ref.name, field_ref.desc)
|
||||||
|
.expect("TO hecken work");
|
||||||
|
let value = self.stack.pop().expect("stack to have value");
|
||||||
|
*result.value.lock().unwrap() = Some(value);
|
||||||
|
Ok(ExecutionResult::Continue)
|
||||||
|
}
|
||||||
|
|
||||||
Ops::return_void => Ok(ExecutionResult::Return(())),
|
Ops::return_void => Ok(ExecutionResult::Return(())),
|
||||||
_ => {
|
_ => {
|
||||||
todo!("Unimplemented op: {:?}", op)
|
todo!("Unimplemented op: {:?}", op)
|
||||||
3
crates/core/src/main.rs
Normal file
3
crates/core/src/main.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
jvm_rs_core::run()
|
||||||
|
}
|
||||||
15
crates/core/src/native_libraries.rs
Normal file
15
crates/core/src/native_libraries.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use crate::class_file::ConstantPoolEntry;
|
||||||
|
use dashmap::DashMap;
|
||||||
|
use libloading::os::windows::Library;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub type NativeLibraries = HashMap<String, Library>;
|
||||||
|
// impl NativeExt for NativeLibraries {}
|
||||||
|
//
|
||||||
|
// trait NativeExt: AsRef<[..]> {
|
||||||
|
// fn find(&self, name: String) -> () {
|
||||||
|
// for lib in self.iter() {
|
||||||
|
// lib
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
@ -1,10 +1,19 @@
|
|||||||
use crate::class::RuntimeClass;
|
use crate::class::RuntimeClass;
|
||||||
use crate::class_file::{ClassFile, MethodRef};
|
use crate::class_file::{ClassFile, MethodData, MethodRef};
|
||||||
use crate::class_loader::{ClassLoader, LoaderRef};
|
use crate::class_loader::{ClassLoader, LoaderRef};
|
||||||
|
use crate::jni::create_jni_function_table;
|
||||||
use crate::vm::Vm;
|
use crate::vm::Vm;
|
||||||
use crate::{Frame, MethodDescriptor, Value, VmError};
|
use crate::{BaseType, FieldType, Frame, MethodDescriptor, Value, VmError};
|
||||||
use deku::DekuError::Incomplete;
|
use deku::DekuError::Incomplete;
|
||||||
|
use jni::sys::jlong;
|
||||||
|
use jni::JNIEnv;
|
||||||
|
use libffi::low::call;
|
||||||
|
use libffi::middle::*;
|
||||||
|
use log::{trace, warn};
|
||||||
|
use std::ops::Add;
|
||||||
|
use std::ptr::null_mut;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
type MethodCallResult = Result<Option<Value>, VmError>;
|
type MethodCallResult = Result<Option<Value>, VmError>;
|
||||||
|
|
||||||
@ -38,9 +47,9 @@ impl VmThread {
|
|||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_or_load(what)
|
.get_or_load(what)
|
||||||
.map_err(|e| VmError::LoaderError(e))?;
|
.map_err(VmError::LoaderError)?;
|
||||||
|
|
||||||
// Phase 2: Collect classes that need initialization (short lock)
|
// Phase 2: Collect classes that need initialisation (short lock)
|
||||||
let classes_to_init = {
|
let classes_to_init = {
|
||||||
let mut loader = self.loader.lock().unwrap();
|
let mut loader = self.loader.lock().unwrap();
|
||||||
let classes = loader.needs_init.clone();
|
let classes = loader.needs_init.clone();
|
||||||
@ -48,7 +57,7 @@ impl VmThread {
|
|||||||
classes
|
classes
|
||||||
};
|
};
|
||||||
|
|
||||||
// Phase 3: Initialize each class (NO lock held - allows recursion)
|
// Phase 3: Initialise each class (NO lock held - allows recursion)
|
||||||
for class in classes_to_init {
|
for class in classes_to_init {
|
||||||
self.init(class, thread.clone())?;
|
self.init(class, thread.clone())?;
|
||||||
}
|
}
|
||||||
@ -74,7 +83,7 @@ impl VmThread {
|
|||||||
}
|
}
|
||||||
InitState::Initializing(tid) if *tid == current_thread => {
|
InitState::Initializing(tid) if *tid == current_thread => {
|
||||||
// JVM Spec 5.5: Recursive initialization by same thread is allowed
|
// JVM Spec 5.5: Recursive initialization by same thread is allowed
|
||||||
println!(
|
warn!(
|
||||||
"Class {} already being initialized by this thread (recursive)",
|
"Class {} already being initialized by this thread (recursive)",
|
||||||
class.this_class
|
class.this_class
|
||||||
);
|
);
|
||||||
@ -102,7 +111,7 @@ impl VmThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Perform actual initialization
|
// Perform actual initialization
|
||||||
println!("Initializing class: {}", class.this_class);
|
trace!("Initializing class: {}", class.this_class);
|
||||||
let result = (|| {
|
let result = (|| {
|
||||||
// Initialize superclass first (if any)
|
// Initialize superclass first (if any)
|
||||||
if let Some(ref super_class) = class.super_class {
|
if let Some(ref super_class) = class.super_class {
|
||||||
@ -110,7 +119,7 @@ impl VmThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run <clinit> if present
|
// Run <clinit> if present
|
||||||
let class_init_method = class.find_method("<clinit>", MethodDescriptor::void());
|
let class_init_method = class.find_method("<clinit>", &MethodDescriptor::void());
|
||||||
if let Ok(method) = class_init_method {
|
if let Ok(method) = class_init_method {
|
||||||
Frame::new(
|
Frame::new(
|
||||||
method.code.clone().unwrap(),
|
method.code.clone().unwrap(),
|
||||||
@ -130,7 +139,7 @@ impl VmThread {
|
|||||||
match result {
|
match result {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
*state = InitState::Initialized;
|
*state = InitState::Initialized;
|
||||||
println!("Class {} initialized successfully", class.this_class);
|
trace!("Class {} initialized successfully", class.this_class);
|
||||||
}
|
}
|
||||||
Err(ref e) => {
|
Err(ref e) => {
|
||||||
*state = InitState::Error(format!("{:?}", e));
|
*state = InitState::Error(format!("{:?}", e));
|
||||||
@ -142,9 +151,18 @@ impl VmThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn invoke_main(&self, what: &str, thread: Arc<VmThread>) {
|
pub fn invoke_main(&self, what: &str, thread: Arc<VmThread>) {
|
||||||
|
let method_ref = MethodRef {
|
||||||
|
class: what.to_string(),
|
||||||
|
name: "main".to_string(),
|
||||||
|
desc: MethodDescriptor::psvm(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.invoke(method_ref, thread).expect("Main method died");
|
||||||
|
return ();
|
||||||
|
|
||||||
let class = self.get_or_resolve_class(what, thread.clone()).unwrap();
|
let class = self.get_or_resolve_class(what, thread.clone()).unwrap();
|
||||||
println!("invoking main: {}", class.this_class);
|
println!("invoking main: {}", class.this_class);
|
||||||
let main_method = class.find_method("main", MethodDescriptor::psvm());
|
let main_method = class.find_method("main", &MethodDescriptor::psvm());
|
||||||
println!("{:?}", main_method);
|
println!("{:?}", main_method);
|
||||||
if let Ok(meth) = main_method {
|
if let Ok(meth) = main_method {
|
||||||
let mut frame = Frame::new(
|
let mut frame = Frame::new(
|
||||||
@ -162,10 +180,13 @@ impl VmThread {
|
|||||||
pub fn invoke(&self, method_reference: MethodRef, thread: Arc<VmThread>) -> MethodCallResult {
|
pub fn invoke(&self, method_reference: MethodRef, thread: Arc<VmThread>) -> MethodCallResult {
|
||||||
let class = self.get_or_resolve_class(&method_reference.class, thread.clone())?;
|
let class = self.get_or_resolve_class(&method_reference.class, thread.clone())?;
|
||||||
let resolved_method = class
|
let resolved_method = class
|
||||||
.find_method(&method_reference.name, method_reference.desc)
|
.find_method(&method_reference.name, &method_reference.desc)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
println!("invoking {}: {}", method_reference.name, class.this_class);
|
||||||
if resolved_method.flags.ACC_NATIVE {
|
if resolved_method.flags.ACC_NATIVE {
|
||||||
return self.invoke_native();
|
unsafe {
|
||||||
|
return self.invoke_native(&method_reference);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let mut frame = Frame::new(
|
let mut frame = Frame::new(
|
||||||
resolved_method.code.clone().unwrap(),
|
resolved_method.code.clone().unwrap(),
|
||||||
@ -176,7 +197,79 @@ impl VmThread {
|
|||||||
frame.execute()
|
frame.execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invoke_native(&self) -> MethodCallResult {
|
pub fn invoke_native(&self, method: &MethodRef) -> MethodCallResult {
|
||||||
todo!("Invoke native")
|
let symbol_name = generate_jni_method_name(method);
|
||||||
|
println!("{:?}", &symbol_name);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// manually load relevant library for poc
|
||||||
|
let lib = libloading::os::windows::Library::new(
|
||||||
|
"C:\\Program Files\\Java\\jdk-25\\bin\\jvm_rs.dll",
|
||||||
|
)
|
||||||
|
.expect("load jvm_rs.dll");
|
||||||
|
|
||||||
|
// build pointer to native fn
|
||||||
|
let cp = CodePtr::from_ptr(
|
||||||
|
lib.get::<*const ()>(symbol_name.as_ref())
|
||||||
|
.unwrap()
|
||||||
|
.as_raw_ptr(),
|
||||||
|
);
|
||||||
|
// build actual JNI interface that forms the table of
|
||||||
|
// native functions that can be used to manipulate the JVM
|
||||||
|
let JNIEnv = create_jni_function_table();
|
||||||
|
|
||||||
|
// coerce my method descriptors into libffi C equivalents, then call
|
||||||
|
let l = method
|
||||||
|
.build_cif()
|
||||||
|
.call::<jlong>(cp, &*vec![arg(&JNIEnv), arg(&null_mut::<()>())]);
|
||||||
|
|
||||||
|
println!("{l}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
// todo!("Invoke native")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_jni_method_name(method_ref: &MethodRef) -> String {
|
||||||
|
let class_name = &method_ref.class.replace("/", "_");
|
||||||
|
let method_name = &method_ref.name;
|
||||||
|
format!("Java_{class_name}_{method_name}")
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FieldType> for Type {
|
||||||
|
fn from(value: FieldType) -> Self {
|
||||||
|
match value {
|
||||||
|
FieldType::Base(v) => match v {
|
||||||
|
BaseType::Byte => Type::i8(),
|
||||||
|
BaseType::Char => Type::u16(),
|
||||||
|
BaseType::Double => Type::f64(),
|
||||||
|
BaseType::Float => Type::f32(),
|
||||||
|
BaseType::Int => Type::i32(),
|
||||||
|
BaseType::Long => Type::i64(),
|
||||||
|
BaseType::Short => Type::i16(),
|
||||||
|
BaseType::Boolean => Type::i8(),
|
||||||
|
},
|
||||||
|
FieldType::ClassType(_) => Self::pointer(),
|
||||||
|
FieldType::ArrayType(_) => Self::pointer(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MethodRef {
|
||||||
|
fn build_cif(&self) -> Cif {
|
||||||
|
let mut args = vec![
|
||||||
|
Type::pointer(), //JNIEnv*
|
||||||
|
Type::pointer(), //jclass
|
||||||
|
];
|
||||||
|
for v in self.desc.parameters.clone() {
|
||||||
|
args.push(v.into())
|
||||||
|
}
|
||||||
|
let return_type = if let Some(x) = self.desc.return_type.clone() {
|
||||||
|
x.into()
|
||||||
|
} else {
|
||||||
|
Type::void()
|
||||||
|
};
|
||||||
|
Builder::new().args(args).res(return_type).into_cif()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,14 +1,17 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use crate::class_file::ClassFile;
|
use crate::class_file::ClassFile;
|
||||||
use crate::class_loader::ClassLoader;
|
use crate::class_loader::ClassLoader;
|
||||||
use crate::Frame;
|
|
||||||
use crate::thread::VmThread;
|
use crate::thread::VmThread;
|
||||||
|
use crate::Frame;
|
||||||
|
use libloading::os::windows::Symbol;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
// struct AbstractObject<'a> {}
|
// struct AbstractObject<'a> {}
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
// for now, model just a single thread
|
// for now, model just a single thread
|
||||||
pub thread: Mutex<Vec<Arc<VmThread>>>,
|
pub thread: Mutex<Vec<Arc<VmThread>>>,
|
||||||
pub loader: Arc<Mutex<ClassLoader>>
|
pub loader: Arc<Mutex<ClassLoader>>,
|
||||||
|
pub native_methods: HashMap<String, Symbol<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
@ -17,6 +20,7 @@ impl Vm {
|
|||||||
let vm = Arc::new(Self {
|
let vm = Arc::new(Self {
|
||||||
loader: Arc::new(Mutex::from(ClassLoader::default())),
|
loader: Arc::new(Mutex::from(ClassLoader::default())),
|
||||||
thread: Mutex::new(Vec::new()),
|
thread: Mutex::new(Vec::new()),
|
||||||
|
native_methods: Default::default(),
|
||||||
});
|
});
|
||||||
let thread = Arc::new(VmThread::new(vm.clone(), None));
|
let thread = Arc::new(VmThread::new(vm.clone(), None));
|
||||||
vm.thread.lock().unwrap().push(thread.clone());
|
vm.thread.lock().unwrap().push(thread.clone());
|
||||||
12
crates/jvm-rs-sys/Cargo.toml
Normal file
12
crates/jvm-rs-sys/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "jvm-rs-sys"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
publish = ["nexus"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
jni = { workspace = true }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "jvm_rs"
|
||||||
|
crate-type = ["cdylib"]
|
||||||
97
crates/jvm-rs-sys/src/lib.rs
Normal file
97
crates/jvm-rs-sys/src/lib.rs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use jni::objects::{JClass, JString};
|
||||||
|
use jni::strings::JNIString;
|
||||||
|
use jni::sys::{jclass, jlong};
|
||||||
|
use jni::{JNIEnv, NativeMethod};
|
||||||
|
use std::ffi::c_void;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "system" fn current_time_millis<'local>(
|
||||||
|
mut env: JNIEnv<'local>,
|
||||||
|
jclass: JClass<'local>,
|
||||||
|
) -> jlong {
|
||||||
|
println!("Sneaky hobitses has hijacked the native methods he has");
|
||||||
|
|
||||||
|
// SystemTime::now()
|
||||||
|
// .duration_since(UNIX_EPOCH)
|
||||||
|
// .unwrap()
|
||||||
|
// .as_millis() as jlong
|
||||||
|
|
||||||
|
1337i64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "system" fn Java_org_example_MockIO_print<'local>(
|
||||||
|
mut env: JNIEnv<'local>,
|
||||||
|
jclass: JClass<'local>,
|
||||||
|
input: JString<'local>,
|
||||||
|
) {
|
||||||
|
let input: String = env
|
||||||
|
.get_string(&input)
|
||||||
|
.expect("Couldn't get java string!")
|
||||||
|
.into();
|
||||||
|
std::io::stdout()
|
||||||
|
.write_all(input.as_bytes())
|
||||||
|
.expect("Failed to emit to stdout");
|
||||||
|
// println!("Yeetus bageetus! Im printing from rust!")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "system" fn Java_org_example_MockIO_registerNatives<'local>(
|
||||||
|
mut env: JNIEnv<'local>,
|
||||||
|
jclass: JClass<'local>,
|
||||||
|
) {
|
||||||
|
let system_methods = vec![NativeMethod {
|
||||||
|
name: JNIString::from("currentTimeMillis"),
|
||||||
|
sig: JNIString::from("()J"),
|
||||||
|
fn_ptr: current_time_millis as *mut c_void,
|
||||||
|
}];
|
||||||
|
let system_class = env
|
||||||
|
.find_class("java/lang/System")
|
||||||
|
.expect("Failed to find system class");
|
||||||
|
|
||||||
|
env.register_native_methods(system_class, &system_methods)
|
||||||
|
.expect("failed to register method");
|
||||||
|
|
||||||
|
let library_methods = vec![NativeMethod {
|
||||||
|
name: JNIString::from("findEntry0"),
|
||||||
|
sig: JNIString::from("(JLjava/lang/String;)J"),
|
||||||
|
fn_ptr: findEntry0 as *mut c_void,
|
||||||
|
}];
|
||||||
|
|
||||||
|
let library_class = env
|
||||||
|
.find_class("jdk/internal/loader/NativeLibrary")
|
||||||
|
.expect("Failed to find system class");
|
||||||
|
|
||||||
|
// env.register_native_methods(library_class, &library_methods)
|
||||||
|
// .expect("failed to register method");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "system" fn findEntry0<'local>(
|
||||||
|
mut env: JNIEnv<'local>,
|
||||||
|
jclass: JClass<'local>,
|
||||||
|
handle: jlong,
|
||||||
|
name: JString<'local>,
|
||||||
|
) -> jlong {
|
||||||
|
let name: String = env
|
||||||
|
.get_string(&name)
|
||||||
|
.expect("Couldn't get java string!")
|
||||||
|
.into();
|
||||||
|
println!("Name: {}, Handle: {}", name, handle);
|
||||||
|
0i64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "system" fn Java_org_example_Main_getTime<'local>(
|
||||||
|
mut env: JNIEnv<'local>,
|
||||||
|
jclass: JClass<'local>,
|
||||||
|
) -> jlong {
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_millis() as jlong
|
||||||
|
}
|
||||||
@ -1,5 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
jvm_rs::run()
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user