/* * 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 com.googlecode.dex2jar.ir.IrMethod; import com.googlecode.dex2jar.ir.Trap; import com.googlecode.dex2jar.ir.expr.Local; import com.googlecode.dex2jar.ir.expr.PhiExpr; import com.googlecode.dex2jar.ir.expr.Value; import com.googlecode.dex2jar.ir.stmt.AssignStmt; import com.googlecode.dex2jar.ir.stmt.LabelStmt; import com.googlecode.dex2jar.ir.stmt.Stmt; import java.util.*; public class DeadCodeTransformer implements Transformer { @Override public void transform(IrMethod method) { Cfg.createCFG(method); Cfg.dfsVisit(method, null); if (method.traps != null) { for (Iterator<Trap> it = method.traps.iterator(); it.hasNext();) { Trap t = it.next(); boolean allNotThrow = true; for (Stmt p = t.start; p != t.end; p = p.getNext()) { if (p.visited && Cfg.isThrow(p)) { allNotThrow = false; break; } } if (allNotThrow) { it.remove(); continue; } boolean allNotVisited = true; boolean allVisited = true; for (LabelStmt labelStmt : t.handlers) { if (labelStmt.visited) { allNotVisited = false; } else { allVisited = false; } } if (allNotVisited) { it.remove(); } else { // keep start and end t.start.visited = true; t.end.visited = true; if (!allVisited) { // part visited List<String> types = new ArrayList<>(t.handlers.length); List<LabelStmt> labelStmts = new ArrayList<>(t.handlers.length); for (int i = 0; i < t.handlers.length; i++) { labelStmts.add(t.handlers[i]); types.add(t.types[i]); } t.handlers = labelStmts.toArray(new LabelStmt[labelStmts.size()]); t.types = types.toArray(new String[types.size()]); } } } } Set<Local> definedLocals = new HashSet<>(); for (Iterator<Stmt> it = method.stmts.iterator(); it.hasNext();) { Stmt p = it.next(); if (!p.visited) { it.remove(); continue; } if (p.st == Stmt.ST.ASSIGN || p.st == Stmt.ST.IDENTITY) { if (p.getOp1().vt == Value.VT.LOCAL) { definedLocals.add((Local) p.getOp1()); } } } if (method.phiLabels != null) { for (Iterator<LabelStmt> it = method.phiLabels.iterator(); it.hasNext();) { LabelStmt labelStmt = it.next(); if (!labelStmt.visited) { it.remove(); continue; } if (labelStmt.phis != null) { for (AssignStmt phi : labelStmt.phis) { definedLocals.add((Local) phi.getOp1()); } } } } method.locals.clear(); method.locals.addAll(definedLocals); Set<Value> tmp = new HashSet<>(); if (method.phiLabels != null) { for (Iterator<LabelStmt> it = method.phiLabels.iterator(); it.hasNext();) { LabelStmt labelStmt = it.next(); if (labelStmt.phis != null) { for (AssignStmt phi : labelStmt.phis) { PhiExpr phiExpr = (PhiExpr) phi.getOp2(); boolean needRebuild = false; for (Value v : phiExpr.getOps()) { if (!definedLocals.contains(v)) { needRebuild = true; break; } } if (needRebuild) { for (Value v : phiExpr.getOps()) { if (definedLocals.contains(v)) { tmp.add(v); } } phiExpr.setOps(tmp.toArray(new Value[tmp.size()])); tmp.clear(); } } } } } } }