├── .gitignore ├── src ├── main │ └── java │ │ └── org │ │ └── destiny │ │ ├── jvm │ │ ├── model │ │ │ ├── attr │ │ │ │ ├── StackMapTable.java │ │ │ │ ├── ConstantValue.java │ │ │ │ ├── LineNumberTable.java │ │ │ │ ├── LocalVariableTable.java │ │ │ │ └── Code.java │ │ │ ├── constant │ │ │ │ ├── ClassIndex.java │ │ │ │ ├── ConstantInfo.java │ │ │ │ ├── detail │ │ │ │ │ ├── AbstractConstantInfo.java │ │ │ │ │ ├── ConstantStringInfo.java │ │ │ │ │ ├── ConstantClassInfo.java │ │ │ │ │ ├── ConstantUtf8Info.java │ │ │ │ │ ├── ConstantFieldRefInfo.java │ │ │ │ │ ├── ConstantMethodRefInfo.java │ │ │ │ │ └── ConstantNameAndTypeInfo.java │ │ │ │ ├── ConstantInfoEnum.java │ │ │ │ └── ConstantPool.java │ │ │ ├── AbstractAttributeInfo.java │ │ │ ├── runtime │ │ │ │ ├── StackFrame.java │ │ │ │ └── ExecutionResult.java │ │ │ ├── command │ │ │ │ ├── ByteCodeCmd.java │ │ │ │ ├── NoOperandCmd.java │ │ │ │ ├── OneOperandCmd.java │ │ │ │ ├── TwoOperandCmd.java │ │ │ │ ├── DupCmd.java │ │ │ │ ├── IloadCmd.java │ │ │ │ ├── Aload0Cmd.java │ │ │ │ ├── Aload1Cmd.java │ │ │ │ ├── Aload2Cmd.java │ │ │ │ ├── Fload3Cmd.java │ │ │ │ ├── Iload1Cmd.java │ │ │ │ ├── Iload2Cmd.java │ │ │ │ ├── Iload3Cmd.java │ │ │ │ ├── AStore1Cmd.java │ │ │ │ ├── VoidReturnCmd.java │ │ │ │ ├── BipushCmd.java │ │ │ │ ├── LdcCmd.java │ │ │ │ ├── GetFieldCmd.java │ │ │ │ ├── PutFieldCmd.java │ │ │ │ ├── NewObjectCmd.java │ │ │ │ ├── InvokeSpecialCmd.java │ │ │ │ ├── InvokeVirtualCmd.java │ │ │ │ ├── GetStaticFieldCmd.java │ │ │ │ └── CommandParser.java │ │ │ ├── InterfaceInfo.java │ │ │ ├── AccessFlagEnum.java │ │ │ ├── FieldInfo.java │ │ │ ├── MethodInfo.java │ │ │ ├── AccessFlag.java │ │ │ └── ClassFile.java │ │ ├── test │ │ │ ├── EmployeeV1.java │ │ │ └── Employee.java │ │ ├── MiniJVM.java │ │ ├── ExecutorEngine.java │ │ ├── util │ │ │ ├── CommandIterator.java │ │ │ ├── ConstantFactory.java │ │ │ ├── ByteCodeIterator.java │ │ │ └── AttributeFactory.java │ │ ├── MethodArea.java │ │ └── loader │ │ │ ├── ClassFileLoader.java │ │ │ └── ClassFileAnalyser.java │ │ ├── hotswap │ │ ├── HotSwapClassLoader.java │ │ ├── HackSystem.java │ │ ├── ByteUtils.java │ │ └── ClassModifier.java │ │ └── classplader │ │ └── MyClassLoader.java └── test │ └── java │ └── org │ └── destiny │ ├── jvm │ └── loader │ │ ├── ClassFileAnalyserTest.java │ │ └── ClassFileLoaderTest.java │ └── classplader │ └── MyClassLoaderTest.java ├── minijvm.iml ├── pom.xml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Java template 3 | # Compiled class file 4 | *.class 5 | 6 | # Log file 7 | *.log 8 | 9 | # BlueJ files 10 | *.ctxt 11 | 12 | # Mobile Tools for Java (J2ME) 13 | .mtj.tmp/ 14 | 15 | # Package Files # 16 | *.jar 17 | *.war 18 | *.ear 19 | *.zip 20 | *.tar.gz 21 | *.rar 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | hs_err_pid* 25 | 26 | .idea -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/attr/StackMapTable.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.attr; 2 | 3 | /** 4 | * @author 王康 5 | * destinywk@163.com 6 | * ------------------------------------------------------------------ 7 | *
8 | * ------------------------------------------------------------------ 9 | * Corpright 2017 Destiny, Org. All rights reserved. 10 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 11 | * @version JDK 1.8.0_101 12 | * @since 2017/8/22 16:38 13 | */ 14 | public class StackMapTable { 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/constant/ClassIndex.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.constant; 2 | 3 | /** 4 | * @author 王康 5 | * destinywk@163.com 6 | * ------------------------------------------------------------------ 7 | * 8 | * ------------------------------------------------------------------ 9 | * Corpright 2017 Destiny, Org. All rights reserved. 10 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 11 | * @version JDK 1.8.0_101 12 | * @since 2017/8/22 16:38 13 | */ 14 | public class ClassIndex { 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/constant/ConstantInfo.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.constant; 2 | 3 | /** 4 | * @author 王康 5 | * destinywk@163.com 6 | * ------------------------------------------------------------------ 7 | * 8 | * ------------------------------------------------------------------ 9 | * Corpright 2017 Destiny, Org. All rights reserved. 10 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 11 | * @version JDK 1.8.0_101 12 | * @since 2017/8/22 16:38 13 | */ 14 | public class ConstantInfo { 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/AbstractAttributeInfo.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model; 2 | 3 | /** 4 | * @author 王康 5 | * destinywk@163.com 6 | * ------------------------------------------------------------------ 7 | * 8 | * ------------------------------------------------------------------ 9 | * Corpright 2017 Destiny, Org. All rights reserved. 10 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 11 | * @version JDK 1.8.0_101 12 | * @since 2017/8/22 16:38 13 | */ 14 | public abstract class AbstractAttributeInfo { 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/test/EmployeeV1.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.test; 2 | 3 | public class EmployeeV1 { 4 | 5 | 6 | private String name; 7 | private int age; 8 | 9 | public EmployeeV1(String name, int age) { 10 | this.name = name; 11 | this.age = age; 12 | } 13 | 14 | public void setName(String name) { 15 | this.name = name; 16 | } 17 | public void setAge(int age){ 18 | this.age = age; 19 | } 20 | public void sayHello() { 21 | System.out.println("Hello , this is class Employee "); 22 | } 23 | public static void main(String[] args){ 24 | EmployeeV1 p = new EmployeeV1("Andy",29); 25 | p.sayHello(); 26 | 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/test/Employee.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.test; 2 | 3 | 4 | public class Employee { 5 | 6 | private String name; 7 | private int age; 8 | 9 | public Employee(String name, int age) { 10 | this.name = name; 11 | this.age = age; 12 | } 13 | 14 | public void sayHello(String name) { 15 | System.out.println( "hello " + name); 16 | } 17 | 18 | public void setName(String name) { 19 | this.name = name; 20 | } 21 | 22 | public void setAge(int age) { 23 | this.age = age; 24 | } 25 | 26 | public static void main(String[] args) { 27 | Employee employee = new Employee("destiny", 20); 28 | employee.sayHello("wangkang"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/runtime/StackFrame.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.runtime; 2 | 3 | import org.destiny.jvm.model.MethodInfo; /** 4 | * @author 王康 5 | * destinywk@163.com 6 | * ------------------------------------------------------------------ 7 | *8 | * 栈帧对象 9 | *
10 | * ------------------------------------------------------------------ 11 | * Corpright 2017 Destiny, Org. All rights reserved. 12 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 13 | * @version JDK 1.8.0_101 14 | * @since 2017/8/22 16:38 15 | */ 16 | public class StackFrame { 17 | public static StackFrame create(MethodInfo mainMethod) { 18 | return null; 19 | } 20 | 21 | public ExecutionResult execute() { 22 | return null; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/runtime/ExecutionResult.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.runtime; 2 | 3 | import org.destiny.jvm.model.MethodInfo; 4 | 5 | /** 6 | * @author 王康 7 | * destinywk@163.com 8 | * ------------------------------------------------------------------ 9 | * 10 | * ------------------------------------------------------------------ 11 | * Corpright 2017 Destiny, Org. All rights reserved. 12 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 13 | * @version JDK 1.8.0_101 14 | * @since 2017/8/22 16:38 15 | */ 16 | public class ExecutionResult { 17 | private boolean pauseAndRunNewFrame; 18 | 19 | 20 | public boolean isPauseAndRunNewFrame() { 21 | return pauseAndRunNewFrame; 22 | } 23 | 24 | public MethodInfo getNextMethod() { 25 | return null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/hotswap/HotSwapClassLoader.java: -------------------------------------------------------------------------------- 1 | package org.destiny.hotswap; 2 | 3 | /** 4 | * @author 王康 5 | * destinywk@163.com 6 | * ------------------------------------------------------------------ 7 | *8 | * 为了多次载入执行类而加入的加载器 9 | * 把defineClass方法开放出来,只有外部显式调用的时候才会使用到loadByte方法 10 | * 由虚拟机调用的时候,仍然按照原有的双亲委派规则使用loadClass方法进行类加载 11 | *
12 | * ------------------------------------------------------------------ 13 | * Corpright 2017 Destiny, Org. All rights reserved. 14 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 15 | * @version JDK 1.8.0_101 16 | * @since 2017/8/22 16:38 17 | */ 18 | public class HotSwapClassLoader extends ClassLoader { 19 | 20 | public HotSwapClassLoader() { 21 | super(HotSwapClassLoader.class.getClassLoader()); 22 | } 23 | 24 | public Class loadByte(byte[] classByte) { 25 | return defineClass(null, classByte, 0, classByte.length); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/MiniJVM.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm; 2 | 3 | import org.destiny.jvm.loader.ClassFileLoader; 4 | 5 | /** 6 | * @author 王康 7 | * hzwangkang1@corp.netease.com 8 | * ------------------------------------------------------------------ 9 | * 10 | * ------------------------------------------------------------------ 11 | * Corpright 2018 Netease, Inc. All rights reserved. 12 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 13 | * @version JDK 1.8.0_101 14 | * @since 2017/8/22 16:38 15 | */ 16 | public class MiniJVM { 17 | 18 | public void run(String[] classPaths, String className) { 19 | ClassFileLoader loader = new ClassFileLoader(); 20 | 21 | // 添加 classPath 22 | for (String classPath : classPaths) { 23 | loader.addClassPath(classPath); 24 | } 25 | 26 | MethodArea methodArea = MethodArea.getInstance(); 27 | methodArea. 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/command/ByteCodeCmd.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.command; 2 | 3 | import org.destiny.jvm.model.runtime.ExecutionResult; 4 | import org.destiny.jvm.model.runtime.StackFrame; 5 | 6 | /** 7 | * @author 王康 8 | * destinywk@163.com 9 | * ------------------------------------------------------------------ 10 | * 11 | * ------------------------------------------------------------------ 12 | * Corpright 2017 Destiny, Org. All rights reserved. 13 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 14 | * @version JDK 1.8.0_101 15 | * @since 2017/8/22 16:38 16 | */ 17 | public abstract class ByteCodeCmd { 18 | 19 | private int offset; 20 | 21 | public int getOffset() { 22 | return offset; 23 | } 24 | 25 | public void setOffset(int offset) { 26 | this.offset = offset; 27 | } 28 | 29 | abstract void execute(StackFrame stackFrame, ExecutionResult result); 30 | 31 | abstract int getLength(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/InterfaceInfo.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author 王康 7 | * destinywk@163.com 8 | * ------------------------------------------------------------------ 9 | * 10 | * ------------------------------------------------------------------ 11 | * Corpright 2017 Destiny, Org. All rights reserved. 12 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 13 | * @version JDK 1.8.0_101 14 | * @since 2017/8/22 16:38 15 | */ 16 | public class InterfaceInfo { 17 | 18 | private List10 | * 常量池中元素的顶层抽象类 11 | *
12 | * ------------------------------------------------------------------ 13 | * Corpright 2017 Destiny, Org. All rights reserved. 14 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 15 | * @version JDK 1.8.0_101 16 | * @since 2017/8/22 16:38 17 | */ 18 | public abstract class AbstractConstantInfo { 19 | 20 | protected ConstantPool constantPool; 21 | 22 | // abstract protected String getContent(); 23 | 24 | public ConstantPool getConstantPool() { 25 | return constantPool; 26 | } 27 | 28 | public void setConstantPool(ConstantPool constantPool) { 29 | this.constantPool = constantPool; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/command/NoOperandCmd.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.command; 2 | 3 | import org.destiny.jvm.model.constant.ConstantPool; 4 | 5 | /** 6 | * @author 王康 7 | * destinywk@163.com 8 | * ------------------------------------------------------------------ 9 | * 10 | * ------------------------------------------------------------------ 11 | * Corpright 2017 Destiny, Org. All rights reserved. 12 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 13 | * @version JDK 1.8.0_101 14 | * @since 2017/8/22 16:38 15 | */ 16 | public abstract class NoOperandCmd extends ByteCodeCmd { 17 | 18 | private ConstantPool constantPool; 19 | 20 | public NoOperandCmd(ConstantPool constantPool) { 21 | this.constantPool = constantPool; 22 | } 23 | 24 | public int getLength() { 25 | return 1; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return "NoOperandCmd{" + 31 | "constantPool=" + constantPool + 32 | '}'; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/command/OneOperandCmd.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.command; 2 | 3 | import org.destiny.jvm.model.constant.ConstantPool; 4 | 5 | /** 6 | * @author 王康 7 | * destinywk@163.com 8 | * ------------------------------------------------------------------ 9 | * 10 | * ------------------------------------------------------------------ 11 | * Corpright 2017 Destiny, Org. All rights reserved. 12 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 13 | * @version JDK 1.8.0_101 14 | * @since 2017/8/22 16:38 15 | */ 16 | public abstract class OneOperandCmd extends ByteCodeCmd { 17 | 18 | private ConstantPool constantPool; 19 | 20 | public OneOperandCmd(ConstantPool constantPool) { 21 | this.constantPool = constantPool; 22 | } 23 | 24 | @Override 25 | public int getLength() { 26 | return 2; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "OneOperandCmd{" + 32 | "constantPool=" + constantPool + 33 | '}'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/command/TwoOperandCmd.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.command; 2 | 3 | import org.destiny.jvm.model.constant.ConstantPool; 4 | 5 | /** 6 | * @author 王康 7 | * destinywk@163.com 8 | * ------------------------------------------------------------------ 9 | * 10 | * ------------------------------------------------------------------ 11 | * Corpright 2017 Destiny, Org. All rights reserved. 12 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 13 | * @version JDK 1.8.0_101 14 | * @since 2017/8/22 16:38 15 | */ 16 | public abstract class TwoOperandCmd extends ByteCodeCmd { 17 | 18 | private ConstantPool constantPool; 19 | 20 | 21 | 22 | public TwoOperandCmd(ConstantPool constantPool) { 23 | this.constantPool = constantPool; 24 | } 25 | 26 | @Override 27 | public int getLength() { 28 | return 3; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return "TwoOperandCmd{" + 34 | "constantPool=" + constantPool + 35 | '}'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/hotswap/HackSystem.java: -------------------------------------------------------------------------------- 1 | package org.destiny.hotswap; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.InputStream; 5 | import java.io.PrintStream; 6 | 7 | /** 8 | * @author 王康 9 | * destinywk@163.com 10 | * ------------------------------------------------------------------ 11 | *12 | * 为JavaClass劫持java.lang.System提供支持 13 | *
14 | * ------------------------------------------------------------------ 15 | * Corpright 2017 Destiny, Org. All rights reserved. 16 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 17 | * @version JDK 1.8.0_101 18 | * @since 2017/8/22 16:38 19 | */ 20 | public class HackSystem { 21 | 22 | public static final InputStream in = System.in; 23 | 24 | private static ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 25 | 26 | public final static PrintStream out = new PrintStream(byteArrayOutputStream); 27 | 28 | public static final PrintStream err = out; 29 | 30 | public static String getBufferString() { 31 | return byteArrayOutputStream.toString(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/constant/detail/ConstantStringInfo.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.constant.detail; 2 | 3 | /** 4 | * @author 王康 5 | * destinywk@163.com 6 | * ------------------------------------------------------------------ 7 | * 8 | * ------------------------------------------------------------------ 9 | * Corpright 2017 Destiny, Org. All rights reserved. 10 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 11 | * @version JDK 1.8.0_101 12 | * @since 2017/8/22 16:38 13 | */ 14 | public class ConstantStringInfo extends AbstractConstantInfo { 15 | 16 | private int tag = 8; 17 | private int stringIndex; 18 | 19 | public ConstantStringInfo() { 20 | } 21 | 22 | public ConstantStringInfo(int stringIndex) { 23 | this.stringIndex = stringIndex; 24 | } 25 | 26 | public int getStringIndex() { 27 | return stringIndex; 28 | } 29 | 30 | public void setStringIndex(int stringIndex) { 31 | this.stringIndex = stringIndex; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "ConstantStringInfo{" + 37 | "tag=" + tag + 38 | ", stringIndex=" + stringIndex + 39 | '}'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/constant/detail/ConstantClassInfo.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.constant.detail; 2 | 3 | /** 4 | * @author 王康 5 | * destinywk@163.com 6 | * ------------------------------------------------------------------ 7 | *8 | * 用于表示类或接口 9 | *
10 | * ------------------------------------------------------------------ 11 | * Corpright 2017 Destiny, Org. All rights reserved. 12 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 13 | * @version JDK 1.8.0_101 14 | * @since 2017/8/22 16:38 15 | */ 16 | public class ConstantClassInfo extends AbstractConstantInfo { 17 | 18 | private int tag = 7; 19 | private int nameIndex; 20 | 21 | public ConstantClassInfo() { 22 | } 23 | 24 | public ConstantClassInfo(int nameIndex) { 25 | this.nameIndex = nameIndex; 26 | } 27 | 28 | public int getNameIndex() { 29 | return nameIndex; 30 | } 31 | 32 | public void setNameIndex(int nameIndex) { 33 | this.nameIndex = nameIndex; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "ConstantClassInfo{" + 39 | "tag=" + tag + 40 | ", nameIndex=" + nameIndex + 41 | '}'; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/ExecutorEngine.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm; 2 | 3 | import org.destiny.jvm.model.MethodInfo; 4 | import org.destiny.jvm.model.runtime.ExecutionResult; 5 | import org.destiny.jvm.model.runtime.StackFrame; 6 | 7 | import java.util.Stack; 8 | 9 | /** 10 | * @author 王康 11 | * hzwangkang1@corp.netease.com 12 | * ------------------------------------------------------------------ 13 | * 14 | * ------------------------------------------------------------------ 15 | * Corpright 2018 Netease, Inc. All rights reserved. 16 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 17 | * @version JDK 1.8.0_101 18 | * @since 2018/7/1 14:56 19 | */ 20 | public class ExecutorEngine { 21 | 22 | private Stack8 | * 字节数组迭代器,自身维护一个字节数组的下标 9 | * 用于按照指定要求遍历字节数组,并返回不同格式数据 10 | *
11 | * ------------------------------------------------------------------ 12 | * Corpright 2017 Destiny, Org. All rights reserved. 13 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 14 | * @version JDK 1.8.0_101 15 | * @since 2017/8/22 16:38 16 | */ 17 | public class CommandIterator { 18 | 19 | private String codes; 20 | 21 | private int index; 22 | 23 | public CommandIterator(String codes) { 24 | this.codes = codes; 25 | index = 0; 26 | } 27 | 28 | public boolean hasNext() { 29 | return index < codes.length(); 30 | } 31 | 32 | public String next2CharAsString() { 33 | StringBuilder stringBuilder = new StringBuilder(); 34 | stringBuilder.append(codes.charAt(index++)); 35 | stringBuilder.append(codes.charAt(index++)); 36 | return stringBuilder.toString(); 37 | } 38 | 39 | public int next2CharAsInt() { 40 | String s = next2CharAsString(); 41 | return Integer.valueOf(s, 16); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /minijvm.iml: -------------------------------------------------------------------------------- 1 | 2 |10 | * 用于表示字符常量的值 11 | *
12 | * ------------------------------------------------------------------ 13 | * Corpright 2017 Destiny, Org. All rights reserved. 14 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 15 | * @version JDK 1.8.0_101 16 | * @since 2017/8/22 16:38 17 | */ 18 | public class ConstantUtf8Info extends AbstractConstantInfo { 19 | 20 | private int tag = 1; 21 | private int length; 22 | private byte[] bytes; 23 | 24 | public ConstantUtf8Info() { 25 | } 26 | 27 | public ConstantUtf8Info(int length, byte[] bytes) { 28 | this.length = length; 29 | this.bytes = bytes; 30 | } 31 | 32 | public int getLength() { 33 | return length; 34 | } 35 | 36 | public void setLength(int length) { 37 | this.length = length; 38 | } 39 | 40 | public byte[] getBytes() { 41 | return bytes; 42 | } 43 | 44 | public void setBytes(byte[] bytes) { 45 | this.bytes = bytes; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return "ConstantUtf8Info{" + 51 | "tag=" + tag + 52 | ", length=" + length + 53 | ", bytes=" + Arrays.toString(bytes) + 54 | '}'; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/org/destiny/jvm/loader/ClassFileAnalyserTest.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.loader; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import org.destiny.jvm.model.ClassFile; 5 | import org.destiny.jvm.model.MethodInfo; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.*; 10 | 11 | /** 12 | * @author 王康 13 | * destinywk@163.com 14 | * ------------------------------------------------------------------ 15 | * 16 | * ------------------------------------------------------------------ 17 | * Corpright 2017 Destiny, Org. All rights reserved. 18 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 19 | * @version JDK 1.8.0_101 20 | * @since 2017/8/22 16:38 21 | */ 22 | public class ClassFileAnalyserTest { 23 | 24 | private ClassFileLoader classFileLoader; 25 | 26 | @Before 27 | public void before() { 28 | classFileLoader = new ClassFileLoader(); 29 | } 30 | 31 | @Test 32 | public void readBinaryCode() throws Exception { 33 | 34 | } 35 | 36 | @Test 37 | public void analysis() throws Exception { 38 | classFileLoader.addClassPath("/Users/destiny/IdeaProjects/coderising/coderising-02-jvm/src/main/java"); 39 | byte[] bytes = classFileLoader.readBinaryCode("org.destiny.jvm.test.Employee"); 40 | ClassFileAnalyser analyser = new ClassFileAnalyser(); 41 | ClassFile classFile = analyser.analysis(bytes); 42 | System.out.println(JSON.toJSONString(classFile)); 43 | 44 | MethodInfo method = classFile.getMethod("main", "([Ljava/lang/String;)V"); 45 | System.err.println(method); 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/constant/ConstantInfoEnum.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.constant; 2 | 3 | /** 4 | * @author 王康 5 | * destinywk@163.com 6 | * ------------------------------------------------------------------ 7 | *8 | * 常量池种类枚举 9 | *
10 | * ------------------------------------------------------------------ 11 | * Corpright 2017 Destiny, Org. All rights reserved. 12 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 13 | * @version JDK 1.8.0_101 14 | * @since 2017/8/22 16:38 15 | */ 16 | public enum ConstantInfoEnum { 17 | 18 | CONSTANT_CLASS_INFO(7, "CONSTANT_CLASS_INFO"), 19 | CONSTANT_FIELD_INFO(9, "CONSTANT_FIELD_INFO"), 20 | CONSTANT_METHOD_INFO(10, "CONSTANT_METHOD_INFO"), 21 | CONSTANT_INTERFACE_INFO(11, "CONSTANT_INTERFACE_INFO"), 22 | CONSTANT_NAMEANDTYPE_INFO(12, "CONSTANT_NAMEANDTYPE_INFO"), 23 | CONSTANT_STRING_INFO(8, "CONSTANT_STRING_INFO"), 24 | CONSTANT_UTF8_INFO(1, "CONSTANT_UTF8_INFO"), 25 | ; 26 | 27 | 28 | private int tag; 29 | private String name; 30 | 31 | ConstantInfoEnum(int tag, String name) { 32 | this.tag = tag; 33 | this.name = name; 34 | } 35 | 36 | public int getTag() { 37 | return tag; 38 | } 39 | 40 | public String getName() { 41 | return name; 42 | } 43 | 44 | public static ConstantInfoEnum valueOf(int tag) { 45 | ConstantInfoEnum[] values = values(); 46 | for (ConstantInfoEnum constantInfoEnum : values) { 47 | if (constantInfoEnum.tag == tag) { 48 | return constantInfoEnum; 49 | } 50 | } 51 | return null; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/constant/ConstantPool.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.constant; 2 | 3 | import org.destiny.jvm.model.constant.detail.AbstractConstantInfo; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author 王康 9 | * destinywk@163.com 10 | * ------------------------------------------------------------------ 11 | *12 | * 常量池 13 | *
14 | * ------------------------------------------------------------------ 15 | * Corpright 2017 Destiny, Org. All rights reserved. 16 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 17 | * @version JDK 1.8.0_101 18 | * @since 2017/8/22 16:38 19 | */ 20 | public class ConstantPool { 21 | 22 | private int length; 23 | private List8 | * 用于表示字段或方法,但没有指明该字段或方法所属的类或接口 9 | *
10 | * ------------------------------------------------------------------ 11 | * Corpright 2017 Destiny, Org. All rights reserved. 12 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 13 | * @version JDK 1.8.0_101 14 | * @since 2017/8/22 16:38 15 | */ 16 | public class ConstantNameAndTypeInfo extends AbstractConstantInfo { 17 | 18 | private int tag = 12; 19 | 20 | /** 21 | * 对常量池中 CONSTANTS_Utf8_info结构的索引 22 | */ 23 | private int nameIndex; 24 | 25 | /** 26 | * 对常量池中 CONSTANTS_Utf8_info结构的索引 27 | */ 28 | private int descriptorIndex; 29 | 30 | public ConstantNameAndTypeInfo() { 31 | } 32 | 33 | public ConstantNameAndTypeInfo(int nameIndex, int descriptorIndex) { 34 | this.nameIndex = nameIndex; 35 | this.descriptorIndex = descriptorIndex; 36 | } 37 | 38 | public int getNameIndex() { 39 | return nameIndex; 40 | } 41 | 42 | public void setNameIndex(int nameIndex) { 43 | this.nameIndex = nameIndex; 44 | } 45 | 46 | public int getDescriptorIndex() { 47 | return descriptorIndex; 48 | } 49 | 50 | public void setDescriptorIndex(int descriptorIndex) { 51 | this.descriptorIndex = descriptorIndex; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return "ConstantNameAndTypeInfo{" + 57 | "tag=" + tag + 58 | ", nameIndex=" + nameIndex + 59 | ", descriptorIndex=" + descriptorIndex + 60 | '}'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/AccessFlagEnum.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model; 2 | 3 | /** 4 | * @author 王康 5 | * destinywk@163.com 6 | * ------------------------------------------------------------------ 7 | *8 | * 访问标志 9 | *
10 | * ------------------------------------------------------------------ 11 | * Corpright 2017 Destiny, Org. All rights reserved. 12 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 13 | * @version JDK 1.8.0_101 14 | * @since 2017/8/22 16:38 15 | */ 16 | public enum AccessFlagEnum { 17 | 18 | PUBLIC("ACC_PUBLIC", 0x0001, "声明为public,可以从包外访问"), 19 | PRIVATE("ACC_PRIVATE", 0x0002, "声明为private"), 20 | PROTECTED("ACC_PROTECTED", 0x0004, "声明为protected"), 21 | STATIC("ACC_STATIC", 0x0008, "是否为static"), 22 | FINAL("ACC_FINAL", 0x0010, "是否为final"), 23 | SYNCHRONIZED("ACC_SYNCHRONIZED", 0x0020, "是否为synchronized"), 24 | SUPER("ACC_SUPER", 0x0020, "当用到invokespecial指令时,需要对父类方法做特殊处理"), 25 | INTERFACE("ACC_INTERFACE", 0x200, "该class文件定义的是接口而不是类"), 26 | ABSTRACT("ACC_ABSTRACT", 0x400, "声明为abstract,不能被实例化"), 27 | SYNTHETIC("ACC_SYNTHETIC", 0x1000, "表示该class文件并非由Java源代码所生成"), 28 | ANNOTATION("ACC_ANNOTATION", 0x2000, "标识注解类型"), 29 | ENUM("ACC_ENUM", 0x4000, "标识枚举类型") 30 | ; 31 | 32 | private String accessName; 33 | private int accessValue; 34 | private String accessDesc; 35 | 36 | AccessFlagEnum(String accessName, int accessValue, String accessDesc) { 37 | this.accessName = accessName; 38 | this.accessValue = accessValue; 39 | this.accessDesc = accessDesc; 40 | } 41 | 42 | public String getAccessName() { 43 | return accessName; 44 | } 45 | 46 | public int getAccessValue() { 47 | return accessValue; 48 | } 49 | 50 | public String getAccessDesc() { 51 | return accessDesc; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/hotswap/ByteUtils.java: -------------------------------------------------------------------------------- 1 | package org.destiny.hotswap; 2 | 3 | /** 4 | * @author 王康 5 | * destinywk@163.com 6 | * ------------------------------------------------------------------ 7 | * 8 | * ------------------------------------------------------------------ 9 | * Corpright 2017 Destiny, Org. All rights reserved. 10 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 11 | * @version JDK 1.8.0_101 12 | * @since 2017/8/22 16:38 13 | */ 14 | public class ByteUtils { 15 | 16 | public static int bytes2Int(byte[] b, int start, int len) { 17 | int sum = 0; 18 | int end = start + len; 19 | for (int i = start; i < end; ++ i) { 20 | int n = b[i] & 0xff; 21 | n <<= (-- len) * 8; 22 | sum = n + sum; 23 | } 24 | return sum; 25 | } 26 | 27 | public static byte[] int2Bytes(int value, int len) { 28 | byte[] b = new byte[len]; 29 | for (int i = 0; i < len; ++ i) { 30 | b[len - i - 1] = (byte) ((value >> 8 * i) & 0xff); 31 | } 32 | return b; 33 | } 34 | 35 | public static String bytes2String(byte[] b, int start, int len) { 36 | return new String(b, start, len); 37 | } 38 | 39 | public static byte[] string2Bytes(String str) { 40 | return str.getBytes(); 41 | } 42 | 43 | public static byte[] bytesReplace(byte[] originalBytes, int offset, int len, byte[] replaceBytes) { 44 | byte[] newBytes = new byte[originalBytes.length + (replaceBytes.length - len)]; 45 | System.arraycopy(originalBytes, 0, newBytes, 0, offset); 46 | System.arraycopy(replaceBytes, 0, newBytes, offset, replaceBytes.length); 47 | System.arraycopy(originalBytes, offset + len, newBytes, offset + replaceBytes.length, originalBytes.length - offset - len); 48 | return newBytes; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/org/destiny/jvm/loader/ClassFileLoaderTest.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.loader; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import java.io.UnsupportedEncodingException; 7 | 8 | /** 9 | * @author 王康 10 | * destinywk@163.com 11 | * ------------------------------------------------------------------ 12 | *13 | * ------------------------------------------------------------------ 14 | * Corpright 2017 Destiny, Org. All rights reserved. 15 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 16 | * @version JDK 1.8.0_101 17 | * @since 2017/8/22 16:38 18 | */ 19 | public class ClassFileLoaderTest { 20 | 21 | 22 | private ClassFileLoader classFileLoader; 23 | 24 | @Before 25 | public void before() { 26 | classFileLoader = new ClassFileLoader(); 27 | } 28 | 29 | @Test 30 | public void readBinaryCode() throws Exception { 31 | classFileLoader.addClassPath("/Users/destiny"); 32 | // System.out.println(classFileLoader.getClassPaths()); 33 | byte[] bytes = classFileLoader.readBinaryCode("Employee"); 34 | System.out.println(bytes.length); 35 | // parseToString(new byte[]{bytes[0], bytes[1], bytes[2], bytes[3]}); 36 | } 37 | 38 | @Test 39 | public void addClassPath() throws Exception { 40 | classFileLoader.addClassPath("/Users/destiny"); 41 | classFileLoader.addClassPath("/Users/guest"); 42 | // int[] ints = new int[]{1, 2}; 43 | System.out.println(classFileLoader.getClassPaths()); 44 | } 45 | 46 | @Test 47 | public void judgeMagic() { 48 | 49 | } 50 | 51 | private String parseToString(byte[] codes) throws UnsupportedEncodingException { 52 | StringBuilder stringBuilder = new StringBuilder(); 53 | for (byte b : codes) { 54 | System.out.println(b); 55 | } 56 | return null; 57 | } 58 | 59 | 60 | } -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/util/ConstantFactory.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.util; 2 | 3 | import org.destiny.jvm.model.constant.detail.*; 4 | 5 | /** 6 | * @author 王康 7 | * destinywk@163.com 8 | * ------------------------------------------------------------------ 9 | *
10 | * 字节码文件的常量工厂,用于根据tag的不同返回不同常量 11 | * 目前暂时只实现 7,9,10,8,12,1 12 | *
13 | * ------------------------------------------------------------------ 14 | * Corpright 2017 Destiny, Org. All rights reserved. 15 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 16 | * @version JDK 1.8.0_101 17 | * @since 2017/8/22 16:38 18 | */ 19 | public class ConstantFactory { 20 | 21 | public AbstractConstantInfo create(ByteCodeIterator iterator) { 22 | int tag = iterator.readU1ToInt(); 23 | 24 | AbstractConstantInfo constantInfo = null; 25 | switch (tag) { 26 | case 1: 27 | int length = iterator.readU2ToInt(); 28 | constantInfo = new ConstantUtf8Info(length, iterator.read(length)); 29 | break; 30 | case 7: 31 | constantInfo = new ConstantClassInfo(iterator.readU2ToInt()); 32 | break; 33 | case 8: 34 | constantInfo = new ConstantStringInfo(iterator.readU2ToInt()); 35 | break; 36 | case 9: 37 | constantInfo = new ConstantFieldRefInfo(iterator.readU2ToInt(), iterator.readU2ToInt()); 38 | break; 39 | case 10: 40 | constantInfo = new ConstantMethodRefInfo(iterator.readU2ToInt(), iterator.readU2ToInt()); 41 | break; 42 | case 12: 43 | constantInfo = new ConstantNameAndTypeInfo(iterator.readU2ToInt(), iterator.readU2ToInt()); 44 | break; 45 | default: 46 | throw new IllegalArgumentException("所传参数无法对应常量池内容: " + tag); 47 | } 48 | return constantInfo; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/attr/ConstantValue.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.attr; 2 | 3 | import org.destiny.jvm.model.AbstractAttributeInfo; 4 | 5 | /** 6 | * @author 王康 7 | * destinywk@163.com 8 | * ------------------------------------------------------------------ 9 | *10 | * 定长属性 11 | * 如果该字段为静态字段,即field_info结构的access_flags项设置了ACC_STATIC标志 12 | * 则说明这个field_info结构所表示的字段,将赋值为它的ConstantValue属性所表示的值 13 | *
14 | * ------------------------------------------------------------------ 15 | * Corpright 2017 Destiny, Org. All rights reserved. 16 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 17 | * @version JDK 1.8.0_101 18 | * @since 2017/8/22 16:38 19 | */ 20 | public class ConstantValue extends AbstractAttributeInfo { 21 | 22 | private int attributeNameIndex; // 常量池的索引 23 | private int attributeLength; // 固定为2 24 | private int constantValueIndex; // 常量池的索引,常量池在该位置给出了给出了该属性的常量值 25 | 26 | public int getAttributeNameIndex() { 27 | return attributeNameIndex; 28 | } 29 | 30 | public void setAttributeNameIndex(int attributeNameIndex) { 31 | this.attributeNameIndex = attributeNameIndex; 32 | } 33 | 34 | public int getAttributeLength() { 35 | return attributeLength; 36 | } 37 | 38 | public void setAttributeLength(int attributeLength) { 39 | this.attributeLength = attributeLength; 40 | } 41 | 42 | public int getConstantValueIndex() { 43 | return constantValueIndex; 44 | } 45 | 46 | public void setConstantValueIndex(int constantValueIndex) { 47 | this.constantValueIndex = constantValueIndex; 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return "ConstantValue{" + 53 | "attributeNameIndex=" + attributeNameIndex + 54 | ", attributeLength=" + attributeLength + 55 | ", constantValueIndex=" + constantValueIndex + 56 | '}'; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/MethodArea.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm; 2 | 3 | import org.destiny.jvm.loader.ClassFileAnalyser; 4 | import org.destiny.jvm.loader.ClassFileLoader; 5 | import org.destiny.jvm.model.ClassFile; 6 | import org.destiny.jvm.model.MethodInfo; 7 | 8 | import java.io.FileNotFoundException; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * @author 王康 14 | * hzwangkang1@corp.netease.com 15 | * ------------------------------------------------------------------ 16 | *17 | * 方法区 18 | *
19 | * ------------------------------------------------------------------ 20 | * Corpright 2018 Netease, Inc. All rights reserved. 21 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 22 | * @version JDK 1.8.0_101 23 | * @since 2017/8/22 16:38 24 | */ 25 | public class MethodArea { 26 | 27 | private Map方法
10 | * ------------------------------------------------------------------ 11 | * Corpright 2017 Destiny, Org. All rights reserved. 12 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 13 | * @version JDK 1.8.0_101 14 | * @since 2017/8/22 16:38 15 | */ 16 | public class MethodInfo { 17 | 18 | private int accessFlags; 19 | private int nameIndex; 20 | private int descriptorIndex; 21 | private int attributesCount; 22 | private List8 | * 字节数组迭代器,自身维护一个字节数组的下标 9 | * 用于按照指定要求遍历字节数组,并返回不同格式数据 10 | *
11 | * ------------------------------------------------------------------ 12 | * Corpright 2017 Destiny, Org. All rights reserved. 13 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 14 | * @version JDK 1.8.0_101 15 | * @since 2017/8/22 16:38 16 | */ 17 | public class ByteCodeIterator { 18 | 19 | private final byte[] codes; 20 | 21 | private int index; 22 | 23 | public ByteCodeIterator(byte[] codes) { 24 | this.codes = codes; 25 | index = 0; 26 | } 27 | 28 | public byte[] read(int length) { 29 | byte[] bytes = new byte[length]; 30 | for (int i = 0; i < length; ++ i) { 31 | bytes[i] = codes[index++]; 32 | } 33 | return bytes; 34 | } 35 | 36 | public String readU4ToString() { 37 | return parse2String(new byte[]{codes[index++], codes[index++], codes[index++], codes[index++]}); 38 | } 39 | 40 | public int readU1ToInt() { 41 | return Byte.toUnsignedInt(codes[index++]); 42 | } 43 | 44 | public int readU2ToInt() { 45 | return parse2Int(new byte[]{codes[index++], codes[index++]}); 46 | } 47 | 48 | public int readU4ToInt() { 49 | return parse2Int(new byte[]{codes[index++], codes[index++], codes[index++], codes[index++]}); 50 | } 51 | 52 | /** 53 | * 将字节数组转换成字符串 54 | * @param codes 字节流 55 | * @return 56 | */ 57 | public String parse2String(byte[] codes) { 58 | StringBuilder stringBuilder = new StringBuilder(); 59 | for (int i = 0; i < codes.length; ++ i) { 60 | byte b = codes[i]; 61 | int value = b & 0xFF; 62 | String strHex = Integer.toHexString(value); 63 | if (strHex.length() < 2) { 64 | strHex = "0" + strHex; 65 | } 66 | stringBuilder.append(strHex); 67 | } 68 | return stringBuilder.toString(); 69 | } 70 | 71 | 72 | private int parse2Int(byte[] bytes) { 73 | int result = 0; 74 | for (int i = 0; i < bytes.length; ++ i) { 75 | result = result | (bytes[bytes.length - 1 - i] & 0xFF) << (i << 3); 76 | } 77 | return result; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/classplader/MyClassLoader.java: -------------------------------------------------------------------------------- 1 | package org.destiny.classplader; 2 | 3 | import org.apache.commons.io.IOUtils; 4 | 5 | import java.io.*; 6 | 7 | /** 8 | * @author 王康 9 | * destinywk@163.com 10 | * ------------------------------------------------------------------ 11 | *12 | * ------------------------------------------------------------------ 13 | * Corpright 2017 Destiny, Org. All rights reserved. 14 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 15 | * @version JDK 1.8.0_101 16 | * @since 2017/8/22 16:38 17 | */ 18 | public class MyClassLoader extends ClassLoader { 19 | 20 | @Override 21 | protected Class> findClass(String name) throws ClassNotFoundException { 22 | // 获取字节数组 23 | byte[] bytes = loadByteCode(name); 24 | if (bytes == null) { 25 | throw new ClassNotFoundException(); 26 | } else { 27 | // 28 | return defineClass(name, bytes, 0, bytes.length); 29 | } 30 | } 31 | 32 | private byte[] loadByteCode(String name) { 33 | String fileName = "/Users/destiny" 34 | + File.separatorChar + name.replace('.', File.separatorChar) + ".class"; 35 | try (InputStream inputStream = new FileInputStream(fileName); 36 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { 37 | byte[] buffer = new byte[1024]; 38 | int length = 0; 39 | while ((length = inputStream.read(buffer)) != -1) { 40 | byteArrayOutputStream.write(buffer, 0, length); 41 | } 42 | return byteArrayOutputStream.toByteArray(); 43 | } catch (FileNotFoundException e) { 44 | e.printStackTrace(); 45 | } catch (IOException e) { 46 | e.printStackTrace(); 47 | } 48 | return null; 49 | } 50 | 51 | private byte[] loadClassFile(String classFileName) { 52 | File file = new File(classFileName); 53 | try { 54 | return IOUtils.toByteArray(new FileInputStream(file)); 55 | } catch (FileNotFoundException e) { 56 | e.printStackTrace(); 57 | } catch (IOException e) { 58 | e.printStackTrace(); 59 | } 60 | return null; 61 | } 62 | 63 | public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { 64 | MyClassLoader myClassLoader = new MyClassLoader(); 65 | Class> clazz = Class.forName("org.destiny.classplader.MyClassLoader", true, myClassLoader); 66 | Object o = clazz.newInstance(); 67 | System.out.println(o); 68 | System.out.println(o.getClass().getClassLoader()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/hotswap/ClassModifier.java: -------------------------------------------------------------------------------- 1 | package org.destiny.hotswap; 2 | 3 | /** 4 | * @author 王康 5 | * destinywk@163.com 6 | * ------------------------------------------------------------------ 7 | *
8 | * 修改class文件 9 | * 目前只提供修改常量池常量的功能 10 | *
11 | * ------------------------------------------------------------------ 12 | * Corpright 2017 Destiny, Org. All rights reserved. 13 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 14 | * @version JDK 1.8.0_101 15 | * @since 2017/8/22 16:38 16 | */ 17 | public class ClassModifier { 18 | 19 | /** 20 | * Class文件中常量池的起始偏移量 21 | */ 22 | private static final int CONSTANT_POOL_COUNT_INDEX = 8; 23 | 24 | /** 25 | * CONSTANT_Utf8_info常量的tag标志 26 | */ 27 | private static final int CONSTANT_Utf8_info = 1; 28 | 29 | /** 30 | * 常量池中11中常量所占的长度 31 | */ 32 | private static final int[] CONSTANT_ITEM_LENGTH = {-1, -1, -1, 5, 5, 9, 9, 3, 3, 5, 5, 5, 5}; 33 | 34 | private static final int u1 = 1; 35 | private static final int u2 = 2; 36 | 37 | private byte[] classByte; 38 | 39 | public ClassModifier(byte[] classByte) { 40 | this.classByte = classByte; 41 | } 42 | 43 | /** 44 | * 修改常量池中CONSTANT_Utf8_info常量的内容 45 | * @param oldStr 46 | * @param newStr 47 | * @return 48 | */ 49 | public byte[] modifyUTF8Constant(String oldStr, String newStr) { 50 | int cpc = getConstantPoolCount(); 51 | int offset = CONSTANT_POOL_COUNT_INDEX + u2; 52 | for (int i = 0; i < cpc; ++ i) { 53 | int tag = ByteUtils.bytes2Int(classByte, offset, u1); 54 | if (tag == CONSTANT_Utf8_info) { 55 | int len = ByteUtils.bytes2Int(classByte, offset + u1, u2); 56 | offset += (u1 + u2); 57 | String str = ByteUtils.bytes2String(classByte, offset, len); 58 | if (str.equalsIgnoreCase(oldStr)) { 59 | byte[] strBytes = ByteUtils.string2Bytes(newStr); 60 | byte[] strlen = ByteUtils.int2Bytes(newStr.length(), u2); 61 | classByte = ByteUtils.bytesReplace(classByte, offset - u2, u2, strlen); 62 | classByte = ByteUtils.bytesReplace(classByte, offset, len, strBytes); 63 | } else { 64 | offset += len; 65 | } 66 | } else { 67 | offset += CONSTANT_ITEM_LENGTH[tag]; 68 | } 69 | } 70 | return classByte; 71 | } 72 | 73 | /** 74 | * 获取常量池中常量的数量 75 | * @return 76 | */ 77 | public int getConstantPoolCount() { 78 | return ByteUtils.bytes2Int(classByte, CONSTANT_POOL_COUNT_INDEX, u2); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/org/destiny/jvm/model/attr/LineNumberTable.java: -------------------------------------------------------------------------------- 1 | package org.destiny.jvm.model.attr; 2 | 3 | import org.destiny.jvm.util.ByteCodeIterator; 4 | import org.destiny.jvm.model.AbstractAttributeInfo; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author 王康 10 | * destinywk@163.com 11 | * ------------------------------------------------------------------ 12 | * 13 | * ------------------------------------------------------------------ 14 | * Corpright 2017 Destiny, Org. All rights reserved. 15 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 16 | * @version JDK 1.8.0_101 17 | * @since 2017/8/22 16:38 18 | */ 19 | public class LineNumberTable extends AbstractAttributeInfo { 20 | 21 | private int attributeNameIndex; // 指向常量池,一定是LineNumberTable 22 | private int attributeLength; // 当前属性长度,不包括开始的6个字节 23 | private int lineNumberTableLength; // 成员数量 24 | private List
14 | * ------------------------------------------------------------------
15 | * Corpright 2017 Destiny, Org. All rights reserved.
16 | * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
17 | * @version JDK 1.8.0_101
18 | * @since 2017/8/22 16:38
19 | */
20 | public class ClassFileLoader {
21 |
22 | /**
23 | * 用于存储loader的所有classpath
24 | */
25 | private List
19 | * 类的解析器,负责根据读入的字节流解析class文件
20 | *
20 | * 属性工厂,用于生产和返回属性
21 | *
15 | * 变长属性,位于method_info中
16 | *