├── NestLoop.gif
├── fizzbuzz.gif
├── src
├── attribute.rs
├── order.rs
├── option.rs
├── stackframe.rs
├── java_class.rs
├── bin
│ └── main.rs
├── string_pool.rs
├── array.rs
├── wasm.rs
├── lib.rs
├── object.rs
├── java_class
│ ├── default.rs
│ ├── builtin.rs
│ └── custom.rs
├── attribute
│ ├── code.rs
│ ├── defs.rs
│ └── instruction.rs
├── utils.rs
├── field.rs
├── method.rs
├── operand.rs
└── constant.rs
├── memo.md
├── tests
├── class
│ ├── Field.class
│ ├── Switch.class
│ ├── DconstN.class
│ ├── FizzBuzz.class
│ ├── FizzBuzz2.class
│ ├── LongArray.class
│ ├── NestFor.class
│ ├── CustomArray.class
│ ├── HelloWorld.class
│ ├── MinusInt30.class
│ ├── OtherClass.class
│ ├── FloatCulculate.class
│ ├── InstanceField.class
│ ├── LongCulculate.class
│ ├── NestForElement.class
│ ├── PrimitiveArray.class
│ ├── PrintMessage.class
│ ├── InitializeStatic.class
│ ├── ArrayElementClass.class
│ ├── CallInstanceMethod.class
│ ├── SimpleMultiDimentions.class
│ ├── NewAndCallInstanceMethod.class
│ └── CustomMultiDimentionArray.class
├── original
│ ├── LongCulculate.java
│ ├── MinusInt30.java
│ ├── DconstN.java
│ ├── PrimitiveArray.java
│ ├── SimpleMultiDimentions.java
│ ├── LongArray.java
│ ├── FloatCulculate.java
│ ├── CustomArray.java
│ ├── InitializeStatic.java
│ ├── Switch.java
│ ├── CustomMultiDimentionArray.java
│ ├── InstanceField.java
│ ├── NewAndCallInstanceMethod.java
│ └── NestFor.java
└── test.rs
├── .gitignore
├── web
├── index.html
├── map.js
├── index.js
├── Result.vue
├── package.json
├── webpack.config.js
├── App.vue
└── Setting.vue
├── .vscode
└── launch.json
├── .travis.yml
├── Cargo.toml
├── README.md
└── Cargo.lock
/NestLoop.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/NestLoop.gif
--------------------------------------------------------------------------------
/fizzbuzz.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/fizzbuzz.gif
--------------------------------------------------------------------------------
/src/attribute.rs:
--------------------------------------------------------------------------------
1 | pub mod code;
2 | pub mod defs;
3 | pub mod instruction;
4 |
--------------------------------------------------------------------------------
/memo.md:
--------------------------------------------------------------------------------
1 | ```
2 | javap -v x.class
3 | javac xxx.java
4 | ```
5 |
6 | - 0xED to rewrite binary
7 |
--------------------------------------------------------------------------------
/tests/class/Field.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/Field.class
--------------------------------------------------------------------------------
/tests/class/Switch.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/Switch.class
--------------------------------------------------------------------------------
/tests/class/DconstN.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/DconstN.class
--------------------------------------------------------------------------------
/tests/class/FizzBuzz.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/FizzBuzz.class
--------------------------------------------------------------------------------
/tests/class/FizzBuzz2.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/FizzBuzz2.class
--------------------------------------------------------------------------------
/tests/class/LongArray.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/LongArray.class
--------------------------------------------------------------------------------
/tests/class/NestFor.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/NestFor.class
--------------------------------------------------------------------------------
/tests/class/CustomArray.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/CustomArray.class
--------------------------------------------------------------------------------
/tests/class/HelloWorld.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/HelloWorld.class
--------------------------------------------------------------------------------
/tests/class/MinusInt30.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/MinusInt30.class
--------------------------------------------------------------------------------
/tests/class/OtherClass.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/OtherClass.class
--------------------------------------------------------------------------------
/tests/class/FloatCulculate.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/FloatCulculate.class
--------------------------------------------------------------------------------
/tests/class/InstanceField.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/InstanceField.class
--------------------------------------------------------------------------------
/tests/class/LongCulculate.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/LongCulculate.class
--------------------------------------------------------------------------------
/tests/class/NestForElement.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/NestForElement.class
--------------------------------------------------------------------------------
/tests/class/PrimitiveArray.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/PrimitiveArray.class
--------------------------------------------------------------------------------
/tests/class/PrintMessage.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/PrintMessage.class
--------------------------------------------------------------------------------
/tests/class/InitializeStatic.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/InitializeStatic.class
--------------------------------------------------------------------------------
/tests/class/ArrayElementClass.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/ArrayElementClass.class
--------------------------------------------------------------------------------
/tests/class/CallInstanceMethod.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/CallInstanceMethod.class
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | **/*.rs.bk
3 | *.java
4 | *.class
5 | !tests/class/*.class
6 | !tests/original/*.java
7 |
8 | node_modules
--------------------------------------------------------------------------------
/tests/class/SimpleMultiDimentions.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/SimpleMultiDimentions.class
--------------------------------------------------------------------------------
/tests/class/NewAndCallInstanceMethod.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/NewAndCallInstanceMethod.class
--------------------------------------------------------------------------------
/tests/class/CustomMultiDimentionArray.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rchaser53/rust-jvm/HEAD/tests/class/CustomMultiDimentionArray.class
--------------------------------------------------------------------------------
/tests/original/LongCulculate.java:
--------------------------------------------------------------------------------
1 | public class LongCulculate {
2 | public static void main(String[] args) {
3 | long a = -1;
4 | System.out.println(a * -3);
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/tests/original/MinusInt30.java:
--------------------------------------------------------------------------------
1 | public class MinusInt30 {
2 | public static void main(String[] args) {
3 | int a = -30;
4 | System.out.println(a); // 1.0
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/tests/original/DconstN.java:
--------------------------------------------------------------------------------
1 | public class DconstN {
2 | public static void main(String[] args) {
3 | double a = 1D;
4 | double b = 0D;
5 | System.out.println(a);
6 | System.out.println(b);
7 | }
8 | }
--------------------------------------------------------------------------------
/tests/original/PrimitiveArray.java:
--------------------------------------------------------------------------------
1 | public class PrimitiveArray {
2 | public static void main(String[] args){
3 | int foo[] = new int[3];
4 | foo[1] = 100;
5 | System.out.println(foo[1]);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tests/original/SimpleMultiDimentions.java:
--------------------------------------------------------------------------------
1 | public class SimpleMultiDimentions {
2 | public static void main(String[] args){
3 | int[] foo[] = new int [4][3];
4 | foo[2][1] = 5;
5 | System.out.println(foo[2][1]);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%= htmlWebpackPlugin.options.title %>
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/original/LongArray.java:
--------------------------------------------------------------------------------
1 | public class LongArray {
2 | public static void main(String[] args){
3 | long funyan[] = { 1, 2, 3, 4, 5 };
4 | funyan[1] = 12;
5 | System.out.println(funyan[1]);
6 | System.out.println(funyan[2]);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "configurations": [
3 | {
4 | "type": "java",
5 | "name": "CodeLens (Launch) - InitializeStatic",
6 | "request": "launch",
7 | "mainClass": "InitializeStatic",
8 | "projectName": "r-jvm_11c22782"
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/tests/original/FloatCulculate.java:
--------------------------------------------------------------------------------
1 | public class FloatCulculate {
2 | public static void main(String[] args) {
3 | float a = - 1.2F;
4 | System.out.println(a * 2);
5 | System.out.println(a / 3);
6 | System.out.println(a + 4);
7 | System.out.println(a - 5);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: rust
2 | cache: cargo
3 |
4 | matrix:
5 | include:
6 | - os: linux
7 | rust: nightly
8 |
9 | - os: osx
10 | rust: nightly
11 |
12 | script:
13 | - cargo check
14 | - cargo test -- --test-threads=1
15 |
16 | branches:
17 | only:
18 | - master
19 |
20 | notifications:
21 | email: false
--------------------------------------------------------------------------------
/web/map.js:
--------------------------------------------------------------------------------
1 | export function get_file_content_from_js(key) {
2 | const value = window.map[key];
3 | if (value == null) {
4 | console.error(`${key} is not found. upload ${key}`);
5 | return [];
6 | }
7 | return window.map[key];
8 | }
9 |
10 | export function output_log(value) {
11 | console.log(value);
12 | window.output.push(value);
13 | }
14 |
--------------------------------------------------------------------------------
/tests/original/CustomArray.java:
--------------------------------------------------------------------------------
1 | public class CustomArray {
2 | public static void main(String[] args){
3 | ArrayElementClass foo[] = new ArrayElementClass[3];
4 | foo[0] = new ArrayElementClass(1);
5 | System.out.println(foo[0].a);
6 | }
7 | }
8 |
9 | class ArrayElementClass {
10 | int a;
11 | ArrayElementClass(int input) {
12 | a = input;
13 | }
14 | }
--------------------------------------------------------------------------------
/tests/original/InitializeStatic.java:
--------------------------------------------------------------------------------
1 | public class InitializeStatic {
2 | static int sa = 3;
3 | public static void main(String[] args){
4 | System.out.println(InitializeStatic.sa + OtherClass.sb);
5 | InitializeStatic.sa = 5;
6 | OtherClass.sb += 1;
7 | System.out.println(InitializeStatic.sa + OtherClass.sb);
8 | }
9 | }
10 |
11 | class OtherClass {
12 | static int sb = 4;
13 | }
--------------------------------------------------------------------------------
/tests/original/Switch.java:
--------------------------------------------------------------------------------
1 | public class Switch {
2 | public static void main(String[] args){
3 | int i = 1;
4 | switch (i) {
5 | case 1:
6 | System.out.println("abc");
7 | break;
8 | case 2:
9 | System.out.println("def");
10 | break;
11 | default:
12 | System.out.println("def");
13 | break;
14 | }
15 | }
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/src/order.rs:
--------------------------------------------------------------------------------
1 | use crate::operand::Item;
2 |
3 | #[derive(Debug)]
4 | pub struct Order {
5 | pub opecode: Opecode,
6 | pub operand: Item,
7 | }
8 | impl Order {
9 | pub fn new(opecode: Opecode, operand: Item) -> Order {
10 | Order { opecode, operand }
11 | }
12 | }
13 |
14 | #[derive(Debug)]
15 | pub enum Opecode {
16 | Iadd,
17 | Iconst,
18 | Ireturn,
19 | IfIcmple,
20 | }
21 |
--------------------------------------------------------------------------------
/tests/original/CustomMultiDimentionArray.java:
--------------------------------------------------------------------------------
1 | public class CustomMultiDimentionArray {
2 | public static void main(String[] args){
3 | ArrayElementClass[] foo[] = new ArrayElementClass[3][4];
4 | foo[1][2] = new ArrayElementClass(11);
5 | System.out.println(foo[1][2].a);
6 | }
7 | }
8 |
9 | class ArrayElementClass {
10 | int a;
11 | ArrayElementClass(int input) {
12 | a = input;
13 | }
14 | }
--------------------------------------------------------------------------------
/tests/original/InstanceField.java:
--------------------------------------------------------------------------------
1 | public class InstanceField {
2 | public static void main(String[] args){
3 | Field fa = new Field(1);
4 | fa.xxxx = 12;
5 | System.out.println(fa.xxxx);
6 |
7 | Field fb = new Field(2);
8 | fb.xxxx = 13;
9 | System.out.println(fb.xxxx);
10 | }
11 | }
12 |
13 | class Field {
14 | int xxxx;
15 | public Field(int a) {
16 | xxxx = a;
17 | System.out.println(xxxx);
18 | }
19 | }
--------------------------------------------------------------------------------
/tests/original/NewAndCallInstanceMethod.java:
--------------------------------------------------------------------------------
1 | public class NewAndCallInstanceMethod {
2 | public static void main(String[] args){
3 | CallInstanceMethod a = new CallInstanceMethod();
4 | a.abc();
5 | System.out.println(">>> created");
6 | }
7 | }
8 |
9 | class CallInstanceMethod {
10 | CallInstanceMethod() {
11 | System.out.println(">>> constructor");
12 | }
13 |
14 | void abc() {
15 | System.out.println(">>> abc");
16 | }
17 | }
--------------------------------------------------------------------------------
/src/option.rs:
--------------------------------------------------------------------------------
1 | use std::sync::Mutex;
2 |
3 | /**
4 | * 0: no info
5 | * 1: emit instruction
6 | * 2: emit instruction + operandstack
7 | */
8 | #[derive(Debug)]
9 | pub struct RjOption {
10 | pub debug_mode: usize,
11 | }
12 |
13 | impl RjOption {
14 | pub fn new() -> RjOption {
15 | RjOption { debug_mode: 0 }
16 | }
17 | }
18 |
19 | lazy_static! {
20 | pub static ref RJ_OPTION: Mutex = Mutex::new(RjOption::new());
21 | }
22 |
--------------------------------------------------------------------------------
/src/stackframe.rs:
--------------------------------------------------------------------------------
1 | use crate::operand::{Item, OperandStack};
2 |
3 | #[derive(Debug)]
4 | pub struct Stackframe {
5 | pub local_variables: Vec- ,
6 | pub operand_stack: OperandStack,
7 | }
8 |
9 | impl Stackframe {
10 | pub fn new(variables_number: usize) -> Self {
11 | Stackframe {
12 | local_variables: Vec::with_capacity(variables_number),
13 | operand_stack: OperandStack::new(),
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/java_class.rs:
--------------------------------------------------------------------------------
1 | pub mod builtin;
2 | pub mod custom;
3 | pub mod default;
4 |
5 | #[derive(Debug)]
6 | pub enum JavaClass {
7 | BuiltIn(builtin::BuiltIn),
8 | Custom(custom::Custom),
9 | }
10 |
11 | impl JavaClass {
12 | pub fn this_class_name(&self) -> usize {
13 | match self {
14 | JavaClass::BuiltIn(builtin) => builtin.class_name,
15 | JavaClass::Custom(custom) => custom.this_class_name(),
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/web/index.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import App from "./App.vue";
3 |
4 | window.map = {};
5 | window.output = [];
6 | window.onload = async () => {
7 | const rust = await import("./pkg");
8 |
9 | new Vue({
10 | el: "#app",
11 | components: {
12 | App
13 | },
14 | data() {
15 | return {
16 | entryFileName: "",
17 | fileNames: []
18 | };
19 | },
20 | template: ``,
21 | computed: {
22 | rust() {
23 | return rust;
24 | },
25 | window() {
26 | return window;
27 | }
28 | }
29 | });
30 | };
31 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "r-jvm"
3 | version = "0.1.0"
4 | authors = ["rchaser53 "]
5 | edition = "2018"
6 |
7 | [dependencies]
8 | clap = "2.33.0"
9 | console_error_panic_hook = "0.1.6"
10 | lazy_static = "1.4.0"
11 | wasm-bindgen = "0.2.55"
12 |
13 | [dependencies.web-sys]
14 | version = "0.3.32"
15 | features = [
16 | 'CssStyleDeclaration',
17 | 'Document',
18 | 'Element',
19 | 'HtmlElement',
20 | 'EventTarget',
21 | 'Node',
22 | 'Window',
23 | 'console'
24 | ]
25 |
26 | [dependencies.js-sys]
27 | version = "0.3.32"
28 |
29 | [[bin]]
30 | name = "rj"
31 | path = "src/bin/main.rs"
32 |
33 | [[test]]
34 | name = "test"
35 | harness = false
36 |
37 | [lib]
38 | crate-type = ["cdylib", "lib"]
--------------------------------------------------------------------------------
/tests/original/NestFor.java:
--------------------------------------------------------------------------------
1 | public class NestFor {
2 | public static void main(String[] args){
3 | int i = 5;
4 | int j = 6;
5 | int count = 0;
6 | NestForElement[] foo[] = new NestForElement[i][j];
7 | for (int ii=0; ii
2 |
8 |
9 |
10 |
19 |
20 |
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # How to play
4 |
5 | ```sh
6 | $ cargo run --bin rj -- ClassName
7 | ```
8 |
9 | # Play on Browser
10 |
11 | rust-jvm can be used on browser using wasm.
12 |
13 | ```sh
14 | $ cd ./web
15 | $ npm i
16 | $ npm run serve
17 | ```
18 |
19 | ## dependencies
20 |
21 | you need to install below to play rust-jvm using wasm.
22 |
23 | - [node](https://nodejs.org/ja/download/)
24 | - [rust](https://www.rust-lang.org/tools/install)
25 | - [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/)
26 |
27 | ## Demo
28 |
29 | ## FizzBuzz on Wasm
30 |
31 |
32 | ## Creating Instance + Nested Array on Cli
33 |
34 |
--------------------------------------------------------------------------------
/src/bin/main.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 | use clap::{App, Arg};
3 |
4 | use r_jvm;
5 |
6 | fn main() {
7 | let matches = App::new("rj")
8 | .version("0.1")
9 | .author("rchaser53 ")
10 | .about("toy jvm implemented by Rust")
11 | .arg(
12 | Arg::with_name("debug")
13 | .help("emits the debug information")
14 | .long("debug")
15 | .takes_value(true),
16 | )
17 | .args_from_usage(
18 | "
19 | 'Sets the input file to use'",
20 | )
21 | .get_matches();
22 |
23 | if let Some(file_name) = matches.value_of("INPUT") {
24 | r_jvm::execute(
25 | file_name.to_string(),
26 | matches
27 | .value_of("debug")
28 | .unwrap_or("0")
29 | .parse::()
30 | .unwrap_or(0),
31 | );
32 | } else {
33 | println!("should input the file");
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/string_pool.rs:
--------------------------------------------------------------------------------
1 | use std::collections::HashMap;
2 |
3 | pub struct StringPool {
4 | pub id: usize,
5 | pub key_value_map: HashMap,
6 | pub value_key_map: HashMap,
7 | }
8 |
9 | impl StringPool {
10 | pub fn new() -> StringPool {
11 | StringPool {
12 | id: 0,
13 | key_value_map: HashMap::new(),
14 | value_key_map: HashMap::new(),
15 | }
16 | }
17 |
18 | pub fn insert(&mut self, value: String) -> usize {
19 | if let Some(id) = self.value_key_map.get(&value) {
20 | return *id;
21 | }
22 |
23 | let id = self.id;
24 | self.id += 1;
25 |
26 | self.value_key_map.insert(value.clone(), id);
27 | self.key_value_map.insert(id, value);
28 |
29 | id
30 | }
31 |
32 | pub fn get_value(&self, id: &usize) -> String {
33 | self.key_value_map
34 | .get(id)
35 | .expect("exist string in string_pool")
36 | .to_string()
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/web/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rj",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "format": "prettier --write \"**/*.{md,js,ts,vue,json}\"",
8 | "serve": "webpack-dev-server"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/rchaser53/rj.git"
13 | },
14 | "keywords": [],
15 | "author": "rchaser53",
16 | "license": "MIT",
17 | "bugs": {
18 | "url": "https://github.com/rchaser53/rj/issues"
19 | },
20 | "homepage": "https://github.com/rchaser53/rj#readme",
21 | "dependencies": {
22 | "@wasm-tool/wasm-pack-plugin": "1.0.1",
23 | "css-loader": "^3.2.1",
24 | "html-webpack-plugin": "^3.2.0",
25 | "node-sass": "^4.13.0",
26 | "prettier": "^1.19.1",
27 | "sass-loader": "^8.0.0",
28 | "serialize-javascript": ">=3.1.0",
29 | "style-loader": "^1.0.1",
30 | "text-encoding": "^0.7.0",
31 | "vue": "^2.6.10",
32 | "vue-loader": "^15.7.2",
33 | "vue-style-loader": "^4.1.2",
34 | "vue-template-compiler": "^2.6.10",
35 | "webpack": "^4.41.2",
36 | "webpack-cli": "^3.3.10",
37 | "webpack-dev-server": "^3.9.0"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/tests/test.rs:
--------------------------------------------------------------------------------
1 | use r_jvm;
2 |
3 | fn test_helper(file_name: String) {
4 | println!("** {} **", &file_name);
5 | r_jvm::execute(file_name, 0);
6 | println!("");
7 | }
8 |
9 | fn main() {
10 | test_helper(String::from("tests/class/HelloWorld"));
11 | test_helper(String::from("tests/class/FizzBuzz"));
12 | test_helper(String::from("tests/class/FizzBuzz2"));
13 | test_helper(String::from("tests/class/NewAndCallInstanceMethod"));
14 | test_helper(String::from("tests/class/InitializeStatic"));
15 | test_helper(String::from("tests/class/Switch"));
16 | test_helper(String::from("tests/class/InstanceField"));
17 | test_helper(String::from("tests/class/PrimitiveArray"));
18 | test_helper(String::from("tests/class/CustomArray"));
19 | test_helper(String::from("tests/class/SimpleMultiDimentions"));
20 | test_helper(String::from("tests/class/CustomMultiDimentionArray"));
21 | test_helper(String::from("tests/class/NestFor"));
22 | test_helper(String::from("tests/class/LongArray"));
23 | test_helper(String::from("tests/class/MinusInt30"));
24 | test_helper(String::from("tests/class/LongCulculate"));
25 | test_helper(String::from("tests/class/FloatCulculate"));
26 | test_helper(String::from("tests/class/DconstN"));
27 | }
28 |
--------------------------------------------------------------------------------
/src/array.rs:
--------------------------------------------------------------------------------
1 | use crate::operand::Item;
2 |
3 | use std::cell::RefCell;
4 | use std::collections::HashMap;
5 | use std::fmt;
6 |
7 | #[derive(Debug)]
8 | pub struct ArrayMap {
9 | pub id: usize,
10 | pub map: HashMap,
11 | }
12 | impl ArrayMap {
13 | pub fn new() -> ArrayMap {
14 | ArrayMap {
15 | id: 0,
16 | map: HashMap::new(),
17 | }
18 | }
19 |
20 | pub fn add(&mut self, value: Array) -> usize {
21 | let id = self.id;
22 | self.id += 1;
23 | self.map.insert(id, value);
24 | id
25 | }
26 |
27 | pub fn get(&self, id: &usize) -> Option<&Array> {
28 | self.map.get(id)
29 | }
30 |
31 | pub fn get_mut(&mut self, id: &usize) -> Option<&mut Array> {
32 | self.map.get_mut(id)
33 | }
34 | }
35 |
36 | #[derive(Debug)]
37 | pub enum PrimitiveArrayType {
38 | TBoolean = 4,
39 | TChar = 5,
40 | TFloat = 6,
41 | TDouble = 7,
42 | TByte = 8,
43 | TShort = 9,
44 | TInt = 10,
45 | TLong = 11,
46 | }
47 |
48 | #[derive(Clone, Debug)]
49 | pub enum Array {
50 | Primitive(RefCell>),
51 | Array(RefCell>),
52 | Custom(RefCell>),
53 | }
54 |
55 | impl fmt::Display for Array {
56 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 | write!(f, "")
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/web/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | const HtmlWebpackPlugin = require("html-webpack-plugin");
4 | const { VueLoaderPlugin } = require("vue-loader");
5 |
6 | const webpack = require("webpack");
7 | const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
8 |
9 | module.exports = {
10 | entry: "./index.js",
11 | output: {
12 | path: path.resolve(__dirname, "dist"),
13 | filename: "index.js"
14 | },
15 | resolve: {
16 | alias: {
17 | vue$: "vue/dist/vue.esm.js"
18 | }
19 | },
20 | plugins: [
21 | new HtmlWebpackPlugin({
22 | template: path.resolve(__dirname, "index.html")
23 | }),
24 | new WasmPackPlugin({
25 | crateDirectory: path.resolve(__dirname, ".."),
26 | outDir: path.resolve(__dirname, "./pkg")
27 | }),
28 | new webpack.ProvidePlugin({
29 | TextDecoder: ["text-encoding", "TextDecoder"],
30 | TextEncoder: ["text-encoding", "TextEncoder"]
31 | }),
32 | new VueLoaderPlugin()
33 | ],
34 | module: {
35 | rules: [
36 | {
37 | test: /\.vue$/,
38 | loader: "vue-loader",
39 | options: {
40 | esModule: true
41 | }
42 | },
43 | {
44 | test: /\.css$/,
45 | use: [
46 | "vue-style-loader",
47 | {
48 | loader: "css-loader"
49 | }
50 | ]
51 | }
52 | ]
53 | },
54 | mode: "development",
55 | devServer: {
56 | open: true,
57 | }
58 | };
59 |
--------------------------------------------------------------------------------
/src/wasm.rs:
--------------------------------------------------------------------------------
1 | #[cfg(unix)]
2 | use crate::utils::read_file;
3 |
4 | #[allow(unused_imports)]
5 | use wasm_bindgen::prelude::*;
6 |
7 | #[cfg(target_arch = "wasm32")]
8 | #[wasm_bindgen]
9 | extern "C" {
10 | pub fn alert(s: &str);
11 |
12 | #[wasm_bindgen(js_namespace = console)]
13 | pub fn log(s: &str);
14 |
15 | #[wasm_bindgen(js_namespace = console, js_name = log)]
16 | pub fn log_u8_array(a: &[u8]);
17 |
18 | #[wasm_bindgen(js_namespace = console, js_name = log)]
19 | pub fn log_u32(a: u32);
20 |
21 | #[wasm_bindgen(js_namespace = console, js_name = log)]
22 | pub fn log_u16(a: u16);
23 | }
24 |
25 | #[cfg(target_arch = "wasm32")]
26 | #[wasm_bindgen(module = "/web/map.js")]
27 | extern "C" {
28 | pub fn get_file_content_from_js(key: &str) -> Vec;
29 | pub fn output_log(key: &str);
30 | }
31 |
32 | #[cfg(target_arch = "wasm32")]
33 | #[wasm_bindgen]
34 | pub fn get_file_content(key: &str) -> Vec {
35 | let val = get_file_content_from_js(key);
36 | if val.len() == 0 {
37 | panic!("undefined value come. cannot continue")
38 | }
39 | val
40 | }
41 |
42 | #[cfg(unix)]
43 | pub fn get_file_content(key: &str) -> Vec {
44 | read_file(&key).expect(&format!(
45 | "need to add handler for the case failed to find the class file: {}",
46 | &key
47 | ))
48 | }
49 |
50 | #[cfg(unix)]
51 | pub fn print_log(value: &str) {
52 | println!("{}", value);
53 | }
54 |
55 | #[cfg(target_arch = "wasm32")]
56 | #[wasm_bindgen]
57 | pub fn print_log(value: &str) {
58 | output_log(value);
59 | }
60 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![feature(exclusive_range_pattern)]
2 | #![allow(dead_code)]
3 |
4 | mod array;
5 | mod attribute;
6 | mod constant;
7 | mod context;
8 | mod field;
9 | mod java_class;
10 | mod method;
11 | mod object;
12 | mod operand;
13 | mod option;
14 | mod order;
15 | mod stackframe;
16 | mod string_pool;
17 | mod utils;
18 | mod wasm;
19 |
20 | use crate::context::Context;
21 | use crate::java_class::{custom::Custom, default::setup_class_map};
22 | use crate::string_pool::StringPool;
23 |
24 | use crate::option::RJ_OPTION;
25 | use crate::wasm::get_file_content;
26 |
27 | #[allow(unused_imports)]
28 | use wasm_bindgen::prelude::*;
29 |
30 | use std::path::Path;
31 |
32 | #[macro_use]
33 | extern crate lazy_static;
34 |
35 | pub fn execute(file_name: String, debug_mode: usize) {
36 | RJ_OPTION.lock().unwrap().debug_mode = debug_mode;
37 | let class_name = file_name + ".class";
38 | let buffer = get_file_content(&class_name);
39 | let mut string_pool = StringPool::new();
40 | let (class_file, _pc_count) = Custom::new(&mut string_pool, &buffer, 0);
41 | let class_map = setup_class_map(&mut string_pool);
42 | let parent_path = if let Some(parent_path) = Path::new(&class_name).parent() {
43 | parent_path.to_str().unwrap()
44 | } else {
45 | "./"
46 | };
47 |
48 | let mut context = Context::new(&mut string_pool, class_map, &class_file, parent_path);
49 | context.run_entry_file(&mut string_pool, class_file);
50 | }
51 |
52 | #[cfg(target_arch = "wasm32")]
53 | #[wasm_bindgen]
54 | pub fn run_wasm(class_name: &str) {
55 | use console_error_panic_hook::hook;
56 | use std::panic;
57 | panic::set_hook(Box::new(hook));
58 |
59 | let mut string_pool = StringPool::new();
60 | let inputs = get_file_content(class_name);
61 | let (class_file, _pc_count) = Custom::new(&mut string_pool, &inputs, 0);
62 | let class_map = setup_class_map(&mut string_pool);
63 | let parent_path = "";
64 |
65 | let mut context = Context::new(&mut string_pool, class_map, &class_file, parent_path);
66 | context.run_entry_file(&mut string_pool, class_file);
67 | }
68 |
--------------------------------------------------------------------------------
/src/object.rs:
--------------------------------------------------------------------------------
1 | use crate::operand::Item;
2 |
3 | use std::cell::RefCell;
4 | use std::collections::HashMap;
5 | use std::fmt;
6 |
7 | #[derive(Debug)]
8 | pub struct ObjectMap {
9 | pub id: usize,
10 | pub map: HashMap,
11 | }
12 | impl ObjectMap {
13 | pub fn new() -> ObjectMap {
14 | ObjectMap {
15 | id: 0,
16 | map: HashMap::new(),
17 | }
18 | }
19 |
20 | pub fn add(&mut self, value: Objectref) -> usize {
21 | let id = self.id;
22 | self.id += 1;
23 | self.map.insert(id, value);
24 | id
25 | }
26 |
27 | pub fn get(&self, id: &usize) -> Option<&Objectref> {
28 | self.map.get(id)
29 | }
30 |
31 | pub fn get_mut(&mut self, id: &usize) -> Option<&mut Objectref> {
32 | self.map.get_mut(id)
33 | }
34 | }
35 |
36 | #[derive(PartialEq, Clone, Debug)]
37 | pub struct Objectref {
38 | pub class_name_id: usize,
39 | pub field_map: RefCell>,
40 | pub is_initialized: bool,
41 | }
42 |
43 | pub type FieldMap = RefCell>;
44 |
45 | impl Objectref {
46 | pub fn new(class_name_id: usize, field_map: FieldMap, is_initialized: bool) -> Objectref {
47 | Objectref {
48 | class_name_id,
49 | field_map,
50 | is_initialized,
51 | }
52 | }
53 | }
54 |
55 | impl fmt::Display for Objectref {
56 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 | let field_map = self.field_map.borrow();
58 | let keys = field_map.keys();
59 | let mut val_strs = Vec::with_capacity(keys.len());
60 | for key in keys {
61 | let val = field_map.get(key).unwrap();
62 | match val.1 {
63 | Item::Null => val_strs.push(format!("{}.{}: {}", key.0, key.1, val.0)),
64 | _ => val_strs.push(format!("{}.{}: {} {}", key.0, key.1, val.0, val.1)),
65 | };
66 | }
67 |
68 | write!(
69 | f,
70 | "object_ref:
71 | class {}:
72 | {}",
73 | self.class_name_id,
74 | val_strs.join("\n")
75 | )
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/web/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
14 |
15 |
72 |
73 |
114 |
--------------------------------------------------------------------------------
/src/java_class/default.rs:
--------------------------------------------------------------------------------
1 | use crate::java_class::{
2 | builtin::{BuiltIn, BuiltInMethod, BuitlInCodeType},
3 | JavaClass,
4 | };
5 | use crate::string_pool::StringPool;
6 | use std::collections::HashMap;
7 |
8 | pub fn setup_class_map(string_pool: &mut StringPool) -> HashMap {
9 | let mut class_map = HashMap::new();
10 | let (print_stream_name, print_stream) = create_print_stream(string_pool);
11 | let (java_lang_object_name, java_lang_object) = create_java_lang_object(string_pool);
12 | let (java_lang_integer_name, java_lang_integer) = create_java_lang_integer(string_pool);
13 | let (java_lang_system_name, java_lang_system) = create_java_lang_system(string_pool);
14 |
15 | class_map.insert(print_stream_name, print_stream);
16 | class_map.insert(java_lang_object_name, java_lang_object);
17 | class_map.insert(java_lang_integer_name, java_lang_integer);
18 | class_map.insert(java_lang_system_name, java_lang_system);
19 | class_map
20 | }
21 |
22 | fn create_print_stream(string_pool: &mut StringPool) -> (usize, JavaClass) {
23 | let class_name_id = string_pool.insert(String::from("java/io/PrintStream"));
24 | let mut print_stream = BuiltIn::new(class_name_id);
25 | let println_name_id = string_pool.insert(String::from("println"));
26 | let println = BuiltInMethod::new(println_name_id, BuitlInCodeType::Println);
27 | print_stream.methods.insert(println_name_id, println);
28 | (class_name_id, JavaClass::BuiltIn(print_stream))
29 | }
30 |
31 | fn create_java_lang_object(string_pool: &mut StringPool) -> (usize, JavaClass) {
32 | let java_lang_object_name_id = string_pool.insert(String::from("java/lang/Object"));
33 | let mut java_lang_object = BuiltIn::new(java_lang_object_name_id);
34 | let init_name_id = string_pool.insert(String::from(""));
35 | let init = BuiltInMethod::new(init_name_id, BuitlInCodeType::JavaLangObjectInit);
36 | java_lang_object.methods.insert(init_name_id, init);
37 | (
38 | java_lang_object_name_id,
39 | JavaClass::BuiltIn(java_lang_object),
40 | )
41 | }
42 |
43 | fn create_java_lang_system(string_pool: &mut StringPool) -> (usize, JavaClass) {
44 | let java_lang_system_name_id = string_pool.insert(String::from("java/lang/System"));
45 | let mut java_lang_system = BuiltIn::new(java_lang_system_name_id);
46 | let init_name_id = string_pool.insert(String::from(""));
47 | let init = BuiltInMethod::new(init_name_id, BuitlInCodeType::JavaLangSystemInit);
48 | java_lang_system.methods.insert(init_name_id, init);
49 | (
50 | java_lang_system_name_id,
51 | JavaClass::BuiltIn(java_lang_system),
52 | )
53 | }
54 |
55 | fn create_java_lang_integer(string_pool: &mut StringPool) -> (usize, JavaClass) {
56 | let java_lang_integer_name_id = string_pool.insert(String::from("java/lang/Integer"));
57 | let mut java_lang_integer = BuiltIn::new(java_lang_integer_name_id);
58 | let to_string_name_id = string_pool.insert(String::from("toString"));
59 | let to_string = BuiltInMethod::new(to_string_name_id, BuitlInCodeType::JavaLangObjectToString);
60 | java_lang_integer
61 | .methods
62 | .insert(to_string_name_id, to_string);
63 | (
64 | java_lang_integer_name_id,
65 | JavaClass::BuiltIn(java_lang_integer),
66 | )
67 | }
68 |
--------------------------------------------------------------------------------
/web/Setting.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | -
45 | {{ fileName }}
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
102 |
103 |
144 |
--------------------------------------------------------------------------------
/src/attribute/code.rs:
--------------------------------------------------------------------------------
1 | use crate::attribute::defs::Attribute;
2 | use crate::attribute::instruction::Instruction;
3 | use crate::constant::ConstantPool;
4 | use crate::string_pool::StringPool;
5 | use crate::utils::extract_x_byte_as_usize;
6 | use std::fmt;
7 |
8 | #[derive(Debug)]
9 | pub struct Code {
10 | pub attribute_name_index: u16, // u2
11 | pub attribute_length: u32, // u4
12 | pub max_stack: u16, // u2
13 | pub max_locals: u16, // u2
14 | pub code_length: usize, // u4
15 | pub code: Vec,
16 | pub exception_table_length: usize, // u2
17 | pub exception_table: Vec,
18 | pub attributes_count: usize, // u2
19 | pub attribute_info: Vec,
20 | }
21 |
22 | impl Code {
23 | pub fn new(
24 | string_pool: &mut StringPool,
25 | constant_pool: &ConstantPool,
26 | inputs: &[u8],
27 | index: usize,
28 | attribute_name_index: u16,
29 | ) -> (Code, usize) {
30 | let (attribute_length, index) = extract_x_byte_as_usize(inputs, index, 4);
31 | let attribute_length = attribute_length as u32;
32 |
33 | let (max_stack, index) = extract_x_byte_as_usize(inputs, index, 2);
34 | let max_stack = max_stack as u16;
35 |
36 | let (max_locals, index) = extract_x_byte_as_usize(inputs, index, 2);
37 | let max_locals = max_locals as u16;
38 |
39 | let (code_length, mut index) = extract_x_byte_as_usize(inputs, index, 4);
40 | let mut code = Vec::with_capacity(code_length);
41 | let mut code_loop_index = 0;
42 |
43 | while code_length - code_loop_index > 0 {
44 | let (tag, update_index) = extract_x_byte_as_usize(inputs, index, 1);
45 | let (update_index, consume_index) =
46 | Instruction::create_and_push(&mut code, inputs, update_index, tag);
47 | code_loop_index += consume_index;
48 | index = update_index;
49 | }
50 |
51 | let (exception_table_length, index) = extract_x_byte_as_usize(inputs, index, 2);
52 | let exception_table = Vec::with_capacity(exception_table_length);
53 |
54 | let (attributes_count, mut index) = extract_x_byte_as_usize(inputs, index, 2);
55 | let mut attribute_info = Vec::with_capacity(attributes_count);
56 | for _ in 0..attributes_count {
57 | let (attribute, update_index) =
58 | Attribute::new(string_pool, constant_pool, inputs, index);
59 | index = update_index;
60 | attribute_info.push(attribute);
61 | }
62 |
63 | (
64 | Code {
65 | attribute_name_index,
66 | attribute_length,
67 | max_stack,
68 | max_locals,
69 | code_length,
70 | code,
71 | exception_table_length,
72 | exception_table,
73 | attributes_count,
74 | attribute_info,
75 | },
76 | index,
77 | )
78 | }
79 | }
80 |
81 | impl fmt::Display for Code {
82 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 | let mut code_strs = Vec::with_capacity(self.code_length);
84 | for (index, code) in self.code.iter().enumerate() {
85 | if let Instruction::Noope = *code {
86 | continue;
87 | }
88 | code_strs.push(format!("{}: {}", index, code));
89 | }
90 | let mut attribute_strs = Vec::with_capacity(self.attributes_count);
91 | for item in self.attribute_info.iter() {
92 | attribute_strs.push(format!("{}", item));
93 | }
94 |
95 | write!(
96 | f,
97 | "Code:
98 | stack:{}, locals={}, args_size=?
99 | {}
100 | {}",
101 | self.max_stack,
102 | self.max_locals,
103 | code_strs.join("\n "),
104 | attribute_strs.join("\n "),
105 | )
106 | }
107 | }
108 |
109 | #[derive(Debug)]
110 | pub struct ExceptionTableItem {
111 | pub start_pc: u16, //u2
112 | pub end_pc: u16, //u2
113 | pub handler_pc: u16, //u2
114 | pub catch_type: u16, //u2
115 | }
116 |
--------------------------------------------------------------------------------
/src/utils.rs:
--------------------------------------------------------------------------------
1 | use crate::attribute::instruction::Instruction;
2 | use crate::object::{ObjectMap, Objectref};
3 | use crate::operand::Item;
4 | use crate::option::RJ_OPTION;
5 | use crate::stackframe::Stackframe;
6 |
7 | use std::cell::RefCell;
8 | use std::collections::HashMap;
9 | use std::fs::File;
10 | use std::io::prelude::*;
11 | use std::io::Result;
12 | use std::iter;
13 | use std::path::Path;
14 |
15 | pub fn read_file>(input: &P) -> Result> {
16 | let mut result = vec![];
17 | let mut f = File::open(input)?;
18 | f.read_to_end(&mut result)?;
19 | Ok(result)
20 | }
21 |
22 | pub fn extract_x_byte_as_vec(input: &[u8], index: usize, x: usize) -> (Vec, usize) {
23 | let mut result = Vec::with_capacity(x);
24 | for i in 0..x {
25 | result.push(input[index + i]);
26 | }
27 | (result, index + x)
28 | }
29 |
30 | pub fn extract_x_byte_as_usize(input: &[u8], index: usize, x: usize) -> (usize, usize) {
31 | let mut result: usize = 0;
32 | for i in 0..x {
33 | result += (input[index + i] as usize) << (x - i - 1) * 8;
34 | }
35 | (result, index + x)
36 | }
37 |
38 | pub fn devide_i64_to_two_i32(input: i64) -> (i32, i32) {
39 | (((input >> 32) << 32) as i32, (input & 0xFFFFFFFF) as i32)
40 | }
41 |
42 | pub fn emit_debug_info(instruction: &Instruction, stackframe: Option<&Stackframe>) {
43 | match RJ_OPTION.lock().unwrap().debug_mode {
44 | 1 => {
45 | println!("instruction: {}", instruction,);
46 | }
47 | 2 => {
48 | println!(
49 | "instruction: {}
50 | operand_stack:
51 | {}
52 | ",
53 | instruction,
54 | stackframe.unwrap().operand_stack
55 | );
56 | }
57 | _ => {}
58 | };
59 | }
60 |
61 | pub fn iniailize_primitive_array(type_index: usize, length: usize) -> Vec<(Item, Item)> {
62 | let default_val = match type_index {
63 | // TBoolean
64 | 4 => (Item::Boolean(false), Item::Null),
65 | // // TChar
66 | // 5 => ,
67 | // // TFloat
68 | // 6 => ,
69 | // // TDouble
70 | // 7 => ,
71 | // // TByte
72 | // 8 => ,
73 | // // TShort
74 | // 9 => ,
75 | // TInt
76 | 10 => (Item::Int(0), Item::Null),
77 | // TLong
78 | 11 => (Item::Long(0), Item::Long(0)),
79 | _ => unreachable!("type_index range should 4 - 11"),
80 | };
81 | let mut initialize_vec = vec![];
82 | initialize_vec.extend(iter::repeat(default_val).take(length));
83 | initialize_vec
84 | }
85 |
86 | pub fn initialize_objectref_array(
87 | object_map: &mut ObjectMap,
88 | class_name_id: usize,
89 | length: usize,
90 | ) -> Vec {
91 | let mut initialize_vec = Vec::with_capacity(length);
92 | for _ in 0..length {
93 | let id = object_map.add(Objectref::new(
94 | class_name_id,
95 | RefCell::new(HashMap::new()),
96 | false,
97 | ));
98 | initialize_vec.push(id);
99 | }
100 |
101 | initialize_vec
102 | }
103 |
104 | #[macro_export]
105 | macro_rules! add_flags {
106 | ($flags:expr, $num:expr, $flag:expr) => {
107 | if $num & $flag as usize != 0 {
108 | $flags.push($flag)
109 | }
110 | };
111 | }
112 |
113 | #[test]
114 | pub fn test_extract_x_byte_as_vec() {
115 | let mut input = vec![1, 2, 3, 4];
116 | assert_eq!(extract_x_byte_as_vec(&mut input, 1, 2), (vec![2, 3], 3));
117 |
118 | let mut input = vec![1, 2, 3, 4, 5, 6, 7, 8];
119 | assert_eq!(
120 | extract_x_byte_as_vec(&mut input, 3, 4),
121 | (vec![4, 5, 6, 7], 7)
122 | );
123 | }
124 |
125 | #[test]
126 | pub fn test_extract_x_byte_as_usize() {
127 | let mut input = vec![1, 2, 3, 4];
128 | assert_eq!(
129 | extract_x_byte_as_usize(&mut input, 1, 2),
130 | ((2 << 8) as usize + 3, 3)
131 | );
132 | assert_eq!(input[3], 4);
133 |
134 | let mut input = vec![1, 2, 3, 4, 5, 6, 7, 8];
135 | let fourth = 1 << (8 * 3);
136 | let third = 2 << (8 * 2);
137 | let second = 3 << (8 * 1);
138 | let first = 4 << (8 * 0);
139 |
140 | assert_eq!(
141 | extract_x_byte_as_usize(&mut input, 0, 4),
142 | (first + second + third + fourth, 4)
143 | );
144 | assert_eq!(input[4], 5);
145 | }
146 |
--------------------------------------------------------------------------------
/src/java_class/builtin.rs:
--------------------------------------------------------------------------------
1 | use std::collections::HashMap;
2 |
3 | use crate::constant::ConstantPool;
4 | use crate::operand::Item;
5 | use crate::stackframe::Stackframe;
6 | use crate::string_pool::StringPool;
7 | use crate::wasm::print_log;
8 |
9 | #[derive(Debug)]
10 | pub struct BuiltIn {
11 | pub class_name: usize,
12 | pub methods: HashMap,
13 | }
14 |
15 | impl BuiltIn {
16 | pub fn new(class_name: usize) -> BuiltIn {
17 | BuiltIn {
18 | class_name,
19 | methods: HashMap::new(),
20 | }
21 | }
22 | }
23 |
24 | #[derive(Debug)]
25 | pub enum BuiltInLocal {
26 | Println,
27 | }
28 |
29 | #[derive(Debug)]
30 | pub struct BuiltInMethod {
31 | pub name: usize,
32 | pub code_type: BuitlInCodeType,
33 | }
34 |
35 | impl BuiltInMethod {
36 | pub fn new(name: usize, code_type: BuitlInCodeType) -> BuiltInMethod {
37 | BuiltInMethod { name, code_type }
38 | }
39 |
40 | pub fn parameter_length(&self, string_map: &mut StringPool, descriptor: usize) -> usize {
41 | let descriptor = string_map.get_value(&descriptor);
42 | match self.code_type {
43 | BuitlInCodeType::Println => match descriptor.as_ref() {
44 | "(J)V" | "(D)V" => 2,
45 | _ => 1,
46 | },
47 | BuitlInCodeType::JavaLangSystemInit
48 | | BuitlInCodeType::JavaLangObjectInit
49 | | BuitlInCodeType::JavaLangObjectToString => 1,
50 | }
51 | }
52 |
53 | pub fn execute(
54 | &mut self,
55 | string_map: &mut StringPool,
56 | constant_pool: &ConstantPool,
57 | stackframes: &mut Vec,
58 | ) {
59 | let mut stackframe = stackframes.pop().expect("should has stack_frame");
60 | match self.code_type {
61 | BuitlInCodeType::Println => {
62 | if let Some(item) = stackframe.local_variables.get(0) {
63 | match item {
64 | Item::Fieldref(index) => {
65 | let value =
66 | string_map.get_value(&constant_pool.get_fieldref_as_utf8(*index));
67 | print_log(&format!("{}", value));
68 | }
69 | Item::String(id) => {
70 | let value = string_map.get_value(id);
71 | print_log(&value);
72 | }
73 | Item::Int(value) => {
74 | print_log(&format!("{}", value));
75 | }
76 | Item::Long(second) => {
77 | if let Some(Item::Long(first)) = stackframe.local_variables.get(1) {
78 | let value: u64 = (((*first as u64) << 32) as u64) | *second as u64;
79 | let value = if value > 0x7fffffffffffffff {
80 | -1 * ((value ^ 0xffffffffffffffff) + 1) as i64
81 | } else {
82 | value as i64
83 | };
84 | print_log(&format!("{}", value));
85 | } else {
86 | unreachable!("should exist long second item")
87 | }
88 | let _ = stackframe.operand_stack.stack.pop();
89 | }
90 | // TBD should fix to output value correctly
91 | Item::Objectref(object_ref) => {
92 | print_log(&format!("objectref: {}", object_ref));
93 | }
94 | Item::Float(value) => {
95 | print_log(&format!("{}", value));
96 | }
97 | Item::Double(second) => {
98 | if let Some(Item::Double(first)) = stackframe.local_variables.get(1) {
99 | let value: u64 = (((*first as u64) << 32) as u64) | *second as u64;
100 | let s: i64 = if value >> 63 == 0 as u64 { 1 } else { -1 };
101 | let e = (value >> 52 as i32) & 0x7ff;
102 | let m = if e == 0 {
103 | ((value & 0xfffffffffffff) << 1) as i64
104 | } else {
105 | ((value & 0xfffffffffffff) | 0x10000000000000) as i64
106 | };
107 | print_log(&format!(
108 | "{}",
109 | (s * m) as f64 * f64::powf(2.0f64, e as f64 - 1075 as f64)
110 | ));
111 | } else {
112 | unreachable!("should exist long second item")
113 | }
114 | let _ = stackframe.operand_stack.stack.pop();
115 | }
116 | _ => unimplemented!(),
117 | };
118 | let _ = stackframe.operand_stack.stack.pop();
119 | } else {
120 | unreachable!("should have a argument for println")
121 | }
122 | }
123 | BuitlInCodeType::JavaLangSystemInit | BuitlInCodeType::JavaLangObjectInit => {}
124 | BuitlInCodeType::JavaLangObjectToString => {
125 | let val = if let Some(Item::Int(val)) = stackframe.local_variables.get(0) {
126 | val
127 | } else {
128 | unreachable!("should have a argument for toString")
129 | };
130 | let stackframe = stackframes.last_mut().expect("should exist stackframe");
131 | let string_id = string_map.insert(val.to_string());
132 | stackframe.operand_stack.stack.push(Item::String(string_id));
133 | }
134 | }
135 | }
136 | }
137 |
138 | #[derive(Debug)]
139 | pub enum BuitlInCodeType {
140 | Println,
141 | JavaLangObjectInit,
142 | JavaLangSystemInit,
143 | JavaLangObjectToString,
144 | }
145 |
--------------------------------------------------------------------------------
/src/field.rs:
--------------------------------------------------------------------------------
1 | use crate::attribute::defs::Attribute;
2 | use crate::utils::extract_x_byte_as_usize;
3 | use std::fmt;
4 |
5 | #[derive(Debug)]
6 | pub struct Field {
7 | pub access_flags: FieldAccessFlags, // u2
8 | pub name_index: usize, // u2
9 | pub descriptor_index: usize, // u2
10 | pub attributes_count: usize, // u2
11 | pub attribute_info: Vec,
12 | }
13 |
14 | impl Field {
15 | pub fn new(inputs: &[u8], index: usize) -> (Field, usize) {
16 | let (access_flags, index) = extract_x_byte_as_usize(inputs, index, 2);
17 | let access_flags = extract_access_flags(access_flags);
18 |
19 | let (name_index, index) = extract_x_byte_as_usize(inputs, index, 2);
20 | let (descriptor_index, index) = extract_x_byte_as_usize(inputs, index, 2);
21 | let (attributes_count, index) = extract_x_byte_as_usize(inputs, index, 2);
22 |
23 | (
24 | Field {
25 | access_flags,
26 | name_index,
27 | descriptor_index,
28 | attributes_count,
29 | attribute_info: vec![],
30 | },
31 | index,
32 | )
33 | }
34 | }
35 |
36 | impl fmt::Display for Field {
37 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 | let mut attribute_strs = Vec::with_capacity(self.attributes_count);
39 | for item in self.attribute_info.iter() {
40 | attribute_strs.push(format!("{}", item));
41 | }
42 |
43 | write!(
44 | f,
45 | " name: #{}
46 | descriptor: #{}
47 | flags: {}
48 | attribute:
49 | {}",
50 | self.name_index,
51 | self.descriptor_index,
52 | self.access_flags,
53 | attribute_strs.join("\n ")
54 | )
55 | }
56 | }
57 |
58 | #[derive(Debug)]
59 | pub enum FieldDescriptor {
60 | BaseType(BaseType),
61 | // L ClassName ; reference an instance of class ClassName
62 | ObjectType(String),
63 | ArrayType(Box),
64 | }
65 |
66 | #[derive(Debug)]
67 | pub enum BaseType {
68 | B, // byte
69 | C, // char
70 | D, // double
71 | F, // float
72 | I, // int
73 | J, // long
74 | S, // short
75 | Z, // boolean
76 | }
77 |
78 | impl From<&str> for FieldDescriptor {
79 | fn from(input: &str) -> FieldDescriptor {
80 | match &input[0..1] {
81 | "B" => FieldDescriptor::BaseType(BaseType::B),
82 | "C" => FieldDescriptor::BaseType(BaseType::C),
83 | "D" => FieldDescriptor::BaseType(BaseType::D),
84 | "F" => FieldDescriptor::BaseType(BaseType::F),
85 | "I" => FieldDescriptor::BaseType(BaseType::I),
86 | "J" => FieldDescriptor::BaseType(BaseType::J),
87 | "S" => FieldDescriptor::BaseType(BaseType::S),
88 | "Z" => FieldDescriptor::BaseType(BaseType::Z),
89 | "L" => FieldDescriptor::ObjectType(input[1..].to_string()),
90 | "[" => unimplemented!("need to implement for Array"),
91 | _ => panic!("failed to convert {} to FieldDescriptor", input),
92 | }
93 | }
94 | }
95 |
96 | fn extract_access_flags(num: usize) -> FieldAccessFlags {
97 | let mut access_flags = vec![];
98 | crate::add_flags!(&mut access_flags, num, FieldAccessFlag::AccPublic);
99 | crate::add_flags!(&mut access_flags, num, FieldAccessFlag::AccPrivate);
100 | crate::add_flags!(&mut access_flags, num, FieldAccessFlag::AccProtected);
101 | crate::add_flags!(&mut access_flags, num, FieldAccessFlag::AccStatic);
102 | crate::add_flags!(&mut access_flags, num, FieldAccessFlag::AccFinal);
103 | crate::add_flags!(&mut access_flags, num, FieldAccessFlag::AccVolatitle);
104 | crate::add_flags!(&mut access_flags, num, FieldAccessFlag::AccTransient);
105 | crate::add_flags!(&mut access_flags, num, FieldAccessFlag::AccSynthetic);
106 | crate::add_flags!(&mut access_flags, num, FieldAccessFlag::AccEnum);
107 |
108 | FieldAccessFlags(access_flags)
109 | }
110 |
111 | #[derive(Debug)]
112 | pub struct FieldAccessFlags(Vec);
113 | impl fmt::Display for FieldAccessFlags {
114 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 | let mut result = Vec::with_capacity(self.0.len());
116 | for item in self.0.iter() {
117 | result.push(format!("{}", item));
118 | }
119 | write!(f, "{}", result.join(", "))
120 | }
121 | }
122 |
123 | #[derive(Debug)]
124 | pub enum FieldAccessFlag {
125 | Unknown = 0x0000,
126 | AccPublic = 0x0001,
127 | AccPrivate = 0x0002,
128 | AccProtected = 0x0004,
129 | AccStatic = 0x0008,
130 | AccFinal = 0x0010,
131 | AccVolatitle = 0x0040,
132 | AccTransient = 0x0080,
133 | AccSynthetic = 0x1000,
134 | AccEnum = 0x4000,
135 | }
136 |
137 | impl fmt::Display for FieldAccessFlag {
138 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 | match self {
140 | FieldAccessFlag::Unknown => write!(f, ""),
141 | FieldAccessFlag::AccPublic => write!(f, "ACC_PUBLIC"),
142 | FieldAccessFlag::AccPrivate => write!(f, "ACC_PRIVATE"),
143 | FieldAccessFlag::AccProtected => write!(f, "ACC_PROTECTED"),
144 | FieldAccessFlag::AccStatic => write!(f, "ACC_STATIC"),
145 | FieldAccessFlag::AccFinal => write!(f, "ACC_FINAL"),
146 | FieldAccessFlag::AccVolatitle => write!(f, "ACC_VOLATITLE"),
147 | FieldAccessFlag::AccTransient => write!(f, "ACC_TRANSIENT"),
148 | FieldAccessFlag::AccSynthetic => write!(f, "ACC_SYNTHETIC"),
149 | FieldAccessFlag::AccEnum => write!(f, "ACC_ENUM"),
150 | }
151 | }
152 | }
153 |
154 | impl From for FieldAccessFlag {
155 | fn from(num: usize) -> FieldAccessFlag {
156 | match num {
157 | 0x0000 => FieldAccessFlag::Unknown, // custom
158 | 0x0001 => FieldAccessFlag::AccPublic,
159 | 0x0002 => FieldAccessFlag::AccPrivate,
160 | 0x0004 => FieldAccessFlag::AccProtected,
161 | 0x0008 => FieldAccessFlag::AccStatic,
162 | 0x0010 => FieldAccessFlag::AccFinal,
163 | 0x0040 => FieldAccessFlag::AccVolatitle,
164 | 0x0080 => FieldAccessFlag::AccTransient,
165 | 0x1000 => FieldAccessFlag::AccSynthetic,
166 | 0x4000 => FieldAccessFlag::AccEnum,
167 | _ => panic!("failed to convert {} to FieldAccessFlag", num),
168 | }
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/src/method.rs:
--------------------------------------------------------------------------------
1 | use crate::attribute::code::Code;
2 | use crate::attribute::defs::Attribute;
3 | use crate::constant::ConstantPool;
4 | use crate::string_pool::StringPool;
5 | use crate::utils::*;
6 | use std::fmt;
7 |
8 | #[derive(Debug)]
9 | pub struct Method {
10 | pub access_flags: MethodAccessFlags, // u2
11 | pub name_index: usize, // u2
12 | pub descriptor_index: usize, // u2
13 | pub attributes_count: usize, // u2
14 | pub attribute_info: Vec,
15 | }
16 |
17 | impl Method {
18 | pub fn new(
19 | string_pool: &mut StringPool,
20 | constant_pool: &ConstantPool,
21 | inputs: &[u8],
22 | index: usize,
23 | ) -> (Method, usize) {
24 | let (access_flag_num, index) = extract_x_byte_as_usize(inputs, index, 2);
25 | let access_flags = extract_access_flags(access_flag_num);
26 | let (name_index, index) = extract_x_byte_as_usize(inputs, index, 2);
27 | let (descriptor_index, index) = extract_x_byte_as_usize(inputs, index, 2);
28 |
29 | let (attributes_count, mut index) = extract_x_byte_as_usize(inputs, index, 2);
30 | let mut attribute_info = Vec::with_capacity(attributes_count);
31 | for _ in 0..attributes_count {
32 | let (attribute, updated_index) =
33 | Attribute::new(string_pool, constant_pool, inputs, index);
34 | index = updated_index;
35 | attribute_info.push(attribute);
36 | }
37 |
38 | (
39 | Method {
40 | access_flags,
41 | name_index,
42 | descriptor_index,
43 | attributes_count,
44 | attribute_info,
45 | },
46 | index,
47 | )
48 | }
49 |
50 | pub fn extract_code<'a>(&self) -> Option<&Code> {
51 | if let Some(attribute) = self.attribute_info.iter().find(|attribute| {
52 | if let Attribute::Code(_) = attribute {
53 | true
54 | } else {
55 | false
56 | }
57 | }) {
58 | if let Attribute::Code(ref code) = attribute {
59 | Some(code)
60 | } else {
61 | unreachable!();
62 | }
63 | } else {
64 | None
65 | }
66 | }
67 |
68 | pub fn run(&self) -> Result<(), String> {
69 | if let Some(code) = self.extract_code() {
70 | for instruction in code.code.iter() {
71 | println!("{}", instruction);
72 | }
73 | }
74 | Ok(())
75 | }
76 | }
77 |
78 | impl fmt::Display for Method {
79 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 | let mut attribute_strs = Vec::with_capacity(self.attributes_count);
81 | for item in self.attribute_info.iter() {
82 | attribute_strs.push(format!("{}", item));
83 | }
84 |
85 | write!(
86 | f,
87 | " name: #{}
88 | descriptor: #{}
89 | flags: {}
90 | {}",
91 | self.name_index,
92 | self.descriptor_index,
93 | self.access_flags,
94 | attribute_strs.join("\n\n")
95 | )
96 | }
97 | }
98 |
99 | fn extract_access_flags(num: usize) -> MethodAccessFlags {
100 | let mut access_flags = vec![];
101 | crate::add_flags!(&mut access_flags, num, MethodAccessFlag::AccPublic);
102 | crate::add_flags!(&mut access_flags, num, MethodAccessFlag::AccPrivate);
103 | crate::add_flags!(&mut access_flags, num, MethodAccessFlag::AccProtected);
104 | crate::add_flags!(&mut access_flags, num, MethodAccessFlag::AccStatic);
105 | crate::add_flags!(&mut access_flags, num, MethodAccessFlag::AccFinal);
106 |
107 | crate::add_flags!(&mut access_flags, num, MethodAccessFlag::AccSynchronized);
108 | crate::add_flags!(&mut access_flags, num, MethodAccessFlag::AccBridge);
109 | crate::add_flags!(&mut access_flags, num, MethodAccessFlag::AccVarargs);
110 | crate::add_flags!(&mut access_flags, num, MethodAccessFlag::AccNative);
111 | crate::add_flags!(&mut access_flags, num, MethodAccessFlag::AccAbstract);
112 | crate::add_flags!(&mut access_flags, num, MethodAccessFlag::AccStrict);
113 | crate::add_flags!(&mut access_flags, num, MethodAccessFlag::AccSynthetic);
114 |
115 | MethodAccessFlags(access_flags)
116 | }
117 |
118 | #[derive(Debug, PartialEq)]
119 | pub enum MethodAccessFlag {
120 | AccPublic = 0x0001,
121 | AccPrivate = 0x0002,
122 | AccProtected = 0x0004,
123 | AccStatic = 0x0008,
124 | AccFinal = 0x0010,
125 | AccSynchronized = 0x0020,
126 | AccBridge = 0x0040,
127 | AccVarargs = 0x0080,
128 | AccNative = 0x0100,
129 | AccAbstract = 0x0400,
130 | AccStrict = 0x0800,
131 | AccSynthetic = 0x1000,
132 | }
133 |
134 | impl fmt::Display for MethodAccessFlag {
135 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 | match self {
137 | MethodAccessFlag::AccPublic => write!(f, "ACC_PUBLIC"),
138 | MethodAccessFlag::AccPrivate => write!(f, "ACC_PRIVATE"),
139 | MethodAccessFlag::AccProtected => write!(f, "ACC_PROTECTED"),
140 | MethodAccessFlag::AccStatic => write!(f, "ACC_STATIC"),
141 | MethodAccessFlag::AccFinal => write!(f, "ACC_FINAL"),
142 | MethodAccessFlag::AccSynchronized => write!(f, "ACC_SYNCHRONIZED"),
143 | MethodAccessFlag::AccBridge => write!(f, "ACC_BRIDGE"),
144 | MethodAccessFlag::AccVarargs => write!(f, "ACC_VARARGS"),
145 | MethodAccessFlag::AccNative => write!(f, "ACC_NATIVE"),
146 | MethodAccessFlag::AccAbstract => write!(f, "ACC_ABSTRACT"),
147 | MethodAccessFlag::AccStrict => write!(f, "ACC_STRICT"),
148 | MethodAccessFlag::AccSynthetic => write!(f, "ACC_SYNTHETIC"),
149 | }
150 | }
151 | }
152 |
153 | impl From for MethodAccessFlag {
154 | fn from(num: usize) -> MethodAccessFlag {
155 | match num {
156 | 0x0001 => MethodAccessFlag::AccPublic,
157 | 0x0002 => MethodAccessFlag::AccPrivate,
158 | 0x0004 => MethodAccessFlag::AccProtected,
159 | 0x0008 => MethodAccessFlag::AccStatic,
160 | 0x0010 => MethodAccessFlag::AccFinal,
161 | 0x0020 => MethodAccessFlag::AccSynchronized,
162 | 0x0040 => MethodAccessFlag::AccBridge,
163 | 0x0080 => MethodAccessFlag::AccVarargs,
164 | 0x0100 => MethodAccessFlag::AccNative,
165 | 0x0400 => MethodAccessFlag::AccAbstract,
166 | 0x0800 => MethodAccessFlag::AccStrict,
167 | 0x1000 => MethodAccessFlag::AccSynthetic,
168 | _ => panic!("failed to convert {} to MethodAccessFlag", num),
169 | }
170 | }
171 | }
172 |
173 | #[derive(Debug)]
174 | pub struct MethodAccessFlags(pub Vec);
175 | impl fmt::Display for MethodAccessFlags {
176 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 | let mut result = Vec::with_capacity(self.0.len());
178 | for item in self.0.iter() {
179 | result.push(format!("{}", item));
180 | }
181 | if result.is_empty() {
182 | write!(f, "")
183 | } else {
184 | write!(f, "{}", result.join(", "))
185 | }
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/src/operand.rs:
--------------------------------------------------------------------------------
1 | // use crate::utils::devide_u64_to_two_u32;
2 | use std::cmp::{Ordering, PartialOrd};
3 | use std::fmt;
4 |
5 | pub fn devide_i64_two_usize(input: i64) -> (usize, usize) {
6 | let high_value = ((input >> 32) << 32) as usize;
7 | let low_value = (input & 0xFFFFFFFF) as usize;
8 | if input > 0 {
9 | (low_value, high_value)
10 | } else {
11 | (0xFFFFFFFF - low_value, 0xFFFFFFFF - high_value)
12 | }
13 | }
14 |
15 | #[derive(PartialEq, Clone, Debug)]
16 | pub enum Item {
17 | Null,
18 | Int(i32),
19 | Long(usize),
20 | Float(f32),
21 | Double(usize),
22 | String(usize),
23 | Boolean(bool),
24 | Classref(usize),
25 | Fieldref(usize),
26 | Objectref(usize),
27 | Arrayref(usize),
28 | }
29 |
30 | impl fmt::Display for Item {
31 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 | match self {
33 | Item::Null => write!(f, "null"),
34 | Item::Int(val) => write!(f, "int: {}", val),
35 | Item::Long(val) => write!(f, "long: {}", val),
36 | Item::Float(val) => write!(f, "float: {}", val),
37 | Item::Double(val) => write!(f, "double: {}", val),
38 | Item::Boolean(val) => write!(f, "boolean: {}", val),
39 | Item::String(val) => write!(f, "string: {}", val),
40 | Item::Classref(val) => write!(f, "class_ref: {}", val),
41 | Item::Fieldref(val) => write!(f, "field_ref: {}", val),
42 | Item::Objectref(val) => write!(f, "object_ref: {}", val),
43 | Item::Arrayref(val) => write!(f, "array_ref {}", val),
44 | }
45 | }
46 | }
47 |
48 | impl PartialOrd for Item {
49 | fn partial_cmp(&self, other: &Item) -> Option {
50 | match (self, other) {
51 | (Item::Null, Item::Null) => Some(Ordering::Equal),
52 | (Item::Int(left), Item::Int(right)) => Some(left.cmp(right)),
53 | (Item::Float(left), Item::Float(right)) => Some({
54 | if left > right {
55 | Ordering::Greater
56 | } else if left == right {
57 | Ordering::Equal
58 | } else {
59 | Ordering::Less
60 | }
61 | }),
62 | (Item::Double(left), Item::Double(right)) => Some(left.cmp(right)),
63 | (Item::Boolean(left), Item::Boolean(right)) => Some(left.cmp(right)),
64 | (Item::Long(left), Item::Long(right)) => Some(left.cmp(right)),
65 | (Item::Classref(left), Item::Classref(right)) => Some(left.cmp(right)),
66 | (Item::Fieldref(left), Item::Fieldref(right)) => Some(left.cmp(right)),
67 | (Item::String(left), Item::String(right)) => Some(left.cmp(right)),
68 | _ => None,
69 | }
70 | }
71 | }
72 |
73 | #[derive(Debug)]
74 | pub struct OperandStack {
75 | pub stack: Vec- ,
76 | }
77 |
78 | macro_rules! culculate {
79 | ($name:ident, $extract_method:ident, $type:ident, $op:tt) => {
80 | pub fn $name(&mut self) -> Item {
81 | let (first, second) = self.$extract_method();
82 | Item::$type(first $op second)
83 | }
84 | }
85 | }
86 |
87 | impl OperandStack {
88 | pub fn new() -> Self {
89 | OperandStack { stack: vec![] }
90 | }
91 |
92 | fn extract_long_values_as_i64(&mut self) -> (i64, i64) {
93 | match (
94 | self.stack.pop(),
95 | self.stack.pop(),
96 | self.stack.pop(),
97 | self.stack.pop(),
98 | ) {
99 | (
100 | Some(Item::Long(second_2)),
101 | Some(Item::Long(second_1)),
102 | Some(Item::Long(first_2)),
103 | Some(Item::Long(first_1)),
104 | ) => {
105 | let second: u64 = (((second_1 as u64) << 32) as u64) | second_2 as u64;
106 | let second = if second > 0x7fffffffffffffff {
107 | -1 * ((second ^ 0xffffffffffffffff) + 1) as i64
108 | } else {
109 | second as i64
110 | };
111 | let first: u64 = (((first_1 as u64) << 32) as u64) | first_2 as u64;
112 | let first = if first > 0x7fffffffffffffff {
113 | -1 * ((first ^ 0xffffffffffffffff) + 1) as i64
114 | } else {
115 | first as i64
116 | };
117 | (first, second)
118 | }
119 | (second_2, second_1, first_2, first_1) => panic!(
120 | "failed to extract long values
121 | first: {:?}, {:?}
122 | second: {:?}, {:?}",
123 | first_1, first_2, second_1, second_2
124 | ),
125 | }
126 | }
127 |
128 | fn extract_int_values(&mut self) -> (i32, i32) {
129 | match (self.stack.pop(), self.stack.pop()) {
130 | (Some(Item::Int(second)), Some(Item::Int(first))) => (first, second),
131 | (second, first) => panic!(
132 | "failed to extract int values
133 | first: {:?}
134 | second: {:?}",
135 | second, first
136 | ),
137 | }
138 | }
139 |
140 | fn extract_float_values(&mut self) -> (f32, f32) {
141 | match (self.stack.pop(), self.stack.pop()) {
142 | (Some(Item::Float(second)), Some(Item::Float(first))) => (first, second),
143 | (second, first) => panic!(
144 | "failed to extract float values
145 | first: {:?}
146 | second: {:?}",
147 | second, first
148 | ),
149 | }
150 | }
151 |
152 | culculate!(iadd, extract_int_values, Int, +);
153 | culculate!(isub, extract_int_values, Int, -);
154 | culculate!(imul, extract_int_values, Int, *);
155 | culculate!(idiv, extract_int_values, Int, /);
156 | culculate!(irem, extract_int_values, Int, %);
157 |
158 | culculate!(fadd, extract_float_values, Float, +);
159 | culculate!(fsub, extract_float_values, Float, -);
160 | culculate!(fmul, extract_float_values, Float, *);
161 | culculate!(fdiv, extract_float_values, Float, /);
162 | culculate!(frem, extract_float_values, Float, %);
163 |
164 | pub fn ladd(&mut self) -> (Item, Item) {
165 | let (first, second) = self.extract_long_values_as_i64();
166 | let (first, second) = devide_i64_two_usize(first + second);
167 | (Item::Long(first), Item::Long(second))
168 | }
169 |
170 | pub fn lsub(&mut self) -> (Item, Item) {
171 | let (first, second) = self.extract_long_values_as_i64();
172 | let (first, second) = devide_i64_two_usize(first + second);
173 | (Item::Long(first), Item::Long(second))
174 | }
175 |
176 | pub fn lmul(&mut self) -> (Item, Item) {
177 | let (first, second) = self.extract_long_values_as_i64();
178 | let (first, second) = devide_i64_two_usize(first * second);
179 | (Item::Long(first), Item::Long(second))
180 | }
181 |
182 | pub fn ldiv(&mut self) -> (Item, Item) {
183 | let (first, second) = self.extract_long_values_as_i64();
184 | let (first, second) = devide_i64_two_usize(first / second);
185 | (Item::Long(first), Item::Long(second))
186 | }
187 |
188 | pub fn lrem(&mut self) -> (Item, Item) {
189 | let (first, second) = self.extract_long_values_as_i64();
190 | let (first, second) = devide_i64_two_usize(first % second);
191 | (Item::Long(first), Item::Long(second))
192 | }
193 |
194 | pub fn lcmp(&mut self) -> Item {
195 | let (first, second) = self.extract_long_values_as_i64();
196 | self.compare_value(first, second)
197 | }
198 |
199 | pub fn fcmp(&mut self) -> Item {
200 | let (first, second) = self.extract_float_values();
201 | self.compare_value(first, second)
202 | }
203 |
204 | fn compare_value(&self, first: T, second: T) -> Item
205 | where
206 | T: PartialOrd,
207 | {
208 | if first > second {
209 | Item::Int(1)
210 | } else if first == second {
211 | Item::Int(0)
212 | } else {
213 | Item::Int(-1)
214 | }
215 | }
216 | }
217 |
218 | impl fmt::Display for OperandStack {
219 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220 | let length = self.stack.len();
221 | let mut item_string_vec = Vec::with_capacity(length);
222 | let mut index = 0;
223 | for item in self.stack.iter() {
224 | match item {
225 | Item::Long(_) => {
226 | item_string_vec.push(format!("#{}+#{} {}", index, index + 1, item));
227 | index += 1;
228 | }
229 | _ => item_string_vec.push(format!("#{} {}", index, item)),
230 | };
231 | index += 1;
232 | }
233 |
234 | write!(
235 | f,
236 | "length: {}
237 | item ====================
238 | {}
239 | ========================",
240 | length,
241 | item_string_vec.join("\n")
242 | )
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/src/java_class/custom.rs:
--------------------------------------------------------------------------------
1 | use crate::attribute::code::Code;
2 | use crate::attribute::defs::Attribute;
3 | use crate::constant::ConstantPool;
4 | use crate::field::{Field, FieldDescriptor};
5 | use crate::method::{Method, MethodAccessFlag};
6 | use crate::string_pool::StringPool;
7 | use crate::utils::*;
8 | use std::fmt;
9 |
10 | #[derive(Debug)]
11 | pub struct Interface(usize);
12 |
13 | #[derive(Debug)]
14 | pub struct Custom {
15 | pub magic: u32, // u4
16 | pub minor_version: u16, // u2
17 | pub major_version: u16, // u2
18 | pub constant_pool_count: usize, // u2
19 | pub cp_info: ConstantPool, // cp_info constant_pool[constant_pool_count-1];
20 | pub access_flags: AccessFlags, // u2
21 | pub this_class: usize, // u2
22 | pub super_class: usize, // u2
23 | pub interfaces_count: usize, // u2
24 | pub interfaces: Vec, // u2 interfaces[interfaces_count];
25 | pub fields_count: usize, // u2
26 | pub fields: Vec, // field_info fields[fields_count];
27 | pub methods_count: usize, // u2
28 | pub methods: Vec, // method_info methods[methods_count];
29 | pub attributes_count: usize, // u2
30 | pub attributes: Vec, // attribute_info attributes[attributes_count];
31 | }
32 |
33 | impl Custom {
34 | pub fn new(string_pool: &mut StringPool, input: &[u8], index: usize) -> (Custom, usize) {
35 | let (magic, index) = extract_x_byte_as_usize(input, index, 4);
36 | let magic = magic as u32;
37 |
38 | let (minor_version, index) = extract_x_byte_as_usize(input, index, 2);
39 | let minor_version = minor_version as u16;
40 | let (major_version, index) = extract_x_byte_as_usize(input, index, 2);
41 | let major_version = major_version as u16;
42 |
43 | let (constant_pool_count, index) = extract_x_byte_as_usize(input, index, 2);
44 | let (cp_info, index) = ConstantPool::new(string_pool, input, index, constant_pool_count);
45 |
46 | let (access_flags_num, index) = extract_x_byte_as_usize(input, index, 2);
47 | let access_flags = extract_access_flags(access_flags_num);
48 |
49 | let (this_class, index) = extract_x_byte_as_usize(input, index, 2);
50 | let (super_class, index) = extract_x_byte_as_usize(input, index, 2);
51 |
52 | let (interfaces_count, mut index) = extract_x_byte_as_usize(input, index, 2);
53 | let mut interfaces = Vec::with_capacity(interfaces_count);
54 | for _ in 0..interfaces_count {
55 | let (interface_index, updated_index) = extract_x_byte_as_usize(input, index, 2);
56 | index = updated_index;
57 | interfaces.push(Interface(interface_index));
58 | }
59 |
60 | let (fields_count, mut index) = extract_x_byte_as_usize(input, index, 2);
61 | let mut fields = Vec::with_capacity(fields_count);
62 | for _ in 0..fields_count {
63 | let (field, updated_index) = Field::new(input, index);
64 | index = updated_index;
65 | fields.push(field);
66 | }
67 |
68 | let (methods_count, mut index) = extract_x_byte_as_usize(input, index, 2);
69 | let mut methods = Vec::with_capacity(methods_count);
70 | for _ in 0..methods_count {
71 | let (method, updated_index) = Method::new(string_pool, &cp_info, input, index);
72 | index = updated_index;
73 | methods.push(method);
74 | }
75 |
76 | let (attributes_count, mut index) = extract_x_byte_as_usize(input, index, 2);
77 | let mut attributes = Vec::with_capacity(attributes_count);
78 |
79 | for _ in 0..attributes_count {
80 | let (attribute, updated_index) = Attribute::new(string_pool, &cp_info, input, index);
81 | index = updated_index;
82 | attributes.push(attribute);
83 | }
84 | (
85 | Custom {
86 | magic,
87 | minor_version,
88 | major_version,
89 | constant_pool_count,
90 | cp_info,
91 | access_flags,
92 | this_class,
93 | super_class,
94 | interfaces_count,
95 | interfaces,
96 | fields_count,
97 | fields,
98 | methods_count,
99 | methods,
100 | attributes_count,
101 | attributes,
102 | },
103 | index,
104 | )
105 | }
106 |
107 | pub fn get_entry_method(&self) -> Option<&Method> {
108 | if let Some(main_index) = self.cp_info.get_main_index() {
109 | return self.methods.iter().find(|method| {
110 | method
111 | .access_flags
112 | .0
113 | .iter()
114 | .find(|flag| **flag == MethodAccessFlag::AccPublic)
115 | .is_some()
116 | && method.name_index == main_index
117 | });
118 | }
119 | panic!(
120 | "failed to find main method in this class. the detail is below
121 | {}",
122 | self
123 | );
124 | }
125 |
126 | pub fn get_clinit_code(&self) -> Option<&Code> {
127 | if let Some(clinit_index) = self.cp_info.get_clinit_index() {
128 | let method_option = self.methods.iter().find(|method| {
129 | method
130 | .access_flags
131 | .0
132 | .iter()
133 | .find(|flag| **flag == MethodAccessFlag::AccStatic)
134 | .is_some()
135 | && method.name_index == clinit_index
136 | });
137 | if let Some(method) = method_option {
138 | if let Some(Attribute::Code(code)) = method.attribute_info.iter().find(|attr| {
139 | if let Attribute::Code(_) = attr {
140 | true
141 | } else {
142 | false
143 | }
144 | }) {
145 | Some(code)
146 | } else {
147 | None
148 | }
149 | } else {
150 | None
151 | }
152 | } else {
153 | None
154 | }
155 | }
156 |
157 | pub fn this_class_name(&self) -> usize {
158 | let class_ref = self.cp_info.get_class_ref(self.this_class);
159 | self.cp_info.get_utf8(class_ref.name_index)
160 | }
161 |
162 | pub fn get_method(&self, name_index: usize, descriptor_index: usize) -> Option<&Method> {
163 | self.methods
164 | .iter()
165 | .find(|item| item.name_index == name_index && item.descriptor_index == descriptor_index)
166 | }
167 |
168 | pub fn get_method_by_string(&self, name: usize, descriptor: usize) -> Option<&Method> {
169 | self.methods.iter().find(|item| {
170 | (self.cp_info.get_utf8(item.name_index) == name)
171 | && (self.cp_info.get_utf8(item.descriptor_index) == descriptor)
172 | })
173 | }
174 |
175 | pub fn get_method_code(&self, name_index: usize, descriptor_index: usize) -> Option<&Code> {
176 | if let Some(method) = self.get_method(name_index, descriptor_index) {
177 | if let Some(Attribute::Code(code)) = method.attribute_info.iter().find(|attr| {
178 | if let Attribute::Code(_) = attr {
179 | true
180 | } else {
181 | false
182 | }
183 | }) {
184 | Some(code)
185 | } else {
186 | None
187 | }
188 | } else {
189 | unreachable!(
190 | "method name: {} descriptor: {} is not found",
191 | name_index, descriptor_index
192 | )
193 | }
194 | }
195 |
196 | pub fn get_method_code_by_string(&self, name: usize, descriptor: usize) -> Option<&Code> {
197 | if let Some(method) = self.get_method_by_string(name, descriptor) {
198 | if let Some(Attribute::Code(code)) = method.attribute_info.iter().find(|attr| {
199 | if let Attribute::Code(_) = attr {
200 | true
201 | } else {
202 | false
203 | }
204 | }) {
205 | Some(code)
206 | } else {
207 | None
208 | }
209 | } else {
210 | unreachable!(
211 | "method name: {} descriptor: {} is not found",
212 | name, descriptor
213 | )
214 | }
215 | }
216 |
217 | pub fn get_descriptor(
218 | &self,
219 | string_map: &mut StringPool,
220 | descriptor_index: usize,
221 | ) -> FieldDescriptor {
222 | let descriptor_str = string_map.get_value(&self.cp_info.get_utf8(descriptor_index));
223 | FieldDescriptor::from(descriptor_str.as_ref())
224 | }
225 | }
226 |
227 | impl fmt::Display for Custom {
228 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229 | let mut field_strs = Vec::with_capacity(self.fields_count);
230 | for item in self.fields.iter() {
231 | field_strs.push(format!("{}", item));
232 | }
233 |
234 | let mut method_strs = Vec::with_capacity(self.methods_count);
235 | for item in self.methods.iter() {
236 | method_strs.push(format!("{}", item));
237 | }
238 |
239 | let mut attribute_strs = Vec::with_capacity(self.attributes_count);
240 | for item in self.attributes.iter() {
241 | attribute_strs.push(format!("{}", item));
242 | }
243 | write!(
244 | f,
245 | "minor version: {}
246 | major version: {}
247 | flags: {}
248 | Constant pool:
249 | {}
250 |
251 | Fields:
252 | {}
253 | Methods:
254 | {}
255 |
256 | Attributes:
257 | {}",
258 | self.minor_version,
259 | self.major_version,
260 | self.access_flags,
261 | self.cp_info,
262 | field_strs.join("\n"),
263 | method_strs.join("\n\n"),
264 | attribute_strs.join("\n ")
265 | )
266 | }
267 | }
268 |
269 | fn extract_access_flags(num: usize) -> AccessFlags {
270 | let mut access_flags = vec![];
271 | crate::add_flags!(&mut access_flags, num, AccessFlag::AccPublic);
272 | crate::add_flags!(&mut access_flags, num, AccessFlag::AccFinal);
273 | crate::add_flags!(&mut access_flags, num, AccessFlag::AccSuper);
274 | crate::add_flags!(&mut access_flags, num, AccessFlag::AccInterface);
275 | crate::add_flags!(&mut access_flags, num, AccessFlag::AccAbstract);
276 | crate::add_flags!(&mut access_flags, num, AccessFlag::AccSynthetic);
277 | crate::add_flags!(&mut access_flags, num, AccessFlag::AccAnnotation);
278 | crate::add_flags!(&mut access_flags, num, AccessFlag::AccEnum);
279 |
280 | AccessFlags(access_flags)
281 | }
282 |
283 | #[derive(Debug)]
284 | pub enum AccessFlag {
285 | AccPublic = 0x0001,
286 | AccFinal = 0x0010,
287 | AccSuper = 0x0020,
288 | AccInterface = 0x0200,
289 | AccAbstract = 0x0400,
290 | AccSynthetic = 0x1000,
291 | AccAnnotation = 0x2000,
292 | AccEnum = 0x4000,
293 | }
294 |
295 | impl fmt::Display for AccessFlag {
296 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 | match self {
298 | AccessFlag::AccPublic => write!(f, "ACC_PUBLIC"),
299 | AccessFlag::AccFinal => write!(f, "ACC_FINAL"),
300 | AccessFlag::AccSuper => write!(f, "ACC_SUPER"),
301 | AccessFlag::AccInterface => write!(f, "ACC_INTERFACE"),
302 | AccessFlag::AccAbstract => write!(f, "ACC_ABSTRACT"),
303 | AccessFlag::AccSynthetic => write!(f, "ACC_SYNTHETIC"),
304 | AccessFlag::AccAnnotation => write!(f, "ACC_ANNOTATION"),
305 | AccessFlag::AccEnum => write!(f, "ACC_ENUM"),
306 | }
307 | }
308 | }
309 |
310 | impl From for AccessFlag {
311 | fn from(num: usize) -> AccessFlag {
312 | match num {
313 | 0x0001 => AccessFlag::AccPublic,
314 | 0x0010 => AccessFlag::AccFinal,
315 | 0x0020 => AccessFlag::AccSuper,
316 | 0x0200 => AccessFlag::AccInterface,
317 | 0x0400 => AccessFlag::AccAbstract,
318 | 0x1000 => AccessFlag::AccSynthetic,
319 | 0x2000 => AccessFlag::AccAnnotation,
320 | 0x4000 => AccessFlag::AccEnum,
321 | _ => panic!("failed to convert {} to AccessFlag", num),
322 | }
323 | }
324 | }
325 |
326 | #[derive(Debug)]
327 | pub struct AccessFlags(Vec);
328 | impl fmt::Display for AccessFlags {
329 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
330 | let mut result = Vec::with_capacity(self.0.len());
331 | for item in self.0.iter() {
332 | result.push(format!("{}", item));
333 | }
334 | write!(f, "flags: {}", result.join(", "))
335 | }
336 | }
337 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "ansi_term"
5 | version = "0.11.0"
6 | source = "registry+https://github.com/rust-lang/crates.io-index"
7 | dependencies = [
8 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
9 | ]
10 |
11 | [[package]]
12 | name = "anyhow"
13 | version = "1.0.23"
14 | source = "registry+https://github.com/rust-lang/crates.io-index"
15 |
16 | [[package]]
17 | name = "atty"
18 | version = "0.2.13"
19 | source = "registry+https://github.com/rust-lang/crates.io-index"
20 | dependencies = [
21 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
22 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
23 | ]
24 |
25 | [[package]]
26 | name = "bitflags"
27 | version = "1.2.1"
28 | source = "registry+https://github.com/rust-lang/crates.io-index"
29 |
30 | [[package]]
31 | name = "bumpalo"
32 | version = "2.6.0"
33 | source = "registry+https://github.com/rust-lang/crates.io-index"
34 |
35 | [[package]]
36 | name = "cfg-if"
37 | version = "0.1.10"
38 | source = "registry+https://github.com/rust-lang/crates.io-index"
39 |
40 | [[package]]
41 | name = "clap"
42 | version = "2.33.0"
43 | source = "registry+https://github.com/rust-lang/crates.io-index"
44 | dependencies = [
45 | "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
46 | "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
47 | "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
48 | "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
49 | "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
50 | "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
51 | "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
52 | ]
53 |
54 | [[package]]
55 | name = "console_error_panic_hook"
56 | version = "0.1.6"
57 | source = "registry+https://github.com/rust-lang/crates.io-index"
58 | dependencies = [
59 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
60 | "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
61 | ]
62 |
63 | [[package]]
64 | name = "heck"
65 | version = "0.3.1"
66 | source = "registry+https://github.com/rust-lang/crates.io-index"
67 | dependencies = [
68 | "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
69 | ]
70 |
71 | [[package]]
72 | name = "js-sys"
73 | version = "0.3.32"
74 | source = "registry+https://github.com/rust-lang/crates.io-index"
75 | dependencies = [
76 | "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
77 | ]
78 |
79 | [[package]]
80 | name = "lazy_static"
81 | version = "1.4.0"
82 | source = "registry+https://github.com/rust-lang/crates.io-index"
83 |
84 | [[package]]
85 | name = "libc"
86 | version = "0.2.65"
87 | source = "registry+https://github.com/rust-lang/crates.io-index"
88 |
89 | [[package]]
90 | name = "log"
91 | version = "0.4.8"
92 | source = "registry+https://github.com/rust-lang/crates.io-index"
93 | dependencies = [
94 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
95 | ]
96 |
97 | [[package]]
98 | name = "memchr"
99 | version = "2.2.1"
100 | source = "registry+https://github.com/rust-lang/crates.io-index"
101 |
102 | [[package]]
103 | name = "nom"
104 | version = "4.2.3"
105 | source = "registry+https://github.com/rust-lang/crates.io-index"
106 | dependencies = [
107 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
108 | "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
109 | ]
110 |
111 | [[package]]
112 | name = "proc-macro2"
113 | version = "1.0.6"
114 | source = "registry+https://github.com/rust-lang/crates.io-index"
115 | dependencies = [
116 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
117 | ]
118 |
119 | [[package]]
120 | name = "quote"
121 | version = "1.0.2"
122 | source = "registry+https://github.com/rust-lang/crates.io-index"
123 | dependencies = [
124 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
125 | ]
126 |
127 | [[package]]
128 | name = "r-jvm"
129 | version = "0.1.0"
130 | dependencies = [
131 | "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
132 | "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
133 | "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
134 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
135 | "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
136 | "web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
137 | ]
138 |
139 | [[package]]
140 | name = "sourcefile"
141 | version = "0.1.4"
142 | source = "registry+https://github.com/rust-lang/crates.io-index"
143 |
144 | [[package]]
145 | name = "strsim"
146 | version = "0.8.0"
147 | source = "registry+https://github.com/rust-lang/crates.io-index"
148 |
149 | [[package]]
150 | name = "syn"
151 | version = "1.0.8"
152 | source = "registry+https://github.com/rust-lang/crates.io-index"
153 | dependencies = [
154 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
155 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
156 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
157 | ]
158 |
159 | [[package]]
160 | name = "textwrap"
161 | version = "0.11.0"
162 | source = "registry+https://github.com/rust-lang/crates.io-index"
163 | dependencies = [
164 | "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
165 | ]
166 |
167 | [[package]]
168 | name = "unicode-segmentation"
169 | version = "1.6.0"
170 | source = "registry+https://github.com/rust-lang/crates.io-index"
171 |
172 | [[package]]
173 | name = "unicode-width"
174 | version = "0.1.6"
175 | source = "registry+https://github.com/rust-lang/crates.io-index"
176 |
177 | [[package]]
178 | name = "unicode-xid"
179 | version = "0.2.0"
180 | source = "registry+https://github.com/rust-lang/crates.io-index"
181 |
182 | [[package]]
183 | name = "vec_map"
184 | version = "0.8.1"
185 | source = "registry+https://github.com/rust-lang/crates.io-index"
186 |
187 | [[package]]
188 | name = "version_check"
189 | version = "0.1.5"
190 | source = "registry+https://github.com/rust-lang/crates.io-index"
191 |
192 | [[package]]
193 | name = "wasm-bindgen"
194 | version = "0.2.55"
195 | source = "registry+https://github.com/rust-lang/crates.io-index"
196 | dependencies = [
197 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
198 | "wasm-bindgen-macro 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
199 | ]
200 |
201 | [[package]]
202 | name = "wasm-bindgen-backend"
203 | version = "0.2.55"
204 | source = "registry+https://github.com/rust-lang/crates.io-index"
205 | dependencies = [
206 | "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
207 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
208 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
209 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
210 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
211 | "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
212 | "wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
213 | ]
214 |
215 | [[package]]
216 | name = "wasm-bindgen-macro"
217 | version = "0.2.55"
218 | source = "registry+https://github.com/rust-lang/crates.io-index"
219 | dependencies = [
220 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
221 | "wasm-bindgen-macro-support 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
222 | ]
223 |
224 | [[package]]
225 | name = "wasm-bindgen-macro-support"
226 | version = "0.2.55"
227 | source = "registry+https://github.com/rust-lang/crates.io-index"
228 | dependencies = [
229 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
230 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
231 | "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
232 | "wasm-bindgen-backend 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
233 | "wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
234 | ]
235 |
236 | [[package]]
237 | name = "wasm-bindgen-shared"
238 | version = "0.2.55"
239 | source = "registry+https://github.com/rust-lang/crates.io-index"
240 |
241 | [[package]]
242 | name = "wasm-bindgen-webidl"
243 | version = "0.2.55"
244 | source = "registry+https://github.com/rust-lang/crates.io-index"
245 | dependencies = [
246 | "anyhow 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
247 | "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
248 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
249 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
250 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
251 | "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
252 | "wasm-bindgen-backend 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
253 | "weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
254 | ]
255 |
256 | [[package]]
257 | name = "web-sys"
258 | version = "0.3.32"
259 | source = "registry+https://github.com/rust-lang/crates.io-index"
260 | dependencies = [
261 | "anyhow 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
262 | "js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
263 | "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
264 | "wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
265 | "wasm-bindgen-webidl 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
266 | ]
267 |
268 | [[package]]
269 | name = "weedle"
270 | version = "0.10.0"
271 | source = "registry+https://github.com/rust-lang/crates.io-index"
272 | dependencies = [
273 | "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
274 | ]
275 |
276 | [[package]]
277 | name = "winapi"
278 | version = "0.3.8"
279 | source = "registry+https://github.com/rust-lang/crates.io-index"
280 | dependencies = [
281 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
282 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
283 | ]
284 |
285 | [[package]]
286 | name = "winapi-i686-pc-windows-gnu"
287 | version = "0.4.0"
288 | source = "registry+https://github.com/rust-lang/crates.io-index"
289 |
290 | [[package]]
291 | name = "winapi-x86_64-pc-windows-gnu"
292 | version = "0.4.0"
293 | source = "registry+https://github.com/rust-lang/crates.io-index"
294 |
295 | [metadata]
296 | "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
297 | "checksum anyhow 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6f1072d8f55592084072d2d3cb23a4b680a8543c00f10d446118e85ad3718142"
298 | "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
299 | "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
300 | "checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
301 | "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
302 | "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
303 | "checksum console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
304 | "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
305 | "checksum js-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "1c840fdb2167497b0bd0db43d6dfe61e91637fa72f9d061f8bd17ddc44ba6414"
306 | "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
307 | "checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8"
308 | "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
309 | "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
310 | "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
311 | "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
312 | "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
313 | "checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3"
314 | "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
315 | "checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92"
316 | "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
317 | "checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
318 | "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
319 | "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
320 | "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
321 | "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
322 | "checksum wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "29ae32af33bacd663a9a28241abecf01f2be64e6a185c6139b04f18b6385c5f2"
323 | "checksum wasm-bindgen-backend 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "1845584bd3593442dc0de6e6d9f84454a59a057722f36f005e44665d6ab19d85"
324 | "checksum wasm-bindgen-macro 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "87fcc747e6b73c93d22c947a6334644d22cfec5abd8b66238484dc2b0aeb9fe4"
325 | "checksum wasm-bindgen-macro-support 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "3dc4b3f2c4078c8c4a5f363b92fcf62604c5913cbd16c6ff5aaf0f74ec03f570"
326 | "checksum wasm-bindgen-shared 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ca0b78d6d3be8589b95d1d49cdc0794728ca734adf36d7c9f07e6459508bb53d"
327 | "checksum wasm-bindgen-webidl 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "3126356474ceb717c8fb5549ae387c9fbf4872818454f4d87708bee997214bb5"
328 | "checksum web-sys 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)" = "98405c0a2e722ed3db341b4c5b70eb9fe0021621f7350bab76df93b09b649bbf"
329 | "checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164"
330 | "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
331 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
332 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
333 |
--------------------------------------------------------------------------------
/src/attribute/defs.rs:
--------------------------------------------------------------------------------
1 | use crate::attribute::code::Code;
2 | use crate::constant::{ConstPoolItem, ConstantPool};
3 | use crate::string_pool::StringPool;
4 | use crate::utils::extract_x_byte_as_usize;
5 |
6 | use std::fmt;
7 |
8 | #[derive(Debug)]
9 | pub enum Attribute {
10 | SourceFile(SourceFile),
11 | InnerClasses,
12 | EnclosingMethod,
13 | SourceDebugExtension,
14 | BootstrapMethods,
15 | ConstantValue,
16 | Code(Code),
17 | Exceptions,
18 | RuntimeVisibleParameterAnnotations,
19 | RuntimeInvisibleParameterAnnotations,
20 | AnnotationDefault,
21 | MethodParameters,
22 | Synthetic,
23 | Deprecated,
24 | Signature,
25 | RuntimeVisibleAnnotations,
26 | RuntimeInvisibleAnnotations,
27 | LineNumberTable(LineNumberTable),
28 | LocalVariableTable,
29 | LocalVariableTypeTable,
30 | StackMapTable(StackMapTable),
31 | RuntimeVisibleTypeAnnotations,
32 | RuntimeInvisibleTypeAnnotations,
33 | }
34 |
35 | impl Attribute {
36 | pub fn new(
37 | string_pool: &mut StringPool,
38 | constant_pool: &ConstantPool,
39 | inputs: &[u8],
40 | index: usize,
41 | ) -> (Attribute, usize) {
42 | let (attribute_name_index, index) = extract_x_byte_as_usize(inputs, index, 2);
43 | if let ConstPoolItem::ConstantUtf8(item) = &constant_pool.0[attribute_name_index] {
44 | let attribute_name_index = attribute_name_index as u16;
45 |
46 | match AttributeTag::from(string_pool.get_value(&item.id)) {
47 | AttributeTag::SourceFile => {
48 | let (item, index) = SourceFile::new(inputs, index, attribute_name_index);
49 | (Attribute::SourceFile(item), index)
50 | }
51 | AttributeTag::LineNumberTable => {
52 | let (item, index) = LineNumberTable::new(inputs, index, attribute_name_index);
53 | (Attribute::LineNumberTable(item), index)
54 | }
55 | AttributeTag::StackMapTable => {
56 | let (item, index) = StackMapTable::new(inputs, index, attribute_name_index);
57 | (Attribute::StackMapTable(item), index)
58 | }
59 | AttributeTag::Code => {
60 | let (item, index) = Code::new(
61 | string_pool,
62 | constant_pool,
63 | inputs,
64 | index,
65 | attribute_name_index,
66 | );
67 | (Attribute::Code(item), index)
68 | }
69 | _ => unimplemented!(),
70 | }
71 | } else {
72 | panic!(
73 | "{:?} is not ConstantUtf8",
74 | constant_pool.0[attribute_name_index]
75 | );
76 | }
77 | }
78 | }
79 |
80 | impl fmt::Display for Attribute {
81 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 | match self {
83 | Attribute::SourceFile(val) => write!(f, "{}", val),
84 | Attribute::Code(val) => write!(f, "{}", val),
85 | Attribute::LineNumberTable(val) => write!(f, "{}", val),
86 | Attribute::StackMapTable(val) => write!(f, "{}", val),
87 | _ => unimplemented!(),
88 | }
89 | }
90 | }
91 |
92 | // this is a custom enum for handling
93 | #[derive(Debug)]
94 | pub enum AttributeTag {
95 | SourceFile,
96 | InnerClasses,
97 | EnclosingMethod,
98 | SourceDebugExtension,
99 | BootstrapMethods,
100 | ConstantValue,
101 | Code,
102 | Exceptions,
103 | RuntimeVisibleParameterAnnotations,
104 | RuntimeInvisibleParameterAnnotations,
105 | AnnotationDefault,
106 | MethodParameters,
107 | Synthetic,
108 | Deprecated,
109 | Signature,
110 | RuntimeVisibleAnnotations,
111 | RuntimeInvisibleAnnotations,
112 | LineNumberTable,
113 | LocalVariableTable,
114 | LocalVariableTypeTable,
115 | StackMapTable,
116 | RuntimeVisibleTypeAnnotations,
117 | RuntimeInvisibleTypeAnnotations,
118 | }
119 |
120 | impl From for AttributeTag {
121 | fn from(input: String) -> AttributeTag {
122 | match input.as_str() {
123 | "SourceFile" => AttributeTag::SourceFile,
124 | "InnerClasses" => AttributeTag::InnerClasses,
125 | "EnclosingMethod" => AttributeTag::EnclosingMethod,
126 | "SourceDebugExtension" => AttributeTag::SourceDebugExtension,
127 | "BootstrapMethods" => AttributeTag::BootstrapMethods,
128 | "ConstantValue" => AttributeTag::ConstantValue,
129 | "Code" => AttributeTag::Code,
130 | "Exceptions" => AttributeTag::Exceptions,
131 | "RuntimeVisibleParameterAnnotations" => {
132 | AttributeTag::RuntimeVisibleParameterAnnotations
133 | }
134 | "RuntimeInvisibleParameterAnnotations" => {
135 | AttributeTag::RuntimeInvisibleParameterAnnotations
136 | }
137 | "AnnotationDefault" => AttributeTag::AnnotationDefault,
138 | "MethodParameters" => AttributeTag::MethodParameters,
139 | "Synthetic" => AttributeTag::Synthetic,
140 | "Deprecated" => AttributeTag::Deprecated,
141 | "Signature" => AttributeTag::Signature,
142 | "RuntimeVisibleAnnotations" => AttributeTag::RuntimeVisibleAnnotations,
143 | "RuntimeInvisibleAnnotations" => AttributeTag::RuntimeInvisibleAnnotations,
144 | "LineNumberTable" => AttributeTag::LineNumberTable,
145 | "LocalVariableTable" => AttributeTag::LocalVariableTable,
146 | "LocalVariableTypeTable" => AttributeTag::LocalVariableTypeTable,
147 | "StackMapTable" => AttributeTag::StackMapTable,
148 | "RuntimeVisibleTypeAnnotations" => AttributeTag::RuntimeVisibleTypeAnnotations,
149 | "RuntimeInvisibleTypeAnnotations" => AttributeTag::RuntimeInvisibleTypeAnnotations,
150 | _ => unreachable!(),
151 | }
152 | }
153 | }
154 |
155 | #[derive(Debug)]
156 | pub struct SourceFile {
157 | pub attribute_name_index: u16, // u2
158 | pub attribute_length: u32, // u4
159 | pub sourcefile_index: u16, // u2
160 | }
161 |
162 | impl SourceFile {
163 | pub fn new(inputs: &[u8], index: usize, attribute_name_index: u16) -> (SourceFile, usize) {
164 | let (attribute_length, index) = extract_x_byte_as_usize(inputs, index, 4);
165 | let attribute_length = attribute_length as u32;
166 |
167 | let (sourcefile_index, index) = extract_x_byte_as_usize(inputs, index, 2);
168 | let sourcefile_index = sourcefile_index as u16;
169 |
170 | let source_file = SourceFile {
171 | attribute_name_index,
172 | attribute_length,
173 | sourcefile_index,
174 | };
175 | (source_file, index)
176 | }
177 | }
178 |
179 | impl fmt::Display for SourceFile {
180 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 | write!(f, "SourceFile: #{}", self.sourcefile_index)
182 | }
183 | }
184 |
185 | #[derive(Debug)]
186 | pub struct LineNumberTable {
187 | pub attribute_name_index: u16, // u2
188 | pub attribute_length: u32, // u4
189 | pub line_number_table_length: usize, // u2
190 | pub line_number_tables: Vec,
191 | }
192 |
193 | impl LineNumberTable {
194 | pub fn new(inputs: &[u8], index: usize, attribute_name_index: u16) -> (LineNumberTable, usize) {
195 | let (attribute_length, index) = extract_x_byte_as_usize(inputs, index, 4);
196 | let attribute_length = attribute_length as u32;
197 |
198 | let (line_number_table_length, mut index) = extract_x_byte_as_usize(inputs, index, 2);
199 | let mut line_number_tables = Vec::with_capacity(line_number_table_length);
200 |
201 | for _ in 0..line_number_table_length {
202 | let (start_pc, update_index) = extract_x_byte_as_usize(inputs, index, 2);
203 | let start_pc = start_pc as u16;
204 |
205 | let (line_number, update_index) = extract_x_byte_as_usize(inputs, update_index, 2);
206 | let line_number = line_number as u16;
207 |
208 | line_number_tables.push(LineNumberTableItem {
209 | start_pc,
210 | line_number,
211 | });
212 | index = update_index;
213 | }
214 |
215 | (
216 | LineNumberTable {
217 | attribute_name_index,
218 | attribute_length,
219 | line_number_table_length,
220 | line_number_tables,
221 | },
222 | index,
223 | )
224 | }
225 | }
226 |
227 | impl fmt::Display for LineNumberTable {
228 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229 | let mut table_strs = Vec::with_capacity(self.line_number_table_length);
230 | for item in self.line_number_tables.iter() {
231 | table_strs.push(format!("{}", item));
232 | }
233 | write!(
234 | f,
235 | "LineNumberTable:
236 | {}",
237 | table_strs.join("\n ")
238 | )
239 | }
240 | }
241 |
242 | #[derive(Debug)]
243 | pub struct LineNumberTableItem {
244 | pub start_pc: u16, // u2
245 | pub line_number: u16, // u2
246 | }
247 |
248 | impl fmt::Display for LineNumberTableItem {
249 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 | write!(f, " line {}: {}", self.line_number, self.start_pc)
251 | }
252 | }
253 |
254 | #[derive(Debug)]
255 | pub struct StackMapTable {
256 | attribute_name_index: u16, // u2
257 | attribute_length: u32, // u4
258 | number_of_entries: usize, // u2
259 | stack_map_frame: Vec,
260 | }
261 |
262 | impl StackMapTable {
263 | pub fn new(inputs: &[u8], index: usize, attribute_name_index: u16) -> (StackMapTable, usize) {
264 | let (attribute_length, index) = extract_x_byte_as_usize(inputs, index, 4);
265 | let attribute_length = attribute_length as u32;
266 |
267 | let (number_of_entries, mut index) = extract_x_byte_as_usize(inputs, index, 2);
268 | let mut stack_map_frame = Vec::with_capacity(number_of_entries);
269 |
270 | for _ in 0..number_of_entries {
271 | let (frame, update_index) = StackMapFrame::new(inputs, index);
272 | stack_map_frame.push(frame);
273 | index = update_index;
274 | }
275 | (
276 | StackMapTable {
277 | attribute_name_index,
278 | attribute_length,
279 | number_of_entries,
280 | stack_map_frame,
281 | },
282 | index,
283 | )
284 | }
285 | }
286 |
287 | impl fmt::Display for StackMapTable {
288 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 | let mut stack_map_frame_strs = Vec::with_capacity(self.number_of_entries);
290 | for item in self.stack_map_frame.iter() {
291 | stack_map_frame_strs.push(format!("frame_type = {}", item));
292 | }
293 |
294 | write!(
295 | f,
296 | "StackMapTable: number_of_entries = {}
297 | frame_type = {}",
298 | self.number_of_entries,
299 | stack_map_frame_strs.join("\n ")
300 | )
301 | }
302 | }
303 |
304 | #[derive(Debug)]
305 | pub enum StackMapFrame {
306 | SameFrame(SameFrame),
307 | SameLocals1StackItemFrame,
308 | SameLocals1StackItemFrameExtended,
309 | ChopFrame(ChopFrame),
310 | SameFrameExtended,
311 | AppendFrame(AppendFrame),
312 | FullFrame(FullFrame),
313 | }
314 |
315 | #[derive(Debug)]
316 | pub struct SameFrame {
317 | frame_type: usize,
318 | }
319 |
320 | #[derive(Debug)]
321 | pub struct ChopFrame {
322 | frame_type: usize,
323 | offset_delta: usize,
324 | }
325 |
326 | #[derive(Debug)]
327 | pub struct AppendFrame {
328 | frame_type: usize,
329 | offset_delta: usize,
330 | locals: Vec,
331 | }
332 |
333 | #[derive(Debug)]
334 | pub struct FullFrame {
335 | frame_type: usize,
336 | offset_delta: usize, // u2
337 | number_of_locals: usize, // u2
338 | locals: Vec, // locals[number_of_locals]
339 | number_of_stack_items: usize, // u2
340 | stack: Vec, // stack[number_of_stack_items]
341 | }
342 |
343 | impl StackMapFrame {
344 | pub fn new(inputs: &[u8], index: usize) -> (StackMapFrame, usize) {
345 | let (frame_type, index) = extract_x_byte_as_usize(inputs, index, 1);
346 | match frame_type {
347 | 0..=63 => (StackMapFrame::SameFrame(SameFrame { frame_type }), index),
348 | 248..=250 => {
349 | let (offset_delta, index) = extract_x_byte_as_usize(inputs, index, 2);
350 | (
351 | StackMapFrame::ChopFrame(ChopFrame {
352 | frame_type,
353 | offset_delta,
354 | }),
355 | index,
356 | )
357 | }
358 | 252..=254 => {
359 | let (offset_delta, index) = extract_x_byte_as_usize(inputs, index, 2);
360 | let length = (frame_type as i32) - 251;
361 | let (locals, index) = if length > 0 {
362 | extract_verification_type_info(inputs, index, length as usize)
363 | } else {
364 | (vec![], index)
365 | };
366 |
367 | (
368 | StackMapFrame::AppendFrame(AppendFrame {
369 | frame_type,
370 | offset_delta,
371 | locals,
372 | }),
373 | index,
374 | )
375 | }
376 | 255 => {
377 | let (offset_delta, index) = extract_x_byte_as_usize(inputs, index, 2);
378 | let (number_of_locals, index) = extract_x_byte_as_usize(inputs, index, 2);
379 | let (locals, index) =
380 | extract_verification_type_info(inputs, index, number_of_locals);
381 | let (number_of_stack_items, index) = extract_x_byte_as_usize(inputs, index, 2);
382 | let (stack, index) =
383 | extract_verification_type_info(inputs, index, number_of_stack_items);
384 |
385 | (
386 | StackMapFrame::FullFrame(FullFrame {
387 | frame_type,
388 | offset_delta,
389 | number_of_locals,
390 | locals,
391 | number_of_stack_items,
392 | stack,
393 | }),
394 | index,
395 | )
396 | }
397 | _ => unimplemented!(),
398 | }
399 | }
400 | }
401 |
402 | impl fmt::Display for StackMapFrame {
403 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 | match self {
405 | StackMapFrame::SameFrame(SameFrame { frame_type }) => {
406 | write!(f, "{} /* same */", frame_type)
407 | }
408 | StackMapFrame::ChopFrame(ChopFrame {
409 | frame_type,
410 | offset_delta,
411 | }) => write!(
412 | f,
413 | "{} /* chop */
414 | offset_delta = {}",
415 | frame_type, offset_delta
416 | ),
417 | StackMapFrame::AppendFrame(AppendFrame {
418 | frame_type,
419 | offset_delta,
420 | locals,
421 | }) => write!(
422 | f,
423 | "{} /* append */
424 | offset_delta = {}
425 | locals = [{}]",
426 | frame_type,
427 | offset_delta,
428 | locals
429 | .iter()
430 | .map(|local| format!("{}", local))
431 | .collect::>()
432 | .join(", ")
433 | ),
434 | StackMapFrame::FullFrame(FullFrame {
435 | frame_type,
436 | offset_delta,
437 | locals,
438 | stack,
439 | ..
440 | }) => write!(
441 | f,
442 | "{} /* full_frame */
443 | offset_delta = {}
444 | locals = [{}]
445 | stack = [{}]",
446 | frame_type,
447 | offset_delta,
448 | format!(
449 | "{}",
450 | locals
451 | .iter()
452 | .map(|local| format!("{}", local))
453 | .collect::>()
454 | .join(", ")
455 | ),
456 | format!(
457 | "{}",
458 | stack
459 | .iter()
460 | .map(|item| format!("{}", item))
461 | .collect::>()
462 | .join(", ")
463 | )
464 | ),
465 | _ => unimplemented!(),
466 | }
467 | }
468 | }
469 |
470 | #[derive(Debug)]
471 | pub enum VerificationTypeInfo {
472 | TopVariableInfo, // 0
473 | IntegerVariableInfo, // 1
474 | FloatVariableInfo, // 2
475 | DoubleVariableInfo, // 3
476 | LongVariableInfo, // 4
477 | NullVariableInfo, // 5
478 | UninitializedThisVariableInfo, // 6
479 | ObjectVariableInfo(usize), // 7, u2(cpool_index)
480 | UninitializedVariableInfo(usize), // 8, u2(offset)
481 | }
482 |
483 | impl fmt::Display for VerificationTypeInfo {
484 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
485 | match self {
486 | VerificationTypeInfo::TopVariableInfo => write!(f, "top"),
487 | VerificationTypeInfo::IntegerVariableInfo => write!(f, "int"),
488 | VerificationTypeInfo::FloatVariableInfo => write!(f, "float"),
489 | VerificationTypeInfo::DoubleVariableInfo => write!(f, "double"),
490 | VerificationTypeInfo::LongVariableInfo => write!(f, "long"),
491 | VerificationTypeInfo::NullVariableInfo => write!(f, "null"),
492 | VerificationTypeInfo::UninitializedThisVariableInfo => write!(f, "uninitialized_this"),
493 | VerificationTypeInfo::ObjectVariableInfo(index) => {
494 | write!(f, "object_variable: #{}", index)
495 | }
496 | VerificationTypeInfo::UninitializedVariableInfo(index) => {
497 | write!(f, "uninitialized_variable: #{}", index)
498 | }
499 | }
500 | }
501 | }
502 |
503 | pub fn extract_verification_type_info(
504 | inputs: &[u8],
505 | original_index: usize,
506 | length: usize,
507 | ) -> (Vec, usize) {
508 | let mut index = original_index;
509 | let mut result = Vec::with_capacity(length);
510 | for _ in 0..length {
511 | let (tag, update_index) = extract_x_byte_as_usize(inputs, index, 1);
512 | let (type_info, update_index) = match tag {
513 | 0 => (VerificationTypeInfo::TopVariableInfo, update_index),
514 | 1 => (VerificationTypeInfo::IntegerVariableInfo, update_index),
515 | 2 => (VerificationTypeInfo::FloatVariableInfo, update_index),
516 | 3 => (VerificationTypeInfo::DoubleVariableInfo, update_index),
517 | 4 => (VerificationTypeInfo::LongVariableInfo, update_index),
518 | 5 => (VerificationTypeInfo::NullVariableInfo, update_index),
519 | 6 => (
520 | VerificationTypeInfo::UninitializedThisVariableInfo,
521 | update_index,
522 | ),
523 | 7 => {
524 | let (cpool_index, update_index) = extract_x_byte_as_usize(inputs, update_index, 2);
525 | (
526 | VerificationTypeInfo::ObjectVariableInfo(cpool_index),
527 | update_index,
528 | )
529 | }
530 | 8 => {
531 | let (offset, update_index) = extract_x_byte_as_usize(inputs, update_index, 2);
532 | (
533 | VerificationTypeInfo::UninitializedVariableInfo(offset),
534 | update_index,
535 | )
536 | }
537 | _ => unreachable!(
538 | "should be below 8 for verification_type_info. actual {}",
539 | tag
540 | ),
541 | };
542 | result.push(type_info);
543 | index = update_index;
544 | }
545 | (result, index)
546 | }
547 |
--------------------------------------------------------------------------------
/src/constant.rs:
--------------------------------------------------------------------------------
1 | use crate::operand::Item;
2 | use crate::string_pool::StringPool;
3 | use crate::utils::*;
4 | use std::fmt;
5 |
6 | #[derive(Debug, PartialEq)]
7 | pub struct ConstantPool(pub Vec);
8 | impl ConstantPool {
9 | pub fn new(
10 | string_map: &mut StringPool,
11 | inputs: &[u8],
12 | mut index: usize,
13 | length: usize,
14 | ) -> (ConstantPool, usize) {
15 | let mut items = vec![ConstPoolItem::ConstantNull];
16 | let mut constant_index = 0;
17 | let constant_pool_length = length - 1;
18 | while constant_pool_length > constant_index {
19 | let (tag, update_index) = extract_x_byte_as_usize(inputs, index, 1);
20 |
21 | let (item, update_index) = match ConstPoolTag::from(tag) {
22 | ConstPoolTag::ConstantClass => {
23 | let (item, update_index) =
24 | ConstantClass::create_and_update_index(inputs, update_index);
25 | (ConstPoolItem::ConstantClass(item), update_index)
26 | }
27 | ConstPoolTag::ConstantMethodref => {
28 | let (item, update_index) =
29 | ConstantMethodref::create_and_update_index(inputs, update_index);
30 | (ConstPoolItem::ConstantMethodref(item), update_index)
31 | }
32 | ConstPoolTag::ConstantNameAndType => {
33 | let (item, update_index) =
34 | ConstantNameAndType::create_and_update_index(inputs, update_index);
35 | (ConstPoolItem::ConstantNameAndType(item), update_index)
36 | }
37 | ConstPoolTag::ConstantUtf8 => {
38 | let (item, update_index) =
39 | ConstantUtf8::create_and_update_index(string_map, inputs, update_index);
40 | (ConstPoolItem::ConstantUtf8(item), update_index)
41 | }
42 | ConstPoolTag::ConstantString => {
43 | let (item, update_index) =
44 | ConstantString::create_and_update_index(inputs, update_index);
45 | (ConstPoolItem::ConstantString(item), update_index)
46 | }
47 | ConstPoolTag::ConstantFieldref => {
48 | let (item, update_index) =
49 | ConstantFieldref::create_and_update_index(inputs, update_index);
50 | (ConstPoolItem::ConstantFieldref(item), update_index)
51 | }
52 | ConstPoolTag::ConstantFloat => {
53 | let (item, update_index) =
54 | ConstantFloat::create_and_update_index(inputs, update_index);
55 | (ConstPoolItem::ConstantFloat(item), update_index)
56 | }
57 | ConstPoolTag::ConstantLong => {
58 | let (item, update_index) =
59 | ConstantLong::create_and_update_index(inputs, update_index);
60 | constant_index += 2;
61 | index = update_index;
62 | items.push(ConstPoolItem::ConstantLong(item));
63 | items.push(ConstPoolItem::ConstantNull);
64 | continue;
65 | }
66 | ConstPoolTag::ConstantDouble => {
67 | let (item, update_index) =
68 | ConstantDouble::create_and_update_index(inputs, update_index);
69 | constant_index += 2;
70 | index = update_index;
71 | items.push(ConstPoolItem::ConstantDouble(item));
72 | items.push(ConstPoolItem::ConstantNull);
73 | continue;
74 | }
75 | _ => unimplemented!(
76 | "
77 | constant pool purse failed.
78 | current constant pool
79 | {}.
80 | next tag: {}",
81 | ConstantPool(items),
82 | tag
83 | ),
84 | };
85 | constant_index += 1;
86 | index = update_index;
87 | items.push(item);
88 | }
89 |
90 | (ConstantPool(items), index)
91 | }
92 |
93 | pub fn get_main_index(&self) -> Option {
94 | self.0.iter().position(|item| {
95 | if let ConstPoolItem::ConstantUtf8(utf8) = item {
96 | utf8.bytes == vec![0x6D, 0x61, 0x69, 0x6E] // main
97 | } else {
98 | false
99 | }
100 | })
101 | }
102 |
103 | pub fn get_clinit_index(&self) -> Option {
104 | self.0.iter().position(|item| {
105 | if let ConstPoolItem::ConstantUtf8(utf8) = item {
106 | //
107 | utf8.bytes == vec![0x3C, 0x63, 0x6C, 0x69, 0x6E, 0x69, 0x74, 0x3E]
108 | } else {
109 | false
110 | }
111 | })
112 | }
113 |
114 | pub fn create_and_set_operand_stack_item(&self, stack: &mut Vec
- , index: usize) {
115 | match self.0.get(index) {
116 | Some(ref item) => match item {
117 | // ConstPoolItem::ConstantClass(ConstantClass),
118 | // ConstPoolItem::ConstantMethodref(ConstantMethodref),
119 | // ConstPoolItem::ConstantInterfaceMethodref,
120 | // ConstPoolItem::ConstantNameAndType(ConstantNameAndType),
121 | ConstPoolItem::ConstantString(ref item) => {
122 | stack.push(Item::String(self.get_string(item.string_index)));
123 | }
124 | ConstPoolItem::ConstantFieldref(_) => stack.push(Item::Fieldref(index)),
125 | ConstPoolItem::ConstantUtf8(item) => stack.push(Item::String(item.id)),
126 | ConstPoolItem::ConstantLong(ref item) => {
127 | stack.push(Item::Long(item.high_bytes));
128 | stack.push(Item::Long(item.low_bytes));
129 | }
130 | ConstPoolItem::ConstantNull => {
131 | unreachable!("index: {}. should not come ConstantNull", index)
132 | }
133 | _ => unimplemented!("{:?}", item),
134 | },
135 | _ => unreachable!("index: {} is not found", index),
136 | };
137 | }
138 |
139 | pub fn get_name_and_type(&self, index: usize) -> &ConstantNameAndType {
140 | match self.0.get(index) {
141 | Some(ConstPoolItem::ConstantNameAndType(ref item)) => item,
142 | _ => unreachable!(
143 | "should be ConstantNameAndType. actual {:?}",
144 | self.0.get(index)
145 | ),
146 | }
147 | }
148 |
149 | pub fn get_class_ref(&self, index: usize) -> &ConstantClass {
150 | match self.0.get(index) {
151 | Some(ConstPoolItem::ConstantClass(ref item)) => item,
152 | _ => unreachable!("should be ConstantClass. actual {:?}", self.0.get(index)),
153 | }
154 | }
155 |
156 | pub fn get_class_ref_name(&self, index: usize) -> usize {
157 | match self.0.get(index) {
158 | Some(ConstPoolItem::ConstantClass(ref item)) => self.get_utf8(item.name_index),
159 | _ => unreachable!("should be ConstantClass. actual {:?}", self.0.get(index)),
160 | }
161 | }
162 |
163 | // (class_name, field_name)
164 | pub fn get_class_and_field_name(&self, index: usize) -> (usize, usize) {
165 | let field = self.get_field_ref(index);
166 | let name_and_type = self.get_name_and_type(field.name_and_type_index);
167 | let class_name = self.get_class_ref_name(field.class_index);
168 | let field_name = self.get_utf8(name_and_type.name_index);
169 | (class_name, field_name)
170 | }
171 |
172 | pub fn get_method_ref(&self, index: usize) -> &ConstantMethodref {
173 | match self.0.get(index) {
174 | Some(ConstPoolItem::ConstantMethodref(ref item)) => item,
175 | _ => unreachable!(
176 | "should be ConstantMethodref. actual {:?}",
177 | self.0.get(index)
178 | ),
179 | }
180 | }
181 |
182 | pub fn get_field_ref(&self, index: usize) -> &ConstantFieldref {
183 | match self.0.get(index) {
184 | Some(ConstPoolItem::ConstantFieldref(ref item)) => item,
185 | _ => unreachable!("should be ConstantFieldref. actual {:?}", self.0.get(index)),
186 | }
187 | }
188 |
189 | pub fn get_string(&self, index: usize) -> usize {
190 | match self.0.get(index) {
191 | Some(ConstPoolItem::ConstantString(ref item)) => self.get_utf8(item.string_index),
192 | _ => unreachable!("should be ConstantString. actual {:?}", self.0.get(index)),
193 | }
194 | }
195 |
196 | pub fn get_float(&self, index: usize) -> f32 {
197 | match self.0.get(index) {
198 | Some(ConstPoolItem::ConstantFloat(ConstantFloat { bytes, .. })) => {
199 | let s: f32 = if bytes >> 31 == 0 as usize { 1.0 } else { -1.0 };
200 | let e = ((bytes >> 23 as usize) & 0xff) as f32;
201 | let m = if e == 0.0 {
202 | ((bytes & 0x7fffff) << 1) as f32
203 | } else {
204 | ((bytes & 0x7fffff) | 0x800000) as f32
205 | };
206 | // s * m * 2e-150
207 | s * m * f32::powf(2.0f32, e - 150 as f32)
208 | }
209 | _ => unreachable!("should be ConstantFloat. actual {:?}", self.0.get(index)),
210 | }
211 | }
212 |
213 | pub fn get_item_tag(&self, index: usize) -> ConstPoolTag {
214 | match self.0.get(index) {
215 | Some(ConstPoolItem::ConstantString(_)) => ConstPoolTag::ConstantString,
216 | Some(ConstPoolItem::ConstantFloat(_)) => ConstPoolTag::ConstantFloat,
217 | _ => unimplemented!(),
218 | }
219 | }
220 |
221 | pub fn get_utf8(&self, index: usize) -> usize {
222 | match self.0.get(index) {
223 | Some(ConstPoolItem::ConstantUtf8(item)) => item.id,
224 | _ => unreachable!("should be ConstantUtf8. actual {:?}", self.0.get(index)),
225 | }
226 | }
227 |
228 | pub fn get_utf8_as_string(&self, string_pool: &mut StringPool, index: usize) -> String {
229 | let id = self.get_utf8(index);
230 | string_pool.get_value(&id)
231 | }
232 |
233 | pub fn get_fieldref_as_utf8(&self, index: usize) -> usize {
234 | match self.0.get(index) {
235 | Some(ConstPoolItem::ConstantFieldref(ref item)) => {
236 | let name_and_type = self.get_name_and_type(item.name_and_type_index);
237 | self.get_utf8(name_and_type.name_index)
238 | }
239 | _ => unreachable!("should be ConstantFieldRef. actual {:?}", self.0.get(index)),
240 | }
241 | }
242 | }
243 |
244 | impl fmt::Display for ConstantPool {
245 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 | let mut result = Vec::with_capacity(self.0.len());
247 | for (index, item) in self.0.iter().enumerate() {
248 | let rw = match item {
249 | ConstPoolItem::ConstantNull => {
250 | continue;
251 | }
252 | ConstPoolItem::ConstantMethodref(item) => format!(
253 | " #{} = Methodref #{}.#{}",
254 | index, item.class_index, item.name_and_type_index,
255 | ),
256 | ConstPoolItem::ConstantFieldref(item) => format!(
257 | " #{} = Fieldref #{}.#{}",
258 | index, item.class_index, item.name_and_type_index
259 | ),
260 | ConstPoolItem::ConstantString(item) => {
261 | format!(" #{} = String #{}", index, item.string_index)
262 | }
263 | ConstPoolItem::ConstantClass(item) => {
264 | format!(" #{} = Class #{}", index, item.name_index)
265 | }
266 | ConstPoolItem::ConstantUtf8(item) => format!(
267 | " #{} = Utf8 {}",
268 | index,
269 | String::from_utf8_lossy(item.bytes.as_slice())
270 | ),
271 | ConstPoolItem::ConstantNameAndType(item) => format!(
272 | " #{} = NameAndType #{}:#{}",
273 | index, item.name_index, item.descriptor_index
274 | ),
275 | ConstPoolItem::ConstantLong(item) => format!(
276 | " #{} = Long {}l",
277 | index,
278 | ((item.high_bytes as i64) << 32) as i64 | item.low_bytes as i64
279 | ),
280 | ConstPoolItem::ConstantDouble(item) => format!(
281 | " #{} = Double {}",
282 | index,
283 | ((item.high_bytes << 8) | item.low_bytes) & 0xFFFF
284 | ),
285 | _ => unimplemented!(),
286 | };
287 | result.push(rw);
288 | }
289 | write!(f, "{}", result.join("\n"))
290 | }
291 | }
292 |
293 | #[derive(Debug, PartialEq)]
294 | pub enum ConstPoolTag {
295 | ConstantNull = 0, // custom tag for index 0
296 | ConstantClass = 7,
297 | ConstantFieldref = 9,
298 | ConstantMethodref = 10,
299 | ConstantInterfaceMethodref = 11,
300 | ConstantString = 8,
301 | ConstantInteger = 3,
302 | ConstantFloat = 4,
303 | ConstantLong = 5,
304 | ConstantDouble = 6,
305 | ConstantNameAndType = 12,
306 | ConstantUtf8 = 1,
307 | ConstantMethodHandle = 15,
308 | ConstantMethodType = 16,
309 | ConstantInvokeDynamic = 18,
310 | }
311 |
312 | impl From for ConstPoolTag {
313 | fn from(num: usize) -> ConstPoolTag {
314 | match num {
315 | 0 => ConstPoolTag::ConstantNull,
316 | 7 => ConstPoolTag::ConstantClass,
317 | 9 => ConstPoolTag::ConstantFieldref,
318 | 10 => ConstPoolTag::ConstantMethodref,
319 | 11 => ConstPoolTag::ConstantInterfaceMethodref,
320 | 8 => ConstPoolTag::ConstantString,
321 | 3 => ConstPoolTag::ConstantInteger,
322 | 4 => ConstPoolTag::ConstantFloat,
323 | 5 => ConstPoolTag::ConstantLong,
324 | 6 => ConstPoolTag::ConstantDouble,
325 | 12 => ConstPoolTag::ConstantNameAndType,
326 | 1 => ConstPoolTag::ConstantUtf8,
327 | 15 => ConstPoolTag::ConstantMethodHandle,
328 | 16 => ConstPoolTag::ConstantMethodType,
329 | 18 => ConstPoolTag::ConstantInvokeDynamic,
330 | _ => panic!("failed to convert {} to ConstPoolTag", num),
331 | }
332 | }
333 | }
334 |
335 | #[derive(Debug, PartialEq)]
336 | pub enum ConstPoolItem {
337 | ConstantNull,
338 | ConstantClass(ConstantClass),
339 | ConstantFieldref(ConstantFieldref),
340 | ConstantMethodref(ConstantMethodref),
341 | ConstantInterfaceMethodref,
342 | ConstantString(ConstantString),
343 | ConstantInteger,
344 | ConstantFloat(ConstantFloat),
345 | ConstantLong(ConstantLong),
346 | ConstantDouble(ConstantDouble),
347 | ConstantNameAndType(ConstantNameAndType),
348 | ConstantUtf8(ConstantUtf8),
349 | ConstantMethodHandle,
350 | ConstantMethodType,
351 | ConstantInvokeDynamic,
352 | }
353 |
354 | #[derive(Debug, PartialEq)]
355 | pub struct ConstantLong {
356 | pub tag: ConstPoolTag,
357 | pub high_bytes: usize, // u4
358 | pub low_bytes: usize, // u4
359 | }
360 |
361 | impl ConstantLong {
362 | pub fn create_and_update_index(inputs: &[u8], index: usize) -> (ConstantLong, usize) {
363 | let (high_bytes, index) = extract_x_byte_as_usize(inputs, index, 4);
364 | let (low_bytes, index) = extract_x_byte_as_usize(inputs, index, 4);
365 | (
366 | ConstantLong {
367 | tag: ConstPoolTag::ConstantString,
368 | high_bytes,
369 | low_bytes,
370 | },
371 | index,
372 | )
373 | }
374 | }
375 |
376 | #[derive(Debug, PartialEq)]
377 | pub struct ConstantDouble {
378 | pub tag: ConstPoolTag,
379 | pub high_bytes: usize, // u4
380 | pub low_bytes: usize, // u4
381 | }
382 |
383 | impl ConstantDouble {
384 | pub fn create_and_update_index(inputs: &[u8], index: usize) -> (ConstantDouble, usize) {
385 | let (high_bytes, index) = extract_x_byte_as_usize(inputs, index, 4);
386 | let (low_bytes, index) = extract_x_byte_as_usize(inputs, index, 4);
387 | (
388 | ConstantDouble {
389 | tag: ConstPoolTag::ConstantString,
390 | high_bytes,
391 | low_bytes,
392 | },
393 | index,
394 | )
395 | }
396 | }
397 |
398 | #[derive(Debug, PartialEq)]
399 | pub struct ConstantString {
400 | pub tag: ConstPoolTag,
401 | pub string_index: usize, // u2
402 | }
403 |
404 | impl ConstantString {
405 | pub fn create_and_update_index(inputs: &[u8], index: usize) -> (ConstantString, usize) {
406 | let (string_index, index) = extract_x_byte_as_usize(inputs, index, 2);
407 | (
408 | ConstantString {
409 | tag: ConstPoolTag::ConstantString,
410 | string_index,
411 | },
412 | index,
413 | )
414 | }
415 | }
416 |
417 | #[derive(Debug, PartialEq)]
418 | pub struct ConstantFloat {
419 | pub tag: ConstPoolTag,
420 | pub bytes: usize, // u4
421 | }
422 |
423 | impl ConstantFloat {
424 | pub fn create_and_update_index(inputs: &[u8], index: usize) -> (ConstantFloat, usize) {
425 | let (bytes, index) = extract_x_byte_as_usize(inputs, index, 4);
426 | (
427 | ConstantFloat {
428 | tag: ConstPoolTag::ConstantFloat,
429 | bytes,
430 | },
431 | index,
432 | )
433 | }
434 | }
435 |
436 | #[derive(Debug, PartialEq)]
437 | pub struct ConstantFieldref {
438 | pub tag: ConstPoolTag,
439 | pub class_index: usize, // u2
440 | pub name_and_type_index: usize, // u2
441 | }
442 |
443 | impl ConstantFieldref {
444 | pub fn create_and_update_index(inputs: &[u8], index: usize) -> (ConstantFieldref, usize) {
445 | let (class_index, index) = extract_x_byte_as_usize(inputs, index, 2);
446 | let (name_and_type_index, index) = extract_x_byte_as_usize(inputs, index, 2);
447 | (
448 | ConstantFieldref {
449 | tag: ConstPoolTag::ConstantFieldref,
450 | class_index,
451 | name_and_type_index,
452 | },
453 | index,
454 | )
455 | }
456 | }
457 |
458 | #[derive(Debug, PartialEq)]
459 | pub struct ConstantNameAndType {
460 | pub tag: ConstPoolTag,
461 | pub name_index: usize, // u2
462 | pub descriptor_index: usize, // u2
463 | }
464 |
465 | impl ConstantNameAndType {
466 | pub fn create_and_update_index(inputs: &[u8], index: usize) -> (ConstantNameAndType, usize) {
467 | let (name_index, index) = extract_x_byte_as_usize(inputs, index, 2);
468 | let (descriptor_index, index) = extract_x_byte_as_usize(inputs, index, 2);
469 |
470 | (
471 | ConstantNameAndType {
472 | tag: ConstPoolTag::ConstantNameAndType,
473 | name_index,
474 | descriptor_index,
475 | },
476 | index,
477 | )
478 | }
479 | }
480 |
481 | #[derive(Debug, PartialEq)]
482 | pub struct ConstantClass {
483 | pub tag: ConstPoolTag,
484 | pub name_index: usize, // u2
485 | }
486 |
487 | impl ConstantClass {
488 | pub fn create_and_update_index(inputs: &[u8], index: usize) -> (ConstantClass, usize) {
489 | let (name_index, index) = extract_x_byte_as_usize(inputs, index, 2);
490 | (
491 | ConstantClass {
492 | tag: ConstPoolTag::ConstantClass,
493 | name_index,
494 | },
495 | index,
496 | )
497 | }
498 | }
499 |
500 | #[derive(Debug, PartialEq)]
501 | pub struct ConstantMethodref {
502 | pub tag: ConstPoolTag,
503 | pub class_index: usize, // u2
504 | pub name_and_type_index: usize, // u2
505 | }
506 |
507 | impl ConstantMethodref {
508 | pub fn create_and_update_index(inputs: &[u8], index: usize) -> (ConstantMethodref, usize) {
509 | let (class_index, index) = extract_x_byte_as_usize(inputs, index, 2);
510 | let (name_and_type_index, index) = extract_x_byte_as_usize(inputs, index, 2);
511 |
512 | (
513 | ConstantMethodref {
514 | tag: ConstPoolTag::ConstantMethodref,
515 | class_index,
516 | name_and_type_index,
517 | },
518 | index,
519 | )
520 | }
521 | }
522 |
523 | #[derive(Debug, PartialEq)]
524 | pub struct ConstantUtf8 {
525 | pub id: usize, // custom value
526 | pub tag: ConstPoolTag,
527 | pub length: usize, // u2
528 | pub bytes: Vec,
529 | }
530 |
531 | impl ConstantUtf8 {
532 | pub fn create_and_update_index(
533 | string_map: &mut StringPool,
534 | inputs: &[u8],
535 | index: usize,
536 | ) -> (ConstantUtf8, usize) {
537 | let (utf8_length, index) = extract_x_byte_as_usize(inputs, index, 2);
538 | let (bytes, index) = extract_x_byte_as_vec(inputs, index, utf8_length);
539 | let value = String::from_utf8_lossy(bytes.as_slice());
540 | let id = string_map.insert(value.to_string());
541 |
542 | (
543 | ConstantUtf8 {
544 | id,
545 | tag: ConstPoolTag::ConstantUtf8,
546 | length: utf8_length,
547 | bytes,
548 | },
549 | index,
550 | )
551 | }
552 | }
553 |
554 | #[cfg(test)]
555 | mod test {
556 | use super::*;
557 | #[test]
558 | fn constant_pool_constant_methodref() {
559 | let mut inputs = vec![
560 | 0x0a, // class
561 | 0x00, 0x0a, // class_index
562 | 0x00, 0x0b, // name_and_type_index
563 | ];
564 |
565 | let result = ConstantPool::new(&mut StringPool::new(), &mut inputs, 0, 2);
566 |
567 | assert_eq!(
568 | result,
569 | (
570 | ConstantPool(vec![
571 | ConstPoolItem::ConstantNull,
572 | ConstPoolItem::ConstantMethodref(ConstantMethodref {
573 | tag: ConstPoolTag::ConstantMethodref,
574 | class_index: 0x0a,
575 | name_and_type_index: 0x0b
576 | })
577 | ]),
578 | inputs.len()
579 | )
580 | );
581 | }
582 |
583 | #[test]
584 | fn constant_pool_constant_class() {
585 | let mut inputs = vec![
586 | 0x07, // class
587 | 0x00, 0x0b, // name_index
588 | ];
589 | let result = ConstantPool::new(&mut StringPool::new(), &mut inputs, 0, 2);
590 |
591 | assert_eq!(
592 | result,
593 | (
594 | ConstantPool(vec![
595 | ConstPoolItem::ConstantNull,
596 | ConstPoolItem::ConstantClass(ConstantClass {
597 | tag: ConstPoolTag::ConstantClass,
598 | name_index: 0x0b
599 | })
600 | ]),
601 | inputs.len()
602 | )
603 | );
604 | }
605 |
606 | // #[test]
607 | // fn constant_pool_utf8() {
608 | // let mut inputs = [
609 | // 0x01, // utf8
610 | // 0x00, 0x0A, // length
611 | // 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6C, 0x65, // bytes(SourceFile)
612 | // ];
613 | // let result = ConstantPool::new(&mut inputs, 0, 2);
614 |
615 | // assert_eq!(
616 | // result,
617 | // (
618 | // ConstantPool(vec![
619 | // ConstPoolItem::ConstantNull,
620 | // ConstPoolItem::ConstantUtf8(ConstantUtf8 {
621 |
622 | // tag: ConstPoolTag::ConstantUtf8,
623 | // length: 0x0a,
624 | // bytes: vec![0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6C, 0x65]
625 | // })
626 | // ]),
627 | // inputs.len()
628 | // )
629 | // );
630 | // }
631 |
632 | #[test]
633 | fn constant_pool_name_and_type() {
634 | let mut inputs = vec![
635 | 0x0c, // name_and_type
636 | 0x00, 0x0a, // name_index
637 | 0x00, 0x0b, // descriptor_index
638 | ];
639 | let result = ConstantPool::new(&mut StringPool::new(), &mut inputs, 0, 2);
640 |
641 | assert_eq!(
642 | result,
643 | (
644 | ConstantPool(vec![
645 | ConstPoolItem::ConstantNull,
646 | ConstPoolItem::ConstantNameAndType(ConstantNameAndType {
647 | tag: ConstPoolTag::ConstantNameAndType,
648 | name_index: 0x0a,
649 | descriptor_index: 0x0b
650 | })
651 | ]),
652 | inputs.len()
653 | )
654 | );
655 | }
656 |
657 | #[test]
658 | fn constant_pool_name_and_type_print() {
659 | let mut inputs = vec![
660 | 0x0c, // name_and_type
661 | 0x00, 0x0a, // name_index
662 | 0x00, 0x0b, // descriptor_index
663 | ];
664 | let (constant_pool, _) = ConstantPool::new(&mut StringPool::new(), &mut inputs, 0, 2);
665 |
666 | assert_eq!(
667 | format!("{}", constant_pool),
668 | " #1 = NameAndType #10:#11"
669 | );
670 | }
671 | }
672 |
--------------------------------------------------------------------------------
/src/attribute/instruction.rs:
--------------------------------------------------------------------------------
1 | use crate::utils::{extract_x_byte_as_usize, extract_x_byte_as_vec};
2 | use std::fmt;
3 |
4 | #[derive(Debug)]
5 | pub enum Instruction {
6 | Aconstnull, // 0x01
7 | IconstN(i32), // 0x02(-1) - 0x08(5)
8 | LconstN(usize), // 0x09(0) - 0x0a(1)
9 | FconstN(f32), // 0x0b(0) - 0x0d(1)
10 | DconstN(usize), // 0x0e(0) - 0x0f(1)
11 | Bipush(i32), // 0x10
12 | Sipush(usize), // 0x11
13 | Ldc(usize), // 0x12
14 | Ldc2W(usize, usize), // 0x14
15 | Iload(usize), // 0x15
16 | Aload(usize), // 0x19
17 | IloadN(usize), // 0x1a(0) - 0x1d(3)
18 | LloadN(usize), // 0x1e(0) - 0x21(3)
19 | FloadN(usize), // 0x22(0) - 0x25(3)
20 | DloadN(usize), // 0x26(0) - 0x29(3)
21 | AloadN(usize), // 0x2a(0) - 0x2d(3)
22 | Iaload, // 0x2e
23 | Laload, // 0x2f
24 | Aaload, // 0x32
25 | Baload, // 0x33
26 | Istore(i32), // 0x36
27 | Astore(usize), // 0x3a
28 | IstoreN(i32), // 0x3b(0) - 0x3e(3)
29 | LstoreN(usize), // 0x3f(0) - 0x42(3)
30 | FstoreN(usize), // 0x43(0) - 0x46(3)
31 | DstoreN(usize), // 0x47(0) - 0x4a(3)
32 | AstoreN(usize), // 0x4b(0) - 0x4e(3)
33 | Iastore, // 0x4f
34 | Lastore, // 0x50
35 | Aastore, // 0x53
36 | Bastore, // 0x54
37 | Pop, // 0x57
38 | Dup, // 0x59
39 | Iadd, // 0x60
40 | Ladd, // 0x61
41 | Fadd, // 0x62
42 | Isub, // 0x64
43 | Lsub, // 0x65
44 | Fsub, // 0x66
45 | Imul, // 0x68
46 | Lmul, // 0x69
47 | Fmul, // 0x6a
48 | Idiv, // 0x6c
49 | Ldiv, // 0x6d
50 | Fdiv, // 0x6e
51 | Irem, // 0x70
52 | Lrem, // 0x71
53 | Iinc(usize, usize), // 0x84
54 | Lcmp, // 0x94
55 | Fcmpg, // 0x95
56 | Fcmpl, // 0x96
57 | Ifeq(usize, usize), // 0x99
58 | Ifne(usize, usize), // 0x9a
59 | Iflt(usize, usize), // 0x9b
60 | Ifge(usize, usize), // 0x9c
61 | Ifgt(usize, usize), // 0x9d
62 | Ifle(usize, usize), // 0x9e
63 | Ificmpeq(usize, usize), // 0x9f
64 | Ificmpne(usize, usize), // 0xa0
65 | Ificmplt(usize, usize), // 0xa1
66 | Ificmpge(usize, usize), // 0xa2
67 | Ificmpgt(usize, usize), // 0xa3
68 | Ificmple(usize, usize), // 0xa4
69 | Goto(usize), // 0xa7
70 | Lookupswitch(Vec<(Option, usize)>), // 0xab
71 | Ireturn, // 0xac
72 | Areturn, // 0xb0
73 | Return, // 0xb1
74 | Getstatic(usize), // 0xb2
75 | Putstatic(usize), // 0xb3
76 | Getfield(usize), // 0xb4
77 | Putfield(usize), // 0xb5
78 | Invokevirtual(usize), // 0xb6
79 | Invokespecial(usize), // 0xb7
80 | Invokestatic(usize), // 0xb8
81 | New(usize), // 0xbb
82 | Newarray(usize), // 0xbc
83 | Anewarray(usize), // 0xbd
84 | Multianewarray(usize, usize), // 0xc5
85 | Noope, // custom command for Ificmple etc.
86 | }
87 |
88 | impl fmt::Display for Instruction {
89 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 | match self {
91 | Instruction::Aconstnull => write!(f, "aconst_null"),
92 | Instruction::IconstN(val) => write!(f, "iconst_{}", val),
93 | Instruction::LconstN(val) => write!(f, "lconst_{}", val),
94 | Instruction::FconstN(val) => write!(f, "fconst_{}", val),
95 | Instruction::DconstN(val) => write!(f, "dconst_{}", val),
96 | Instruction::Bipush(val) => write!(f, "bipush {}", val),
97 | Instruction::Sipush(val) => write!(f, "sipush {}", val),
98 | Instruction::Ldc(val) => write!(f, "ldc #{}", val),
99 | Instruction::Ldc2W(a, b) => write!(f, "ldc2_w #{},{}", a, b),
100 | Instruction::Iload(val) => write!(f, "iload #{}", val),
101 | Instruction::Aload(val) => write!(f, "aload #{}", val),
102 | Instruction::IloadN(val) => write!(f, "iload_{}", val),
103 | Instruction::LloadN(val) => write!(f, "lload_{}", val),
104 | Instruction::FloadN(val) => write!(f, "fload_{}", val),
105 | Instruction::DloadN(val) => write!(f, "dload_{}", val),
106 | Instruction::AloadN(val) => write!(f, "aload_{}", val),
107 | Instruction::Iaload => write!(f, "iaload"),
108 | Instruction::Laload => write!(f, "laload"),
109 | Instruction::Aaload => write!(f, "aaload"),
110 | Instruction::Baload => write!(f, "baload"),
111 | Instruction::Istore(val) => write!(f, "istore #{}", val),
112 | Instruction::Astore(val) => write!(f, "astore #{}", val),
113 | Instruction::Aastore => write!(f, "aastore"),
114 | Instruction::Bastore => write!(f, "bastore"),
115 | Instruction::IstoreN(val) => write!(f, "istore_{}", val),
116 | Instruction::LstoreN(val) => write!(f, "lstore_{}", val),
117 | Instruction::FstoreN(val) => write!(f, "fstore_{}", val),
118 | Instruction::DstoreN(val) => write!(f, "dstore_{}", val),
119 | Instruction::Iastore => write!(f, "iastore"),
120 | Instruction::Lastore => write!(f, "lastore"),
121 | Instruction::AstoreN(val) => write!(f, "astore_{}", val),
122 | Instruction::Pop => write!(f, "pop"),
123 | Instruction::Dup => write!(f, "dup"),
124 | Instruction::Iadd => write!(f, "iadd"),
125 | Instruction::Ladd => write!(f, "ladd"),
126 | Instruction::Fadd => write!(f, "fadd"),
127 | Instruction::Isub => write!(f, "isub"),
128 | Instruction::Lsub => write!(f, "lsub"),
129 | Instruction::Fsub => write!(f, "fsub"),
130 | Instruction::Imul => write!(f, "imul"),
131 | Instruction::Lmul => write!(f, "lmul"),
132 | Instruction::Fmul => write!(f, "fmul"),
133 | Instruction::Idiv => write!(f, "idiv"),
134 | Instruction::Ldiv => write!(f, "ldiv"),
135 | Instruction::Fdiv => write!(f, "fdiv"),
136 | Instruction::Irem => write!(f, "irem"),
137 | Instruction::Lrem => write!(f, "lrem"),
138 | Instruction::Iinc(a, b) => write!(f, "iinc {}, {}", a, b),
139 | Instruction::Lcmp => write!(f, "lcmp"),
140 | Instruction::Fcmpg => write!(f, "fcmpg"),
141 | Instruction::Fcmpl => write!(f, "fcmpl"),
142 | Instruction::Ifeq(a, b) => write!(f, "if_eq {}, {}", a, b),
143 | Instruction::Ifne(a, b) => write!(f, "if_ne {}, {}", a, b),
144 | Instruction::Iflt(a, b) => write!(f, "if_lt {}, {}", a, b),
145 | Instruction::Ifge(a, b) => write!(f, "if_ge {}, {}", a, b),
146 | Instruction::Ifgt(a, b) => write!(f, "if_gt {}, {}", a, b),
147 | Instruction::Ifle(a, b) => write!(f, "if_le {}, {}", a, b),
148 | Instruction::Ificmpeq(a, b) => write!(f, "if_icmpeq {}, {}", a, b),
149 | Instruction::Ificmpne(a, b) => write!(f, "if_icmpne {}, {}", a, b),
150 | Instruction::Ificmplt(a, b) => write!(f, "if_icmplt {}, {}", a, b),
151 | Instruction::Ificmpge(a, b) => write!(f, "if_icmpge {}, {}", a, b),
152 | Instruction::Ificmpgt(a, b) => write!(f, "if_icmpgt {}, {}", a, b),
153 | Instruction::Ificmple(a, b) => write!(f, "if_icmple {}, {}", a, b),
154 | Instruction::Goto(val) => write!(f, "goto {}", val),
155 | Instruction::Ireturn => write!(f, "ireturn"),
156 | Instruction::Lookupswitch(vals) => {
157 | let vals_length = vals.len();
158 | let mut output_strings = Vec::with_capacity(vals_length);
159 | for (key, val) in &vals[1..vals_length] {
160 | output_strings.push(format!(" {}: {}", key.unwrap(), val));
161 | }
162 | output_strings.push(format!(" default: {}", vals.last().unwrap().1));
163 | write!(
164 | f,
165 | "lookupswitch {{ // {}
166 | {}
167 | }}",
168 | vals_length - 1,
169 | output_strings.join("\n")
170 | )
171 | }
172 | Instruction::Areturn => write!(f, "areturn"),
173 | Instruction::Return => write!(f, "return"),
174 | Instruction::Getstatic(val) => write!(f, "getstatic #{}", val),
175 | Instruction::Putstatic(val) => write!(f, "putstatic #{}", val),
176 | Instruction::Getfield(val) => write!(f, "getfield #{}", val),
177 | Instruction::Putfield(val) => write!(f, "putfield #{}", val),
178 | Instruction::Invokevirtual(val) => write!(f, "invokevirtual #{}", val),
179 | Instruction::Invokespecial(val) => write!(f, "invokespecial #{}", val),
180 | Instruction::Invokestatic(val) => write!(f, "invokestatic #{}", val),
181 | Instruction::New(val) => write!(f, "new #{}", val),
182 | Instruction::Newarray(val) => write!(f, "newarray #{}", val),
183 | Instruction::Anewarray(val) => write!(f, "anewarray #{}", val),
184 | Instruction::Multianewarray(index, dimensions) => {
185 | write!(f, "multianewarray #{} {}", index, dimensions)
186 | }
187 | Instruction::Noope => write!(f, "noope"),
188 | }
189 | }
190 | }
191 |
192 | impl Instruction {
193 | pub fn create_and_push(
194 | codes: &mut Vec,
195 | inputs: &[u8],
196 | index: usize,
197 | tag: usize,
198 | ) -> (usize, usize) {
199 | macro_rules! simple_instruct {
200 | ($expr:expr) => {
201 | codes.push($expr);
202 | return (index, 1);
203 | };
204 | }
205 |
206 | match tag {
207 | // aconst_null
208 | 0x01 => {
209 | simple_instruct!(Instruction::Aconstnull);
210 | }
211 | // iconst_n
212 | val @ 0x02..=0x08 => {
213 | simple_instruct!(Instruction::IconstN(val as i32 - 0x03));
214 | }
215 | // lconst_n
216 | val @ 0x09..=0x0a => {
217 | simple_instruct!(Instruction::LconstN(val - 0x09));
218 | }
219 | // fconst_n
220 | val @ 0x0b..=0x0d => {
221 | simple_instruct!(Instruction::FconstN((val - 0x0b) as f32));
222 | }
223 | // dconst_n
224 | val @ 0x0e..=0x0f => {
225 | simple_instruct!(Instruction::DconstN(val - 0x0e));
226 | }
227 | // bipush
228 | 0x10 => {
229 | let (val, index) = extract_x_byte_as_usize(inputs, index, 1);
230 | let val = if val > 0x79 {
231 | -1 * ((val ^ 0xff) + 1) as i32
232 | } else {
233 | val as i32
234 | };
235 | codes.push(Instruction::Bipush(val));
236 | codes.push(Instruction::Noope);
237 | (index, 2)
238 | }
239 | // sipush
240 | 0x11 => {
241 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
242 | codes.push(Instruction::Sipush(val));
243 | codes.push(Instruction::Noope);
244 | codes.push(Instruction::Noope);
245 | (index, 3)
246 | }
247 | // ldc
248 | 0x12 => {
249 | let (val, index) = extract_x_byte_as_usize(inputs, index, 1);
250 | codes.push(Instruction::Ldc(val));
251 | codes.push(Instruction::Noope);
252 | (index, 2)
253 | }
254 | // ldc2_w
255 | 0x14 => {
256 | let (val, index) = extract_x_byte_as_vec(inputs, index, 2);
257 | codes.push(Instruction::Ldc2W(val[0] as usize, val[1] as usize));
258 | codes.push(Instruction::Noope);
259 | codes.push(Instruction::Noope);
260 | (index, 3)
261 | }
262 | // iload
263 | 0x15 => {
264 | let (val, index) = extract_x_byte_as_usize(inputs, index, 1);
265 | codes.push(Instruction::Iload(val));
266 | codes.push(Instruction::Noope);
267 | (index, 2)
268 | }
269 | // aload
270 | 0x19 => {
271 | let (val, index) = extract_x_byte_as_usize(inputs, index, 1);
272 | codes.push(Instruction::Aload(val));
273 | codes.push(Instruction::Noope);
274 | (index, 2)
275 | }
276 | // iload_n
277 | val @ 0x1a..=0x1d => {
278 | simple_instruct!(Instruction::IloadN(val - 0x1a));
279 | }
280 | // lload_n
281 | val @ 0x1e..=0x21 => {
282 | simple_instruct!(Instruction::LloadN(val - 0x1e));
283 | }
284 | // fload_n
285 | val @ 0x22..=0x25 => {
286 | simple_instruct!(Instruction::FloadN(val - 0x22));
287 | }
288 | // dload_n
289 | val @ 0x26..=0x29 => {
290 | simple_instruct!(Instruction::DloadN(val - 0x26));
291 | }
292 | // aload_n
293 | val @ 0x2a..=0x2d => {
294 | simple_instruct!(Instruction::AloadN(val - 0x2a));
295 | }
296 | // iaload
297 | 0x2e => {
298 | simple_instruct!(Instruction::Iaload);
299 | }
300 | // laload
301 | 0x2f => {
302 | simple_instruct!(Instruction::Laload);
303 | }
304 | // iaload
305 | 0x32 => {
306 | simple_instruct!(Instruction::Aaload);
307 | }
308 | // baload
309 | 0x33 => {
310 | simple_instruct!(Instruction::Baload);
311 | }
312 | // istore
313 | 0x36 => {
314 | let (val, index) = extract_x_byte_as_usize(inputs, index, 1);
315 | codes.push(Instruction::Istore(val as i32));
316 | codes.push(Instruction::Noope);
317 | (index, 2)
318 | }
319 | // astore
320 | 0x3a => {
321 | let (val, index) = extract_x_byte_as_usize(inputs, index, 1);
322 | codes.push(Instruction::Astore(val));
323 | codes.push(Instruction::Noope);
324 | (index, 2)
325 | }
326 | // istore_n
327 | val @ 0x3b..=0x3e => {
328 | simple_instruct!(Instruction::IstoreN(val as i32 - 0x3b));
329 | }
330 | // lstore_n
331 | val @ 0x3f..=0x42 => {
332 | simple_instruct!(Instruction::LstoreN(val - 0x3f));
333 | }
334 | // fstore_n
335 | val @ 0x43..=0x46 => {
336 | simple_instruct!(Instruction::FstoreN(val - 0x43));
337 | }
338 | // dstore_n
339 | val @ 0x47..=0x4a => {
340 | simple_instruct!(Instruction::DstoreN(val - 0x47));
341 | }
342 | // astore_n
343 | val @ 0x4b..=0x4e => {
344 | simple_instruct!(Instruction::AstoreN(val - 0x4b));
345 | }
346 | // iastore
347 | 0x4f => {
348 | simple_instruct!(Instruction::Iastore);
349 | }
350 | // lastore
351 | 0x50 => {
352 | simple_instruct!(Instruction::Lastore);
353 | }
354 | // aastore
355 | 0x53 => {
356 | simple_instruct!(Instruction::Aastore);
357 | }
358 | // bastore
359 | 0x54 => {
360 | simple_instruct!(Instruction::Bastore);
361 | }
362 | // pop
363 | 0x57 => {
364 | simple_instruct!(Instruction::Pop);
365 | }
366 | // dup
367 | 0x59 => {
368 | simple_instruct!(Instruction::Dup);
369 | }
370 | // iadd
371 | 0x60 => {
372 | simple_instruct!(Instruction::Iadd);
373 | }
374 | // ladd
375 | 0x61 => {
376 | simple_instruct!(Instruction::Ladd);
377 | }
378 | // fadd
379 | 0x62 => {
380 | simple_instruct!(Instruction::Fadd);
381 | }
382 | // isub
383 | 0x64 => {
384 | simple_instruct!(Instruction::Isub);
385 | }
386 | // lsub
387 | 0x65 => {
388 | simple_instruct!(Instruction::Lsub);
389 | }
390 | // fsub
391 | 0x66 => {
392 | simple_instruct!(Instruction::Fsub);
393 | }
394 | // imul
395 | 0x68 => {
396 | simple_instruct!(Instruction::Imul);
397 | }
398 | // lmul
399 | 0x69 => {
400 | simple_instruct!(Instruction::Lmul);
401 | }
402 | // fmul
403 | 0x6a => {
404 | simple_instruct!(Instruction::Fmul);
405 | }
406 | // idiv
407 | 0x6c => {
408 | simple_instruct!(Instruction::Idiv);
409 | }
410 | // ldiv
411 | 0x6d => {
412 | simple_instruct!(Instruction::Ldiv);
413 | }
414 | // fdiv
415 | 0x6e => {
416 | simple_instruct!(Instruction::Fdiv);
417 | }
418 | // irem
419 | 0x70 => {
420 | simple_instruct!(Instruction::Irem);
421 | }
422 | // lrem
423 | 0x71 => {
424 | simple_instruct!(Instruction::Lrem);
425 | }
426 | // iinc
427 | 0x84 => {
428 | let (val, index) = extract_x_byte_as_vec(inputs, index, 2);
429 | codes.push(Instruction::Iinc(val[0] as usize, val[1] as usize));
430 | codes.push(Instruction::Noope);
431 | codes.push(Instruction::Noope);
432 | (index, 3)
433 | }
434 | // lcmp
435 | 0x94 => {
436 | simple_instruct!(Instruction::Lcmp);
437 | }
438 | // fcmpg
439 | 0x95 => {
440 | simple_instruct!(Instruction::Fcmpg);
441 | }
442 | // fcmpl
443 | 0x96 => {
444 | simple_instruct!(Instruction::Fcmpl);
445 | }
446 | // ifeq
447 | 0x99 => {
448 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
449 | let code_length = codes.len();
450 | codes.push(Instruction::Ifeq(
451 | (val + code_length - 1) & 0xffff,
452 | code_length + 2,
453 | ));
454 | codes.push(Instruction::Noope);
455 | codes.push(Instruction::Noope);
456 | (index, 3)
457 | }
458 | // ifne
459 | 0x9a => {
460 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
461 | let code_length = codes.len();
462 | codes.push(Instruction::Ifne(
463 | (val + code_length - 1) & 0xffff,
464 | code_length + 2,
465 | ));
466 | codes.push(Instruction::Noope);
467 | codes.push(Instruction::Noope);
468 | (index, 3)
469 | }
470 | // iflt
471 | 0x9b => {
472 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
473 | let code_length = codes.len();
474 | codes.push(Instruction::Iflt(
475 | (val + code_length - 1) & 0xffff,
476 | code_length + 2,
477 | ));
478 | codes.push(Instruction::Noope);
479 | codes.push(Instruction::Noope);
480 | (index, 3)
481 | }
482 | // ifge
483 | 0x9c => {
484 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
485 | let code_length = codes.len();
486 | codes.push(Instruction::Ifge(
487 | (val + code_length - 1) & 0xffff,
488 | code_length + 2,
489 | ));
490 | codes.push(Instruction::Noope);
491 | codes.push(Instruction::Noope);
492 | (index, 3)
493 | }
494 | // ifgt
495 | 0x9d => {
496 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
497 | let code_length = codes.len();
498 | codes.push(Instruction::Ifgt(
499 | (val + code_length - 1) & 0xffff,
500 | code_length + 2,
501 | ));
502 | codes.push(Instruction::Noope);
503 | codes.push(Instruction::Noope);
504 | (index, 3)
505 | }
506 | // ifle
507 | 0x9e => {
508 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
509 | let code_length = codes.len();
510 | codes.push(Instruction::Ifle(
511 | (val + code_length - 1) & 0xffff,
512 | code_length + 2,
513 | ));
514 | codes.push(Instruction::Noope);
515 | codes.push(Instruction::Noope);
516 | (index, 3)
517 | }
518 | // if_icmpeq
519 | 0x9f => {
520 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
521 | let code_length = codes.len();
522 | codes.push(Instruction::Ificmpeq(
523 | (val + code_length - 1) & 0xffff,
524 | code_length + 2,
525 | ));
526 | codes.push(Instruction::Noope);
527 | codes.push(Instruction::Noope);
528 | (index, 3)
529 | }
530 | // if_icmpne
531 | 0xa0 => {
532 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
533 | let code_length = codes.len();
534 | codes.push(Instruction::Ificmpne(
535 | (val + code_length - 1) & 0xffff,
536 | code_length + 2,
537 | ));
538 | codes.push(Instruction::Noope);
539 | codes.push(Instruction::Noope);
540 | (index, 3)
541 | }
542 | // if_icmplt
543 | 0xa1 => {
544 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
545 | let code_length = codes.len();
546 | codes.push(Instruction::Ificmplt(
547 | (val + code_length - 1) & 0xffff,
548 | code_length + 2,
549 | ));
550 | codes.push(Instruction::Noope);
551 | codes.push(Instruction::Noope);
552 | (index, 3)
553 | }
554 | // if_icmpge
555 | 0xa2 => {
556 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
557 | let code_length = codes.len();
558 | codes.push(Instruction::Ificmpge(
559 | (val + code_length - 1) & 0xffff,
560 | code_length + 2,
561 | ));
562 | codes.push(Instruction::Noope);
563 | codes.push(Instruction::Noope);
564 | (index, 3)
565 | }
566 | // if_icmpgt
567 | 0xa3 => {
568 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
569 | let code_length = codes.len();
570 | codes.push(Instruction::Ificmpgt(
571 | (val + code_length - 1) & 0xffff,
572 | code_length + 2,
573 | ));
574 | codes.push(Instruction::Noope);
575 | codes.push(Instruction::Noope);
576 | (index, 3)
577 | }
578 | // if_icmple
579 | 0xa4 => {
580 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
581 | let code_length = codes.len();
582 | codes.push(Instruction::Ificmple(
583 | (val + code_length - 1) & 0xffff,
584 | code_length + 2,
585 | ));
586 | codes.push(Instruction::Noope);
587 | codes.push(Instruction::Noope);
588 | (index, 3)
589 | }
590 | // goto
591 | 0xa7 => {
592 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
593 | let code_length = codes.len();
594 | codes.push(Instruction::Goto((val + code_length - 1) & 0xFFFF));
595 | codes.push(Instruction::Noope);
596 | codes.push(Instruction::Noope);
597 | (index, 3)
598 | }
599 | // lookupswitch
600 | 0xab => {
601 | let (offset, index) = extract_x_byte_as_usize(inputs, index, 4);
602 | // default_value can be used for branch_length
603 | let (default_value, mut index) = extract_x_byte_as_usize(inputs, index, 4);
604 | // default + branch_length
605 | let mut switch_values = Vec::with_capacity(1 + default_value);
606 | switch_values.push((None, offset + default_value));
607 |
608 | for _ in 0..default_value {
609 | let (key, update_index) = extract_x_byte_as_usize(inputs, index, 4);
610 | let (val, update_index) = extract_x_byte_as_usize(inputs, update_index, 4);
611 | switch_values.push((Some(key), val + default_value));
612 | index = update_index
613 | }
614 | codes.push(Instruction::Lookupswitch(switch_values));
615 |
616 | let set_length = default_value + 1;
617 | let switch_instructions_len = set_length * 4 * 2;
618 | for _ in 0..switch_instructions_len {
619 | codes.push(Instruction::Noope)
620 | }
621 | (index, switch_instructions_len + 1)
622 | }
623 | // ireturn
624 | 0xac => {
625 | simple_instruct!(Instruction::Ireturn);
626 | }
627 | // areturn
628 | 0xb0 => {
629 | simple_instruct!(Instruction::Areturn);
630 | }
631 | // return
632 | 0xb1 => {
633 | simple_instruct!(Instruction::Return);
634 | }
635 | // getstatic
636 | 0xb2 => {
637 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
638 | codes.push(Instruction::Getstatic(val));
639 | codes.push(Instruction::Noope);
640 | codes.push(Instruction::Noope);
641 | (index, 3)
642 | }
643 | // getstatic
644 | 0xb3 => {
645 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
646 | codes.push(Instruction::Putstatic(val));
647 | codes.push(Instruction::Noope);
648 | codes.push(Instruction::Noope);
649 | (index, 3)
650 | }
651 | // getfield
652 | 0xb4 => {
653 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
654 | codes.push(Instruction::Getfield(val));
655 | codes.push(Instruction::Noope);
656 | codes.push(Instruction::Noope);
657 | (index, 3)
658 | }
659 | // putfield
660 | 0xb5 => {
661 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
662 | codes.push(Instruction::Putfield(val));
663 | codes.push(Instruction::Noope);
664 | codes.push(Instruction::Noope);
665 | (index, 3)
666 | }
667 | // invokevirtual
668 | 0xb6 => {
669 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
670 | codes.push(Instruction::Invokevirtual(val));
671 | codes.push(Instruction::Noope);
672 | codes.push(Instruction::Noope);
673 | (index, 3)
674 | }
675 | // invokespecial
676 | 0xb7 => {
677 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
678 | codes.push(Instruction::Invokespecial(val));
679 | codes.push(Instruction::Noope);
680 | codes.push(Instruction::Noope);
681 | (index, 3)
682 | }
683 | // invokestatic
684 | 0xb8 => {
685 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
686 | codes.push(Instruction::Invokestatic(val));
687 | codes.push(Instruction::Noope);
688 | codes.push(Instruction::Noope);
689 | (index, 3)
690 | }
691 | // new
692 | 0xbb => {
693 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
694 | codes.push(Instruction::New(val));
695 | codes.push(Instruction::Noope);
696 | codes.push(Instruction::Noope);
697 | (index, 3)
698 | }
699 | // newarray
700 | 0xbc => {
701 | let (val, index) = extract_x_byte_as_usize(inputs, index, 1);
702 | codes.push(Instruction::Newarray(val));
703 | codes.push(Instruction::Noope);
704 | (index, 2)
705 | }
706 | // anewarray
707 | 0xbd => {
708 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
709 | codes.push(Instruction::Anewarray(val));
710 | codes.push(Instruction::Noope);
711 | codes.push(Instruction::Noope);
712 | (index, 3)
713 | }
714 | // multianewarray
715 | 0xc5 => {
716 | let (val, index) = extract_x_byte_as_usize(inputs, index, 2);
717 | let (dimentions, index) = extract_x_byte_as_usize(inputs, index, 1);
718 | codes.push(Instruction::Multianewarray(val, dimentions));
719 | codes.push(Instruction::Noope);
720 | codes.push(Instruction::Noope);
721 | codes.push(Instruction::Noope);
722 | (index, 4)
723 | }
724 | _ => unimplemented!("tag: {:x}", tag),
725 | }
726 | }
727 |
728 | pub fn counsume_index(&self) -> usize {
729 | match self {
730 | Instruction::Lookupswitch(vals) => vals.len() * 4,
731 | Instruction::Multianewarray(_, _) => 3,
732 | Instruction::Ificmple(_, _)
733 | | Instruction::Getstatic(_)
734 | | Instruction::Putstatic(_)
735 | | Instruction::Getfield(_)
736 | | Instruction::Putfield(_)
737 | | Instruction::Iinc(_, _)
738 | | Instruction::Sipush(_)
739 | | Instruction::Ldc2W(_, _)
740 | | Instruction::Invokevirtual(_)
741 | | Instruction::Invokespecial(_)
742 | | Instruction::Invokestatic(_)
743 | | Instruction::New(_)
744 | | Instruction::Anewarray(_) => 2,
745 | Instruction::Iload(_)
746 | | Instruction::Aload(_)
747 | | Instruction::Istore(_)
748 | | Instruction::Astore(_)
749 | | Instruction::Bipush(_)
750 | | Instruction::Newarray(_)
751 | | Instruction::Ldc(_) => 1,
752 | Instruction::Aconstnull
753 | | Instruction::IconstN(_)
754 | | Instruction::LconstN(_)
755 | | Instruction::FconstN(_)
756 | | Instruction::DconstN(_)
757 | | Instruction::IstoreN(_)
758 | | Instruction::IloadN(_)
759 | | Instruction::LstoreN(_)
760 | | Instruction::FstoreN(_)
761 | | Instruction::DstoreN(_)
762 | | Instruction::LloadN(_)
763 | | Instruction::FloadN(_)
764 | | Instruction::DloadN(_)
765 | | Instruction::AstoreN(_)
766 | | Instruction::AloadN(_)
767 | | Instruction::Pop
768 | | Instruction::Dup
769 | | Instruction::Iadd
770 | | Instruction::Ladd
771 | | Instruction::Fadd
772 | | Instruction::Isub
773 | | Instruction::Lsub
774 | | Instruction::Fsub
775 | | Instruction::Imul
776 | | Instruction::Lmul
777 | | Instruction::Fmul
778 | | Instruction::Idiv
779 | | Instruction::Ldiv
780 | | Instruction::Fdiv
781 | | Instruction::Irem
782 | | Instruction::Lrem
783 | | Instruction::Lcmp
784 | | Instruction::Fcmpg
785 | | Instruction::Fcmpl
786 | | Instruction::Ireturn
787 | | Instruction::Areturn
788 | | Instruction::Iaload
789 | | Instruction::Laload
790 | | Instruction::Aaload
791 | | Instruction::Baload
792 | | Instruction::Iastore
793 | | Instruction::Lastore
794 | | Instruction::Aastore
795 | | Instruction::Bastore
796 | | Instruction::Return => 0,
797 | instruction => unimplemented!("{}", instruction),
798 | }
799 | }
800 | }
801 |
--------------------------------------------------------------------------------