├── .gitignore
├── README.md
├── pom.xml
└── src
└── main
└── java
└── org
└── caoym
└── jjvm
├── JJvm.java
├── JvmDefaultClassLoader.java
├── VirtualMachine.java
├── lang
├── JvmClass.java
├── JvmClassLoader.java
├── JvmField.java
├── JvmMethod.java
└── JvmObject.java
├── natives
├── JvmNativeClass.java
├── JvmNativeConstructor.java
├── JvmNativeField.java
├── JvmNativeMethod.java
└── JvmNativeObject.java
├── opcode
├── BytecodeInterpreter.java
├── JvmOpcodeClass.java
├── JvmOpcodeMethod.java
├── JvmOpcodeObject.java
├── JvmOpcodeObjectField.java
├── JvmOpcodeStaticField.java
├── OpcodeInvoker.java
└── OpcodeRout.java
└── runtime
├── Env.java
├── JvmStack.java
├── Slots.java
├── SlotsStack.java
└── StackFrame.java
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | .idea
3 | *.iml
4 | .DS_Store
5 | .project
6 | .settings
7 | .classpath
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JJvm
2 |
3 | 这是一个Java实现的JAVA虚拟机,它会非常简单,实际上简单的只够运行HelloWorld。虽然简单,但尽量符合 JVM 标准,目前主要参考依据是[《Java虚拟机规范 (Java SE 7 中文版)》](http://www.iteye.com/topic/1117824)。
4 |
5 | 关于此项目的说明,[详见此文](http://www.jianshu.com/p/4d81465c2fb8)。
6 |
7 | ## 运行
8 |
9 | 先写一个HelloWorld,代码如下:
10 |
11 | ```java
12 | package org.caoym;
13 |
14 | public class HelloWorld {
15 | public static void main(String[] args){
16 | System.out.println("Hello World");
17 | }
18 | }
19 | ```
20 |
21 | 可以通过以下命令运行:
22 |
23 | ```shell
24 | $ java /home/myclasspath org.caoym.jjvm.JJvm org.caoym.HelloWorld
25 | Hello World
26 | ```
27 |
28 | ## 可运行的示例
29 |
30 | [用于测试 JJvm 的示例代码可在此处下载](https://github.com/caoym/jjvm-samples)
31 |
32 |
33 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.caoym
8 | jjvm
9 | 1.0-SNAPSHOT
10 |
11 |
12 | jdk.tools
13 | jdk.tools
14 | 1.8
15 | system
16 |
17 | /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/lib/tools.jar
18 |
19 |
20 | jdk.rt
21 | jdk.rt
22 | 1.8
23 | system
24 |
25 | /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/jre/lib/rt.jar
26 |
27 |
28 |
29 |
30 |
31 | org.apache.maven.plugins
32 | maven-compiler-plugin
33 | 3.6.0
34 |
35 | 1.8
36 | 1.8
37 |
38 |
39 |
40 |
42 | ${java.home}\lib\rt.jar;${java.home}\lib\jce.jar
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/JJvm.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm;
2 |
3 | import java.nio.file.Paths;
4 | import java.util.Arrays;
5 |
6 | /**
7 | * Created by caoyangmin on 2017/9/7.
8 | */
9 | public class JJvm {
10 | static public void main(String[] args){
11 | if(args.length == 0){
12 | System.out.println("Usage: [args...]");
13 | return;
14 | }
15 | VirtualMachine vm = new VirtualMachine(Paths.get(args[0]), args[1]);
16 | try {
17 | args = Arrays.copyOfRange(args, 2, args.length);
18 | vm.run(args);
19 | } catch (Exception e) {
20 | e.printStackTrace();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/JvmDefaultClassLoader.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm;
2 |
3 | import org.caoym.jjvm.lang.JvmClass;
4 | import org.caoym.jjvm.lang.JvmClassLoader;
5 | import org.caoym.jjvm.opcode.JvmOpcodeClass;
6 | import org.caoym.jjvm.natives.JvmNativeClass;
7 |
8 | import java.nio.file.Files;
9 | import java.nio.file.Path;
10 | import java.nio.file.Paths;
11 |
12 | /**
13 | * 虚拟机的引导类加载器
14 | *
15 | */
16 | public class JvmDefaultClassLoader implements JvmClassLoader {
17 |
18 | /**
19 | * 类搜索路径
20 | */
21 | private Path classPath;
22 |
23 | public JvmDefaultClassLoader(Path classPath) {
24 | this.classPath = classPath;
25 | }
26 | public JvmClass loadClass(String className) throws ClassNotFoundException{
27 | //
28 | String fileName = classPath + "/"+className.replace(".", "/")+".class";
29 | Path path = Paths.get(fileName);
30 | //如果文件存在,加载文件字节码
31 | //否则尝试通过虚拟机宿主加载指定类,并将加载后的类当做 native 类
32 | if(Files.exists(path)){
33 | return JvmOpcodeClass.read(this, path);
34 | }else{
35 | return new JvmNativeClass(this, Class.forName(className.replace("/",".")));
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/VirtualMachine.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm;
2 |
3 | import org.caoym.jjvm.lang.JvmClass;
4 | import org.caoym.jjvm.lang.JvmClassLoader;
5 | import org.caoym.jjvm.lang.JvmMethod;
6 | import org.caoym.jjvm.runtime.Env;
7 |
8 | import java.nio.file.Path;
9 | import java.util.Hashtable;
10 |
11 | public class VirtualMachine {
12 | /**
13 | * 初始类
14 | * 包含 main 方法的类
15 | */
16 | private String initialClass;
17 | /**
18 | * 类加载器
19 | */
20 | private JvmClassLoader classLoader;
21 | /**
22 | * 方法区(Method Area)
23 | * 存储运行时类信息
24 | */
25 | private Hashtable methodArea = new Hashtable();
26 |
27 | public VirtualMachine(Path classPath, String initialClass){
28 | classLoader = new JvmDefaultClassLoader(classPath);
29 | this.initialClass = initialClass;
30 | }
31 | /**
32 | * 执行虚拟机
33 | * @param args
34 | * @throws Exception
35 | */
36 | public void run(String[] args) throws Exception {
37 | Env env = new Env(this);
38 | JvmClass clazz = getClass(initialClass);
39 | //找到入口方法
40 | JvmMethod method = clazz.getMethod(
41 | "main",
42 | "([Ljava/lang/String;)V");
43 | //执行入口方法
44 | method.call(env, null, new Object[]{args});
45 | }
46 |
47 | public JvmClass getClass(String className) throws ClassNotFoundException {
48 | JvmClass found = methodArea.get(className);
49 | if(found == null){
50 | found = classLoader.loadClass(className);
51 | methodArea.put(className, found);
52 | }
53 | return found;
54 | }
55 |
56 |
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/lang/JvmClass.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm.lang;
2 |
3 | import org.caoym.jjvm.runtime.Env;
4 |
5 | /**
6 | * Jvm 内部的 Class 表示
7 | */
8 | public interface JvmClass {
9 |
10 | /**
11 | * 分配实例的内存空间,但不执行实例的构造函数
12 | * @return
13 | * @throws InstantiationException
14 | * @throws IllegalAccessException
15 | */
16 | public JvmObject newInstance(Env env) throws InstantiationException, IllegalAccessException;
17 | /**
18 | * 获取方法
19 | * @param name 方法名,如`main`
20 | * @param desc 方法类型描述,如`([Ljava/lang/String;)V`
21 | * @return
22 | * @throws NoSuchMethodException
23 | */
24 | public JvmMethod getMethod(String name, String desc) throws NoSuchMethodException;
25 |
26 | /**
27 | * 获取方法
28 | * @param name 方法名,如`main`
29 | * @param desc 方法类型描述,如`([Ljava/lang/String;)V`
30 | */
31 | public boolean hasMethod(String name, String desc);
32 |
33 | /**
34 | * 获取属性
35 | * @param name 属性名
36 | * @return
37 | * @throws NoSuchFieldException
38 | */
39 | public JvmField getField(String name) throws NoSuchFieldException, IllegalAccessException;
40 |
41 | /**
42 | * 获取当前类的 class loader
43 | * @return
44 | */
45 | public JvmClassLoader getClassLoader();
46 |
47 | /**
48 | * 返回父类
49 | */
50 | public JvmClass getSuperClass() throws ClassNotFoundException;
51 |
52 | /**
53 | * 返回类名
54 | */
55 | public String getName();
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/lang/JvmClassLoader.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm.lang;
2 |
3 | public interface JvmClassLoader {
4 | public JvmClass loadClass(String className) throws ClassNotFoundException;
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/lang/JvmField.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm.lang;
2 |
3 | import org.caoym.jjvm.runtime.Env;
4 |
5 | /**
6 | * Created by caoyangmin on 2017/9/29.
7 | */
8 | public interface JvmField {
9 | public void set(Env env, Object thiz, Object value) throws IllegalAccessException;
10 | public Object get(Env env,Object thiz)throws IllegalAccessException;
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/lang/JvmMethod.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm.lang;
2 |
3 | import org.caoym.jjvm.runtime.Env;
4 |
5 | public interface JvmMethod {
6 | /**
7 | * 执行对象或者类方法
8 | * 方法被调用时,会产生一个新的栈帧,并推入当前线程的栈
9 | * 方法执行结束后,栈帧被退出,同时期返回值被推入上一个栈帧(当前方法的调用者)的操作数栈
10 | */
11 | public void call(Env env, Object thiz, Object ...args) throws Exception;
12 |
13 | public int getParameterCount();
14 |
15 | public String getName();
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/lang/JvmObject.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm.lang;
2 |
3 | /**
4 | * Created by caoyangmin on 2017/9/29.
5 | */
6 | public interface JvmObject {
7 | /**
8 | * 获取父类实例
9 | */
10 | JvmObject getSuper();
11 |
12 | /**
13 | * 获取实例的类
14 | */
15 | JvmClass getClazz();
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/natives/JvmNativeClass.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm.natives;
2 |
3 | import jdk.internal.org.objectweb.asm.Type;
4 | import org.caoym.jjvm.lang.*;
5 | import org.caoym.jjvm.runtime.Env;
6 |
7 | import java.lang.reflect.Constructor;
8 | import java.lang.reflect.Method;
9 | import java.util.AbstractMap;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | /**
14 | * 包装 native 类
15 | */
16 | public class JvmNativeClass implements JvmClass {
17 |
18 | private final Class nativeClass;
19 | private final String className;
20 | private final JvmClassLoader classLoader;
21 | private final HashMap, JvmMethod> methods = new HashMap<>();
22 |
23 | public JvmNativeClass(JvmClassLoader classLoader, Class nativeClass){
24 | this.nativeClass = nativeClass;
25 | this.classLoader = classLoader;
26 | this.className = nativeClass.getName();
27 | //普通方法
28 | for (Method method : nativeClass.getMethods()) {
29 | methods.put(
30 | new AbstractMap.SimpleEntry<>(method.getName(), Type.getMethodDescriptor(method)),
31 | new JvmNativeMethod(this, method)
32 | );
33 | }
34 | //构造方法
35 | for( Constructor constructor : nativeClass.getConstructors()){
36 | methods.put(
37 | new AbstractMap.SimpleEntry<>("", Type.getConstructorDescriptor(constructor)),
38 | new JvmNativeConstructor(this, constructor)
39 | );
40 | }
41 | }
42 |
43 | @Override
44 | public JvmObject newInstance(Env env) throws InstantiationException, IllegalAccessException {
45 | return new JvmNativeObject(this);
46 | }
47 |
48 | @Override
49 | public JvmMethod getMethod(String name, String desc) throws NoSuchMethodException {
50 | JvmMethod found = methods.get(new AbstractMap.SimpleEntry<>(name, desc));
51 | if(found == null){
52 | throw new NoSuchMethodException(name+":"+desc+" not exist");
53 | }
54 | return found;
55 | }
56 |
57 | @Override
58 | public boolean hasMethod(String name, String desc) {
59 | JvmMethod found = methods.get(new AbstractMap.SimpleEntry<>(name, desc));
60 | return found != null;
61 | }
62 |
63 | @Override
64 | public JvmField getField(String name) throws NoSuchFieldException, IllegalAccessException {
65 | return new JvmNativeField(this, nativeClass.getField(name));
66 | }
67 |
68 | @Override
69 | public JvmClassLoader getClassLoader() {
70 | return classLoader;
71 | }
72 |
73 | @Override
74 | public JvmClass getSuperClass() throws ClassNotFoundException {
75 | return classLoader.loadClass(nativeClass.getSuperclass().getName());
76 | }
77 |
78 | @Override
79 | public String getName() {
80 | return className;
81 | }
82 |
83 | public Class getNativeClass() {
84 | return nativeClass;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/natives/JvmNativeConstructor.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm.natives;
2 |
3 | import org.caoym.jjvm.lang.JvmClass;
4 | import org.caoym.jjvm.lang.JvmMethod;
5 | import org.caoym.jjvm.runtime.Env;
6 | import org.caoym.jjvm.runtime.StackFrame;
7 |
8 | import java.lang.reflect.Constructor;
9 |
10 | /**
11 | * native 类的构造器方法
12 | */
13 | public class JvmNativeConstructor implements JvmMethod {
14 |
15 | private final Constructor constructor;
16 | private final JvmClass clazz;
17 |
18 | public JvmNativeConstructor(JvmClass clazz, Constructor constructor){
19 | this.clazz = clazz;
20 | this.constructor = constructor;
21 | }
22 | @Override
23 | public void call(Env env, Object thiz, Object... args) throws Exception {
24 | assert (thiz instanceof JvmNativeObject);
25 |
26 | StackFrame frame = env.getStack().newFrame(clazz, this);
27 | Object object = constructor.newInstance(JvmNativeObject.multiUnwrap(args));
28 | ((JvmNativeObject) thiz).setNativeObject(object);
29 | //将返回值推入调用者的操作数栈
30 | frame.setReturn(null, "void");
31 | }
32 |
33 | @Override
34 | public int getParameterCount() {
35 | return constructor.getParameterCount();
36 | }
37 |
38 | @Override
39 | public String getName() {
40 | return "";
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/natives/JvmNativeField.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm.natives;
2 |
3 | import org.caoym.jjvm.lang.JvmField;
4 | import org.caoym.jjvm.runtime.Env;
5 |
6 | import java.lang.reflect.Field;
7 |
8 | /**
9 | * Created by caoyangmin on 2017/9/29.
10 | */
11 | public class JvmNativeField implements JvmField{
12 |
13 | JvmNativeClass clazz;
14 | Field filed;
15 | public JvmNativeField(JvmNativeClass nativeClass, Field field){
16 | this.clazz = nativeClass;
17 | this.filed = field;
18 | }
19 | @Override
20 | public Object get(Env env, Object thiz) throws IllegalAccessException {
21 | // 非基础类型,需要用JvmNativeObject包装
22 | return JvmNativeObject.wrap(filed.get(thiz), filed.getType(), clazz.getClassLoader());
23 | }
24 |
25 | @Override
26 | public void set(Env env, Object thiz, Object value) throws IllegalAccessException {
27 | // 去掉JvmNativeObject包装
28 | filed.set(thiz, JvmNativeObject.unwrap(value));
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/natives/JvmNativeMethod.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm.natives;
2 |
3 | import org.caoym.jjvm.lang.JvmClass;
4 | import org.caoym.jjvm.runtime.Env;
5 | import org.caoym.jjvm.lang.JvmMethod;
6 | import org.caoym.jjvm.runtime.StackFrame;
7 |
8 | import java.lang.reflect.Method;
9 | import java.util.Arrays;
10 |
11 | /**
12 | * 包装 native 方法
13 | */
14 | public class JvmNativeMethod implements JvmMethod {
15 |
16 | private final JvmClass clazz;
17 | private final Method method;
18 | private final String name;
19 |
20 | public JvmNativeMethod(JvmClass clazz, Method method){
21 | this.clazz = clazz;
22 | this.method = method;
23 | this.name = method.getName();
24 | }
25 | @Override
26 | public void call(Env env, Object thiz, Object... args) throws Exception {
27 | assert thiz instanceof JvmNativeObject;
28 | StackFrame frame = env.getStack().newFrame(clazz, this);
29 | Object object = ((JvmNativeObject) thiz).getNativeObject();
30 | Object res = method.invoke(object, JvmNativeObject.multiUnwrap(args));
31 | // 非基础类型,需要用JvmNativeObject包装
32 | res = JvmNativeObject.wrap(res, method.getReturnType(), clazz.getClassLoader());
33 | //将返回值推入调用者的操作数栈
34 | frame.setReturn(res, method.getReturnType().getName());
35 | }
36 |
37 | @Override
38 | public int getParameterCount() {
39 | return method.getParameterCount();
40 | }
41 |
42 | @Override
43 | public String getName() {
44 | return name;
45 | }
46 |
47 | public Method getNativeMethod() {
48 | return method;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/natives/JvmNativeObject.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm.natives;
2 |
3 | import org.caoym.jjvm.lang.JvmClass;
4 | import org.caoym.jjvm.lang.JvmClassLoader;
5 | import org.caoym.jjvm.lang.JvmObject;
6 | import sun.reflect.generics.reflectiveObjects.NotImplementedException;
7 |
8 | import java.util.Arrays;
9 |
10 | public class JvmNativeObject implements JvmObject{
11 |
12 | private Object object;
13 | private final JvmNativeClass clazz;
14 |
15 | public JvmNativeObject(JvmNativeClass clazz){
16 | this.clazz = clazz;
17 | }
18 |
19 | public Object getNativeObject() {
20 | return object;
21 | }
22 |
23 | public void setNativeObject(Object object) {
24 | this.object = object;
25 | }
26 |
27 | @Override
28 | public JvmObject getSuper() {
29 | throw new NotImplementedException();
30 | }
31 |
32 | @Override
33 | public JvmClass getClazz() {
34 | return clazz;
35 | }
36 |
37 | static public Object wrap(Object object, Class clazz, JvmClassLoader classLoader){
38 | if(object == null){
39 | return null;
40 | }
41 | // 非基础类型,需要用JvmNativeObject包装
42 | String primitiveTypes[] = {
43 | byte.class.getName(),
44 | short.class.getName(),
45 | int.class.getName(),
46 | long.class.getName(),
47 | char.class.getName(),
48 | float.class.getName(),
49 | double.class.getName(),
50 | boolean.class.getName()
51 | };
52 | Arrays.sort(primitiveTypes);
53 | if(Arrays.binarySearch(primitiveTypes, clazz.getName()) <0 ){
54 | JvmNativeObject wrap = new JvmNativeObject(new JvmNativeClass(classLoader, clazz));
55 | wrap.setNativeObject(object);
56 | return wrap;
57 | }
58 | return object;
59 | }
60 |
61 | static public Object unwrap(Object object){
62 | if(object instanceof JvmNativeObject){
63 | return ((JvmNativeObject) object).getNativeObject();
64 | }
65 | return object;
66 | }
67 | static public Object[] multiUnwrap(Object[] objects){
68 | Object[] res = new Object[objects.length];
69 | for (int i=0; i ");
41 | sb.append(frame.getCurrentClass().getName());
42 | sb.append(".");
43 | sb.append(frame.getCurrentMethod().getName());
44 | sb.append("@");
45 | sb.append(pc);
46 | sb.append(":");
47 | sb.append(codes[pc]);
48 | System.out.println(sb);
49 | codes[pc].invoke(env, frame);
50 | }
51 | }
52 |
53 | public static OpcodeInvoker[] parseCodes(byte[] codes){
54 | ArrayList opcodes = new ArrayList<>();
55 | for(int i=0; i, JvmOpcodeMethod> methods = new HashMap<>();
22 | private Map fields = new HashMap<>();
23 | /**
24 | * 是否已经初始化
25 | */
26 | boolean inited = false;
27 |
28 | static public JvmOpcodeClass read(JvmClassLoader classLoader, Path path) throws ClassNotFoundException {
29 | try {
30 | return new JvmOpcodeClass(classLoader, ClassFile.read(path));
31 | } catch (IOException e) {
32 | throw new ClassNotFoundException(e.toString());
33 | } catch (Exception e) {
34 | throw new InternalError(e);
35 | }
36 | }
37 | /**
38 | * @param classLoader
39 | * @param classFile
40 | * @throws ConstantPoolException
41 | */
42 | private JvmOpcodeClass(JvmClassLoader classLoader, ClassFile classFile) throws ConstantPoolException, Descriptor.InvalidDescriptor {
43 | this.classFile = classFile;
44 | this.className = classFile.getName();
45 | this.classLoader = classLoader;
46 | for (Method method : classFile.methods) {
47 | String name = method.getName(classFile.constant_pool);
48 | String desc = method.descriptor.getValue(classFile.constant_pool);
49 | methods.put(new AbstractMap.SimpleEntry<>(name, desc), new JvmOpcodeMethod(this, method));
50 | }
51 | //准备阶段
52 | prepare();
53 | }
54 |
55 | /**
56 | * 准备阶段(Preparation)
57 | * 分配静态变量,并初始化为默认值,但不会执行任何字节码,在初始化阶段(clinit) 会有显式的初始化器来初始化这些静态字段,所以准备阶段不做
58 | * 这些事情。
59 | * @see `http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.4.2`
60 | */
61 | private void prepare() throws ConstantPoolException, Descriptor.InvalidDescriptor {
62 | for(Field i : this.classFile.fields){
63 | if(i.access_flags.is(AccessFlags.ACC_STATIC)){
64 | fields.put(i.getName(classFile.constant_pool), new JvmOpcodeStaticField(this, i));
65 | }else{
66 | fields.put(i.getName(classFile.constant_pool), new JvmOpcodeObjectField(this, i));
67 | }
68 | }
69 | }
70 |
71 | /**
72 | * 初始化阶段(Initialization)
73 | * 调用类的方法(如果有)
74 | * @see `http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.5`
75 | */
76 | public void clinit(Env env) throws Exception {
77 | if(inited){
78 | return;
79 | }
80 | synchronized(this){
81 | if(inited){
82 | return;
83 | }
84 | inited = true;
85 | JvmOpcodeMethod method = methods.get(new AbstractMap.SimpleEntry<>("", "()V"));
86 | if(method != null){
87 | method.call(env, null);
88 | }
89 | }
90 | }
91 |
92 | @Override
93 | public JvmObject newInstance(Env env) throws InstantiationException, IllegalAccessException {
94 | try {
95 | clinit(env);
96 | } catch (Exception e) {
97 | throw new InstantiationException(e.getMessage());
98 | }
99 | return new JvmOpcodeObject(env, this);
100 | }
101 |
102 | @Override
103 | public JvmMethod getMethod(String name, String desc) throws NoSuchMethodException {
104 | JvmOpcodeMethod method = methods.get(new AbstractMap.SimpleEntry<>(name, desc));
105 | if(method == null){
106 | throw new NoSuchMethodException("method "+name+":"+ desc+" not exist");
107 | }
108 | return method;
109 | }
110 |
111 | @Override
112 | public boolean hasMethod(String name, String desc) {
113 | JvmOpcodeMethod method = methods.get(new AbstractMap.SimpleEntry<>(name, desc));
114 | return method != null;
115 | }
116 |
117 | @Override
118 | public JvmField getField(String name) throws NoSuchFieldException, IllegalAccessException {
119 | JvmField field = fields.get(name);
120 | if(field == null){
121 | throw new NoSuchFieldException("field "+name+" of "+ className+" not exist");
122 | }
123 | return field;
124 | }
125 |
126 | @Override
127 | public JvmClassLoader getClassLoader() {
128 | return classLoader;
129 | }
130 |
131 | @Override
132 | public JvmClass getSuperClass() throws ClassNotFoundException {
133 | try {
134 | return classLoader.loadClass(classFile.getSuperclassName());
135 | } catch (ConstantPoolException e) {
136 | throw new ClassNotFoundException(e.getMessage());
137 | }
138 | }
139 |
140 | @Override
141 | public String getName() {
142 | return className;
143 | }
144 |
145 | public ClassFile getClassFile() {
146 | return classFile;
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/main/java/org/caoym/jjvm/opcode/JvmOpcodeMethod.java:
--------------------------------------------------------------------------------
1 | package org.caoym.jjvm.opcode;
2 |
3 | import com.sun.tools.classfile.*;
4 | import org.caoym.jjvm.lang.JvmMethod;
5 | import org.caoym.jjvm.runtime.*;
6 |
7 | /**
8 | * 字节码方法(区别于 native 方法)
9 | */
10 | public class JvmOpcodeMethod implements JvmMethod {
11 |
12 | private final JvmOpcodeClass clazz;
13 | private final Method method;
14 | private final OpcodeInvoker[] opcodes;
15 | private final Code_attribute codeAttribute;
16 | private final String name;
17 | private final int parameterCount;
18 |
19 |
20 | public JvmOpcodeMethod(JvmOpcodeClass clazz, Method method) throws ConstantPoolException, Descriptor.InvalidDescriptor {
21 | this.clazz = clazz;
22 | this.method = method;
23 | codeAttribute = (Code_attribute)method.attributes.get("Code");
24 | opcodes = BytecodeInterpreter.parseCodes(codeAttribute.code);
25 | String temp = "";
26 | temp = method.getName(clazz.getClassFile().constant_pool);
27 | parameterCount = method.descriptor.getParameterCount(clazz.getClassFile().constant_pool);
28 | name = temp;
29 | }
30 |
31 | /**
32 | * 解释执行方法的字节码
33 | */
34 | public void call(Env env, Object thiz, Object ...args) throws Exception {
35 | // 每次方法调用都产生一个新的栈帧,当前方法返回后,将其(栈帧)设置为已返回,BytecodeInterpreter.run会在检查到返回后,将栈帧推
36 | // 出栈,并将返回值(如果有)推入上一个栈帧的操作数栈
37 |
38 | StackFrame frame = env.getStack().newFrame(
39 | clazz,
40 | this,
41 | clazz.getClassFile().constant_pool,
42 | opcodes,
43 | codeAttribute.max_locals,
44 | codeAttribute.max_stack);
45 |
46 | // Java 虚拟机使用局部变量表来完成方法调用时的参数传递,当一个方法被调用的时候,它的 参数将会传递至从 0 开始的连续的局部变量表位置
47 | // 上。特别地,当一个实例方法被调用的时候, 第 0 个局部变量一定是用来存储被调用的实例方法所在的对象的引用(即 Java 语言中的“this”
48 | // 关键字)。后续的其他参数将会传递至从 1 开始的连续的局部变量表位置上。
49 |
50 | Slots