diff --git a/group13/2729382520/L6/src/io/github/vxzh/datastructure/less6/expr/InfixExpr.java b/group13/2729382520/L6/src/io/github/vxzh/datastructure/less6/expr/InfixExpr.java new file mode 100644 index 0000000000..f0f597e6cb --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/datastructure/less6/expr/InfixExpr.java @@ -0,0 +1,121 @@ +package io.github.vxzh.datastructure.less6.expr; + +import java.util.Stack; + +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + check(); + + Stack operateStack = new Stack(); + Stack numStack = new Stack(); + + char[] ch = expr.toCharArray(); + + 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]); + } + numStack.push(tmp); + + } + if (ch[i] == '+' || ch[i] == '-' || ch[i] == '*' || ch[i] == '/') { + operateStack.push(ch[i]); + } + + if (!(operateStack.isEmpty()) && (char) operateStack.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--; + } + numStack.push(tmp); + + int tmp1 = Integer.parseInt("" + numStack.pop()); + int tmp2 = Integer.parseInt("" + numStack.pop()); + numStack.push(tmp1 * tmp2); + operateStack.pop(); + + } + if (!(operateStack.isEmpty()) && (char) operateStack.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--; + } + numStack.push(tmp); + + int tmp1 = Integer.parseInt("" + numStack.pop()); + int tmp2 = Integer.parseInt("" + numStack.pop()); + numStack.push(tmp2 / tmp1); + operateStack.pop(); + } + } + // 将栈中的数字和运算法逆置,便于计算 + reverse(numStack); + reverse(operateStack); + + while (!(operateStack.isEmpty())) { + if ((char) operateStack.peek() == '+') { + int tmp1 = Integer.parseInt("" + numStack.pop()); + int tmp2 = Integer.parseInt("" + numStack.pop()); + numStack.push(tmp1 + tmp2); + } + + if ((char) operateStack.peek() == '-') { + int tmp1 = Integer.parseInt("" + numStack.pop()); + int tmp2 = Integer.parseInt("" + numStack.pop()); + numStack.push(tmp1 - tmp2); + } + operateStack.pop(); + } + + return Float.parseFloat("" + numStack.pop()); + } + + private void reverse(Stack 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); + + } + + private boolean check() { + if (expr.length() <= 0) { + return false; + } else if ('+' == expr.charAt(0) || '-' == expr.charAt(0) || '*' == expr.charAt(0) || '/' == expr.charAt(0)) { + return false; + } else if ('+' == expr.charAt(expr.length() - 1) || '-' == expr.charAt(expr.length() - 1) || '*' == expr.charAt(expr.length() - 1) || '/' == expr.charAt(expr.length() - 1)) { + return false; + } + + return true; + } + +} \ No newline at end of file diff --git a/group13/2729382520/L6/src/io/github/vxzh/datastructure/less6/expr/InfixExprTest.java b/group13/2729382520/L6/src/io/github/vxzh/datastructure/less6/expr/InfixExprTest.java new file mode 100644 index 0000000000..dbf63cea14 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/datastructure/less6/expr/InfixExprTest.java @@ -0,0 +1,47 @@ +package io.github.vxzh.datastructure.less6.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/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); + } + + } + +} \ No newline at end of file diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/AttributeInfo.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..cec3cd75f7 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/AttributeInfo.java @@ -0,0 +1,20 @@ +package io.github.vxzh.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/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/CodeAttr.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..de04b35cad --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/CodeAttr.java @@ -0,0 +1,116 @@ +package io.github.vxzh.jvm.attr; + + +import io.github.vxzh.jvm.clz.ClassFile; +import io.github.vxzh.jvm.clz.ConstantPool; +import io.github.vxzh.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); + + System.out.println(code); + + //ByteCodeCommand[] cmds = ByteCodeCommand.parse(clzFile,code); + + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, code); + + int exceptionTableLen = iter.nextU2ToInt(); + //TODO 处理exception + if (exceptionTableLen > 0) { + String exTable = iter.nextUxToHexString(exceptionTableLen); + System.out.println("Encountered exception table , just ignore it :" + exTable); + + } + + + int subAttrCount = iter.nextU2ToInt(); + + for (int x = 1; x <= subAttrCount; x++) { + int subAttrIndex = iter.nextU2ToInt(); + String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrIndex); + + //已经向前移动了U2, 现在退回去。 + iter.back(2); + //line item table + 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 " + subAttrName); + } + + + } + + return codeAttr; + } + + + public String toString(ConstantPool pool) { + StringBuilder buffer = new StringBuilder(); + buffer.append("Code:").append(code).append("\n"); + /*for(int i=0;i 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 index = iter.nextU2ToInt(); + int len = iter.nextU4ToInt(); + + LineNumberTable table = new LineNumberTable(index, len); + + int itemLen = iter.nextU2ToInt(); + + for (int i = 1; i <= itemLen; i++) { + LineNumberItem item = new LineNumberItem(); + item.setStartPC(iter.nextU2ToInt()); + item.setLineNum(iter.nextU2ToInt()); + table.addLineNumberItem(item); + } + return table; + } + + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("Line Number Table:\n"); + for (LineNumberItem item : items) { + buffer.append("startPC:" + item.getStartPC()).append(","); + buffer.append("lineNum:" + item.getLineNum()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + + } + + +} \ No newline at end of file diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/LocalVariableItem.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..a0e0f4286a --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/LocalVariableItem.java @@ -0,0 +1,49 @@ +package io.github.vxzh.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/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/LocalVariableTable.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..4993f6ce77 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/LocalVariableTable.java @@ -0,0 +1,57 @@ +package io.github.vxzh.jvm.attr; + + +import io.github.vxzh.jvm.clz.ConstantPool; +import io.github.vxzh.jvm.loader.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +public class LocalVariableTable extends AttributeInfo { + + List items = new ArrayList(); + + public LocalVariableTable(int attrNameIndex, int attrLen) { + super(attrNameIndex, attrLen); + } + + + private void addLocalVariableItem(LocalVariableItem item) { + this.items.add(item); + } + + 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; + } + + + public String toString(ConstantPool pool) { + StringBuilder buffer = new StringBuilder(); + buffer.append("Local Variable Table:\n"); + for (LocalVariableItem item : items) { + buffer.append("startPC:" + item.getStartPC()).append(","); + buffer.append("name:" + pool.getUTF8String(item.getNameIndex())).append(","); + buffer.append("desc:" + pool.getUTF8String(item.getDescIndex())).append(","); + buffer.append("slotIndex:" + item.getIndex()).append("\n"); + } + buffer.append("\n"); + return buffer.toString(); + } +} \ No newline at end of file diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/StackMapTable.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..4538a51d42 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package io.github.vxzh.jvm.attr; + + +import io.github.vxzh.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/group13/2729382520/L6/src/io/github/vxzh/jvm/clz/AccessFlag.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/clz/AccessFlag.java new file mode 100755 index 0000000000..4c3a3c8900 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/clz/AccessFlag.java @@ -0,0 +1,26 @@ +package io.github.vxzh.jvm.clz; + +public class AccessFlag { + private int flagValue; + + public AccessFlag(int value) { + this.flagValue = value; + } + + public int getFlagValue() { + return flagValue; + } + + public void setFlagValue(int flag) { + this.flagValue = flag; + } + + public boolean isPublicClass() { + return (this.flagValue & 0x0001) != 0; + } + + public boolean isFinalClass() { + return (this.flagValue & 0x0010) != 0; + } + +} \ No newline at end of file diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/clz/ClassFile.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/clz/ClassFile.java new file mode 100755 index 0000000000..93adf1976a --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/clz/ClassFile.java @@ -0,0 +1,106 @@ +package io.github.vxzh.jvm.clz; + +import io.github.vxzh.jvm.constant.ClassInfo; +import io.github.vxzh.jvm.field.Field; +import io.github.vxzh.jvm.method.Method; + +import java.util.ArrayList; +import java.util.List; + +public class ClassFile { + + private int minorVersion; + private int majorVersion; + + private AccessFlag accessFlag; + private ClassIndex clzIndex; + private ConstantPool pool; + + private List fields = new ArrayList(); + private List methods = new ArrayList(); + + + public ClassIndex getClzIndex() { + return clzIndex; + } + + public AccessFlag getAccessFlag() { + return accessFlag; + } + + public void setAccessFlag(AccessFlag accessFlag) { + this.accessFlag = accessFlag; + } + + + public ConstantPool getConstantPool() { + return pool; + } + + public int getMinorVersion() { + return minorVersion; + } + + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + + public int getMajorVersion() { + return majorVersion; + } + + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + + public void setConstPool(ConstantPool pool) { + this.pool = pool; + + } + + 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() { + + if (this.accessFlag.isPublicClass()) { + System.out.println("Access flag : public "); + } + System.out.println("Class Name:" + getClassName()); + + System.out.println("Super Class Name:" + getSuperClassName()); + + + } + + private String getClassName() { + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo) this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + + private String getSuperClassName() { + ClassInfo superClass = (ClassInfo) this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } + + +} diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/clz/ClassIndex.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/clz/ClassIndex.java new file mode 100755 index 0000000000..4500959430 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/clz/ClassIndex.java @@ -0,0 +1,22 @@ +package io.github.vxzh.jvm.clz; + +public class ClassIndex { + private int thisClassIndex; + private int superClassIndex; + + public int getThisClassIndex() { + return thisClassIndex; + } + + public void setThisClassIndex(int thisClassIndex) { + this.thisClassIndex = thisClassIndex; + } + + public int getSuperClassIndex() { + return superClassIndex; + } + + public void setSuperClassIndex(int superClassIndex) { + this.superClassIndex = superClassIndex; + } +} \ No newline at end of file diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/clz/ConstantPool.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/clz/ConstantPool.java new file mode 100755 index 0000000000..b96e330020 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/clz/ConstantPool.java @@ -0,0 +1,35 @@ +package io.github.vxzh.jvm.clz; + +import io.github.vxzh.jvm.constant.ConstantInfo; +import io.github.vxzh.jvm.constant.UTF8Info; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos = new ArrayList(); + + + public ConstantPool() { + + } + + public void addConstantInfo(ConstantInfo info) { + + this.constantInfos.add(info); + + } + + public ConstantInfo getConstantInfo(int index) { + return this.constantInfos.get(index); + } + + public String getUTF8String(int index) { + return ((UTF8Info) this.constantInfos.get(index)).getValue(); + } + + public Object getSize() { + return this.constantInfos.size() - 1; + } +} diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/ClassInfo.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/ClassInfo.java new file mode 100755 index 0000000000..c9586ee16c --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/ClassInfo.java @@ -0,0 +1,30 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public class ClassInfo extends ConstantInfo { + private int tag = ConstantInfo.CONSTANT_CLASS_INFO; + private int nameIndex; + + public ClassInfo(ConstantPool pool) { + super(pool); + } + + public int getNameIndex() { + return nameIndex; + } + + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + + public int getTag() { + return tag; + } + + public String getClassName() { + int index = getNameIndex(); + UTF8Info utf8Info = (UTF8Info) constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/ConstantInfo.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/ConstantInfo.java new file mode 100755 index 0000000000..0f3d63685c --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/ConstantInfo.java @@ -0,0 +1,42 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public abstract class ConstantInfo { + + public static final int CONSTANT_UTF8_INFO = 1;// + public static final int CONSTANT_INTEGER_INFO = 3; + public static final int CONSTANT_FLOAT_INFO = 4;// + public static final int CONSTANT_LONG_INFO = 5; + public static final int CONSTANT_DOUBLE_INFO = 6; + public static final int CONSTANT_CLASS_INFO = 7;// + public static final int CONSTANT_STRING_INFO = 8;// + public static final int CONSTANT_FIELDREF_INFO = 9;// + public static final int CONSTANT_METHODREF_INFO = 10;// + public static final int CONSTANT_INTERFACEMETHODREF_INFO = 11; + public static final int CONSTANT_NAMEANDTYPE_INFO = 12;// + public static final int CONSTANT_METHODHANDLE_INFO = 15; + public static final int CONSTANT_METHODTYPE_INFO = 16; + public static final int CONSTANT_INVOKEDYNAMIC_INFO = 18; + + protected ConstantPool constantPool; + + public ConstantInfo() { + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + + public abstract int getTag(); + + public ConstantPool getConstantPool() { + return constantPool; + } + + public ConstantInfo getConstantInfo(int index) { + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/FieldRefInfo.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/FieldRefInfo.java new file mode 100755 index 0000000000..f39bc87b72 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/FieldRefInfo.java @@ -0,0 +1,60 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public class FieldRefInfo extends ConstantInfo { + private int tag = ConstantInfo.CONSTANT_FIELDREF_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + + public int getTag() { + return tag; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString() { + + NameAndTypeInfo typeInfo = (NameAndTypeInfo) this.getConstantInfo(this.getNameAndTypeIndex()); + + return getClassName() + " : " + typeInfo.getName() + ":" + typeInfo.getTypeInfo() + "]"; + } + + public String getClassName() { + + ClassInfo classInfo = (ClassInfo) this.getConstantInfo(this.getClassInfoIndex()); + + UTF8Info utf8Info = (UTF8Info) this.getConstantInfo(classInfo.getNameIndex()); + + return utf8Info.getValue(); + + } + + public String getFieldName() { + NameAndTypeInfo typeInfo = (NameAndTypeInfo) this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getFieldType() { + NameAndTypeInfo typeInfo = (NameAndTypeInfo) this.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } +} diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/MethodRefInfo.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/MethodRefInfo.java new file mode 100755 index 0000000000..46535b7769 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/MethodRefInfo.java @@ -0,0 +1,60 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public class MethodRefInfo extends ConstantInfo { + + private int tag = ConstantInfo.CONSTANT_METHODREF_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getTag() { + return tag; + } + + public int getClassInfoIndex() { + return classInfoIndex; + } + + public void setClassInfoIndex(int classInfoIndex) { + this.classInfoIndex = classInfoIndex; + } + + public int getNameAndTypeIndex() { + return nameAndTypeIndex; + } + + public void setNameAndTypeIndex(int nameAndTypeIndex) { + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public String toString() { + + return getClassName() + " : " + this.getMethodName() + " : " + this.getParamAndReturnType(); + } + + public String getClassName() { + ConstantPool pool = this.getConstantPool(); + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(this.getClassInfoIndex()); + return clzInfo.getClassName(); + } + + public String getMethodName() { + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo) pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getName(); + } + + public String getParamAndReturnType() { + ConstantPool pool = this.getConstantPool(); + NameAndTypeInfo typeInfo = (NameAndTypeInfo) pool.getConstantInfo(this.getNameAndTypeIndex()); + return typeInfo.getTypeInfo(); + } + + +} diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/NameAndTypeInfo.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/NameAndTypeInfo.java new file mode 100755 index 0000000000..a081902eac --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,51 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public class NameAndTypeInfo extends ConstantInfo { + public int tag = ConstantInfo.CONSTANT_NAMEANDTYPE_INFO; + + private int nameIndex; + private int descriptorIndex; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getNameIndex() { + return nameIndex; + } + + public void setNameIndex(int nameIndex) { + this.nameIndex = nameIndex; + } + + public int getDescriptorIndex() { + return descriptorIndex; + } + + public void setDescriptorIndex(int descriptorIndex) { + this.descriptorIndex = descriptorIndex; + } + + public int getTag() { + return tag; + } + + + public String getName() { + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info) pool.getConstantInfo(nameIndex); + return utf8Info1.getValue(); + } + + public String getTypeInfo() { + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info) pool.getConstantInfo(descriptorIndex); + return utf8Info2.getValue(); + } + + public String toString() { + return "(" + getName() + "," + getTypeInfo() + ")"; + } +} diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/NullConstantInfo.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/NullConstantInfo.java new file mode 100755 index 0000000000..1d1d8394f9 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/NullConstantInfo.java @@ -0,0 +1,14 @@ +package io.github.vxzh.jvm.constant; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo() { + + } + + @Override + public int getTag() { + return -1; + } + +} diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/StringInfo.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/StringInfo.java new file mode 100755 index 0000000000..e5175eed4a --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/StringInfo.java @@ -0,0 +1,30 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public class StringInfo extends ConstantInfo { + private int tag = ConstantInfo.CONSTANT_STRING_INFO; + private int index; + + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getTag() { + return tag; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + + public String toString() { + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/UTF8Info.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/UTF8Info.java new file mode 100755 index 0000000000..e1fb81006b --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/constant/UTF8Info.java @@ -0,0 +1,40 @@ +package io.github.vxzh.jvm.constant; + +import io.github.vxzh.jvm.clz.ConstantPool; + +public class UTF8Info extends ConstantInfo { + private int tag = ConstantInfo.CONSTANT_UTF8_INFO; + private int length; + private String value; + + public UTF8Info(ConstantPool pool) { + super(pool); + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public int getTag() { + return tag; + } + + @Override + public String toString() { + return "UTF8Info [tag=" + tag + ", length=" + length + ", value=" + value + ")]"; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + +} diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/field/Field.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/field/Field.java new file mode 100644 index 0000000000..7bb54a6b0c --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/field/Field.java @@ -0,0 +1,48 @@ +package io.github.vxzh.jvm.field; + + +import io.github.vxzh.jvm.clz.ClassFile; +import io.github.vxzh.jvm.constant.UTF8Info; +import io.github.vxzh.jvm.loader.ByteCodeIterator; + +public class Field { + private int accessFlag; + private int nameIndex; + private int descriptorIndex; + private ClassFile clzFile; + + public Field(int accessFlag, int nameIndex, int descriptorIndex, ClassFile clzFile) { + + this.accessFlag = accessFlag; + this.nameIndex = nameIndex; + this.descriptorIndex = descriptorIndex; + this.clzFile = clzFile; + } + + public String toString() { + String name = ((UTF8Info) clzFile.getConstantPool().getConstantInfo(this.nameIndex)).getValue(); + String desc = ((UTF8Info) clzFile.getConstantPool().getConstantInfo(this.descriptorIndex)).getValue(); + return name + ":" + desc; + } + + + public static Field parse(ClassFile clzFile, ByteCodeIterator iter) { + + int accessFlag = iter.nextU2ToInt(); + int nameIndex = iter.nextU2ToInt(); + int descIndex = iter.nextU2ToInt(); + int attribCount = iter.nextU2ToInt(); + //System.out.println("field attribute count:"+ attribCount); + + Field f = new Field(accessFlag, nameIndex, descIndex, clzFile); + + if (attribCount > 0) { + throw new RuntimeException("Field Attribute has not been implemented"); + } + + return f; + } + +} + + diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/loader/ByteCodeIterator.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..f3744d85b5 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,58 @@ +package io.github.vxzh.jvm.loader; + +import io.github.vxzh.jvm.util.Util; + +import java.util.Arrays; + +public class ByteCodeIterator { + + byte[] codes; + int pos = 0; + + ByteCodeIterator(byte[] codes) { + this.codes = codes; + } + + + public byte[] getBytes(int len) { + if (pos + len >= codes.length) { + throw new ArrayIndexOutOfBoundsException(); + } + + byte[] data = Arrays.copyOfRange(codes, pos, pos + len); + pos += len; + return data; + } + + public int nextU1toInt() { + return Util.byteToInt(new byte[]{codes[pos++]}); + } + + public int nextU2ToInt() { + 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 nextU4ToHexString() { + return Util.byteToHexString((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; + } + + +} \ No newline at end of file diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/loader/ClassFileLoader.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/loader/ClassFileLoader.java new file mode 100755 index 0000000000..275e9da3ac --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/loader/ClassFileLoader.java @@ -0,0 +1,58 @@ +package io.github.vxzh.jvm.loader; + +import io.github.vxzh.jvm.clz.ClassFile; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + +public class ClassFileLoader { + + private List clzPaths = new ArrayList(); + + public byte[] readBinaryCode(String className) { + className = className.replace('.', File.separatorChar) + ".class"; + for (String path : this.clzPaths) { + String clzFileName = path + File.separatorChar + className; + byte[] codes = loadClassFile(clzFileName); + if (codes != null) { + return codes; + } + } + return null; + } + + public void addClassPath(String path) { + if (this.clzPaths.contains(path)) { + return; + } + clzPaths.add(path); + } + + public String getClassPath() { + return StringUtils.join(this.clzPaths, ";"); + } + + private byte[] loadClassFile(String clzFileName) { + File f = new File(clzFileName); + try { + return IOUtils.toByteArray(new FileInputStream(f)); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } + +} \ No newline at end of file diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/loader/ClassFileParser.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..4f5bafddbe --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/loader/ClassFileParser.java @@ -0,0 +1,188 @@ +package io.github.vxzh.jvm.loader; + +import io.github.vxzh.jvm.clz.AccessFlag; +import io.github.vxzh.jvm.clz.ClassFile; +import io.github.vxzh.jvm.clz.ClassIndex; +import io.github.vxzh.jvm.clz.ConstantPool; +import io.github.vxzh.jvm.constant.ClassInfo; +import io.github.vxzh.jvm.constant.FieldRefInfo; +import io.github.vxzh.jvm.constant.MethodRefInfo; +import io.github.vxzh.jvm.constant.NameAndTypeInfo; +import io.github.vxzh.jvm.constant.NullConstantInfo; +import io.github.vxzh.jvm.constant.StringInfo; +import io.github.vxzh.jvm.constant.UTF8Info; +import io.github.vxzh.jvm.field.Field; +import io.github.vxzh.jvm.method.Method; + +import java.io.UnsupportedEncodingException; + +import static io.github.vxzh.jvm.constant.ConstantInfo.CONSTANT_CLASS_INFO; +import static io.github.vxzh.jvm.constant.ConstantInfo.CONSTANT_FIELDREF_INFO; +import static io.github.vxzh.jvm.constant.ConstantInfo.CONSTANT_METHODREF_INFO; +import static io.github.vxzh.jvm.constant.ConstantInfo.CONSTANT_NAMEANDTYPE_INFO; +import static io.github.vxzh.jvm.constant.ConstantInfo.CONSTANT_STRING_INFO; +import static io.github.vxzh.jvm.constant.ConstantInfo.CONSTANT_UTF8_INFO; + +public class ClassFileParser { + + + public ClassFile parse(byte[] codes) { + + ClassFile clzFile = new ClassFile(); + + ByteCodeIterator iter = new ByteCodeIterator(codes); + + //验证魔数 + String magicNumber = iter.nextU4ToHexString(); + if (!"cafebabe".equals(magicNumber)) { + return null; + } + + //解析次版本号和主版本号 + clzFile.setMinorVersion(iter.nextU2ToInt()); + clzFile.setMajorVersion(iter.nextU2ToInt()); + + //解析常量池 + 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) { + + AccessFlag flag = new AccessFlag(iter.nextU2ToInt()); + // System.out.println("Is public class: " + flag.isPublicClass()); + // System.out.println("Is final class : " + flag.isFinalClass()); + + return flag; + } + + private ClassIndex parseClassInfex(ByteCodeIterator iter) { + + int thisClassIndex = iter.nextU2ToInt(); + int superClassIndex = iter.nextU2ToInt(); + + ClassIndex clzIndex = new ClassIndex(); + + clzIndex.setThisClassIndex(thisClassIndex); + clzIndex.setSuperClassIndex(superClassIndex); + + return clzIndex; + + } + + private ConstantPool parseConstantPool(ByteCodeIterator iter) { + + int constPoolCount = iter.nextU2ToInt(); + + System.out.println("Constant Pool Count :" + constPoolCount); + + ConstantPool pool = new ConstantPool(); + + pool.addConstantInfo(new NullConstantInfo()); + + for (int i = 1; i <= constPoolCount - 1; i++) { + + int tag = iter.nextU1toInt(); + + if (tag == CONSTANT_CLASS_INFO) {//7 + // Class Info + int utf8Index = iter.nextU2ToInt(); + ClassInfo clzInfo = new ClassInfo(pool); + clzInfo.setNameIndex(utf8Index); + pool.addConstantInfo(clzInfo); + } else if (tag == CONSTANT_UTF8_INFO) {//1 + // UTF-8 String + int len = iter.nextU2ToInt(); + byte[] data = iter.getBytes(len); + String value = null; + try { + value = new String(data, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + UTF8Info utf8Str = new UTF8Info(pool); + utf8Str.setLength(len); + utf8Str.setValue(value); + pool.addConstantInfo(utf8Str); + } else if (tag == CONSTANT_STRING_INFO) {//8 + StringInfo info = new StringInfo(pool); + info.setIndex(iter.nextU2ToInt()); + pool.addConstantInfo(info); + } else if (tag == CONSTANT_FIELDREF_INFO) {//9 + FieldRefInfo field = new FieldRefInfo(pool); + field.setClassInfoIndex(iter.nextU2ToInt()); + field.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(field); + } else if (tag == CONSTANT_METHODREF_INFO) {//10 + // MethodRef + MethodRefInfo method = new MethodRefInfo(pool); + method.setClassInfoIndex(iter.nextU2ToInt()); + method.setNameAndTypeIndex(iter.nextU2ToInt()); + pool.addConstantInfo(method); + } else if (tag == CONSTANT_NAMEANDTYPE_INFO) {//12 + // Name and Type Info + NameAndTypeInfo nameType = new NameAndTypeInfo(pool); + nameType.setNameIndex(iter.nextU2ToInt()); + nameType.setDescriptorIndex(iter.nextU2ToInt()); + pool.addConstantInfo(nameType); + } else { + 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 fieldCount = iter.nextU2ToInt(); + + for (int i = 1; i <= fieldCount; i++) { + Field f = Field.parse(clzFile, 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/group13/2729382520/L6/src/io/github/vxzh/jvm/method/Method.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/method/Method.java new file mode 100644 index 0000000000..40d88910e3 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/method/Method.java @@ -0,0 +1,92 @@ +package io.github.vxzh.jvm.method; + + +import io.github.vxzh.jvm.attr.AttributeInfo; +import io.github.vxzh.jvm.attr.CodeAttr; +import io.github.vxzh.jvm.clz.ClassFile; +import io.github.vxzh.jvm.clz.ConstantPool; +import io.github.vxzh.jvm.constant.UTF8Info; +import io.github.vxzh.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 String toString() { + + ConstantPool pool = this.clzFile.getConstantPool(); + StringBuilder buffer = new StringBuilder(); + + String name = ((UTF8Info) pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info) pool.getConstantInfo(this.descriptorIndex)).getValue(); + + buffer.append(name).append(":").append(desc).append("\n"); + + buffer.append(this.codeAttr.toString(pool)); + + return buffer.toString(); + } + + 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 i = 0; i < attribCount; 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 CODE attribute is implemented , please implement the " + attrName); + } + + } + + return m; + + } + + +} diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/test/ClassFileloaderTest.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/test/ClassFileloaderTest.java new file mode 100755 index 0000000000..b8defc4b12 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,254 @@ +package io.github.vxzh.jvm.test; + +import io.github.vxzh.jvm.clz.ClassFile; +import io.github.vxzh.jvm.clz.ClassIndex; +import io.github.vxzh.jvm.clz.ConstantPool; +import io.github.vxzh.jvm.constant.ClassInfo; +import io.github.vxzh.jvm.constant.MethodRefInfo; +import io.github.vxzh.jvm.constant.NameAndTypeInfo; +import io.github.vxzh.jvm.constant.UTF8Info; +import io.github.vxzh.jvm.field.Field; +import io.github.vxzh.jvm.loader.ClassFileLoader; +import io.github.vxzh.jvm.method.Method; + +import io.github.vxzh.jvm.util.Util; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +public class ClassFileloaderTest { + + private static final String FULL_QUALIFIED_CLASS_NAME = "com/coderising/jvm/test/EmployeeV1"; + static String path1 = "/Users/xuxiaoqing/Workspace/test"; + static String path2 = "/Users/xuxiaoqing/Documents/demo"; + + static ClassFile clzFile = null; + + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "io.github.vxzh.jvm.test.EmployeeV1"; + + clzFile = loader.loadClass(className); + clzFile.print(); + } + + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testClassPath() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + loader.addClassPath(path2); + + String clzPath = loader.getClassPath(); + + Assert.assertEquals(path1 + ";" + path2, clzPath); + + } + + @Test + public void testClassFileLength() { + + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + + String className = "io.github.vxzh.jvm.test.EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1056, byteCodes.length); + + } + + + @Test + public void testMagicNumber() { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "io.github.vxzh.jvm.test.EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3]}; + + + String acctualValue = Util.byteToHexString(codes); + + Assert.assertEquals("cafebabe", acctualValue); + } + + @Test + public void testVersion() { + + Assert.assertEquals(0, clzFile.getMinorVersion()); + Assert.assertEquals(52, clzFile.getMajorVersion()); + + } + + @Test + public void testConstantPool() { + + + ConstantPool pool = clzFile.getConstantPool(); + + Assert.assertEquals(53, pool.getSize()); + + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(1); + Assert.assertEquals(2, clzInfo.getNameIndex()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(2); + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, utf8Info.getValue()); + } + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(3); + Assert.assertEquals(4, clzInfo.getNameIndex()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(4); + Assert.assertEquals("java/lang/Object", utf8Info.getValue()); + } + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(5); + Assert.assertEquals("name", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(6); + Assert.assertEquals("Ljava/lang/String;", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(7); + Assert.assertEquals("age", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(8); + Assert.assertEquals("I", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(9); + Assert.assertEquals("", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(10); + Assert.assertEquals("(Ljava/lang/String;I)V", utf8Info.getValue()); + + utf8Info = (UTF8Info) pool.getConstantInfo(11); + Assert.assertEquals("Code", utf8Info.getValue()); + } + + { + MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(12); + Assert.assertEquals(3, methodRef.getClassInfoIndex()); + Assert.assertEquals(13, methodRef.getNameAndTypeIndex()); + } + + { + NameAndTypeInfo nameAndType = (NameAndTypeInfo) pool.getConstantInfo(13); + Assert.assertEquals(9, nameAndType.getNameIndex()); + Assert.assertEquals(14, nameAndType.getDescriptorIndex()); + } + //抽查几个吧 + { + MethodRefInfo methodRef = (MethodRefInfo) pool.getConstantInfo(45); + Assert.assertEquals(1, methodRef.getClassInfoIndex()); + Assert.assertEquals(46, methodRef.getNameAndTypeIndex()); + } + + { + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(53); + Assert.assertEquals("EmployeeV1.java", utf8Info.getValue()); + } + } + + @Test + public void testClassIndex() { + + ClassIndex clzIndex = clzFile.getClzIndex(); + ClassInfo thisClassInfo = (ClassInfo) clzFile.getConstantPool().getConstantInfo(clzIndex.getThisClassIndex()); + ClassInfo superClassInfo = (ClassInfo) clzFile.getConstantPool().getConstantInfo(clzIndex.getSuperClassIndex()); + + + 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); + } + + +} \ No newline at end of file diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/test/EmployeeV1.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/test/EmployeeV1.java new file mode 100755 index 0000000000..87e05ff033 --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/test/EmployeeV1.java @@ -0,0 +1,29 @@ +package io.github.vxzh.jvm.test; + +public class EmployeeV1 { + + private String name; + private int age; + + public EmployeeV1(String name, int age) { + this.name = name; + this.age = age; + } + + public void setName(String name) { + this.name = name; + } + + public void setAge(int age) { + this.age = age; + } + + public void sayHello() { + System.out.println("Hello , this is class Employee "); + } + + public static void main(String[] args) { + EmployeeV1 p = new EmployeeV1("Andy", 29); + p.sayHello(); + } +} \ No newline at end of file diff --git a/group13/2729382520/L6/src/io/github/vxzh/jvm/util/Util.java b/group13/2729382520/L6/src/io/github/vxzh/jvm/util/Util.java new file mode 100644 index 0000000000..9a659ef3eb --- /dev/null +++ b/group13/2729382520/L6/src/io/github/vxzh/jvm/util/Util.java @@ -0,0 +1,23 @@ +package io.github.vxzh.jvm.util; + +public class Util { + public static int byteToInt(byte[] codes) { + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16).intValue(); + } + + + public static String byteToHexString(byte[] codes) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < codes.length; i++) { + byte b = codes[i]; + int value = b & 0xFF; + String strHex = Integer.toHexString(value); + if (strHex.length() < 2) { + strHex = "0" + strHex; + } + buffer.append(strHex); + } + return buffer.toString(); + } +} \ No newline at end of file