add 支持运行 jar 文件

This commit is contained in:
wangxiang
2023-07-22 16:06:24 +08:00
parent 80f3de533e
commit f939eadff2
4 changed files with 115 additions and 20 deletions

View File

@@ -74,7 +74,7 @@ public void test_LSUB() throws Exception {
值得注意的是,这种方式编译运行的字节码文件是基于 java17 版本的。 值得注意的是,这种方式编译运行的字节码文件是基于 java17 版本的。
## 运行 .class 文件 ## 运行 .class 文件
1. 使用 maven 命令将项目编译打包,得到 `haidnorJVM-1.0.jar` 文件 1. 使用 maven 命令将 haidnorJVM 编译打包,得到 `haidnorJVM-1.0.jar` 文件
2. 编写一个简单的程序,例如以下代码 2. 编写一个简单的程序,例如以下代码
```java ```java
public class HelloWorld { public class HelloWorld {
@@ -87,7 +87,9 @@ public void test_LSUB() throws Exception {
4. 使用 haidnorJVM 运行程序。执行命令 `java -jar haidnorJVM-1.0-SNAPSHOT.jar -class R:\HelloWorld.class`。注意需要 class 文件的绝对路径 4. 使用 haidnorJVM 运行程序。执行命令 `java -jar haidnorJVM-1.0-SNAPSHOT.jar -class R:\HelloWorld.class`。注意需要 class 文件的绝对路径
## 运行 .jar 文件 ## 运行 .jar 文件
开发中... 1. 使用 maven 命令将 haidnorJVM 编译打包,得到 `haidnorJVM-1.0.jar` 文件
2. 编写一个 java 项目编译打包成 .jar 文件,例如 demo.jar。要求 .jar 文件中的 META-INF/MANIFEST.MF 文件内有 `Main-Class` 属性 (含有 public static void main(String[] args) 方法的主类信息)
3. 使用 haidnorJVM 运行程序。执行命令 `java -jar haidnorJVM-1.0-SNAPSHOT.jar -class R:\demo.jar`。注意需要 jar 文件的绝对路径
# 完成度,已实现的 JVM 指令 # 完成度,已实现的 JVM 指令
```java ```java

View File

@@ -17,6 +17,10 @@ import haidnor.jvm.util.JavaClassUtil;
import haidnor.jvm.util.JvmThreadHolder; import haidnor.jvm.util.JvmThreadHolder;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/** /**
* @author wang xiang * @author wang xiang
*/ */
@@ -37,17 +41,36 @@ public class Main {
CommandLine cmd = parser.parse(options, args); CommandLine cmd = parser.parse(options, args);
if (cmd.hasOption("jar")) { if (cmd.hasOption("jar")) {
String path = cmd.getOptionValue("jar"); String jarFilePath = cmd.getOptionValue("jar");
// TODO
} try (JarFile jarFile = new JarFile(jarFilePath)) {
if (cmd.hasOption("class")) { ClassLoader bootClassLoader = new ClassLoader(jarFile, "ApplicationClassLoader");
String mainClass = jarFile.getManifest().getMainAttributes().getValue("Main-Class");
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
String className = entry.getName().replace('/', '.').substring(0, entry.getName().length() - 6);
if (className.equals(mainClass)) {
JvmThreadHolder.set(new JvmThread());
Klass mainMeteKlass = bootClassLoader.loadClass(jarFile, entry);
KlassMethod mainKlassMethod = JavaClassUtil.getMainMethod(mainMeteKlass);
Metaspace.registerJavaClass(mainMeteKlass);
JavaExecutionEngine.callMainStaticMethod(mainKlassMethod);
break;
}
}
}
}
} else if (cmd.hasOption("class")) {
JvmThreadHolder.set(new JvmThread()); JvmThreadHolder.set(new JvmThread());
String path = cmd.getOptionValue("class"); String path = cmd.getOptionValue("class");
ClassLoader bootClassLoader = new ClassLoader("ApplicationClassLoader"); ClassLoader bootClassLoader = new ClassLoader("ApplicationClassLoader");
Klass mainMeteKlass = bootClassLoader.loadClassWithAbsolutePath(path); Klass mainMeteKlass = bootClassLoader.loadClassWithAbsolutePath(path);
KlassMethod mainKlassMethod = JavaClassUtil.getMainMethod(mainMeteKlass); KlassMethod mainKlassMethod = JavaClassUtil.getMainMethod(mainMeteKlass);
Metaspace.registerJavaClass(mainMeteKlass); Metaspace.registerJavaClass(mainMeteKlass);
JavaExecutionEngine.callMainStaticMethod(mainKlassMethod); JavaExecutionEngine.callMainStaticMethod(mainKlassMethod);
} }
} }

View File

@@ -4,12 +4,12 @@ import haidnor.jvm.rtda.heap.Klass;
import org.apache.bcel.classfile.ClassParser; import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.JavaClass;
import java.io.File; import java.io.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Enumeration;
import java.util.Properties; import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/** /**
* @author wang xiang * @author wang xiang
@@ -20,6 +20,8 @@ public class ClassLoader {
public final static String rtJarPath; public final static String rtJarPath;
public JarFile jarFile = null;
static { static {
URL resource = ClassLoader.class.getResource("/"); URL resource = ClassLoader.class.getResource("/");
String path = resource.getPath(); String path = resource.getPath();
@@ -42,16 +44,33 @@ public class ClassLoader {
this.name = name; this.name = name;
} }
public ClassLoader(JarFile jarFile, String name) {
this.name = name;
this.jarFile = jarFile;
}
/** /**
* @param classPath 类路径,例如 haidnor/jvm/classloader/ClassLoader * @param classPath 类路径,例如 haidnor/jvm/classloader/ClassLoader
*/ */
public Klass loadClass(String classPath) throws IOException { public Klass loadClass(String classPath) throws IOException {
ClassParser classParser; ClassParser classParser = null;
if (classPath.startsWith("java/")) { if (classPath.startsWith("java/")) {
if (!new File(rtJarPath).exists()) { if (!new File(rtJarPath).exists()) {
throw new IllegalStateException("rt.jar not found"); throw new IllegalStateException("rt.jar not found");
} }
classParser = new ClassParser(rtJarPath, classPath + ".class"); classParser = new ClassParser(rtJarPath, classPath + ".class");
} else if (jarFile != null) {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
String className = entry.getName().substring(0, entry.getName().length() - 6);
if (className.equals(classPath)) {
InputStream inputStream = jarFile.getInputStream(entry);
classParser = new ClassParser(inputStream, null);
}
}
}
} else { } else {
URL resource = this.getClass().getResource("/"); URL resource = this.getClass().getResource("/");
String fileName = resource.getPath() + classPath + ".class"; String fileName = resource.getPath() + classPath + ".class";
@@ -62,6 +81,13 @@ public class ClassLoader {
return new Klass(this, javaClass); return new Klass(this, javaClass);
} }
public Klass loadClass(JarFile jarFile, JarEntry entry) throws IOException {
InputStream inputStream = jarFile.getInputStream(entry);
ClassParser classParser = new ClassParser(inputStream, null);
JavaClass javaClass = classParser.parse();
return new Klass(this, javaClass);
}
public Klass loadClassWithAbsolutePath(String absolutePath) throws IOException { public Klass loadClassWithAbsolutePath(String absolutePath) throws IOException {
ClassParser classParser = new ClassParser(absolutePath); ClassParser classParser = new ClassParser(absolutePath);
JavaClass javaClass = classParser.parse(); JavaClass javaClass = classParser.parse();

View File

@@ -1,19 +1,12 @@
package haidnor.jvm.test; package haidnor.jvm.test;
import org.junit.Test;
import haidnor.jvm.classloader.ClassLoader; import haidnor.jvm.classloader.ClassLoader;
import haidnor.jvm.core.JavaExecutionEngine; import haidnor.jvm.core.JavaExecutionEngine;
import haidnor.jvm.rtda.heap.Klass; import haidnor.jvm.rtda.heap.Klass;
import haidnor.jvm.rtda.heap.KlassMethod; import haidnor.jvm.rtda.heap.KlassMethod;
import haidnor.jvm.rtda.metaspace.Metaspace; import haidnor.jvm.rtda.metaspace.Metaspace;
import haidnor.jvm.runtime.JvmThread; import haidnor.jvm.runtime.JvmThread;
import haidnor.jvm.test.demo.Demo1; import haidnor.jvm.test.demo.*;
import haidnor.jvm.test.demo.Demo2;
import haidnor.jvm.test.demo.Demo3;
import haidnor.jvm.test.demo.Demo4;
import haidnor.jvm.test.demo.Demo5;
import haidnor.jvm.test.demo.Demo6;
import haidnor.jvm.test.instruction.Array; import haidnor.jvm.test.instruction.Array;
import haidnor.jvm.test.instruction.DO_WHILE; import haidnor.jvm.test.instruction.DO_WHILE;
import haidnor.jvm.test.instruction.math.ISUB; import haidnor.jvm.test.instruction.math.ISUB;
@@ -23,6 +16,13 @@ import haidnor.jvm.test.instruction.references.NEW;
import haidnor.jvm.util.JavaClassUtil; import haidnor.jvm.util.JavaClassUtil;
import haidnor.jvm.util.JvmThreadHolder; import haidnor.jvm.util.JvmThreadHolder;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.junit.Test;
import java.io.IOException;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
public class TestJVM { public class TestJVM {
@@ -99,4 +99,48 @@ public class TestJVM {
public void test_INVOKEINTERFACE() throws Exception { public void test_INVOKEINTERFACE() throws Exception {
runMainClass(INVOKEINTERFACE.class); runMainClass(INVOKEINTERFACE.class);
} }
@Test
public void test_() throws Exception {
String jarFilePath = "D:\\project_java\\JvmDemo\\target\\JvmDemo-1.0-SNAPSHOT.jar";
try (JarFile jarFile = new JarFile(jarFilePath)) {
Manifest manifest = jarFile.getManifest();
// 读取指定键的值
String mainClass = manifest.getMainAttributes().getValue("Main-Class");
System.out.println(mainClass);
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void test_jar() throws Exception {
String jarFilePath = "D:/project_java/JvmDemo/target/JvmDemo-1.0-SNAPSHOT.jar";
JvmThreadHolder.set(new JvmThread());
try (JarFile jarFile = new JarFile(jarFilePath)) {
ClassLoader bootClassLoader = new ClassLoader(jarFile, "ApplicationClassLoader");
// 找到主类 a.b.Main
String mainClass = jarFile.getManifest().getMainAttributes().getValue("Main-Class");
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
String className = entry.getName().replace('/', '.').substring(0, entry.getName().length() - 6);
if (className.equals(mainClass)) {
Klass mainMeteKlass = bootClassLoader.loadClass(jarFile, entry);
KlassMethod mainKlassMethod = JavaClassUtil.getMainMethod(mainMeteKlass);
Metaspace.registerJavaClass(mainMeteKlass);
JavaExecutionEngine.callMainStaticMethod(mainKlassMethod);
break;
}
}
}
}
}
} }