1 /* 2 * Copyright (C) 2007 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.dex.code; 18 19 import com.android.dx.rop.code.RegisterSpec; 20 import com.android.dx.rop.code.RegisterSpecList; 21 import com.android.dx.rop.cst.Constant; 22 import com.android.dx.rop.cst.CstInteger; 23 import com.android.dx.rop.cst.CstKnownNull; 24 import com.android.dx.rop.cst.CstLiteral64; 25 import com.android.dx.rop.cst.CstLiteralBits; 26 import com.android.dx.rop.cst.CstString; 27 import com.android.dx.util.AnnotatedOutput; 28 import com.android.dx.util.Hex; 29 30 import java.util.BitSet; 31 32 /** 33 * Base class for all instruction format handlers. Instruction format 34 * handlers know how to translate {@link DalvInsn} instances into 35 * streams of code units, as well as human-oriented listing strings 36 * representing such translations. 37 */ 38 public abstract class InsnFormat { 39 /** 40 * flag to enable/disable the new extended opcode formats; meant as a 41 * temporary measure until VM support for the salient opcodes is 42 * added. TODO: Remove this declaration when the VM can deal. 43 */ 44 public static boolean ALLOW_EXTENDED_OPCODES = true; 45 46 /** 47 * Returns the string form, suitable for inclusion in a listing 48 * dump, of the given instruction. The instruction must be of this 49 * instance's format for proper operation. 50 * 51 * @param insn {@code non-null;} the instruction 52 * @param noteIndices whether to include an explicit notation of 53 * constant pool indices 54 * @return {@code non-null;} the string form 55 */ listingString(DalvInsn insn, boolean noteIndices)56 public final String listingString(DalvInsn insn, boolean noteIndices) { 57 String op = insn.getOpcode().getName(); 58 String arg = insnArgString(insn); 59 String comment = insnCommentString(insn, noteIndices); 60 StringBuilder sb = new StringBuilder(100); 61 62 sb.append(op); 63 64 if (arg.length() != 0) { 65 sb.append(' '); 66 sb.append(arg); 67 } 68 69 if (comment.length() != 0) { 70 sb.append(" // "); 71 sb.append(comment); 72 } 73 74 return sb.toString(); 75 } 76 77 /** 78 * Returns the string form of the arguments to the given instruction. 79 * The instruction must be of this instance's format. If the instruction 80 * has no arguments, then the result should be {@code ""}, not 81 * {@code null}. 82 * 83 * <p>Subclasses must override this method.</p> 84 * 85 * @param insn {@code non-null;} the instruction 86 * @return {@code non-null;} the string form 87 */ insnArgString(DalvInsn insn)88 public abstract String insnArgString(DalvInsn insn); 89 90 /** 91 * Returns the associated comment for the given instruction, if any. 92 * The instruction must be of this instance's format. If the instruction 93 * has no comment, then the result should be {@code ""}, not 94 * {@code null}. 95 * 96 * <p>Subclasses must override this method.</p> 97 * 98 * @param insn {@code non-null;} the instruction 99 * @param noteIndices whether to include an explicit notation of 100 * constant pool indices 101 * @return {@code non-null;} the string form 102 */ insnCommentString(DalvInsn insn, boolean noteIndices)103 public abstract String insnCommentString(DalvInsn insn, 104 boolean noteIndices); 105 106 /** 107 * Gets the code size of instructions that use this format. The 108 * size is a number of 16-bit code units, not bytes. This should 109 * throw an exception if this format is of variable size. 110 * 111 * @return {@code >= 0;} the instruction length in 16-bit code units 112 */ codeSize()113 public abstract int codeSize(); 114 115 /** 116 * Returns whether or not the given instruction's arguments will 117 * fit in this instance's format. This includes such things as 118 * counting register arguments, checking register ranges, and 119 * making sure that additional arguments are of appropriate types 120 * and are in-range. If this format has a branch target but the 121 * instruction's branch offset is unknown, this method will simply 122 * not check the offset. 123 * 124 * <p>Subclasses must override this method.</p> 125 * 126 * @param insn {@code non-null;} the instruction to check 127 * @return {@code true} iff the instruction's arguments are 128 * appropriate for this instance, or {@code false} if not 129 */ isCompatible(DalvInsn insn)130 public abstract boolean isCompatible(DalvInsn insn); 131 132 /** 133 * Returns which of a given instruction's registers will fit in 134 * this instance's format. 135 * 136 * <p>The default implementation of this method always returns 137 * an empty BitSet. Subclasses must override this method if they 138 * have registers.</p> 139 * 140 * @param insn {@code non-null;} the instruction to check 141 * @return {@code non-null;} a BitSet flagging registers in the 142 * register list that are compatible to this format 143 */ compatibleRegs(DalvInsn insn)144 public BitSet compatibleRegs(DalvInsn insn) { 145 return new BitSet(); 146 } 147 148 /** 149 * Returns whether or not the given instruction's branch offset will 150 * fit in this instance's format. This always returns {@code false} 151 * for formats that don't include a branch offset. 152 * 153 * <p>The default implementation of this method always returns 154 * {@code false}. Subclasses must override this method if they 155 * include branch offsets.</p> 156 * 157 * @param insn {@code non-null;} the instruction to check 158 * @return {@code true} iff the instruction's branch offset is 159 * appropriate for this instance, or {@code false} if not 160 */ branchFits(TargetInsn insn)161 public boolean branchFits(TargetInsn insn) { 162 return false; 163 } 164 165 /** 166 * Writes the code units for the given instruction to the given 167 * output destination. The instruction must be of this instance's format. 168 * 169 * <p>Subclasses must override this method.</p> 170 * 171 * @param out {@code non-null;} the output destination to write to 172 * @param insn {@code non-null;} the instruction to write 173 */ writeTo(AnnotatedOutput out, DalvInsn insn)174 public abstract void writeTo(AnnotatedOutput out, DalvInsn insn); 175 176 /** 177 * Helper method to return a register list string. 178 * 179 * @param list {@code non-null;} the list of registers 180 * @return {@code non-null;} the string form 181 */ regListString(RegisterSpecList list)182 protected static String regListString(RegisterSpecList list) { 183 int sz = list.size(); 184 StringBuffer sb = new StringBuffer(sz * 5 + 2); 185 186 sb.append('{'); 187 188 for (int i = 0; i < sz; i++) { 189 if (i != 0) { 190 sb.append(", "); 191 } 192 sb.append(list.get(i).regString()); 193 } 194 195 sb.append('}'); 196 197 return sb.toString(); 198 } 199 200 /** 201 * Helper method to return a register range string. 202 * 203 * @param list {@code non-null;} the list of registers (which must be 204 * sequential) 205 * @return {@code non-null;} the string form 206 */ regRangeString(RegisterSpecList list)207 protected static String regRangeString(RegisterSpecList list) { 208 int size = list.size(); 209 StringBuilder sb = new StringBuilder(30); 210 211 sb.append("{"); 212 213 switch (size) { 214 case 0: { 215 // Nothing to do. 216 break; 217 } 218 case 1: { 219 sb.append(list.get(0).regString()); 220 break; 221 } 222 default: { 223 RegisterSpec lastReg = list.get(size - 1); 224 if (lastReg.getCategory() == 2) { 225 /* 226 * Add one to properly represent a list-final 227 * category-2 register. 228 */ 229 lastReg = lastReg.withOffset(1); 230 } 231 232 sb.append(list.get(0).regString()); 233 sb.append(".."); 234 sb.append(lastReg.regString()); 235 } 236 } 237 238 sb.append("}"); 239 240 return sb.toString(); 241 } 242 243 /** 244 * Helper method to return a literal bits argument string. 245 * 246 * @param value the value 247 * @return {@code non-null;} the string form 248 */ literalBitsString(CstLiteralBits value)249 protected static String literalBitsString(CstLiteralBits value) { 250 StringBuffer sb = new StringBuffer(100); 251 252 sb.append('#'); 253 254 if (value instanceof CstKnownNull) { 255 sb.append("null"); 256 } else { 257 sb.append(value.typeName()); 258 sb.append(' '); 259 sb.append(value.toHuman()); 260 } 261 262 return sb.toString(); 263 } 264 265 /** 266 * Helper method to return a literal bits comment string. 267 * 268 * @param value the value 269 * @param width the width of the constant, in bits (used for displaying 270 * the uninterpreted bits; one of: {@code 4 8 16 32 64} 271 * @return {@code non-null;} the comment 272 */ literalBitsComment(CstLiteralBits value, int width)273 protected static String literalBitsComment(CstLiteralBits value, 274 int width) { 275 StringBuffer sb = new StringBuffer(20); 276 277 sb.append("#"); 278 279 long bits; 280 281 if (value instanceof CstLiteral64) { 282 bits = ((CstLiteral64) value).getLongBits(); 283 } else { 284 bits = value.getIntBits(); 285 } 286 287 switch (width) { 288 case 4: sb.append(Hex.uNibble((int) bits)); break; 289 case 8: sb.append(Hex.u1((int) bits)); break; 290 case 16: sb.append(Hex.u2((int) bits)); break; 291 case 32: sb.append(Hex.u4((int) bits)); break; 292 case 64: sb.append(Hex.u8(bits)); break; 293 default: { 294 throw new RuntimeException("shouldn't happen"); 295 } 296 } 297 298 return sb.toString(); 299 } 300 301 /** 302 * Helper method to return a branch address string. 303 * 304 * @param insn {@code non-null;} the instruction in question 305 * @return {@code non-null;} the string form of the instruction's 306 * branch target 307 */ branchString(DalvInsn insn)308 protected static String branchString(DalvInsn insn) { 309 TargetInsn ti = (TargetInsn) insn; 310 int address = ti.getTargetAddress(); 311 312 return (address == (char) address) ? Hex.u2(address) : Hex.u4(address); 313 } 314 315 /** 316 * Helper method to return the comment for a branch. 317 * 318 * @param insn {@code non-null;} the instruction in question 319 * @return {@code non-null;} the comment 320 */ branchComment(DalvInsn insn)321 protected static String branchComment(DalvInsn insn) { 322 TargetInsn ti = (TargetInsn) insn; 323 int offset = ti.getTargetOffset(); 324 325 return (offset == (short) offset) ? Hex.s2(offset) : Hex.s4(offset); 326 } 327 328 /** 329 * Helper method to return the constant string for a {@link CstInsn} 330 * in human form. 331 * 332 * @param insn {@code non-null;} a constant-bearing instruction 333 * @return {@code non-null;} the human string form of the contained 334 * constant 335 */ cstString(DalvInsn insn)336 protected static String cstString(DalvInsn insn) { 337 CstInsn ci = (CstInsn) insn; 338 Constant cst = ci.getConstant(); 339 340 return cst instanceof CstString ? ((CstString) cst).toQuoted() : cst.toHuman(); 341 } 342 343 /** 344 * Helper method to return an instruction comment for a constant. 345 * 346 * @param insn {@code non-null;} a constant-bearing instruction 347 * @return {@code non-null;} comment string representing the constant 348 */ cstComment(DalvInsn insn)349 protected static String cstComment(DalvInsn insn) { 350 CstInsn ci = (CstInsn) insn; 351 352 if (! ci.hasIndex()) { 353 return ""; 354 } 355 356 StringBuilder sb = new StringBuilder(20); 357 int index = ci.getIndex(); 358 359 sb.append(ci.getConstant().typeName()); 360 sb.append('@'); 361 362 if (index < 65536) { 363 sb.append(Hex.u2(index)); 364 } else { 365 sb.append(Hex.u4(index)); 366 } 367 368 return sb.toString(); 369 } 370 371 /** 372 * Helper method to determine if a signed int value fits in a nibble. 373 * 374 * @param value the value in question 375 * @return {@code true} iff it's in the range -8..+7 376 */ signedFitsInNibble(int value)377 protected static boolean signedFitsInNibble(int value) { 378 return (value >= -8) && (value <= 7); 379 } 380 381 /** 382 * Helper method to determine if an unsigned int value fits in a nibble. 383 * 384 * @param value the value in question 385 * @return {@code true} iff it's in the range 0..0xf 386 */ unsignedFitsInNibble(int value)387 protected static boolean unsignedFitsInNibble(int value) { 388 return value == (value & 0xf); 389 } 390 391 /** 392 * Helper method to determine if a signed int value fits in a byte. 393 * 394 * @param value the value in question 395 * @return {@code true} iff it's in the range -0x80..+0x7f 396 */ signedFitsInByte(int value)397 protected static boolean signedFitsInByte(int value) { 398 return (byte) value == value; 399 } 400 401 /** 402 * Helper method to determine if an unsigned int value fits in a byte. 403 * 404 * @param value the value in question 405 * @return {@code true} iff it's in the range 0..0xff 406 */ unsignedFitsInByte(int value)407 protected static boolean unsignedFitsInByte(int value) { 408 return value == (value & 0xff); 409 } 410 411 /** 412 * Helper method to determine if a signed int value fits in a short. 413 * 414 * @param value the value in question 415 * @return {@code true} iff it's in the range -0x8000..+0x7fff 416 */ signedFitsInShort(int value)417 protected static boolean signedFitsInShort(int value) { 418 return (short) value == value; 419 } 420 421 /** 422 * Helper method to determine if an unsigned int value fits in a short. 423 * 424 * @param value the value in question 425 * @return {@code true} iff it's in the range 0..0xffff 426 */ unsignedFitsInShort(int value)427 protected static boolean unsignedFitsInShort(int value) { 428 return value == (value & 0xffff); 429 } 430 431 /** 432 * Helper method to determine if a list of registers are sequential, 433 * including degenerate cases for empty or single-element lists. 434 * 435 * @param list {@code non-null;} the list of registers 436 * @return {@code true} iff the list is sequentially ordered 437 */ isRegListSequential(RegisterSpecList list)438 protected static boolean isRegListSequential(RegisterSpecList list) { 439 int sz = list.size(); 440 441 if (sz < 2) { 442 return true; 443 } 444 445 int first = list.get(0).getReg(); 446 int next = first; 447 448 for (int i = 0; i < sz; i++) { 449 RegisterSpec one = list.get(i); 450 if (one.getReg() != next) { 451 return false; 452 } 453 next += one.getCategory(); 454 } 455 456 return true; 457 } 458 459 /** 460 * Helper method to extract the callout-argument index from an 461 * appropriate instruction. 462 * 463 * @param insn {@code non-null;} the instruction 464 * @return {@code >= 0;} the callout argument index 465 */ argIndex(DalvInsn insn)466 protected static int argIndex(DalvInsn insn) { 467 int arg = ((CstInteger) ((CstInsn) insn).getConstant()).getValue(); 468 469 if (arg < 0) { 470 throw new IllegalArgumentException("bogus insn"); 471 } 472 473 return arg; 474 } 475 476 /** 477 * Helper method to combine an opcode and a second byte of data into 478 * the appropriate form for emitting into a code buffer. 479 * 480 * @param insn {@code non-null;} the instruction containing the opcode 481 * @param arg {@code 0..255;} arbitrary other byte value 482 * @return combined value 483 */ opcodeUnit(DalvInsn insn, int arg)484 protected static short opcodeUnit(DalvInsn insn, int arg) { 485 if ((arg & 0xff) != arg) { 486 throw new IllegalArgumentException("arg out of range 0..255"); 487 } 488 489 int opcode = insn.getOpcode().getOpcode(); 490 491 if ((opcode & 0xff) != opcode) { 492 throw new IllegalArgumentException("opcode out of range 0..255"); 493 } 494 495 return (short) (opcode | (arg << 8)); 496 } 497 498 /** 499 * Helper method to get an extended (16-bit) opcode out of an 500 * instruction, returning it as a code unit. The opcode 501 * <i>must</i> be an extended opcode. 502 * 503 * @param insn {@code non-null;} the instruction containing the 504 * extended opcode 505 * @return the opcode as a code unit 506 */ opcodeUnit(DalvInsn insn)507 protected static short opcodeUnit(DalvInsn insn) { 508 int opcode = insn.getOpcode().getOpcode(); 509 510 if ((opcode < 0xff) || (opcode > 0xffff)) { 511 throw new IllegalArgumentException( 512 "extended opcode out of range 255..65535"); 513 } 514 515 return (short) opcode; 516 } 517 518 /** 519 * Helper method to combine two bytes into a code unit. 520 * 521 * @param low {@code 0..255;} low byte 522 * @param high {@code 0..255;} high byte 523 * @return combined value 524 */ codeUnit(int low, int high)525 protected static short codeUnit(int low, int high) { 526 if ((low & 0xff) != low) { 527 throw new IllegalArgumentException("low out of range 0..255"); 528 } 529 530 if ((high & 0xff) != high) { 531 throw new IllegalArgumentException("high out of range 0..255"); 532 } 533 534 return (short) (low | (high << 8)); 535 } 536 537 /** 538 * Helper method to combine four nibbles into a code unit. 539 * 540 * @param n0 {@code 0..15;} low nibble 541 * @param n1 {@code 0..15;} medium-low nibble 542 * @param n2 {@code 0..15;} medium-high nibble 543 * @param n3 {@code 0..15;} high nibble 544 * @return combined value 545 */ codeUnit(int n0, int n1, int n2, int n3)546 protected static short codeUnit(int n0, int n1, int n2, int n3) { 547 if ((n0 & 0xf) != n0) { 548 throw new IllegalArgumentException("n0 out of range 0..15"); 549 } 550 551 if ((n1 & 0xf) != n1) { 552 throw new IllegalArgumentException("n1 out of range 0..15"); 553 } 554 555 if ((n2 & 0xf) != n2) { 556 throw new IllegalArgumentException("n2 out of range 0..15"); 557 } 558 559 if ((n3 & 0xf) != n3) { 560 throw new IllegalArgumentException("n3 out of range 0..15"); 561 } 562 563 return (short) (n0 | (n1 << 4) | (n2 << 8) | (n3 << 12)); 564 } 565 566 /** 567 * Helper method to combine two nibbles into a byte. 568 * 569 * @param low {@code 0..15;} low nibble 570 * @param high {@code 0..15;} high nibble 571 * @return {@code 0..255;} combined value 572 */ makeByte(int low, int high)573 protected static int makeByte(int low, int high) { 574 if ((low & 0xf) != low) { 575 throw new IllegalArgumentException("low out of range 0..15"); 576 } 577 578 if ((high & 0xf) != high) { 579 throw new IllegalArgumentException("high out of range 0..15"); 580 } 581 582 return low | (high << 4); 583 } 584 585 /** 586 * Writes one code unit to the given output destination. 587 * 588 * @param out {@code non-null;} where to write to 589 * @param c0 code unit to write 590 */ write(AnnotatedOutput out, short c0)591 protected static void write(AnnotatedOutput out, short c0) { 592 out.writeShort(c0); 593 } 594 595 /** 596 * Writes two code units to the given output destination. 597 * 598 * @param out {@code non-null;} where to write to 599 * @param c0 code unit to write 600 * @param c1 code unit to write 601 */ write(AnnotatedOutput out, short c0, short c1)602 protected static void write(AnnotatedOutput out, short c0, short c1) { 603 out.writeShort(c0); 604 out.writeShort(c1); 605 } 606 607 /** 608 * Writes three code units to the given output destination. 609 * 610 * @param out {@code non-null;} where to write to 611 * @param c0 code unit to write 612 * @param c1 code unit to write 613 * @param c2 code unit to write 614 */ write(AnnotatedOutput out, short c0, short c1, short c2)615 protected static void write(AnnotatedOutput out, short c0, short c1, 616 short c2) { 617 out.writeShort(c0); 618 out.writeShort(c1); 619 out.writeShort(c2); 620 } 621 622 /** 623 * Writes four code units to the given output destination. 624 * 625 * @param out {@code non-null;} where to write to 626 * @param c0 code unit to write 627 * @param c1 code unit to write 628 * @param c2 code unit to write 629 * @param c3 code unit to write 630 */ write(AnnotatedOutput out, short c0, short c1, short c2, short c3)631 protected static void write(AnnotatedOutput out, short c0, short c1, 632 short c2, short c3) { 633 out.writeShort(c0); 634 out.writeShort(c1); 635 out.writeShort(c2); 636 out.writeShort(c3); 637 } 638 639 /** 640 * Writes five code units to the given output destination. 641 * 642 * @param out {@code non-null;} where to write to 643 * @param c0 code unit to write 644 * @param c1 code unit to write 645 * @param c2 code unit to write 646 * @param c3 code unit to write 647 * @param c4 code unit to write 648 */ write(AnnotatedOutput out, short c0, short c1, short c2, short c3, short c4)649 protected static void write(AnnotatedOutput out, short c0, short c1, 650 short c2, short c3, short c4) { 651 out.writeShort(c0); 652 out.writeShort(c1); 653 out.writeShort(c2); 654 out.writeShort(c3); 655 out.writeShort(c4); 656 } 657 658 /** 659 * Writes three code units to the given output destination, where the 660 * second and third are represented as single <code>int</code> and emitted 661 * in little-endian order. 662 * 663 * @param out {@code non-null;} where to write to 664 * @param c0 code unit to write 665 * @param c1c2 code unit pair to write 666 */ write(AnnotatedOutput out, short c0, int c1c2)667 protected static void write(AnnotatedOutput out, short c0, int c1c2) { 668 write(out, c0, (short) c1c2, (short) (c1c2 >> 16)); 669 } 670 671 /** 672 * Writes four code units to the given output destination, where the 673 * second and third are represented as single <code>int</code> and emitted 674 * in little-endian order. 675 * 676 * @param out {@code non-null;} where to write to 677 * @param c0 code unit to write 678 * @param c1c2 code unit pair to write 679 * @param c3 code unit to write 680 */ write(AnnotatedOutput out, short c0, int c1c2, short c3)681 protected static void write(AnnotatedOutput out, short c0, int c1c2, 682 short c3) { 683 write(out, c0, (short) c1c2, (short) (c1c2 >> 16), c3); 684 } 685 686 /** 687 * Writes five code units to the given output destination, where the 688 * second and third are represented as single <code>int</code> and emitted 689 * in little-endian order. 690 * 691 * @param out {@code non-null;} where to write to 692 * @param c0 code unit to write 693 * @param c1c2 code unit pair to write 694 * @param c3 code unit to write 695 * @param c4 code unit to write 696 */ write(AnnotatedOutput out, short c0, int c1c2, short c3, short c4)697 protected static void write(AnnotatedOutput out, short c0, int c1c2, 698 short c3, short c4) { 699 write(out, c0, (short) c1c2, (short) (c1c2 >> 16), c3, c4); 700 } 701 702 /** 703 * Writes five code units to the given output destination, where the 704 * second through fifth are represented as single <code>long</code> 705 * and emitted in little-endian order. 706 * 707 * @param out {@code non-null;} where to write to 708 * @param c0 code unit to write 709 * @param c1c2c3c4 code unit quad to write 710 */ write(AnnotatedOutput out, short c0, long c1c2c3c4)711 protected static void write(AnnotatedOutput out, short c0, long c1c2c3c4) { 712 write(out, c0, (short) c1c2c3c4, (short) (c1c2c3c4 >> 16), 713 (short) (c1c2c3c4 >> 32), (short) (c1c2c3c4 >> 48)); 714 } 715 } 716