11package jadx .core .dex .visitors ;
22
3- import java .util .HashSet ;
3+ import java .util .ArrayList ;
4+ import java .util .Collections ;
5+ import java .util .IdentityHashMap ;
46import java .util .List ;
57import java .util .Map ;
8+ import java .util .Set ;
69import java .util .SortedMap ;
710import java .util .TreeMap ;
811
912import jadx .core .dex .attributes .AFlag ;
13+ import jadx .core .dex .attributes .nodes .CodeFeaturesAttr ;
14+ import jadx .core .dex .attributes .nodes .CodeFeaturesAttr .CodeFeature ;
1015import jadx .core .dex .instructions .FilledNewArrayNode ;
1116import jadx .core .dex .instructions .IndexInsnNode ;
1217import jadx .core .dex .instructions .InsnType ;
@@ -35,21 +40,20 @@ public class ReplaceNewArray extends AbstractVisitor {
3540
3641 @ Override
3742 public void visit (MethodNode mth ) throws JadxException {
38- if (mth . isNoCode ( )) {
43+ if (! CodeFeaturesAttr . contains ( mth , CodeFeature . NEW_ARRAY )) {
3944 return ;
4045 }
46+ InsnRemover remover = new InsnRemover (mth );
4147 int k = 0 ;
4248 while (true ) {
4349 boolean changed = false ;
44- InsnRemover remover = new InsnRemover (mth );
4550 for (BlockNode block : mth .getBasicBlocks ()) {
46- remover .setBlock (block );
47- List <InsnNode > instructions = block .getInstructions ();
48- int size = instructions .size ();
51+ List <InsnNode > insnList = block .getInstructions ();
52+ int size = insnList .size ();
4953 for (int i = 0 ; i < size ; i ++) {
50- changed |= processInsn (mth , instructions , i , remover );
54+ changed |= processInsn (mth , insnList , i , remover );
5155 }
52- remover .perform ( );
56+ remover .performForBlock ( block );
5357 }
5458 if (changed ) {
5559 CodeShrinkVisitor .shrinkMethod (mth );
@@ -107,12 +111,11 @@ private static boolean processNewArray(MethodNode mth,
107111 SortedMap <Long , InsnNode > arrPuts = new TreeMap <>();
108112 for (RegisterArg registerArg : useList ) {
109113 InsnNode parentInsn = registerArg .getParentInsn ();
110- if (parentInsn == null || parentInsn .getType () != InsnType .APUT ) {
114+ if (parentInsn == null
115+ || parentInsn .getType () != InsnType .APUT
116+ || !arrArg .sameRegAndSVar (parentInsn .getArg (0 ))) {
111117 continue ;
112118 }
113- if (!arrArg .sameRegAndSVar (parentInsn .getArg (0 ))) {
114- return false ;
115- }
116119 Object constVal = InsnUtils .getConstValueByArg (mth .root (), parentInsn .getArg (1 ));
117120 if (!(constVal instanceof LiteralArg )) {
118121 return false ;
@@ -130,8 +133,7 @@ private static boolean processNewArray(MethodNode mth,
130133 if (arrPuts .size () < minLen ) {
131134 return false ;
132135 }
133- // expect all puts to be in same block
134- if (!new HashSet <>(instructions ).containsAll (arrPuts .values ())) {
136+ if (!verifyPutInsns (arrArg , instructions , arrPuts )) {
135137 return false ;
136138 }
137139
@@ -165,6 +167,28 @@ private static boolean processNewArray(MethodNode mth,
165167 return true ;
166168 }
167169
170+ private static boolean verifyPutInsns (RegisterArg arrReg , List <InsnNode > insnList , SortedMap <Long , InsnNode > arrPuts ) {
171+ List <InsnNode > puts = new ArrayList <>(arrPuts .values ());
172+ int putsCount = puts .size ();
173+ // expect all puts to be in the same block
174+ if (insnList .size () < putsCount ) {
175+ return false ;
176+ }
177+ Set <InsnNode > insnSet = Collections .newSetFromMap (new IdentityHashMap <>());
178+ insnSet .addAll (insnList );
179+ if (!insnSet .containsAll (puts )) {
180+ return false ;
181+ }
182+ // array arg shouldn't be used in puts insns
183+ for (InsnNode put : puts ) {
184+ InsnArg putArg = put .getArg (2 );
185+ if (putArg .isUseVar (arrReg )) {
186+ return false ;
187+ }
188+ }
189+ return true ;
190+ }
191+
168192 private static InsnArg replaceConstInArg (MethodNode mth , InsnArg valueArg ) {
169193 if (valueArg .isLiteral ()) {
170194 IFieldInfoRef f = mth .getParentClass ().getConstFieldByLiteralArg ((LiteralArg ) valueArg );
0 commit comments