JumboStringConversionTest.java revision e94ee6fe80deea0e9d4e2a28a7b7d20137e25a83
1/*
2 * Copyright 2012, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.jf.dexlib2.writer;
33
34// TODO: uncomment/reimplement
35/*public class JumboStringConversionTest {
36    private static final int MIN_NUM_JUMBO_STRINGS = 2;
37
38    private MockStringIndexProvider mockStringIndexProvider;
39    ArrayList<String> mJumboStrings;
40
41    private class InsnWriteUtil extends InstructionWriteUtil<StringReference, Reference> {
42        public InsnWriteUtil(@Nonnull MethodImplementation implementation) {
43            super(implementation.getInstructions(), mockStringIndexProvider, ImmutableInstructionFactory.INSTANCE);
44        }
45    }
46
47    @Before
48    public void setup() {
49        mockStringIndexProvider = new MockStringIndexProvider();
50        StringBuilder stringBuilder = new StringBuilder("a");
51        mJumboStrings = Lists.newArrayList();
52        int index = 0;
53
54        // populate StringPool, make sure there are more than 64k+MIN_NUM_JUMBO_STRINGS strings
55        while (mJumboStrings.size()<MIN_NUM_JUMBO_STRINGS) {
56            for (int pos=stringBuilder.length()-1;pos>=0;pos--) {
57                for (char ch='a';ch<='z';ch++) {
58                    stringBuilder.setCharAt(pos, ch);
59                    mockStringIndexProvider.intern(stringBuilder.toString(), index++);
60                    if (mockStringIndexProvider.getNumItems()>0xFFFF) {
61                        mJumboStrings.add(stringBuilder.toString());
62                    }
63                }
64            }
65
66            stringBuilder.setLength(stringBuilder.length()+1);
67            for (int pos=0;pos<stringBuilder.length();pos++) {
68                stringBuilder.setCharAt(pos, 'a');
69            }
70        }
71    }
72
73    @Test
74    public void testInstruction21c() {
75        ArrayList<ImmutableInstruction> instructions = Lists.newArrayList();
76        instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0,
77                new ImmutableStringReference(mJumboStrings.get(0))));
78
79        ImmutableMethodImplementation methodImplementation =
80                new ImmutableMethodImplementation(1, instructions, null, null);
81        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
82
83        for (Instruction instr: writeUtil.getInstructions()) {
84            Assert.assertEquals("Jumbo string conversion was not performed!",
85                    instr.getOpcode(), Opcode.CONST_STRING_JUMBO);
86        }
87    }
88
89    private ArrayList<ImmutableInstruction> createSimpleInstructionList() {
90        ArrayList<ImmutableInstruction> instructions = Lists.newArrayList();
91        instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(0))));
92        instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(1))));
93        instructions.add(new ImmutableInstruction10x(Opcode.NOP));
94
95        ArrayList<SwitchElement> switchElements = Lists.newArrayList();
96        switchElements.add(new ImmutableSwitchElement(0, 5));
97        instructions.add(new ImmutablePackedSwitchPayload(switchElements));
98        instructions.add(new ImmutableSparseSwitchPayload(switchElements));
99
100        return instructions;
101    }
102
103    @Test
104    public void testInstruction10tSimple() {
105        ArrayList<ImmutableInstruction> instructions = createSimpleInstructionList();
106        instructions.add(1, new ImmutableInstruction10t(Opcode.GOTO, 3));
107
108        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
109        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
110
111        for (Instruction instr: writeUtil.getInstructions()) {
112            if (instr instanceof Instruction10t) {
113                Instruction10t instruction = (Instruction10t) instr;
114                Assert.assertEquals("goto (Format10t) target was not modified properly", instruction.getCodeOffset(), 4);
115                break;
116            }
117        }
118    }
119
120    @Test
121    public void testInstruction20tSimple() {
122        ArrayList<ImmutableInstruction> instructions = createSimpleInstructionList();
123        instructions.add(1, new ImmutableInstruction20t(Opcode.GOTO_16, 4));
124
125        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
126        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
127
128        for (Instruction instr: writeUtil.getInstructions()) {
129            if (instr instanceof Instruction20t) {
130                Instruction20t instruction = (Instruction20t) instr;
131                Assert.assertEquals("goto/16 (Format20t) target was not modified properly", instruction.getCodeOffset(), 5);
132                break;
133            }
134        }
135    }
136
137    @Test
138    public void testInstruction30t() {
139        ArrayList<ImmutableInstruction> instructions = createSimpleInstructionList();
140        instructions.add(1, new ImmutableInstruction30t(Opcode.GOTO_32, 5));
141
142        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
143        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
144
145        for (Instruction instr: writeUtil.getInstructions()) {
146            if (instr instanceof Instruction30t) {
147                Instruction30t instruction = (Instruction30t) instr;
148                Assert.assertEquals("goto/32 (Format30t) target was not modified properly", instruction.getCodeOffset(), 6);
149                break;
150            }
151        }
152    }
153
154    @Test
155    public void testInstruction21t() {
156        ArrayList<ImmutableInstruction> instructions = createSimpleInstructionList();
157        instructions.add(1, new ImmutableInstruction21t(Opcode.IF_EQZ, 0, 4));
158
159        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
160        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
161
162        for (Instruction instr: writeUtil.getInstructions()) {
163            if (instr instanceof Instruction21t) {
164                Instruction21t instruction = (Instruction21t) instr;
165                Assert.assertEquals("branch instruction (Format21t) target was not modified properly", instruction.getCodeOffset(), 5);
166                break;
167            }
168        }
169    }
170
171    @Test
172    public void testInstruction22t() {
173        ArrayList<ImmutableInstruction> instructions = createSimpleInstructionList();
174        instructions.add(1, new ImmutableInstruction22t(Opcode.IF_EQ, 0, 1, 4));
175
176        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
177        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
178
179        for (Instruction instr: writeUtil.getInstructions()) {
180            if (instr instanceof Instruction22t) {
181                Instruction22t instruction = (Instruction22t) instr;
182                Assert.assertEquals("branch instruction (Format22t) target was not modified properly", instruction.getCodeOffset(), 5);
183                break;
184            }
185        }
186    }
187
188    @Test
189    public void testInstruction31t() {
190        ArrayList<ImmutableInstruction> instructions = createSimpleInstructionList();
191        instructions.add(1, new ImmutableInstruction31t(Opcode.PACKED_SWITCH, 0, 5));
192
193        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
194        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
195
196        for (Instruction instr: writeUtil.getInstructions()) {
197            if (instr instanceof Instruction31t) {
198                Instruction31t instruction = (Instruction31t) instr;
199                Assert.assertEquals("branch instruction (Format31t) target was not modified properly", instruction.getCodeOffset(), 6);
200                break;
201            }
202        }
203    }
204
205    @Test
206    public void testPackedSwitchPayload() {
207        ArrayList<ImmutableInstruction> instructions = createSimpleInstructionList();
208        instructions.add(1, new ImmutableInstruction31t(Opcode.PACKED_SWITCH, 0, 6));
209
210        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
211        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
212
213        for (Instruction instr: writeUtil.getInstructions()) {
214            if (instr instanceof PackedSwitchPayload) {
215                PackedSwitchPayload instruction = (PackedSwitchPayload) instr;
216                for (SwitchElement switchElement: instruction.getSwitchElements()) {
217                    Assert.assertEquals("packed switch payload offset was not modified properly", switchElement.getOffset(), 6);
218                }
219                break;
220            }
221        }
222    }
223
224    @Test
225    public void testSparseSwitchPayload() {
226        ArrayList<ImmutableInstruction> instructions = createSimpleInstructionList();
227        instructions.add(1, new ImmutableInstruction31t(Opcode.SPARSE_SWITCH, 0, 12));
228
229        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
230        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
231
232        for (Instruction instr: writeUtil.getInstructions()) {
233            if (instr instanceof SparseSwitchPayload) {
234                SparseSwitchPayload instruction = (SparseSwitchPayload) instr;
235                for (SwitchElement switchElement: instruction.getSwitchElements()) {
236                    Assert.assertEquals("packed switch payload offset was not modified properly", switchElement.getOffset(), 6);
237                }
238                break;
239            }
240        }
241    }
242
243    @Test
244    public void testArrayPayloadAlignment() {
245        ArrayList<ImmutableInstruction> instructions = createSimpleInstructionList();
246        // add misaligned array payload
247        instructions.add(new ImmutableInstruction10x(Opcode.NOP));
248        instructions.add(new ImmutableArrayPayload(4, null));
249
250        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
251        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
252
253        int codeOffset = 0;
254        for (Instruction instr: writeUtil.getInstructions()) {
255            if (codeOffset == 21) {
256                Assert.assertEquals("array payload was not aligned properly", instr.getOpcode(), Opcode.NOP);
257                break;
258            }
259            codeOffset += instr.getCodeUnits();
260        }
261    }
262
263    @Test
264    public void testPackedSwitchAlignment() {
265        ArrayList<ImmutableInstruction> instructions = createSimpleInstructionList();
266        // packed switch instruction is already misaligned
267
268        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
269        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
270
271        int codeOffset = 0;
272        for (Instruction instr: writeUtil.getInstructions()) {
273            if (codeOffset == 7) {
274                Assert.assertEquals("packed switch payload was not aligned properly", instr.getOpcode(), Opcode.NOP);
275                break;
276            }
277            codeOffset += instr.getCodeUnits();
278        }
279    }
280
281    @Test
282    public void testSparseSwitchAlignment() {
283        ArrayList<ImmutableInstruction> instructions = createSimpleInstructionList();
284        // insert a nop to mis-align sparse switch payload
285        instructions.add(4, new ImmutableInstruction10x(Opcode.NOP));
286
287        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
288        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
289
290        int codeOffset = 0;
291        for (Instruction instr: writeUtil.getInstructions()) {
292            if (codeOffset == 15) {
293                Assert.assertEquals("packed switch payload was not aligned properly", instr.getOpcode(), Opcode.NOP);
294                break;
295            }
296            codeOffset += instr.getCodeUnits();
297        }
298    }
299
300    @Test
301    public void testGotoToGoto16() {
302        ArrayList<ImmutableInstruction> instructions = Lists.newArrayList();
303        instructions.add(new ImmutableInstruction10t(Opcode.GOTO, 127));
304        instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(0))));
305        for (int i=0;i<127;i++) {
306            instructions.add(new ImmutableInstruction10x(Opcode.NOP));
307        }
308
309        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
310        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
311
312        Instruction instr = writeUtil.getInstructions().iterator().next();
313        Assert.assertEquals("goto was not converted to goto/16 properly", instr.getOpcode(), Opcode.GOTO_16);
314    }
315
316    @Test
317    public void testGoto16ToGoto32() {
318        ArrayList<ImmutableInstruction> instructions = Lists.newArrayList();
319        instructions.add(new ImmutableInstruction20t(Opcode.GOTO_16, Short.MAX_VALUE));
320        instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(0))));
321        for (int i=0;i<Short.MAX_VALUE;i++) {
322            instructions.add(new ImmutableInstruction10x(Opcode.NOP));
323        }
324
325        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
326        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
327
328        Instruction instr = writeUtil.getInstructions().iterator().next();
329        Assert.assertEquals("goto/16 was not converted to goto/32 properly", instr.getOpcode(), Opcode.GOTO_32);
330    }
331
332    @Test
333    public void testGotoIterative() {
334        ArrayList<ImmutableInstruction> instructions = Lists.newArrayList();
335
336        instructions.add(new ImmutableInstruction10t(Opcode.GOTO, 126));
337        instructions.add(new ImmutableInstruction10t(Opcode.GOTO, 127));
338        instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(0))));
339        for (int i=0;i<122;i++) {
340            instructions.add(new ImmutableInstruction10x(Opcode.NOP));
341        }
342        instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(1))));
343        instructions.add(new ImmutableInstruction10x(Opcode.NOP));
344
345        // this misaligned array payload will cause nop insertion on the first pass and its removal on the second pass
346        instructions.add(new ImmutableInstruction10x(Opcode.NOP));
347        instructions.add(new ImmutableArrayPayload(4, null));
348
349        ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
350        InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
351
352        Instruction instr = writeUtil.getInstructions().iterator().next();
353        Assert.assertEquals("goto was not converted to goto/16 properly", instr.getOpcode(), Opcode.GOTO_16);
354
355        int codeOffset = 0;
356        for (Instruction instruction: writeUtil.getInstructions()) {
357            if (instruction instanceof ArrayPayload) {
358                Assert.assertEquals("packed switch payload was not aligned properly", codeOffset%2, 0);
359            }
360            codeOffset += instruction.getCodeUnits();
361        }
362    }
363}*/
364