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