From bbc13347daf4ec2dfe09835e2c6cf369209a9bf4 Mon Sep 17 00:00:00 2001 From: jy <977996067@qq.com> Date: Sun, 23 Apr 2017 13:45:13 +0800 Subject: [PATCH] =?UTF-8?q?4.23=E4=BD=9C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/task7/expr/InfixExpr.java | 79 ++++++++ .../src/task7/expr/InfixExprTest.java | 56 +++++ .../src/task7/expr/PostfixExpr.java | 45 +++++ .../src/task7/expr/PostfixExprTest.java | 37 ++++ .../src/task7/expr/PrefixExpr.java | 47 +++++ .../src/task7/expr/PrefixExprTest.java | 44 ++++ .../1507_977996067/src/task7/expr/Token.java | 53 +++++ .../src/task7/expr/TokenParser.java | 57 ++++++ .../src/task7/jvm/attr/AttributeInfo.java | 19 ++ .../src/task7/jvm/attr/CodeAttr.java | 120 +++++++++++ .../src/task7/jvm/attr/LineNumberTable.java | 72 +++++++ .../src/task7/jvm/attr/LocalVariableItem.java | 39 ++++ .../task7/jvm/attr/LocalVariableTable.java | 57 ++++++ .../src/task7/jvm/attr/StackMapTable.java | 30 +++ .../src/task7/jvm/clz/AccessFlag.java | 25 +++ .../src/task7/jvm/clz/ClassFile.java | 134 ++++++++++++ .../src/task7/jvm/clz/ClassIndex.java | 19 ++ .../src/task7/jvm/cmd/BiPushCmd.java | 23 +++ .../src/task7/jvm/cmd/ByteCodeCommand.java | 128 ++++++++++++ .../src/task7/jvm/cmd/CommandParser.java | 124 ++++++++++++ .../src/task7/jvm/cmd/GetFieldCmd.java | 22 ++ .../src/task7/jvm/cmd/GetStaticFieldCmd.java | 23 +++ .../src/task7/jvm/cmd/InvokeSpecialCmd.java | 23 +++ .../src/task7/jvm/cmd/InvokeVirtualCmd.java | 22 ++ .../src/task7/jvm/cmd/LdcCmd.java | 29 +++ .../src/task7/jvm/cmd/NewObjectCmd.java | 19 ++ .../src/task7/jvm/cmd/NoOperandCmd.java | 23 +++ .../src/task7/jvm/cmd/OneOperandCmd.java | 27 +++ .../src/task7/jvm/cmd/PutFieldCmd.java | 19 ++ .../src/task7/jvm/cmd/TwoOperandCmd.java | 67 ++++++ .../src/task7/jvm/constant/ClassInfo.java | 31 +++ .../src/task7/jvm/constant/ConstantInfo.java | 35 ++++ .../src/task7/jvm/constant/ConstantPool.java | 37 ++++ .../src/task7/jvm/constant/FieldRefInfo.java | 65 ++++++ .../src/task7/jvm/constant/MethodRefInfo.java | 65 ++++++ .../task7/jvm/constant/NameAndTypeInfo.java | 56 +++++ .../task7/jvm/constant/NullConstantInfo.java | 21 ++ .../src/task7/jvm/constant/StringInfo.java | 35 ++++ .../src/task7/jvm/constant/UTF8Info.java | 45 +++++ .../src/task7/jvm/field/Field.java | 48 +++++ .../task7/jvm/loader/ByteCodeIterator.java | 56 +++++ .../src/task7/jvm/loader/ClassFileLoader.java | 122 +++++++++++ .../src/task7/jvm/loader/ClassFileParser.java | 112 ++++++++++ .../src/task7/jvm/method/Method.java | 91 +++++++++ .../src/task7/jvm/print/ClassFilePrinter.java | 44 ++++ .../task7/jvm/print/ConstantInfoVisitor.java | 18 ++ .../jvm/print/ConstantInfoVisitorImpl.java | 51 +++++ .../task7/jvm/print/ConstantPoolPrinter.java | 26 +++ .../task7/jvm/test/ClassFileloaderTest.java | 191 ++++++++++++++++++ .../src/task7/jvm/test/EmployeeV1.java | 29 +++ .../src/task7/jvm/util/Util.java | 23 +++ 51 files changed, 2683 insertions(+) create mode 100644 group15/1507_977996067/src/task7/expr/InfixExpr.java create mode 100644 group15/1507_977996067/src/task7/expr/InfixExprTest.java create mode 100644 group15/1507_977996067/src/task7/expr/PostfixExpr.java create mode 100644 group15/1507_977996067/src/task7/expr/PostfixExprTest.java create mode 100644 group15/1507_977996067/src/task7/expr/PrefixExpr.java create mode 100644 group15/1507_977996067/src/task7/expr/PrefixExprTest.java create mode 100644 group15/1507_977996067/src/task7/expr/Token.java create mode 100644 group15/1507_977996067/src/task7/expr/TokenParser.java create mode 100644 group15/1507_977996067/src/task7/jvm/attr/AttributeInfo.java create mode 100644 group15/1507_977996067/src/task7/jvm/attr/CodeAttr.java create mode 100644 group15/1507_977996067/src/task7/jvm/attr/LineNumberTable.java create mode 100644 group15/1507_977996067/src/task7/jvm/attr/LocalVariableItem.java create mode 100644 group15/1507_977996067/src/task7/jvm/attr/LocalVariableTable.java create mode 100644 group15/1507_977996067/src/task7/jvm/attr/StackMapTable.java create mode 100644 group15/1507_977996067/src/task7/jvm/clz/AccessFlag.java create mode 100644 group15/1507_977996067/src/task7/jvm/clz/ClassFile.java create mode 100644 group15/1507_977996067/src/task7/jvm/clz/ClassIndex.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/BiPushCmd.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/ByteCodeCommand.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/CommandParser.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/GetFieldCmd.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/GetStaticFieldCmd.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/InvokeSpecialCmd.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/InvokeVirtualCmd.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/LdcCmd.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/NewObjectCmd.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/NoOperandCmd.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/OneOperandCmd.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/PutFieldCmd.java create mode 100644 group15/1507_977996067/src/task7/jvm/cmd/TwoOperandCmd.java create mode 100644 group15/1507_977996067/src/task7/jvm/constant/ClassInfo.java create mode 100644 group15/1507_977996067/src/task7/jvm/constant/ConstantInfo.java create mode 100644 group15/1507_977996067/src/task7/jvm/constant/ConstantPool.java create mode 100644 group15/1507_977996067/src/task7/jvm/constant/FieldRefInfo.java create mode 100644 group15/1507_977996067/src/task7/jvm/constant/MethodRefInfo.java create mode 100644 group15/1507_977996067/src/task7/jvm/constant/NameAndTypeInfo.java create mode 100644 group15/1507_977996067/src/task7/jvm/constant/NullConstantInfo.java create mode 100644 group15/1507_977996067/src/task7/jvm/constant/StringInfo.java create mode 100644 group15/1507_977996067/src/task7/jvm/constant/UTF8Info.java create mode 100644 group15/1507_977996067/src/task7/jvm/field/Field.java create mode 100644 group15/1507_977996067/src/task7/jvm/loader/ByteCodeIterator.java create mode 100644 group15/1507_977996067/src/task7/jvm/loader/ClassFileLoader.java create mode 100644 group15/1507_977996067/src/task7/jvm/loader/ClassFileParser.java create mode 100644 group15/1507_977996067/src/task7/jvm/method/Method.java create mode 100644 group15/1507_977996067/src/task7/jvm/print/ClassFilePrinter.java create mode 100644 group15/1507_977996067/src/task7/jvm/print/ConstantInfoVisitor.java create mode 100644 group15/1507_977996067/src/task7/jvm/print/ConstantInfoVisitorImpl.java create mode 100644 group15/1507_977996067/src/task7/jvm/print/ConstantPoolPrinter.java create mode 100644 group15/1507_977996067/src/task7/jvm/test/ClassFileloaderTest.java create mode 100644 group15/1507_977996067/src/task7/jvm/test/EmployeeV1.java create mode 100644 group15/1507_977996067/src/task7/jvm/util/Util.java diff --git a/group15/1507_977996067/src/task7/expr/InfixExpr.java b/group15/1507_977996067/src/task7/expr/InfixExpr.java new file mode 100644 index 0000000000..1a18634382 --- /dev/null +++ b/group15/1507_977996067/src/task7/expr/InfixExpr.java @@ -0,0 +1,79 @@ +package task7.expr; + +import org.junit.Assert; +import task5.stack.Stack; + +import java.util.Arrays; + +public class InfixExpr { + + private String expr; + + private Stack numberStack = new Stack<>(); + + private Stack resultStack = new Stack<>(); + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + + Assert.assertNotNull(expr); + + String[] operators = expr.split("[\\d]+"); + + int length = operators.length; + + Arrays.stream(expr.split("[+\\-*/]+")) + .map(Float::parseFloat) + .forEach(numberStack::push); + + numberStack = reverse(numberStack); + + resultStack.push(numberStack.pop()); + + for (int i = 1; i < length; i++) { + String currentOperator = operators[i]; +// 先做乘除,结果放resultStack里面 + switch (currentOperator) { + case "*": + resultStack.push(resultStack.pop() * numberStack.pop()); + break; + case "/": + resultStack.push(resultStack.pop() / numberStack.pop()); + break; + case "+": + resultStack.push(numberStack.pop()); + break; + case "-": + resultStack.push(numberStack.pop()); + break; + } + } + + resultStack = reverse(resultStack); + +// 做加减 + for (int i = 1; i < length; i++) { + String currentOperator = operators[i]; + if ("+".equals(currentOperator)) { + Float num1 = resultStack.pop(); + Float num2 = resultStack.pop(); + resultStack.push(num1 + num2); + } else if ("-".equals(currentOperator)) { + Float num1 = resultStack.pop(); + Float num2 = resultStack.pop(); + resultStack.push(num1 - num2); + } + } + return resultStack.peek(); + } + + private Stack reverse(Stack stackToReverse) { + Stack temp = new Stack<>(); + while (!stackToReverse.isEmpty()) + temp.push(stackToReverse.pop()); + return temp; + } +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task7/expr/InfixExprTest.java b/group15/1507_977996067/src/task7/expr/InfixExprTest.java new file mode 100644 index 0000000000..f9eb14cbdf --- /dev/null +++ b/group15/1507_977996067/src/task7/expr/InfixExprTest.java @@ -0,0 +1,56 @@ +package task7.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; + +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); + } + + } + + @Test + public void testExprSplit() { + String expr = "3*20+12*5-40/2"; + Arrays.stream(expr.split("[+\\-*/]+")).forEach(System.out::println); + Arrays.stream(expr.split("[\\d]+")).forEach(System.out::println); + } + +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task7/expr/PostfixExpr.java b/group15/1507_977996067/src/task7/expr/PostfixExpr.java new file mode 100644 index 0000000000..369e52c203 --- /dev/null +++ b/group15/1507_977996067/src/task7/expr/PostfixExpr.java @@ -0,0 +1,45 @@ +package task7.expr; + +import task5.stack.Stack; + +import java.util.List; + +public class PostfixExpr { + private String expr = null; + + private Stack numberStack = new Stack<>(); + + public PostfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + List parse = new TokenParser().parse(expr); + for (int i = 0; i < parse.size(); i++) { + Token token = parse.get(i); +// 后缀表达式:从左向右遍历 遇到操作数入栈,遇到操作符弹出操作数栈的两个数计算再入栈 + if (token.isNumber()) + numberStack.push((float) token.getIntValue()); + else + numberStack.push(cal(token.toString(), numberStack.pop(), numberStack.pop())); + } + /*while (!operatorStack.isEmpty()) { + numberStack.push(cal(operatorStack.pop(), numberStack.pop(), numberStack.pop())); + }*/ + return numberStack.peek(); + } + + private static float cal(String operator, float var1, float var2) { + switch (operator) { + case "+": + return var2 + var1; + case "-": + return var2 - var1; + case "*": + return var2 * var1; + case "/": + return var2 / var1; + } + return -1; + } +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task7/expr/PostfixExprTest.java b/group15/1507_977996067/src/task7/expr/PostfixExprTest.java new file mode 100644 index 0000000000..172d397011 --- /dev/null +++ b/group15/1507_977996067/src/task7/expr/PostfixExprTest.java @@ -0,0 +1,37 @@ +package task7.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class PostfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + PostfixExpr expr = new PostfixExpr("6 5 2 3 + 8 * + 3 + *"); + Assert.assertEquals(288, expr.evaluate(), 0.0f); + } + { + //9+(3-1)*3+10/2 + PostfixExpr expr = new PostfixExpr("9 3 1-3*+ 10 2/+"); + Assert.assertEquals(20, expr.evaluate(), 0.0f); + } + + { + //10-2*3+50 + PostfixExpr expr = new PostfixExpr("10 2 3 * - 50 +"); + Assert.assertEquals(54, expr.evaluate(), 0.0f); + } + } + +} diff --git a/group15/1507_977996067/src/task7/expr/PrefixExpr.java b/group15/1507_977996067/src/task7/expr/PrefixExpr.java new file mode 100644 index 0000000000..fe5cb137f0 --- /dev/null +++ b/group15/1507_977996067/src/task7/expr/PrefixExpr.java @@ -0,0 +1,47 @@ +package task7.expr; + +import task5.stack.Stack; + +import java.util.List; + +public class PrefixExpr { + + private String expr; + + private Stack numberStack = new Stack<>(); + + public PrefixExpr(String expr) { + this.expr = expr; + + } + + public float evaluate() { + List parse = new TokenParser().parse(expr); + for (int i = parse.size() - 1; i >= 0; i--) { + Token token = parse.get(i); +// 前缀表达式:从右向左遍历 遇到操作数入栈,遇到操作符弹出操作数栈的两个数计算再入栈 + if (token.isNumber()) + numberStack.push((float) token.getIntValue()); + else + numberStack.push(cal(token.toString(), numberStack.pop(), numberStack.pop())); + } + /*while (!operatorStack.isEmpty()) { + numberStack.push(cal(operatorStack.pop(), numberStack.pop(), numberStack.pop())); + }*/ + return numberStack.peek(); + } + + private static float cal(String operator, float var1, float var2) { + switch (operator) { + case "+": + return var1 + var2; + case "-": + return var1 - var2; + case "*": + return var1 * var2; + case "/": + return var1 / var2; + } + return -1; + } +} diff --git a/group15/1507_977996067/src/task7/expr/PrefixExprTest.java b/group15/1507_977996067/src/task7/expr/PrefixExprTest.java new file mode 100644 index 0000000000..9ac8f9936f --- /dev/null +++ b/group15/1507_977996067/src/task7/expr/PrefixExprTest.java @@ -0,0 +1,44 @@ +package task7.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class PrefixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + { + // 2*3+4*5 + PrefixExpr expr = new PrefixExpr("+ * 2 3* 4 5"); + Assert.assertEquals(26, expr.evaluate(), 0.001f); + } + { + // 4*2 + 6+9*2/3 -8 + PrefixExpr expr = new PrefixExpr("- + + 6 / * 2 9 3 * 4 2 8"); + Assert.assertEquals(12, expr.evaluate(), 0.001f); + } + { + //(3+4)*5-6 + PrefixExpr expr = new PrefixExpr("- * + 3 4 5 6"); + Assert.assertEquals(29, expr.evaluate(), 0.001f); + } + { + //1+((2+3)*4)-5 + PrefixExpr expr = new PrefixExpr("- + 1 * + 2 3 4 5"); + Assert.assertEquals(16, expr.evaluate(), 0.001f); + } + + + } + +} diff --git a/group15/1507_977996067/src/task7/expr/Token.java b/group15/1507_977996067/src/task7/expr/Token.java new file mode 100644 index 0000000000..5ca7b1aef8 --- /dev/null +++ b/group15/1507_977996067/src/task7/expr/Token.java @@ -0,0 +1,53 @@ +package task7.expr; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Token { + public static final List OPERATORS = Arrays.asList("+", "-", "*", "/"); + private static final Map priorities = new HashMap<>(); + + static { + priorities.put("+", 1); + priorities.put("-", 1); + priorities.put("*", 2); + priorities.put("/", 2); + } + + static final int OPERATOR = 1; + static final int NUMBER = 2; + String value; + int type; + + public Token(int type, String value) { + this.type = type; + this.value = value; + } + + public boolean isNumber() { + return type == NUMBER; + } + + public boolean isOperator() { + return type == OPERATOR; + } + + public int getIntValue() { + return Integer.valueOf(value); + } + + public String toString() { + return value; + } + + public boolean hasHigherPriority(Token t) { + if (!this.isOperator() && !t.isOperator()) { + throw new RuntimeException("numbers can't compare priority"); + } + return priorities.get(this.value) - priorities.get(t.value) > 0; + } + + +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task7/expr/TokenParser.java b/group15/1507_977996067/src/task7/expr/TokenParser.java new file mode 100644 index 0000000000..45d75ffc12 --- /dev/null +++ b/group15/1507_977996067/src/task7/expr/TokenParser.java @@ -0,0 +1,57 @@ +package task7.expr; + +import java.util.ArrayList; +import java.util.List; + +public class TokenParser { + + + public List parse(String expr) { + List tokens = new ArrayList<>(); + + int i = 0; + + while (i < expr.length()) { + + char c = expr.charAt(i); + + if (isOperator(c)) { + + Token t = new Token(Token.OPERATOR, String.valueOf(c)); + tokens.add(t); + i++; + + } else if (Character.isDigit(c)) { + + int nextOperatorIndex = indexOfNextOperator(i, expr); + String value = expr.substring(i, nextOperatorIndex); + Token t = new Token(Token.NUMBER, value); + tokens.add(t); + i = nextOperatorIndex; + + } else { +// System.out.println("char :[" + c + "] is not number or operator,ignore"); + i++; + } + + } + return tokens; + } + + private int indexOfNextOperator(int i, String expr) { + + while (Character.isDigit(expr.charAt(i))) { + i++; + if (i == expr.length()) { + break; + } + } + return i; + + } + + private boolean isOperator(char c) { + String sc = String.valueOf(c); + return Token.OPERATORS.contains(sc); + } +} diff --git a/group15/1507_977996067/src/task7/jvm/attr/AttributeInfo.java b/group15/1507_977996067/src/task7/jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..aba714c39b --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/attr/AttributeInfo.java @@ -0,0 +1,19 @@ +package task7.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/group15/1507_977996067/src/task7/jvm/attr/CodeAttr.java b/group15/1507_977996067/src/task7/jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..e3784bec44 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/attr/CodeAttr.java @@ -0,0 +1,120 @@ +package task7.jvm.attr; + + +import task7.jvm.clz.ClassFile; +import task7.jvm.cmd.ByteCodeCommand; +import task7.jvm.cmd.CommandParser; +import task7.jvm.constant.ConstantPool; +import task7.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.next2Bytes(); + int attrLen = iter.next4Bytes(); + int maxStack = iter.next2Bytes(); + int maxLocals = iter.next2Bytes(); + int codeLen = iter.next4Bytes(); + + String code = iter.nextUxToHexString(codeLen); + + System.out.println(code); + + ByteCodeCommand[] cmds = CommandParser.parse(clzFile, code); + + CodeAttr codeAttr = new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, code); + + int exceptionTableLen = iter.next2Bytes(); + //TODO 处理exception + if (exceptionTableLen > 0) { + String exTable = iter.nextUxToHexString(exceptionTableLen); + System.out.println("Encountered exception table , just ignore it :" + exTable); + + } + + + int subAttrCount = iter.next2Bytes(); + + for (int x = 1; x <= subAttrCount; x++) { + int subAttrIndex = iter.next2Bytes(); + 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 < cmds.length; i++) { + buffer.append(cmds[i].toString(pool)).append("\n"); + } + buffer.append("\n"); + buffer.append(this.lineNumTable.toString()); + buffer.append(this.localVarTable.toString(pool)); + return buffer.toString(); + } + + private void setStackMapTable(StackMapTable t) { + this.stackMapTable = t; + + } + + +} diff --git a/group15/1507_977996067/src/task7/jvm/attr/LineNumberTable.java b/group15/1507_977996067/src/task7/jvm/attr/LineNumberTable.java new file mode 100644 index 0000000000..ebaec852b9 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/attr/LineNumberTable.java @@ -0,0 +1,72 @@ +package task7.jvm.attr; + +import task7.jvm.loader.ByteCodeIterator; + +import java.util.ArrayList; +import java.util.List; + +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 index = iter.next2Bytes(); + int len = iter.next4Bytes(); + + LineNumberTable table = new LineNumberTable(index, len); + + int itemLen = iter.next2Bytes(); + + for (int i = 1; i <= itemLen; i++) { + LineNumberItem item = new LineNumberItem(); + item.setStartPC(iter.next2Bytes()); + item.setLineNum(iter.next2Bytes()); + 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(); + + } + + +} diff --git a/group15/1507_977996067/src/task7/jvm/attr/LocalVariableItem.java b/group15/1507_977996067/src/task7/jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..fbb27e8812 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package task7.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/group15/1507_977996067/src/task7/jvm/attr/LocalVariableTable.java b/group15/1507_977996067/src/task7/jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..7bcf199b3c --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/attr/LocalVariableTable.java @@ -0,0 +1,57 @@ +package task7.jvm.attr; + + +import task7.jvm.constant.ConstantPool; +import task7.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.next2Bytes(); + int len = iter.next4Bytes(); + + LocalVariableTable table = new LocalVariableTable(index,len); + + int itemLen = iter.next2Bytes(); + + for(int i=1; i<=itemLen; i++){ + LocalVariableItem item = new LocalVariableItem(); + item.setStartPC(iter.next2Bytes()); + item.setLength(iter.next2Bytes()); + item.setNameIndex(iter.next2Bytes()); + item.setDescIndex(iter.next2Bytes()); + item.setIndex(iter.next2Bytes()); + 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(); + } +} diff --git a/group15/1507_977996067/src/task7/jvm/attr/StackMapTable.java b/group15/1507_977996067/src/task7/jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..f57144783d --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package task7.jvm.attr; + + +import task7.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.next2Bytes(); + int len = iter.next4Bytes(); + 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/group15/1507_977996067/src/task7/jvm/clz/AccessFlag.java b/group15/1507_977996067/src/task7/jvm/clz/AccessFlag.java new file mode 100644 index 0000000000..e333b4621d --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/clz/AccessFlag.java @@ -0,0 +1,25 @@ +package task7.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/group15/1507_977996067/src/task7/jvm/clz/ClassFile.java b/group15/1507_977996067/src/task7/jvm/clz/ClassFile.java new file mode 100644 index 0000000000..1587998e29 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/clz/ClassFile.java @@ -0,0 +1,134 @@ +package task7.jvm.clz; + +import task7.jvm.constant.ClassInfo; +import task7.jvm.constant.ConstantPool; +import task7.jvm.field.Field; +import task7.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 void setClzIndex(ClassIndex clzIndex) { + this.clzIndex = clzIndex; + } + + public ConstantPool getPool() { + return pool; + } + + public void setPool(ConstantPool pool) { + this.pool = pool; + } + + public List getFields() { + return fields; + } + + public void setFields(List fields) { + this.fields = fields; + } + + public List getMethods() { + return methods; + } + + public void setMethods(List methods) { + this.methods = methods; + } + + 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 print() { + + if (this.accessFlag.isPublicClass()) { + System.out.println("Access flag : public "); + } + System.out.println("Class Name:" + getClassName()); + + System.out.println("Super Class Name:" + getSuperClassName()); + + + } + + public String getClassName() { + int thisClassIndex = this.clzIndex.getThisClassIndex(); + ClassInfo thisClass = (ClassInfo) this.getConstantPool().getConstantInfo(thisClassIndex); + return thisClass.getClassName(); + } + + public String getSuperClassName() { + ClassInfo superClass = (ClassInfo) this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); + return superClass.getClassName(); + } + + public Method getMethod(String methodName, String paramAndReturnType) { + + for (Method method : methods) { + int nameIndex = method.getNameIndex(); + int descriptorIndex = method.getDescriptorIndex(); + String name = getConstantPool().getUTF8String(nameIndex); + String descriptor = getConstantPool().getUTF8String(descriptorIndex); + if (methodName.equalsIgnoreCase(name) && paramAndReturnType.equalsIgnoreCase(descriptor)) { + return method; + } + } + return null; + } + + public Method getMainMethod() { + + return getMethod("main", "([Ljava/lang/String;)"); + } +} diff --git a/group15/1507_977996067/src/task7/jvm/clz/ClassIndex.java b/group15/1507_977996067/src/task7/jvm/clz/ClassIndex.java new file mode 100644 index 0000000000..b4342d6557 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/clz/ClassIndex.java @@ -0,0 +1,19 @@ +package task7.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/group15/1507_977996067/src/task7/jvm/cmd/BiPushCmd.java b/group15/1507_977996067/src/task7/jvm/cmd/BiPushCmd.java new file mode 100644 index 0000000000..b80f830944 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/BiPushCmd.java @@ -0,0 +1,23 @@ +package task7.jvm.cmd; + +import task7.jvm.clz.ClassFile; +import task7.jvm.constant.ConstantInfo; +import task7.jvm.constant.ConstantPool; + + +public class BiPushCmd extends OneOperandCmd { + + public BiPushCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return this.getOffset()+": "+ this.getOpCode()+" " + this.getReadableCodeText() + " " + this.getOperand(); + } + + + +} diff --git a/group15/1507_977996067/src/task7/jvm/cmd/ByteCodeCommand.java b/group15/1507_977996067/src/task7/jvm/cmd/ByteCodeCommand.java new file mode 100644 index 0000000000..e4c9e2ac2d --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/ByteCodeCommand.java @@ -0,0 +1,128 @@ +package task7.jvm.cmd; + +import java.util.HashMap; +import java.util.Map; + +import task7.jvm.clz.ClassFile; +import task7.jvm.constant.ConstantInfo; +import task7.jvm.constant.ConstantPool; + + +public abstract class ByteCodeCommand { + + String opCode; + ClassFile clzFile; + private int offset; + + private static Map codeMap = new HashMap(); + + static{ + codeMap.put("01", "aconst_null"); + + codeMap.put("BB", "new"); + codeMap.put("37", "lstore"); + codeMap.put("B7", "invokespecial"); + codeMap.put("B6", "invokevirtual"); + codeMap.put("B4", "getfield"); + codeMap.put("B5", "putfield"); + codeMap.put("B2", "getstatic"); + + codeMap.put("2A", "aload_0"); + codeMap.put("2B", "aload_1"); + codeMap.put("2C", "aload_2"); + + codeMap.put("10", "bipush"); + codeMap.put("15", "iload"); + codeMap.put("1A", "iload_0"); + codeMap.put("1B", "iload_1"); + codeMap.put("1C", "iload_2"); + codeMap.put("1D", "iload_3"); + + codeMap.put("25", "fload_3"); + + codeMap.put("1E", "lload_0"); + + codeMap.put("24", "fload_2"); + codeMap.put("4C", "astore_1"); + + codeMap.put("A2", "if_icmp_ge"); + codeMap.put("A4", "if_icmple"); + + codeMap.put("A7", "goto"); + + codeMap.put("B1", "return"); + codeMap.put("AC", "ireturn"); + codeMap.put("AE", "freturn"); + + codeMap.put("03", "iconst_0"); + codeMap.put("04", "iconst_1"); + + codeMap.put("3C", "istore_1"); + codeMap.put("3D", "istore_2"); + + codeMap.put("59", "dup"); + + codeMap.put("60", "iadd"); + codeMap.put("84", "iinc"); + + codeMap.put("12", "ldc"); + } + + + + + + protected ByteCodeCommand(ClassFile clzFile, String opCode){ + this.clzFile = clzFile; + this.opCode = opCode; + } + + protected ClassFile getClassFile() { + return clzFile; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + protected ConstantInfo getConstantInfo(int index){ + return this.getClassFile().getConstantPool().getConstantInfo(index); + } + + protected ConstantPool getConstantPool(){ + return this.getClassFile().getConstantPool(); + } + + + + public String getOpCode() { + return opCode; + } + + public abstract int getLength(); + + + + + public String toString(){ + + StringBuffer buffer = new StringBuffer(); + buffer.append(this.opCode); + + return buffer.toString(); + } + public abstract String toString(ConstantPool pool); + + public String getReadableCodeText(){ + String txt = codeMap.get(opCode); + if(txt == null){ + return opCode; + } + return txt; + } + +// public abstract void execute(StackFrame frame,FrameResult result); +} diff --git a/group15/1507_977996067/src/task7/jvm/cmd/CommandParser.java b/group15/1507_977996067/src/task7/jvm/cmd/CommandParser.java new file mode 100644 index 0000000000..f6a12e1701 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/CommandParser.java @@ -0,0 +1,124 @@ +package task7.jvm.cmd; + +import java.util.ArrayList; +import java.util.List; + +import task7.jvm.clz.ClassFile; + +public class CommandParser { + + public static final String aconst_null = "01"; + public static final String new_object = "BB"; + public static final String lstore = "37"; + public static final String invokespecial = "B7"; + public static final String invokevirtual = "B6"; + public static final String getfield = "B4"; + public static final String putfield = "B5"; + public static final String getstatic = "B2"; + public static final String ldc = "12"; + public static final String dup = "59"; + public static final String bipush = "10"; + public static final String aload_0 = "2A"; + public static final String aload_1 = "2B"; + public static final String aload_2 = "2C"; + public static final String iload = "15"; + public static final String iload_1 = "1B"; + public static final String iload_2 = "1C"; + public static final String iload_3 = "1D"; + public static final String fload_3 = "25"; + + public static final String voidreturn = "B1"; + public static final String ireturn = "AC"; + public static final String freturn = "AE"; + + public static final String astore_1 = "4C"; + public static final String if_icmp_ge = "A2"; + public static final String if_icmple = "A4"; + public static final String goto_no_condition = "A7"; + public static final String iconst_0 = "03"; + public static final String iconst_1 = "04"; + public static final String istore_1 = "3C"; + public static final String istore_2 = "3D"; + public static final String iadd = "60"; + public static final String iinc = "84"; + + public static ByteCodeCommand[] parse(ClassFile clzFile, String codes) { + codes = codes.toUpperCase(); + System.out.println("=========> codes: " + codes); + CommandIterator iterator = new CommandIterator(codes); + List commands = new ArrayList<>(); + while (iterator.hasNext()) { + String opCode = iterator.next2CharAsString(); + switch (opCode) { + case new_object: + NewObjectCmd newObjectCmd = new NewObjectCmd(clzFile, codes); + newObjectCmd.setOprand1(iterator.next2CharAsInt()); + newObjectCmd.setOprand2(iterator.next2CharAsInt()); + commands.add(newObjectCmd); + break; + case ldc: + LdcCmd ldcCmd = new LdcCmd(clzFile, codes); + ldcCmd.setOperand(iterator.next2CharAsInt()); + commands.add(ldcCmd); + break; + case bipush: + BiPushCmd biPushCmd = new BiPushCmd(clzFile, codes); + biPushCmd.setOperand(iterator.next2CharAsInt()); + commands.add(biPushCmd); + break; + case invokespecial: + InvokeSpecialCmd invokeSpecialCmd = new InvokeSpecialCmd(clzFile, codes); + invokeSpecialCmd.setOprand1(iterator.next2CharAsInt()); + invokeSpecialCmd.setOprand2(iterator.next2CharAsInt()); + commands.add(invokeSpecialCmd); + break; + case invokevirtual: + InvokeVirtualCmd invokeVirtualCmd = new InvokeVirtualCmd(clzFile, codes); + invokeVirtualCmd.setOprand1(iterator.next2CharAsInt()); + invokeVirtualCmd.setOprand2(iterator.next2CharAsInt()); + commands.add(invokeVirtualCmd); + break; + default: + NoOperandCmd noOperandCmd = new NoOperandCmd(clzFile, codes); + commands.add(noOperandCmd); + } + } + calcuateOffset(commands); + return commands.toArray(new ByteCodeCommand[commands.size()]); + } + + private static void calcuateOffset(List cmds) { + + int offset = 0; + for (ByteCodeCommand cmd : cmds) { + cmd.setOffset(offset); + offset += cmd.getLength(); + } + + } + + private static class CommandIterator { + String codes = null; + int pos = 0; + + CommandIterator(String codes) { + this.codes = codes; + } + + public boolean hasNext() { + return pos < this.codes.length(); + } + + public String next2CharAsString() { + String result = codes.substring(pos, pos + 2); + pos += 2; + return result; + } + + public int next2CharAsInt() { + String s = this.next2CharAsString(); + return Integer.valueOf(s, 16); + } + + } +} diff --git a/group15/1507_977996067/src/task7/jvm/cmd/GetFieldCmd.java b/group15/1507_977996067/src/task7/jvm/cmd/GetFieldCmd.java new file mode 100644 index 0000000000..531770d8b9 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/GetFieldCmd.java @@ -0,0 +1,22 @@ +package task7.jvm.cmd; + +import task7.jvm.clz.ClassFile; +import task7.jvm.constant.ConstantPool; + + +public class GetFieldCmd extends TwoOperandCmd { + + public GetFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + + + +} diff --git a/group15/1507_977996067/src/task7/jvm/cmd/GetStaticFieldCmd.java b/group15/1507_977996067/src/task7/jvm/cmd/GetStaticFieldCmd.java new file mode 100644 index 0000000000..7f43150ca2 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/GetStaticFieldCmd.java @@ -0,0 +1,23 @@ +package task7.jvm.cmd; + +import task7.jvm.clz.ClassFile; +import task7.jvm.constant.ClassInfo; +import task7.jvm.constant.ConstantPool; +import task7.jvm.constant.FieldRefInfo; +import task7.jvm.constant.UTF8Info; + + +public class GetStaticFieldCmd extends TwoOperandCmd { + + public GetStaticFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + +} diff --git a/group15/1507_977996067/src/task7/jvm/cmd/InvokeSpecialCmd.java b/group15/1507_977996067/src/task7/jvm/cmd/InvokeSpecialCmd.java new file mode 100644 index 0000000000..ffe71dfb15 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/InvokeSpecialCmd.java @@ -0,0 +1,23 @@ +package task7.jvm.cmd; + +import task7.jvm.clz.ClassFile; +import task7.jvm.constant.ConstantPool; +import task7.jvm.constant.MethodRefInfo; + + +public class InvokeSpecialCmd extends TwoOperandCmd { + + public InvokeSpecialCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + + +} diff --git a/group15/1507_977996067/src/task7/jvm/cmd/InvokeVirtualCmd.java b/group15/1507_977996067/src/task7/jvm/cmd/InvokeVirtualCmd.java new file mode 100644 index 0000000000..de80616b39 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/InvokeVirtualCmd.java @@ -0,0 +1,22 @@ +package task7.jvm.cmd; + +import task7.jvm.clz.ClassFile; +import task7.jvm.constant.ConstantPool; + + +public class InvokeVirtualCmd extends TwoOperandCmd { + + public InvokeVirtualCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + + + +} diff --git a/group15/1507_977996067/src/task7/jvm/cmd/LdcCmd.java b/group15/1507_977996067/src/task7/jvm/cmd/LdcCmd.java new file mode 100644 index 0000000000..143b070968 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/LdcCmd.java @@ -0,0 +1,29 @@ +package task7.jvm.cmd; + +import task7.jvm.clz.ClassFile; +import task7.jvm.constant.ConstantInfo; +import task7.jvm.constant.ConstantPool; +import task7.jvm.constant.StringInfo; + +public class LdcCmd extends OneOperandCmd { + + public LdcCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + ConstantInfo info = (ConstantInfo)pool.getConstantInfo(this.getOperand()); + + String value = "TBD"; + if(info instanceof StringInfo){ + StringInfo strInfo = (StringInfo)info; + value = strInfo.toString(); + } + + return this.getOffset()+":"+this.getOpCode()+" " + this.getReadableCodeText() + " "+ value; + + } + +} diff --git a/group15/1507_977996067/src/task7/jvm/cmd/NewObjectCmd.java b/group15/1507_977996067/src/task7/jvm/cmd/NewObjectCmd.java new file mode 100644 index 0000000000..09ffc20c19 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/NewObjectCmd.java @@ -0,0 +1,19 @@ +package task7.jvm.cmd; + +import task7.jvm.clz.ClassFile; +import task7.jvm.constant.ConstantPool; + +public class NewObjectCmd extends TwoOperandCmd{ + + public NewObjectCmd(ClassFile clzFile, String opCode){ + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsClassInfo(pool); + } + + +} diff --git a/group15/1507_977996067/src/task7/jvm/cmd/NoOperandCmd.java b/group15/1507_977996067/src/task7/jvm/cmd/NoOperandCmd.java new file mode 100644 index 0000000000..16810f3874 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/NoOperandCmd.java @@ -0,0 +1,23 @@ +package task7.jvm.cmd; + +import task7.jvm.clz.ClassFile; +import task7.jvm.constant.ConstantPool; + +public class NoOperandCmd extends ByteCodeCommand{ + + public NoOperandCmd(ClassFile clzFile, String opCode) { + super(clzFile, opCode); + } + + @Override + public String toString(ConstantPool pool) { + return this.getOffset()+":" +this.getOpCode() + " "+ this.getReadableCodeText(); + } + + + + public int getLength(){ + return 1; + } + +} diff --git a/group15/1507_977996067/src/task7/jvm/cmd/OneOperandCmd.java b/group15/1507_977996067/src/task7/jvm/cmd/OneOperandCmd.java new file mode 100644 index 0000000000..713610e243 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/OneOperandCmd.java @@ -0,0 +1,27 @@ +package task7.jvm.cmd; + +import task7.jvm.clz.ClassFile; + +public abstract class OneOperandCmd extends ByteCodeCommand { + + private int operand; + + public OneOperandCmd(ClassFile clzFile,String opCode) { + super(clzFile, opCode); + + } + public int getOperand() { + + return this.operand; + } + + public void setOperand(int oprand1) { + this.operand = oprand1; + + } + public int getLength(){ + return 2; + } + + +} diff --git a/group15/1507_977996067/src/task7/jvm/cmd/PutFieldCmd.java b/group15/1507_977996067/src/task7/jvm/cmd/PutFieldCmd.java new file mode 100644 index 0000000000..df2b895c03 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/PutFieldCmd.java @@ -0,0 +1,19 @@ +package task7.jvm.cmd; + +import task7.jvm.clz.ClassFile; +import task7.jvm.constant.ConstantPool; + +public class PutFieldCmd extends TwoOperandCmd { + + public PutFieldCmd(ClassFile clzFile,String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + +} diff --git a/group15/1507_977996067/src/task7/jvm/cmd/TwoOperandCmd.java b/group15/1507_977996067/src/task7/jvm/cmd/TwoOperandCmd.java new file mode 100644 index 0000000000..9cf2fded56 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/cmd/TwoOperandCmd.java @@ -0,0 +1,67 @@ +package task7.jvm.cmd; + +import task7.jvm.clz.ClassFile; +import task7.jvm.constant.ClassInfo; +import task7.jvm.constant.ConstantInfo; +import task7.jvm.constant.ConstantPool; +import task7.jvm.constant.FieldRefInfo; +import task7.jvm.constant.MethodRefInfo; + +public abstract class TwoOperandCmd extends ByteCodeCommand{ + + int oprand1 = -1; + int oprand2 = -1; + + public int getOprand1() { + return oprand1; + } + + public void setOprand1(int oprand1) { + this.oprand1 = oprand1; + } + + public void setOprand2(int oprand2) { + this.oprand2 = oprand2; + } + + public int getOprand2() { + return oprand2; + } + + public TwoOperandCmd(ClassFile clzFile,String opCode) { + super(clzFile, opCode); + } + + public int getIndex(){ + int oprand1 = this.getOprand1(); + int oprand2 = this.getOprand2(); + int index = oprand1 << 8 | oprand2; + return index; + } + + protected String getOperandAsClassInfo(ConstantPool pool){ + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ClassInfo info = (ClassInfo)pool.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" "+ codeTxt +" "+ info.getClassName(); + } + + protected String getOperandAsMethod(ConstantPool pool){ + int index = getIndex(); + String codeTxt = getReadableCodeText(); + ConstantInfo constInfo = this.getConstantInfo(index); + MethodRefInfo info = (MethodRefInfo)this.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); + } + + protected String getOperandAsField(ConstantPool pool){ + int index = getIndex(); + + String codeTxt = getReadableCodeText(); + FieldRefInfo info = (FieldRefInfo)this.getConstantInfo(index); + return this.getOffset()+":"+this.getOpCode()+" " + codeTxt +" "+ info.toString(); + } + public int getLength(){ + return 3; + } +} diff --git a/group15/1507_977996067/src/task7/jvm/constant/ClassInfo.java b/group15/1507_977996067/src/task7/jvm/constant/ClassInfo.java new file mode 100644 index 0000000000..8c2af5157a --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/constant/ClassInfo.java @@ -0,0 +1,31 @@ +package task7.jvm.constant; + +import task7.jvm.print.ConstantInfoVisitor; + +public class ClassInfo extends ConstantInfo { + private int type = ConstantInfo.CLASS_INFO; + private int utf8Index ; + public ClassInfo(ConstantPool pool) { + super(pool); + } + public int getUtf8Index() { + return utf8Index; + } + public void setUtf8Index(int utf8Index) { + this.utf8Index = utf8Index; + } + public int getType() { + return type; + } + + @Override + public void accept(ConstantInfoVisitor visitor) { + visitor.visitClassInfo(this); + } + + public String getClassName() { + int index = getUtf8Index(); + UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); + return utf8Info.getValue(); + } +} diff --git a/group15/1507_977996067/src/task7/jvm/constant/ConstantInfo.java b/group15/1507_977996067/src/task7/jvm/constant/ConstantInfo.java new file mode 100644 index 0000000000..24922e29d3 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/constant/ConstantInfo.java @@ -0,0 +1,35 @@ +package task7.jvm.constant; + +import task7.jvm.print.ConstantInfoVisitor; + +public abstract class ConstantInfo { + public static final int UTF8_INFO = 1; + public static final int FLOAT_INFO = 4; + public static final int CLASS_INFO = 7; + public static final int STRING_INFO = 8; + public static final int FIELD_INFO = 9; + public static final int METHOD_INFO = 10; + public static final int NAME_AND_TYPE_INFO = 12; + protected ConstantPool constantPool; + + public ConstantInfo() { + + } + + public ConstantInfo(ConstantPool pool) { + this.constantPool = pool; + } + + public abstract int getType(); + + public abstract void accept(ConstantInfoVisitor visitor); + + public ConstantPool getConstantPool() { + return constantPool; + } + + public ConstantInfo getConstantInfo(int index) { + return this.constantPool.getConstantInfo(index); + } + +} diff --git a/group15/1507_977996067/src/task7/jvm/constant/ConstantPool.java b/group15/1507_977996067/src/task7/jvm/constant/ConstantPool.java new file mode 100644 index 0000000000..485f0dd7c2 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/constant/ConstantPool.java @@ -0,0 +1,37 @@ +package task7.jvm.constant; + +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + private List constantInfos; + + public ConstantPool() { + this.constantInfos = new ArrayList<>(); + } + + public ConstantPool(int size) { + this.constantInfos = new ArrayList<>(size); + + addConstantInfo(new NullConstantInfo()); + } + + 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/group15/1507_977996067/src/task7/jvm/constant/FieldRefInfo.java b/group15/1507_977996067/src/task7/jvm/constant/FieldRefInfo.java new file mode 100644 index 0000000000..01474d2dd6 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/constant/FieldRefInfo.java @@ -0,0 +1,65 @@ +package task7.jvm.constant; + +import task7.jvm.print.ConstantInfoVisitor; + +public class FieldRefInfo extends ConstantInfo { + private int type = ConstantInfo.FIELD_INFO; + private int classInfoIndex; + private int nameAndTypeIndex; + + public FieldRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + @Override + public void accept(ConstantInfoVisitor visitor) { + visitor.visitFieldRefInfo(this); + } + + 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.getUtf8Index()); + + 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/group15/1507_977996067/src/task7/jvm/constant/MethodRefInfo.java b/group15/1507_977996067/src/task7/jvm/constant/MethodRefInfo.java new file mode 100644 index 0000000000..104b798e59 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/constant/MethodRefInfo.java @@ -0,0 +1,65 @@ +package task7.jvm.constant; + +import task7.jvm.print.ConstantInfoVisitor; + +public class MethodRefInfo extends ConstantInfo { + + private int type = ConstantInfo.METHOD_INFO; + + private int classInfoIndex; + private int nameAndTypeIndex; + + public MethodRefInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + @Override + public void accept(ConstantInfoVisitor visitor) { + visitor.visitMethodRefInfo(this); + } + + 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/group15/1507_977996067/src/task7/jvm/constant/NameAndTypeInfo.java b/group15/1507_977996067/src/task7/jvm/constant/NameAndTypeInfo.java new file mode 100644 index 0000000000..18089a2008 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/constant/NameAndTypeInfo.java @@ -0,0 +1,56 @@ +package task7.jvm.constant; + +import task7.jvm.print.ConstantInfoVisitor; + +public class NameAndTypeInfo extends ConstantInfo { + public int type = ConstantInfo.NAME_AND_TYPE_INFO; + + private int index1; + private int index2; + + public NameAndTypeInfo(ConstantPool pool) { + super(pool); + } + + public int getIndex1() { + return index1; + } + + public void setIndex1(int index1) { + this.index1 = index1; + } + + public int getIndex2() { + return index2; + } + + public void setIndex2(int index2) { + this.index2 = index2; + } + + public int getType() { + return type; + } + + @Override + public void accept(ConstantInfoVisitor visitor) { + visitor.visitNameAndTypeInfo(this); + } + + + public String getName() { + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info1 = (UTF8Info) pool.getConstantInfo(index1); + return utf8Info1.getValue(); + } + + public String getTypeInfo() { + ConstantPool pool = this.getConstantPool(); + UTF8Info utf8Info2 = (UTF8Info) pool.getConstantInfo(index2); + return utf8Info2.getValue(); + } + + public String toString() { + return "(" + getName() + "," + getTypeInfo() + ")"; + } +} diff --git a/group15/1507_977996067/src/task7/jvm/constant/NullConstantInfo.java b/group15/1507_977996067/src/task7/jvm/constant/NullConstantInfo.java new file mode 100644 index 0000000000..216b03a449 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/constant/NullConstantInfo.java @@ -0,0 +1,21 @@ +package task7.jvm.constant; + +import task7.jvm.print.ConstantInfoVisitor; + +public class NullConstantInfo extends ConstantInfo { + + public NullConstantInfo() { + + } + + @Override + public int getType() { + return -1; + } + + @Override + public void accept(ConstantInfoVisitor visitor) { + // non impl + } + +} diff --git a/group15/1507_977996067/src/task7/jvm/constant/StringInfo.java b/group15/1507_977996067/src/task7/jvm/constant/StringInfo.java new file mode 100644 index 0000000000..0b601e3adb --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/constant/StringInfo.java @@ -0,0 +1,35 @@ +package task7.jvm.constant; + +import task7.jvm.print.ConstantInfoVisitor; + +public class StringInfo extends ConstantInfo { + private int type = ConstantInfo.STRING_INFO; + private int index; + + public StringInfo(ConstantPool pool) { + super(pool); + } + + public int getType() { + return type; + } + + @Override + public void accept(ConstantInfoVisitor visitor) { + visitor.visitStringInfo(this); + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + + public String toString() { + return this.getConstantPool().getUTF8String(index); + } + +} diff --git a/group15/1507_977996067/src/task7/jvm/constant/UTF8Info.java b/group15/1507_977996067/src/task7/jvm/constant/UTF8Info.java new file mode 100644 index 0000000000..53686ca0a8 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/constant/UTF8Info.java @@ -0,0 +1,45 @@ +package task7.jvm.constant; + +import task7.jvm.print.ConstantInfoVisitor; + +public class UTF8Info extends ConstantInfo { + private int type = ConstantInfo.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 getType() { + return type; + } + + @Override + public void accept(ConstantInfoVisitor visitor) { + visitor.visitUtf8Info(this); + } + + @Override + public String toString() { + return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value + ")]"; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + +} diff --git a/group15/1507_977996067/src/task7/jvm/field/Field.java b/group15/1507_977996067/src/task7/jvm/field/Field.java new file mode 100644 index 0000000000..989f3316c4 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/field/Field.java @@ -0,0 +1,48 @@ +package task7.jvm.field; + + +import task7.jvm.constant.ConstantPool; +import task7.jvm.constant.UTF8Info; +import task7.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 String toString() { + String name = ((UTF8Info) pool.getConstantInfo(this.nameIndex)).getValue(); + + String desc = ((UTF8Info) pool.getConstantInfo(this.descriptorIndex)).getValue(); + return name + ":" + desc; + } + + + public static Field parse(ConstantPool pool, ByteCodeIterator iter) { + + int accessFlag = iter.next2Bytes(); + int nameIndex = iter.next2Bytes(); + int descIndex = iter.next2Bytes(); + int attribCount = iter.next2Bytes(); + //System.out.println("field attribute count:"+ attribCount); + + Field f = new Field(accessFlag, nameIndex, descIndex, pool); + + if (attribCount > 0) { + throw new RuntimeException("Field Attribute has not been implemented"); + } + + return f; + } + +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task7/jvm/loader/ByteCodeIterator.java b/group15/1507_977996067/src/task7/jvm/loader/ByteCodeIterator.java new file mode 100644 index 0000000000..81c268cdc9 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/loader/ByteCodeIterator.java @@ -0,0 +1,56 @@ +package task7.jvm.loader; + +import task7.jvm.util.Util; + +import java.util.Arrays; + +public class ByteCodeIterator { + + private int position; + + private byte[] bytes; + + public ByteCodeIterator(byte[] bytes) { + this.bytes = bytes; + } + + public String getMagicNumber() { + position = 0; + byte[] bytes = Arrays.copyOf(this.bytes, 4); + position += 4; + return Util.byteToHexString(bytes); + } + + public int next2Bytes() { + return nextBytes(2); + } + + public int next4Bytes() { + return nextBytes(4); + } + + public int nextFlag() { + return nextBytes(1); + } + + public void back(int length) { + position -= length; + } + + public byte[] getBytes(int length) { + byte[] bytes = Arrays.copyOfRange(this.bytes, position, position + length); + position += length; + return bytes; + } + + public String nextUxToHexString(int length) { + return new String(getBytes(length)); + } + + private int nextBytes(int size) { + byte[] bytes = Arrays.copyOfRange(this.bytes, position, position + size); + position += size; + return Util.byteToInt(bytes); + } + +} diff --git a/group15/1507_977996067/src/task7/jvm/loader/ClassFileLoader.java b/group15/1507_977996067/src/task7/jvm/loader/ClassFileLoader.java new file mode 100644 index 0000000000..350d8b92f4 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/loader/ClassFileLoader.java @@ -0,0 +1,122 @@ +package task7.jvm.loader; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import task7.jvm.clz.ClassFile; + +import java.io.*; +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; + } + + 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 void addClassPath(String path) { + if (this.clzPaths.contains(path)) { + return; + } + + this.clzPaths.add(path); + + } + + + public String getClassPath() { + return StringUtils.join(this.clzPaths, ";"); + } + + public ClassFile loadClass(String className) { + byte[] codes = this.readBinaryCode(className); + ClassFileParser parser = new ClassFileParser(); + return parser.parse(codes); + + } + + + // ------------------------------backup------------------------ + public String getClassPath_V1() { + + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < this.clzPaths.size(); i++) { + buffer.append(this.clzPaths.get(i)); + if (i < this.clzPaths.size() - 1) { + buffer.append(";"); + } + } + return buffer.toString(); + } + + private byte[] loadClassFile_V1(String clzFileName) { + + BufferedInputStream bis = null; + + try { + + File f = new File(clzFileName); + + + bis = new BufferedInputStream(new FileInputStream(f)); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + + byte[] buffer = new byte[1024]; + int length = -1; + + while ((length = bis.read(buffer)) != -1) { + bos.write(buffer, 0, length); + } + + byte[] codes = bos.toByteArray(); + + return codes; + + } catch (IOException e) { + e.printStackTrace(); + + } finally { + if (bis != null) { + try { + bis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return null; + + } + + +} \ No newline at end of file diff --git a/group15/1507_977996067/src/task7/jvm/loader/ClassFileParser.java b/group15/1507_977996067/src/task7/jvm/loader/ClassFileParser.java new file mode 100644 index 0000000000..eeea785114 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/loader/ClassFileParser.java @@ -0,0 +1,112 @@ +package task7.jvm.loader; + +import task7.jvm.clz.AccessFlag; +import task7.jvm.clz.ClassFile; +import task7.jvm.clz.ClassIndex; +import task7.jvm.constant.*; +import task7.jvm.field.Field; +import task7.jvm.method.Method; + +import java.util.ArrayList; +import java.util.List; + +public class ClassFileParser { + + private ConstantPool constantPool; + + public ClassFile parse(byte[] codes) { + ClassFile classFile = new ClassFile(); + ByteCodeIterator iterator = new ByteCodeIterator(codes); + System.out.println(iterator.getMagicNumber()); + + classFile.setMinorVersion(iterator.next2Bytes()); + classFile.setMajorVersion(iterator.next2Bytes()); + + parseConstantPool(iterator); + classFile.setConstPool(constantPool); + classFile.setAccessFlag(parseAccessFlag(iterator)); + classFile.setClassIndex(parseClassIndex(iterator));//task5 over + + iterator.next2Bytes(); // interface + + classFile.setFields(parseFileds(iterator)); + classFile.setMethods(parseMethods(classFile, iterator));//task6 over + return classFile; + } + + + private AccessFlag parseAccessFlag(ByteCodeIterator iter) { + return new AccessFlag(iter.next2Bytes()); + } + + private ClassIndex parseClassIndex(ByteCodeIterator iter) { + ClassIndex clazIndex = new ClassIndex(); + clazIndex.setThisClassIndex(iter.next2Bytes()); + clazIndex.setSuperClassIndex(iter.next2Bytes()); + return clazIndex; + } + + private void parseConstantPool(ByteCodeIterator iter) { + int poolCount = iter.next2Bytes(); + ConstantPool pool = new ConstantPool(poolCount); + for (int i = 0; i < poolCount; i++) { + int tag = iter.nextFlag(); + if (tag == ConstantInfo.UTF8_INFO) { //utf-8 + int length = iter.next2Bytes(); + byte[] bytes = iter.getBytes(length); + UTF8Info utf8Info = new UTF8Info(pool); + utf8Info.setValue(new String(bytes)); + utf8Info.setLength(length); + pool.addConstantInfo(utf8Info); + } else if (tag == ConstantInfo.STRING_INFO) { + StringInfo stringInfo = new StringInfo(pool); + stringInfo.setIndex(iter.next2Bytes()); + pool.addConstantInfo(stringInfo); + } else if (tag == ConstantInfo.CLASS_INFO) { + ClassInfo classInfo = new ClassInfo(pool); + classInfo.setUtf8Index(iter.next2Bytes()); + pool.addConstantInfo(classInfo); + } else if (tag == ConstantInfo.FIELD_INFO) { + FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); + fieldRefInfo.setClassInfoIndex(iter.next2Bytes()); + fieldRefInfo.setNameAndTypeIndex(iter.next2Bytes()); + pool.addConstantInfo(fieldRefInfo); + } else if (tag == ConstantInfo.METHOD_INFO) { + MethodRefInfo methodRefInfo = new MethodRefInfo(pool); + methodRefInfo.setClassInfoIndex(iter.next2Bytes()); + methodRefInfo.setNameAndTypeIndex(iter.next2Bytes()); + pool.addConstantInfo(methodRefInfo); + } else if (tag == ConstantInfo.NAME_AND_TYPE_INFO) { + NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); + nameAndTypeInfo.setIndex1(iter.next2Bytes()); + nameAndTypeInfo.setIndex2(iter.next2Bytes()); + pool.addConstantInfo(nameAndTypeInfo); + } + } + this.constantPool = pool; + } + + private List parseFileds(ByteCodeIterator iter) { + int fieldCount = iter.next2Bytes(); + + List fieldList = new ArrayList<>(fieldCount); + + for (int i = 0; i < fieldCount; i++) { + Field f = Field.parse(constantPool, iter); + fieldList.add(f); + } + return fieldList; + } + + private List parseMethods(ClassFile classFile, ByteCodeIterator iter) { + int methodCount = iter.next2Bytes(); + + List methodList = new ArrayList<>(methodCount); + + for (int i = 0; i < methodCount; i++) { + Method m = Method.parse(classFile, iter); + methodList.add(m); + } + return methodList; + } +} diff --git a/group15/1507_977996067/src/task7/jvm/method/Method.java b/group15/1507_977996067/src/task7/jvm/method/Method.java new file mode 100644 index 0000000000..13643df703 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/method/Method.java @@ -0,0 +1,91 @@ +package task7.jvm.method; + +import task7.jvm.attr.AttributeInfo; +import task7.jvm.attr.CodeAttr; +import task7.jvm.clz.ClassFile; +import task7.jvm.constant.ConstantPool; +import task7.jvm.constant.UTF8Info; +import task7.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.next2Bytes(); + int nameIndex = iter.next2Bytes(); + int descIndex = iter.next2Bytes(); + int attribCount = iter.next2Bytes(); + + + Method m = new Method(clzFile, accessFlag, nameIndex, descIndex); + + for (int j = 1; j <= attribCount; j++) { + + int attrNameIndex = iter.next2Bytes(); + 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/group15/1507_977996067/src/task7/jvm/print/ClassFilePrinter.java b/group15/1507_977996067/src/task7/jvm/print/ClassFilePrinter.java new file mode 100644 index 0000000000..3f4607a044 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/print/ClassFilePrinter.java @@ -0,0 +1,44 @@ +package task7.jvm.print; + +import task7.jvm.clz.ClassFile; +import task7.jvm.loader.ClassFileLoader; + +public class ClassFilePrinter { + ClassFile clzFile = null; + + public ClassFilePrinter(ClassFile clzFile) { + this.clzFile = clzFile; + } + + public void print() { + + if (clzFile.getAccessFlag().isPublicClass()) { + System.out.println("Access flag : public "); + } + System.out.println("Class Name:" + clzFile.getClassName()); + + System.out.println("Super Class Name:" + clzFile.getSuperClassName()); + + System.out.println("minor version:" + clzFile.getMinorVersion()); + + System.out.println("major version:" + clzFile.getMinorVersion()); + + ConstantPoolPrinter cnstPoolPrinter = new ConstantPoolPrinter(clzFile.getConstantPool()); + cnstPoolPrinter.print(); + + + } + + public static void main(String[] args) { + String path = "C:\\Users\\liuxin\\git\\coding2017\\liuxin\\mini-jvm\\bin"; + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path); + String className = "com.coderising.jvm.test.EmployeeV1"; + + ClassFile clzFile = loader.loadClass(className); + + ClassFilePrinter printer = new ClassFilePrinter(clzFile); + + printer.print(); + } +} diff --git a/group15/1507_977996067/src/task7/jvm/print/ConstantInfoVisitor.java b/group15/1507_977996067/src/task7/jvm/print/ConstantInfoVisitor.java new file mode 100644 index 0000000000..40851fc1bf --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/print/ConstantInfoVisitor.java @@ -0,0 +1,18 @@ +package task7.jvm.print; + +import task7.jvm.constant.*; + +public interface ConstantInfoVisitor { + + void visitClassInfo(ClassInfo classInfo); + + void visitFieldRefInfo(FieldRefInfo fieldRefInfo); + + void visitMethodRefInfo(MethodRefInfo methodRefInfo); + + void visitNameAndTypeInfo(NameAndTypeInfo nameAndTypeInfo); + + void visitStringInfo(StringInfo stringInfo); + + void visitUtf8Info(UTF8Info utf8Info); +} diff --git a/group15/1507_977996067/src/task7/jvm/print/ConstantInfoVisitorImpl.java b/group15/1507_977996067/src/task7/jvm/print/ConstantInfoVisitorImpl.java new file mode 100644 index 0000000000..776d23bc79 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/print/ConstantInfoVisitorImpl.java @@ -0,0 +1,51 @@ +package task7.jvm.print; + +import task7.jvm.constant.*; + +public class ConstantInfoVisitorImpl implements ConstantInfoVisitor { + @Override + public void visitClassInfo(ClassInfo classInfo) { + StringBuilder sb = new StringBuilder(); + sb.append("Class\t#").append(classInfo.getUtf8Index()).append("\t").append(classInfo.getClassName()); + System.out.println(sb); + } + + @Override + public void visitFieldRefInfo(FieldRefInfo fieldRefInfo) { + StringBuilder sb = new StringBuilder(); + sb.append("FieldRef\t#").append(fieldRefInfo.getClassInfoIndex()).append("\t").append(fieldRefInfo.getFieldName()); + System.out.println(sb); + + } + + @Override + public void visitMethodRefInfo(MethodRefInfo methodRefInfo) { + StringBuilder sb = new StringBuilder(); + sb.append("MethodRef\t#").append(methodRefInfo.getMethodName()); + System.out.println(sb); + } + + @Override + public void visitNameAndTypeInfo(NameAndTypeInfo nameAndTypeInfo) { + StringBuilder sb = new StringBuilder(); + sb.append("NameAndType\t#").append(nameAndTypeInfo.getName()).append("\t") + .append(nameAndTypeInfo.getIndex1()).append("\t") + .append(nameAndTypeInfo.getIndex2()).append("\t") + .append(nameAndTypeInfo.getTypeInfo()); + System.out.println(sb); + } + + @Override + public void visitStringInfo(StringInfo stringInfo) { + StringBuilder sb = new StringBuilder(); + sb.append("String\t#").append(stringInfo.getIndex()); + System.out.println(sb); + } + + @Override + public void visitUtf8Info(UTF8Info utf8Info) { + StringBuilder sb = new StringBuilder(); + sb.append("UTF8\t#").append(utf8Info.getValue()); + System.out.println(sb); + } +} diff --git a/group15/1507_977996067/src/task7/jvm/print/ConstantPoolPrinter.java b/group15/1507_977996067/src/task7/jvm/print/ConstantPoolPrinter.java new file mode 100644 index 0000000000..d6e87cad83 --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/print/ConstantPoolPrinter.java @@ -0,0 +1,26 @@ +package task7.jvm.print; + +import task7.jvm.constant.ConstantInfo; +import task7.jvm.constant.ConstantPool; + +public class ConstantPoolPrinter { + + private ConstantPool pool; + + ConstantPoolPrinter(ConstantPool pool) { + this.pool = pool; + } + + public void print() { + + System.out.println("Constant Pool:"); + + ConstantInfoVisitor visitor = new ConstantInfoVisitorImpl(); + int size = (int) pool.getSize(); + for (int i = 0; i < size; i++) { + System.out.print("#" + i + "= "); + ConstantInfo constantInfo = pool.getConstantInfo(i); + constantInfo.accept(visitor); + } + } +} diff --git a/group15/1507_977996067/src/task7/jvm/test/ClassFileloaderTest.java b/group15/1507_977996067/src/task7/jvm/test/ClassFileloaderTest.java new file mode 100644 index 0000000000..53bea9b04e --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/test/ClassFileloaderTest.java @@ -0,0 +1,191 @@ +package task7.jvm.test; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import task7.jvm.clz.ClassFile; +import task7.jvm.clz.ClassIndex; +import task7.jvm.constant.*; +import task7.jvm.loader.ClassFileLoader; + +public class ClassFileloaderTest { + + + private static final String FULL_QUALIFIED_CLASS_NAME = "EmployeeV1"; + + static String path1 = "E:\\Idea\\coding2017\\group15\\1507_977996067\\out\\task5\\jvm\\test"; + static String path2 = "C:\temp"; + + static ClassFile clzFile = null; + static { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "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 = "EmployeeV1"; + + byte[] byteCodes = loader.readBinaryCode(className); + + // 注意:这个字节数可能和你的JVM版本有关系, 你可以看看编译好的类到底有多大 + Assert.assertEquals(1038, byteCodes.length); + + } + + + @Test + public void testMagicNumber() { + ClassFileLoader loader = new ClassFileLoader(); + loader.addClassPath(path1); + String className = "EmployeeV1"; + byte[] byteCodes = loader.readBinaryCode(className); + byte[] codes = new byte[]{byteCodes[0], byteCodes[1], byteCodes[2], byteCodes[3]}; + + String actualValue = this.byteToHexString(codes); + + Assert.assertEquals("cafebabe", actualValue); + } + + + private 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(); + } + + /** + * ---------------------------------------------------------------------- + */ + + + @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.getUtf8Index()); + + UTF8Info utf8Info = (UTF8Info) pool.getConstantInfo(2); + Assert.assertEquals(FULL_QUALIFIED_CLASS_NAME, utf8Info.getValue()); + } + { + ClassInfo clzInfo = (ClassInfo) pool.getConstantInfo(3); + Assert.assertEquals(4, clzInfo.getUtf8Index()); + + 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.getIndex1()); + Assert.assertEquals(14, nameAndType.getIndex2()); + } + //抽查几个吧 + { + 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()); + } + + +} diff --git a/group15/1507_977996067/src/task7/jvm/test/EmployeeV1.java b/group15/1507_977996067/src/task7/jvm/test/EmployeeV1.java new file mode 100644 index 0000000000..866b94811a --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/test/EmployeeV1.java @@ -0,0 +1,29 @@ +package task7.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/group15/1507_977996067/src/task7/jvm/util/Util.java b/group15/1507_977996067/src/task7/jvm/util/Util.java new file mode 100644 index 0000000000..60158ac03a --- /dev/null +++ b/group15/1507_977996067/src/task7/jvm/util/Util.java @@ -0,0 +1,23 @@ +package task7.jvm.util; + +public class Util { + public static int byteToInt(byte[] codes){ + String s1 = byteToHexString(codes); + return Integer.valueOf(s1, 16); + } + + + public static String byteToHexString(byte[] codes ){ + StringBuffer buffer = new StringBuffer(); + for(int i=0;i