分析Item例子1:
class Parent { /* <init>() { super(); // JCES树节点,Item(void) px = 0; // JCES树节点,AssignItem(lhs = MemberItem(px)) } */ int px = 0; } public class Test07 extends Parent { /* public <init>() { super(); // JCES树节点,Item(void) px = 1; // JCES树节点,AssignItem(lhs = MemberItem(px)) } */ int px = 1; public void t() { String[] a = new String[10]; a[0] = "str"; // JCES树节点,AssignItem(lhs = IndexedItem(object)) String b = a[0]; int subx = this.px; int superx = super.px; if (b == "str") { instanceMethod(); // JCES树节点,Item(void) } else { staticMethod(); // JCES树节点,StackItem(int) } // JCES树节点,item=AssignItem(lhs = MemberItem(px)) px++; new String(); // JCES树节点,StackItem(object) // (Object)new String(); // 这样的书写形式不被允许 } public void instanceMethod() {} public static int staticMethod() { return 0; } }
在访问Gen类的visitExec(JCExpressionStatement tree) 方法时,首先知道哪些表达式可能是ExpressionStatement,如下上下文无关方法:
ExpressionStatement: StatementExpression ; StatementExpression: Assignment PreIncrementExpression PreDecrementExpression PostIncrementExpression PostDecrementExpression MethodInvocation ClassInstanceCreationExpression
对于StackItem来说,调用drop()后为空实现,不需要将方法的返回值压入栈,也不需要存储到本地变量表。对于AssignItem的drop()方法的实现如下:
public void drop() { lhs.store(); }
来说要看lhs,而lhs可能是如下几种情况:
AssignmentExpression: ConditionalExpression Assignment Assignment: LeftHandSide AssignmentOperator AssignmentExpression LeftHandSide: ExpressionName FieldAccess ArrayAccess AssignmentOperator: one of = *= /= %= += -= <<= >>= >>>= &= ^= |=
所以只可能是IndexedItem、MemberItem与LocalItem、StaticItem这几项,调用其 store()方法:
(1)IndexedItem项的store()方法实现如下:
public void store() { items.code.emitop0(iastore + typecode); }
(2)MemberItem项的store()方法实现如下。
public void store() { int poolIndex = items.pool.put(member); items.code.emitop2(putfield, poolIndex); }
MemberItem代表实例成员或者实例方法,在这里不可能为实例方法。因为方法返回的类型是VAL而并非VAR。
(3)LocalItem项的store()方法实现如下。
如在方法中声明如下
int b; b = 3;
其LocalItem的store()方法的实现如下:
public void store() { if (reg <= 3) { int opcode = istore_0 + Code.truncate(typecode) * 4 + reg; items.code.emitop0(opcode); }else { int opcode = istore + Code.truncate(typecode); items.code.emitop1w(opcode, reg); } // 往本地变量表中存储局部变量,关于store指令的压入只在这里有,其它地方没有 // 这个在本地变量表中存储的变量通过store拿到了赋值,所以生命周期开始了 items.code.setDefined(reg); }
(4)StaticItem项的store()方法实现如下。
public void store() { int i = items.pool.put(member); items.code.emitop2(putstatic, i); }
对如下的例子进行分析,例子如下:
class Parent{ int px = 0; } public class Test08 extends Parent{ int px = 1; public void t(){ String[] a = new String[10]; a[0] = "str"; String b = a[0]; int subx = this.px; int superx = super.px; if(b=="str"){ instanceMethod(); }else{ staticMethod(); } } public void instanceMethod(){} public static void staticMethod(){} }
1、super()语句
调用链为visitExec(JCExpressionStatement tree)->visitIdentifier(JCIdentifier tree),其中tree的参数如下截图。
生成SelfItem后调用load()方法,压入指令aload_0,返回StackItem(object)后放弃,在stack中压入的类型为UninitializedType类型。
生成MemberItem(Parent() nonvirtual)后做为result结果,从visitIdentifier()方法中返回。为的是调用父类的构造函数,这个MemberItem如下截图。
调用MemberItem的invoke()方法,常量池中放入父类构造函数,生成invokespecial调用指令。
返回Item(void),是因为调用方法后返回的就是void类型,调用这个类型的drop()方法,这个方法无任何操作。
2、px=1语句
调用visitIdentifier(JCIdentifier tree)方法,处理px关键字,其参数如下截图所示。
生成SelfItem(this)并调用其load()方法,压入指令aload_0。返回StackItem(object)。
生成MemberItem,这是由于px是个实例变量。
生成ImmediateItem(1)并调用其load()方法,压入指令iconst_1,返回StackItem(int)。
生成AssignItem,各参数值如下截图。
调用AssignItem的drop()方法,这个方法会调用MemberItem的store()方法,将px变量加入常量池后,压入指令putfield。
最后生成的字节码如下:
public com.test19.Test08(); flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method com/test19/Parent."<init>":()V 4: aload_0 5: iconst_1 6: putfield #2 // Field px:I 9: return
3、String[] a = new String[10]语句
生成ImmediateItem(10)后调用load()方法,压入bipush指令,返回StackItem(int),舍弃。
将类型String放到常量池中,压入anewarray指令,生成StackItem(object),调用load()方法,由于本来是栈内的内容,所以方法调用后无任何改变。
生成LocalItem,各参数的值如下截图。
调用store()方法,压入astore_1指令。最终的字节码如下:
0: bipush 10 2: anewarray #3 // class java/lang/String 5: astore_1
4、a[0] = "str"语句
语法树结构如下截图。
生成localItem(type=java.lang.String[]; reg=1),调用load()方法将aload_1指令压入栈。返回stack(object),舍弃。
生成immediate(0),调用load()方法,压入iconst_0指令,返回stack(int),舍弃。
生成indexed(object),如下截图所示。
生成immediate(str),调用load()方法,压入ldc1指令,返回stack(object),舍弃。
生成assign(lhs = indexed(object)),如下截图所示。
调用drop()方法,这个方法会调用MemberItem的store()方法,压入指令aastore。
最终生成的class文件内容如下:
6: aload_1 7: iconst_0 8: ldc #4 // String str 10: aastore
5、String b = a[0]语句
生成localItem(type=java.lang.String[]; reg=1),调用load()方法,压入指令aload_1,返回StackItem(object),舍弃。
生成immediate(0),调用load()方法,压入iconst_0指令,返回StackItem(int),舍弃。
生成indexed(object),调用load()方法,压入aaload指令,返回StackItem(object),舍弃。
生成localItem(type=java.lang.String; reg=2),调用store()方法,压入astore_2指令。
最终生成的class内容如下:
11: aload_1 12: iconst_0 13: aaload 14: astore_2
6、int subx = this.px
生成SelfItem(this),调用load()方法,压入aload_0指令,生成StackItem(object),舍弃。
生成member(px),调用load()方法,将px放入常量池,压入指令getfield,生成StackItem(int),舍弃。
生成localItem(type=int; reg=3),调用store()方法,压入指令istore_3。
最终生成的class内容如下:
15: aload_0 16: getfield #2 // Field px:I 19: istore_3
7、if(b=="str"){instanceMethod();}else{staticMethod();}
生成的class文件内容如下:
26: aload_2 27: ldc #4 // String str 29: if_acmpne 39 32: aload_0 33: invokevirtual #6 // Method instanceMethod:()V 36: goto 42 39: invokestatic #7 // Method staticMethod:()V
7.1、b=="str"
生成localItem(type=java.lang.String; reg=2),调用load()方法后,压入aload_2指令,返回StackItem(object),舍弃。
生成immediate(str),调用load()方法,压入ldc1指令,返回StackItem(object),舍弃。
生成cond(if_acmpeq),调用mkCond()方法,无任何操作。
调用jumpFalse()方法,
7.2、instanceMethod()语句
生成SelfItem(this),调用load()方法,压入aload_0指令,返回StackItem(object),舍弃。
生成member(instanceMethod()), 调用invoke()方法,将instanceMethod()方法存储到常量池中,压入invokevirtual指令。生成Item(void),调用drop()方法,无任何操作。
压入goto_指令
7.3、staticMethod()语句
生成static(staticMethod()), 调用invoke()方法,将staticMethod()方法存储到常量池中,压入invokestatic指令。在压入指令的过程中会处理pendingJumps
生成Item(void),调用drop()方法,无任何操作。
压入goto_指令
8、方法返回
压入return_指令之前要解决thenExit