diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/CodeAttr.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/CodeAttr.java index 9ecd803572..00135d59c7 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/CodeAttr.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/CodeAttr.java @@ -99,7 +99,7 @@ private void setStackMapTable(StackMapTable t) { public String toString(ConstantPool pool) { StringBuffer buffer = new StringBuffer(); for(int i=0;i codeMap = new HashMap(); - - static{ - codeMap.put("01", "aconst_null"); - - codeMap.put("BB", "new"); - codeMap.put("37", "lstore"); - codeMap.put("B7", "invokespecial"); - codeMap.put("B6", "invokevirtual"); - codeMap.put("B4", "getfield"); - codeMap.put("B5", "putfield"); - codeMap.put("B2", "getstatic"); - - codeMap.put("2A", "aload_0"); - codeMap.put("2B", "aload_1"); - codeMap.put("2C", "aload_2"); - - codeMap.put("10", "bipush"); - codeMap.put("15", "iload"); - codeMap.put("1A", "iload_0"); - codeMap.put("1B", "iload_1"); - codeMap.put("1C", "iload_2"); - codeMap.put("1D", "iload_3"); - - codeMap.put("25", "fload_3"); - - codeMap.put("1E", "lload_0"); - - codeMap.put("24", "fload_2"); - codeMap.put("4C", "astore_1"); - - codeMap.put("A2", "if_icmp_ge"); - codeMap.put("A4", "if_icmple"); - - codeMap.put("A7", "goto"); - - codeMap.put("B1", "return"); - codeMap.put("AC", "ireturn"); - codeMap.put("AE", "freturn"); - - codeMap.put("03", "iconst_0"); - codeMap.put("04", "iconst_1"); - - codeMap.put("3C", "istore_1"); - codeMap.put("3D", "istore_2"); - - codeMap.put("59", "dup"); - - codeMap.put("60", "iadd"); - codeMap.put("84", "iinc"); - - codeMap.put("12", "ldc"); - } - - + String opCode; + ClassFile clzFile; + private int offset; - + public static final String aconst_null = "01"; + public static final String new_object = "BB"; + public static final String lstore = "37"; + public static final String invokespecial = "B7"; + public static final String invokevirtual = "B6"; + public static final String getfield = "B4"; + public static final String putfield = "B5"; + public static final String getstatic = "B2"; + public static final String ldc = "12"; + public static final String dup = "59"; + public static final String bipush = "10"; + public static final String aload_0 = "2A"; + public static final String aload_1 = "2B"; + public static final String aload_2 = "2C"; + public static final String iload = "15"; + public static final String iload_1 = "1B"; + public static final String iload_2 = "1C"; + public static final String iload_3 = "1D"; + public static final String fload_3 = "25"; - protected ByteCodeCommand(ClassFile clzFile, String opCode){ - this.clzFile = clzFile; - this.opCode = opCode; - } - - protected ClassFile getClassFile() { - return clzFile; - } - - public int getOffset() { - return offset; - } + public static final String voidreturn = "B1"; + public static final String ireturn = "AC"; + public static final String freturn = "AE"; - public void setOffset(int offset) { - this.offset = offset; - } - protected ConstantInfo getConstantInfo(int index){ - return this.getClassFile().getConstantPool().getConstantInfo(index); - } - - protected ConstantPool getConstantPool(){ - return this.getClassFile().getConstantPool(); - } - - - - public String getOpCode() { - return opCode; - } + public static final String astore_1 = "4C"; + public static final String if_icmp_ge = "A2"; + public static final String if_icmple = "A4"; + public static final String goto_no_condition = "A7"; + public static final String iconst_0 = "03"; + public static final String iconst_1 = "04"; + public static final String istore_1 = "3C"; + public static final String istore_2 = "3D"; + public static final String iadd = "60"; + public static final String iinc = "84"; + private static Map codeMap = new HashMap(); - public abstract int getLength(); - - - - - public String toString(){ - - StringBuffer buffer = new StringBuffer(); - buffer.append(this.opCode); - - return buffer.toString(); - } - public abstract String toString(ConstantPool pool); - - public String getReadableCodeText(){ - String txt = codeMap.get(opCode); - if(txt == null){ - return opCode; - } - return txt; + static { + codeMap.put("01", "aconst_null"); + + codeMap.put("BB", "new"); + codeMap.put("37", "lstore"); + codeMap.put("B7", "invokespecial"); + codeMap.put("B6", "invokevirtual"); + codeMap.put("B4", "getfield"); + codeMap.put("B5", "putfield"); + codeMap.put("B2", "getstatic"); + + codeMap.put("2A", "aload_0"); + codeMap.put("2B", "aload_1"); + codeMap.put("2C", "aload_2"); + + codeMap.put("10", "bipush"); + codeMap.put("15", "iload"); + codeMap.put("1A", "iload_0"); + codeMap.put("1B", "iload_1"); + codeMap.put("1C", "iload_2"); + codeMap.put("1D", "iload_3"); + + codeMap.put("25", "fload_3"); + + codeMap.put("1E", "lload_0"); + + codeMap.put("24", "fload_2"); + codeMap.put("4C", "astore_1"); + + codeMap.put("A2", "if_icmp_ge"); + codeMap.put("A4", "if_icmple"); + + codeMap.put("A7", "goto"); + + codeMap.put("B1", "return"); + codeMap.put("AC", "ireturn"); + codeMap.put("AE", "freturn"); + + codeMap.put("03", "iconst_0"); + codeMap.put("04", "iconst_1"); + + codeMap.put("3C", "istore_1"); + codeMap.put("3D", "istore_2"); + + codeMap.put("59", "dup"); + + codeMap.put("60", "iadd"); + codeMap.put("84", "iinc"); + + codeMap.put("12", "ldc"); + } + + protected ByteCodeCommand(ClassFile clzFile, String opCode) { + this.clzFile = clzFile; + this.opCode = opCode; + } + + protected ClassFile getClassFile() { + return clzFile; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + + protected ConstantInfo getConstantInfo(int index) { + return this.getClassFile().getConstantPool().getConstantInfo(index); + } + + protected ConstantPool getConstantPool() { + return this.getClassFile().getConstantPool(); + } + + public String getOpCode() { + return opCode; + } + + public abstract int getLength(); + + public String getReadableCodeText() { + String txt = codeMap.get(opCode); + if (txt == null) { + return opCode; } - - //public abstract void execute(StackFrame frame,FrameResult result); + return txt; + } + + public abstract void execute(StackFrame frame, ExecutionResult result); } \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/CommandParser.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/CommandParser.java index b982fa7aa4..7ead19d285 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/CommandParser.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/CommandParser.java @@ -7,41 +7,6 @@ public class CommandParser { - public static final String aconst_null = "01"; - public static final String new_object = "BB"; - public static final String lstore = "37"; - public static final String invokespecial = "B7"; - public static final String invokevirtual = "B6"; - public static final String getfield = "B4"; - public static final String putfield = "B5"; - public static final String getstatic = "B2"; - public static final String ldc = "12"; - public static final String dup = "59"; - public static final String bipush = "10"; - public static final String aload_0 = "2A"; - public static final String aload_1 = "2B"; - public static final String aload_2 = "2C"; - public static final String iload = "15"; - public static final String iload_1 = "1B"; - public static final String iload_2 = "1C"; - public static final String iload_3 = "1D"; - public static final String fload_3 = "25"; - - public static final String voidreturn = "B1"; - public static final String ireturn = "AC"; - public static final String freturn = "AE"; - - public static final String astore_1 = "4C"; - public static final String if_icmp_ge = "A2"; - public static final String if_icmple = "A4"; - public static final String goto_no_condition = "A7"; - public static final String iconst_0 = "03"; - public static final String iconst_1 = "04"; - public static final String istore_1 = "3C"; - public static final String istore_2 = "3D"; - public static final String iadd = "60"; - public static final String iinc = "84"; - public static ByteCodeCommand[] parse(ClassFile clzFile, String codes) { if ((codes == null) || (codes.length() == 0) || (codes.length() % 2) != 0) { @@ -57,51 +22,53 @@ public static ByteCodeCommand[] parse(ClassFile clzFile, String codes) { while (iter.hasNext()) { String opCode = iter.next2CharAsString(); - if (new_object.equals(opCode)) { + if (ByteCodeCommand.new_object.equals(opCode)) { NewObjectCmd cmd = new NewObjectCmd(clzFile, opCode); cmd.setOprand1(iter.next2CharAsInt()); cmd.setOprand2(iter.next2CharAsInt()); cmds.add(cmd); - } else if (invokespecial.equals(opCode)) { + } else if (ByteCodeCommand.invokespecial.equals(opCode)) { InvokeSpecialCmd cmd = new InvokeSpecialCmd(clzFile, opCode); cmd.setOprand1(iter.next2CharAsInt()); cmd.setOprand2(iter.next2CharAsInt()); // System.out.println( cmd.toString(clzFile.getConstPool())); cmds.add(cmd); - } else if (invokevirtual.equals(opCode)) { + } else if (ByteCodeCommand.invokevirtual.equals(opCode)) { InvokeVirtualCmd cmd = new InvokeVirtualCmd(clzFile, opCode); cmd.setOprand1(iter.next2CharAsInt()); cmd.setOprand2(iter.next2CharAsInt()); cmds.add(cmd); - } else if (getfield.equals(opCode)) { + } else if (ByteCodeCommand.getfield.equals(opCode)) { GetFieldCmd cmd = new GetFieldCmd(clzFile, opCode); cmd.setOprand1(iter.next2CharAsInt()); cmd.setOprand2(iter.next2CharAsInt()); cmds.add(cmd); - } else if (getstatic.equals(opCode)) { + } else if (ByteCodeCommand.getstatic.equals(opCode)) { GetStaticFieldCmd cmd = new GetStaticFieldCmd(clzFile, opCode); cmd.setOprand1(iter.next2CharAsInt()); cmd.setOprand2(iter.next2CharAsInt()); cmds.add(cmd); - } else if (putfield.equals(opCode)) { + } else if (ByteCodeCommand.putfield.equals(opCode)) { PutFieldCmd cmd = new PutFieldCmd(clzFile, opCode); cmd.setOprand1(iter.next2CharAsInt()); cmd.setOprand2(iter.next2CharAsInt()); cmds.add(cmd); - } else if (ldc.equals(opCode)) { + } else if (ByteCodeCommand.ldc.equals(opCode)) { LdcCmd cmd = new LdcCmd(clzFile, opCode); cmd.setOperand(iter.next2CharAsInt()); cmds.add(cmd); - } else if (bipush.equals(opCode)) { + } else if (ByteCodeCommand.bipush.equals(opCode)) { BiPushCmd cmd = new BiPushCmd(clzFile, opCode); cmd.setOperand(iter.next2CharAsInt()); cmds.add(cmd); - } else if (dup.equals(opCode) || aload_0.equals(opCode) || aload_1.equals(opCode) || aload_2.equals(opCode) - || iload_1.equals(opCode) || iload_2.equals(opCode) || iload_3.equals(opCode) - || fload_3.equals(opCode) || voidreturn.equals(opCode) || astore_1.equals(opCode)) { + } else if (ByteCodeCommand.dup.equals(opCode) || ByteCodeCommand.aload_0.equals(opCode) + || ByteCodeCommand.aload_1.equals(opCode) || ByteCodeCommand.aload_2.equals(opCode) + || ByteCodeCommand.iload_1.equals(opCode) || ByteCodeCommand.iload_2.equals(opCode) + || ByteCodeCommand.iload_3.equals(opCode) || ByteCodeCommand.fload_3.equals(opCode) + || ByteCodeCommand.voidreturn.equals(opCode) || ByteCodeCommand.astore_1.equals(opCode)) { NoOperandCmd cmd = new NoOperandCmd(clzFile, opCode); cmds.add(cmd); diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/GetFieldCmd.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/GetFieldCmd.java index ec34e7b4a7..e9be866ec6 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/GetFieldCmd.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/GetFieldCmd.java @@ -2,6 +2,10 @@ import com.github.HarryHook.coding2017.jvm.clz.ClassFile; import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; +import com.github.HarryHook.coding2017.jvm.constant.FieldRefInfo; +import com.github.HarryHook.coding2017.jvm.engine.ExecutionResult; +import com.github.HarryHook.coding2017.jvm.engine.JavaObject; +import com.github.HarryHook.coding2017.jvm.engine.StackFrame; public class GetFieldCmd extends TwoOperandCmd { @@ -10,9 +14,21 @@ public GetFieldCmd(ClassFile clzFile, String opCode) { } @Override - public String toString(ConstantPool pool) { + public String toString() { + + return super.getOperandAsField(); + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + FieldRefInfo fieldRef = (FieldRefInfo) this.getConstantInfo(this.getIndex()); + String fieldName = fieldRef.getFieldName(); + JavaObject jo = frame.getOprandStack().pop(); + JavaObject fieldValue = jo.getFieldValue(fieldName); + + frame.getOprandStack().push(fieldValue); - return super.getOperandAsField(pool); } } diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/GetStaticFieldCmd.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/GetStaticFieldCmd.java index 1090e17374..eb943f2422 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/GetStaticFieldCmd.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/GetStaticFieldCmd.java @@ -1,24 +1,39 @@ package com.github.HarryHook.coding2017.jvm.cmd; - import com.github.HarryHook.coding2017.jvm.clz.ClassFile; -import com.github.HarryHook.coding2017.jvm.constant.ClassInfo; import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; import com.github.HarryHook.coding2017.jvm.constant.FieldRefInfo; -import com.github.HarryHook.coding2017.jvm.constant.UTF8Info; - +import com.github.HarryHook.coding2017.jvm.engine.ExecutionResult; +import com.github.HarryHook.coding2017.jvm.engine.Heap; +import com.github.HarryHook.coding2017.jvm.engine.JavaObject; +import com.github.HarryHook.coding2017.jvm.engine.StackFrame; public class GetStaticFieldCmd extends TwoOperandCmd { - public GetStaticFieldCmd(ClassFile clzFile,String opCode) { - super(clzFile,opCode); - - } + public GetStaticFieldCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + + } + + @Override + public String toString() { + + return super.getOperandAsField(); + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + FieldRefInfo info = (FieldRefInfo) this.getConstantInfo(this.getIndex()); + String className = info.getClassName(); + String fieldName = info.getFieldName(); + String fieldType = info.getFieldType(); - @Override - public String toString(ConstantPool pool) { - - return super.getOperandAsField(pool); + if ("java/lang/System".equals(className) && "out".equals(fieldName) + && "Ljava/io/PrintStream;".equals(fieldType)) { + JavaObject jo = Heap.getInstance().newObject(className); + frame.getOprandStack().push(jo); } + // TODO 处理非System.out的情况 + } } \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/InvokeSpecialCmd.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/InvokeSpecialCmd.java index 4afc337f47..3c847d847e 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/InvokeSpecialCmd.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/InvokeSpecialCmd.java @@ -3,21 +3,39 @@ import com.github.HarryHook.coding2017.jvm.clz.ClassFile; import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; import com.github.HarryHook.coding2017.jvm.constant.MethodRefInfo; - +import com.github.HarryHook.coding2017.jvm.engine.ExecutionResult; +import com.github.HarryHook.coding2017.jvm.engine.MethodArea; +import com.github.HarryHook.coding2017.jvm.engine.StackFrame; +import com.github.HarryHook.coding2017.jvm.method.Method; public class InvokeSpecialCmd extends TwoOperandCmd { - public InvokeSpecialCmd(ClassFile clzFile,String opCode) { - super(clzFile,opCode); - - } + public InvokeSpecialCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + + } + + @Override + public String toString() { + + return super.getOperandAsMethod(); + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + MethodRefInfo methodRefInfo = (MethodRefInfo) this.getConstantInfo(this.getIndex()); + + // 我们不用实现jang.lang.Object 的init方法 + if (methodRefInfo.getClassName().equals("java/lang/Object") && methodRefInfo.getMethodName().equals("")) { + return; - @Override - public String toString(ConstantPool pool) { - - return super.getOperandAsMethod(pool); } + Method nextMethod = MethodArea.getInstance().getMethod(methodRefInfo); + + result.setNextAction(ExecutionResult.PAUSE_AND_RUN_NEW_FRAME); + result.setNextMethod(nextMethod); - + } } \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/InvokeVirtualCmd.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/InvokeVirtualCmd.java index 6b494dceda..b94dba6f95 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/InvokeVirtualCmd.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/InvokeVirtualCmd.java @@ -1,21 +1,81 @@ package com.github.HarryHook.coding2017.jvm.cmd; import com.github.HarryHook.coding2017.jvm.clz.ClassFile; -import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; +import com.github.HarryHook.coding2017.jvm.constant.MethodRefInfo; +import com.github.HarryHook.coding2017.jvm.engine.ExecutionResult; +import com.github.HarryHook.coding2017.jvm.engine.JavaObject; +import com.github.HarryHook.coding2017.jvm.engine.MethodArea; +import com.github.HarryHook.coding2017.jvm.engine.StackFrame; +import com.github.HarryHook.coding2017.jvm.method.Method; public class InvokeVirtualCmd extends TwoOperandCmd { - public InvokeVirtualCmd(ClassFile clzFile,String opCode) { - super(clzFile,opCode); + public InvokeVirtualCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + } + + @Override + public String toString() { + + return super.getOperandAsMethod(); + } + + private boolean isSystemOutPrintlnMethod(String className, String methodName) { + return "java/io/PrintStream".equals(className) && "println".equals(methodName); + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + // 先得到对该方法的描述 + MethodRefInfo methodRefInfo = (MethodRefInfo) this.getConstantInfo(this.getIndex()); + + String className = methodRefInfo.getClassName(); + String methodName = methodRefInfo.getMethodName(); + + // 我们没有实现System.out.println方法, 所以也不用建立新的栈帧, 直接调用Java的方法, 打印出来即可。 + if (isSystemOutPrintlnMethod(className, methodName)) { + JavaObject jo = (JavaObject) frame.getOprandStack().pop(); + String value = jo.toString(); + System.err.println("-------------------" + value + "----------------"); + + // 这里就是那个out对象, 因为是个假的,直接pop出来 + frame.getOprandStack().pop(); + + return; + } + + // 注意:多态, 这才是真正的对象, 先从该对象的class 中去找对应的方法,找不到的话再去找父类的方法 + JavaObject jo = frame.getOprandStack().peek(); + + MethodArea ma = MethodArea.getInstance(); + + Method m = null; + + String currentClassName = jo.getClassName(); + + while (currentClassName != null) { + + ClassFile currentClassFile = ma.findClassFile(currentClassName); + + m = currentClassFile.getMethod(methodRefInfo.getMethodName(), methodRefInfo.getParamAndReturnType()); + if (m != null) { + + break; + + } else { + // 查找父类 + currentClassName = currentClassFile.getSuperClassName(); + } } - @Override - public String toString(ConstantPool pool) { - - return super.getOperandAsMethod(pool); + if (m == null) { + throw new RuntimeException("Can't find method for :" + methodRefInfo.toString()); } - - + result.setNextAction(ExecutionResult.PAUSE_AND_RUN_NEW_FRAME); + + result.setNextMethod(m); + } } \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/LdcCmd.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/LdcCmd.java index 073ddd73a9..5a611df6ae 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/LdcCmd.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/LdcCmd.java @@ -4,26 +4,47 @@ import com.github.HarryHook.coding2017.jvm.constant.ConstantInfo; import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; import com.github.HarryHook.coding2017.jvm.constant.StringInfo; +import com.github.HarryHook.coding2017.jvm.engine.ExecutionResult; +import com.github.HarryHook.coding2017.jvm.engine.Heap; +import com.github.HarryHook.coding2017.jvm.engine.JavaObject; +import com.github.HarryHook.coding2017.jvm.engine.StackFrame; public class LdcCmd extends OneOperandCmd { - public LdcCmd(ClassFile clzFile,String opCode) { - super(clzFile,opCode); + public LdcCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + } + + @Override + public String toString() { + + ConstantInfo info = (ConstantInfo) getConstantInfo(this.getOperand()); + + String value = "TBD"; + if (info instanceof StringInfo) { + StringInfo strInfo = (StringInfo) info; + value = strInfo.toString(); } - - @Override - public String toString(ConstantPool pool) { - - ConstantInfo info = (ConstantInfo)pool.getConstantInfo(this.getOperand()); - - String value = "TBD"; - if(info instanceof StringInfo){ - StringInfo strInfo = (StringInfo)info; - value = strInfo.toString(); - } - - return this.getOffset()+":"+this.getOpCode()+" " + this.getReadableCodeText() + " "+ value; - + + return this.getOffset() + ":" + this.getOpCode() + " " + this.getReadableCodeText() + " " + value; + + } + + public void execute(StackFrame frame, ExecutionResult result) { + + ConstantPool pool = this.getConstantPool(); + ConstantInfo info = (ConstantInfo) pool.getConstantInfo(this.getOperand()); + + if (info instanceof StringInfo) { + StringInfo strInfo = (StringInfo) info; + String value = strInfo.toString(); + JavaObject jo = Heap.getInstance().newString(value); + frame.getOprandStack().push(jo); + } else { + // TBD 处理其他类型 + throw new RuntimeException("Only support StringInfo constant"); } - + + } + } \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/NewObjectCmd.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/NewObjectCmd.java index 9c959e31dd..1345d7181f 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/NewObjectCmd.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/NewObjectCmd.java @@ -1,19 +1,38 @@ package com.github.HarryHook.coding2017.jvm.cmd; import com.github.HarryHook.coding2017.jvm.clz.ClassFile; +import com.github.HarryHook.coding2017.jvm.constant.ClassInfo; import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; +import com.github.HarryHook.coding2017.jvm.engine.ExecutionResult; +import com.github.HarryHook.coding2017.jvm.engine.Heap; +import com.github.HarryHook.coding2017.jvm.engine.JavaObject; +import com.github.HarryHook.coding2017.jvm.engine.StackFrame; -public class NewObjectCmd extends TwoOperandCmd{ - - public NewObjectCmd(ClassFile clzFile, String opCode){ - super(clzFile,opCode); - } +public class NewObjectCmd extends TwoOperandCmd { - @Override - public String toString(ConstantPool pool) { - - return super.getOperandAsClassInfo(pool); - } + public NewObjectCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + } + + @Override + public String toString() { + + return super.getOperandAsClassInfo(); + } + + public void execute(StackFrame frame, ExecutionResult result) { + + int index = this.getIndex(); + + ClassInfo info = (ClassInfo) this.getConstantInfo(index); + + String clzName = info.getClassName(); + + // 在Java堆上创建一个实例 + JavaObject jo = Heap.getInstance().newObject(clzName); + + frame.getOprandStack().push(jo); + + } - } diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/NoOperandCmd.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/NoOperandCmd.java index 554eac0690..c658260086 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/NoOperandCmd.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/NoOperandCmd.java @@ -2,22 +2,140 @@ import com.github.HarryHook.coding2017.jvm.clz.ClassFile; import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; +import com.github.HarryHook.coding2017.jvm.engine.ExecutionResult; +import com.github.HarryHook.coding2017.jvm.engine.Heap; +import com.github.HarryHook.coding2017.jvm.engine.JavaObject; +import com.github.HarryHook.coding2017.jvm.engine.StackFrame; -public class NoOperandCmd extends ByteCodeCommand{ +public class NoOperandCmd extends ByteCodeCommand { - public NoOperandCmd(ClassFile clzFile, String opCode) { - super(clzFile, opCode); - } + public NoOperandCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + } + + @Override + public String toString() { + return this.getOffset() + ":" + this.getOpCode() + " " + this.getReadableCodeText(); + } + + public int getLength() { + return 1; + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + String opCode = this.getOpCode(); + + if (ByteCodeCommand.aload_0.equals(opCode)) { + + JavaObject jo = frame.getLocalVariableValue(0); + + frame.getOprandStack().push(jo); + + } else if (ByteCodeCommand.aload_1.equals(opCode)) { + + JavaObject jo = frame.getLocalVariableValue(1); + + frame.getOprandStack().push(jo); + + } else if (ByteCodeCommand.aload_2.equals(opCode)) { + + JavaObject jo = frame.getLocalVariableValue(2); + + frame.getOprandStack().push(jo); + + } else if (ByteCodeCommand.iload_1.equals(opCode)) { + + JavaObject jo = frame.getLocalVariableValue(1); + + frame.getOprandStack().push(jo); + + } else if (ByteCodeCommand.iload_2.equals(opCode)) { + + JavaObject jo = frame.getLocalVariableValue(2); + + frame.getOprandStack().push(jo); + + } else if (ByteCodeCommand.iload_3.equals(opCode)) { + + JavaObject jo = frame.getLocalVariableValue(3); + + frame.getOprandStack().push(jo); + + } else if (ByteCodeCommand.fload_3.equals(opCode)) { + + JavaObject jo = frame.getLocalVariableValue(3); + + frame.getOprandStack().push(jo); + + } else if (ByteCodeCommand.voidreturn.equals(opCode)) { - @Override - public String toString(ConstantPool pool) { - return this.getOffset()+":" +this.getOpCode() + " "+ this.getReadableCodeText(); + result.setNextAction(ExecutionResult.EXIT_CURRENT_FRAME); + + } else if (ByteCodeCommand.ireturn.equals(opCode)) { + StackFrame callerFrame = frame.getCallerFrame(); + JavaObject jo = frame.getOprandStack().pop(); + callerFrame.getOprandStack().push(jo); + + } else if (ByteCodeCommand.freturn.equals(opCode)) { + + StackFrame callerFrame = frame.getCallerFrame(); + JavaObject jo = frame.getOprandStack().pop(); + callerFrame.getOprandStack().push(jo); } - - - public int getLength(){ - return 1; + else if (ByteCodeCommand.astore_1.equals(opCode)) { + + JavaObject jo = frame.getOprandStack().pop(); + + frame.setLocalVariableValue(1, jo); + + } else if (ByteCodeCommand.dup.equals(opCode)) { + + JavaObject jo = frame.getOprandStack().peek(); + frame.getOprandStack().push(jo); + + } else if (ByteCodeCommand.iconst_0.equals(opCode)) { + + JavaObject jo = Heap.getInstance().newInt(0); + + frame.getOprandStack().push(jo); + + } else if (ByteCodeCommand.iconst_1.equals(opCode)) { + + JavaObject jo = Heap.getInstance().newInt(1); + + frame.getOprandStack().push(jo); + + } else if (ByteCodeCommand.istore_1.equals(opCode)) { + + JavaObject jo = frame.getOprandStack().pop(); + + frame.setLocalVariableValue(1, jo); + + } else if (ByteCodeCommand.istore_2.equals(opCode)) { + + JavaObject jo = frame.getOprandStack().pop(); + + frame.setLocalVariableValue(2, jo); + + } else if (ByteCodeCommand.iadd.equals(opCode)) { + + JavaObject jo1 = frame.getOprandStack().pop(); + JavaObject jo2 = frame.getOprandStack().pop(); + + JavaObject sum = Heap.getInstance().newInt(jo1.getIntValue() + jo2.getIntValue()); + + frame.getOprandStack().push(sum); + + } else if (ByteCodeCommand.aconst_null.equals(opCode)) { + + frame.getOprandStack().push(null); + + } else { + throw new RuntimeException("you must forget to implement the operation :" + opCode); } + } } diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/PutFieldCmd.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/PutFieldCmd.java index f3a197114c..91549d7c01 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/PutFieldCmd.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/PutFieldCmd.java @@ -1,19 +1,43 @@ package com.github.HarryHook.coding2017.jvm.cmd; import com.github.HarryHook.coding2017.jvm.clz.ClassFile; +import com.github.HarryHook.coding2017.jvm.constant.ClassInfo; import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; +import com.github.HarryHook.coding2017.jvm.constant.FieldRefInfo; +import com.github.HarryHook.coding2017.jvm.constant.NameAndTypeInfo; +import com.github.HarryHook.coding2017.jvm.engine.ExecutionResult; +import com.github.HarryHook.coding2017.jvm.engine.JavaObject; +import com.github.HarryHook.coding2017.jvm.engine.StackFrame; public class PutFieldCmd extends TwoOperandCmd { - public PutFieldCmd(ClassFile clzFile,String opCode) { - super(clzFile,opCode); - } + public PutFieldCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + } - @Override - public String toString(ConstantPool pool) { - - return super.getOperandAsField(pool); - } + @Override + public String toString() { + return super.getOperandAsField(); + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + FieldRefInfo fieldRef = (FieldRefInfo) this.getConstantInfo(this.getIndex()); + + ClassInfo clzInfo = (ClassInfo) this.getConstantInfo(fieldRef.getClassInfoIndex()); + NameAndTypeInfo nameTypeInfo = (NameAndTypeInfo) this.getConstantInfo(fieldRef.getNameAndTypeIndex()); + // for example : name + String fieldName = nameTypeInfo.getName(); + // for example : Ljava/lang/String : 注意:我们不再检查类型 + String fieldType = nameTypeInfo.getTypeInfo(); + + JavaObject fieldValue = frame.getOprandStack().pop(); + JavaObject objectRef = frame.getOprandStack().pop(); + + objectRef.setFieldValue(fieldName, fieldValue); + + } } \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/TwoOperandCmd.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/TwoOperandCmd.java index 13edc86215..d0d38f368f 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/TwoOperandCmd.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/cmd/TwoOperandCmd.java @@ -7,61 +7,62 @@ import com.github.HarryHook.coding2017.jvm.constant.FieldRefInfo; import com.github.HarryHook.coding2017.jvm.constant.MethodRefInfo; -public abstract class TwoOperandCmd extends ByteCodeCommand{ - - int oprand1 = -1; - int oprand2 = -1; - - public int getOprand1() { - return oprand1; - } +public abstract class TwoOperandCmd extends ByteCodeCommand { - public void setOprand1(int oprand1) { - this.oprand1 = oprand1; - } + int oprand1 = -1; + int oprand2 = -1; - public void setOprand2(int oprand2) { - this.oprand2 = oprand2; - } + public int getOprand1() { + return oprand1; + } - public int getOprand2() { - return oprand2; - } - - public TwoOperandCmd(ClassFile clzFile,String opCode) { - super(clzFile, opCode); - } + public void setOprand1(int oprand1) { + this.oprand1 = oprand1; + } - public int getIndex(){ - int oprand1 = this.getOprand1(); - int oprand2 = this.getOprand2(); - int index = oprand1 << 8 | oprand2; - return index; - } - - protected String getOperandAsClassInfo(ConstantPool pool){ - int index = getIndex(); - String codeTxt = getReadableCodeText(); - ClassInfo info = (ClassInfo)pool.getConstantInfo(index); - return this.getOffset()+":"+this.getOpCode()+" "+ codeTxt +" "+ info.getClassName(); - } - - protected String getOperandAsMethod(ConstantPool pool){ - int index = getIndex(); - String codeTxt = getReadableCodeText(); - ConstantInfo constInfo = this.getConstantInfo(index); - MethodRefInfo info = (MethodRefInfo)this.getConstantInfo(index); - return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); - } + public void setOprand2(int oprand2) { + this.oprand2 = oprand2; + } - protected String getOperandAsField(ConstantPool pool){ - int index = getIndex(); - - String codeTxt = getReadableCodeText(); - FieldRefInfo info = (FieldRefInfo)this.getConstantInfo(index); - return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); - } - public int getLength(){ - return 3; - } + public int getOprand2() { + return oprand2; + } + + public TwoOperandCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + } + + public int getIndex() { + int oprand1 = this.getOprand1(); + int oprand2 = this.getOprand2(); + int index = oprand1 << 8 | oprand2; + return index; + } + + protected String getOperandAsClassInfo() { + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ClassInfo info = (ClassInfo) getConstantInfo(index); + return this.getOffset() + ":" + this.getOpCode() + " " + codeTxt + " " + info.getClassName(); + } + + protected String getOperandAsMethod() { + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ConstantInfo constInfo = this.getConstantInfo(index); + MethodRefInfo info = (MethodRefInfo) this.getConstantInfo(index); + return this.getOffset() + ":" + this.getOpCode() + " " + codeTxt + " " + info.toString(); + } + + protected String getOperandAsField() { + int index = getIndex(); + + String codeTxt = getReadableCodeText(); + FieldRefInfo info = (FieldRefInfo) this.getConstantInfo(index); + return this.getOffset() + ":" + this.getOpCode() + " " + codeTxt + " " + info.toString(); + } + + public int getLength() { + return 3; + } } diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/constant/ClassInfo.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/constant/ClassInfo.java index e4822e2bbb..3ea5bcbc53 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/constant/ClassInfo.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/constant/ClassInfo.java @@ -25,8 +25,9 @@ public String getClassName() { UTF8Info utf8Info = (UTF8Info) constantPool.getConstantInfo(index); return utf8Info.getValue(); } + @Override - public void accept(Visitor visitor) { - visitor.visitClassInfo(this); - } + public void accept(Visitor visitor) { + visitor.visitClassInfo(this); + } } diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/constant/ConstantInfo.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/constant/ConstantInfo.java index 6c502016a3..cf046f6b2e 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/constant/ConstantInfo.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/constant/ConstantInfo.java @@ -27,17 +27,22 @@ public ConstantPool getConstantPool() { public ConstantInfo getConstantInfo(int index) { return this.constantPool.getConstantInfo(index); } - + public abstract void accept(Visitor visitor); - - public static interface Visitor{ - public void visitClassInfo(ClassInfo info); - public void visitFieldRef(FieldRefInfo info); - public void visitMethodRef(MethodRefInfo info); - public void visitNameAndType(NameAndTypeInfo info); - public void visitString(StringInfo info); - public void visistUTF8(UTF8Info info); - - } - + + public static interface Visitor { + public void visitClassInfo(ClassInfo info); + + public void visitFieldRef(FieldRefInfo info); + + public void visitMethodRef(MethodRefInfo info); + + public void visitNameAndType(NameAndTypeInfo info); + + public void visitString(StringInfo info); + + public void visistUTF8(UTF8Info info); + + } + } \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/ExecutionResult.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/ExecutionResult.java new file mode 100644 index 0000000000..2e6a07838c --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/ExecutionResult.java @@ -0,0 +1,53 @@ +package com.github.HarryHook.coding2017.jvm.engine; + +import com.github.HarryHook.coding2017.jvm.method.Method; + +public class ExecutionResult { + public static final int RUN_NEXT_CMD = 1; + public static final int JUMP = 2; + public static final int EXIT_CURRENT_FRAME = 3; + public static final int PAUSE_AND_RUN_NEW_FRAME = 4; + + private int nextAction = RUN_NEXT_CMD; + + private int nextCmdOffset = 0; + + private Method nextMethod; + + public Method getNextMethod() { + return nextMethod; + } + + public void setNextMethod(Method nextMethod) { + this.nextMethod = nextMethod; + } + + public void setNextAction(int action) { + this.nextAction = action; + } + + public boolean isPauseAndRunNewFrame() { + return this.nextAction == PAUSE_AND_RUN_NEW_FRAME; + } + + public boolean isExitCurrentFrame() { + return this.nextAction == EXIT_CURRENT_FRAME; + } + + public boolean isRunNextCmd() { + return this.nextAction == RUN_NEXT_CMD; + } + + public boolean isJump() { + return this.nextAction == JUMP; + } + + public int getNextCmdOffset() { + return nextCmdOffset; + } + + public void setNextCmdOffset(int nextCmdOffset) { + this.nextCmdOffset = nextCmdOffset; + } + +} diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/ExecutorEngine.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/ExecutorEngine.java new file mode 100644 index 0000000000..85eeeaba50 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/ExecutorEngine.java @@ -0,0 +1,78 @@ +package com.github.HarryHook.coding2017.jvm.engine; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import com.github.HarryHook.coding2017.jvm.attr.CodeAttr; +import com.github.HarryHook.coding2017.jvm.clz.ClassFile; +import com.github.HarryHook.coding2017.jvm.cmd.ByteCodeCommand; +import com.github.HarryHook.coding2017.jvm.constant.MethodRefInfo; +import com.github.HarryHook.coding2017.jvm.method.Method; + +public class ExecutorEngine { + + private Stack stack = new Stack(); + + public ExecutorEngine() { + + } + + public void execute(Method mainMethod) { + + StackFrame mainFrame = StackFrame.create(mainMethod); + stack.push(mainFrame); + + while (!stack.empty()) { + + StackFrame frame = stack.peek(); + + ExecutionResult result = frame.execute(); + + if (result.isPauseAndRunNewFrame()) { + + Method nextMethod = result.getNextMethod(); + StackFrame nextFrame = StackFrame.create(nextMethod); + nextFrame.setCallerFrame(frame); + setupFunctionCallParams(frame, nextFrame); + + stack.push(nextFrame); + + } else { + + stack.pop(); + + } + } + + } + + private void setupFunctionCallParams(StackFrame currentFrame, StackFrame nextFrame) { + + Method nextMethod = nextFrame.getMethod(); + + List paramList = nextMethod.getParameterList(); + + // 加上1 是因为要把this也传递过去 + + int paramNum = paramList.size() + 1; + + List values = new ArrayList(); + + // 数据结构知识: 从栈中取出栈顶的x个元素 + while (paramNum > 0) { + values.add(currentFrame.getOprandStack().pop()); + paramNum--; + } + // 数据结构知识: 把一个列表倒序排列 + List params = new ArrayList(); + + for (int i = values.size() - 1; i >= 0; i--) { + params.add(values.get(i)); + } + + nextFrame.setLocalVariableTable(params); + + } + +} diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/Heap.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/Heap.java new file mode 100644 index 0000000000..f249407d7f --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/Heap.java @@ -0,0 +1,43 @@ +package com.github.HarryHook.coding2017.jvm.engine; + +public class Heap { + + /** + * 没有实现垃圾回收, 所以对于下面新创建的对象, 并没有记录到一个数据结构当中 + */ + + private static Heap instance = new Heap(); + + private Heap() { + } + + public static Heap getInstance() { + return instance; + } + + public JavaObject newObject(String clzName) { + + JavaObject jo = new JavaObject(JavaObject.OBJECT); + jo.setClassName(clzName); + return jo; + } + + public JavaObject newString(String value) { + JavaObject jo = new JavaObject(JavaObject.STRING); + jo.setStringValue(value); + return jo; + } + + public JavaObject newFloat(float value) { + JavaObject jo = new JavaObject(JavaObject.FLOAT); + jo.setFloatValue(value); + return jo; + } + + public JavaObject newInt(int value) { + JavaObject jo = new JavaObject(JavaObject.INT); + jo.setIntValue(value); + return jo; + } + +} diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/JavaObject.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/JavaObject.java new file mode 100644 index 0000000000..edce5aad4f --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/JavaObject.java @@ -0,0 +1,82 @@ +package com.github.HarryHook.coding2017.jvm.engine; + +import java.util.HashMap; +import java.util.Map; + +public class JavaObject { + public static final int OBJECT = 1; + public static final int STRING = 2; + public static final int INT = 3; + public static final int FLOAT = 4; + + int type; + private String className; + + private Map fieldValues = new HashMap(); + + private String stringValue; + + private int intValue; + + private float floatValue; + + public void setFieldValue(String fieldName, JavaObject fieldValue) { + fieldValues.put(fieldName, fieldValue); + } + + public JavaObject(int type) { + this.type = type; + } + + public void setClassName(String className) { + this.className = className; + } + + public void setStringValue(String value) { + stringValue = value; + } + + public String getStringValue() { + return this.stringValue; + } + + public void setIntValue(int value) { + this.intValue = value; + } + + public int getIntValue() { + return this.intValue; + } + + public int getType() { + return type; + } + + public JavaObject getFieldValue(String fieldName) { + return this.fieldValues.get(fieldName); + } + + public String toString() { + switch (this.getType()) { + case INT: + return String.valueOf(this.intValue); + case STRING: + return this.stringValue; + case OBJECT: + return this.className + ":" + this.fieldValues; + case FLOAT: + return String.valueOf(this.floatValue); + default: + return null; + } + } + + public String getClassName() { + return this.className; + } + + public void setFloatValue(float value) { + this.floatValue = value; + } + +} diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/MethodArea.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/MethodArea.java new file mode 100644 index 0000000000..0e102b8765 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/MethodArea.java @@ -0,0 +1,83 @@ +package com.github.HarryHook.coding2017.jvm.engine; + +import java.util.HashMap; +import java.util.Map; + +import com.github.HarryHook.coding2017.jvm.clz.ClassFile; +import com.github.HarryHook.coding2017.jvm.constant.MethodRefInfo; +import com.github.HarryHook.coding2017.jvm.loader.ClassFileLoader; +import com.github.HarryHook.coding2017.jvm.method.Method; + +public class MethodArea { + + public static final MethodArea instance = new MethodArea(); + + /** + * 注意:我们做了极大的简化, ClassLoader 只有一个, 实际JVM中的ClassLoader,是一个双亲委托的模型 + */ + + private ClassFileLoader clzLoader = null; + + Map map = new HashMap(); + + private MethodArea() { + } + + public static MethodArea getInstance() { + return instance; + } + + public void setClassFileLoader(ClassFileLoader clzLoader) { + this.clzLoader = clzLoader; + } + + public Method getMainMethod(String className) { + + ClassFile clzFile = this.findClassFile(className); + + return clzFile.getMainMethod(); + } + + public ClassFile findClassFile(String className) { + + if (map.get(className) != null) { + return map.get(className); + } + // 看来该class 文件还没有load过 + ClassFile clzFile = this.clzLoader.loadClass(className); + + map.put(className, clzFile); + + return clzFile; + + } + + public Method getMethod(String className, String methodName, String paramAndReturnType) { + + ClassFile clz = this.findClassFile(className); + + Method m = clz.getMethod(methodName, paramAndReturnType); + + if (m == null) { + + throw new RuntimeException("method can't be found : \n" + "class: " + className + "method: " + methodName + + "paramAndReturnType: " + paramAndReturnType); + } + + return m; + } + + public Method getMethod(MethodRefInfo methodRef) { + + ClassFile clz = this.findClassFile(methodRef.getClassName()); + + Method m = clz.getMethod(methodRef.getMethodName(), methodRef.getParamAndReturnType()); + + if (m == null) { + throw new RuntimeException("method can't be found : " + methodRef.toString()); + } + + return m; + + } +} diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/MiniJVM.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/MiniJVM.java new file mode 100644 index 0000000000..95cc99974e --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/MiniJVM.java @@ -0,0 +1,28 @@ +package com.github.HarryHook.coding2017.jvm.engine; + +import java.io.FileNotFoundException; +import java.io.IOException; + +import com.github.HarryHook.coding2017.jvm.loader.ClassFileLoader; + +public class MiniJVM { + + public void run(String[] classPaths, String className) throws FileNotFoundException, IOException { + + ClassFileLoader loader = new ClassFileLoader(); + for (int i = 0; i < classPaths.length; i++) { + loader.addClassPath(classPaths[i]); + } + + MethodArea methodArea = MethodArea.getInstance(); + + methodArea.setClassFileLoader(loader); + + ExecutorEngine engine = new ExecutorEngine(); + + className = className.replace(".", "/"); + + engine.execute(methodArea.getMainMethod(className)); + } + +} diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/OperandStack.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/OperandStack.java new file mode 100644 index 0000000000..cd468c79f6 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/OperandStack.java @@ -0,0 +1,29 @@ +package com.github.HarryHook.coding2017.jvm.engine; + +import java.util.ArrayList; +import java.util.List; + +public class OperandStack { + private List operands = new ArrayList(); + + public void push(JavaObject jo) { + operands.add(jo); + } + + public JavaObject pop() { + int index = size() - 1; + JavaObject jo = (JavaObject) operands.get(index); + operands.remove(index); + return jo; + + } + + public JavaObject top() { + int index = size() - 1; + return (JavaObject) operands.get(index); + } + + public int size() { + return operands.size(); + } +} diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/StackFrame.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/StackFrame.java new file mode 100644 index 0000000000..8ceee230dd --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/engine/StackFrame.java @@ -0,0 +1,116 @@ +package com.github.HarryHook.coding2017.jvm.engine; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import com.github.HarryHook.coding2017.jvm.cmd.ByteCodeCommand; +import com.github.HarryHook.coding2017.jvm.method.Method; + +public class StackFrame { + + private List localVariableTable = new ArrayList(); + private Stack oprandStack = new Stack(); + + int index = 0; + + private Method m = null; + + private StackFrame callerFrame = null; + + public StackFrame getCallerFrame() { + return callerFrame; + } + + public void setCallerFrame(StackFrame callerFrame) { + this.callerFrame = callerFrame; + } + + public static StackFrame create(Method m) { + + StackFrame frame = new StackFrame(m); + + return frame; + } + + private StackFrame(Method m) { + this.m = m; + + } + + public JavaObject getLocalVariableValue(int index) { + return this.localVariableTable.get(index); + } + + public Stack getOprandStack() { + return this.oprandStack; + } + + public int getNextCommandIndex(int offset) { + + ByteCodeCommand[] cmds = m.getCodeAttr().getCmds(); + for (int i = 0; i < cmds.length; i++) { + if (cmds[i].getOffset() == offset) { + return i; + } + } + throw new RuntimeException("Can't find next command"); + } + + public ExecutionResult execute() { + + ByteCodeCommand[] cmds = m.getCmds(); + + while (index < cmds.length) { + + ExecutionResult result = new ExecutionResult(); + // 缺省值是执行下一条命令 + result.setNextAction(ExecutionResult.RUN_NEXT_CMD); + + System.out.println(cmds[index].toString()); + + cmds[index].execute(this, result); + + if (result.isRunNextCmd()) { + index++; + } else if (result.isExitCurrentFrame()) { + return result; + } else if (result.isPauseAndRunNewFrame()) { + index++; + return result; + } else if (result.isJump()) { + int offset = result.getNextCmdOffset(); + this.index = getNextCommandIndex(offset); + } else { + index++; + } + + } + + // 当前StackFrmae的指令全部执行完毕,可以退出了 + ExecutionResult result = new ExecutionResult(); + result.setNextAction(ExecutionResult.EXIT_CURRENT_FRAME); + return result; + + } + + public void setLocalVariableTable(List values) { + this.localVariableTable = values; + } + + public void setLocalVariableValue(int index, JavaObject jo) { + // 问题: 为什么要这么做?? + if (this.localVariableTable.size() - 1 < index) { + for (int i = this.localVariableTable.size(); i <= index; i++) { + this.localVariableTable.add(null); + } + } + this.localVariableTable.set(index, jo); + + } + + public Method getMethod() { + return m; + } + +} diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/method/Method.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/method/Method.java index 08b8ff029b..344177f549 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/method/Method.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/method/Method.java @@ -4,6 +4,9 @@ import com.github.HarryHook.coding2017.jvm.clz.ClassFile; import com.github.HarryHook.coding2017.jvm.cmd.ByteCodeCommand; +import java.util.ArrayList; +import java.util.List; + import javax.management.RuntimeErrorException; import com.github.HarryHook.coding2017.jvm.attr.AttributeInfo; @@ -54,26 +57,28 @@ public static Method parse(ClassFile clzFile, ByteCodeIterator iter) { int nameIndex = iter.nextU2ToInt(); int descriptorIndex = iter.nextU2ToInt(); int attributeCount = iter.nextU2ToInt(); - + Method m = new Method(clzFile, accessFlag, nameIndex, descriptorIndex); - - for(int i=1; i<=attributeCount; i++) { + + for (int i = 1; i <= attributeCount; i++) { int attrNameIndex = iter.nextU2ToInt(); String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); iter.back(2); - - if(AttributeInfo.CODE.equalsIgnoreCase(attrName)) { + + if (AttributeInfo.CODE.equalsIgnoreCase(attrName)) { CodeAttr codeAttr = CodeAttr.parse(clzFile, iter); m.setCodeAttr(codeAttr); } else { throw new RuntimeException("only Attribute is complemented!"); } - + } return m; } - public String toString(ConstantPool pool) { + + public String toString() { + ConstantPool pool = this.clzFile.getConstantPool(); StringBuffer buffer = new StringBuffer(); String name = ((UTF8Info) pool.getConstantInfo(this.nameIndex)).getValue(); String desc = ((UTF8Info) pool.getConstantInfo(this.descriptorIndex)).getValue(); @@ -81,7 +86,66 @@ public String toString(ConstantPool pool) { buffer.append(this.codeAttr.toString(pool)); return buffer.toString(); } - public ByteCodeCommand[] getCmds() { + + public ByteCodeCommand[] getCmds() { return this.getCodeAttr().getCmds(); -} + } + + private String getParamAndReturnType() { + UTF8Info nameAndTypeInfo = (UTF8Info) this.getClzFile().getConstantPool() + .getConstantInfo(this.getDescriptorIndex()); + return nameAndTypeInfo.getValue(); + } + + public List getParameterList() { + + // e.g. (Ljava/util/List;Ljava/lang/String;II)V + String paramAndType = getParamAndReturnType(); + + int first = paramAndType.indexOf("("); + int last = paramAndType.lastIndexOf(")"); + // e.g. Ljava/util/List;Ljava/lang/String;II + String param = paramAndType.substring(first + 1, last); + + List paramList = new ArrayList(); + + if ((null == param) || "".equals(param)) { + return paramList; + } + + while (!param.equals("")) { + + int pos = 0; + // 这是一个对象类型 + if (param.charAt(pos) == 'L') { + + int end = param.indexOf(";"); + + if (end == -1) { + throw new RuntimeException("can't find the ; for a object type"); + } + paramList.add(param.substring(pos + 1, end)); + + pos = end + 1; + + } else if (param.charAt(pos) == 'I') { + // int + paramList.add("I"); + pos++; + + } else if (param.charAt(pos) == 'F') { + // float + paramList.add("F"); + pos++; + + } else { + throw new RuntimeException("the param has unsupported type:" + param); + } + + param = param.substring(pos); + + } + return paramList; + + } } \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/test/MiniJVMTest.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/test/MiniJVMTest.java new file mode 100644 index 0000000000..d30ddd7c26 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/test/MiniJVMTest.java @@ -0,0 +1,29 @@ +package com.github.HarryHook.coding2017.jvm.test; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.github.HarryHook.coding2017.jvm.engine.MiniJVM;; + +public class MiniJVMTest { + + static final String PATH = "F:\\Coding2017\\group02\\727171008\\bin"; + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testMain() throws Exception { + String[] classPaths = { PATH }; + MiniJVM jvm = new MiniJVM(); + jvm.run(classPaths, "com.github.HarryHook.coding2017.jvm.test.EmployeeV1"); + + } + +} \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/queue/CircleQueue.java b/group02/727171008/src/com/github/HarryHook/coding2017/queue/CircleQueue.java index cd82fb2550..8ab6f440f4 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/queue/CircleQueue.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/queue/CircleQueue.java @@ -1,5 +1,7 @@ package com.github.HarryHook.coding2017.queue; +import java.util.NoSuchElementException; + /** * 用数组实现循环队列 * @@ -16,23 +18,65 @@ public class CircleQueue { // 队头 private int front = 0; - // 队尾 + // 队尾,最后一个有效元素的下一个元素 private int rear = 0; - + // 队内元素个数 + private int size = 0; public boolean isEmpty() { + if(rear == front) { //但不一定为0 + return true; + } return false; } - public int size() { - return -1; + public int size() { + return size; } public void enQueue(E data) { + if((rear + 1) % DEFAULT_SIZE != front) { //队列未满 + elementData[rear] = data; + rear = (rear + 1) % DEFAULT_SIZE; + size++; + } } public E deQueue() { - return null; + if (isEmpty()) { + throw new NoSuchElementException("Queue underflow"); + } + E data = (E) elementData[front]; + front = (front + 1) % DEFAULT_SIZE; + size--; + return data; + } + public static void main(String[] args) { + CircleQueue queue = new CircleQueue<>(); + queue.enQueue(1); + queue.enQueue(1); + queue.enQueue(2); + queue.enQueue(3); + queue.enQueue(1); + queue.enQueue(1); + queue.enQueue(2); + queue.enQueue(3); + queue.enQueue(1); + queue.enQueue(1); + queue.enQueue(2); + queue.enQueue(3); + System.out.println("queue.deQueue()= " + queue.deQueue()); + System.out.println("queue.deQueue()= " + queue.deQueue()); + System.out.println("queue.deQueue()= " + queue.deQueue()); + System.out.println("queue.deQueue()= " + queue.deQueue()); + System.out.println("queue.size= " + queue.size()); + queue.enQueue(3); + queue.enQueue(3); + queue.enQueue(1); + queue.enQueue(1); + queue.enQueue(2); + System.out.println("queue.rear= " + queue.rear); + System.out.println("queue.front= " + queue.front); } } diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/queue/Josephus.java b/group02/727171008/src/com/github/HarryHook/coding2017/queue/Josephus.java index 7b5fe53f5e..b919fbe94c 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/queue/Josephus.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/queue/Josephus.java @@ -1,7 +1,10 @@ package com.github.HarryHook.coding2017.queue; +import java.util.ArrayList; import java.util.List; +import com.sun.corba.se.spi.orb.StringPair; + /** * 用Queue来实现Josephus问题 在这个古老的问题当中, N个深陷绝境的人一致同意用这种方式减少生存人数: N个人围成一圈(位置记为0到N-1), * 并且从第一个人报数, 报到M的人会被杀死, 直到最后一个人留下来 该方法返回一个List, 包含了被杀死人的次序 @@ -12,7 +15,28 @@ public class Josephus { public static List execute(int n, int m) { - return null; + Queue queue = new Queue<>(); + List list = new ArrayList<>(); + + for (int i = 0; i < n; i++) { + queue.enQueue(i); + } + int i = 0; + while (!(queue.isEmpty())) { + int j = queue.deQueue(); + if (++i % m == 0) { + list.add(j); + } else { + queue.enQueue(j); + } + } + return list; + } + + public static void main(String[] args) { + Josephus circle = new Josephus(); + List list = circle.execute(41, 3); + System.out.println(list); } } diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/queue/QueueWithTwoStacks.java b/group02/727171008/src/com/github/HarryHook/coding2017/queue/QueueWithTwoStacks.java index c72abadcd2..494ad7452e 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/queue/QueueWithTwoStacks.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/queue/QueueWithTwoStacks.java @@ -14,24 +14,55 @@ public class QueueWithTwoStacks { private Stack stack2; public QueueWithTwoStacks() { - stack1 = new Stack(); - stack2 = new Stack(); + stack1 = new Stack(); // 入队 + stack2 = new Stack(); // 出队 } public boolean isEmpty() { + if (stack1.isEmpty() && stack2.isEmpty()) { + return true; + } return false; } public int size() { - return -1; + return stack1.size() + stack2.size(); } public void enQueue(E item) { + stack1.push(item); } public E deQueue() { - return null; + + if (isEmpty()) { + throw new RuntimeException("queue is empty"); + } + + while (!(stack1.isEmpty())) { + stack2.push(stack1.pop()); + } + E popItem = stack2.pop(); + while (!(stack2.isEmpty())) { + stack1.push(stack2.pop()); + } + + return popItem; + } + + public static void main(String[] args) { + QueueWithTwoStacks stackQueue = new QueueWithTwoStacks<>(); + stackQueue.enQueue(5); + stackQueue.enQueue(36); + stackQueue.enQueue(1); + stackQueue.enQueue(2); + stackQueue.deQueue(); + stackQueue.enQueue(3); + while (!(stackQueue.isEmpty())) { + System.out.println(stackQueue.deQueue()); + } + } } diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/stack/QuickMinStack.java b/group02/727171008/src/com/github/HarryHook/coding2017/stack/QuickMinStack.java new file mode 100644 index 0000000000..70f1d03903 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/stack/QuickMinStack.java @@ -0,0 +1,64 @@ +package com.github.HarryHook.coding2017.stack; + +import java.util.Stack; + +/** + * 设计一个栈,支持栈的push和pop操作,以及第三种操作findMin, 它返回改数据结构中的最小元素 + * finMin操作最坏的情形下时间复杂度应该是O(1) , 简单来讲,操作一次就可以得到最小值 + * + * @author HarryHook + * + */ +public class QuickMinStack { + Stack s1 = new Stack<>(); + Stack s2 = new Stack<>(); + + public void push(int data) { + + s1.push(data); + + if (s2.isEmpty()) { + s2.push(data); + } else if (data > s2.peek()) { + s2.push(s2.peek()); + } else { + s2.push(data); + } + + } + + public int pop() { + if (s1.isEmpty()) { + throw new RuntimeException("stack is empty"); + } + s2.pop(); + return s1.pop(); + } + + public int findMin() { + if (s2.isEmpty()) { + throw new RuntimeException("stack is empty"); + } + return s2.peek(); + } + + public static void main(String[] args) { + QuickMinStack stack = new QuickMinStack(); + stack.push(5); + stack.push(3); + stack.push(2); + stack.push(4); + stack.push(1); + System.out.println("findMin: " + stack.findMin()); + System.out.println("pop: " + stack.pop()); + System.out.println("findMin: " + stack.findMin()); + System.out.println("pop: " + stack.pop()); + System.out.println("findMin: " + stack.findMin()); + System.out.println("pop: " + stack.pop()); + System.out.println("findMin: " + stack.findMin()); + System.out.println("pop: " + stack.pop()); + System.out.println("findMin: " + stack.findMin()); + System.out.println("pop: " + stack.pop()); + System.out.println("findMin: " + stack.findMin()); + } +} diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/stack/StackWithTwoQueues.java b/group02/727171008/src/com/github/HarryHook/coding2017/stack/StackWithTwoQueues.java new file mode 100644 index 0000000000..14e109e53e --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/stack/StackWithTwoQueues.java @@ -0,0 +1,58 @@ +package com.github.HarryHook.coding2017.stack; + +import com.github.HarryHook.coding2017.queue.Queue; + +public class StackWithTwoQueues { + private Queue queue1; + private Queue queue2; + + public StackWithTwoQueues() { + queue1 = new Queue<>(); // 入栈 + queue2 = new Queue<>(); // 出栈 + } + + public boolean isEmpty() { + if (queue1.isEmpty() && queue2.isEmpty()) { + return true; + } + return false; + } + + public int size() { + return queue1.size() + queue2.size(); + } + + public void push(int data) { + queue1.enQueue(data); + } + + public int pop() { + if (isEmpty()) { + throw new RuntimeException("stack is empty"); + } + while(!(queue1.isEmpty())) { + queue2.enQueue(queue1.deQueue()); + } + int tmp = 0; + while(!(queue2.isEmpty())) { + tmp = queue2.deQueue(); + if(queue2.isEmpty()) { + break; + } + queue1.enQueue(tmp); + } + return tmp; + } + public static void main(String[] args) { + StackWithTwoQueues stack = new StackWithTwoQueues(); + stack.push(1); + stack.push(2); + stack.push(3); + System.out.println(stack.pop()); + stack.push(43); + System.out.println(stack.pop()); + System.out.println(stack.pop()); + System.out.println(stack.pop()); + } + +} diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/stack/TwoStackInOneArray.java b/group02/727171008/src/com/github/HarryHook/coding2017/stack/TwoStackInOneArray.java new file mode 100644 index 0000000000..0829b5b34c --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/stack/TwoStackInOneArray.java @@ -0,0 +1,150 @@ +package com.github.HarryHook.coding2017.stack; + +import java.util.Arrays; + +/** + * 用一个数组实现两个栈 将数组的起始位置看作是第一个栈的栈底,将数组的尾部看作第二个栈的栈底,压栈时,栈顶指针分别向中间移动,直到两栈顶指针相遇,则扩容。 + * + * @author HarryHook + * + */ +public class TwoStackInOneArray { + Object[] data = new Object[6]; + int i = 0; + int j = data.length - 1; + + /** + * 向第一个栈中压入元素 + * + * @param o + */ + public void push1(Object o) { + if (i > j) { + expansion(); + } + data[i++] = o; + + } + + /** + * 从第一个栈中弹出元素 + * + * @return + */ + public Object pop1() { + if (data[0] == null) { + throw new RuntimeException("stack1 is empty"); + } + Object tmp = data[i - 1]; + data[--i] = null; + return tmp; + } + + /** + * 获取第一个栈的栈顶元素 + * + * @return + */ + + public Object peek1() { + return data[i - 1]; + } + + /* + * 向第二个栈压入元素 + */ + public void push2(Object o) { + if (i > j) { + expansion(); + } + data[j--] = o; + + } + + /** + * 从第二个栈弹出元素 + * + * @return + */ + public Object pop2() { + if (data[data.length - 1] == null) { + throw new RuntimeException("stack2 is empty"); + } + Object tmp = data[j + 1]; + data[++j] = null; + return tmp; + + } + + /** + * 获取第二个栈的栈顶元素 + * + * @return + */ + + public Object peek2() { + return data[j + 1]; + } + + // 给数组扩容 + public void expansion() { + int oldCapacity = data.length; + int newCapacity = oldCapacity * 2; // 此时扩容是因为数组有可能全是stack2的元素 + data = Arrays.copyOf(data, newCapacity); + int newIndex = newCapacity - 1; + for (int k = oldCapacity - 1; k > j; k--) { + data[newIndex--] = data[k]; + data[k] = null; + } + j += newCapacity - oldCapacity; + } + + public static void main(String[] args) { + TwoStackInOneArray stack = new TwoStackInOneArray(); + + stack.push1(3); + stack.push1(5); + stack.push1(6); + stack.push1(11); + System.out.println("peek1: " + stack.peek1()); + System.out.println("pop1: " + stack.pop1()); + System.out.println("pop1: " + stack.pop1()); + stack.push1(61); + System.out.println("pop1: " + stack.pop1()); + System.out.println("pop1: " + stack.pop1()); + System.out.println("peek1: " + stack.peek1()); + System.out.println("pop1: " + stack.pop1()); + + stack.push2(123); + stack.push2(1); + stack.push2(4); + + stack.push1(3); + stack.push1(5); + stack.push1(6); + + stack.push2(123); + stack.push2(1); + stack.push2(4); + stack.push2(12); + stack.push2(2); + stack.push2(8); + System.out.println("pop1: " + stack.pop1()); + System.out.println("peek1: " + stack.peek1()); + System.out.println("pop1: " + stack.pop1()); + System.out.println("pop1: " + stack.pop1()); + + System.out.println("pop2: " + stack.pop2()); + System.out.println("pop2: " + stack.pop2()); + System.out.println("pop2: " + stack.pop2()); + System.out.println("pop2: " + stack.pop2()); + System.out.println("pop2: " + stack.pop2()); + System.out.println("pop2: " + stack.pop2()); + + System.out.println("pop2: " + stack.pop2()); + System.out.println("pop2: " + stack.pop2()); + System.out.println("pop2: " + stack.pop2()); + + } + +}