├── .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 locals = frame.getLocalVariables(); 51 | int pos = 0; 52 | if(!method.access_flags.is(AccessFlags.ACC_STATIC)){ 53 | locals.set(0, thiz, 1); 54 | pos++; 55 | } 56 | 57 | for (Object arg : args) { 58 | locals.set(pos++, arg, 1); 59 | } 60 | 61 | // 执行方法前确保类已经初始化 62 | clazz.clinit(env); 63 | BytecodeInterpreter.run(env); 64 | } 65 | 66 | @Override 67 | public int getParameterCount() { 68 | return parameterCount; 69 | } 70 | 71 | @Override 72 | public String getName() { 73 | return name; 74 | } 75 | public byte getCode(int pc){ 76 | Code_attribute codeAttribute = (Code_attribute)method.attributes.get("Code"); 77 | return codeAttribute.code[pc]; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/caoym/jjvm/opcode/JvmOpcodeObject.java: -------------------------------------------------------------------------------- 1 | package org.caoym.jjvm.opcode; 2 | 3 | import org.caoym.jjvm.lang.JvmClass; 4 | import org.caoym.jjvm.lang.JvmObject; 5 | import org.caoym.jjvm.runtime.Env; 6 | 7 | import java.lang.reflect.Field; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | public class JvmOpcodeObject implements JvmObject{ 12 | 13 | private final JvmOpcodeClass clazz; 14 | private final Map fields = new HashMap<>(); 15 | /** 16 | * 父类的实例,即通过 super 访问到的实例 17 | */ 18 | private final JvmObject superObject; 19 | public JvmOpcodeObject(Env env, JvmOpcodeClass clazz) throws IllegalAccessException, InstantiationException { 20 | this.clazz = clazz; 21 | JvmClass superClass = null; 22 | try { 23 | superClass = clazz.getSuperClass(); 24 | } catch (ClassNotFoundException e) { 25 | throw new InstantiationException(e.getMessage()); 26 | } 27 | superObject = superClass.newInstance(env); 28 | //初始化成员变量 29 | for (Field field : superClass.getClass().getFields()) { 30 | Object value; 31 | //初始化为默认值 32 | switch (field.getType().getName()){ 33 | case "byte": 34 | value = (byte)0; 35 | break; 36 | case "char": 37 | value = '\u0000'; 38 | break; 39 | case "double": 40 | value = 0.; 41 | break; 42 | case "float": 43 | value = 0.f; 44 | break; 45 | case "int": 46 | value = 0; 47 | break; 48 | case "long": 49 | value = 0L; 50 | break; 51 | case "short": 52 | value = (short)0; 53 | break; 54 | case "boolean": 55 | value = false; 56 | break; 57 | default: 58 | value = null; 59 | break; 60 | } 61 | fields.put(field.getName(), value); 62 | } 63 | } 64 | public void setField(String name, Object value) { 65 | fields.put(name, value); 66 | } 67 | 68 | public Object getField(String name) { 69 | return fields.get(name); 70 | } 71 | 72 | @Override 73 | public JvmObject getSuper() { 74 | return superObject; 75 | } 76 | 77 | @Override 78 | public JvmClass getClazz() { 79 | return clazz; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/org/caoym/jjvm/opcode/JvmOpcodeObjectField.java: -------------------------------------------------------------------------------- 1 | package org.caoym.jjvm.opcode; 2 | 3 | import com.sun.tools.classfile.ConstantPoolException; 4 | import org.caoym.jjvm.lang.JvmField; 5 | import org.caoym.jjvm.runtime.Env; 6 | import com.sun.tools.classfile.Field; 7 | import sun.reflect.generics.reflectiveObjects.NotImplementedException; 8 | 9 | 10 | public class JvmOpcodeObjectField implements JvmField { 11 | private final JvmOpcodeClass clazz; 12 | private final Field field; 13 | private final String fieldName; 14 | 15 | public JvmOpcodeObjectField(JvmOpcodeClass clazz, Field field) throws ConstantPoolException { 16 | this.clazz = clazz; 17 | this.field = field; 18 | fieldName = field.getName(clazz.getClassFile().constant_pool); 19 | } 20 | @Override 21 | public void set(Env env, Object thiz, Object value) throws IllegalAccessException { 22 | assert thiz instanceof JvmOpcodeObject; 23 | ((JvmOpcodeObject) thiz).setField(fieldName, value); 24 | } 25 | 26 | @Override 27 | public Object get(Env env, Object thiz) throws IllegalAccessException { 28 | assert thiz instanceof JvmOpcodeObject; 29 | return ((JvmOpcodeObject) thiz).getField(fieldName); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/caoym/jjvm/opcode/JvmOpcodeStaticField.java: -------------------------------------------------------------------------------- 1 | package org.caoym.jjvm.opcode; 2 | 3 | import com.sun.tools.classfile.ConstantPoolException; 4 | import com.sun.tools.classfile.Descriptor; 5 | import com.sun.tools.classfile.Field; 6 | import org.caoym.jjvm.lang.JvmField; 7 | import org.caoym.jjvm.runtime.Env; 8 | 9 | /** 10 | * 静态成员 11 | */ 12 | public class JvmOpcodeStaticField implements JvmField { 13 | private final Field field; 14 | private final JvmOpcodeClass clazz; 15 | private Object value; 16 | private final String type; 17 | public JvmOpcodeStaticField(JvmOpcodeClass clazz, Field field) throws Descriptor.InvalidDescriptor, ConstantPoolException { 18 | this.field = field; 19 | this.clazz = clazz; 20 | type = field.descriptor.getFieldType(this.clazz.getClassFile().constant_pool); 21 | //初始化为默认值 22 | switch (type){ 23 | case "byte": 24 | value = (byte)0; 25 | break; 26 | case "char": 27 | value = '\u0000'; 28 | break; 29 | case "double": 30 | value = 0.; 31 | break; 32 | case "float": 33 | value = 0.f; 34 | break; 35 | case "int": 36 | value = 0; 37 | break; 38 | case "long": 39 | value = 0L; 40 | break; 41 | case "short": 42 | value = (short)0; 43 | break; 44 | case "value": 45 | value = false; 46 | break; 47 | default: 48 | value = null; 49 | break; 50 | } 51 | } 52 | 53 | @Override 54 | public void set(Env env, Object thiz, Object value) throws IllegalAccessException { 55 | this.value = value; 56 | } 57 | 58 | @Override 59 | public Object get(Env env, Object thiz) throws IllegalAccessException { 60 | return value; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/caoym/jjvm/opcode/OpcodeInvoker.java: -------------------------------------------------------------------------------- 1 | package org.caoym.jjvm.opcode; 2 | 3 | import org.caoym.jjvm.runtime.Env; 4 | import org.caoym.jjvm.runtime.StackFrame; 5 | 6 | public interface OpcodeInvoker { 7 | public void invoke(Env env, StackFrame frame) throws Exception ; 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/org/caoym/jjvm/opcode/OpcodeRout.java: -------------------------------------------------------------------------------- 1 | package org.caoym.jjvm.opcode; 2 | 3 | import com.sun.org.apache.bcel.internal.Constants; 4 | import com.sun.tools.classfile.ConstantPool; 5 | import com.sun.tools.classfile.ConstantPoolException; 6 | import org.caoym.jjvm.lang.JvmClass; 7 | import org.caoym.jjvm.lang.JvmField; 8 | import org.caoym.jjvm.lang.JvmMethod; 9 | import org.caoym.jjvm.lang.JvmObject; 10 | import org.caoym.jjvm.runtime.Env; 11 | import org.caoym.jjvm.runtime.StackFrame; 12 | 13 | import java.util.*; 14 | 15 | /** 16 | * 操作数例程 17 | */ 18 | public enum OpcodeRout { 19 | 20 | /** 21 | * 将第0个引用类型局部变量推送至栈顶 22 | */ 23 | ALOAD_0(Constants.ALOAD_0){ 24 | @Override 25 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 26 | Object object = frame.getLocalVariables().get(0); 27 | frame.getOperandStack().push(object, 1); 28 | } 29 | }, 30 | /** 31 | * 将第1个引用类型局部变量推送至栈顶 32 | */ 33 | ALOAD_1(Constants.ALOAD_1){ 34 | @Override 35 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 36 | frame.getOperandStack().push(frame.getLocalVariables().get(1), 1); 37 | } 38 | }, 39 | /** 40 | * 将第2个引用类型局部变量推送至栈顶 41 | */ 42 | ALOAD_2(Constants.ALOAD_2){ 43 | @Override 44 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 45 | frame.getOperandStack().push(frame.getLocalVariables().get(2), 1); 46 | } 47 | }, 48 | /** 49 | * 将第3个引用类型局部变量推送至栈顶 50 | */ 51 | ALOAD_3(Constants.ALOAD_3){ 52 | @Override 53 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 54 | frame.getOperandStack().push(frame.getLocalVariables().get(3), 1); 55 | } 56 | }, 57 | /** 58 | * 从当前方法返回 void 59 | */ 60 | RETURN(Constants.RETURN){ 61 | @Override 62 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 63 | frame.setReturn(null, "void"); 64 | } 65 | }, 66 | /** 67 | * 获取对象的静态字段值 68 | */ 69 | GETSTATIC(Constants.GETSTATIC){ 70 | @Override 71 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 72 | int index = (operands[0]<<8)|operands[1]; 73 | ConstantPool.CONSTANT_Fieldref_info info 74 | = (ConstantPool.CONSTANT_Fieldref_info)frame.getConstantPool().get(index); 75 | //静态字段所在的类 76 | JvmClass clazz = env.getVm().getClass(info.getClassName()); 77 | JvmField field = clazz.getField(info.getNameAndTypeInfo().getName()); 78 | //静态字段的值 79 | Object value = field.get(env,null); 80 | frame.getOperandStack().push(value, 1); 81 | } 82 | }, 83 | /** 84 | * 调用超类构造方法,实例初始化方法,私有方法。 85 | */ 86 | INVOKESPECIAL(Constants.INVOKESPECIAL){ 87 | @Override 88 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 89 | int arg = (operands[0]<<8)|operands[1]; 90 | 91 | ConstantPool.CONSTANT_Methodref_info info 92 | = (ConstantPool.CONSTANT_Methodref_info)frame.getConstantPool().get(arg); 93 | 94 | JvmClass clazz = env.getVm().getClass(info.getClassName()); 95 | JvmMethod method = clazz.getMethod( 96 | info.getNameAndTypeInfo().getName(), 97 | info.getNameAndTypeInfo().getType() 98 | ); 99 | //从操作数栈中推出方法的参数 100 | ArrayList args = frame.getOperandStack().multiPop(method.getParameterCount() + 1); 101 | Collections.reverse(args); 102 | Object[] argsArr = args.toArray(); 103 | JvmObject thiz = (JvmObject) argsArr[0]; 104 | 105 | //根据类名确定是调用父类还是子类 106 | while (!thiz.getClazz().getName().equals(clazz.getName())){ 107 | thiz = thiz.getSuper(); 108 | } 109 | method.call(env, thiz, Arrays.copyOfRange(argsArr,1, argsArr.length)); 110 | } 111 | }, 112 | /** 113 | * 将 int,float 或 String 型常量值从常量池中推送至栈顶 114 | */ 115 | LDC(Constants.LDC){ 116 | @Override 117 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 118 | int arg = operands[0]; 119 | ConstantPool.CPInfo info = frame.getConstantPool().get(arg); 120 | frame.getOperandStack().push(asObject(info), 1); 121 | } 122 | }, 123 | /** 124 | * 调用实例方法 125 | */ 126 | INVOKEVIRTUAL(Constants.INVOKEVIRTUAL){ 127 | @Override 128 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 129 | INVOKESPECIAL.invoke(env, frame, operands); 130 | } 131 | }, 132 | /** 133 | * 将 double 型 0 推送至栈顶 134 | */ 135 | DCONST_0(Constants.DCONST_0){ 136 | @Override 137 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 138 | frame.getOperandStack().push(0.0,2); 139 | } 140 | }, 141 | /** 142 | * 将栈顶 double 型数值存入第二个局部变量。 143 | */ 144 | DSTORE_1(Constants.DSTORE_1){ 145 | @Override 146 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 147 | Object var = frame.getOperandStack().pop(); 148 | frame.getLocalVariables().set(1, var, 2); 149 | } 150 | }, 151 | /** 152 | * 将第二个 double 型局部变量推送至栈顶。 153 | */ 154 | DLOAD_1(Constants.DLOAD_1){ 155 | @Override 156 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 157 | Object var = frame.getLocalVariables().get(1); 158 | frame.getOperandStack().push(var, 2); 159 | } 160 | }, 161 | 162 | //dconst_1: 将 double 型 1 推送至栈顶 163 | DCONST_1(Constants.DCONST_1){ 164 | @Override 165 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 166 | frame.getOperandStack().push(1.0, 2); 167 | } 168 | }, 169 | /** 170 | * 将栈顶两 double 型数值相加并将结果压入栈顶 171 | */ 172 | DADD(Constants.DADD){ 173 | @Override 174 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 175 | Double var1 = (Double) frame.getOperandStack().pop(); 176 | Double var2 = (Double) frame.getOperandStack().pop(); 177 | frame.getOperandStack().push(var1 + var2, 2); 178 | } 179 | }, 180 | /** 181 | * 将 int 型 0 推送至栈顶 182 | */ 183 | ICONST_0(Constants.ICONST_0){ 184 | @Override 185 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 186 | frame.getOperandStack().push(0,1); 187 | } 188 | }, 189 | //iconst_1: 将 int 型 1 推送至栈顶 190 | ICONST_1(Constants.ICONST_1){ 191 | @Override 192 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 193 | frame.getOperandStack().push(1, 1); 194 | } 195 | }, 196 | //iconst_2: 将 int 型 2 推送至栈顶 197 | ICONST_2(Constants.ICONST_2){ 198 | @Override 199 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 200 | frame.getOperandStack().push(2, 1); 201 | } 202 | }, 203 | //iconst_3: 将 int 型 3 推送至栈顶 204 | ICONST_3(Constants.ICONST_3){ 205 | @Override 206 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 207 | frame.getOperandStack().push(3, 1); 208 | } 209 | }, 210 | //iconst_4: 将 int 型 4 推送至栈顶 211 | ICONST_4(Constants.ICONST_4){ 212 | @Override 213 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 214 | frame.getOperandStack().push(4, 1); 215 | } 216 | }, 217 | //iconst_5: 将 int 型 5 推送至栈顶 218 | ICONST_5(Constants.ICONST_5){ 219 | @Override 220 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 221 | frame.getOperandStack().push(5, 1); 222 | } 223 | }, 224 | /** 225 | * 将栈顶 int 型数值存入第0个局部变量 226 | */ 227 | ISTORE_0(Constants.ISTORE_0){ 228 | @Override 229 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 230 | frame.getLocalVariables().set(0, frame.getOperandStack().pop(), 1); 231 | } 232 | }, 233 | /** 234 | * 将栈顶 int 型数值存入第1个局部变量 235 | */ 236 | ISTORE_1(Constants.ISTORE_1){ 237 | @Override 238 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 239 | frame.getLocalVariables().set(1, frame.getOperandStack().pop(), 1); 240 | } 241 | }, 242 | /** 243 | * 将栈顶 int 型数值存入第2个局部变量 244 | */ 245 | ISTORE_2(Constants.ISTORE_2){ 246 | @Override 247 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 248 | frame.getLocalVariables().set(2, frame.getOperandStack().pop(), 1); 249 | } 250 | }, 251 | /** 252 | * 将栈顶 int 型数值存入第3个局部变量 253 | */ 254 | ISTORE_3(Constants.ISTORE_3){ 255 | @Override 256 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 257 | frame.getLocalVariables().set(3, frame.getOperandStack().pop(), 1); 258 | } 259 | }, 260 | /** 261 | * 将第0个 int 型局部变量推送至栈顶。 262 | */ 263 | ILOAD_0(Constants.ILOAD_0){ 264 | @Override 265 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 266 | frame.getOperandStack().push(frame.getLocalVariables().get(0), 1); 267 | } 268 | }, 269 | /** 270 | * 将第1个 int 型局部变量推送至栈顶。 271 | */ 272 | ILOAD_1(Constants.ILOAD_1){ 273 | @Override 274 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 275 | frame.getOperandStack().push(frame.getLocalVariables().get(1), 1); 276 | } 277 | }, 278 | /** 279 | * 将第2个 int 型局部变量推送至栈顶。 280 | */ 281 | ILOAD_2(Constants.ILOAD_2){ 282 | @Override 283 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 284 | frame.getOperandStack().push(frame.getLocalVariables().get(2), 1); 285 | } 286 | }, 287 | /** 288 | * 将第3个 int 型局部变量推送至栈顶。 289 | */ 290 | ILOAD_3(Constants.ILOAD_3){ 291 | @Override 292 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 293 | frame.getOperandStack().push(frame.getLocalVariables().get(3), 1); 294 | } 295 | }, 296 | /** 297 | * 将指定 int 型变量增加指定值。 298 | */ 299 | IINC(Constants.IINC){ 300 | @Override 301 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 302 | Integer var = (Integer) frame.getLocalVariables().get(operands[0]); 303 | frame.getLocalVariables().set(operands[0], var + operands[1], 1); 304 | } 305 | }, 306 | /** 307 | * 将栈顶 int 型数值强制转换成 double 型数值并将结果压入栈顶 308 | */ 309 | I2D(Constants.I2D){ 310 | @Override 311 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 312 | Integer var = (Integer) frame.getOperandStack().pop(); 313 | frame.getOperandStack().push((double) var, 2); 314 | } 315 | }, 316 | /** 317 | * 从数组中加载一个 reference 类型数据到操作数栈 318 | */ 319 | AALOAD(Constants.AALOAD){ 320 | @Override 321 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 322 | int index = (int) frame.getOperandStack().pop(); 323 | Object[] arrayRef = (Object[]) frame.getOperandStack().pop(); 324 | frame.getOperandStack().push(arrayRef[index]); 325 | } 326 | }, 327 | /** 328 | * 创建一个对象,并将其引用值压入栈顶。 329 | */ 330 | NEW(Constants.NEW){ 331 | @Override 332 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 333 | int index = (operands[0] << 8)| operands[1]; 334 | ConstantPool.CONSTANT_Class_info info 335 | = (ConstantPool.CONSTANT_Class_info)frame.getConstantPool().get(index); 336 | JvmClass clazz = env.getVm().getClass(info.getName()); 337 | frame.getOperandStack().push(clazz.newInstance(env)); 338 | } 339 | }, 340 | /** 341 | * 复制栈顶数值并将复制值压入栈顶。 342 | */ 343 | DUP(Constants.DUP){ 344 | @Override 345 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 346 | frame.getOperandStack().push(frame.getOperandStack().pick(), frame.getOperandStack().getEndSize()); 347 | } 348 | }, 349 | /** 350 | * 为指定的类的静态域赋值。 351 | */ 352 | PUTSTATIC(Constants.PUTSTATIC){ 353 | @Override 354 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 355 | Object var = frame.getOperandStack().pop(); 356 | int index = (operands[0] << 8)| operands[1]; 357 | ConstantPool.CONSTANT_Fieldref_info info 358 | = (ConstantPool.CONSTANT_Fieldref_info)frame.getConstantPool().get(index); 359 | 360 | JvmClass clazz = env.getVm().getClass(info.getClassName()); 361 | JvmField field = clazz.getField(info.getNameAndTypeInfo().getName()); 362 | field.set(env, null, var); 363 | } 364 | }, 365 | /** 366 | * 为指定的类的实例域赋值 367 | */ 368 | PUTFIELD(Constants.PUTFIELD){ 369 | @Override 370 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 371 | Object value = frame.getOperandStack().pop(); 372 | Object objectref = frame.getOperandStack().pop(); 373 | 374 | int index = (operands[0] << 8)| operands[1]; 375 | ConstantPool.CONSTANT_Fieldref_info info 376 | = (ConstantPool.CONSTANT_Fieldref_info)frame.getConstantPool().get(index); 377 | JvmClass clazz = env.getVm().getClass(info.getClassName()); 378 | JvmField field = clazz.getField(info.getNameAndTypeInfo().getName()); 379 | assert field != null; 380 | field.set(env,objectref, value); 381 | } 382 | }, 383 | /** 384 | * 获取指定类的实例域,并将其值压入栈顶 385 | */ 386 | GETFIELD(Constants.GETFIELD){ 387 | @Override 388 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 389 | Object objectref = frame.getOperandStack().pop(); 390 | 391 | int index = (operands[0] << 8)| operands[1]; 392 | ConstantPool.CONSTANT_Fieldref_info info 393 | = (ConstantPool.CONSTANT_Fieldref_info)frame.getConstantPool().get(index); 394 | JvmClass clazz = env.getVm().getClass(info.getClassName()); 395 | JvmField field = clazz.getField(info.getNameAndTypeInfo().getName()); 396 | frame.getOperandStack().push(field.get(env, objectref)); 397 | } 398 | }, 399 | /** 400 | * 调用接口方法 401 | */ 402 | INVOKEINTERFACE(Constants.INVOKEINTERFACE){ 403 | @Override 404 | public void invoke(Env env, StackFrame frame, byte[] operands) throws Exception { 405 | 406 | // 获取接口和方法信息 407 | int arg = (operands[0]<<8)|operands[1]; 408 | 409 | ConstantPool.CONSTANT_InterfaceMethodref_info info 410 | = (ConstantPool.CONSTANT_InterfaceMethodref_info)frame.getConstantPool().get(arg); 411 | 412 | String interfaceName = info.getClassName(); 413 | String name = info.getNameAndTypeInfo().getName(); 414 | String type = info.getNameAndTypeInfo().getType(); 415 | 416 | // 获取接口的参数数量 417 | int count = 0xff&operands[2]; //TODO count代表参数个数,还是参数所占的槽位数? 418 | //从操作数栈中推出方法的参数 419 | ArrayList args = frame.getOperandStack().multiPop(count + 1); 420 | Collections.reverse(args); 421 | Object[] argsArr = args.toArray(); 422 | 423 | JvmObject thiz = (JvmObject)argsArr[0]; 424 | JvmMethod method = null; 425 | //递归搜索接口方法 426 | while(thiz != null){ 427 | if(thiz.getClazz().hasMethod(name, type)){ 428 | method = thiz.getClazz().getMethod(name, type); 429 | break; 430 | }else{ 431 | thiz = thiz.getSuper(); 432 | } 433 | } 434 | if(method == null){ 435 | throw new AbstractMethodError(info.toString()); 436 | } 437 | // 执行接口方法 438 | method.call(env, thiz, Arrays.copyOfRange(argsArr,1, argsArr.length)); 439 | } 440 | } 441 | ; 442 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 443 | 444 | private static Map codeMapping = new HashMap<>(); 445 | private final short code; 446 | 447 | OpcodeRout(short code){ 448 | this.code = code; 449 | } 450 | 451 | public abstract void invoke(Env env, StackFrame frame, byte[] operands) throws Exception; 452 | 453 | public short getCode() { 454 | return code; 455 | } 456 | 457 | public static OpcodeRout valueOf(short code){ 458 | OpcodeRout op = codeMapping.get(code); 459 | if(op == null){ 460 | throw new InternalError("The opcode "+Constants.OPCODE_NAMES[code]+" Not Impl"); 461 | } 462 | return op; 463 | } 464 | 465 | static private Object asObject(ConstantPool.CPInfo info) throws ConstantPoolException { 466 | Object res = null; 467 | switch (info.getTag()){ 468 | case ConstantPool.CONSTANT_Integer: 469 | res = ((ConstantPool.CONSTANT_Integer_info) info).value; 470 | break; 471 | case ConstantPool.CONSTANT_Float: 472 | res = ((ConstantPool.CONSTANT_Float_info) info).value; 473 | break; 474 | case ConstantPool.CONSTANT_String: 475 | res = ((ConstantPool.CONSTANT_String_info)info).getString(); 476 | break; 477 | default: 478 | throw new InternalError("unknown type: "+info.getTag()); 479 | } 480 | return res; 481 | } 482 | 483 | static { 484 | for (OpcodeRout op: values()) { 485 | codeMapping.put(op.getCode(), op); 486 | } 487 | } 488 | 489 | } 490 | -------------------------------------------------------------------------------- /src/main/java/org/caoym/jjvm/runtime/Env.java: -------------------------------------------------------------------------------- 1 | package org.caoym.jjvm.runtime; 2 | import org.caoym.jjvm.VirtualMachine; 3 | 4 | 5 | /** 6 | * 线程上下文 7 | */ 8 | public class Env { 9 | /** 10 | * 虚拟机栈 11 | */ 12 | private JvmStack stack = new JvmStack(); 13 | /** 14 | * 当前虚拟机 15 | */ 16 | private VirtualMachine vm; 17 | 18 | public Env(VirtualMachine vm){ 19 | this.vm = vm; 20 | } 21 | 22 | public JvmStack getStack() { 23 | return stack; 24 | } 25 | 26 | public VirtualMachine getVm() { 27 | return vm; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/caoym/jjvm/runtime/JvmStack.java: -------------------------------------------------------------------------------- 1 | package org.caoym.jjvm.runtime; 2 | 3 | import com.sun.tools.classfile.ConstantPool; 4 | import org.caoym.jjvm.lang.JvmClass; 5 | import org.caoym.jjvm.lang.JvmMethod; 6 | import org.caoym.jjvm.opcode.OpcodeInvoker; 7 | 8 | /** 9 | * 虚拟机栈 10 | * 每个虚拟机线程持有一个独立的栈 11 | */ 12 | public class JvmStack { 13 | 14 | private SlotsStack frames = new SlotsStack<>(1024); 15 | private boolean running = false; 16 | 17 | public StackFrame newFrame(JvmClass clazz, JvmMethod method) { 18 | StackFrame frame = new StackFrame(clazz, method, null, null, 0, 0); 19 | frames.push(frame, 1); 20 | return frame; 21 | } 22 | 23 | public StackFrame newFrame(JvmClass clazz, JvmMethod method, ConstantPool constantPool, 24 | OpcodeInvoker[] opcodes, 25 | int variables, 26 | int stackSize) { 27 | StackFrame frame = new StackFrame(clazz, method, constantPool, opcodes, variables, stackSize); 28 | frames.push(frame, 1); 29 | return frame; 30 | } 31 | public StackFrame currentFrame() { 32 | return frames.pick(); 33 | } 34 | public StackFrame popFrame(){ 35 | return frames.pop(); 36 | } 37 | public boolean isRunning() { 38 | return running; 39 | } 40 | public void setRunning(boolean running) { 41 | this.running = running; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/caoym/jjvm/runtime/Slots.java: -------------------------------------------------------------------------------- 1 | package org.caoym.jjvm.runtime; 2 | 3 | import java.util.ArrayList; 4 | import java.util.NoSuchElementException; 5 | 6 | /** 7 | * 可指定槽位大小的数组 8 | */ 9 | public class Slots { 10 | private T[] buffer; 11 | 12 | public Slots(int size){ 13 | buffer = (T[]) new Object[size]; 14 | } 15 | 16 | public void set(int pos, T entity, int size) throws IllegalArgumentException{ 17 | if(pos <0 || pos+size > buffer.length){ 18 | throw new IllegalArgumentException("invalid entity size "+size); 19 | } 20 | buffer[pos] = entity; 21 | for(int i=1; i= buffer.length){ 28 | throw new NoSuchElementException(); 29 | } 30 | return buffer[pos]; 31 | } 32 | 33 | public int size(){ 34 | return buffer.length; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/caoym/jjvm/runtime/SlotsStack.java: -------------------------------------------------------------------------------- 1 | package org.caoym.jjvm.runtime; 2 | 3 | import java.util.ArrayList; 4 | import java.util.NoSuchElementException; 5 | 6 | /** 7 | * 可指定槽位大小的栈 8 | */ 9 | public class SlotsStack { 10 | 11 | private T[] buffer; 12 | 13 | private int end = 0; 14 | 15 | public SlotsStack(int size){ 16 | buffer = (T[]) new Object[size]; 17 | } 18 | 19 | public void push(T entity) throws IllegalArgumentException{ 20 | this.push(entity, 1); 21 | } 22 | 23 | public void push(T entity, int size) throws IllegalArgumentException{ 24 | if(size <=0 || end+size>buffer.length){ 25 | throw new IllegalArgumentException("invalid entity size "+size); 26 | } 27 | buffer[end] = entity; 28 | for(int i=1; i0){ 37 | end--; 38 | T entity = buffer[end]; 39 | if(entity != null){ 40 | buffer[end] = null; 41 | return entity; 42 | } 43 | 44 | } 45 | throw new NoSuchElementException(); 46 | } 47 | 48 | /** 49 | * 按正常出栈的顺序 pop 出全部元素 50 | * @return 51 | */ 52 | public ArrayList multiPop(int count) { 53 | if(count<=0) throw new IllegalArgumentException("count should not <= 0"); 54 | ArrayList items = new ArrayList<>(); 55 | while (end >0 && count>0){ 56 | end--; 57 | T entity = buffer[end]; 58 | if(entity != null){ 59 | buffer[end] = null; 60 | items.add(entity); 61 | count --; 62 | } 63 | } 64 | return items; 65 | } 66 | 67 | /** 68 | * 取出最后一个元素,但不出栈 69 | * @return 70 | */ 71 | public T pick(){ 72 | int end = this.end; 73 | while (end > 0) 74 | { 75 | end--; 76 | T entity = buffer[end]; 77 | if(entity != null){ 78 | return entity; 79 | } 80 | } 81 | return null; 82 | } 83 | 84 | public int getEndSize() { 85 | int end = this.end; 86 | while (end > 0) 87 | { 88 | end--; 89 | if(buffer[end] != null){ 90 | return this.end-end; 91 | } 92 | } 93 | return 0; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/org/caoym/jjvm/runtime/StackFrame.java: -------------------------------------------------------------------------------- 1 | package org.caoym.jjvm.runtime; 2 | 3 | import com.sun.tools.classfile.ConstantPool; 4 | import org.caoym.jjvm.lang.JvmClass; 5 | import org.caoym.jjvm.lang.JvmMethod; 6 | import org.caoym.jjvm.opcode.OpcodeInvoker; 7 | 8 | /** 9 | * 栈帧 10 | * 11 | * 对应 JVM 规范中的栈帧的概念,用于表示一次方法调用的上下文 12 | */ 13 | public class StackFrame { 14 | 15 | /** 16 | * 局部变量表(Local Variables) 17 | * 用于存储方法的局部变量 18 | */ 19 | private Slots localVariables; 20 | 21 | /** 22 | * 操作数栈(Operand Stack) 23 | * 用于存储操作指令的输入输出 24 | */ 25 | private SlotsStack operandStack; 26 | 27 | /** 28 | * 字节码 29 | */ 30 | private OpcodeInvoker[] opcodes; 31 | 32 | /** 33 | * 程序计数器 34 | */ 35 | private int pc=0; 36 | /** 37 | * 常量池(Constant Pool) 38 | */ 39 | private ConstantPool constantPool; 40 | private Object returnVal; 41 | private String returnType; 42 | private boolean isReturned = false; 43 | private final JvmClass clazz; 44 | private final JvmMethod method; 45 | 46 | StackFrame(JvmClass clazz,JvmMethod method, ConstantPool constantPool, 47 | OpcodeInvoker[] opcodes, 48 | int variables, 49 | int stackSize) { 50 | this.constantPool = constantPool; 51 | this.opcodes = opcodes; 52 | this.operandStack = new SlotsStack<>(stackSize); 53 | this.localVariables = new Slots<>(variables); 54 | this.clazz = clazz; 55 | this.method = method; 56 | } 57 | 58 | public Slots getLocalVariables() { 59 | return localVariables; 60 | } 61 | 62 | public SlotsStack getOperandStack() { 63 | return operandStack; 64 | } 65 | 66 | public ConstantPool getConstantPool() { 67 | return constantPool; 68 | } 69 | 70 | public void setPC(int pc) { 71 | this.pc = pc; 72 | } 73 | 74 | public void setReturn(Object returnVal, String returnType) { 75 | this.isReturned = true; 76 | this.returnVal = returnVal; 77 | this.returnType = returnType; 78 | } 79 | 80 | public Object getReturn() { 81 | return returnVal; 82 | } 83 | public String getReturnType() { 84 | return returnType; 85 | } 86 | 87 | public boolean isReturned() { 88 | return isReturned; 89 | } 90 | 91 | public int getPC() { 92 | return pc; 93 | } 94 | public int increasePC(){ 95 | return pc++; 96 | } 97 | public OpcodeInvoker[] getOpcodes() { 98 | return opcodes; 99 | } 100 | 101 | public JvmClass getCurrentClass() { 102 | return clazz; 103 | } 104 | 105 | public JvmMethod getCurrentMethod() { 106 | return method; 107 | } 108 | } 109 | --------------------------------------------------------------------------------