• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.RegisterSpec;
20 import com.android.dx.rop.code.RegOps;
21 import com.android.dx.rop.code.CstInsn;
22 import com.android.dx.rop.code.LocalItem;
23 import com.android.dx.rop.cst.CstInteger;
24 
25 import java.util.HashSet;
26 import java.util.ArrayList;
27 import java.util.List;
28 
29 /**
30  * Combine identical move-param insns, which may result from Ropper's
31  * handling of synchronized methods.
32  */
33 public 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      */
process(SsaMethod ssaMethod)43     public static void process(SsaMethod ssaMethod) {
44         new MoveParamCombiner(ssaMethod).run();
45     }
46 
MoveParamCombiner(SsaMethod ssaMeth)47     private MoveParamCombiner(SsaMethod ssaMeth) {
48         this.ssaMeth = ssaMeth;
49     }
50 
51     /**
52      * Runs this optimization step.
53      */
run()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      */
getParamIndex(NormalSsaInsn insn)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