/* * Copyright (C) 2007 The Android Open Source Project * * 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.android.dx.command.dump; import com.android.dx.cf.code.ConcreteMethod; import com.android.dx.cf.code.Ropper; import com.android.dx.cf.iface.Member; import com.android.dx.cf.iface.Method; import com.android.dx.rop.code.RopMethod; import com.android.dx.rop.code.TranslationAdvice; import com.android.dx.rop.code.DexTranslationAdvice; import com.android.dx.rop.code.AccessFlags; import com.android.dx.ssa.DeadCodeRemover; import com.android.dx.ssa.PhiTypeResolver; import com.android.dx.ssa.SsaBasicBlock; import com.android.dx.ssa.SsaConverter; import com.android.dx.ssa.SsaInsn; import com.android.dx.ssa.SsaMethod; import com.android.dx.ssa.Optimizer; import com.android.dx.ssa.ConstCollector; import com.android.dx.ssa.SCCP; import com.android.dx.ssa.LiteralOpUpgrader; import com.android.dx.ssa.back.SsaToRop; import com.android.dx.util.ByteArray; import com.android.dx.util.Hex; import com.android.dx.util.IntList; import java.io.PrintStream; import java.util.ArrayList; import java.util.BitSet; import java.util.Collections; import java.util.EnumSet; /** * Dumper for the SSA-translated blocks of a method. */ public class SsaDumper extends BlockDumper { /** * Does the dump. * * @param bytes {@code non-null;} bytes of the original class file * @param out {@code non-null;} where to dump to * @param filePath the file path for the class, excluding any base * directory specification * @param args commandline parsedArgs */ public static void dump(byte[] bytes, PrintStream out, String filePath, Args args) { SsaDumper sd = new SsaDumper(bytes, out, filePath, args); sd.dump(); } /** * Constructs an instance. * * @param bytes {@code non-null;} bytes of the original class file * @param out {@code non-null;} where to dump to * @param filePath the file path for the class, excluding any base * directory specification * @param args commandline parsedArgs */ private SsaDumper(byte[] bytes, PrintStream out, String filePath, Args args) { super(bytes, out, filePath, true, args); } /** {@inheritDoc} */ @Override public void endParsingMember(ByteArray bytes, int offset, String name, String descriptor, Member member) { if (!(member instanceof Method)) { return; } if (!shouldDumpMethod(name)) { return; } ConcreteMethod meth = new ConcreteMethod((Method) member, classFile, true, true); TranslationAdvice advice = DexTranslationAdvice.THE_ONE; RopMethod rmeth = Ropper.convert(meth, advice); SsaMethod ssaMeth = null; boolean isStatic = AccessFlags.isStatic(meth.getAccessFlags()); int paramWidth = computeParamWidth(meth, isStatic); if (args.ssaStep == null) { ssaMeth = Optimizer.debugNoRegisterAllocation(rmeth, paramWidth, isStatic, true, advice, EnumSet.allOf(Optimizer.OptionalStep.class)); } else if ("edge-split".equals(args.ssaStep)) { ssaMeth = Optimizer.debugEdgeSplit(rmeth, paramWidth, isStatic, true, advice); } else if ("phi-placement".equals(args.ssaStep)) { ssaMeth = Optimizer.debugPhiPlacement( rmeth, paramWidth, isStatic, true, advice); } else if ("renaming".equals(args.ssaStep)) { ssaMeth = Optimizer.debugRenaming( rmeth, paramWidth, isStatic, true, advice); } else if ("dead-code".equals(args.ssaStep)) { ssaMeth = Optimizer.debugDeadCodeRemover( rmeth, paramWidth, isStatic,true, advice); } StringBuffer sb = new StringBuffer(2000); sb.append("first "); sb.append(Hex.u2( ssaMeth.blockIndexToRopLabel(ssaMeth.getEntryBlockIndex()))); sb.append('\n'); ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks(); ArrayList<SsaBasicBlock> sortedBlocks = (ArrayList<SsaBasicBlock>) blocks.clone(); Collections.sort(sortedBlocks, SsaBasicBlock.LABEL_COMPARATOR); for (SsaBasicBlock block : sortedBlocks) { sb.append("block ") .append(Hex.u2(block.getRopLabel())).append('\n'); BitSet preds = block.getPredecessors(); for (int i = preds.nextSetBit(0); i >= 0; i = preds.nextSetBit(i+1)) { sb.append(" pred "); sb.append(Hex.u2(ssaMeth.blockIndexToRopLabel(i))); sb.append('\n'); } sb.append(" live in:" + block.getLiveInRegs()); sb.append("\n"); for (SsaInsn insn : block.getInsns()) { sb.append(" "); sb.append(insn.toHuman()); sb.append('\n'); } if (block.getSuccessors().cardinality() == 0) { sb.append(" returns\n"); } else { int primary = block.getPrimarySuccessorRopLabel(); IntList succLabelList = block.getRopLabelSuccessorList(); int szSuccLabels = succLabelList.size(); for (int i = 0; i < szSuccLabels; i++) { sb.append(" next "); sb.append(Hex.u2(succLabelList.get(i))); if (szSuccLabels != 1 && primary == succLabelList.get(i)) { sb.append(" *"); } sb.append('\n'); } } sb.append(" live out:" + block.getLiveOutRegs()); sb.append("\n"); } suppressDump = false; setAt(bytes, 0); parsed(bytes, 0, bytes.size(), sb.toString()); suppressDump = true; } }