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