From fb595861c298cf4f64c787043bd6c9ef51bf599d Mon Sep 17 00:00:00 2001 From: liangduoduo666666 <798277403@qq.com> Date: Sat, 13 May 2017 12:39:45 +0800 Subject: [PATCH] =?UTF-8?q?zl=E7=9A=84=E7=AC=AC=E5=85=AD=E4=B8=83=E5=91=A8?= =?UTF-8?q?=E4=BD=9C=E4=B8=9A=E8=A1=A5=E4=BA=A4=EF=BC=8Cjvm=E5=AF=B9?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=96=B9=E6=B3=95=EF=BC=8C=E5=AD=97=E8=8A=82?= =?UTF-8?q?=E7=A0=81=E7=9A=84=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zhouliang/litestruts/struts.xml | 11 ++ .../src/basic/stack/expr/InfixExpr.java | 70 ++++++++ .../src/basic/stack/expr/InfixExprTest.java | 51 ++++++ .../src/basic/stack/expr/InfixToPostfix.java | 75 ++++++++ .../basic/stack/expr/InfixToPostfixTest.java | 41 +++++ .../src/basic/stack/expr/PostfixExpr.java | 60 +++++++ .../src/basic/stack/expr/PostfixExprTest.java | 41 +++++ .../src/basic/stack/expr/PrefixExpr.java | 83 +++++++++ .../src/basic/stack/expr/PrefixExprTest.java | 45 +++++ .../798277403/src/basic/stack/expr/Token.java | 52 ++++++ .../src/basic/stack/expr/TokenParser.java | 57 ++++++ .../src/basic/stack/expr/TokenParserTest.java | 41 +++++ group24/798277403/src/litestruts/struts.xml | 11 ++ .../src/mini_jvm/attr/AttributeInfo.java | 22 +++ .../798277403/src/mini_jvm/attr/CodeAttr.java | 106 ++++++++++++ .../src/mini_jvm/attr/LineNumberTable.java | 69 ++++++++ .../src/mini_jvm/attr/LocalVariableItem.java | 39 +++++ .../src/mini_jvm/attr/LocalVariableTable.java | 59 +++++++ .../src/mini_jvm/attr/StackMapTable.java | 30 ++++ .../798277403/src/mini_jvm/clz/ClassFile.java | 57 +++++- .../798277403/src/mini_jvm/cmd/BiPushCmd.java | 30 ++++ .../src/mini_jvm/cmd/ByteCodeCommand.java | 153 +++++++++++++++++ .../src/mini_jvm/cmd/CommandParser.java | 162 ++++++++++++++++++ .../src/mini_jvm/cmd/GetFieldCmd.java | 29 ++++ .../src/mini_jvm/cmd/GetStaticFieldCmd.java | 28 +++ .../src/mini_jvm/cmd/InvokeSpecialCmd.java | 30 ++++ .../src/mini_jvm/cmd/InvokeVirtualCmd.java | 29 ++++ .../798277403/src/mini_jvm/cmd/LdcCmd.java | 38 ++++ .../src/mini_jvm/cmd/NewObjectCmd.java | 28 +++ .../src/mini_jvm/cmd/NoOperandCmd.java | 33 ++++ .../src/mini_jvm/cmd/OneOperandCmd.java | 30 ++++ .../src/mini_jvm/cmd/PutFieldCmd.java | 28 +++ .../src/mini_jvm/cmd/TwoOperandCmd.java | 67 ++++++++ .../src/mini_jvm/constant/ClassInfo.java | 5 + .../src/mini_jvm/constant/ConstantInfo.java | 14 +- .../src/mini_jvm/constant/ConstantPool.java | 2 +- .../src/mini_jvm/constant/FieldRefInfo.java | 5 + .../src/mini_jvm/constant/MethodRefInfo.java | 7 +- .../mini_jvm/constant/NameAndTypeInfo.java | 5 + .../mini_jvm/constant/NullConstantInfo.java | 8 +- .../src/mini_jvm/constant/StringInfo.java | 7 +- .../src/mini_jvm/constant/UTF8Info.java | 6 + .../src/mini_jvm/engine/ExecutionResult.java | 57 ++++++ .../src/mini_jvm/engine/ExecutorEngine.java | 31 ++++ .../798277403/src/mini_jvm/engine/Heap.java | 39 +++++ .../src/mini_jvm/engine/JavaObject.java | 71 ++++++++ .../src/mini_jvm/engine/MethodArea.java | 69 ++++++++ .../src/mini_jvm/engine/MiniJVM.java | 30 ++++ .../src/mini_jvm/engine/StackFrame.java | 96 +++++++++++ .../798277403/src/mini_jvm/field/Field.java | 48 ++++++ .../src/mini_jvm/loader/ClassFileParser.java | 35 ++++ .../798277403/src/mini_jvm/method/Method.java | 92 ++++++++++ .../src/mini_jvm/print/ClassFilePrinter.java | 45 +++++ .../mini_jvm/print/ConstantPoolPrinter.java | 79 +++++++++ .../print/ConstantPoolPrinterBad.java | 41 +++++ .../mini_jvm/test/ClassFileloaderTest.java | 159 ++++++++++++++++- 56 files changed, 2638 insertions(+), 18 deletions(-) create mode 100644 group24/798277403/out/production/zhouliang/litestruts/struts.xml create mode 100644 group24/798277403/src/basic/stack/expr/InfixExpr.java create mode 100644 group24/798277403/src/basic/stack/expr/InfixExprTest.java create mode 100644 group24/798277403/src/basic/stack/expr/InfixToPostfix.java create mode 100644 group24/798277403/src/basic/stack/expr/InfixToPostfixTest.java create mode 100644 group24/798277403/src/basic/stack/expr/PostfixExpr.java create mode 100644 group24/798277403/src/basic/stack/expr/PostfixExprTest.java create mode 100644 group24/798277403/src/basic/stack/expr/PrefixExpr.java create mode 100644 group24/798277403/src/basic/stack/expr/PrefixExprTest.java create mode 100644 group24/798277403/src/basic/stack/expr/Token.java create mode 100644 group24/798277403/src/basic/stack/expr/TokenParser.java create mode 100644 group24/798277403/src/basic/stack/expr/TokenParserTest.java create mode 100644 group24/798277403/src/litestruts/struts.xml create mode 100644 group24/798277403/src/mini_jvm/attr/AttributeInfo.java create mode 100644 group24/798277403/src/mini_jvm/attr/CodeAttr.java create mode 100644 group24/798277403/src/mini_jvm/attr/LineNumberTable.java create mode 100644 group24/798277403/src/mini_jvm/attr/LocalVariableItem.java create mode 100644 group24/798277403/src/mini_jvm/attr/LocalVariableTable.java create mode 100644 group24/798277403/src/mini_jvm/attr/StackMapTable.java create mode 100644 group24/798277403/src/mini_jvm/cmd/BiPushCmd.java create mode 100644 group24/798277403/src/mini_jvm/cmd/ByteCodeCommand.java create mode 100644 group24/798277403/src/mini_jvm/cmd/CommandParser.java create mode 100644 group24/798277403/src/mini_jvm/cmd/GetFieldCmd.java create mode 100644 group24/798277403/src/mini_jvm/cmd/GetStaticFieldCmd.java create mode 100644 group24/798277403/src/mini_jvm/cmd/InvokeSpecialCmd.java create mode 100644 group24/798277403/src/mini_jvm/cmd/InvokeVirtualCmd.java create mode 100644 group24/798277403/src/mini_jvm/cmd/LdcCmd.java create mode 100644 group24/798277403/src/mini_jvm/cmd/NewObjectCmd.java create mode 100644 group24/798277403/src/mini_jvm/cmd/NoOperandCmd.java create mode 100644 group24/798277403/src/mini_jvm/cmd/OneOperandCmd.java create mode 100644 group24/798277403/src/mini_jvm/cmd/PutFieldCmd.java create mode 100644 group24/798277403/src/mini_jvm/cmd/TwoOperandCmd.java create mode 100644 group24/798277403/src/mini_jvm/engine/ExecutionResult.java create mode 100644 group24/798277403/src/mini_jvm/engine/ExecutorEngine.java create mode 100644 group24/798277403/src/mini_jvm/engine/Heap.java create mode 100644 group24/798277403/src/mini_jvm/engine/JavaObject.java create mode 100644 group24/798277403/src/mini_jvm/engine/MethodArea.java create mode 100644 group24/798277403/src/mini_jvm/engine/MiniJVM.java create mode 100644 group24/798277403/src/mini_jvm/engine/StackFrame.java create mode 100644 group24/798277403/src/mini_jvm/field/Field.java create mode 100644 group24/798277403/src/mini_jvm/method/Method.java create mode 100644 group24/798277403/src/mini_jvm/print/ClassFilePrinter.java create mode 100644 group24/798277403/src/mini_jvm/print/ConstantPoolPrinter.java create mode 100644 group24/798277403/src/mini_jvm/print/ConstantPoolPrinterBad.java diff --git a/group24/798277403/out/production/zhouliang/litestruts/struts.xml b/group24/798277403/out/production/zhouliang/litestruts/struts.xml new file mode 100644 index 0000000000..ba03a9d20d --- /dev/null +++ b/group24/798277403/out/production/zhouliang/litestruts/struts.xml @@ -0,0 +1,11 @@ + + + + /jsp/homepage.jsp + /jsp/showLogin.jsp + + + /jsp/welcome.jsp + /jsp/error.jsp + + diff --git a/group24/798277403/src/basic/stack/expr/InfixExpr.java b/group24/798277403/src/basic/stack/expr/InfixExpr.java new file mode 100644 index 0000000000..2b395d87f5 --- /dev/null +++ b/group24/798277403/src/basic/stack/expr/InfixExpr.java @@ -0,0 +1,70 @@ +package basic.stack.expr; + +import java.util.List; +import java.util.Stack; + +/** + * 中缀表达式求值 + */ +public class InfixExpr { + String expr = null; + + public InfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + TokenParser parser = new TokenParser(); + List tokens = parser.parse(this.expr); + + + Stack opStack = new Stack<>(); + Stack numStack = new Stack<>(); + + for(Token token : tokens){ + + if (token.isOperator()){ + //当运算符栈不为空,并且当前的操作符优先级不比栈顶操作符优先级高时,弹出栈顶操作符进行运算 + while(!opStack.isEmpty() + && !token.hasHigherPriority(opStack.peek())){ + Token prevOperator = opStack.pop(); + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + Float result = calculate(prevOperator.toString(), f1,f2); + numStack.push(result); + } + opStack.push(token); + } + if(token.isNumber()){ + numStack.push(new Float(token.getIntValue())); + } + } + + while(!opStack.isEmpty()){ + Token token = opStack.pop(); + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + numStack.push(calculate(token.toString(), f1,f2)); + } + + + return numStack.pop().floatValue(); + } + + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); + } + +} diff --git a/group24/798277403/src/basic/stack/expr/InfixExprTest.java b/group24/798277403/src/basic/stack/expr/InfixExprTest.java new file mode 100644 index 0000000000..67f6f08060 --- /dev/null +++ b/group24/798277403/src/basic/stack/expr/InfixExprTest.java @@ -0,0 +1,51 @@ +package basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InfixExprTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testEvaluate() { + //InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); + { + InfixExpr expr = new InfixExpr("2+3*4+5"); + Assert.assertEquals(19.0, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); + Assert.assertEquals(100.0, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("3*20/2"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("20/2*3"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + + { + InfixExpr expr = new InfixExpr("10-30+50"); + Assert.assertEquals(30, expr.evaluate(), 0.001f); + } + { + InfixExpr expr = new InfixExpr("10-2*3+50"); + Assert.assertEquals(54, expr.evaluate(), 0.001f); + } + + } + +} diff --git a/group24/798277403/src/basic/stack/expr/InfixToPostfix.java b/group24/798277403/src/basic/stack/expr/InfixToPostfix.java new file mode 100644 index 0000000000..438d8bb37b --- /dev/null +++ b/group24/798277403/src/basic/stack/expr/InfixToPostfix.java @@ -0,0 +1,75 @@ +package basic.stack.expr; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class InfixToPostfix { + + public static List convert(String expr) { + List inFixTokens = new TokenParser().parse(expr); + List postFixTokens = new ArrayList<>(); + Stack opStack = new Stack(); + + for(Token token : inFixTokens){ + if(token.isNumber()){ + postFixTokens.add(token); + } + if(token.isOperator()){ + while(!opStack.isEmpty() && !token.hasHigherPriority(opStack.peek())){ + postFixTokens.add(opStack.pop()); + } + opStack.push(token); + } + if(token.toString().equals("(")){ + opStack.push(token); + } + if(token.toString().equals(")")){ + while(!opStack.peek().value.equals(")")){ + postFixTokens.add(opStack.pop()); + } + opStack.pop(); + } + } + while(!opStack.isEmpty()){ + postFixTokens.add(opStack.pop()); + } + return postFixTokens; + } + + + public static List convert1(String expr) { + List inFixTokens = new TokenParser().parse(expr); + + List postFixTokens = new ArrayList<>(); + + Stack opStack = new Stack(); + for(Token token : inFixTokens){ + + if(token.isOperator()){ + + while(!opStack.isEmpty() + && !token.hasHigherPriority(opStack.peek())){ + postFixTokens.add(opStack.pop()); + + } + opStack.push(token); + + } + if(token.isNumber()){ + + postFixTokens.add(token); + + } + } + + while(!opStack.isEmpty()){ + postFixTokens.add(opStack.pop()); + } + + return postFixTokens; + } + + + +} diff --git a/group24/798277403/src/basic/stack/expr/InfixToPostfixTest.java b/group24/798277403/src/basic/stack/expr/InfixToPostfixTest.java new file mode 100644 index 0000000000..b5584851de --- /dev/null +++ b/group24/798277403/src/basic/stack/expr/InfixToPostfixTest.java @@ -0,0 +1,41 @@ +package basic.stack.expr; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + + + +public class InfixToPostfixTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testConvert() { + { + List tokens = InfixToPostfix.convert("2+3"); + Assert.assertEquals("[2, 3, +]", tokens.toString()); + } + { + + List tokens = InfixToPostfix.convert("2+3*4"); + Assert.assertEquals("[2, 3, 4, *, +]", tokens.toString()); + } + + { + + List tokens = InfixToPostfix.convert("2-3*4+5"); + Assert.assertEquals("[2, 3, 4, *, -, 5, +]", tokens.toString()); + } + } + +} diff --git a/group24/798277403/src/basic/stack/expr/PostfixExpr.java b/group24/798277403/src/basic/stack/expr/PostfixExpr.java new file mode 100644 index 0000000000..b9aab26059 --- /dev/null +++ b/group24/798277403/src/basic/stack/expr/PostfixExpr.java @@ -0,0 +1,60 @@ +package basic.stack.expr; + +import java.util.List; +import java.util.Stack; + +public class PostfixExpr { +String expr = null; + + public PostfixExpr(String expr) { + this.expr = expr; + } + + public float evaluate() { + TokenParser parser = new TokenParser(); + List tokens = parser.parse(this.expr); + + Stack opStack = new Stack<>(); + Stack numStack = new Stack<>(); + for(Token token : tokens){ + if(token.isNumber()){ + numStack.push(new Float(token.getIntValue())); + } + if(token.isOperator()){ + if(numStack.size()>=2){ + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + Float result = calculate(token.toString(), f1,f2); + numStack.push(result); + }else{ + opStack.push(token); + } + } + } + + while(!opStack.isEmpty()){ + Token token = opStack.pop(); + Float f2 = numStack.pop(); + Float f1 = numStack.pop(); + Float result = calculate(token.toString(), f1,f2); + numStack.push(result); + } + return numStack.pop().floatValue(); + } + + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); + } +} diff --git a/group24/798277403/src/basic/stack/expr/PostfixExprTest.java b/group24/798277403/src/basic/stack/expr/PostfixExprTest.java new file mode 100644 index 0000000000..641635398a --- /dev/null +++ b/group24/798277403/src/basic/stack/expr/PostfixExprTest.java @@ -0,0 +1,41 @@ +package basic.stack.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/group24/798277403/src/basic/stack/expr/PrefixExpr.java b/group24/798277403/src/basic/stack/expr/PrefixExpr.java new file mode 100644 index 0000000000..740ce8b788 --- /dev/null +++ b/group24/798277403/src/basic/stack/expr/PrefixExpr.java @@ -0,0 +1,83 @@ +package basic.stack.expr; + +import java.util.List; +import java.util.Stack; + +public class PrefixExpr { + String expr = null; + + public PrefixExpr(String expr) { + this.expr = expr; + } + +/* public float evaluate() { + TokenParser parser = new TokenParser(); + List tokens = parser.parse(this.expr); + Stack opStack = new Stack<>(); + Stack numStack = new Stack<>(); + + for(int i=tokens.size()-1; i>=0; i--){ + Token token = tokens.get(i); + if(token.isNumber()){ + numStack.push(new Float(token.getIntValue())); + } + if(token.isOperator()){ + Float f1 = numStack.pop(); + Float f2 = numStack.pop(); + Float result = calculate(token.toString(),f1,f2); + numStack.push(result); + } + } + + while(!opStack.isEmpty()){ + Token token = opStack.pop(); + Float f1 = numStack.pop(); + Float f2 = numStack.pop(); + Float result = calculate(token.toString(),f1,f2); + numStack.push(result); + } + System.out.println(numStack.peek()); + return numStack.pop().floatValue(); + }*/ + + + public float evaluate() { + TokenParser parser = new TokenParser(); + List tokens = parser.parse(this.expr); + + Stack exprStack = new Stack<>(); + Stack numStack = new Stack<>(); + for(Token token : tokens){ + exprStack.push(token); + } + + while(!exprStack.isEmpty()){ + Token t = exprStack.pop(); + if(t.isNumber()){ + numStack.push(new Float(t.getIntValue())); + }else{ + Float f1 = numStack.pop(); + Float f2 = numStack.pop(); + numStack.push(calculate(t.toString(),f1,f2)); + + } + } + return numStack.pop().floatValue(); + } + + private Float calculate(String op, Float f1, Float f2){ + if(op.equals("+")){ + return f1+f2; + } + if(op.equals("-")){ + return f1-f2; + } + if(op.equals("*")){ + return f1*f2; + } + if(op.equals("/")){ + return f1/f2; + } + throw new RuntimeException(op + " is not supported"); + } +} diff --git a/group24/798277403/src/basic/stack/expr/PrefixExprTest.java b/group24/798277403/src/basic/stack/expr/PrefixExprTest.java new file mode 100644 index 0000000000..4d4c42c368 --- /dev/null +++ b/group24/798277403/src/basic/stack/expr/PrefixExprTest.java @@ -0,0 +1,45 @@ +package basic.stack.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/group24/798277403/src/basic/stack/expr/Token.java b/group24/798277403/src/basic/stack/expr/Token.java new file mode 100644 index 0000000000..459e44bc47 --- /dev/null +++ b/group24/798277403/src/basic/stack/expr/Token.java @@ -0,0 +1,52 @@ +package basic.stack.expr; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +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).intValue(); + } + + + 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/group24/798277403/src/basic/stack/expr/TokenParser.java b/group24/798277403/src/basic/stack/expr/TokenParser.java new file mode 100644 index 0000000000..2feb36520f --- /dev/null +++ b/group24/798277403/src/basic/stack/expr/TokenParser.java @@ -0,0 +1,57 @@ +package basic.stack.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/group24/798277403/src/basic/stack/expr/TokenParserTest.java b/group24/798277403/src/basic/stack/expr/TokenParserTest.java new file mode 100644 index 0000000000..9f9feb447e --- /dev/null +++ b/group24/798277403/src/basic/stack/expr/TokenParserTest.java @@ -0,0 +1,41 @@ +package basic.stack.expr; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class TokenParserTest { + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void test() { + + TokenParser parser = new TokenParser(); + List tokens = parser.parse("300*20+12*5-20/4"); + + Assert.assertEquals(300, tokens.get(0).getIntValue()); + Assert.assertEquals("*", tokens.get(1).toString()); + Assert.assertEquals(20, tokens.get(2).getIntValue()); + Assert.assertEquals("+", tokens.get(3).toString()); + Assert.assertEquals(12, tokens.get(4).getIntValue()); + Assert.assertEquals("*", tokens.get(5).toString()); + Assert.assertEquals(5, tokens.get(6).getIntValue()); + Assert.assertEquals("-", tokens.get(7).toString()); + Assert.assertEquals(20, tokens.get(8).getIntValue()); + Assert.assertEquals("/", tokens.get(9).toString()); + Assert.assertEquals(4, tokens.get(10).getIntValue()); + } + +} diff --git a/group24/798277403/src/litestruts/struts.xml b/group24/798277403/src/litestruts/struts.xml new file mode 100644 index 0000000000..ba03a9d20d --- /dev/null +++ b/group24/798277403/src/litestruts/struts.xml @@ -0,0 +1,11 @@ + + + + /jsp/homepage.jsp + /jsp/showLogin.jsp + + + /jsp/welcome.jsp + /jsp/error.jsp + + diff --git a/group24/798277403/src/mini_jvm/attr/AttributeInfo.java b/group24/798277403/src/mini_jvm/attr/AttributeInfo.java new file mode 100644 index 0000000000..796141c499 --- /dev/null +++ b/group24/798277403/src/mini_jvm/attr/AttributeInfo.java @@ -0,0 +1,22 @@ +package mini_jvm.attr; + +/** + * 属性表 + */ +public abstract class AttributeInfo { + public static final String CODE = "Code"; //Java代码编译成的字节码指令 + public static final String CONST_VALUE = "ConstantValue"; //final关键字定义的常量值 + public static final String EXCEPTIONS = "Exceptions"; //方法抛出的异常 + public static final String LINE_NUM_TABLE = "LineNumberTable"; //Java源码的行号和字节码指令的对应关系 + 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/group24/798277403/src/mini_jvm/attr/CodeAttr.java b/group24/798277403/src/mini_jvm/attr/CodeAttr.java new file mode 100644 index 0000000000..07df10d251 --- /dev/null +++ b/group24/798277403/src/mini_jvm/attr/CodeAttr.java @@ -0,0 +1,106 @@ +package mini_jvm.attr; + + +import mini_jvm.clz.ClassFile; +import mini_jvm.cmd.ByteCodeCommand; +import mini_jvm.cmd.CommandParser; +import mini_jvm.constant.ConstantPool; +import mini_jvm.loader.ByteCodeIterator; + +public class CodeAttr extends AttributeInfo { + private int maxStack ; //操作数栈的最大深度 + private int maxLocals ; //局部变量表所需要的存储空间 + private int codeLen ; //字节码长度 + private String code; //字节码 + private ByteCodeCommand[] cmds ; //字节码指令 + private LineNumberTable lineNumTable; + private LocalVariableTable localVarTable; + private StackMapTable stackMapTable; + + public String getCode() { + return code; + } + public ByteCodeCommand[] getCmds() { + return cmds; + } + 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); + ByteCodeCommand[] cmds = CommandParser.parse(clzFile,code);//解析字节码指令 + + CodeAttr codeAttr = new CodeAttr(attrNameIndex,attrLen,maxStack,maxStack,codeLen,code,cmds); + int exceptionTableLen = iter.nextU2ToInt(); //异常表长度 + if(exceptionTableLen>0){ + String exTable = iter.nextUxToHexString(exceptionTableLen); + //这里对异常表不做处理 + System.out.println("Encountered exception table , just ignore it :" + exTable); + } + + int subAttrCount = iter.nextU2ToInt(); //Code属性的子属性总数 + for(int x=1; x<=subAttrCount; x++){ + int subAttrIndex = iter.nextU2ToInt(); //子属性的索引 + String subAttrName = clzFile.getConstantPool().getUTF8String(subAttrIndex); //得到子属性的名称 + + //已经向前移动了U2, 现在退回去。 + iter.back(2); + //根据子属性的名称,分别解析 + if(AttributeInfo.LINE_NUM_TABLE.equalsIgnoreCase(subAttrName)){ + LineNumberTable t = LineNumberTable.parse(iter); + codeAttr.setLineNumberTable(t); + } else if(AttributeInfo.LOCAL_VAR_TABLE.equalsIgnoreCase(subAttrName)){ + LocalVariableTable t = LocalVariableTable.parse(iter); + codeAttr.setLocalVariableTable(t); + } else if (AttributeInfo.STACK_MAP_TABLE.equalsIgnoreCase(subAttrName)){ + StackMapTable t = StackMapTable.parse(iter); + codeAttr.setStackMapTable(t); + } else{ + throw new RuntimeException("Need code to process " + 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(); + + } + + + +} diff --git a/group24/798277403/src/mini_jvm/attr/LocalVariableItem.java b/group24/798277403/src/mini_jvm/attr/LocalVariableItem.java new file mode 100644 index 0000000000..d8b4385933 --- /dev/null +++ b/group24/798277403/src/mini_jvm/attr/LocalVariableItem.java @@ -0,0 +1,39 @@ +package mini_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/group24/798277403/src/mini_jvm/attr/LocalVariableTable.java b/group24/798277403/src/mini_jvm/attr/LocalVariableTable.java new file mode 100644 index 0000000000..dce26065fc --- /dev/null +++ b/group24/798277403/src/mini_jvm/attr/LocalVariableTable.java @@ -0,0 +1,59 @@ +package mini_jvm.attr; + + +import mini_jvm.constant.ConstantPool; +import mini_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(); + } +} diff --git a/group24/798277403/src/mini_jvm/attr/StackMapTable.java b/group24/798277403/src/mini_jvm/attr/StackMapTable.java new file mode 100644 index 0000000000..65b3b24c82 --- /dev/null +++ b/group24/798277403/src/mini_jvm/attr/StackMapTable.java @@ -0,0 +1,30 @@ +package mini_jvm.attr; + + +import mini_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/group24/798277403/src/mini_jvm/clz/ClassFile.java b/group24/798277403/src/mini_jvm/clz/ClassFile.java index 4cf756c090..c641d1eefb 100644 --- a/group24/798277403/src/mini_jvm/clz/ClassFile.java +++ b/group24/798277403/src/mini_jvm/clz/ClassFile.java @@ -3,14 +3,22 @@ import mini_jvm.constant.ClassInfo; import mini_jvm.constant.ConstantPool; +import mini_jvm.field.Field; +import mini_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 int minorVersion; //java次版本号 + private int majorVersion; //java主版本号 + private AccessFlag accessFlag; //访问标志,表示public等或者是接口等,包括类和父类的访问标志 + private ClassIndex clzIndex; //类索引和父类索引,用来确定类的继承关系 + private ConstantPool pool; //常量池,包括常量池总数和所有常量 + private List fields = new ArrayList(); //字段 + private List methods = new ArrayList(); //方法 + public ClassIndex getClzIndex() { return clzIndex; @@ -52,14 +60,47 @@ public void print(){ System.out.println("Class Name:"+ getClassName()); System.out.println("Super Class Name:"+ getSuperClassName()); } - - private String getClassName(){ + + public String getClassName(){ int thisClassIndex = this.clzIndex.getThisClassIndex(); ClassInfo thisClass = (ClassInfo)this.getConstantPool().getConstantInfo(thisClassIndex); return thisClass.getClassName(); } - private String getSuperClassName(){ + public String getSuperClassName(){ ClassInfo superClass = (ClassInfo)this.getConstantPool().getConstantInfo(this.clzIndex.getSuperClassIndex()); return superClass.getClassName(); } + + + 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 Method getMethod(String methodName, String paramAndReturnType){ + for(Method m :methods){ + int nameIndex = m.getNameIndex(); + int descriptionIndex = m.getDescriptorIndex(); + + String name = this.getConstantPool().getUTF8String(nameIndex); + String desc = this.getConstantPool().getUTF8String(descriptionIndex); + if(name.equals(methodName) && desc.equals(paramAndReturnType)){ + return m; + } + } + return null; + } + public Method getMainMethod(){ + return getMethod("main","([Ljava/lang/String;)V"); + } } diff --git a/group24/798277403/src/mini_jvm/cmd/BiPushCmd.java b/group24/798277403/src/mini_jvm/cmd/BiPushCmd.java new file mode 100644 index 0000000000..f07275d3c8 --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/BiPushCmd.java @@ -0,0 +1,30 @@ +package mini_jvm.cmd; + + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.ConstantPool; +import mini_jvm.engine.ExecutionResult; +import mini_jvm.engine.StackFrame; + +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(); + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + + } + + + +} diff --git a/group24/798277403/src/mini_jvm/cmd/ByteCodeCommand.java b/group24/798277403/src/mini_jvm/cmd/ByteCodeCommand.java new file mode 100644 index 0000000000..e9e3401010 --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/ByteCodeCommand.java @@ -0,0 +1,153 @@ +package mini_jvm.cmd; + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.ConstantInfo; +import mini_jvm.constant.ConstantPool; +import mini_jvm.engine.ExecutionResult; +import mini_jvm.engine.StackFrame; + +import java.util.HashMap; +import java.util.Map; + + + + +public abstract class ByteCodeCommand { + + String opCode; + ClassFile clzFile; + private int offset; + + public static final String aconst_null = "01"; + public static final String new_object = "BB"; //创建一个对象 + public static final String lstore = "37"; + public static final String invokespecial = "B7"; //对一个对象进行初始化, 父类的初始化, 调用私有方法 + public static final String invokevirtual = "B6"; //指令调用对象的实例方法(多态) + public static final String getfield = "B4"; + public static final String putfield = "B5"; //给一个对象的字段赋值 + public static final String getstatic = "B2"; + public static final String ldc = "12"; //从运行时常量池中提取数据压入栈中 + public static final String dup = "59"; //复制操作数栈栈顶的值,并压入到栈顶 + public static final String bipush = "10"; //将 byte 带符号扩展为一个 int 类型的值 value,然后将 value 压入到操作数栈中。 + public static final String aload_0 = "2A"; //从局部变量表中把index为0的reference的值加载到到操作数栈中 + 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"; //从局部变量表中把index为2的int类型的值加载到到操作数栈中 + 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"; //方法返回,从当前函数栈帧退出, 返回int + public static final String freturn = "AE"; //方法返回,从当前函数栈帧退出, 返回float + + public static final String astore_1 = "4C"; //将栈顶的reference 类型数据保存到局部变量表中 + + public static final String if_icmp_ge = "A2"; + public static final String if_icmple = "A4"; + public static final String goto_no_condition = "A7"; + public static final String iconst_0 = "03"; //将一个数值从操作数栈存储到局部变量表 + public static final String iconst_1 = "04"; + public static final String istore_1 = "3C"; + public static final String istore_2 = "3D"; + public static final String iadd = "60"; //加法指令 + public static final String iinc = "84"; //局部变量自增指令 + private static Map codeMap = new HashMap(); + + static{ + codeMap.put("01", "aconst_null"); + + codeMap.put("BB", "new"); + codeMap.put("37", "lstore"); + codeMap.put("B7", "invokespecial"); + codeMap.put("B6", "invokevirtual"); + codeMap.put("B4", "getfield"); + codeMap.put("B5", "putfield"); + codeMap.put("B2", "getstatic"); + + codeMap.put("2A", "aload_0"); + codeMap.put("2B", "aload_1"); + codeMap.put("2C", "aload_2"); + + codeMap.put("10", "bipush"); + codeMap.put("15", "iload"); + codeMap.put("1A", "iload_0"); + codeMap.put("1B", "iload_1"); + codeMap.put("1C", "iload_2"); + codeMap.put("1D", "iload_3"); + + codeMap.put("25", "fload_3"); + + codeMap.put("1E", "lload_0"); + + codeMap.put("24", "fload_2"); + codeMap.put("4C", "astore_1"); + + codeMap.put("A2", "if_icmp_ge"); + codeMap.put("A4", "if_icmple"); + + codeMap.put("A7", "goto"); + + codeMap.put("B1", "return"); + codeMap.put("AC", "ireturn"); + codeMap.put("AE", "freturn"); + + codeMap.put("03", "iconst_0"); + codeMap.put("04", "iconst_1"); + + codeMap.put("3C", "istore_1"); + codeMap.put("3D", "istore_2"); + + codeMap.put("59", "dup"); + + codeMap.put("60", "iadd"); + codeMap.put("84", "iinc"); + + codeMap.put("12", "ldc"); + } + + + protected ByteCodeCommand(ClassFile clzFile, String opCode){ + this.clzFile = clzFile; + this.opCode = opCode; + } + + protected ClassFile getClassFile() { + return clzFile; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + protected ConstantInfo getConstantInfo(int index){ + return this.getClassFile().getConstantPool().getConstantInfo(index); + } + + protected ConstantPool getConstantPool(){ + return this.getClassFile().getConstantPool(); + } + + + + public String getOpCode() { + return opCode; + } + + public abstract int getLength(); + + public String getReadableCodeText(){ + String txt = codeMap.get(opCode); + if(txt == null){ + return opCode; + } + return txt; + } + public abstract String toString(ConstantPool pool); + + public abstract void execute(StackFrame frame,ExecutionResult result); +} diff --git a/group24/798277403/src/mini_jvm/cmd/CommandParser.java b/group24/798277403/src/mini_jvm/cmd/CommandParser.java new file mode 100644 index 0000000000..af57520f46 --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/CommandParser.java @@ -0,0 +1,162 @@ +package mini_jvm.cmd; + +import mini_jvm.clz.ClassFile; + +import java.util.ArrayList; +import java.util.List; + + +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"; + + /** + * 将codes字符串解析成字节码指令(指令有多种,操作数个数有1,2,3个) + * @param clzFile classFile引用 + * @param codes 方法字节码 + * @return 字节码指令 + */ + public static ByteCodeCommand[] parse(ClassFile clzFile, String codes) { + if ((codes == null) || (codes.length() == 0) || (codes.length() % 2) != 0) { + throw new RuntimeException("the orignal code is not correct"); + } + codes = codes.toUpperCase(); + + CommandIterator iter = new CommandIterator(codes); + List cmds = new ArrayList(); + + while (iter.hasNext()) { + String opCode = iter.next2CharAsString(); + if (ByteCodeCommand.new_object.equals(opCode)) { + NewObjectCmd cmd = new NewObjectCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (ByteCodeCommand.invokespecial.equals(opCode)) { + InvokeSpecialCmd cmd = new InvokeSpecialCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (ByteCodeCommand.invokevirtual.equals(opCode)) { + InvokeVirtualCmd cmd = new InvokeVirtualCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (ByteCodeCommand.getfield.equals(opCode)) { + GetFieldCmd cmd = new GetFieldCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (ByteCodeCommand.getstatic.equals(opCode)) { + GetStaticFieldCmd cmd = new GetStaticFieldCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (ByteCodeCommand.putfield.equals(opCode)) { + PutFieldCmd cmd = new PutFieldCmd(clzFile, opCode); + cmd.setOprand1(iter.next2CharAsInt()); + cmd.setOprand2(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (ByteCodeCommand.ldc.equals(opCode)) { + LdcCmd cmd = new LdcCmd(clzFile, opCode); + cmd.setOperand(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (ByteCodeCommand.bipush.equals(opCode)) { + BiPushCmd cmd = new BiPushCmd(clzFile, opCode); + cmd.setOperand(iter.next2CharAsInt()); + cmds.add(cmd); + } else if (ByteCodeCommand.dup.equals(opCode) + || ByteCodeCommand.aload_0.equals(opCode) + || ByteCodeCommand.aload_1.equals(opCode) + || ByteCodeCommand.aload_2.equals(opCode) + || ByteCodeCommand.iload_1.equals(opCode) + || ByteCodeCommand.iload_2.equals(opCode) + || ByteCodeCommand.iload_3.equals(opCode) + || ByteCodeCommand.fload_3.equals(opCode) + || ByteCodeCommand.voidreturn.equals(opCode) + || ByteCodeCommand.astore_1.equals(opCode)) { + + NoOperandCmd cmd = new NoOperandCmd(clzFile, opCode); + cmds.add(cmd); + } else { + throw new RuntimeException("Sorry, the java instruction " + opCode + " has not been implemented"); + } + + } + + calcuateOffset(cmds); + + ByteCodeCommand[] result = new ByteCodeCommand[cmds.size()]; + cmds.toArray(result); + return result; + } + + private static void calcuateOffset(List cmds) { + + int offset = 0; + for (ByteCodeCommand cmd : cmds) { + cmd.setOffset(offset); + offset += cmd.getLength(); + } + + } + + //每一个指令都是占两个字节,有的指令是对应常量池中的索引所以是int,有的是字符串 + 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).intValue(); + } + + } +} diff --git a/group24/798277403/src/mini_jvm/cmd/GetFieldCmd.java b/group24/798277403/src/mini_jvm/cmd/GetFieldCmd.java new file mode 100644 index 0000000000..743f892573 --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/GetFieldCmd.java @@ -0,0 +1,29 @@ +package mini_jvm.cmd; + + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.ConstantPool; +import mini_jvm.engine.ExecutionResult; +import mini_jvm.engine.StackFrame; + +public class GetFieldCmd extends TwoOperandCmd { + + public GetFieldCmd(ClassFile clzFile, String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + return super.getOperandAsField(pool); + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + + } + + + + +} diff --git a/group24/798277403/src/mini_jvm/cmd/GetStaticFieldCmd.java b/group24/798277403/src/mini_jvm/cmd/GetStaticFieldCmd.java new file mode 100644 index 0000000000..80c407441c --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/GetStaticFieldCmd.java @@ -0,0 +1,28 @@ +package mini_jvm.cmd; + + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.ConstantPool; +import mini_jvm.engine.ExecutionResult; +import mini_jvm.engine.StackFrame; + +public class GetStaticFieldCmd extends TwoOperandCmd { + + public GetStaticFieldCmd(ClassFile clzFile, String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + + } + +} diff --git a/group24/798277403/src/mini_jvm/cmd/InvokeSpecialCmd.java b/group24/798277403/src/mini_jvm/cmd/InvokeSpecialCmd.java new file mode 100644 index 0000000000..ea9e33785d --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/InvokeSpecialCmd.java @@ -0,0 +1,30 @@ +package mini_jvm.cmd; + + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.ConstantPool; +import mini_jvm.engine.ExecutionResult; +import mini_jvm.engine.StackFrame; + +public class InvokeSpecialCmd extends TwoOperandCmd { + + public InvokeSpecialCmd(ClassFile clzFile, String opCode) { + super(clzFile,opCode); + + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + + } + + + +} diff --git a/group24/798277403/src/mini_jvm/cmd/InvokeVirtualCmd.java b/group24/798277403/src/mini_jvm/cmd/InvokeVirtualCmd.java new file mode 100644 index 0000000000..5057132d8e --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/InvokeVirtualCmd.java @@ -0,0 +1,29 @@ +package mini_jvm.cmd; + + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.ConstantPool; +import mini_jvm.engine.ExecutionResult; +import mini_jvm.engine.StackFrame; + +public class InvokeVirtualCmd extends TwoOperandCmd { + + public InvokeVirtualCmd(ClassFile clzFile, String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsMethod(pool); + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + } + + + + +} diff --git a/group24/798277403/src/mini_jvm/cmd/LdcCmd.java b/group24/798277403/src/mini_jvm/cmd/LdcCmd.java new file mode 100644 index 0000000000..25a0ea5753 --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/LdcCmd.java @@ -0,0 +1,38 @@ +package mini_jvm.cmd; + + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.ConstantInfo; +import mini_jvm.constant.ConstantPool; +import mini_jvm.constant.StringInfo; +import mini_jvm.engine.ExecutionResult; +import mini_jvm.engine.StackFrame; + +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; + + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + + } + +} diff --git a/group24/798277403/src/mini_jvm/cmd/NewObjectCmd.java b/group24/798277403/src/mini_jvm/cmd/NewObjectCmd.java new file mode 100644 index 0000000000..56afe06698 --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/NewObjectCmd.java @@ -0,0 +1,28 @@ +package mini_jvm.cmd; + + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.ConstantPool; +import mini_jvm.engine.ExecutionResult; +import mini_jvm.engine.StackFrame; + +public class NewObjectCmd extends TwoOperandCmd{ + + public NewObjectCmd(ClassFile clzFile, String opCode){ + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsClassInfo(pool); + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + + } + + +} diff --git a/group24/798277403/src/mini_jvm/cmd/NoOperandCmd.java b/group24/798277403/src/mini_jvm/cmd/NoOperandCmd.java new file mode 100644 index 0000000000..0a2f285b12 --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/NoOperandCmd.java @@ -0,0 +1,33 @@ +package mini_jvm.cmd; + + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.ConstantPool; +import mini_jvm.engine.ExecutionResult; +import mini_jvm.engine.StackFrame; + +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; + } + + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + + } + +} diff --git a/group24/798277403/src/mini_jvm/cmd/OneOperandCmd.java b/group24/798277403/src/mini_jvm/cmd/OneOperandCmd.java new file mode 100644 index 0000000000..65ef9fe5e3 --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/OneOperandCmd.java @@ -0,0 +1,30 @@ +package mini_jvm.cmd; + + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.ConstantPool; + +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; + } + + + public abstract String toString(ConstantPool pool); +} diff --git a/group24/798277403/src/mini_jvm/cmd/PutFieldCmd.java b/group24/798277403/src/mini_jvm/cmd/PutFieldCmd.java new file mode 100644 index 0000000000..9e2d80a3c9 --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/PutFieldCmd.java @@ -0,0 +1,28 @@ +package mini_jvm.cmd; + + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.ConstantPool; +import mini_jvm.engine.ExecutionResult; +import mini_jvm.engine.StackFrame; + +public class PutFieldCmd extends TwoOperandCmd { + + public PutFieldCmd(ClassFile clzFile, String opCode) { + super(clzFile,opCode); + } + + @Override + public String toString(ConstantPool pool) { + + return super.getOperandAsField(pool); + } + + @Override + public void execute(StackFrame frame, ExecutionResult result) { + + + } + + +} diff --git a/group24/798277403/src/mini_jvm/cmd/TwoOperandCmd.java b/group24/798277403/src/mini_jvm/cmd/TwoOperandCmd.java new file mode 100644 index 0000000000..7ec4f5ee38 --- /dev/null +++ b/group24/798277403/src/mini_jvm/cmd/TwoOperandCmd.java @@ -0,0 +1,67 @@ +package mini_jvm.cmd; + + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.*; + +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; + } + + public abstract String toString(ConstantPool pool); + +} diff --git a/group24/798277403/src/mini_jvm/constant/ClassInfo.java b/group24/798277403/src/mini_jvm/constant/ClassInfo.java index ed39387440..0dfb4f790f 100644 --- a/group24/798277403/src/mini_jvm/constant/ClassInfo.java +++ b/group24/798277403/src/mini_jvm/constant/ClassInfo.java @@ -21,4 +21,9 @@ public String getClassName() { UTF8Info utf8Info = (UTF8Info)constantPool.getConstantInfo(index); return utf8Info.getValue(); } + + @Override + public void accept(Visitor visitor) { + visitor.visitClassInfo(this); + } } diff --git a/group24/798277403/src/mini_jvm/constant/ConstantInfo.java b/group24/798277403/src/mini_jvm/constant/ConstantInfo.java index d488321043..a54e152573 100644 --- a/group24/798277403/src/mini_jvm/constant/ConstantInfo.java +++ b/group24/798277403/src/mini_jvm/constant/ConstantInfo.java @@ -25,5 +25,17 @@ public ConstantPool getConstantPool() { public ConstantInfo getConstantInfo(int index){ return this.constantPool.getConstantInfo(index); } - + + + public abstract void accept(Visitor visitor); + + public static interface Visitor{ + public void visitClassInfo(ClassInfo info); + public void visitFieldRef(FieldRefInfo info); + public void visitMethodRef(MethodRefInfo info); + public void visitNameAndType(NameAndTypeInfo info); + public void visitString(StringInfo info); + public void visistUTF8(UTF8Info info); + + } } diff --git a/group24/798277403/src/mini_jvm/constant/ConstantPool.java b/group24/798277403/src/mini_jvm/constant/ConstantPool.java index c8d30c78db..0ed02dc4ac 100644 --- a/group24/798277403/src/mini_jvm/constant/ConstantPool.java +++ b/group24/798277403/src/mini_jvm/constant/ConstantPool.java @@ -21,7 +21,7 @@ public ConstantInfo getConstantInfo(int index){ public String getUTF8String(int index){ return ((UTF8Info)this.constantInfos.get(index)).getValue(); } - public Object getSize() { + public int getSize() { return this.constantInfos.size() -1; } } diff --git a/group24/798277403/src/mini_jvm/constant/FieldRefInfo.java b/group24/798277403/src/mini_jvm/constant/FieldRefInfo.java index 3d74c4244f..a1408735a8 100644 --- a/group24/798277403/src/mini_jvm/constant/FieldRefInfo.java +++ b/group24/798277403/src/mini_jvm/constant/FieldRefInfo.java @@ -51,4 +51,9 @@ public String getFieldType(){ NameAndTypeInfo typeInfo = (NameAndTypeInfo)this.getConstantInfo(this.getNameAndTypeIndex()); return typeInfo.getTypeInfo(); } + + @Override + public void accept(Visitor visitor) { + visitor.visitFieldRef(this); + } } diff --git a/group24/798277403/src/mini_jvm/constant/MethodRefInfo.java b/group24/798277403/src/mini_jvm/constant/MethodRefInfo.java index 4037881ad8..072378f568 100644 --- a/group24/798277403/src/mini_jvm/constant/MethodRefInfo.java +++ b/group24/798277403/src/mini_jvm/constant/MethodRefInfo.java @@ -49,7 +49,10 @@ public String getParamAndReturnType(){ NameAndTypeInfo typeInfo = (NameAndTypeInfo)pool.getConstantInfo(this.getNameAndTypeIndex()); return typeInfo.getTypeInfo(); } - - + + @Override + public void accept(Visitor visitor) { + visitor.visitMethodRef(this); + } } diff --git a/group24/798277403/src/mini_jvm/constant/NameAndTypeInfo.java b/group24/798277403/src/mini_jvm/constant/NameAndTypeInfo.java index badba119df..deeef73aa5 100644 --- a/group24/798277403/src/mini_jvm/constant/NameAndTypeInfo.java +++ b/group24/798277403/src/mini_jvm/constant/NameAndTypeInfo.java @@ -42,4 +42,9 @@ public String getTypeInfo(){ public String toString(){ return "(" + getName() + "," + getTypeInfo()+")"; } + + @Override + public void accept(Visitor visitor) { + visitor.visitNameAndType(this); + } } diff --git a/group24/798277403/src/mini_jvm/constant/NullConstantInfo.java b/group24/798277403/src/mini_jvm/constant/NullConstantInfo.java index 28d102c997..eaed795011 100644 --- a/group24/798277403/src/mini_jvm/constant/NullConstantInfo.java +++ b/group24/798277403/src/mini_jvm/constant/NullConstantInfo.java @@ -9,5 +9,11 @@ public NullConstantInfo(){ public int getType() { return -1; } - + + @Override + public void accept(Visitor visitor) { + + } + + } diff --git a/group24/798277403/src/mini_jvm/constant/StringInfo.java b/group24/798277403/src/mini_jvm/constant/StringInfo.java index 2a9387d247..5736eef352 100644 --- a/group24/798277403/src/mini_jvm/constant/StringInfo.java +++ b/group24/798277403/src/mini_jvm/constant/StringInfo.java @@ -10,7 +10,12 @@ public StringInfo(ConstantPool pool) { public int getType() { return type; } - + + @Override + public void accept(Visitor visitor) { + visitor.visitString(this); + } + public int getIndex() { return index; } diff --git a/group24/798277403/src/mini_jvm/constant/UTF8Info.java b/group24/798277403/src/mini_jvm/constant/UTF8Info.java index 6fc44f5355..0ad0e7ff7b 100644 --- a/group24/798277403/src/mini_jvm/constant/UTF8Info.java +++ b/group24/798277403/src/mini_jvm/constant/UTF8Info.java @@ -16,6 +16,12 @@ public void setLength(int length) { public int getType() { return type; } + + @Override + public void accept(Visitor visitor) { + visitor.visistUTF8(this); + } + @Override public String toString() { return "UTF8Info [type=" + type + ", length=" + length + ", value=" + value +")]"; diff --git a/group24/798277403/src/mini_jvm/engine/ExecutionResult.java b/group24/798277403/src/mini_jvm/engine/ExecutionResult.java new file mode 100644 index 0000000000..58c9d26dca --- /dev/null +++ b/group24/798277403/src/mini_jvm/engine/ExecutionResult.java @@ -0,0 +1,57 @@ +package mini_jvm.engine; + + +import mini_jvm.method.Method; + +public class ExecutionResult { + public static final int RUN_NEXT_CMD = 1; + public static final int JUMP = 2; + public static final int EXIT_CURRENT_FRAME = 3; + public static final int PAUSE_AND_RUN_NEW_FRAME = 4; + + private int nextAction = RUN_NEXT_CMD; + + private int nextCmdOffset = 0; + + private Method nextMethod; + + public Method getNextMethod() { + return nextMethod; + } + public void setNextMethod(Method nextMethod) { + this.nextMethod = nextMethod; + } + + + + public void setNextAction(int action){ + this.nextAction = action; + } + public boolean isPauseAndRunNewFrame(){ + return this.nextAction == PAUSE_AND_RUN_NEW_FRAME; + } + public boolean isExitCurrentFrame(){ + return this.nextAction == EXIT_CURRENT_FRAME; + } + + public boolean isRunNextCmd(){ + return this.nextAction == RUN_NEXT_CMD; + } + + public boolean isJump(){ + return this.nextAction == JUMP; + } + + public int getNextCmdOffset() { + return nextCmdOffset; + } + + public void setNextCmdOffset(int nextCmdOffset) { + this.nextCmdOffset = nextCmdOffset; + } + + + + + +} diff --git a/group24/798277403/src/mini_jvm/engine/ExecutorEngine.java b/group24/798277403/src/mini_jvm/engine/ExecutorEngine.java new file mode 100644 index 0000000000..260211376c --- /dev/null +++ b/group24/798277403/src/mini_jvm/engine/ExecutorEngine.java @@ -0,0 +1,31 @@ +package mini_jvm.engine; + +import mini_jvm.method.Method; + +import java.util.Stack; + + + +public class ExecutorEngine { + + private Stack stack = new Stack(); + + public ExecutorEngine() { + + } + + public void execute(Method mainMethod){ + + + + } + + + + private void setupFunctionCallParams(StackFrame currentFrame,StackFrame nextFrame) { + + + + } + +} diff --git a/group24/798277403/src/mini_jvm/engine/Heap.java b/group24/798277403/src/mini_jvm/engine/Heap.java new file mode 100644 index 0000000000..4a197b98f6 --- /dev/null +++ b/group24/798277403/src/mini_jvm/engine/Heap.java @@ -0,0 +1,39 @@ +package mini_jvm.engine; + +public class Heap { + + /** + * 没有实现垃圾回收, 所以对于下面新创建的对象, 并没有记录到一个数据结构当中 + */ + + private static Heap instance = new Heap(); + private Heap() { + } + public static Heap getInstance(){ + return instance; + } + public JavaObject newObject(String clzName){ + + JavaObject jo = new JavaObject(JavaObject.OBJECT); + jo.setClassName(clzName); + return jo; + } + + public JavaObject newString(String value){ + JavaObject jo = new JavaObject(JavaObject.STRING); + jo.setStringValue(value); + return jo; + } + + public JavaObject newFloat(float value){ + JavaObject jo = new JavaObject(JavaObject.FLOAT); + jo.setFloatValue(value); + return jo; + } + public JavaObject newInt(int value){ + JavaObject jo = new JavaObject(JavaObject.INT); + jo.setIntValue(value); + return jo; + } + +} diff --git a/group24/798277403/src/mini_jvm/engine/JavaObject.java b/group24/798277403/src/mini_jvm/engine/JavaObject.java new file mode 100644 index 0000000000..51185b1056 --- /dev/null +++ b/group24/798277403/src/mini_jvm/engine/JavaObject.java @@ -0,0 +1,71 @@ +package mini_jvm.engine; + +import java.util.HashMap; +import java.util.Map; + +public class JavaObject { + public static final int OBJECT = 1; + public static final int STRING = 2; + public static final int INT = 3; + public static final int FLOAT = 4; + + int type; + private String className; + + private Map fieldValues = new HashMap(); + + private String stringValue; + + private int intValue; + + private float floatValue; + + public void setFieldValue(String fieldName, JavaObject fieldValue){ + fieldValues.put(fieldName, fieldValue); + } + public JavaObject(int type){ + this.type = type; + } + public void setClassName(String className){ + this.className = className; + } + public void setStringValue(String value){ + stringValue = value; + } + public String getStringValue(){ + return this.stringValue; + } + public void setIntValue(int value) { + this.intValue = value; + } + public int getIntValue(){ + return this.intValue; + } + public int getType(){ + return type; + } + public JavaObject getFieldValue(String fieldName){ + return this.fieldValues.get(fieldName); + } + public String toString(){ + switch(this.getType()){ + case INT: + return String.valueOf(this.intValue); + case STRING: + return this.stringValue; + case OBJECT: + return this.className +":"+ this.fieldValues; + case FLOAT : + return String.valueOf(this.floatValue); + default: + return null; + } + } + public String getClassName(){ + return this.className; + } + public void setFloatValue(float value) { + this.floatValue = value; + } + +} diff --git a/group24/798277403/src/mini_jvm/engine/MethodArea.java b/group24/798277403/src/mini_jvm/engine/MethodArea.java new file mode 100644 index 0000000000..fd43904312 --- /dev/null +++ b/group24/798277403/src/mini_jvm/engine/MethodArea.java @@ -0,0 +1,69 @@ +package mini_jvm.engine; + +import mini_jvm.clz.ClassFile; +import mini_jvm.constant.MethodRefInfo; +import mini_jvm.loader.ClassFileLoader; +import mini_jvm.method.Method; + +import java.util.HashMap; +import java.util.Map; + + +public class MethodArea { + + public static final MethodArea instance = new MethodArea(); + + /** + * 注意:我们做了极大的简化, ClassLoader 只有一个, 实际JVM中的ClassLoader,是一个双亲委托的模型 + */ + + private ClassFileLoader clzLoader = null; + + Map map = new HashMap(); + + private MethodArea(){ + } + + public static MethodArea getInstance(){ + return instance; + } + + public void setClassFileLoader(ClassFileLoader clzLoader){ + this.clzLoader = clzLoader; + } + + public Method getMainMethod(String className){ + + ClassFile clzFile = this.findClassFile(className); + + return clzFile.getMainMethod(); + } + + + public ClassFile findClassFile(String className){ + + if(map.get(className) != null){ + return map.get(className); + } + // 看来该class 文件还没有load过 + ClassFile clzFile = this.clzLoader.loadClass(className); + + map.put(className, clzFile); + + return clzFile; + + } + + + public Method getMethod(String className, String methodName, String paramAndReturnType){ + + return null; + } + + + public Method getMethod(MethodRefInfo methodRef){ + + return null; + + } +} diff --git a/group24/798277403/src/mini_jvm/engine/MiniJVM.java b/group24/798277403/src/mini_jvm/engine/MiniJVM.java new file mode 100644 index 0000000000..6781fed5ad --- /dev/null +++ b/group24/798277403/src/mini_jvm/engine/MiniJVM.java @@ -0,0 +1,30 @@ +package mini_jvm.engine; + +import mini_jvm.loader.ClassFileLoader; + +import java.io.FileNotFoundException; +import java.io.IOException; + + + +public class MiniJVM { + + public void run(String[]classPaths , String className) throws FileNotFoundException, IOException{ + + ClassFileLoader loader = new ClassFileLoader(); + for(int i=0;i localVariableTable = new ArrayList(); + private Stack oprandStack = new Stack(); + + int index = 0; + + private Method m = null; + + private StackFrame callerFrame = null; + + public StackFrame getCallerFrame() { + return callerFrame; + } + + public void setCallerFrame(StackFrame callerFrame) { + this.callerFrame = callerFrame; + } + + + + + public static StackFrame create(Method m){ + + StackFrame frame = new StackFrame( m ); + + return frame; + } + + + private StackFrame(Method m) { + this.m = m; + + } + + + + public JavaObject getLocalVariableValue(int index){ + return this.localVariableTable.get(index); + } + + public Stack getOprandStack(){ + return this.oprandStack; + } + + public int getNextCommandIndex(int offset){ + + ByteCodeCommand[] cmds = m.getCodeAttr().getCmds(); + for(int i=0;i values){ + this.localVariableTable = values; + } + + public void setLocalVariableValue(int index, JavaObject jo){ + //问题: 为什么要这么做?? + if(this.localVariableTable.size()-1 < index){ + for(int i=this.localVariableTable.size(); i<=index; i++){ + this.localVariableTable.add(null); + } + } + this.localVariableTable.set(index, jo); + + + } + + public Method getMethod(){ + return m; + } + + +} diff --git a/group24/798277403/src/mini_jvm/field/Field.java b/group24/798277403/src/mini_jvm/field/Field.java new file mode 100644 index 0000000000..1c12093269 --- /dev/null +++ b/group24/798277403/src/mini_jvm/field/Field.java @@ -0,0 +1,48 @@ +package mini_jvm.field; + + +import mini_jvm.constant.ConstantPool; +import mini_jvm.constant.UTF8Info; +import mini_jvm.loader.ByteCodeIterator; + +public class Field { + private int accessFlag; //字段的修饰符,u2类型 + 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.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,pool); + + if(attribCount > 0){ + throw new RuntimeException("Field Attribute has not been implemented"); + } + + return f; + } + +} diff --git a/group24/798277403/src/mini_jvm/loader/ClassFileParser.java b/group24/798277403/src/mini_jvm/loader/ClassFileParser.java index ad2ca0cdf4..fad2e9583e 100644 --- a/group24/798277403/src/mini_jvm/loader/ClassFileParser.java +++ b/group24/798277403/src/mini_jvm/loader/ClassFileParser.java @@ -4,6 +4,8 @@ import mini_jvm.clz.ClassFile; import mini_jvm.clz.ClassIndex; import mini_jvm.constant.*; +import mini_jvm.field.Field; +import mini_jvm.method.Method; import java.io.UnsupportedEncodingException; @@ -35,6 +37,15 @@ public ClassFile parse(byte[] codes) { ClassIndex classIndex = parseClassInfex(iter); classFile.setClassIndex(classIndex); + //6 解析接口 + parseInterfaces(iter); + + //7 解析字段 + parseFileds(classFile, iter); + + //8 解析方法 + parseMethods(classFile, iter); + return classFile; } @@ -126,5 +137,29 @@ private ConstantPool parseConstantPool(ByteCodeIterator iter) { return constantPool; } + private void parseInterfaces(ByteCodeIterator iter) { + int interfaceCount = iter.nextU2ToInt(); + + System.out.println("interfaceCount:" + interfaceCount); + + // TODO : 如果实现了interface, 这里需要解析 + } + + private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { + int filedCount = iter.nextU2ToInt(); + for(int i=0; i 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); + } + + /** -----------------------下面是第五次jvm的测试------------------------ **/ + @Test + public void testByteCodeCommand(){ + { + Method initMethod = this.clzFile.getMethod("", "(Ljava/lang/String;I)V"); + ByteCodeCommand [] cmds = initMethod.getCmds(); + + assertOpCodeEquals("0: aload_0", cmds[0]); + assertOpCodeEquals("1: invokespecial #12", cmds[1]); + assertOpCodeEquals("4: aload_0", cmds[2]); + assertOpCodeEquals("5: aload_1", cmds[3]); + assertOpCodeEquals("6: putfield #15", cmds[4]); + assertOpCodeEquals("9: aload_0", cmds[5]); + assertOpCodeEquals("10: iload_2", cmds[6]); + assertOpCodeEquals("11: putfield #17", cmds[7]); + assertOpCodeEquals("14: return", cmds[8]); + } + + { + Method setNameMethod = this.clzFile.getMethod("setName", "(Ljava/lang/String;)V"); + ByteCodeCommand [] cmds = setNameMethod.getCmds(); + + assertOpCodeEquals("0: aload_0", cmds[0]); + assertOpCodeEquals("1: aload_1", cmds[1]); + assertOpCodeEquals("2: putfield #15", cmds[2]); + assertOpCodeEquals("5: return", cmds[3]); + + } + + { + Method sayHelloMethod = this.clzFile.getMethod("sayHello", "()V"); + ByteCodeCommand [] cmds = sayHelloMethod.getCmds(); + + assertOpCodeEquals("0: getstatic #28", cmds[0]); + assertOpCodeEquals("3: ldc #34", cmds[1]); + assertOpCodeEquals("5: invokevirtual #36", cmds[2]); + assertOpCodeEquals("8: return", cmds[3]); + + } + + { + Method mainMethod = this.clzFile.getMainMethod(); + + ByteCodeCommand [] cmds = mainMethod.getCmds(); + + assertOpCodeEquals("0: new #1", cmds[0]); + assertOpCodeEquals("3: dup", cmds[1]); + assertOpCodeEquals("4: ldc #43", cmds[2]); + assertOpCodeEquals("6: bipush 29", cmds[3]); + assertOpCodeEquals("8: invokespecial #45", cmds[4]); + assertOpCodeEquals("11: astore_1", cmds[5]); + assertOpCodeEquals("12: aload_1", cmds[6]); + assertOpCodeEquals("13: invokevirtual #47", cmds[7]); + assertOpCodeEquals("16: return", cmds[8]); + } + + } + + private void assertOpCodeEquals(String expected, ByteCodeCommand cmd){ + + String acctual = cmd.getOffset()+": "+cmd.getReadableCodeText(); + + if(cmd instanceof OneOperandCmd){ + if(cmd instanceof BiPushCmd){ + acctual += " " + ((OneOperandCmd)cmd).getOperand(); + } else{ + acctual += " #" + ((OneOperandCmd)cmd).getOperand(); + } + } + if(cmd instanceof TwoOperandCmd){ + acctual += " #" + ((TwoOperandCmd)cmd).getIndex(); + } + Assert.assertEquals(expected, acctual); + } + }