Home | History | Annotate | Download | only in dump
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dx.command.dump;
     18 
     19 import com.android.dx.cf.code.ConcreteMethod;
     20 import com.android.dx.cf.code.Ropper;
     21 import com.android.dx.cf.iface.Member;
     22 import com.android.dx.cf.iface.Method;
     23 import com.android.dx.rop.code.AccessFlags;
     24 import com.android.dx.rop.code.DexTranslationAdvice;
     25 import com.android.dx.rop.code.RopMethod;
     26 import com.android.dx.rop.code.TranslationAdvice;
     27 import com.android.dx.ssa.Optimizer;
     28 import com.android.dx.ssa.SsaBasicBlock;
     29 import com.android.dx.ssa.SsaInsn;
     30 import com.android.dx.ssa.SsaMethod;
     31 import com.android.dx.util.ByteArray;
     32 import com.android.dx.util.Hex;
     33 import com.android.dx.util.IntList;
     34 import java.io.PrintStream;
     35 import java.util.ArrayList;
     36 import java.util.BitSet;
     37 import java.util.Collections;
     38 import java.util.EnumSet;
     39 
     40 /**
     41  * Dumper for the SSA-translated blocks of a method.
     42  */
     43 public class SsaDumper extends BlockDumper {
     44     /**
     45      * Does the dump.
     46      *
     47      * @param bytes {@code non-null;} bytes of the original class file
     48      * @param out {@code non-null;} where to dump to
     49      * @param filePath the file path for the class, excluding any base
     50      * directory specification
     51      * @param args commandline parsedArgs
     52      */
     53     public static void dump(byte[] bytes, PrintStream out,
     54             String filePath, Args args) {
     55         SsaDumper sd = new SsaDumper(bytes, out, filePath, args);
     56         sd.dump();
     57     }
     58 
     59     /**
     60      * Constructs an instance.
     61      *
     62      * @param bytes {@code non-null;} bytes of the original class file
     63      * @param out {@code non-null;} where to dump to
     64      * @param filePath the file path for the class, excluding any base
     65      * directory specification
     66      * @param args commandline parsedArgs
     67      */
     68     private SsaDumper(byte[] bytes, PrintStream out, String filePath,
     69             Args args) {
     70         super(bytes, out, filePath, true, args);
     71     }
     72 
     73     /** {@inheritDoc} */
     74     @Override
     75     public void endParsingMember(ByteArray bytes, int offset, String name,
     76             String descriptor, Member member) {
     77         if (!(member instanceof Method)) {
     78             return;
     79         }
     80 
     81         if (!shouldDumpMethod(name)) {
     82             return;
     83         }
     84 
     85         if ((member.getAccessFlags() & (AccessFlags.ACC_ABSTRACT |
     86                 AccessFlags.ACC_NATIVE)) != 0) {
     87             return;
     88         }
     89 
     90         ConcreteMethod meth =
     91             new ConcreteMethod((Method) member, classFile, true, true);
     92         TranslationAdvice advice = DexTranslationAdvice.THE_ONE;
     93         RopMethod rmeth = Ropper.convert(meth, advice, classFile.getMethods(), dexOptions);
     94         SsaMethod ssaMeth = null;
     95         boolean isStatic = AccessFlags.isStatic(meth.getAccessFlags());
     96         int paramWidth = computeParamWidth(meth, isStatic);
     97 
     98         if (args.ssaStep == null) {
     99             ssaMeth = Optimizer.debugNoRegisterAllocation(rmeth,
    100                     paramWidth, isStatic, true, advice,
    101                     EnumSet.allOf(Optimizer.OptionalStep.class));
    102         } else if ("edge-split".equals(args.ssaStep)) {
    103             ssaMeth = Optimizer.debugEdgeSplit(rmeth, paramWidth,
    104                     isStatic, true, advice);
    105         } else if ("phi-placement".equals(args.ssaStep)) {
    106             ssaMeth = Optimizer.debugPhiPlacement(
    107                     rmeth, paramWidth, isStatic, true, advice);
    108         } else if ("renaming".equals(args.ssaStep)) {
    109             ssaMeth = Optimizer.debugRenaming(
    110                     rmeth, paramWidth, isStatic, true, advice);
    111         } else if ("dead-code".equals(args.ssaStep)) {
    112             ssaMeth = Optimizer.debugDeadCodeRemover(
    113                     rmeth, paramWidth, isStatic,true, advice);
    114         }
    115 
    116         StringBuilder sb = new StringBuilder(2000);
    117 
    118         sb.append("first ");
    119         sb.append(Hex.u2(
    120                 ssaMeth.blockIndexToRopLabel(ssaMeth.getEntryBlockIndex())));
    121         sb.append('\n');
    122 
    123         ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
    124         ArrayList<SsaBasicBlock> sortedBlocks =
    125             (ArrayList<SsaBasicBlock>) blocks.clone();
    126         Collections.sort(sortedBlocks, SsaBasicBlock.LABEL_COMPARATOR);
    127 
    128         for (SsaBasicBlock block : sortedBlocks) {
    129             sb.append("block ")
    130                     .append(Hex.u2(block.getRopLabel())).append('\n');
    131 
    132             BitSet preds = block.getPredecessors();
    133 
    134             for (int i = preds.nextSetBit(0); i >= 0;
    135                  i = preds.nextSetBit(i+1)) {
    136                 sb.append("  pred ");
    137                 sb.append(Hex.u2(ssaMeth.blockIndexToRopLabel(i)));
    138                 sb.append('\n');
    139             }
    140 
    141             sb.append("  live in:" + block.getLiveInRegs());
    142             sb.append("\n");
    143 
    144             for (SsaInsn insn : block.getInsns()) {
    145                 sb.append("  ");
    146                 sb.append(insn.toHuman());
    147                 sb.append('\n');
    148             }
    149 
    150             if (block.getSuccessors().cardinality() == 0) {
    151                 sb.append("  returns\n");
    152             } else {
    153                 int primary = block.getPrimarySuccessorRopLabel();
    154 
    155                 IntList succLabelList = block.getRopLabelSuccessorList();
    156 
    157                 int szSuccLabels = succLabelList.size();
    158 
    159                 for (int i = 0; i < szSuccLabels; i++) {
    160                     sb.append("  next ");
    161                     sb.append(Hex.u2(succLabelList.get(i)));
    162 
    163                     if (szSuccLabels != 1 && primary == succLabelList.get(i)) {
    164                         sb.append(" *");
    165                     }
    166                     sb.append('\n');
    167                 }
    168             }
    169 
    170             sb.append("  live out:" + block.getLiveOutRegs());
    171             sb.append("\n");
    172         }
    173 
    174         suppressDump = false;
    175         parsed(bytes, 0, bytes.size(), sb.toString());
    176         suppressDump = true;
    177     }
    178 }
    179