processBlock@Ropper.java
--->sim.simulate
其中,
for (int off = bb.getStart(); off < end; /*off*/) {
int length = code.parseInstruction(off, visitor);
visitor.setPreviousOffset(off);
off += length;
}
parseInstruction@BytecodeArray.java
此处的各种visitXXXX与 整理综合之一-----。。。。对应的指令应该是一样的,不过,此时的visitor已经不是BasicBlocker,而是SimVistor
下面讨论一下SimVistor中的各个visitXXX等方法。
1.
visitNoArgs
代码里稍微注释了machine的几个方法
private class SimVisitor implements BytecodeArray.Visitor {
/**
* {@code non-null;} machine instance to use (just to avoid excessive
* cross-object field access)
*/
private final Machine machine;
/**
* {@code null-ok;} frame to use; set with each call to
* {@link Simulator#simulate}
*/
private Frame frame;
/** offset of the previous bytecode */
private int previousOffset;
/**
* Constructs an instance.
*/
public SimVisitor() {
this.machine = Simulator.this.machine;
this.frame = null;
}
/**
* Sets the frame to act on.
*
* @param frame {@code non-null;} the frame
*/
public void setFrame(Frame frame) {
if (frame == null) {
throw new NullPointerException("frame == null");
}
this.frame = frame;
}
/** {@inheritDoc} */
public void visitInvalid(int opcode, int offset, int length) {
throw new SimException("invalid opcode " + Hex.u1(opcode));
}
/** {@inheritDoc} */
public void visitNoArgs(int opcode, int offset, int length,
Type type) {
switch (opcode) {
case ByteOps.NOP: {
machine.clearArgs();
break;
}
case ByteOps.INEG: {
machine.popArgs(frame, type);//popArgs最后都会调用popArgs(frame,count);
//从stack中pop到args[]并更新argCount@BaseMachine.java
break;
}
case ByteOps.I2L:
case ByteOps.I2F:
case ByteOps.I2D:
case ByteOps.I2B:
case ByteOps.I2C:
case ByteOps.I2S: {
machine.popArgs(frame, Type.INT);
break;
}
case ByteOps.L2I:
case ByteOps.L2F:
case ByteOps.L2D: {
machine.popArgs(frame, Type.LONG);
break;
}
case ByteOps.F2I:
case ByteOps.F2L:
case ByteOps.F2D: {
machine.popArgs(frame, Type.FLOAT);
break;
}
case ByteOps.D2I:
case ByteOps.D2L:
case ByteOps.D2F: {
machine.popArgs(frame, Type.DOUBLE);
break;
}
case ByteOps.RETURN: {
machine.clearArgs();
//初始argCount auxType auxInt auxCst auxTarget auxCases auxInitValues localIndex localTarget resultCount
checkReturnType(Type.VOID);
break;
}
case ByteOps.IRETURN: {
Type checkType = type;
if (type == Type.OBJECT) {
/*
* For an object return, use the best-known
* type of the popped value.
*/
checkType = frame.getStack().peekType(0);
}
machine.popArgs(frame, type);
checkReturnType(checkType);
break;
}
case ByteOps.POP: {
Type peekType = frame.getStack().peekType(0);
if (peekType.isCategory2()) {
throw illegalTos();
}
machine.popArgs(frame, 1);
break;
}
case ByteOps.ARRAYLENGTH: {
Type arrayType = frame.getStack().peekType(0);
if (!arrayType.isArrayOrKnownNull()) {
throw new SimException("type mismatch: expected " +
"array type but encountered " +
arrayType.toHuman());
}
machine.popArgs(frame, Type.OBJECT);
break;
}
case ByteOps.ATHROW:
case ByteOps.MONITORENTER:
case ByteOps.MONITOREXIT: {
machine.popArgs(frame, Type.OBJECT);
break;
}
case ByteOps.IALOAD: {
/*
* Change the type (which is to be pushed) to
* reflect the actual component type of the array
* being popped, unless it turns out to be a
* known-null, in which case we just use the type
* implied by the original instruction.
*/
Type foundArrayType = frame.getStack().peekType(1);
Type requireArrayType;
if (foundArrayType != Type.KNOWN_NULL) {
requireArrayType = foundArrayType;
type = foundArrayType.getComponentType();
} else {
requireArrayType = type.getArrayType();
}
machine.popArgs(frame, requireArrayType, Type.INT);
break;
}
case ByteOps.IADD:
case ByteOps.ISUB:
case ByteOps.IMUL:
case ByteOps.IDIV:
case ByteOps.IREM:
case ByteOps.IAND:
case ByteOps.IOR:
case ByteOps.IXOR: {
machine.popArgs(frame, type, type);
break;
}
case ByteOps.ISHL:
case ByteOps.ISHR:
case ByteOps.IUSHR: {
machine.popArgs(frame, type, Type.INT);
break;
}
case ByteOps.LCMP: {
machine.popArgs(frame, Type.LONG, Type.LONG);
break;
}
case ByteOps.FCMPL:
case ByteOps.FCMPG: {
machine.popArgs(frame, Type.FLOAT, Type.FLOAT);
break;
}
case ByteOps.DCMPL:
case ByteOps.DCMPG: {
machine.popArgs(frame, Type.DOUBLE, Type.DOUBLE);
break;
}
case ByteOps.IASTORE: {
/*
* Change the type (which is the type of the
* element) to reflect the actual component type
* of the array being popped, unless it turns out
* to be a known-null, in which case we just use
* the type implied by the original instruction.
* The category 1 vs. 2 thing here is that, if the
* element type is category 2, we have to skip over
* one extra stack slot to find the array.
*/
Type foundArrayType =
frame.getStack().peekType(type.isCategory1() ? 2 : 3);
Type requireArrayType;
if (foundArrayType != Type.KNOWN_NULL) {
requireArrayType = foundArrayType;
type = foundArrayType.getComponentType();
} else {
requireArrayType = type.getArrayType();
}
machine.popArgs(frame, requireArrayType, Type.INT, type);
break;
}
case ByteOps.POP2:
case ByteOps.DUP2: {
ExecutionStack stack = frame.getStack();
int pattern;
if (stack.peekType(0).isCategory2()) {
// "form 2" in vmspec-2
machine.popArgs(frame, 1);
pattern = 0x11;
} else if (stack.peekType(1).isCategory1()) {
// "form 1"
machine.popArgs(frame, 2);
pattern = 0x2121;
} else {
throw illegalTos();
}
if (opcode == ByteOps.DUP2) {
machine.auxIntArg(pattern);//auxInt = value;@BaseMachine.java
}
break;
}
case ByteOps.DUP: {
Type peekType = frame.getStack().peekType(0);
if (peekType.isCategory2()) {
throw illegalTos();
}
machine.popArgs(frame, 1);
machine.auxIntArg(0x11);
break;
}
case ByteOps.DUP_X1: {
ExecutionStack stack = frame.getStack();
if (! (stack.peekType(0).isCategory1() &&
stack.peekType(1).isCategory1())) {
throw illegalTos();
}
machine.popArgs(frame, 2);
machine.auxIntArg(0x212);
break;
}
case ByteOps.DUP_X2: {
ExecutionStack stack = frame.getStack();
if (stack.peekType(0).isCategory2()) {
throw illegalTos();
}
if (stack.peekType(1).isCategory2()) {
// "form 2" in vmspec-2
machine.popArgs(frame, 2);
machine.auxIntArg(0x212);
} else if (stack.peekType(2).isCategory1()) {
// "form 1"
machine.popArgs(frame, 3);
machine.auxIntArg(0x3213);
} else {
throw illegalTos();
}
break;
}
case ByteOps.DUP2_X1: {
ExecutionStack stack = frame.getStack();
if (stack.peekType(0).isCategory2()) {
// "form 2" in vmspec-2
if (stack.peekType(2).isCategory2()) {
throw illegalTos();
}
machine.popArgs(frame, 2);
machine.auxIntArg(0x212);
} else {
// "form 1"
if (stack.peekType(1).isCategory2() ||
stack.peekType(2).isCategory2()) {
throw illegalTos();
}
machine.popArgs(frame, 3);
machine.auxIntArg(0x32132);
}
break;
}
case ByteOps.DUP2_X2: {
ExecutionStack stack = frame.getStack();
if (stack.peekType(0).isCategory2()) {
if (stack.peekType(2).isCategory2()) {
// "form 4" in vmspec-2
machine.popArgs(frame, 2);
machine.auxIntArg(0x212);
} else if (stack.peekType(3).isCategory1()) {
// "form 2"
machine.popArgs(frame, 3);
machine.auxIntArg(0x3213);
} else {
throw illegalTos();
}
} else if (stack.peekType(1).isCategory1()) {
if (stack.peekType(2).isCategory2()) {
// "form 3"
machine.popArgs(frame, 3);
machine.auxIntArg(0x32132);
} else if (stack.peekType(3).isCategory1()) {
// "form 1"
machine.popArgs(frame, 4);
machine.auxIntArg(0x432143);
} else {
throw illegalTos();
}
} else {
throw illegalTos();
}
break;
}
case ByteOps.SWAP: {
ExecutionStack stack = frame.getStack();
if (! (stack.peekType(0).isCategory1() &&
stack.peekType(1).isCategory1())) {
throw illegalTos();
}
machine.popArgs(frame, 2);
machine.auxIntArg(0x12);
break;
}
default: {
visitInvalid(opcode, offset, length);
return;
}
}
machine.auxType(type);//auxType = type;@BaseMachine.java
machine.run(frame, offset, opcode);//这个是个大家伙,前面有分析,不够全面
}
2.visitConstant@Simulator.java
多了个 machine.auxCstArg(cst);//auxCst = cst;@BaseMachine.java
3.其他的visitXXX ,差不多的样子
4.machine.run这个调用很关键那,每个visitXXX都会有的
machine.run(frame, offset, opcode); //此时的opcode为bytecode@ByteOps.java