/* * 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.an; import com.googlecode.dex2jar.ir.IrMethod; import com.googlecode.dex2jar.ir.expr.Local; 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 com.googlecode.dex2jar.ir.ts.Cfg; import com.googlecode.dex2jar.ir.ts.Cfg.FrameVisitor; import com.googlecode.dex2jar.ir.ts.Cfg.TravelCallBack; import java.util.ArrayList; import java.util.List; @SuppressWarnings({"unchecked"}) public abstract class BaseAnalyze<T extends AnalyzeValue> implements FrameVisitor<T[]>, TravelCallBack { protected static final boolean DEBUG = false; public List<T> aValues = new ArrayList<T>(); private boolean reindexLocal; private T[] currentFrame; protected int localSize; protected IrMethod method; private T[] tmpFrame; public BaseAnalyze(IrMethod method) { this(method,true); } public BaseAnalyze(IrMethod method, boolean reindexLocal) { super(); this.method = method; if (!reindexLocal) { // override the localSize value to the max local index+1 int maxReg = -1; for (Local local : method.locals) { if (local._ls_index > maxReg) { maxReg = local._ls_index; } } this.localSize = maxReg + 1; } else { this.localSize = method.locals.size(); } this.reindexLocal = reindexLocal; } public void analyze() { init(); analyze0(); analyzeValue(); } protected void analyze0() { tmpFrame = newFrame(localSize); Cfg.dfs(method.stmts, this); tmpFrame = null; } protected void analyzeValue() { } protected void afterExec(T[] frame, Stmt stmt) { } @Override public T[] exec(T[] frame, Stmt stmt) { this.currentFrame = frame; try { Cfg.travel(stmt, this, false); } catch (Exception ex) { throw new RuntimeException("fail exe " + stmt, ex); } frame = this.currentFrame; this.currentFrame = null; afterExec(frame, stmt); return frame; } protected T getFromFrame(int idx) { return (T) currentFrame[idx]; } protected T[] getFrame(Stmt stmt) { return (T[]) stmt.frame; } protected void setFrame(Stmt stmt, T[] frame) { stmt.frame = frame; } protected void init() { if (reindexLocal) { int index = 0; for (Local local : method.locals) { local._ls_index = index; index++; } } if (DEBUG) { int idx = 0; for (Stmt s : method.stmts) { if (s.st == Stmt.ST.LABEL) { LabelStmt label = (LabelStmt) s; label.displayName = "L" + idx++; } } } initCFG(); } protected void initCFG() { Cfg.createCFG(method); } protected T[] newFrame() { return newFrame(localSize); } @Override public T[] initFirstFrame(Stmt first) { return newFrame(localSize); } protected abstract T[] newFrame(int size); protected abstract T newValue(); @Override public Local onAssign(Local local, AssignStmt as) { System.arraycopy(currentFrame, 0, tmpFrame, 0, localSize); currentFrame = tmpFrame; T aValue = onAssignLocal(local, as.op2); aValues.add(aValue); currentFrame[local._ls_index] = aValue; return local; } protected T onAssignLocal(Local local, Value value) { return newValue(); } @Override public Local onUse(Local local) { T aValue = (T) currentFrame[local._ls_index]; onUseLocal(aValue, local); return local; } protected void onUseLocal(T aValue, Local local) { } @Override public String toString() { StringBuilder sb = new StringBuilder(); for (Stmt stmt = method.stmts.getFirst(); stmt != null; stmt = stmt.getNext()) { T[] frame = (T[]) stmt.frame; if (frame != null) { for (T p : frame) { if (p == null) { sb.append('.'); } else { sb.append(p.toRsp()); } } sb.append(" | "); } sb.append(stmt.toString()).append('\n'); } return sb.toString(); } }