■ ■ ■ ■ ■ ■
jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java
| skipped 14 lines |
15 | 15 | | import jadx.core.dex.nodes.MethodNode; |
16 | 16 | | import jadx.core.dex.regions.SwitchRegion; |
17 | 17 | | import jadx.core.dex.regions.conditions.IfRegion; |
| 18 | + | import jadx.core.dex.regions.loops.ForLoop; |
| 19 | + | import jadx.core.dex.regions.loops.LoopRegion; |
| 20 | + | import jadx.core.dex.regions.loops.LoopType; |
18 | 21 | | import jadx.core.dex.visitors.AbstractVisitor; |
19 | 22 | | import jadx.core.utils.RegionUtils; |
20 | 23 | | import jadx.core.utils.exceptions.JadxException; |
| skipped 91 lines |
112 | 115 | | } |
113 | 116 | | } |
114 | 117 | | |
| 118 | + | private static class CollectUsageRegionVisitor extends TracedRegionVisitor { |
| 119 | + | private final List<RegisterArg> args; |
| 120 | + | private final Map<Variable, Usage> usageMap; |
| 121 | + | |
| 122 | + | public CollectUsageRegionVisitor(Map<Variable, Usage> usageMap) { |
| 123 | + | this.usageMap = usageMap; |
| 124 | + | args = new ArrayList<RegisterArg>(); |
| 125 | + | } |
| 126 | + | |
| 127 | + | @Override |
| 128 | + | public void processBlockTraced(MethodNode mth, IBlock container, IRegion curRegion) { |
| 129 | + | regionProcess(mth, curRegion); |
| 130 | + | int len = container.getInstructions().size(); |
| 131 | + | for (int i = 0; i < len; i++) { |
| 132 | + | InsnNode insn = container.getInstructions().get(i); |
| 133 | + | if (insn.contains(AFlag.SKIP)) { |
| 134 | + | continue; |
| 135 | + | } |
| 136 | + | args.clear(); |
| 137 | + | processInsn(insn, curRegion); |
| 138 | + | } |
| 139 | + | } |
| 140 | + | |
| 141 | + | private void regionProcess(MethodNode mth, IRegion region) { |
| 142 | + | if (region instanceof LoopRegion) { |
| 143 | + | LoopRegion loopRegion = (LoopRegion) region; |
| 144 | + | LoopType loopType = loopRegion.getType(); |
| 145 | + | if (loopType instanceof ForLoop) { |
| 146 | + | ForLoop forLoop = (ForLoop) loopType; |
| 147 | + | processInsn(forLoop.getInitInsn(), region); |
| 148 | + | processInsn(forLoop.getIncrInsn(), region); |
| 149 | + | } |
| 150 | + | } |
| 151 | + | } |
| 152 | + | |
| 153 | + | void processInsn(InsnNode insn, IRegion curRegion) { |
| 154 | + | if (insn == null) { |
| 155 | + | return; |
| 156 | + | } |
| 157 | + | // result |
| 158 | + | RegisterArg result = insn.getResult(); |
| 159 | + | if (result != null && result.isRegister()) { |
| 160 | + | Usage u = addToUsageMap(result, usageMap); |
| 161 | + | if (u.getArg() == null) { |
| 162 | + | u.setArg(result); |
| 163 | + | u.setArgRegion(curRegion); |
| 164 | + | } |
| 165 | + | u.getAssigns().add(curRegion); |
| 166 | + | } |
| 167 | + | // args |
| 168 | + | args.clear(); |
| 169 | + | insn.getRegisterArgs(args); |
| 170 | + | for (RegisterArg arg : args) { |
| 171 | + | Usage u = addToUsageMap(arg, usageMap); |
| 172 | + | u.getUseRegions().add(curRegion); |
| 173 | + | } |
| 174 | + | } |
| 175 | + | } |
| 176 | + | |
115 | 177 | | @Override |
116 | 178 | | public void visit(MethodNode mth) throws JadxException { |
117 | 179 | | if (mth.isNoCode()) { |
118 | 180 | | return; |
119 | 181 | | } |
120 | | - | |
121 | 182 | | final Map<Variable, Usage> usageMap = new LinkedHashMap<Variable, Usage>(); |
122 | 183 | | for (RegisterArg arg : mth.getArguments(true)) { |
123 | 184 | | addToUsageMap(arg, usageMap); |
124 | 185 | | } |
125 | 186 | | |
126 | 187 | | // collect all variables usage |
127 | | - | IRegionVisitor collect = new TracedRegionVisitor() { |
128 | | - | @Override |
129 | | - | public void processBlockTraced(MethodNode mth, IBlock container, IRegion curRegion) { |
130 | | - | int len = container.getInstructions().size(); |
131 | | - | List<RegisterArg> args = new ArrayList<RegisterArg>(); |
132 | | - | for (int i = 0; i < len; i++) { |
133 | | - | InsnNode insn = container.getInstructions().get(i); |
134 | | - | // result |
135 | | - | RegisterArg result = insn.getResult(); |
136 | | - | if (result != null && result.isRegister()) { |
137 | | - | Usage u = addToUsageMap(result, usageMap); |
138 | | - | if (u.getArg() == null) { |
139 | | - | u.setArg(result); |
140 | | - | u.setArgRegion(curRegion); |
141 | | - | } |
142 | | - | u.getAssigns().add(curRegion); |
143 | | - | } |
144 | | - | // args |
145 | | - | args.clear(); |
146 | | - | insn.getRegisterArgs(args); |
147 | | - | for (RegisterArg arg : args) { |
148 | | - | Usage u = addToUsageMap(arg, usageMap); |
149 | | - | u.getUseRegions().add(curRegion); |
150 | | - | } |
151 | | - | } |
152 | | - | } |
153 | | - | }; |
| 188 | + | IRegionVisitor collect = new CollectUsageRegionVisitor(usageMap); |
154 | 189 | | DepthRegionTraversal.traverseAll(mth, collect); |
155 | 190 | | |
156 | 191 | | // reduce assigns map |
| skipped 32 lines |
189 | 224 | | for (IRegion assignRegion : u.getAssigns()) { |
190 | 225 | | if (u.getArgRegion() == assignRegion |
191 | 226 | | && canDeclareInRegion(u, assignRegion, regionsOrder)) { |
192 | | - | u.getArg().getParentInsn().add(AFlag.DECLARE_VAR); |
193 | | - | processVar(u.getArg()); |
194 | | - | it.remove(); |
195 | | - | break; |
| 227 | + | if (declareAtAssign(u)) { |
| 228 | + | it.remove(); |
| 229 | + | break; |
| 230 | + | } |
196 | 231 | | } |
197 | 232 | | } |
198 | 233 | | } |
| skipped 40 lines |
239 | 274 | | } |
240 | 275 | | } |
241 | 276 | | |
242 | | - | Usage addToUsageMap(RegisterArg arg, Map<Variable, Usage> usageMap) { |
| 277 | + | private static Usage addToUsageMap(RegisterArg arg, Map<Variable, Usage> usageMap) { |
243 | 278 | | Variable varId = new Variable(arg); |
244 | 279 | | Usage usage = usageMap.get(varId); |
245 | 280 | | if (usage == null) { |
| skipped 14 lines |
260 | 295 | | return usage; |
261 | 296 | | } |
262 | 297 | | |
| 298 | + | private static boolean declareAtAssign(Usage u) { |
| 299 | + | RegisterArg arg = u.getArg(); |
| 300 | + | InsnNode parentInsn = arg.getParentInsn(); |
| 301 | + | if (!arg.equals(parentInsn.getResult())) { |
| 302 | + | return false; |
| 303 | + | } |
| 304 | + | parentInsn.add(AFlag.DECLARE_VAR); |
| 305 | + | processVar(arg); |
| 306 | + | return true; |
| 307 | + | } |
| 308 | + | |
263 | 309 | | private static void declareVar(IContainer region, RegisterArg arg) { |
264 | 310 | | DeclareVariablesAttr dv = region.get(AType.DECLARE_VARIABLES); |
265 | 311 | | if (dv == null) { |
| skipped 41 lines |
307 | 353 | | if (pos == null) { |
308 | 354 | | LOG.debug("TODO: Not found order for region {} for {}", region, u); |
309 | 355 | | return false; |
| 356 | + | } |
| 357 | + | // workaround for declare variables used in several loops |
| 358 | + | if (region instanceof LoopRegion) { |
| 359 | + | for (IRegion r : u.getAssigns()) { |
| 360 | + | if (!RegionUtils.isRegionContainsRegion(region, r)) { |
| 361 | + | return false; |
| 362 | + | } |
| 363 | + | } |
310 | 364 | | } |
311 | 365 | | return isAllRegionsAfter(region, pos, u.getAssigns(), regionsOrder) |
312 | 366 | | && isAllRegionsAfter(region, pos, u.getUseRegions(), regionsOrder); |
| skipped 33 lines |