Skip to content

Commit

Permalink
公众号:bugstack虫洞栈 | 用Java实现JVM专题
Browse files Browse the repository at this point in the history
  • Loading branch information
fuzhengwei committed Apr 17, 2020
1 parent ca33852 commit 8f2cd6e
Show file tree
Hide file tree
Showing 1,737 changed files with 55,132 additions and 0 deletions.
28 changes: 28 additions & 0 deletions src/itstack-demo-jvm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# itstack-demo-jvm 用java实现JVM
微信公众号:bugstack虫洞栈,欢迎您的关注&获取更多案例与源码!博客栈:https://bugstack.cn

>JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

本专题主要介绍如何通过java代码来实现JVM的基础功能(搜索解析class文件、字节码命令、运行时数据区等),从而让java程序员通过最熟知的java程序,学习JVM是如何将java程序一步步跑起来的,按照
《java虚拟机规范》与go语言版的《自己动手写Java虚拟机》实现java版虚拟机案例如下;


## 章节列表
- [用Java实现JVM第一章《命令行工具》](https://bugstack.cn/?p=59)
- [用Java实现JVM第二章《搜索class文件》](https://bugstack.cn/?p=60)
- [用Java实现JVM第三章《解析class文件》](https://bugstack.cn/?p=63)
- [用Java实现JVM第三章《解析class文件》附[classReader拆解]](https://bugstack.cn/?p=64)
- [用Java实现JVM第四章《运行时数据区》](https://bugstack.cn/?p=66)
- [用Java实现JVM第五章《指令集和解释器》](https://bugstack.cn/?p=68)
- [用Java实现JVM第六章《类和对象》](https://bugstack.cn/?p=69)
- [用Java实现JVM第七章《方法调用和返回》](https://bugstack.cn/?p=72)
- [用Java实现JVM第八章《数组和字符串》](https://bugstack.cn/?p=73)
- [用Java实现JVM第九章《本地方法调用》](https://bugstack.cn/?p=74)
- [用Java实现JVM第十章《异常处理》](https://bugstack.cn/?p=75)

------------

## 微信公众号:bugstack虫洞栈,欢迎您的关注&获取源码!

![微信公众号:bugstack虫洞栈,欢迎您的关注&获取源码!](https://bugstack.cn/wp-content/uploads/2019/08/qrcode清晰.png)
15 changes: 15 additions & 0 deletions src/itstack-demo-jvm/itstack-demo-jvm-01/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>itstack-demo-jvm</artifactId>
<groupId>org.itatack.demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>itstack-demo-jvm-01</artifactId>


</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.itstack.demo.jvm;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;

import java.util.List;

/**
* http://www.itstack.org
* create by fuzhengwei on 2019/4/24
*/
public class Cmd {

@Parameter(names = {"-?", "-help"}, description = "print help message", order = 3, help = true)
boolean helpFlag = false;

@Parameter(names = "-version", description = "print version and exit", order = 2)
boolean versionFlag = false;

@Parameter(names = {"-cp", "-classpath"}, description = "classpath", order = 1)
String classpath;

@Parameter(description = "main class and args")
List<String> mainClassAndArgs;

boolean ok;

String getMainClass() {
return mainClassAndArgs != null && !mainClassAndArgs.isEmpty()
? mainClassAndArgs.get(0)
: null;
}

List<String> getAppArgs() {
return mainClassAndArgs != null && mainClassAndArgs.size() > 1
? mainClassAndArgs.subList(1, mainClassAndArgs.size())
: null;
}

static Cmd parse(String[] argv) {
Cmd args = new Cmd();
JCommander cmd = JCommander.newBuilder().addObject(args).build();
cmd.parse(argv);
args.ok = true;
return args;
}

}


Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.itstack.demo.jvm;

/**
* http://www.itstack.org
* create by fuzhengwei on 2019/4/24
* program arguments:-version
*/
public class Main {

public static void main(String[] args) {
Cmd cmd = Cmd.parse(args);
if (!cmd.ok || cmd.helpFlag) {
System.out.println("Usage: <main class> [-options] class [args...]");
return;
}
if (cmd.versionFlag) {
System.out.println("java version \"1.8.0\"");
return;
}
startJVM(cmd);
}

private static void startJVM(Cmd cmd) {
System.out.printf("classpath:%s class:%s args:%s\n", cmd.classpath, cmd.getMainClass(), cmd.getAppArgs());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.itstack.demo.test;

public class HelloWorld {

public static void main(String[] args) {
System.out.println("hello world");
}

}
15 changes: 15 additions & 0 deletions src/itstack-demo-jvm/itstack-demo-jvm-02/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>itstack-demo-jvm</artifactId>
<groupId>org.itatack.demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>itstack-demo-jvm-02</artifactId>


</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.itstack.demo.jvm;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;

import java.util.List;

/**
* http://www.itstack.org
* create by fuzhengwei on 2019/4/24
*/
public class Cmd {

@Parameter(names = {"-?", "-help"}, description = "print help message", order = 3, help = true)
boolean helpFlag = false;

@Parameter(names = "-version", description = "print version and exit", order = 2)
boolean versionFlag = false;

@Parameter(names = {"-cp", "-classpath"}, description = "classpath", order = 1)
String classpath;

@Parameter(names = "-Xjre", description = "path to jre", order = 4)
String jre;

@Parameter(description = "main class and args")
List<String> mainClassAndArgs;

boolean ok;

String getMainClass() {
return mainClassAndArgs != null && !mainClassAndArgs.isEmpty()
? mainClassAndArgs.get(0)
: null;
}

List<String> getAppArgs() {
return mainClassAndArgs != null && mainClassAndArgs.size() > 1
? mainClassAndArgs.subList(1, mainClassAndArgs.size())
: null;
}

static Cmd parse(String[] argv) {
Cmd args = new Cmd();
JCommander cmd = JCommander.newBuilder().addObject(args).build();
cmd.parse(argv);
args.ok = true;
return args;
}

}


Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.itstack.demo.jvm;

import org.itstack.demo.jvm.classpath.Classpath;

import java.util.Arrays;

/**
* http://www.itstack.org
* create by fuzhengwei on 2019/4/24
* program arguments:-Xjre "C:\Program Files\Java\jdk1.8.0_161\jre" E:\itstack\git\istack-demo\itstack-demo-jvm\itstack-demo-jvm-02\target\test-classes\org\itstack\demo\test\HelloWorld
*/
public class Main {

public static void main(String[] args) {
Cmd cmd = Cmd.parse(args);
if (!cmd.ok || cmd.helpFlag) {
System.out.println("Usage: <main class> [-options] class [args...]");
return;
}
if (cmd.versionFlag) {
//注意案例测试都是基于1.8,另外jdk1.9以后使用模块化没有rt.jar
System.out.println("java version \"1.8.0\"");
return;
}
startJVM(cmd);
}

private static void startJVM(Cmd cmd) {
Classpath cp = new Classpath(cmd.jre, cmd.classpath);
System.out.printf("classpath:%s class:%s args:%s\n", cp, cmd.getMainClass(), cmd.getAppArgs());
//获取className
String className = cmd.getMainClass().replace(".", "/");
try {
byte[] classData = cp.readClass(className);

System.out.println(Arrays.toString(classData));

System.out.println("classData:");
// for (byte b : classData) {
// //16进制输出
// System.out.print(String.format("%02x", b & 0xff) + " ");
// }
} catch (Exception e) {
System.out.println("Could not find or load main class " + cmd.getMainClass());
e.printStackTrace();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package org.itstack.demo.jvm.classpath;

import org.itstack.demo.jvm.classpath.impl.WildcardEntry;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
* http://www.itstack.org
* create by fuzhengwei on 2019/4/24
* 类路径
*/
public class Classpath {

private Entry bootstrapClasspath; //启动类路径
private Entry extensionClasspath; //扩展类路径
private Entry userClasspath; //用户类路径

public Classpath(String jreOption, String cpOption) {
//启动类&扩展类 "C:\Program Files\Java\jdk1.8.0_161\jre"
bootstrapAndExtensionClasspath(jreOption);
//用户类 E:\..\org\itstack\demo\test\HelloWorld
parseUserClasspath(cpOption);
}

private void bootstrapAndExtensionClasspath(String jreOption) {

String jreDir = getJreDir(jreOption);

//..jre/lib/*
String jreLibPath = Paths.get(jreDir, "lib") + File.separator + "*";
bootstrapClasspath = new WildcardEntry(jreLibPath);

//..jre/lib/ext/*
String jreExtPath = Paths.get(jreDir, "lib", "ext") + File.separator + "*";
extensionClasspath = new WildcardEntry(jreExtPath);

}

private static String getJreDir(String jreOption) {
if (jreOption != null && Files.exists(Paths.get(jreOption))) {
return jreOption;
}
if (Files.exists(Paths.get("./jre"))) {
return "./jre";
}
String jh = System.getenv("JAVA_HOME");
if (jh != null) {
return Paths.get(jh, "jre").toString();
}
throw new RuntimeException("Can not find JRE folder!");
}

private void parseUserClasspath(String cpOption) {
if (cpOption == null) {
cpOption = ".";
}
userClasspath = Entry.create(cpOption);
}

public byte[] readClass(String className) throws Exception {
className = className + ".class";

//[readClass]启动类路径
try {
return bootstrapClasspath.readClass(className);
} catch (Exception ignored) {
//ignored
}

//[readClass]扩展类路径
try {
return extensionClasspath.readClass(className);
} catch (Exception ignored) {
//ignored
}

//[readClass]用户类路径
return userClasspath.readClass(className);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.itstack.demo.jvm.classpath;

import org.itstack.demo.jvm.classpath.impl.CompositeEntry;
import org.itstack.demo.jvm.classpath.impl.DirEntry;
import org.itstack.demo.jvm.classpath.impl.WildcardEntry;
import org.itstack.demo.jvm.classpath.impl.ZipEntry;

import java.io.File;
import java.io.IOException;

/**
* http://www.itstack.org
* create by fuzhengwei on 2019/4/24
* 类路径接口
*/
public interface Entry {

byte[] readClass(String className) throws IOException;

static Entry create(String path) {

//File.pathSeparator;路径分隔符(win\linux)
if (path.contains(File.pathSeparator)) {
return new CompositeEntry(path);
}

if (path.endsWith("*")) {
return new WildcardEntry(path);
}

if (path.endsWith(".jar") || path.endsWith(".JAR") ||
path.endsWith(".zip") || path.endsWith(".ZIP")) {
return new ZipEntry(path);
}

return new DirEntry(path);
}

}
Loading

0 comments on commit 8f2cd6e

Please sign in to comment.