com.googlecode.dex2jar.ir.ts.Cfg Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle Show documentation
Show all versions of gradle Show documentation
fakeradnroid gradle builder
/*
* Copyright (c) 2009-2012 Panxiaobo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.googlecode.dex2jar.ir.ts;
import java.util.Collections;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;
import com.googlecode.dex2jar.ir.ET;
import com.googlecode.dex2jar.ir.IrMethod;
import com.googlecode.dex2jar.ir.Trap;
import com.googlecode.dex2jar.ir.expr.Local;
import com.googlecode.dex2jar.ir.expr.Value;
import com.googlecode.dex2jar.ir.expr.Value.VT;
import com.googlecode.dex2jar.ir.stmt.*;
import com.googlecode.dex2jar.ir.stmt.Stmt.ST;
/**
* TODO DOC
*
* @author Panxiaobo
* @version $Rev$
*/
public class Cfg {
public static int[] countLocalReads(IrMethod method) {
int size = reIndexLocal(method);
final int readCounts[] = new int[size];
travel(method.stmts, new TravelCallBack() {
@Override
public Value onAssign(Local v, AssignStmt as) {
return v;
}
@Override
public Value onUse(Local v) {
readCounts[v._ls_index]++;
return v;
}
}, true);
return readCounts;
}
public static void reIndexLocalAndLabel(IrMethod irMethod) {
reIndexLocal(irMethod);
reIndexLabel(irMethod);
}
private static void reIndexLabel(IrMethod irMethod) {
int i = 0;
for (Stmt stmt : irMethod.stmts) {
if (stmt.st == ST.LABEL) {
((LabelStmt) stmt).displayName = "L" + i++;
}
}
}
public interface FrameVisitor {
T merge(T srcFrame, T distFrame, Stmt src, Stmt dist);
T initFirstFrame(Stmt first);
T exec(T frame, Stmt stmt);
}
public static boolean notThrow(Stmt s) {
return !isThrow(s);
}
public static boolean isThrow(Stmt s) {
ST st = s.st;
if (st.canThrow()) {
return true;
} else if (st.mayThrow()) {
ET et = s.et;
if (et == ET.E1) {
return isThrow(s.getOp());
} else if (et == ET.E2) {
return isThrow(s.getOp1()) || isThrow(s.getOp2());
} else {
throw new RuntimeException();
}
} else {
return false;
}
}
private static boolean isThrow(Value op) {
VT vt = op.vt;
if (vt.canThrow()) {
return true;
} else if (vt.mayThrow()) {
switch (op.et) {
case E1:
return isThrow(op.getOp());
case E2:
return isThrow(op.getOp1()) || isThrow(op.getOp2());
default:
case En:
case E0:
throw new RuntimeException();
}
} else {
return false;
}
}
public static void createCfgWithoutEx(IrMethod jm) {
for (Stmt st : jm.stmts) {
st.frame = null;
st.exceptionHandlers = null;
if (st._cfg_froms == null) {
st._cfg_froms = new TreeSet<>(jm.stmts);
} else {
st._cfg_froms.clear();
}
}
for (Stmt st : jm.stmts) {
if (st.st.canBranch()) {
link(st, ((JumpStmt) st).getTarget());
}
if (st.st.canContinue()) {
link(st, st.getNext());
}
if (st.st.canSwitch()) {
BaseSwitchStmt bss = (BaseSwitchStmt) st;
link(st, bss.defaultTarget);
for (Stmt target : bss.targets) {
link(st, target);
}
}
}
}
public static void createCFG(IrMethod jm) {
createCfgWithoutEx(jm);
for (Trap t : jm.traps) {
for (Stmt s = t.start; s != t.end; s = s.getNext()) {
if (isThrow(s)) {
Set hs = s.exceptionHandlers;
if (hs == null) {
hs = new TreeSet<>(jm.stmts);
s.exceptionHandlers = hs;
}
for (LabelStmt handler : t.handlers) {
link(s, handler);
hs.add(handler);
}
}
}
}
}
public static interface DfsVisitor {
void onVisit(Stmt p);
}
public static void dfsVisit(IrMethod method, DfsVisitor visitor) {
for (Stmt st : method.stmts) {
st.visited = false;
}
Stack stack = new Stack<>();
stack.add(method.stmts.getFirst());
while (!stack.isEmpty()) {
Stmt currentStmt = stack.pop();
if (currentStmt.visited) {
continue;
} else {
currentStmt.visited = true;
}
if (currentStmt.exceptionHandlers != null) {
for (LabelStmt labelStmt : currentStmt.exceptionHandlers) {
stack.push(labelStmt);
}
}
if (visitor != null) {
visitor.onVisit(currentStmt);
}
if (currentStmt.st.canSwitch()) {
BaseSwitchStmt bs = (BaseSwitchStmt) currentStmt;
Collections.addAll(stack, bs.targets);
LabelStmt target = bs.defaultTarget;
stack.add(target);
}
if (currentStmt.st.canBranch()) {
Stmt target = ((JumpStmt) currentStmt).getTarget();
stack.add(target);
}
if (currentStmt.st.canContinue()) {
Stmt target = currentStmt.getNext();
stack.add(target);
}
}
}
@SuppressWarnings("unchecked")
public static void dfs(StmtList stmts, FrameVisitor sv) {
if (stmts.getSize() == 0) {
return;
}
// clean
for (Stmt st : stmts) {
st.visited = false;
st.frame = null;
}
Stack stack = new Stack();
Stmt first = stmts.getFirst();
Stmt nop = null;
if (first.st == ST.LABEL && first._cfg_froms.size() > 0) {
nop = Stmts.nNop();
// for
// L0:
// ...
// GOTO L0:
// make sure the first Label has one more super
first._cfg_froms.add(nop);
}
stack.add(first);
first.frame = sv.initFirstFrame(first);
while (!stack.isEmpty()) {
Stmt currentStmt = stack.pop();
if (currentStmt == null || currentStmt.visited) {
continue;
} else {
currentStmt.visited = true;
}
T beforeExecFrame = (T) currentStmt.frame;
if (currentStmt.exceptionHandlers != null) {
for (LabelStmt labelStmt : currentStmt.exceptionHandlers) {
labelStmt.frame = sv.merge(beforeExecFrame, (T) labelStmt.frame, currentStmt, labelStmt);
stack.push(labelStmt);
}
}
T afterExecFrame = sv.exec(beforeExecFrame, currentStmt);
if (currentStmt.st.canSwitch()) {
BaseSwitchStmt bs = (BaseSwitchStmt) currentStmt;
for (LabelStmt target : bs.targets) {
target.frame = sv.merge(afterExecFrame, (T) target.frame, currentStmt, target);
stack.push(target);
}
LabelStmt target = bs.defaultTarget;
target.frame = sv.merge(afterExecFrame, (T) target.frame, currentStmt, target);
stack.push(target);
}
if (currentStmt.st.canBranch()) {
Stmt target = ((JumpStmt) currentStmt).getTarget();
target.frame = sv.merge(afterExecFrame, (T) target.frame, currentStmt, target);
stack.push(target);
}
if (currentStmt.st.canContinue()) {
Stmt target = currentStmt.getNext();
target.frame = sv.merge(afterExecFrame, (T) target.frame, currentStmt, target);
stack.push(target);
}
}
if (nop != null) {
first._cfg_froms.remove(nop);
}
}
private static void link(Stmt from, Stmt to) {
if (to == null) {// last stmt is a LabelStmt
return;
}
to._cfg_froms.add(from);
}
public interface OnUseCallBack {
Value onUse(Local v);
}
public interface OnAssignCallBack {
Value onAssign(Local v, AssignStmt as);
}
public interface TravelCallBack extends OnUseCallBack, OnAssignCallBack {
}
public static Value travelMod(Value value, OnUseCallBack callback) {
switch (value.et) {
case E0:
if (value.vt == VT.LOCAL) {
return callback.onUse((Local) value);
}
break;
case E1:
value.setOp(travelMod(value.getOp(), callback));
break;
case E2:
value.setOp1(travelMod(value.getOp1(), callback));
value.setOp2(travelMod(value.getOp2(), callback));
break;
case En:
Value ops[] = value.getOps();
for (int i = 0; i < ops.length; i++) {
ops[i] = travelMod(ops[i], callback);
}
break;
}
return value;
}
public static void travel(Value value, OnUseCallBack callback) {
switch (value.et) {
case E0:
if (value.vt == VT.LOCAL) {
callback.onUse((Local) value);
}
break;
case E1:
travel(value.getOp(), callback);
break;
case E2:
travel(value.getOp1(), callback);
travel(value.getOp2(), callback);
break;
case En:
Value ops[] = value.getOps();
for (int i = 0; i < ops.length; i++) {
travel(ops[i], callback);
}
break;
}
}
public static void travelMod(Stmt p, TravelCallBack callback, boolean travelPhi) {
switch (p.et) {
case E1:
p.setOp(travelMod(p.getOp(), callback));
break;
case E2:
Value e2op1 = p.getOp1();
if (e2op1.vt == VT.LOCAL && (p.st == ST.ASSIGN || p.st == ST.IDENTITY)) {
p.setOp2(travelMod(p.getOp2(), callback));
p.setOp1(callback.onAssign((Local) e2op1, (AssignStmt) p));
} else {
p.setOp1(travelMod(p.getOp1(), callback));
p.setOp2(travelMod(p.getOp2(), callback));
}
break;
case En:
case E0:
if (travelPhi && p.st == ST.LABEL) {
LabelStmt labelStmt = (LabelStmt) p;
if (labelStmt.phis != null) {
for (AssignStmt phi : labelStmt.phis) {
travelMod(phi, callback, false);
}
}
}
break;
}
}
public static void travel(Stmt p, TravelCallBack callback, boolean travelPhi) {
switch (p.et) {
case E1:
travel(p.getOp(), callback);
break;
case E2:
Value e2op1 = p.getOp1();
if (e2op1.vt == VT.LOCAL && (p.st == ST.ASSIGN || p.st == ST.IDENTITY)) {
travel(p.getOp2(), callback);
callback.onAssign((Local) e2op1, (AssignStmt) p);
} else {
travel(p.getOp1(), callback);
travel(p.getOp2(), callback);
}
break;
case En:
case E0:
if (travelPhi && p.st == ST.LABEL) {
LabelStmt labelStmt = (LabelStmt) p;
if (labelStmt.phis != null) {
for (AssignStmt phi : labelStmt.phis) {
travel(phi, callback, false);
}
}
}
break;
}
}
public static void travel(StmtList stmts, TravelCallBack callback, boolean travelPhi) {
for (Stmt p = stmts.getFirst(); p != null; p = p.getNext()) {
travel(p, callback, travelPhi);
}
}
public static void travelMod(StmtList stmts, TravelCallBack callback, boolean travelPhi) {
for (Stmt p = stmts.getFirst(); p != null; p = p.getNext()) {
travelMod(p, callback, travelPhi);
}
}
/**
* @param method
* @return size of locals
*/
public static int reIndexLocal(IrMethod method) {
int i = 0;
for (Local local : method.locals) {
local._ls_index = i++;
}
return i;
}
public static void collectTos(Stmt stmt, Set tos) {
if (stmt.st.canBranch()) {
tos.add(((JumpStmt) stmt).getTarget());
}
if (stmt.st.canContinue()) {
tos.add(stmt.getNext());
}
if (stmt.st.canSwitch()) {
BaseSwitchStmt bss = (BaseSwitchStmt) stmt;
tos.add(bss.defaultTarget);
for (Stmt target : bss.targets) {
tos.add(target);
}
}
if (stmt.exceptionHandlers != null) {
tos.addAll(stmt.exceptionHandlers);
}
}
}