1 /* 2 * Copyright (C) 2008 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.ssa; 18 19 import com.android.dx.rop.code.CstInsn; 20 import com.android.dx.rop.code.LocalItem; 21 import com.android.dx.rop.code.RegOps; 22 import com.android.dx.rop.code.RegisterSpec; 23 import com.android.dx.rop.cst.CstInteger; 24 import java.util.HashSet; 25 import java.util.List; 26 27 /** 28 * Combine identical move-param insns, which may result from Ropper's 29 * handling of synchronized methods. 30 */ 31 public class MoveParamCombiner { 32 33 /** method to process */ 34 private final SsaMethod ssaMeth; 35 36 /** 37 * Processes a method with this optimization step. 38 * 39 * @param ssaMethod method to process 40 */ 41 public static void process(SsaMethod ssaMethod) { 42 new MoveParamCombiner(ssaMethod).run(); 43 } 44 45 private MoveParamCombiner(SsaMethod ssaMeth) { 46 this.ssaMeth = ssaMeth; 47 } 48 49 /** 50 * Runs this optimization step. 51 */ 52 private void run() { 53 // This will contain the definition specs for each parameter 54 final RegisterSpec[] paramSpecs 55 = new RegisterSpec[ssaMeth.getParamWidth()]; 56 57 // Insns to delete when all done 58 final HashSet<SsaInsn> deletedInsns = new HashSet(); 59 60 ssaMeth.forEachInsn(new SsaInsn.Visitor() { 61 @Override 62 public void visitMoveInsn (NormalSsaInsn insn) { 63 } 64 @Override 65 public void visitPhiInsn (PhiInsn phi) { 66 } 67 @Override 68 public void visitNonMoveInsn (NormalSsaInsn insn) { 69 if (insn.getOpcode().getOpcode() != RegOps.MOVE_PARAM) { 70 return; 71 } 72 73 int param = getParamIndex(insn); 74 75 if (paramSpecs[param] == null) { 76 paramSpecs[param] = insn.getResult(); 77 } else { 78 final RegisterSpec specA = paramSpecs[param]; 79 final RegisterSpec specB = insn.getResult(); 80 LocalItem localA = specA.getLocalItem(); 81 LocalItem localB = specB.getLocalItem(); 82 LocalItem newLocal; 83 84 /* 85 * Is there local information to preserve? 86 */ 87 88 if (localA == null) { 89 newLocal = localB; 90 } else if (localB == null) { 91 newLocal = localA; 92 } else if (localA.equals(localB)) { 93 newLocal = localA; 94 } else { 95 /* 96 * Oddly, these two identical move-params have distinct 97 * debug info. We'll just keep them distinct. 98 */ 99 return; 100 } 101 102 ssaMeth.getDefinitionForRegister(specA.getReg()) 103 .setResultLocal(newLocal); 104 105 /* 106 * Map all uses of specB to specA 107 */ 108 109 RegisterMapper mapper = new RegisterMapper() { 110 /** {@inheritDoc} */ 111 @Override 112 public int getNewRegisterCount() { 113 return ssaMeth.getRegCount(); 114 } 115 116 /** {@inheritDoc} */ 117 @Override 118 public RegisterSpec map(RegisterSpec registerSpec) { 119 if (registerSpec.getReg() == specB.getReg()) { 120 return specA; 121 } 122 123 return registerSpec; 124 } 125 }; 126 127 List<SsaInsn> uses 128 = ssaMeth.getUseListForRegister(specB.getReg()); 129 130 // Use list is modified by mapSourceRegisters 131 for (int i = uses.size() - 1; i >= 0; i--) { 132 SsaInsn use = uses.get(i); 133 use.mapSourceRegisters(mapper); 134 } 135 136 deletedInsns.add(insn); 137 } 138 139 } 140 }); 141 142 ssaMeth.deleteInsns(deletedInsns); 143 } 144 145 /** 146 * Returns the parameter index associated with a move-param insn. Does 147 * not verify that the insn is a move-param insn. 148 * 149 * @param insn {@code non-null;} a move-param insn 150 * @return {@code >=0;} parameter index 151 */ 152 private int getParamIndex(NormalSsaInsn insn) { 153 CstInsn cstInsn = (CstInsn)(insn.getOriginalRopInsn()); 154 155 int param = ((CstInteger)cstInsn.getConstant()).getValue(); 156 return param; 157 } 158 159 } 160