{"id":20425950,"url":"https://github.com/franzhaidnor/haidnorjvm","last_synced_at":"2025-04-09T08:12:40.444Z","repository":{"id":182286383,"uuid":"668225757","full_name":"FranzHaidnor/haidnorJVM","owner":"FranzHaidnor","description":"使用 Java 实现的 Java 虚拟机 （JVM implemented using java）","archived":false,"fork":false,"pushed_at":"2024-07-05T02:09:11.000Z","size":1254,"stargazers_count":224,"open_issues_count":1,"forks_count":26,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-02T05:08:42.501Z","etag":null,"topics":["java","jvm","language"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FranzHaidnor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-19T10:07:27.000Z","updated_at":"2025-04-01T11:15:20.000Z","dependencies_parsed_at":"2023-12-29T02:24:07.522Z","dependency_job_id":"e96043f4-dfbe-4ecd-9545-e0f442b4b4e7","html_url":"https://github.com/FranzHaidnor/haidnorJVM","commit_stats":null,"previous_names":["franzhaidnor/haidnorjvm"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranzHaidnor%2FhaidnorJVM","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranzHaidnor%2FhaidnorJVM/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranzHaidnor%2FhaidnorJVM/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FranzHaidnor%2FhaidnorJVM/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FranzHaidnor","download_url":"https://codeload.github.com/FranzHaidnor/haidnorJVM/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247999864,"owners_count":21031046,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","jvm","language"],"created_at":"2024-11-15T07:14:47.196Z","updated_at":"2025-04-09T08:12:40.423Z","avatar_url":"https://github.com/FranzHaidnor.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# haidnorJVM\n使用 Java17 编写的 Java 虚拟机\n\n## 意义  \n1. 纸上得来终觉浅，绝知此事要躬行。只学习 JVM 机制和理论，很多时候任然觉得缺乏那种大彻大悟之感  \n2. 使用简单的方式实现 JVM，用于学习理解 JVM 运行原理\n\n## 主要技术选型\n* [Java 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)\n* [Apache Commons BCEL](https://commons.apache.org/proper/commons-bcel/)\n* [Apache Commons CLI](https://commons.apache.org/proper/commons-cli/)\n\n# 实现功能\n* 实现了 99% 的 JVM 字节码指令。参照 JVM 字节码规范实现 [The Java Virtual Machine Instruction Set](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html)\n* 支持算数运算符 (`+`,`-`,`*`,`^`,`%`,`++`,`--`)\n* 支持关系运算符 (`==`,`!=`,`\u003e`,`\u003c`,`\u003e=`,`\u003c=`)\n* 支持位运算符 (`\u0026`,`|`,`^`,`~`,`\u003c\u003c`,`\u003e\u003e`,`\u003e\u003e\u003e`)\n* 支持赋值运算符 (`=`,`+=`,`-=`,`*=`,`%=`,`\u003c\u003c=`,`\u003e\u003e=`,`\u0026=`,`^=`,`|=`)\n* 支持 instanceof 运算符\n* 支持循环结构代码 (`while`,`do...while`,`for`,`foreach`)\n* 支持条件结构代码 (`if`,`if...else`,`if...else if`)\n* 支出创建自定义类\n* 支持创建对象、访问对象\n* 支持抽象类\n* 支持多态继承、接口\n* 支持访问静态方法\n* 支持访问对象方法\n* 支持 JDK 中自带的 Java 类\n* 支持反射\n* 支持异常\n* switch\n* 枚举 (TODD...)\n* lambda 表达式 (TODD...)\n\n# 局限性\n* 不支持多线程\n* 不支持多维数组\n* 暂无双亲委派机制实现\n* 无垃圾收集器实现。垃圾回收依靠宿主 JVM\n\n# 快速体验\n## 你需要准备什么\n1. 集成开发环境 (IDE)。例如 IntelliJ IDEA、Visual Studio Code 或 Eclipse 等等\n2. JDK 17。并配置 JAVA_HOME\n3. Maven\n\n## 配置日志输出级别\n在 `resources\\simplelogger.properties` 文件中修改日志输出级别，一般使用 `debug`、`info`\n\n* 配置 info 级别将不会看到任何 haidnorJVM 内部运行信息\n* 配置 debug 级别下运行将会非常友好的输出 JVM 正在执行的栈信息\n```java\npublic class Demo5 {\n\n    static {\n        System.out.println(\"Demo5 类被加载了\");\n    }\n\n    public static void main(String[] args) {\n        String str = method1(\"hello world\");\n        method1(str);\n    }\n\n    public static String method1(String s) {\n        return method2(s);\n    }\n\n    public static String method2(String s) {\n        return method3(s);\n    }\n\n    public static String method3(String s) {\n        System.out.println(s);\n        return \"你好 世界\";\n    }\n\n}\n```\n使用 haidnorJVM 运行以上程序将会在控制台输出以下内容。每一个 `匚` 结构图形，都表示一个 JVM 线程栈中的栈帧\n```cmd\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - ┌──────────────────[1] haidnor.jvm.test.demo.Demo5 | static void \u003cclinit\u003e()\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │ 0 GETSTATIC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │ 3 LDC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │ 5 INVOKEVIRTUAL\nDemo5 类被加载了\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │ 8 RETURN\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - └──────────────────[1] haidnor.jvm.test.demo.Demo5 | static void \u003cclinit\u003e()\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - ┌──────────────────[1] haidnor.jvm.test.demo.Demo5 | public static void main(String[] args)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │ 0 LDC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │ 2 INVOKESTATIC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   ┌──────────────────[2] haidnor.jvm.test.demo.Demo5 | public static String method1(String s)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │ 0 ALOAD_0\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │ 1 INVOKESTATIC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   ┌──────────────────[3] haidnor.jvm.test.demo.Demo5 | public static String method2(String s)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │ 0 ALOAD_0\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │ 1 INVOKESTATIC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   ┌──────────────────[4] haidnor.jvm.test.demo.Demo5 | public static String method3(String s)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   │ 0 GETSTATIC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   │ 3 ALOAD_0\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   │ 4 INVOKEVIRTUAL\nhello world\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   │ 7 LDC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   │ 9 ARETURN\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   └──────────────────[4] haidnor.jvm.test.demo.Demo5 | public static String method3(String s)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │ 4 ARETURN\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   └──────────────────[3] haidnor.jvm.test.demo.Demo5 | public static String method2(String s)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │ 4 ARETURN\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   └──────────────────[2] haidnor.jvm.test.demo.Demo5 | public static String method1(String s)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │ 5 ASTORE_1\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │ 6 ALOAD_1\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │ 7 INVOKESTATIC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   ┌──────────────────[2] haidnor.jvm.test.demo.Demo5 | public static String method1(String s)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │ 0 ALOAD_0\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │ 1 INVOKESTATIC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   ┌──────────────────[3] haidnor.jvm.test.demo.Demo5 | public static String method2(String s)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │ 0 ALOAD_0\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │ 1 INVOKESTATIC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   ┌──────────────────[4] haidnor.jvm.test.demo.Demo5 | public static String method3(String s)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   │ 0 GETSTATIC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   │ 3 ALOAD_0\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   │ 4 INVOKEVIRTUAL\n你好 世界\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   │ 7 LDC\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   │ 9 ARETURN\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │                   └──────────────────[4] haidnor.jvm.test.demo.Demo5 | public static String method3(String s)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   │ 4 ARETURN\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │                   └──────────────────[3] haidnor.jvm.test.demo.Demo5 | public static String method2(String s)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   │ 4 ARETURN\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │                   └──────────────────[2] haidnor.jvm.test.demo.Demo5 | public static String method1(String s)\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │ 10 POP\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - │ 11 RETURN\n[main] DEBUG haidnor.jvm.core.JavaExecutionEngine - └──────────────────[1] haidnor.jvm.test.demo.Demo5 | public static void main(String[] args)\n\n```\n## 运行单元测试用例\n在 IDE 中打开项目中 test 目录下的 `haidnor.jvm.test.TestJVM.java` 文件。 这是 haidnorJVM 的主要测试类, 里面的测试方法可以解析加载运行 .class 字节码文件。\n```java\npublic class TestJVM {\n   /**\n    *  haidnorJVM 会加载 HelloWorld.java 在 target 目录下的编译后的字节码文件，然后运行其中的 `main(String[] args)` 方法。\n    *  你可以使用打断点的方式看到 haidnorJVM 是如何解释运行 Java 字节码的。\n    *  值得注意的是，这种方式编译运行的字节码文件是基于 java17 版本的。\n    */\n   @Test\n   public void test() {\n      runMainClass(HelloWorld.class);\n   }\n}\n```\n\n## 运行 .class 文件\n1. 使用 maven 命令将 haidnorJVM 编译打包，得到 `haidnorJVM.jar` 文件\n2. 编写一个简单的程序，例如以下代码\n```java\npublic class HelloWorld {\n   public static void main(String[] args) {\n     System.out.println(\"HelloWorld\");\n   }\n}\n```\n3. 编译代码，得到 HelloWorld.class 文件\n4. 使用 haidnorJVM 运行程序。执行命令 `java -jar haidnorJVM.jar -class R:\\HelloWorld.class`。注意! 需要 class 文件的绝对路径\n\n## 运行 .jar 文件\n1. 使用 maven 命令将 haidnorJVM 编译打包，得到 `haidnorJVM.jar` 文件\n2. 编写一个 java 项目编译打包成 .jar 文件，例如 demo.jar。要求 .jar 文件中的 META-INF/MANIFEST.MF 文件内有 `Main-Class` 属性 (含有 `public static void main(String[] args)` 方法的主类信息)\n3. 使用 haidnorJVM 运行程序。执行命令 `java -jar haidnorJVM.jar -class R:\\demo.jar`。注意! 需要 jar 文件的绝对路径\n\n# 存在的问题\n由于 haidnorJVM 目前运行 JDK 自带的类是使用反射解决的，因此 haidnorJVM 使用 JDK17 运行部分 JDK 自带的类时会存在一些问题，例如运行以下代码将会抛出异常\n```java\npublic class Demo {\n    public static void main(String[] args) {\n        List\u003cInteger\u003e list = List.of(1, 2, 3, 4, 5);\n        list.add(6);\n    }\n}\n```\n\n```\njava.lang.reflect.InaccessibleObjectException: Unable to make public boolean java.util.ImmutableCollections$AbstractImmutableCollection.add(java.lang.Object) accessible: module java.base does not \"opens java.util\" to unnamed module @18769467\n\n\tat java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)\n\tat java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)\n\tat java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)\n\tat java.base/java.lang.reflect.Method.setAccessible(Method.java:193)\n```\n它表示尝试通过反射来访问一个方法或字段，但该方法或字段的可访问性限制导致无法访问。  \n\n这个限制通常是由于 Java 模块系统引起的。模块系统允许将代码划分为独立的模块，\n并控制模块之间的访问权限。以上异常的原因是 module java.base does not \"opens java.util\" to unnamed module，也就是说 java.base 模块没有向未命名模块开放 java.util 包\n\n**解决方法：**  \n启动 haidnorJVM 时添加 JVM 参数 `--add-opens java.base/java.util=ALL-UNNAMED` 绕过访问性限制\n\n# 联系作者\n如果您也有兴趣，我们可以一起完善这个项目！欢迎！ 😀\n\n![](/readme/20230721181408.png )  \n微信号: haidnor","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranzhaidnor%2Fhaidnorjvm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffranzhaidnor%2Fhaidnorjvm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranzhaidnor%2Fhaidnorjvm/lists"}