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 17package com.android.dx.command.dump; 18 19import com.android.dx.cf.code.ConcreteMethod; 20import com.android.dx.cf.code.Ropper; 21import com.android.dx.cf.iface.Member; 22import com.android.dx.cf.iface.Method; 23import com.android.dx.rop.code.AccessFlags; 24import com.android.dx.rop.code.DexTranslationAdvice; 25import com.android.dx.rop.code.RopMethod; 26import com.android.dx.rop.code.TranslationAdvice; 27import com.android.dx.ssa.Optimizer; 28import com.android.dx.ssa.SsaBasicBlock; 29import com.android.dx.ssa.SsaInsn; 30import com.android.dx.ssa.SsaMethod; 31import com.android.dx.util.ByteArray; 32import com.android.dx.util.Hex; 33import com.android.dx.util.IntList; 34import java.io.PrintStream; 35import java.util.ArrayList; 36import java.util.BitSet; 37import java.util.Collections; 38import java.util.EnumSet; 39 40/** 41 * Dumper for the SSA-translated blocks of a method. 42 */ 43public 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()); 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 StringBuffer sb = new StringBuffer(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 setAt(bytes, 0); 176 parsed(bytes, 0, bytes.size(), sb.toString()); 177 suppressDump = true; 178 } 179} 180