com.googlecode.dex2jar.ir.ts.Cfg Maven / Gradle / Ivy
The newest version!
/*
* 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);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy