mirror of
https://github.com/FranzHaidnor/haidnorJVM.git
synced 2026-03-13 21:43:42 +08:00
add 支持运行 jar 文件
This commit is contained in:
@@ -74,7 +74,7 @@ public void test_LSUB() throws Exception {
|
||||
值得注意的是,这种方式编译运行的字节码文件是基于 java17 版本的。
|
||||
|
||||
## 运行 .class 文件
|
||||
1. 使用 maven 命令将项目编译打包,得到 `haidnorJVM-1.0.jar` 文件
|
||||
1. 使用 maven 命令将 haidnorJVM 编译打包,得到 `haidnorJVM-1.0.jar` 文件
|
||||
2. 编写一个简单的程序,例如以下代码
|
||||
```java
|
||||
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 文件的绝对路径
|
||||
|
||||
## 运行 .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 指令
|
||||
```java
|
||||
|
||||
@@ -17,6 +17,10 @@ import haidnor.jvm.util.JavaClassUtil;
|
||||
import haidnor.jvm.util.JvmThreadHolder;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* @author wang xiang
|
||||
*/
|
||||
@@ -37,17 +41,36 @@ public class Main {
|
||||
CommandLine cmd = parser.parse(options, args);
|
||||
|
||||
if (cmd.hasOption("jar")) {
|
||||
String path = cmd.getOptionValue("jar");
|
||||
// TODO
|
||||
}
|
||||
if (cmd.hasOption("class")) {
|
||||
String jarFilePath = cmd.getOptionValue("jar");
|
||||
|
||||
try (JarFile jarFile = new JarFile(jarFilePath)) {
|
||||
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());
|
||||
String path = cmd.getOptionValue("class");
|
||||
ClassLoader bootClassLoader = new ClassLoader("ApplicationClassLoader");
|
||||
Klass mainMeteKlass = bootClassLoader.loadClassWithAbsolutePath(path);
|
||||
KlassMethod mainKlassMethod = JavaClassUtil.getMainMethod(mainMeteKlass);
|
||||
Metaspace.registerJavaClass(mainMeteKlass);
|
||||
|
||||
|
||||
JavaExecutionEngine.callMainStaticMethod(mainKlassMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@ import haidnor.jvm.rtda.heap.Klass;
|
||||
import org.apache.bcel.classfile.ClassParser;
|
||||
import org.apache.bcel.classfile.JavaClass;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* @author wang xiang
|
||||
@@ -20,6 +20,8 @@ public class ClassLoader {
|
||||
|
||||
public final static String rtJarPath;
|
||||
|
||||
public JarFile jarFile = null;
|
||||
|
||||
static {
|
||||
URL resource = ClassLoader.class.getResource("/");
|
||||
String path = resource.getPath();
|
||||
@@ -42,16 +44,33 @@ public class ClassLoader {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public ClassLoader(JarFile jarFile, String name) {
|
||||
this.name = name;
|
||||
this.jarFile = jarFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param classPath 类路径,例如 haidnor/jvm/classloader/ClassLoader
|
||||
*/
|
||||
public Klass loadClass(String classPath) throws IOException {
|
||||
ClassParser classParser;
|
||||
ClassParser classParser = null;
|
||||
if (classPath.startsWith("java/")) {
|
||||
if (!new File(rtJarPath).exists()) {
|
||||
throw new IllegalStateException("rt.jar not found");
|
||||
}
|
||||
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 {
|
||||
URL resource = this.getClass().getResource("/");
|
||||
String fileName = resource.getPath() + classPath + ".class";
|
||||
@@ -62,6 +81,13 @@ public class ClassLoader {
|
||||
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 {
|
||||
ClassParser classParser = new ClassParser(absolutePath);
|
||||
JavaClass javaClass = classParser.parse();
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
package haidnor.jvm.test;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import haidnor.jvm.classloader.ClassLoader;
|
||||
import haidnor.jvm.core.JavaExecutionEngine;
|
||||
import haidnor.jvm.rtda.heap.Klass;
|
||||
import haidnor.jvm.rtda.heap.KlassMethod;
|
||||
import haidnor.jvm.rtda.metaspace.Metaspace;
|
||||
import haidnor.jvm.runtime.JvmThread;
|
||||
import haidnor.jvm.test.demo.Demo1;
|
||||
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.demo.*;
|
||||
import haidnor.jvm.test.instruction.Array;
|
||||
import haidnor.jvm.test.instruction.DO_WHILE;
|
||||
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.JvmThreadHolder;
|
||||
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 {
|
||||
|
||||
@@ -99,4 +99,48 @@ public class TestJVM {
|
||||
public void test_INVOKEINTERFACE() throws Exception {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user