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);
+ }
+
}