diff --git a/group02/562768642/src/com/github/orajavac/coding2017/basic/linklist/LRUPageFrame.java b/group02/562768642/src/com/github/orajavac/coding2017/basic/linklist/LRUPageFrame.java index 56b94881b4..482157d08c 100644 --- a/group02/562768642/src/com/github/orajavac/coding2017/basic/linklist/LRUPageFrame.java +++ b/group02/562768642/src/com/github/orajavac/coding2017/basic/linklist/LRUPageFrame.java @@ -18,12 +18,19 @@ private static class Node { private Node first;// 链表头 private Node last;// 链表尾 - + + public LRUPageFrame(){ + init(); + } public LRUPageFrame(int capacity) { this.capacity = capacity; + init(); + } + + public void init(){ first = new Node(); last = new Node(); last.flag = "last"; //用来标识最后一个节点是链表尾,在这里链表尾并不算做内存页 @@ -112,6 +119,21 @@ public void addFirst(Object pageNum){ length++; } + public void add(Object pageNum){ + Node node = first.next; + while (node.next!=null){ + node = node.next; + } + Node e = new Node(); + e.pageNum = pageNum; + Node prev = node.prev; + prev.next = e; + e.prev = prev; + e.next = node; + node.prev = e; + length++; + } + public String toString(){ StringBuilder buffer = new StringBuilder(); Node node = first; @@ -188,4 +210,36 @@ public void remove(Object obj,Object o){ nodef = nodef.next; } } + + /** + * Stack 使用 + * @return + */ + public int getLength(){ + return length; + } + + /** + * Stack 使用 pop + * @return + */ + public Object remove(){ + length--; + Node n = last.prev; + last.prev = n.prev; + n.prev.next = last; + return n.pageNum; + } + + /** + * Stack 使用 pop + * @return + */ + public Object removeLow(){ + length--; + Node n = first.next; + first.next = n.next; + n.next.prev = first; + return n.pageNum; + } } diff --git a/group02/562768642/src/com/github/orajavac/coding2017/basic/stack/Stack.java b/group02/562768642/src/com/github/orajavac/coding2017/basic/stack/Stack.java index 1b8e4153b7..499b4a33e4 100644 --- a/group02/562768642/src/com/github/orajavac/coding2017/basic/stack/Stack.java +++ b/group02/562768642/src/com/github/orajavac/coding2017/basic/stack/Stack.java @@ -10,8 +10,21 @@ public Stack(int capacity){ l = new LRUPageFrame(capacity); } + public Stack(){ + l = new LRUPageFrame(); + } + public void push(Object o){ - l.addFirst(o); + //l.addFirst(o); + l.add(o); + } + + public Object pop(){ + return l.remove(); + } + + public Object popLow(){ + return l.removeLow(); } public String toString(){ @@ -29,4 +42,8 @@ public void remove(Object obj){ public Object getFirstNode(){ return l.getFirstNode(); } + + public int length(){ + return l.getLength(); + } } diff --git a/group02/562768642/src/com/github/orajavac/coding2017/basic/stack/expr/InfixExpr.java b/group02/562768642/src/com/github/orajavac/coding2017/basic/stack/expr/InfixExpr.java new file mode 100644 index 0000000000..a6b4e86a38 --- /dev/null +++ b/group02/562768642/src/com/github/orajavac/coding2017/basic/stack/expr/InfixExpr.java @@ -0,0 +1,95 @@ +package com.github.orajavac.coding2017.basic.stack.expr; + +import java.util.HashMap; +import java.util.Map; +import com.github.orajavac.coding2017.basic.stack.Stack; +import com.github.orajavac.coding2017.jvm.util.Util; + +public class InfixExpr { + + String expr = null; + + private final String ADD = "+"; + + private final String SUB = "-"; + + private final String MUL = "*"; + + private final String DIV = "/"; + + private Map operator = new HashMap(); + + private Stack oper = new Stack(); + + private Stack num = new Stack(); + + public InfixExpr(String expr) { + this.expr = expr; + this.operator.put(this.ADD,1); + this.operator.put(this.SUB,1); + this.operator.put(this.MUL,2); + this.operator.put(this.DIV,2); + } + + public float evaluate() { + Object[] obj = Util.parseOperNumToArray(this.expr); + String key = null; + for (int i=0;i level2){ //2+3*4+5 栈顶运算符大于即将入压运算符 + operation(op,num.pop(),num.pop()); + }else if (level1 == level2){ //3-20+2 栈顶运算符等于即将入压运算符 + operation(op,num.pop(),num.pop()); + }else{ + oper.push(op); //把刚刚弹出,再压入栈 + oper.push(key); + } + } + if (oper.length() == 0){ + oper.push(key); + } + } + + public void operation(Object oper,Object num1,Object num2){ + Integer result = null; + if(oper.equals("*")){ + result = Integer.parseInt(num1.toString()) * Integer.parseInt(num2.toString()); + num.push(result); + } + if(oper.equals("/")){ + result = Integer.parseInt(num2.toString()) / Integer.parseInt(num1.toString()); + num.push(result); + } + if(oper.equals("+")){ + result = Integer.parseInt(num1.toString()) + Integer.parseInt(num2.toString()); + num.push(result); + } + if(oper.equals("-")){ + result = Integer.parseInt(num2.toString()) - Integer.parseInt(num1.toString()); + num.push(result); + } + } +} diff --git a/group02/562768642/src/com/github/orajavac/coding2017/basic/stack/expr/InfixExprTest.java b/group02/562768642/src/com/github/orajavac/coding2017/basic/stack/expr/InfixExprTest.java new file mode 100644 index 0000000000..733f48c7bb --- /dev/null +++ b/group02/562768642/src/com/github/orajavac/coding2017/basic/stack/expr/InfixExprTest.java @@ -0,0 +1,55 @@ +package com.github.orajavac.coding2017.basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +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+12*5-40/2+6"); + Assert.assertEquals(106.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); + } + + { + InfixExpr expr = new InfixExpr("3-4*5+2"); + Assert.assertEquals(-15, expr.evaluate(), 0.001f); + } + + } +} diff --git a/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/AttributeInfo.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..77ea35c265 --- /dev/null +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package com.github.orajavac.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; + } + +} diff --git a/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/CodeAttr.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..4fa025750d --- /dev/null +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/CodeAttr.java @@ -0,0 +1,78 @@ +package com.github.orajavac.coding2017.jvm.attr; + +import com.github.orajavac.coding2017.jvm.clz.ClassFile; +import com.github.orajavac.coding2017.jvm.loader.ByteCodeIterator; + +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); + CodeAttr codeAttr = new CodeAttr(attrNameIndex,attrLen,maxStack,maxLocals,codeLen,code); + int exceptionTableLen = iter.nextU2ToInt(); + if (exceptionTableLen>0){ + String exTable = iter.nextUxToHexString(exceptionTableLen); + } + int subAttrCount = iter.nextU2ToInt(); + for (int x=1;x<=subAttrCount;x++){ + 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.equalsIgnoreCase(subAttrName)){ + LocalVariableTable t = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(t); + }else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)){ + StackMapTable t = StackMapTable.parse(iter); + codeAttr.setStackMapTable(t); + }else{ + throw new RuntimeException("need code to process"); + } + } + return null; + } + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + +} diff --git a/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/LineNumberTable.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..2fd7714bcb --- /dev/null +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/LineNumberTable.java @@ -0,0 +1,40 @@ +package com.github.orajavac.coding2017.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + +import com.github.orajavac.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){ + + return null; + } +} diff --git a/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/LocalVariableItem.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..5ddd8ce997 --- /dev/null +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package com.github.orajavac.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; + } +} diff --git a/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/LocalVariableTable.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..23e528ee79 --- /dev/null +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/LocalVariableTable.java @@ -0,0 +1,34 @@ +package com.github.orajavac.coding2017.jvm.attr; + +import java.util.ArrayList; +import java.util.List; + +import com.github.orajavac.coding2017.jvm.loader.ByteCodeIterator; + +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 index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + LocalVariableTable table = new LocalVariableTable(index,len); + int itemLen = iter.nextU2ToInt(); + for (int i=1;i<=itemLen;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); + } +} diff --git a/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/StackMapTable.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..e9d5430659 --- /dev/null +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/attr/StackMapTable.java @@ -0,0 +1,28 @@ +package com.github.orajavac.coding2017.jvm.attr; + +import com.github.orajavac.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; + + } +} diff --git a/group02/562768642/src/com/github/orajavac/coding2017/jvm/clz/ClassFile.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/clz/ClassFile.java index 79c34bd11f..5bebf86b69 100644 --- a/group02/562768642/src/com/github/orajavac/coding2017/jvm/clz/ClassFile.java +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/clz/ClassFile.java @@ -1,7 +1,12 @@ package com.github.orajavac.coding2017.jvm.clz; +import java.util.ArrayList; +import java.util.List; + import com.github.orajavac.coding2017.jvm.constant.ClassInfo; import com.github.orajavac.coding2017.jvm.constant.ConstantPool; +import com.github.orajavac.coding2017.jvm.field.Field; +import com.github.orajavac.coding2017.jvm.method.Method; public class ClassFile { private int minorVersion; @@ -10,7 +15,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; @@ -47,7 +53,18 @@ public void setClassIndex(ClassIndex clzIndex) { this.clzIndex = clzIndex; } - + public void addField(Field f){ + this.fields.add(f); + } + public List getFields(){ + return this.fields; + } + public void addMethod(Method m){ + this.methods.add(m); + } + public List getMethods() { + return methods; + } public void print(){ diff --git a/group02/562768642/src/com/github/orajavac/coding2017/jvm/field/Field.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/field/Field.java new file mode 100644 index 0000000000..8339ac98d4 --- /dev/null +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/field/Field.java @@ -0,0 +1,34 @@ +package com.github.orajavac.coding2017.jvm.field; + +import com.github.orajavac.coding2017.jvm.constant.ConstantPool; +import com.github.orajavac.coding2017.jvm.loader.ByteCodeIterator; + +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 descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + Field f = new Field(accessFlag,nameIndex,descIndex,pool); + return f; + } +} diff --git a/group02/562768642/src/com/github/orajavac/coding2017/jvm/loader/ByteCodeIterator.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/loader/ByteCodeIterator.java index 14db612ebf..9cc6d5d9b9 100644 --- a/group02/562768642/src/com/github/orajavac/coding2017/jvm/loader/ByteCodeIterator.java +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/loader/ByteCodeIterator.java @@ -15,8 +15,12 @@ public ByteCodeIterator(byte[] codes){ } public byte[] getBytes(int len){ - byte[] data = Arrays.copyOfRange(codes,pos,pos+len); - pos+=len; + if (pos + len >= codes.length) { + throw new ArrayIndexOutOfBoundsException(); + } + + byte[] data = Arrays.copyOfRange(codes, pos, pos + len); + pos += len; return data; } @@ -35,4 +39,18 @@ public int nextU2ToInt(){ 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/562768642/src/com/github/orajavac/coding2017/jvm/loader/ClassFileParser.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/loader/ClassFileParser.java index 065eaa4da7..0cfb131cc3 100644 --- a/group02/562768642/src/com/github/orajavac/coding2017/jvm/loader/ClassFileParser.java +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/loader/ClassFileParser.java @@ -11,6 +11,8 @@ import com.github.orajavac.coding2017.jvm.constant.NullConstantInfo; import com.github.orajavac.coding2017.jvm.constant.StringInfo; import com.github.orajavac.coding2017.jvm.constant.UTF8Info; +import com.github.orajavac.coding2017.jvm.field.Field; +import com.github.orajavac.coding2017.jvm.method.Method; public class ClassFileParser { @@ -22,18 +24,39 @@ public ClassFile parse(byte[] codes) { clzFile.setMinorVersion(iter.nextU2ToInt()); clzFile.setMajorVersion(iter.nextU2ToInt()); - clzFile.setConstPool(parseConstantPool(iter)); + ConstantPool pool = parseConstantPool(iter); + clzFile.setConstPool(pool); + + AccessFlag flag = parseAccessFlag(iter); + clzFile.setAccessFlag(flag); + + ClassIndex clzIndex = parseClassInfex(iter); + clzFile.setClassIndex(clzIndex); + + parseInterfaces(iter); + + parseFileds(clzFile,iter); + + parseMethods(clzFile,iter); return clzFile; } private AccessFlag parseAccessFlag(ByteCodeIterator iter) { - - return null; + AccessFlag flag = new AccessFlag(iter.nextU2ToInt()); + return flag; } private ClassIndex parseClassInfex(ByteCodeIterator iter) { - return null; + int thisClassIndex = iter.nextU2ToInt(); + int superClassIndex = iter.nextU2ToInt(); + + ClassIndex clzIndex = new ClassIndex(); + + clzIndex.setThisClassIndex(thisClassIndex); + clzIndex.setSuperClassIndex(superClassIndex); + + return clzIndex; } @@ -82,9 +105,35 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { nameType.setIndex2(iter.nextU2ToInt()); pool.addConstantInfo(nameType); }else{ - throw new RuntimeException("the constant pool tag "+tag+" has not found"); + throw new RuntimeException("the constant pool tag " + tag + " has not been implemented yet."); } } + 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 parseFileds(ClassFile clzFile,ByteCodeIterator iter){ + int filedCount = iter.nextU2ToInt(); + System.out.println("Field count:" + filedCount); + for (int i=1;i<=filedCount;i++){ + Field f = Field.parse(clzFile.getConstantPool(), iter); + clzFile.addField(f); + } + } + + private void parseMethods(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/562768642/src/com/github/orajavac/coding2017/jvm/loader/test.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/loader/test.java new file mode 100644 index 0000000000..a504858eb3 --- /dev/null +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/loader/test.java @@ -0,0 +1,21 @@ +package com.github.orajavac.coding2017.jvm.loader; + +import com.github.orajavac.coding2017.jvm.clz.ClassFile; + +public class test { + + /** + * @param args + */ + public static void main(String[] args) { + String path1 = "bin"; + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "com.github.orajavac.coding2017.jvm.test.EmployeeV1"; + ClassFile clzFile = loader.loadClass(className); + + System.out.println("getMinorVersion="+clzFile.getMinorVersion()); + System.out.println("getMajorVersion="+clzFile.getMajorVersion()); + } + +} diff --git a/group02/562768642/src/com/github/orajavac/coding2017/jvm/method/Method.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/method/Method.java new file mode 100644 index 0000000000..5beb1fdf12 --- /dev/null +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/method/Method.java @@ -0,0 +1,69 @@ +package com.github.orajavac.coding2017.jvm.method; + +import com.github.orajavac.coding2017.jvm.attr.AttributeInfo; +import com.github.orajavac.coding2017.jvm.attr.CodeAttr; +import com.github.orajavac.coding2017.jvm.clz.ClassFile; +import com.github.orajavac.coding2017.jvm.field.Field; +import com.github.orajavac.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 descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + Method m = new Method(clzFile,accessFlag,nameIndex,descIndex); + for (int j=1;j<=attribCount;j++){ + 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 CODE attribute is"); + } + } + return m; + + } +} diff --git a/group02/562768642/src/com/github/orajavac/coding2017/jvm/test/ClassFileloaderTest.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/test/ClassFileloaderTest.java index 0bab359c95..ce766190f3 100644 --- a/group02/562768642/src/com/github/orajavac/coding2017/jvm/test/ClassFileloaderTest.java +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/test/ClassFileloaderTest.java @@ -1,5 +1,7 @@ package com.github.orajavac.coding2017.jvm.test; +import java.util.List; + import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -12,7 +14,9 @@ import com.github.orajavac.coding2017.jvm.constant.MethodRefInfo; import com.github.orajavac.coding2017.jvm.constant.NameAndTypeInfo; import com.github.orajavac.coding2017.jvm.constant.UTF8Info; +import com.github.orajavac.coding2017.jvm.field.Field; import com.github.orajavac.coding2017.jvm.loader.ClassFileLoader; +import com.github.orajavac.coding2017.jvm.method.Method; public class ClassFileloaderTest { private static final Object FULL_QUALIFIED_CLASS_NAME = null; @@ -85,7 +89,7 @@ public void testMagicNumber(){ public void testVersion(){ Assert.assertEquals(0, clzFile.getMinorVersion()); - Assert.assertEquals(52, clzFile.getMajorVersion()); + Assert.assertEquals(51, clzFile.getMajorVersion()); } @@ -184,4 +188,77 @@ private String byteToHexString(byte[] codes ){ } return buffer.toString(); } + + /** + * 下面是第三次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); + } + } diff --git a/group02/562768642/src/com/github/orajavac/coding2017/jvm/util/Util.java b/group02/562768642/src/com/github/orajavac/coding2017/jvm/util/Util.java index 59fd55ae15..52a84fb7a8 100644 --- a/group02/562768642/src/com/github/orajavac/coding2017/jvm/util/Util.java +++ b/group02/562768642/src/com/github/orajavac/coding2017/jvm/util/Util.java @@ -1,5 +1,11 @@ package com.github.orajavac.coding2017.jvm.util; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public class Util { public static int byteToInt(byte[] codes){ String s1 = byteToHexString(codes); @@ -21,4 +27,19 @@ public static String byteToHexString(byte[] codes ){ } return buffer.toString(); } + + public static Object[] parseOperNumToArray(String str){ + String regEx = "\\d+|(\\*)|(\\+)|(-)|(/)"; + Pattern pat = Pattern.compile(regEx); + Matcher mat = pat.matcher(str); + List l = new ArrayList(); + while(mat.find()){ + l.add(mat.group()); + } + /*Object[] obj = l.toArray(); + for (int i=0;i