接上篇,我们从convertCode开始看
public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {
IrMethod irMethod = dex2ir(methodNode);//主要是创建了它的stmts 把dex类型的指令转换为ir类型的指令
optimize(irMethod);//对ir类型的指令进行优化
ir2j(irMethod, mv);//把优化后的Ir指令转换为java虚拟机指令
}
主要是3步,上面注释写的比较详细了
先看dex2ir
public IrMethod dex2ir(DexMethodNode methodNode) {
return new Dex2IRConverter()
.convert(0 != (methodNode.access & DexConstants.ACC_STATIC), methodNode.method, methodNode.codeNode);
}
新建一个Dex2IRConverter并调用它的convert
public IrMethod convert(boolean isStatic, Method method, DexCodeNode dexCodeNode) {
this.dexCodeNode = dexCodeNode;//设置DexCodeNode
IrMethod irMethod = new IrMethod();//创建一个IrMethod
irMethod.args = method.getParameterTypes();
irMethod.ret = method.getReturnType();
irMethod.owner = method.getOwner();
irMethod.name = method.getName();
irMethod.isStatic = isStatic;
target = irMethod;
insnList = dexCodeNode.stmts;
for (int i = 0; i < insnList.size(); i++) {//是否有标签
DexStmtNode stmtNode = insnList.get(i);
stmtNode.__index = i;//设置 __index
if (stmtNode instanceof DexLabelStmtNode) {
DexLabelStmtNode dexLabelStmtNode = (DexLabelStmtNode) stmtNode;
labelMap.put(dexLabelStmtNode.label, dexLabelStmtNode);
}
}
fixExceptionHandlers();//异常处理指令相关
BitSet[] exBranch = new BitSet[insnList.size()];
parentCount = new int[insnList.size()];
initParentCount(parentCount);//初始化parentCount
BitSet handlers = new BitSet(insnList.size());
initExceptionHandlers(dexCodeNode, exBranch, handlers);
DvmInterpreter interpreter = buildInterpreter();//创建一个DvmInterpreter
frames = new Dex2IrFrame[insnList.size()];//frames是指令的大小
emitStmts = new ArrayList[insnList.size()];//
BitSet access = new BitSet(insnList.size());//已经访问过的指令
dfs(exBranch, handlers, access, interpreter);
StmtList stmts = target.stmts;
stmts.addAll(preEmit);
for (int i = 0; i < insnList.size(); i++) {
DexStmtNode p = insnList.get(i);
if (access.get(i)) {
List es = emitStmts[i];
if (es != null) {
stmts.addAll(es);//添加到stmts
}
} else {
if (p instanceof DexLabelStmtNode) {
stmts.add(getLabel(((DexLabelStmtNode) p).label));
}
}
}
emitStmts = null;//emitStmts重新设置为null
Queue queue = new LinkedList<>();
for (int i1 = 0; i1 < frames.length; i1++) {
Dex2IrFrame frame = frames[i1];
if (parentCount[i1] > 1 && frame != null && access.get(i1)) {
for (int j = 0; j < frame.getTotalRegisters(); j++) {
DvmValue v = frame.getReg(j);
addToQueue(queue, v);
}
}
}
while (!queue.isEmpty()) {
DvmValue v = queue.poll();
getLocal(v);
if (v.parent != null) {
if (v.parent.local == null) {
queue.add(v.parent);
}
}
if (v.otherParent != null) {
for (DvmValue v2 : v.otherParent) {
if (v2.local == null) {
queue.add(v2);
}
}
}
}
Set phiValues = new HashSet<>();
List phiLabels = new ArrayList<>();
for (int i = 0; i < frames.length; i++) {
Dex2IrFrame frame = frames[i];
if (parentCount[i] > 1 && frame != null && access.get(i)) {
DexStmtNode p = insnList.get(i);
LabelStmt labelStmt = getLabel(((DexLabelStmtNode) p).label);
List phis = new ArrayList<>();
for (int j = 0; j < frame.getTotalRegisters(); j++) {
DvmValue v = frame.getReg(j);
addPhi(v, phiValues, phis);
}
labelStmt.phis = phis;
phiLabels.add(labelStmt);
}
}
if (phiLabels.size() > 0) {
target.phiLabels = phiLabels;//好像主要是后面指令优化时候要用
}
return target;
}
1、新建一个IrMethod
2、处理标签
3、处理异常指令
4、初始化parentCount,主要跟跳转等有关
5、调用dfs进行指令转换
6、把处理完的指令添加到target.stmts
我们看下dfs函数
private void dfs(BitSet[] exBranch, BitSet handlers, BitSet access, DvmInterpreter interpreter) {
currentEmit = preEmit;
Dex2IrFrame first = initFirstFrame(dexCodeNode, target);//初始化第一个帧
if (parentCount[0] > 1) {
merge(first, 0);
} else {
frames[0] = first;
}
Stack stack = new Stack<>();
stack.push(insnList.get(0));
Dex2IrFrame tmp = new Dex2IrFrame(dexCodeNode.totalRegister);//创建一个临时的帧
while (!stack.isEmpty()) {
DexStmtNode p = stack.pop();
int index = p.__index;//获取指令的索引index
if (!access.get(index)) {//是否已经处理过
access.set(index);
} else {
continue;
}
Dex2IrFrame frame = frames[index];//frames大小为dex指令的大小
setCurrentEmit(index);//如果为空则新建一个
if (p instanceof DexLabelStmtNode) {//标签指令节点
emit(getLabel(((DexLabelStmtNode) p).label));
if (handlers.get(index)) {
Local ex = newLocal();
emit(Stmts.nIdentity(ex, Exprs.nExceptionRef("Ljava/lang/Throwable;")));
frame.setTmp(new DvmValue(ex));
}
}
BitSet ex = exBranch[index];//跳转
if (ex != null) {
for (int i = ex.nextSetBit(0); i >= 0; i = ex.nextSetBit(i + 1)) {
merge(frame, i);
stack.push(insnList.get(i));
}
}
tmp.init(frame);//用frame初始化tmp
try {
if (p.op != null) {
switch (p.op) {
case RETURN_VOID:
emit(nReturnVoid());//添加一个ReturnVoidStmt
break;
case GOTO:
case GOTO_16:
case GOTO_32:
emit(nGoto(getLabel(((JumpStmtNode) p).label)));
break;
case NOP:
emit(nNop());
break;
case BAD_OP:
emit(nThrow(nInvokeNew(new Value[]{nString("bad dex opcode")}, new String[]{
"Ljava/lang/String;"},
"Ljava/lang/VerifyError;")));
break;
default:
tmp.execute(p, interpreter);//缺省情况执行execute tmp为Dex2IrFrame
break;
}
}
} catch (Exception exception) {
throw new RuntimeException("Fail on Op " + p.op + " index " + index, exception);
}
if (p.op != null) {
Op op = p.op;
if (op.canBranch()) {//分支指令,则把条件不满足时的指令偏移入栈
JumpStmtNode jump = (JumpStmtNode) p;
int targetIndex = indexOf(jump.label);
stack.push(insnList.get(targetIndex));
merge(tmp, targetIndex);
}
if (op.canSwitch()) {
BaseSwitchStmtNode switchStmtNode = (BaseSwitchStmtNode) p;
for (DexLabel label : switchStmtNode.labels) {
int targetIndex = indexOf(label);
stack.push(insnList.get(targetIndex));
merge(tmp, targetIndex);
}
}
if (op.canContinue()) {//继续下一条
stack.push(insnList.get(index + 1));//下一条指令入栈
merge(tmp, index + 1);//把temp和index+1进行merge
}
} else {
stack.push(insnList.get(index + 1));
merge(tmp, index + 1);
}
// cleanup frame it is useless
if (parentCount[index] <= 1) {//重新设置为null
frames[index] = null;
}
}
}
1、调用initFirstFrame初始化第一个帧
2、依次处理各条指令
我们先看initFirstFrame
private Dex2IrFrame initFirstFrame(DexCodeNode methodNode, IrMethod target) {
Dex2IrFrame first = new Dex2IrFrame(methodNode.totalRegister);//总的寄存器个数
int x = methodNode.totalRegister - methodArgCount(target.args);//减去参数使用的寄存器个数
if (!target.isStatic) {// not static 非静态方法第一个参数是this
Local thiz = newLocal();
emit(Stmts.nIdentity(thiz, Exprs.nThisRef(target.owner)));//新建一个this变量
first.setReg(x - 1, new DvmValue(thiz));//参数的前面一个寄存器摄者为this
}
for (int i = 0; i < target.args.length; i++) {//依次对应参数到寄存器,寄存器的下标依据添加的顺序
Local p = newLocal();
emit(Stmts.nIdentity(p, Exprs.nParameterRef(target.args[i], i)));
first.setReg(x, new DvmValue(p));
x += sizeofType(target.args[i]);//递增它的类型大小
}
if (initAllToZero) {//把所有寄存器的初始值设置为0
for (int i = 0; i < first.getTotalRegisters(); i++) {
if (first.getReg(i) == null) {
Local p = newLocal();//新建一个Local变量
emit(nAssign(p, nInt(0)));//以p和一个整型0参数新建一个AssignStmt并添加到currentEmit
first.setReg(i, new DvmValue(p));//以p为参数新建一个DvmValue,并以它为参数调用setReg 把局部变量包装成DvmValue设置到寄存器
}
}
}
return first;
}
这里新建一个Dex2IrFrame,参数是寄存器的个数
static class Dex2IrFrame extends DvmFrame {
public Dex2IrFrame(int totalRegister) {
super(totalRegister);
}
}
public DvmFrame(int totalRegister) {
values = (V[]) new Object[totalRegister];
}
然后如果是非静态方法,则新建一个this指针,然后调用setReg设置到指定索引寄存器
public void setReg(int i, V v) {
if (i > values.length || i < 0) {
return;
}
values[i] = v;
}
然后
for (int i = 0; i < target.args.length; i++) {//依次对应参数到寄存器,寄存器的下标依据添加的顺序
Local p = newLocal();
emit(Stmts.nIdentity(p, Exprs.nParameterRef(target.args[i], i)));
first.setReg(x, new DvmValue(p));
x += sizeofType(target.args[i]);//递增它的类型大小
}
为每个参数新建一个Local,并设置到Reg,
if (initAllToZero) {//把所有寄存器的初始值设置为0
for (int i = 0; i < first.getTotalRegisters(); i++) {
if (first.getReg(i) == null) {
Local p = newLocal();//新建一个Local变量
emit(nAssign(p, nInt(0)));//以p和一个整型0参数新建一个AssignStmt并添加到currentEmit
first.setReg(i, new DvmValue(p));//以p为参数新建一个DvmValue,并以它为参数调用setReg 把局部变量包装成DvmValue设置到寄存器
}
}
}
回到dfs,接下来处理各个指令
if (p.op != null) {
switch (p.op) {
case RETURN_VOID:
emit(nReturnVoid());//添加一个ReturnVoidStmt
break;
case GOTO:
case GOTO_16:
case GOTO_32:
emit(nGoto(getLabel(((JumpStmtNode) p).label)));
break;
case NOP:
emit(nNop());
break;
case BAD_OP:
emit(nThrow(nInvokeNew(new Value[]{nString("bad dex opcode")}, new String[]{
"Ljava/lang/String;"},
"Ljava/lang/VerifyError;")));
break;
default:
tmp.execute(p, interpreter);//缺省情况执行execute tmp为Dex2IrFrame
break;
}
除了几个特别的指令,其他的都调用execute进行处理
public void execute(DexStmtNode insn, DvmInterpreter interpreter) {
if (insn.op == null) {// label or others
return;
}
switch (insn.op) {//根据指令的类型调用相应的解析函数
case CONST://数据定义指令 把数值付给寄存器
case CONST_4:
case CONST_16:
case CONST_HIGH16:
case CONST_WIDE:
case CONST_WIDE_16:
case CONST_WIDE_32:
case CONST_WIDE_HIGH16:
case CONST_STRING:
case CONST_STRING_JUMBO:
case CONST_CLASS:
setReg(((ConstStmtNode) insn).a, interpreter.newOperation(insn));//新建一个变量并设置到寄存器,以便后面的指令使用
setTmp(null);//把temp设置为null
break;
case SGET:
case SGET_BOOLEAN:
case SGET_BYTE:
case SGET_CHAR:
case SGET_OBJECT:
case SGET_SHORT:
case SGET_WIDE:
setReg(((FieldStmtNode) insn).a, interpreter.newOperation(insn));
setTmp(null);
break;
case NEW_INSTANCE:
setReg(((TypeStmtNode) insn).a, interpreter.newOperation(insn));
setTmp(null);
break;
case MOVE:
case MOVE_16:
case MOVE_FROM16:
case MOVE_OBJECT:
case MOVE_OBJECT_16:
case MOVE_OBJECT_FROM16:
case MOVE_WIDE:
case MOVE_WIDE_FROM16:
case MOVE_WIDE_16:
Stmt2RNode stmt2RNode = (Stmt2RNode) insn;
setReg(stmt2RNode.a, interpreter.copyOperation(insn, getReg(stmt2RNode.b)));
setTmp(null);
break;
case MOVE_RESULT:
case MOVE_RESULT_WIDE:
case MOVE_RESULT_OBJECT:
case MOVE_EXCEPTION:
setReg(((Stmt1RNode) insn).a, interpreter.copyOperation(insn, getTmp()));
setTmp(null);
break;
case NOT_INT:
case NOT_LONG:
case NEG_DOUBLE:
case NEG_FLOAT:
case NEG_INT:
case NEG_LONG:
case INT_TO_BYTE:
case INT_TO_CHAR:
case INT_TO_DOUBLE:
case INT_TO_FLOAT:
case INT_TO_LONG:
case INT_TO_SHORT:
case FLOAT_TO_DOUBLE:
case FLOAT_TO_INT:
case FLOAT_TO_LONG:
case DOUBLE_TO_FLOAT:
case DOUBLE_TO_INT:
case DOUBLE_TO_LONG:
case LONG_TO_DOUBLE:
case LONG_TO_FLOAT:
case LONG_TO_INT:
case ARRAY_LENGTH:
Stmt2RNode stmt2RNode1 = (Stmt2RNode) insn;
setReg(stmt2RNode1.a, interpreter.unaryOperation(insn, getReg(stmt2RNode1.b)));
setTmp(null);
break;
case IF_EQZ:
case IF_GEZ:
case IF_GTZ:
case IF_LEZ:
case IF_LTZ:
case IF_NEZ:
interpreter.unaryOperation(insn, getReg(((JumpStmtNode) insn).a));
setTmp(null);
break;
case SPARSE_SWITCH:
interpreter.unaryOperation(insn, getReg(((SparseSwitchStmtNode) insn).a));
setTmp(null);
break;
case PACKED_SWITCH:
interpreter.unaryOperation(insn, getReg(((PackedSwitchStmtNode) insn).a));
setTmp(null);
break;
case SPUT://字段操作指令,用来对对象的字段进行对鞋操作 s开头的是静态字段i开头的是普通字段
case SPUT_BOOLEAN:
case SPUT_BYTE:
case SPUT_CHAR:
case SPUT_OBJECT:
case SPUT_SHORT:
case SPUT_WIDE:
interpreter.unaryOperation(insn, getReg(((FieldStmtNode) insn).a));//获取寄存器的值进行操作
setTmp(null);
break;
case IGET:
case IGET_BOOLEAN:
case IGET_BYTE:
case IGET_CHAR:
case IGET_OBJECT:
case IGET_SHORT:
case IGET_WIDE:
FieldStmtNode fieldStmtNode = (FieldStmtNode) insn;
setReg(fieldStmtNode.a, interpreter.unaryOperation(insn, getReg(fieldStmtNode.b)));
setTmp(null);
break;
case NEW_ARRAY:
case INSTANCE_OF: {
TypeStmtNode typeStmtNode = (TypeStmtNode) insn;
setReg(typeStmtNode.a, interpreter.unaryOperation(insn, getReg(typeStmtNode.b)));
setTmp(null);
}
break;
case CHECK_CAST: {
TypeStmtNode typeStmtNode = (TypeStmtNode) insn;
setReg(typeStmtNode.a, interpreter.unaryOperation(insn, getReg(typeStmtNode.a)));
setTmp(null);
}
break;
case MONITOR_ENTER:
case MONITOR_EXIT:
case THROW:
interpreter.unaryOperation(insn, getReg(((Stmt1RNode) insn).a));
setTmp(null);
break;
case RETURN:
case RETURN_WIDE:
case RETURN_OBJECT:
interpreter.returnOperation(insn, getReg(((Stmt1RNode) insn).a));
setTmp(null);
break;
case AGET:
case AGET_BOOLEAN:
case AGET_BYTE:
case AGET_CHAR:
case AGET_OBJECT:
case AGET_SHORT:
case AGET_WIDE:
case CMP_LONG:
case CMPG_DOUBLE:
case CMPG_FLOAT:
case CMPL_DOUBLE:
case CMPL_FLOAT:
case ADD_DOUBLE:
case ADD_FLOAT:
case ADD_INT:
case ADD_LONG:
case SUB_DOUBLE:
case SUB_FLOAT:
case SUB_INT:
case SUB_LONG:
case MUL_DOUBLE:
case MUL_FLOAT:
case MUL_INT:
case MUL_LONG:
case DIV_DOUBLE:
case DIV_FLOAT:
case DIV_INT:
case DIV_LONG:
case REM_DOUBLE:
case REM_FLOAT:
case REM_INT:
case REM_LONG:
case AND_INT:
case AND_LONG:
case OR_INT:
case OR_LONG:
case XOR_INT:
case XOR_LONG:
case SHL_INT:
case SHL_LONG:
case SHR_INT:
case SHR_LONG:
case USHR_INT:
case USHR_LONG:
Stmt3RNode stmt3RNode = (Stmt3RNode) insn;
setReg(stmt3RNode.a, interpreter.binaryOperation(insn, getReg(stmt3RNode.b), getReg(stmt3RNode.c)));
setTmp(null);
break;
case IF_EQ:
case IF_GE:
case IF_GT:
case IF_LE:
case IF_LT:
case IF_NE:
JumpStmtNode jumpStmtNode = (JumpStmtNode) insn;
interpreter.binaryOperation(insn, getReg(jumpStmtNode.a), getReg(jumpStmtNode.b));
setTmp(null);
break;
case IPUT:
case IPUT_BOOLEAN:
case IPUT_BYTE:
case IPUT_CHAR:
case IPUT_OBJECT:
case IPUT_SHORT:
case IPUT_WIDE:
FieldStmtNode fieldStmtNode1 = (FieldStmtNode) insn;
interpreter.binaryOperation(insn, getReg(fieldStmtNode1.b), getReg(fieldStmtNode1.a));
setTmp(null);
break;
case APUT:
case APUT_BOOLEAN:
case APUT_BYTE:
case APUT_CHAR:
case APUT_OBJECT:
case APUT_SHORT:
case APUT_WIDE:
Stmt3RNode stmt3RNode1 = (Stmt3RNode) insn;
interpreter.ternaryOperation(insn, getReg(stmt3RNode1.b), getReg(stmt3RNode1.c), getReg(stmt3RNode1.a));
setTmp(null);
break;
case INVOKE_VIRTUAL_RANGE:
case INVOKE_VIRTUAL:
case INVOKE_SUPER_RANGE:
case INVOKE_DIRECT_RANGE:
case INVOKE_SUPER:
case INVOKE_DIRECT:
case INVOKE_STATIC_RANGE:
case INVOKE_STATIC:
case INVOKE_INTERFACE_RANGE:
case INVOKE_INTERFACE: {
int i = 0;
MethodStmtNode methodStmtNode = (MethodStmtNode) insn;
List v;
if (insn.op == Op.INVOKE_STATIC || insn.op == Op.INVOKE_STATIC_RANGE) {//静态方法
v = new ArrayList<>(methodStmtNode.method.getParameterTypes().length);
} else {//非静态方法添加this
v = new ArrayList<>(methodStmtNode.method.getParameterTypes().length + 1);
v.add(getReg(methodStmtNode.args[i++]));
}
for (String type : methodStmtNode.method.getParameterTypes()) {//添加参数
v.add(getReg(methodStmtNode.args[i]));
char t = type.charAt(0);
if (t == 'J' || t == 'D') {
i += 2;
} else {
i += 1;
}
}
setTmp(interpreter.naryOperation(insn, v));
}
break;
case FILLED_NEW_ARRAY:
case FILLED_NEW_ARRAY_RANGE: {
FilledNewArrayStmtNode filledNewArrayStmtNode = (FilledNewArrayStmtNode) insn;
List v = new ArrayList<>(filledNewArrayStmtNode.args.length);
for (int i = 0; i < filledNewArrayStmtNode.args.length; i++) {
v.add(getReg(filledNewArrayStmtNode.args[i]));
}
setTmp(interpreter.naryOperation(insn, v));
}
break;
case ADD_DOUBLE_2ADDR:
case ADD_FLOAT_2ADDR:
case ADD_INT_2ADDR:
case ADD_LONG_2ADDR:
case SUB_DOUBLE_2ADDR:
case SUB_FLOAT_2ADDR:
case SUB_INT_2ADDR:
case SUB_LONG_2ADDR:
case MUL_DOUBLE_2ADDR:
case MUL_FLOAT_2ADDR:
case MUL_INT_2ADDR:
case MUL_LONG_2ADDR:
case DIV_DOUBLE_2ADDR:
case DIV_FLOAT_2ADDR:
case DIV_INT_2ADDR:
case DIV_LONG_2ADDR:
case REM_DOUBLE_2ADDR:
case REM_FLOAT_2ADDR:
case REM_INT_2ADDR:
case REM_LONG_2ADDR:
case AND_INT_2ADDR:
case AND_LONG_2ADDR:
case OR_INT_2ADDR:
case OR_LONG_2ADDR:
case XOR_INT_2ADDR:
case XOR_LONG_2ADDR:
case SHL_INT_2ADDR:
case SHL_LONG_2ADDR:
case SHR_INT_2ADDR:
case SHR_LONG_2ADDR:
case USHR_INT_2ADDR:
case USHR_LONG_2ADDR:
Stmt2RNode stmt2RNode2 = (Stmt2RNode) insn;
setReg(stmt2RNode2.a, interpreter.binaryOperation(insn, getReg(stmt2RNode2.a), getReg(stmt2RNode2.b)));
setTmp(null);
break;
case ADD_INT_LIT16:
case ADD_INT_LIT8:
case RSUB_INT_LIT8:
case RSUB_INT:
case MUL_INT_LIT8:
case MUL_INT_LIT16:
case DIV_INT_LIT16:
case DIV_INT_LIT8:
case REM_INT_LIT16:
case REM_INT_LIT8:
case AND_INT_LIT16:
case AND_INT_LIT8:
case OR_INT_LIT16:
case OR_INT_LIT8:
case XOR_INT_LIT16:
case XOR_INT_LIT8:
case SHL_INT_LIT8:
case SHR_INT_LIT8:
case USHR_INT_LIT8:
Stmt2R1NNode stmt2R1NNode = (Stmt2R1NNode) insn;
setReg(stmt2R1NNode.distReg, interpreter.unaryOperation(insn, getReg(stmt2R1NNode.srcReg)));
setTmp(null);
break;
case FILL_ARRAY_DATA:
interpreter.unaryOperation(insn,getReg(((FillArrayDataStmtNode)insn).ra));
setTmp(null);
break;
case GOTO:
case GOTO_16:
case GOTO_32:
case RETURN_VOID:
case BAD_OP:
setTmp(null);
break;
default:
throw new RuntimeException();
}
}
这里对各种指令进行处理,转换为iR指令
这样dex2ir的主要工作就完成了,
接下来是optimize
public void optimize(IrMethod irMethod) {
T_cleanLabel.transform(irMethod);
if (0 != (v3Config & V3.TOPOLOGICAL_SORT)) {
// T_topologicalSort.transform(irMethod);
}
T_deadCode.transform(irMethod);
T_removeLocal.transform(irMethod);
T_removeConst.transform(irMethod);
T_zero.transform(irMethod);
if (T_npe.transformReportChanged(irMethod)) {
T_deadCode.transform(irMethod);
T_removeLocal.transform(irMethod);
T_removeConst.transform(irMethod);
}
T_new.transform(irMethod);
T_fillArray.transform(irMethod);
T_agg.transform(irMethod);
T_multiArray.transform(irMethod);
T_voidInvoke.transform(irMethod);
if (0 != (v3Config & V3.PRINT_IR)) {
int i = 0;
for (Stmt p : irMethod.stmts) {
if (p.st == Stmt.ST.LABEL) {
LabelStmt labelStmt = (LabelStmt) p;
labelStmt.displayName = "L" + i++;
}
}
System.out.println(irMethod);
}
T_type.transform(irMethod);
T_unssa.transform(irMethod);
T_ir2jRegAssign.transform(irMethod);
T_trimEx.transform(irMethod);
}
这里主要是对前面生成的指令进行一些优化,去掉一些没用的指令
接下来是ir2j把IR指令转换为jvm指令
@Override
public void ir2j(IrMethod irMethod, MethodVisitor mv) {
new IR2JConverter(0 != (V3.OPTIMIZE_SYNCHRONIZED & v3Config)).convert(irMethod, mv);
}
public void convert(IrMethod ir, MethodVisitor asm) {
mapLabelStmt(ir);//
reBuildInstructions(ir, asm);//把ir类型(中间类型)的指令转换为java中对应的指令
reBuildTryCatchBlocks(ir, asm);
}
mapLabelStmt对指令中的标签进行出来
然后调用reBuildInstructions重构指令
private void reBuildInstructions(IrMethod ir, MethodVisitor asm) {
asm = new LdcOptimizeAdapter(asm);//ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能
int maxLocalIndex = 0;
for (Local local : ir.locals) {
maxLocalIndex = Math.max(maxLocalIndex, local._ls_index);
}
Map lockMap = new HashMap();
for (Stmt st : ir.stmts) {
switch (st.st) {
case LABEL://标签
LabelStmt labelStmt = (LabelStmt) st;
Label label = (Label) labelStmt.tag;
asm.visitLabel(label);
if (labelStmt.lineNumber >= 0) {
asm.visitLineNumber(labelStmt.lineNumber, label);
}
break;
case ASSIGN: {//赋值
E2Stmt e2 = (E2Stmt) st;
Value v1 = e2.op1;//操作数1
Value v2 = e2.op2; //操作数2
switch (v1.vt) {//左边操作数1的类型
case LOCAL:
Local local = ((Local) v1);
int i = local._ls_index;
boolean skipOrg = false;
if (v2.vt == VT.LOCAL && (i == ((Local) v2)._ls_index)) {// check for a=a
skipOrg = true;
} else if (v1.valueType.charAt(0) == 'I') {// check for IINC
if (v2.vt == VT.ADD) {
if (isLocalWithIndex(v2.getOp1(), i) && v2.getOp2().vt == VT.CONSTANT) { // a=a+1;
int increment = (Integer) ((Constant) v2.getOp2()).value;
if (increment >= Short.MIN_VALUE && increment <= Short.MAX_VALUE) {
asm.visitIincInsn(i, increment);
skipOrg = true;
}
} else if (isLocalWithIndex(v2.getOp2(), i) && v2.getOp1().vt == VT.CONSTANT) { // a=1+a;
int increment = (Integer) ((Constant) v2.getOp1()).value;
if (increment >= Short.MIN_VALUE && increment <= Short.MAX_VALUE) {
asm.visitIincInsn(i, increment);
skipOrg = true;
}
}
} else if (v2.vt == VT.SUB) {
if (isLocalWithIndex(v2.getOp1(), i) && v2.getOp2().vt == VT.CONSTANT) { // a=a-1;
int increment = -(Integer) ((Constant) v2.getOp2()).value;
if (increment >= Short.MIN_VALUE && increment <= Short.MAX_VALUE) {
asm.visitIincInsn(i, increment);
skipOrg = true;
}
}
}
}
if (!skipOrg) {
accept(v2, asm);
if (i >= 0) {
asm.visitVarInsn(getOpcode(v1, ISTORE), i);
} else if (!v1.valueType.equals("V")) { // skip void type locals
switch (v1.valueType.charAt(0)) {
case 'J':
case 'D':
asm.visitInsn(POP2);
break;
default:
asm.visitInsn(POP);
break;
}
}
}
break;
case STATIC_FIELD: {//静态变量
StaticFieldExpr fe = (StaticFieldExpr) v1;//静态变量表达式
accept(v2, asm);//访问右边的变量(入栈)
insertI2x(v2.valueType, fe.type, asm);//是否要做类型转换
asm.visitFieldInsn(PUTSTATIC, toInternal(fe.owner), fe.name, fe.type);//PUTSTATIC为指定的类的静态域赋值
// toInternal去掉前面的L
break;
}
case FIELD: {
FieldExpr fe = (FieldExpr) v1;
accept(fe.op, asm);
accept(v2, asm);
insertI2x(v2.valueType, fe.type, asm);
asm.visitFieldInsn(PUTFIELD, toInternal(fe.owner), fe.name, fe.type);
break;
}
case ARRAY:
ArrayExpr ae = (ArrayExpr) v1;
accept(ae.op1, asm);
accept(ae.op2, asm);
accept(v2, asm);
String tp1 = ae.op1.valueType;
String tp2 = ae.valueType;
if (tp1.charAt(0) == '[') {
String arrayElementType = tp1.substring(1);
insertI2x(v2.valueType, arrayElementType, asm);
asm.visitInsn(getOpcode(arrayElementType, IASTORE));
} else {
asm.visitInsn(getOpcode(tp2, IASTORE));
}
break;
}
}
break;
case IDENTITY: {
E2Stmt e2 = (E2Stmt) st;
if (e2.op2.vt == VT.EXCEPTION_REF) {
int index = ((Local) e2.op1)._ls_index;
if (index >= 0) {
asm.visitVarInsn(ASTORE, index);
} else {
asm.visitInsn(POP);
}
}
}
break;
case FILL_ARRAY_DATA:{
E2Stmt e2 = (E2Stmt) st;
if (e2.getOp2().vt == VT.CONSTANT) {
Object arrayData = ((Constant) e2.getOp2()).value;
int arraySize = Array.getLength(arrayData);
String arrayValueType = e2.getOp1().valueType;
String elementType;
if (arrayValueType.charAt(0) == '[') {
elementType = arrayValueType.substring(1);
} else {
elementType = "I";
}
int iastoreOP = getOpcode(elementType, IASTORE);
accept(e2.getOp1(), asm);
for (int i = 0; i < arraySize; i++) {
asm.visitInsn(DUP);
asm.visitLdcInsn(i);
asm.visitLdcInsn(Array.get(arrayData, i));
asm.visitInsn(iastoreOP);
}
asm.visitInsn(POP);
} else {
FilledArrayExpr filledArrayExpr = (FilledArrayExpr) e2.getOp2();
int arraySize = filledArrayExpr.ops.length;
String arrayValueType = e2.getOp1().valueType;
String elementType;
if (arrayValueType.charAt(0) == '[') {
elementType = arrayValueType.substring(1);
} else {
elementType = "I";
}
int iastoreOP = getOpcode(elementType, IASTORE);
accept(e2.getOp1(), asm);
for (int i = 0; i < arraySize; i++) {
asm.visitInsn(DUP);
asm.visitLdcInsn(i);
accept(filledArrayExpr.ops[i], asm);
asm.visitInsn(iastoreOP);
}
asm.visitInsn(POP);
}
}
break;
case GOTO:
asm.visitJumpInsn(GOTO, (Label) ((GotoStmt) st).target.tag);
break;
case IF:
reBuildJumpInstructions((IfStmt) st, asm);
break;
case LOCK: {
Value v = ((UnopStmt) st).op;
accept(v, asm);
if (optimizeSynchronized) {
switch (v.vt) {
case LOCAL:
// FIXME do we have to disable local due to OptSyncTest ?
// break;
case CONSTANT: {
String key;
if (v.vt == VT.LOCAL) {
key = "L" + ((Local) v)._ls_index;
} else {
key = "C" + ((Constant) v).value;
}
Integer integer = lockMap.get(key);
int nIndex = integer != null ? integer : ++maxLocalIndex;
asm.visitInsn(DUP);
asm.visitVarInsn(getOpcode(v, ISTORE), nIndex);
lockMap.put(key, nIndex);
}
break;
default:
throw new RuntimeException();
}
}
asm.visitInsn(MONITORENTER);
}
break;
case UNLOCK: {
Value v = ((UnopStmt) st).op;
if (optimizeSynchronized) {
switch (v.vt) {
case LOCAL:
case CONSTANT: {
String key;
if (v.vt == VT.LOCAL) {
key = "L" + ((Local) v)._ls_index;
} else {
key = "C" + ((Constant) v).value;
}
Integer integer = lockMap.get(key);
if (integer != null) {
asm.visitVarInsn(getOpcode(v, ILOAD), integer);
} else {
accept(v, asm);
}
}
break;
// TODO other
default: {
accept(v, asm);
break;
}
}
} else {
accept(v, asm);
}
asm.visitInsn(MONITOREXIT);
}
break;
case NOP:
break;
case RETURN: {
Value v = ((UnopStmt) st).op;
accept(v, asm);
insertI2x(v.valueType, ir.ret, asm);
asm.visitInsn(getOpcode(v, IRETURN));
}
break;
case RETURN_VOID:
asm.visitInsn(RETURN);//返回指令
break;
case LOOKUP_SWITCH: {
LookupSwitchStmt lss = (LookupSwitchStmt) st;
accept(lss.op, asm);
Label targets[] = new Label[lss.targets.length];
for (int i = 0; i < targets.length; i++) {
targets[i] = (Label) lss.targets[i].tag;
}
asm.visitLookupSwitchInsn((Label) lss.defaultTarget.tag, lss.lookupValues, targets);
}
break;
case TABLE_SWITCH: {
TableSwitchStmt tss = (TableSwitchStmt) st;
accept(tss.op, asm);
Label targets[] = new Label[tss.targets.length];
for (int i = 0; i < targets.length; i++) {
targets[i] = (Label) tss.targets[i].tag;
}
asm.visitTableSwitchInsn(tss.lowIndex, tss.lowIndex + targets.length - 1,
(Label) tss.defaultTarget.tag, targets);
}
break;
case THROW:
accept(((UnopStmt) st).op, asm);
asm.visitInsn(ATHROW);
break;
case VOID_INVOKE:
Value op = st.getOp();
accept(op, asm);
String ret = op.valueType;
if (op.vt == VT.INVOKE_NEW) {
asm.visitInsn(POP);
} else if (!"V".equals(ret)) {
switch (ret.charAt(0)) {
case 'J':
case 'D':
asm.visitInsn(POP2);
break;
default:
asm.visitInsn(POP);
break;
}
}
break;
default:
throw new RuntimeException("not support st: " + st.st);
}
}
}
private static void accept(Value value, MethodVisitor asm) {
switch (value.et) {//参数个数
case E0:
switch (value.vt) {//值类型
case LOCAL:
asm.visitVarInsn(getOpcode(value, ILOAD), ((Local) value)._ls_index);
break;
case CONSTANT://常量
Constant cst = (Constant) value;
if (cst.value.equals(Constant.Null)) {//是否为空
asm.visitInsn(ACONST_NULL);
} else if (cst.value instanceof Constant.Type) {//Type类型
asm.visitLdcInsn(Type.getType(((Constant.Type) cst.value).desc));
} else {
asm.visitLdcInsn(cst.value);
}
break;
case NEW:
asm.visitTypeInsn(NEW, toInternal(((NewExpr) value).type));
break;
case STATIC_FIELD:
StaticFieldExpr sfe= (StaticFieldExpr) value;
asm.visitFieldInsn(GETSTATIC,toInternal(sfe.owner),sfe.name,sfe.type);
break;
}
break;
case E1:
reBuildE1Expression((E1Expr) value, asm);
break;
case E2:
reBuildE2Expression((E2Expr) value, asm);
break;
case En:
reBuildEnExpression((EnExpr) value, asm);
break;
}
}
主要是转换为jvm指令,出栈,入栈等
当所有的都完成后调用ClassVisitorFactory的visitEnd
public void visitEnd() {
super.visitEnd();
ClassWriter cw = (ClassWriter) super.cv;
byte[] data;
try {
// FIXME handle 'java.lang.RuntimeException: Method code too large!'
data = cw.toByteArray();
} catch (Exception ex) {
System.err.println(String.format("ASM fail to generate .class file: %s", name));
exceptionHandler.handleFileException(ex);
return;
}
try {
Path dist1 = dist.resolve(name + ".class");
Path parent = dist1.getParent();
if (parent != null && !Files.exists(parent)) {
Files.createDirectories(parent);
}
Files.write(dist1, data);
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
这里主要是
data = cw.toByteArray();
public byte[] toByteArray() {
if (index > 0xFFFF) {
throw new RuntimeException("Class file too large!");
}
// computes the real size of the bytecode of this class
int size = 24 + 2 * interfaceCount;
int nbFields = 0;
FieldWriter fb = firstField;
while (fb != null) {
++nbFields;
size += fb.getSize();
fb = (FieldWriter) fb.fv;
}
int nbMethods = 0;
MethodWriter mb = firstMethod;
while (mb != null) {
++nbMethods;
size += mb.getSize();
mb = (MethodWriter) mb.mv;
}
int attributeCount = 0;
if (bootstrapMethods != null) {
// we put it as first attribute in order to improve a bit
// ClassReader.copyBootstrapMethods
++attributeCount;
size += 8 + bootstrapMethods.length;
newUTF8("BootstrapMethods");
}
if (ClassReader.SIGNATURES && signature != 0) {
++attributeCount;
size += 8;
newUTF8("Signature");
}
if (sourceFile != 0) {
++attributeCount;
size += 8;
newUTF8("SourceFile");
}
if (sourceDebug != null) {
++attributeCount;
size += sourceDebug.length + 6;
newUTF8("SourceDebugExtension");
}
if (enclosingMethodOwner != 0) {
++attributeCount;
size += 10;
newUTF8("EnclosingMethod");
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
++attributeCount;
size += 6;
newUTF8("Deprecated");
}
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((version & 0xFFFF) < Opcodes.V1_5
|| (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
++attributeCount;
size += 6;
newUTF8("Synthetic");
}
}
if (innerClasses != null) {
++attributeCount;
size += 8 + innerClasses.length;
newUTF8("InnerClasses");
}
if (ClassReader.ANNOTATIONS && anns != null) {
++attributeCount;
size += 8 + anns.getSize();
newUTF8("RuntimeVisibleAnnotations");
}
if (ClassReader.ANNOTATIONS && ianns != null) {
++attributeCount;
size += 8 + ianns.getSize();
newUTF8("RuntimeInvisibleAnnotations");
}
if (ClassReader.ANNOTATIONS && tanns != null) {
++attributeCount;
size += 8 + tanns.getSize();
newUTF8("RuntimeVisibleTypeAnnotations");
}
if (ClassReader.ANNOTATIONS && itanns != null) {
++attributeCount;
size += 8 + itanns.getSize();
newUTF8("RuntimeInvisibleTypeAnnotations");
}
if (attrs != null) {
attributeCount += attrs.getCount();
size += attrs.getSize(this, null, 0, -1, -1);
}
size += pool.length;
// allocates a byte vector of this size, in order to avoid unnecessary
// arraycopy operations in the ByteVector.enlarge() method
ByteVector out = new ByteVector(size);
out.putInt(0xCAFEBABE).putInt(version);
out.putShort(index).putByteArray(pool.data, 0, pool.length);
int mask = Opcodes.ACC_DEPRECATED | ACC_SYNTHETIC_ATTRIBUTE
| ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC);
out.putShort(access & ~mask).putShort(name).putShort(superName);
out.putShort(interfaceCount);
for (int i = 0; i < interfaceCount; ++i) {
out.putShort(interfaces[i]);
}
out.putShort(nbFields);
fb = firstField;
while (fb != null) {
fb.put(out);
fb = (FieldWriter) fb.fv;
}
out.putShort(nbMethods);
mb = firstMethod;
while (mb != null) {
mb.put(out);
mb = (MethodWriter) mb.mv;
}
out.putShort(attributeCount);
if (bootstrapMethods != null) {
out.putShort(newUTF8("BootstrapMethods"));
out.putInt(bootstrapMethods.length + 2).putShort(
bootstrapMethodsCount);
out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
}
if (ClassReader.SIGNATURES && signature != 0) {
out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);
}
if (sourceFile != 0) {
out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
}
if (sourceDebug != null) {
int len = sourceDebug.length;
out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
out.putByteArray(sourceDebug.data, 0, len);
}
if (enclosingMethodOwner != 0) {
out.putShort(newUTF8("EnclosingMethod")).putInt(4);
out.putShort(enclosingMethodOwner).putShort(enclosingMethod);
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
out.putShort(newUTF8("Deprecated")).putInt(0);
}
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((version & 0xFFFF) < Opcodes.V1_5
|| (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
out.putShort(newUTF8("Synthetic")).putInt(0);
}
}
if (innerClasses != null) {
out.putShort(newUTF8("InnerClasses"));
out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
out.putByteArray(innerClasses.data, 0, innerClasses.length);
}
if (ClassReader.ANNOTATIONS && anns != null) {
out.putShort(newUTF8("RuntimeVisibleAnnotations"));
anns.put(out);
}
if (ClassReader.ANNOTATIONS && ianns != null) {
out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
if (ClassReader.ANNOTATIONS && tanns != null) {
out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
tanns.put(out);
}
if (ClassReader.ANNOTATIONS && itanns != null) {
out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
itanns.put(out);
}
if (attrs != null) {
attrs.put(this, null, 0, -1, -1, out);
}
if (invalidFrames) {
anns = null;
ianns = null;
attrs = null;
innerClassesCount = 0;
innerClasses = null;
bootstrapMethodsCount = 0;
bootstrapMethods = null;
firstField = null;
lastField = null;
firstMethod = null;
lastMethod = null;
computeMaxs = false;
computeFrames = true;
invalidFrames = false;
new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES);
return toByteArray();
}
return out.data;
}
到这里,dex转jar就分析完成了。