invokespecial
This commit is contained in:
parent
4d55892e61
commit
f76a89a086
7 changed files with 585 additions and 122 deletions
363
Cargo.lock
generated
363
Cargo.lock
generated
|
|
@ -2,24 +2,112 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "bzip2"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
|
||||
dependencies = [
|
||||
"bzip2-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bzip2-sys"
|
||||
version = "0.1.11+1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
|
|
@ -38,6 +126,71 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "java_rs"
|
||||
version = "0.1.0"
|
||||
|
|
@ -46,13 +199,223 @@ dependencies = [
|
|||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.148"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "password-hash"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pbkdf2"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"hmac",
|
||||
"password-hash",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"serde",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"byteorder",
|
||||
"bzip2",
|
||||
"constant_time_eq",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
"flate2",
|
||||
"hmac",
|
||||
"pbkdf2",
|
||||
"sha1",
|
||||
"time",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.11.2+zstd.1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "5.0.2+zstd.1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.8+zstd.1.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0", features = ["default"] }
|
||||
zip = { version = "0.6", default-features = false }
|
||||
zip = { version = "0.6", features = ["zstd"] }
|
||||
|
|
@ -72,7 +72,7 @@ impl Method {
|
|||
}
|
||||
|
||||
pub fn name(&self) -> String {
|
||||
let mut full_name = get_modifier(self.access_flags);
|
||||
let mut full_name = String::new();
|
||||
if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.name_index).unwrap() {
|
||||
full_name.push_str(s);
|
||||
}
|
||||
|
|
@ -131,7 +131,6 @@ impl Field {
|
|||
}
|
||||
|
||||
pub fn type_of(&self) -> &String {
|
||||
println!("{}", self.name_index);
|
||||
if let CpEntry::Utf8(s) = &self.constant_pool.get(&self.descriptor_index).unwrap() {
|
||||
return s;
|
||||
}
|
||||
|
|
|
|||
75
src/io.rs
75
src/io.rs
|
|
@ -2,6 +2,60 @@ use anyhow::{anyhow, Error};
|
|||
use std::fs::{self, File};
|
||||
use std::io::Read;
|
||||
|
||||
/// resolves the actual path where the class file is found
|
||||
/// for std lib there is a special case that resolves to the jmod
|
||||
/// notation:
|
||||
/// * [jmod]#classes/[package_path]/[class].class
|
||||
/// * [jar/zip]#[package_path]/[class].class
|
||||
/// * [dir]/[package_path]/[class].class
|
||||
pub fn find_class(classpath: &Vec<String>, class_name: &str) -> Result<String, Error> {
|
||||
if class_name.starts_with("java/") {
|
||||
let mut path: String = "jmods/java.base.jmod#classes/".into();
|
||||
path.push_str(class_name);
|
||||
path.push_str(".class");
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
for clp_entry in classpath {
|
||||
if fs::metadata(&clp_entry)?.is_dir() {
|
||||
let mut maybe_path = clp_entry.clone();
|
||||
maybe_path.push('/');
|
||||
maybe_path.push_str(class_name);
|
||||
maybe_path.push_str(".class");
|
||||
// println!("{}", maybe_path);
|
||||
if fs::metadata(&maybe_path)?.is_file() {
|
||||
return Ok(maybe_path);
|
||||
}
|
||||
} else {
|
||||
//TODO jar/zip files
|
||||
}
|
||||
}
|
||||
Err(anyhow!("Class not found {}", class_name))
|
||||
}
|
||||
|
||||
/// reads the binary class file from file path or archive
|
||||
/// and returns the byte array as Vec
|
||||
pub fn read_bytecode(name: String) -> Result<Vec<u8>, Error> {
|
||||
let mut buffer;
|
||||
if name.contains("#") {
|
||||
let parts: Vec<&str> = name.split("#").collect();
|
||||
let archive_file = File::open(parts[0])?;
|
||||
let mut archive_zip = zip::ZipArchive::new(archive_file)?;
|
||||
let mut entry = archive_zip.by_name(parts[1])?;
|
||||
buffer = vec![0; entry.size() as usize];
|
||||
entry.read(&mut buffer)?;
|
||||
} else {
|
||||
let mut f = File::open(&name)?;
|
||||
let metadata = fs::metadata(&name)?;
|
||||
buffer = vec![0; metadata.len() as usize];
|
||||
let _ = f.read(&mut buffer)?;
|
||||
}
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
|
||||
// methods to read values from big-endian binary data
|
||||
|
||||
pub(crate) fn read_u8(data: &[u8], pos: usize) -> u8 {
|
||||
u8::from_be_bytes(
|
||||
data[pos..pos + 1]
|
||||
|
|
@ -58,24 +112,3 @@ pub(crate) fn read_f64(data: &[u8], pos: usize) -> f64 {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn find_class(classpath: &Vec<String>, class_name: &str) -> Result<String, Error> {
|
||||
for clp_entry in classpath {
|
||||
let mut maybe_path = clp_entry.clone();
|
||||
maybe_path.push('/');
|
||||
maybe_path.push_str(class_name);
|
||||
maybe_path.push_str(".class");
|
||||
println!("{}", maybe_path);
|
||||
if fs::metadata(&maybe_path)?.is_file() {
|
||||
return Ok(maybe_path);
|
||||
}
|
||||
}
|
||||
Err(anyhow!("Class not found {}", class_name))
|
||||
}
|
||||
|
||||
pub fn read_class_file(name: String) -> Result<Vec<u8>, Error> {
|
||||
let mut f = File::open(&name)?;
|
||||
let metadata = fs::metadata(&name)?;
|
||||
let mut buffer = vec![0; metadata.len() as usize];
|
||||
let _ = f.read(&mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,13 @@ use java_rs::vm::Vm;
|
|||
use std::io::Error;
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
// TODO cmdline args
|
||||
// TODO build index for package -> jarfile?
|
||||
|
||||
let mut vm = Vm::new("tests");
|
||||
vm.execute("Main", "public static main([Ljava/lang/String;)V", None)
|
||||
let main_class = "Main";
|
||||
|
||||
vm.execute(main_class, "main([Ljava/lang/String;)V", None)
|
||||
.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,11 +85,11 @@ pub const IRETURN: &u8 = &172; // (0xac) ireturn
|
|||
pub const FRETURN: &u8 = &174; // (0xae) Return float from method
|
||||
pub const DRETURN: &u8 = &175; // (0xaf) Return double from method
|
||||
// pub const areturn: u8 = 176; //(0xb0) return reference
|
||||
// pub const return_v: u8 = 177; // (0xb1) Return void from method (actually 'return' but that's a keyword)
|
||||
pub const RETURN_VOID: &u8 = &177; // (0xb1) Return void from method (actually 'return' but that's a keyword)
|
||||
// pub const getstatic: u8 = 178; // (0xb2) Get static field from class
|
||||
pub const GETFIELD: &u8 = &180; // (0xb4) Fetch field from object3
|
||||
pub const INVOKEVIRTUAL: &u8 = &182; // (0xb6) Invoke instance method; dispatch based on class
|
||||
pub const NEW: &u8 = &187; // (0xbb) Create new object
|
||||
// pub const invokevirtual: u8 = 182; // (0xb6) Invoke instance method; dispatch based on class
|
||||
//
|
||||
pub const INVOKESPECIAL: &u8 = &183; // (0xb7) // nvoke instance method; direct invocation of instance initialization methods and methods of the current class and its supertypes
|
||||
// pub const anewarray: u8 = 189; // (0xbd)
|
||||
|
|
|
|||
137
src/vm.rs
137
src/vm.rs
|
|
@ -1,14 +1,17 @@
|
|||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, Error};
|
||||
|
||||
use crate::class::{AttributeType, Class, Value};
|
||||
use crate::class::Value::Void;
|
||||
use crate::classloader::{load_class, CpEntry};
|
||||
use crate::heap::{Heap, Object};
|
||||
use crate::io::*;
|
||||
use crate::opcodes::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct StackFrame {
|
||||
data: Vec<Arc<Value>>,
|
||||
}
|
||||
|
|
@ -27,29 +30,43 @@ impl StackFrame {
|
|||
}
|
||||
}
|
||||
|
||||
/// single threaded vm
|
||||
pub struct Vm {
|
||||
classpath: Vec<String>,
|
||||
classes: HashMap<String, Arc<Class>>,
|
||||
//TODO implement classloader
|
||||
heap: Heap,
|
||||
pub exitcode: i32,
|
||||
stack: Vec<StackFrame>,
|
||||
}
|
||||
|
||||
const CP_SEP: char = ':';
|
||||
//TODO semicolon on windows
|
||||
|
||||
impl Vm {
|
||||
fn local_stack(&mut self) -> &mut StackFrame {
|
||||
let i = self.stack.len() - 1;
|
||||
self.stack.get_mut(i).unwrap()
|
||||
}
|
||||
|
||||
pub fn new(classpath: &'static str) -> Self {
|
||||
Self {
|
||||
classpath: classpath.split(':').map(|s| s.to_owned()).collect(),
|
||||
classpath: classpath.split(CP_SEP).map(|s| s.to_owned()).collect(),
|
||||
classes: HashMap::new(),
|
||||
heap: Heap::new(),
|
||||
exitcode: 0,
|
||||
stack: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// parse the binary data into a Class struct
|
||||
/// gets the file from cache, or reads it from classpath
|
||||
/// Vm keeps ownership of the class and hands out Arc references to it
|
||||
pub fn get_class(&mut self, class_name: &str) -> Result<Arc<Class>, Error> {
|
||||
println!("get_class {}", class_name);
|
||||
let entry = self.classes.entry(class_name.into());
|
||||
let entry = entry.or_insert_with(|| {
|
||||
print!("read class {} ", class_name);
|
||||
let resolved_path = find_class(&self.classpath, class_name).expect("Class not found");
|
||||
let bytecode = read_class_file(resolved_path).unwrap();
|
||||
println!("full path {}", resolved_path);
|
||||
let bytecode = read_bytecode(resolved_path).unwrap();
|
||||
Arc::new(load_class(bytecode).unwrap())
|
||||
});
|
||||
Ok(entry.clone())
|
||||
|
|
@ -74,16 +91,20 @@ impl Vm {
|
|||
Object::new(class.clone(), data)
|
||||
}
|
||||
|
||||
/// execute the bytecode
|
||||
pub fn execute(
|
||||
&mut self,
|
||||
class_name: &str,
|
||||
method_name: &str,
|
||||
instance: Option<Arc<Object>>,
|
||||
instance: Option<Arc<Value>>,
|
||||
) -> Result<Arc<Value>, Error> {
|
||||
println!("execute {}.{}", class_name, method_name);
|
||||
let class = self.get_class(class_name)?;
|
||||
let method = class.get_method(method_name)?;
|
||||
if let AttributeType::Code(code) = method.attributes.get("Code").unwrap() {
|
||||
let mut stack = StackFrame::new();
|
||||
let stackframe = StackFrame::new();
|
||||
self.stack.push(stackframe);
|
||||
|
||||
let mut pc: usize = 0;
|
||||
while pc < code.opcodes.len() {
|
||||
let opcode = &code.opcodes[pc];
|
||||
|
|
@ -92,17 +113,17 @@ impl Vm {
|
|||
match opcode {
|
||||
BIPUSH => {
|
||||
let c = code.opcodes[pc] as i32;
|
||||
stack.push(Arc::new(Value::I32(c)));
|
||||
self.local_stack().push(Arc::new(Value::I32(c)));
|
||||
pc += 1;
|
||||
}
|
||||
LDC => {
|
||||
let cp_index = read_u8(&code.opcodes, pc) as u16;
|
||||
match method.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Integer(i) => {
|
||||
stack.push(Arc::new(Value::I32(*i)));
|
||||
self.local_stack().push(Arc::new(Value::I32(*i)));
|
||||
}
|
||||
CpEntry::Float(f) => {
|
||||
stack.push(Arc::new(Value::F32(*f)));
|
||||
self.local_stack().push(Arc::new(Value::F32(*f)));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -112,10 +133,10 @@ impl Vm {
|
|||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
match method.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Integer(i) => {
|
||||
stack.push(Arc::new(Value::I32(*i)));
|
||||
self.local_stack().push(Arc::new(Value::I32(*i)));
|
||||
}
|
||||
CpEntry::Float(f) => {
|
||||
stack.push(Arc::new(Value::F32(*f)));
|
||||
self.local_stack().push(Arc::new(Value::F32(*f)));
|
||||
}
|
||||
_ => {
|
||||
panic!("unexpected")
|
||||
|
|
@ -127,10 +148,10 @@ impl Vm {
|
|||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
match method.constant_pool.get(&cp_index).unwrap() {
|
||||
CpEntry::Double(d) => {
|
||||
stack.push(Arc::new(Value::F64(*d)));
|
||||
self.local_stack().push(Arc::new(Value::F64(*d)));
|
||||
}
|
||||
CpEntry::Long(l) => {
|
||||
stack.push(Arc::new(Value::I64(*l)));
|
||||
self.local_stack().push(Arc::new(Value::I64(*l)));
|
||||
}
|
||||
_ => {
|
||||
panic!("unexpected")
|
||||
|
|
@ -139,66 +160,80 @@ impl Vm {
|
|||
|
||||
pc += 2;
|
||||
}
|
||||
ALOAD_0 => match instance.clone() {
|
||||
Some(r) => {
|
||||
stack.push(Arc::new(Value::Ref(r)));
|
||||
ALOAD_0 => {
|
||||
println!("ALOAD_0");
|
||||
match instance.clone() {
|
||||
Some(instance) => {
|
||||
self.local_stack().push(instance);
|
||||
}
|
||||
None => {
|
||||
panic!("static context")
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
DUP => {
|
||||
println!("DUP");
|
||||
let value = stack.pop().expect("Stack empty");
|
||||
stack.push(value.clone());
|
||||
stack.push(value);
|
||||
let value = self.local_stack().pop().expect("Stack empty");
|
||||
self.local_stack().push(value.clone());
|
||||
self.local_stack().push(value);
|
||||
}
|
||||
IRETURN => {
|
||||
return stack.pop();
|
||||
return self.local_stack().pop();
|
||||
}
|
||||
DRETURN => {
|
||||
return stack.pop();
|
||||
return self.local_stack().pop();
|
||||
}
|
||||
FRETURN => {
|
||||
return stack.pop();
|
||||
return self.local_stack().pop();
|
||||
}
|
||||
RETURN_VOID => {
|
||||
self.stack.pop();
|
||||
return Ok(Arc::new(Void))
|
||||
}
|
||||
GETFIELD => {
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
if let CpEntry::Fieldref(_class_index, name_and_type_index) =
|
||||
method.constant_pool.get(&cp_index).unwrap()
|
||||
{
|
||||
if let Value::Ref(inst) = &*stack.pop()? {
|
||||
if let Value::Ref(inst) = &*self.local_stack().pop()? {
|
||||
//TODO smell?
|
||||
if let CpEntry::NameAndType(name, _) =
|
||||
method.constant_pool.get(name_and_type_index).unwrap()
|
||||
{
|
||||
let value = inst.data.get(name).unwrap();
|
||||
// println!("{:?}", value);
|
||||
stack.push(value.clone());
|
||||
self.local_stack().push(value.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
pc += 2;
|
||||
}
|
||||
INVOKEVIRTUAL =>{
|
||||
//TODO implement
|
||||
}
|
||||
INVOKESPECIAL => {
|
||||
let ref_index = read_u16(&code.opcodes, pc);
|
||||
if let CpEntry::MethodRef(_class_index, name_and_type_index) =
|
||||
method.constant_pool.get(&ref_index).unwrap()
|
||||
{}
|
||||
println!("INVOKESPECIAL");
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
let instance = self.local_stack().pop().unwrap();
|
||||
if let Some((class, method)) = get_signature_for_invoke(Rc::clone(&method.constant_pool), cp_index) {
|
||||
self.execute(class.as_str(), method.as_str(), Some(instance));
|
||||
}
|
||||
|
||||
pc += 2;
|
||||
}
|
||||
NEW => {
|
||||
println!("new");
|
||||
let cp_index = read_u16(&code.opcodes, pc);
|
||||
let class_index = read_u16(&code.opcodes, pc);
|
||||
println!("cp_index {}", class_index);
|
||||
if let CpEntry::ClassRef(class_name_index) =
|
||||
method.constant_pool.get(&cp_index).unwrap()
|
||||
method.constant_pool.get(&class_index).unwrap()
|
||||
{
|
||||
if let CpEntry::Utf8(_) =
|
||||
if let CpEntry::Utf8(new_class) =
|
||||
method.constant_pool.get(class_name_index).unwrap()
|
||||
{
|
||||
let class = self.get_class(class_name)?;
|
||||
println!("new {}", new_class);
|
||||
let class = self.get_class(new_class)?;
|
||||
let object = Arc::new(self.new_instance(class));
|
||||
stack.push(Arc::new(Value::Ref(object.clone())));
|
||||
self.local_stack().push(Arc::new(Value::Ref(object.clone())));
|
||||
self.heap.new_object(object);
|
||||
}
|
||||
}
|
||||
|
|
@ -206,7 +241,7 @@ impl Vm {
|
|||
}
|
||||
//TODO implement all opcodes
|
||||
_ => {
|
||||
panic!("opcode not implemented")
|
||||
panic!("opcode not implemented {:?}", self.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -214,3 +249,31 @@ impl Vm {
|
|||
Err(anyhow!("should not happen"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//TODO refs with lifetime
|
||||
fn get_signature_for_invoke(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<(String, String)> {
|
||||
if let CpEntry::MethodRef(class_index, name_and_type_index) = cp.get(&index).unwrap() {
|
||||
if let Some(method_signature) = get_name_and_type(Rc::clone(&cp), *name_and_type_index) {
|
||||
if let CpEntry::ClassRef(class_name_index) = cp.get(&class_index).unwrap() {
|
||||
if let CpEntry::Utf8(class_name) = cp.get(&class_name_index).unwrap() {
|
||||
return Some((class_name.into(), method_signature));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_name_and_type(cp: Rc<HashMap<u16, CpEntry>>, index: u16) -> Option<(String)> {
|
||||
if let CpEntry::NameAndType(method_name_index, signature_index) = cp.get(&index).unwrap() {
|
||||
if let CpEntry::Utf8(method_name) = cp.get(&method_name_index).unwrap() {
|
||||
if let CpEntry::Utf8(signature) = cp.get(&signature_index).unwrap() {
|
||||
let mut method_signature: String = method_name.into();
|
||||
method_signature.push_str(signature);
|
||||
return Some(method_signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue