From cb3fb6fa582deb24c954036d0e57be3a32466154 Mon Sep 17 00:00:00 2001 From: Harry Date: Sun, 16 Apr 2017 22:37:36 +0800 Subject: [PATCH 1/2] add jvm_3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 解析属性表,方法表和Code属性以及LineNumberTable和LocalVarialTable --- .../coding2017/jvm/attr/AttributeInfo.java | 19 ++++ .../coding2017/jvm/attr/CodeAttr.java | 100 ++++++++++++++++++ .../coding2017/jvm/attr/LineNumberTable.java | 57 ++++++++++ .../jvm/attr/LocalVariableItem.java | 49 +++++++++ .../jvm/attr/LocalVariableTable.java | 40 +++++++ .../coding2017/jvm/attr/StackMapTable.java | 29 +++++ .../coding2017/jvm/clz/ClassFile.java | 26 ++++- .../coding2017/jvm/constant/ConstantInfo.java | 3 + .../coding2017/jvm/constant/UTF8Info.java | 7 +- .../HarryHook/coding2017/jvm/field/Field.java | 44 ++++++++ .../jvm/loader/ByteCodeIterator.java | 33 ++++-- .../jvm/loader/ClassFileParser.java | 36 +++++++ .../coding2017/jvm/method/Method.java | 83 +++++++++++++++ .../jvm/test/ClassFileloaderTest.java | 84 ++++++++++++++- 14 files changed, 595 insertions(+), 15 deletions(-) create mode 100644 group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/AttributeInfo.java create mode 100644 group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/CodeAttr.java create mode 100644 group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/LineNumberTable.java create mode 100644 group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/LocalVariableItem.java create mode 100644 group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/LocalVariableTable.java create mode 100644 group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/StackMapTable.java create mode 100644 group02/727171008/src/com/github/HarryHook/coding2017/jvm/field/Field.java create mode 100644 group02/727171008/src/com/github/HarryHook/coding2017/jvm/method/Method.java diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/AttributeInfo.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..33b7dda5c6 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package com.github.HarryHook.coding2017.jvm.attr; + +public abstract class AttributeInfo { + public static final String CODE = "Code"; + public static final String CONST_VALUE = "ConstantValue"; + public static final String EXCEPTIONS = "Exceptions"; + public static final String LINE_NUM_TABLE = "LineNumberTable"; + public static final String LOCAL_VAR_TABLE = "LocalVariableTable"; + public static final String STACK_MAP_TABLE = "StackMapTable"; + int attrNameIndex; + int attrLen; + + public AttributeInfo(int attrNameIndex, int attrLen) { + + this.attrNameIndex = attrNameIndex; + this.attrLen = attrLen; + } + +} \ No newline at end of file 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 new file mode 100644 index 0000000000..47a8bd2b1c --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/CodeAttr.java @@ -0,0 +1,100 @@ +package com.github.HarryHook.coding2017.jvm.attr; + +import com.github.HarryHook.coding2017.jvm.clz.ClassFile; +import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; +import com.github.HarryHook.coding2017.jvm.loader.ByteCodeIterator; +import com.sun.org.apache.bcel.internal.generic.NEW; + +public class CodeAttr extends AttributeInfo { + private int maxStack; + private int maxLocals; + private int codeLen; + private String code; + + public String getCode() { + return code; + } + + // private ByteCodeCommand[] cmds ; + // public ByteCodeCommand[] getCmds() { + // return cmds; + // } + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public CodeAttr(int attrNameIndex, int attrLen, int maxStack, int maxLocals, int codeLen, + String code /* ByteCodeCommand[] cmds */) { + super(attrNameIndex, attrLen); + this.maxStack = maxStack; + this.maxLocals = maxLocals; + this.codeLen = codeLen; + this.code = code; + // this.cmds = cmds; + } + + public void setLineNumberTable(LineNumberTable t) { + this.lineNumTable = t; + } + + public void setLocalVariableTable(LocalVariableTable t) { + this.localVarTable = t; + } + + public static CodeAttr parse(ClassFile clzFile, ByteCodeIterator iter) { + + int attrNameIndex = iter.nextU2ToInt(); + int attrLen = iter.nextU4ToInt(); + int maxStack = iter.nextU2ToInt(); + int maxLocals = iter.nextU2ToInt(); + int codeLen = iter.nextU4ToInt(); + + String code = iter.nextUxToHexString(codeLen); + System.out.println(code); + + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, code); + + int exceptionLength = iter.nextU2ToInt(); + if(exceptionLength > 0) { + String exceptionTable = iter.nextUxToHexString(exceptionLength); + System.out.println("exception Table has not complemented" + exceptionTable); + } + //解析子属性 + int subAttrCount = iter.nextU2ToInt(); + + for(int j=1; j<=subAttrCount; j++) { + + int subAttrIndex = iter.nextU2ToInt(); + String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrIndex); + iter.back(2); + + if(AttributeInfo.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)) { + LineNumberTable t = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(t); + + } else if(AttributeInfo.LOCAL_VAR_TABLE.equals(subAttrName)) { + LocalVariableTable t = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(t); + + } else { + throw new RuntimeException("Need implement" + subAttrName); + } + } + return codeAttr; + } + + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + public String toString(ConstantPool pool) { + StringBuffer buffer = new StringBuffer(); + buffer.append("Code:").append(code).append("\n"); + buffer.append("\n"); + buffer.append(this.lineNumTable.toString()); + //buffer.append(this.localVarTable.toString(pool)); + return buffer.toString(); + } + + +} \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/LineNumberTable.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..51933e9bb6 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/LineNumberTable.java @@ -0,0 +1,57 @@ +package com.github.HarryHook.coding2017.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + +import com.github.HarryHook.coding2017.jvm.loader.ByteCodeIterator; + +public class LineNumberTable extends AttributeInfo { + List items = new ArrayList(); + + private static class LineNumberItem { + int startPC; + int lineNum; + + public int getStartPC() { + return startPC; + } + + public void setStartPC(int startPC) { + this.startPC = startPC; + } + + public int getLineNum() { + return lineNum; + } + + public void setLineNum(int lineNum) { + this.lineNum = lineNum; + } + } + + public void addLineNumberItem(LineNumberItem item) { + this.items.add(item); + } + + public LineNumberTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + + } + + public static LineNumberTable parse(ByteCodeIterator iter) { + int attrNameIndex = iter.nextU2ToInt(); + int attrLength = iter.nextU4ToInt(); + LineNumberTable table = new LineNumberTable(attrNameIndex, attrLength); + int itemLength = iter.nextU2ToInt(); + + for(int i=1; i<=itemLength; i++) { + LineNumberItem item = new LineNumberItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLineNum(iter.nextU2ToInt()); + table.addLineNumberItem(item); + } + + return table; + } + +} \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/LocalVariableItem.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..f442ea5698 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/LocalVariableItem.java @@ -0,0 +1,49 @@ +package com.github.HarryHook.coding2017.jvm.attr; + +public class LocalVariableItem { + private int startPC; + private int length; + private int nameIndex; + private int descIndex; + private int index; + + public int getStartPC() { + return startPC; + } + + public void setStartPC(int startPC) { + this.startPC = startPC; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public int getNameIndex() { + return nameIndex; + } + + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + + public int getDescIndex() { + return descIndex; + } + + public void setDescIndex(int descIndex) { + this.descIndex = descIndex; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } +} \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/LocalVariableTable.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..f9d5d0bdce --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/LocalVariableTable.java @@ -0,0 +1,40 @@ +package com.github.HarryHook.coding2017.jvm.attr; + +import java.util.ArrayList; +import java.util.List; +import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; +import com.github.HarryHook.coding2017.jvm.loader.ByteCodeIterator; + +import sun.util.logging.resources.logging; + +public class LocalVariableTable extends AttributeInfo { + + List items = new ArrayList(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static LocalVariableTable parse(ByteCodeIterator iter) { + int attrNameIndex = iter.nextU2ToInt(); + int attrlength = iter.nextU4ToInt(); + + LocalVariableTable table = new LocalVariableTable(attrNameIndex, attrlength); + int itemLength = iter.nextU2ToInt(); + for (int i = 1; i <= itemLength; i++) { + LocalVariableItem item = new LocalVariableItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLength(iter.nextU2ToInt()); + item.setNameIndex(iter.nextU2ToInt()); + item.setDescIndex(iter.nextU2ToInt()); + item.setIndex(iter.nextU2ToInt()); + table.addLocalVariableItem(item); + } + return table; + } + + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + +} \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/StackMapTable.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..745a2fdc70 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/attr/StackMapTable.java @@ -0,0 +1,29 @@ +package com.github.HarryHook.coding2017.jvm.attr; + +import com.github.HarryHook.coding2017.jvm.loader.ByteCodeIterator; + +public class StackMapTable extends AttributeInfo { + + private String originalCode; + + public StackMapTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + public static StackMapTable parse(ByteCodeIterator iter) { + int index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + StackMapTable t = new StackMapTable(index, len); + + // 后面的StackMapTable太过复杂, 不再处理, 只把原始的代码读进来保存 + String code = iter.nextUxToHexString(len); + t.setOriginalCode(code); + + return t; + } + + private void setOriginalCode(String code) { + this.originalCode = code; + + } +} \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/clz/ClassFile.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/clz/ClassFile.java index 9754e904e4..45e7464e9f 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/clz/ClassFile.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/clz/ClassFile.java @@ -1,7 +1,13 @@ package com.github.HarryHook.coding2017.jvm.clz; + +import java.util.ArrayList; +import java.util.List; + import com.github.HarryHook.coding2017.jvm.constant.ClassInfo; import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; +import com.github.HarryHook.coding2017.jvm.field.Field; +import com.github.HarryHook.coding2017.jvm.method.Method; public class ClassFile { @@ -11,6 +17,8 @@ public class ClassFile { private AccessFlag accessFlag; private ClassIndex clzIndex; private ConstantPool pool; + private List fields = new ArrayList(); + private List methods = new ArrayList();; public ClassIndex getClzIndex() { return clzIndex; @@ -48,7 +56,6 @@ public void setMajorVersion(int majorVersion) { public void setConstantPool(ConstantPool pool) { this.pool = pool; - } public void setClassIndex(ClassIndex clzIndex) { @@ -75,5 +82,22 @@ private String getSuperClassName() { ClassInfo superClass = (ClassInfo) this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); return superClass.getClassName(); } + + public void addField(Field f) { + fields.add(f); + } + + public List getFields() { + return fields; + } + + public void addMethod(Method m) { + methods.add(m); + + } + public List getMethods() { + return methods; + } + } \ No newline at end of file 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 3cf807a716..3d81ed1adb 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,5 +27,8 @@ public ConstantPool getConstantPool() { public ConstantInfo getConstantInfo(int index) { return this.constantPool.getConstantInfo(index); } + + + } \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/constant/UTF8Info.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/constant/UTF8Info.java index e787b42ed2..27c2ec9059 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/constant/UTF8Info.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/constant/UTF8Info.java @@ -26,12 +26,11 @@ public String toString() { return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value + ")]"; } - public String getValue() { - return value; - } - public void setValue(String value) { this.value = value; } + public String getValue(){ + return value; + } } \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/field/Field.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/field/Field.java new file mode 100644 index 0000000000..9d33d90d96 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/field/Field.java @@ -0,0 +1,44 @@ + +package com.github.HarryHook.coding2017.jvm.field; + +import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; +import com.github.HarryHook.coding2017.jvm.loader.ByteCodeIterator; +import com.sun.istack.internal.Pool; +import com.github.HarryHook.coding2017.jvm.constant.UTF8Info; + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private ConstantPool pool; + + public Field(int accessFlag, int nameIndex, int descriptorIndex, ConstantPool pool) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.pool = pool; + } + + public static Field parse(ConstantPool pool, ByteCodeIterator iter) { + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descriptorIndex = iter.nextU2ToInt(); + int attributesCount = iter.nextU2ToInt(); + System.out.println("field attributes Count: " + attributesCount); + Field f = new Field(accessFlag, nameIndex, descriptorIndex, pool); + if(attributesCount > 0) { + throw new RuntimeException("Field has not complemented attribute"); + } + return f; + } + + public String toString() { + String name = ((UTF8Info) pool.getConstantInfo(this.nameIndex)).getValue(); + String desc = ((UTF8Info) pool.getConstantInfo(this.descriptorIndex)).getValue(); + return name +":" + desc; + } + + +} \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/loader/ByteCodeIterator.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/loader/ByteCodeIterator.java index a65cd6f3d8..b773b6b584 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/loader/ByteCodeIterator.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/loader/ByteCodeIterator.java @@ -7,9 +7,11 @@ public class ByteCodeIterator { byte[] codes; int pos = 0; + public ByteCodeIterator(byte[] codes) { this.codes = codes; } + public byte[] getByte(int len) { if (pos + len > codes.length) { throw new ArrayIndexOutOfBoundsException(); @@ -18,22 +20,39 @@ public byte[] getByte(int len) { pos += len; return data; } + public String nextU4ToHexString() { - - return Util.byteToHexString(new byte[] {codes[pos++], codes[pos++], codes[pos++], codes[pos++]}); + + return Util.byteToHexString(new byte[] { codes[pos++], codes[pos++], codes[pos++], codes[pos++] }); } - + public int nextU1ToInt() { - + return Util.byteToInt(new byte[] { codes[pos++] }); } + public int nextU2ToInt() { - - return Util.byteToInt(new byte[] { codes[pos++], codes[pos++]}); + + return Util.byteToInt(new byte[] { codes[pos++], codes[pos++] }); } + public int nextU4ToInt() { - + return Util.byteToInt(new byte[] { codes[pos++], codes[pos++], codes[pos++], codes[pos++] }); } + public String nextUxToHexString(int len) { + byte[] tmp = new byte[len]; + + for (int i = 0; i < len; i++) { + tmp[i] = codes[pos++]; + } + return Util.byteToHexString(tmp).toLowerCase(); + + } + + public void back(int n) { + this.pos -= n; + } + } diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/loader/ClassFileParser.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/loader/ClassFileParser.java index 4a7cc6bd04..40608823e9 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/loader/ClassFileParser.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/loader/ClassFileParser.java @@ -2,6 +2,7 @@ import java.io.UnsupportedEncodingException; + import com.github.HarryHook.coding2017.jvm.clz.AccessFlag; import com.github.HarryHook.coding2017.jvm.clz.ClassFile; import com.github.HarryHook.coding2017.jvm.clz.ClassIndex; @@ -13,6 +14,8 @@ import com.github.HarryHook.coding2017.jvm.constant.NullConstantInfo; import com.github.HarryHook.coding2017.jvm.constant.StringInfo; import com.github.HarryHook.coding2017.jvm.constant.UTF8Info; +import com.github.HarryHook.coding2017.jvm.field.Field; +import com.github.HarryHook.coding2017.jvm.method.Method; public class ClassFileParser { @@ -37,15 +40,22 @@ public ClassFile parse(byte[] codes) { ClassIndex clzIndex = parseClassIndex(iter); clzFile.setClzIndex(clzIndex); + parseInterfaces(iter); + + parseField(clzFile, iter); + + parseMethod(clzFile, iter); return clzFile; } private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + AccessFlag flag = new AccessFlag(iter.nextU2ToInt()); return flag; } private ClassIndex parseClassIndex(ByteCodeIterator iter) { + int thisClassIndex = iter.nextU2ToInt(); int superClassIndex = iter.nextU2ToInt(); ClassIndex clzIndex = new ClassIndex(); @@ -109,7 +119,33 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { } System.out.println("Finished reading Constant Pool "); + return pool; } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextU2ToInt(); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + + private void parseField(ClassFile clzFile, ByteCodeIterator iter){ + int fieldCount = iter.nextU2ToInt(); + for(int i=1; i<=fieldCount; i++) { + Field f = Field.parse(clzFile.getConstantPool(), iter); + clzFile.addField(f); + + } + } + + private void parseMethod(ClassFile clzFile, ByteCodeIterator iter){ + int methodCount = iter.nextU2ToInt(); + for(int i=1; i<=methodCount; i++) { + Method m = Method.parse(clzFile, iter); + clzFile.addMethod(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 new file mode 100644 index 0000000000..d7dedc0439 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/method/Method.java @@ -0,0 +1,83 @@ + +package com.github.HarryHook.coding2017.jvm.method; + +import com.github.HarryHook.coding2017.jvm.clz.ClassFile; + +import javax.management.RuntimeErrorException; + +import com.github.HarryHook.coding2017.jvm.attr.AttributeInfo; +import com.github.HarryHook.coding2017.jvm.attr.CodeAttr; +import com.github.HarryHook.coding2017.jvm.constant.ConstantPool; +import com.github.HarryHook.coding2017.jvm.constant.UTF8Info; +import com.github.HarryHook.coding2017.jvm.loader.ByteCodeIterator; + +public class Method { + + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + + private CodeAttr codeAttr; + + private ClassFile clzFile; + + public ClassFile getClzFile() { + return clzFile; + } + + public int getNameIndex() { + return nameIndex; + } + + public int getDescriptorIndex() { + return descriptorIndex; + } + + public CodeAttr getCodeAttr() { + return codeAttr; + } + + public void setCodeAttr(CodeAttr code) { + this.codeAttr = code; + } + + public Method(ClassFile clzFile, int accessFlag, int nameIndex, int descriptorIndex) { + this.clzFile = clzFile; + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + } + + public static Method parse(ClassFile clzFile, ByteCodeIterator iter) { + int accessFlag = iter.nextU2ToInt(); + 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++) { + int attrNameIndex = iter.nextU2ToInt(); + String attrName = clzFile.getConstantPool().getUTF8String(attrNameIndex); + iter.back(2); + + 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) { + StringBuffer buffer = new StringBuffer(); + String name = ((UTF8Info) pool.getConstantInfo(this.nameIndex)).getValue(); + String desc = ((UTF8Info) pool.getConstantInfo(this.descriptorIndex)).getValue(); + buffer.append(name); + buffer.append(desc); + return buffer.toString(); + } +} \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/test/ClassFileloaderTest.java b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/test/ClassFileloaderTest.java index 1f6a3a9a50..524907ce9f 100644 --- a/group02/727171008/src/com/github/HarryHook/coding2017/jvm/test/ClassFileloaderTest.java +++ b/group02/727171008/src/com/github/HarryHook/coding2017/jvm/test/ClassFileloaderTest.java @@ -1,5 +1,7 @@ package com.github.HarryHook.coding2017.jvm.test; +import java.util.List; + import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -12,7 +14,10 @@ import com.github.HarryHook.coding2017.jvm.constant.MethodRefInfo; import com.github.HarryHook.coding2017.jvm.constant.NameAndTypeInfo; import com.github.HarryHook.coding2017.jvm.constant.UTF8Info; +import com.github.HarryHook.coding2017.jvm.field.Field; import com.github.HarryHook.coding2017.jvm.loader.ClassFileLoader; +import com.github.HarryHook.coding2017.jvm.method.Method; + public class ClassFileloaderTest { @@ -166,8 +171,8 @@ public void testConstantPool() { } { - // UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); - // Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); } } @@ -181,5 +186,78 @@ public void testClassIndex() { Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, thisClassInfo.getClassName()); Assert.assertEquals("java/lang/Object", superClassInfo.getClassName()); } - + /** + * 下面是第三次JVM课应实现的测试用例 + */ + + @Test + public void testReadFields(){ + + List fields = clzFile.getFields(); + Assert.assertEquals(2, fields.size()); + { + Field f = fields.get(0); + Assert.assertEquals("name:Ljava/lang/String;", f.toString()); + } + { + Field f = fields.get(1); + Assert.assertEquals("age:I", f.toString()); + } + } + + @Test + public void testMethods(){ + + List methods = clzFile.getMethods(); + ConstantPool pool = clzFile.getConstantPool(); + + { + Method m = methods.get(0); + assertMethodEquals(pool,m, + "", + "(Ljava/lang/String;I)V", + "2ab7000c2a2bb5000f2a1cb50011b1"); + + } + { + Method m = methods.get(1); + assertMethodEquals(pool,m, + "setName", + "(Ljava/lang/String;)V", + "2a2bb5000fb1"); + + } + { + Method m = methods.get(2); + assertMethodEquals(pool,m, + "setAge", + "(I)V", + "2a1bb50011b1"); + } + { + Method m = methods.get(3); + assertMethodEquals(pool,m, + "sayHello", + "()V", + "b2001c1222b60024b1"); + + } + { + Method m = methods.get(4); + assertMethodEquals(pool,m, + "main", + "([Ljava/lang/String;)V", + "bb000159122b101db7002d4c2bb6002fb1"); + } + } + + private void assertMethodEquals(ConstantPool pool,Method m , String expectedName, String expectedDesc,String expectedCode){ + String methodName = pool.getUTF8String(m.getNameIndex()); + String methodDesc = pool.getUTF8String(m.getDescriptorIndex()); + String code = m.getCodeAttr().getCode(); + Assert.assertEquals(expectedName, methodName); + Assert.assertEquals(expectedDesc, methodDesc); + Assert.assertEquals(expectedCode, code); + } + } From ba473c003d29cbe7962c217af3b99772097033e3 Mon Sep 17 00:00:00 2001 From: Harry Date: Sun, 16 Apr 2017 22:38:02 +0800 Subject: [PATCH 2/2] add InfixExpr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实现中序表达式求值 --- .../coding2017/stack/expr/InfixExpr.java | 107 ++++++++++++++++++ .../coding2017/stack/expr/InfixExprTest.java | 47 ++++++++ 2 files changed, 154 insertions(+) create mode 100644 group02/727171008/src/com/github/HarryHook/coding2017/stack/expr/InfixExpr.java create mode 100644 group02/727171008/src/com/github/HarryHook/coding2017/stack/expr/InfixExprTest.java diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/stack/expr/InfixExpr.java b/group02/727171008/src/com/github/HarryHook/coding2017/stack/expr/InfixExpr.java new file mode 100644 index 0000000000..5b1dbd7fa4 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/stack/expr/InfixExpr.java @@ -0,0 +1,107 @@ +package com.github.HarryHook.coding2017.stack.expr; + +import com.github.HarryHook.coding2017.basic.MyStack; + +public class InfixExpr { + + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + char[] ch = expr.toCharArray(); + MyStack stackOfTocken = new MyStack(); + MyStack stackOfNumber = new MyStack(); + + for (int i = 0; i < ch.length; i++) { + + if (Character.isDigit(ch[i])) { + int tmp = Integer.parseInt("" + ch[i]); + while (i < ch.length - 1 && Character.isDigit(ch[++i])) { + tmp = tmp * 10 + Integer.parseInt("" + ch[i]); + } + + stackOfNumber.push(tmp); + + } + if (ch[i] == '+' || ch[i] == '-' || ch[i] == '*' || ch[i] == '/') { + stackOfTocken.push(ch[i]); + } + + if (!(stackOfTocken.isEmpty()) && (char) stackOfTocken.peek() == '*') { + int tmp = Integer.parseInt("" + ch[++i]); + while (i < ch.length - 1 && Character.isDigit(ch[++i])) { + tmp = tmp * 10 + Integer.parseInt("" + ch[i]); + } + if (i != ch.length - 1) { + i--; + } + stackOfNumber.push(tmp); + + int tmp1 = Integer.parseInt("" + stackOfNumber.pop()); + int tmp2 = Integer.parseInt("" + stackOfNumber.pop()); + stackOfNumber.push(tmp1 * tmp2); + stackOfTocken.pop(); + + } + if (!(stackOfTocken.isEmpty()) && (char) stackOfTocken.peek() == '/') { + int tmp = Integer.parseInt("" + ch[++i]); + while (i < ch.length - 1 && Character.isDigit(ch[++i])) { + tmp = tmp * 10 + Integer.parseInt("" + ch[i]); + } + if (i != ch.length - 1) { + i--; + } + stackOfNumber.push(tmp); + + int tmp1 = Integer.parseInt("" + stackOfNumber.pop()); + int tmp2 = Integer.parseInt("" + stackOfNumber.pop()); + stackOfNumber.push(tmp2 / tmp1); + stackOfTocken.pop(); + } + } + // 将栈中的数字和运算法逆置,便于计算 + reverse(stackOfNumber); + reverse(stackOfTocken); + + while (!(stackOfTocken.isEmpty())) { + if ((char) stackOfTocken.peek() == '+') { + int tmp1 = Integer.parseInt("" + stackOfNumber.pop()); + int tmp2 = Integer.parseInt("" + stackOfNumber.pop()); + stackOfNumber.push(tmp1 + tmp2); + } + + if ((char) stackOfTocken.peek() == '-') { + int tmp1 = Integer.parseInt("" + stackOfNumber.pop()); + int tmp2 = Integer.parseInt("" + stackOfNumber.pop()); + stackOfNumber.push(tmp1 - tmp2); + } + stackOfTocken.pop(); + } + + return Float.parseFloat("" + stackOfNumber.pop()); + } + + private void reverse(MyStack s) { + + if (s.isEmpty()) { + return; + } + // 如果s里面只有一个元素,就返回。具体实现是先pop出来一个,判断剩下的是不是空栈。 + Object tmp1 = s.pop(); + reverse(s); + if (s.isEmpty()) { + s.push(tmp1); + return; + } + Object temp2 = s.pop(); + reverse(s); + s.push(tmp1); + reverse(s); + s.push(temp2); + + } +} \ No newline at end of file diff --git a/group02/727171008/src/com/github/HarryHook/coding2017/stack/expr/InfixExprTest.java b/group02/727171008/src/com/github/HarryHook/coding2017/stack/expr/InfixExprTest.java new file mode 100644 index 0000000000..4abd227502 --- /dev/null +++ b/group02/727171008/src/com/github/HarryHook/coding2017/stack/expr/InfixExprTest.java @@ -0,0 +1,47 @@ +package com.github.HarryHook.coding2017.stack.expr; + +import org.junit.Assert; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + // InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + } + +}