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 17package com.android.dx.cf.code; 18 19import com.android.dx.rop.code.FillArrayDataInsn; 20import com.android.dx.rop.code.Insn; 21import com.android.dx.rop.code.PlainCstInsn; 22import com.android.dx.rop.code.PlainInsn; 23import com.android.dx.rop.code.RegOps; 24import com.android.dx.rop.code.RegisterSpec; 25import com.android.dx.rop.code.RegisterSpecList; 26import com.android.dx.rop.code.Rop; 27import com.android.dx.rop.code.Rops; 28import com.android.dx.rop.code.SourcePosition; 29import com.android.dx.rop.code.SwitchInsn; 30import com.android.dx.rop.code.ThrowingCstInsn; 31import com.android.dx.rop.code.ThrowingInsn; 32import com.android.dx.rop.code.TranslationAdvice; 33import com.android.dx.rop.cst.Constant; 34import com.android.dx.rop.cst.CstFieldRef; 35import com.android.dx.rop.cst.CstMethodRef; 36import com.android.dx.rop.cst.CstNat; 37import com.android.dx.rop.cst.CstType; 38import com.android.dx.rop.cst.CstUtf8; 39import com.android.dx.rop.type.Type; 40import com.android.dx.rop.type.TypeBearer; 41import com.android.dx.rop.type.TypeList; 42import com.android.dx.util.IntList; 43 44import java.util.ArrayList; 45 46/** 47 * Machine implementation for use by {@link Ropper}. 48 */ 49/*package*/ final class RopperMachine extends ValueAwareMachine { 50 /** {@code non-null;} array reflection class */ 51 private static final CstType ARRAY_REFLECT_TYPE = 52 new CstType(Type.internClassName("java/lang/reflect/Array")); 53 54 /** 55 * {@code non-null;} method constant for use in converting 56 * {@code multianewarray} instructions 57 */ 58 private static final CstMethodRef MULTIANEWARRAY_METHOD = 59 new CstMethodRef(ARRAY_REFLECT_TYPE, 60 new CstNat(new CstUtf8("newInstance"), 61 new CstUtf8("(Ljava/lang/Class;[I)" + 62 "Ljava/lang/Object;"))); 63 64 /** {@code non-null;} {@link Ropper} controlling this instance */ 65 private final Ropper ropper; 66 67 /** {@code non-null;} method being converted */ 68 private final ConcreteMethod method; 69 70 /** {@code non-null;} translation advice */ 71 private final TranslationAdvice advice; 72 73 /** max locals of the method */ 74 private final int maxLocals; 75 76 /** {@code non-null;} instructions for the rop basic block in-progress */ 77 private final ArrayList<Insn> insns; 78 79 /** {@code non-null;} catches for the block currently being processed */ 80 private TypeList catches; 81 82 /** whether the catches have been used in an instruction */ 83 private boolean catchesUsed; 84 85 /** whether the block contains a {@code return} */ 86 private boolean returns; 87 88 /** primary successor index */ 89 private int primarySuccessorIndex; 90 91 /** {@code >= 0;} number of extra basic blocks required */ 92 private int extraBlockCount; 93 94 /** true if last processed block ends with a jsr or jsr_W*/ 95 private boolean hasJsr; 96 97 /** true if an exception can be thrown by the last block processed */ 98 private boolean blockCanThrow; 99 100 /** 101 * If non-null, the ReturnAddress that was used by the terminating ret 102 * instruction. If null, there was no ret instruction encountered. 103 */ 104 105 private ReturnAddress returnAddress; 106 107 /** 108 * {@code null-ok;} the appropriate {@code return} op or {@code null} 109 * if it is not yet known 110 */ 111 private Rop returnOp; 112 113 /** 114 * {@code null-ok;} the source position for the return block or {@code null} 115 * if it is not yet known 116 */ 117 private SourcePosition returnPosition; 118 119 /** 120 * Constructs an instance. 121 * 122 * @param ropper {@code non-null;} ropper controlling this instance 123 * @param method {@code non-null;} method being converted 124 * @param advice {@code non-null;} translation advice to use 125 */ 126 public RopperMachine(Ropper ropper, ConcreteMethod method, 127 TranslationAdvice advice) { 128 super(method.getEffectiveDescriptor()); 129 130 if (ropper == null) { 131 throw new NullPointerException("ropper == null"); 132 } 133 134 if (advice == null) { 135 throw new NullPointerException("advice == null"); 136 } 137 138 this.ropper = ropper; 139 this.method = method; 140 this.advice = advice; 141 this.maxLocals = method.getMaxLocals(); 142 this.insns = new ArrayList<Insn>(25); 143 this.catches = null; 144 this.catchesUsed = false; 145 this.returns = false; 146 this.primarySuccessorIndex = -1; 147 this.extraBlockCount = 0; 148 this.blockCanThrow = false; 149 this.returnOp = null; 150 this.returnPosition = null; 151 } 152 153 /** 154 * Gets the instructions array. It is shared and gets modified by 155 * subsequent calls to this instance. 156 * 157 * @return {@code non-null;} the instructions array 158 */ 159 public ArrayList<Insn> getInsns() { 160 return insns; 161 } 162 163 /** 164 * Gets the return opcode encountered, if any. 165 * 166 * @return {@code null-ok;} the return opcode 167 */ 168 public Rop getReturnOp() { 169 return returnOp; 170 } 171 172 /** 173 * Gets the return position, if known. 174 * 175 * @return {@code null-ok;} the return position 176 */ 177 public SourcePosition getReturnPosition() { 178 return returnPosition; 179 } 180 181 /** 182 * Gets ready to start working on a new block. This will clear the 183 * {@link #insns} list, set {@link #catches}, reset whether it has 184 * been used, reset whether the block contains a 185 * {@code return}, and reset {@link #primarySuccessorIndex}. 186 */ 187 public void startBlock(TypeList catches) { 188 this.catches = catches; 189 190 insns.clear(); 191 catchesUsed = false; 192 returns = false; 193 primarySuccessorIndex = 0; 194 extraBlockCount = 0; 195 blockCanThrow = false; 196 hasJsr = false; 197 returnAddress = null; 198 } 199 200 /** 201 * Gets whether {@link #catches} was used. This indicates that the 202 * last instruction in the block is one of the ones that can throw. 203 * 204 * @return whether {@code catches} has been used 205 */ 206 public boolean wereCatchesUsed() { 207 return catchesUsed; 208 } 209 210 /** 211 * Gets whether the block just processed ended with a 212 * {@code return}. 213 * 214 * @return whether the block returns 215 */ 216 public boolean returns() { 217 return returns; 218 } 219 220 /** 221 * Gets the primary successor index. This is the index into the 222 * successors list where the primary may be found or 223 * {@code -1} if there are successors but no primary 224 * successor. This may return something other than 225 * {@code -1} in the case of an instruction with no 226 * successors at all (primary or otherwise). 227 * 228 * @return {@code >= -1;} the primary successor index 229 */ 230 public int getPrimarySuccessorIndex() { 231 return primarySuccessorIndex; 232 } 233 234 /** 235 * Gets how many extra blocks will be needed to represent the 236 * block currently being translated. Each extra block should consist 237 * of one instruction from the end of the original block. 238 * 239 * @return {@code >= 0;} the number of extra blocks needed 240 */ 241 public int getExtraBlockCount() { 242 return extraBlockCount; 243 } 244 245 /** 246 * @return true if at least one of the insn processed since the last 247 * call to startBlock() can throw. 248 */ 249 public boolean canThrow() { 250 return blockCanThrow; 251 } 252 253 /** 254 * @return true if a JSR has ben encountered since the last call to 255 * startBlock() 256 */ 257 public boolean hasJsr() { 258 return hasJsr; 259 } 260 261 /** 262 * @return {@code true} if a {@code ret} has ben encountered since 263 * the last call to {@code startBlock()} 264 */ 265 public boolean hasRet() { 266 return returnAddress != null; 267 } 268 269 /** 270 * @return {@code null-ok;} return address of a {@code ret} 271 * instruction if encountered since last call to startBlock(). 272 * {@code null} if no ret instruction encountered. 273 */ 274 public ReturnAddress getReturnAddress() { 275 return returnAddress; 276 } 277 278 /** {@inheritDoc} */ 279 @Override 280 public void run(Frame frame, int offset, int opcode) { 281 /* 282 * This is the stack pointer after the opcode's arguments have been 283 * popped. 284 */ 285 int stackPointer = maxLocals + frame.getStack().size(); 286 287 // The sources have to be retrieved before super.run() gets called. 288 RegisterSpecList sources = getSources(opcode, stackPointer); 289 int sourceCount = sources.size(); 290 291 super.run(frame, offset, opcode); 292 293 SourcePosition pos = method.makeSourcePosistion(offset); 294 RegisterSpec localTarget = getLocalTarget(); 295 int destCount = resultCount(); 296 RegisterSpec dest; 297 298 if (destCount == 0) { 299 dest = null; 300 switch (opcode) { 301 case ByteOps.POP: 302 case ByteOps.POP2: { 303 // These simply don't appear in the rop form. 304 return; 305 } 306 } 307 } else if (localTarget != null) { 308 dest = localTarget; 309 } else if (destCount == 1) { 310 dest = RegisterSpec.make(stackPointer, result(0)); 311 } else { 312 /* 313 * This clause only ever applies to the stack manipulation 314 * ops that have results (that is, dup* and swap but not 315 * pop*). 316 * 317 * What we do is first move all the source registers into 318 * the "temporary stack" area defined for the method, and 319 * then move stuff back down onto the main "stack" in the 320 * arrangement specified by the stack op pattern. 321 * 322 * Note: This code ends up emitting a lot of what will 323 * turn out to be superfluous moves (e.g., moving back and 324 * forth to the same local when doing a dup); however, 325 * that makes this code a bit easier (and goodness knows 326 * it doesn't need any extra complexity), and all the SSA 327 * stuff is going to want to deal with this sort of 328 * superfluous assignment anyway, so it should be a wash 329 * in the end. 330 */ 331 int scratchAt = ropper.getFirstTempStackReg(); 332 RegisterSpec[] scratchRegs = new RegisterSpec[sourceCount]; 333 334 for (int i = 0; i < sourceCount; i++) { 335 RegisterSpec src = sources.get(i); 336 TypeBearer type = src.getTypeBearer(); 337 RegisterSpec scratch = src.withReg(scratchAt); 338 insns.add(new PlainInsn(Rops.opMove(type), pos, scratch, src)); 339 scratchRegs[i] = scratch; 340 scratchAt += src.getCategory(); 341 } 342 343 for (int pattern = getAuxInt(); pattern != 0; pattern >>= 4) { 344 int which = (pattern & 0x0f) - 1; 345 RegisterSpec scratch = scratchRegs[which]; 346 TypeBearer type = scratch.getTypeBearer(); 347 insns.add(new PlainInsn(Rops.opMove(type), pos, 348 scratch.withReg(stackPointer), 349 scratch)); 350 stackPointer += type.getType().getCategory(); 351 } 352 return; 353 } 354 355 TypeBearer destType = (dest != null) ? dest : Type.VOID; 356 Constant cst = getAuxCst(); 357 int ropOpcode; 358 Rop rop; 359 Insn insn; 360 361 if (opcode == ByteOps.MULTIANEWARRAY) { 362 blockCanThrow = true; 363 364 // Add the extra instructions for handling multianewarray. 365 366 extraBlockCount = 6; 367 368 /* 369 * Add an array constructor for the int[] containing all the 370 * dimensions. 371 */ 372 RegisterSpec dimsReg = 373 RegisterSpec.make(dest.getNextReg(), Type.INT_ARRAY); 374 rop = Rops.opFilledNewArray(Type.INT_ARRAY, sourceCount); 375 insn = new ThrowingCstInsn(rop, pos, sources, catches, 376 CstType.INT_ARRAY); 377 insns.add(insn); 378 379 // Add a move-result for the new-filled-array 380 rop = Rops.opMoveResult(Type.INT_ARRAY); 381 insn = new PlainInsn(rop, pos, dimsReg, RegisterSpecList.EMPTY); 382 insns.add(insn); 383 384 /* 385 * Add a const-class instruction for the specified array 386 * class. 387 */ 388 389 /* 390 * Remove as many dimensions from the originally specified 391 * class as are given in the explicit list of dimensions, 392 * so as to pass the right component class to the standard 393 * Java library array constructor. 394 */ 395 Type componentType = ((CstType) cst).getClassType(); 396 for (int i = 0; i < sourceCount; i++) { 397 componentType = componentType.getComponentType(); 398 } 399 400 RegisterSpec classReg = 401 RegisterSpec.make(dest.getReg(), Type.CLASS); 402 403 if (componentType.isPrimitive()) { 404 /* 405 * The component type is primitive (e.g., int as opposed 406 * to Integer), so we have to fetch the corresponding 407 * TYPE class. 408 */ 409 CstFieldRef typeField = 410 CstFieldRef.forPrimitiveType(componentType); 411 insn = new ThrowingCstInsn(Rops.GET_STATIC_OBJECT, pos, 412 RegisterSpecList.EMPTY, 413 catches, typeField); 414 } else { 415 /* 416 * The component type is an object type, so just make a 417 * normal class reference. 418 */ 419 insn = new ThrowingCstInsn(Rops.CONST_OBJECT, pos, 420 RegisterSpecList.EMPTY, catches, 421 new CstType(componentType)); 422 } 423 424 insns.add(insn); 425 426 // Add a move-result-pseudo for the get-static or const 427 rop = Rops.opMoveResultPseudo(classReg.getType()); 428 insn = new PlainInsn(rop, pos, classReg, RegisterSpecList.EMPTY); 429 insns.add(insn); 430 431 /* 432 * Add a call to the "multianewarray method," that is, 433 * Array.newInstance(class, dims). Note: The result type 434 * of newInstance() is Object, which is why the last 435 * instruction in this sequence is a cast to the right 436 * type for the original instruction. 437 */ 438 439 RegisterSpec objectReg = 440 RegisterSpec.make(dest.getReg(), Type.OBJECT); 441 442 insn = new ThrowingCstInsn( 443 Rops.opInvokeStatic(MULTIANEWARRAY_METHOD.getPrototype()), 444 pos, RegisterSpecList.make(classReg, dimsReg), 445 catches, MULTIANEWARRAY_METHOD); 446 insns.add(insn); 447 448 // Add a move-result. 449 rop = Rops.opMoveResult(MULTIANEWARRAY_METHOD.getPrototype() 450 .getReturnType()); 451 insn = new PlainInsn(rop, pos, objectReg, RegisterSpecList.EMPTY); 452 insns.add(insn); 453 454 /* 455 * And finally, set up for the remainder of this method to 456 * add an appropriate cast. 457 */ 458 459 opcode = ByteOps.CHECKCAST; 460 sources = RegisterSpecList.make(objectReg); 461 } else if (opcode == ByteOps.JSR) { 462 // JSR has no Rop instruction 463 hasJsr = true; 464 return; 465 } else if (opcode == ByteOps.RET) { 466 try { 467 returnAddress = (ReturnAddress)arg(0); 468 } catch (ClassCastException ex) { 469 throw new RuntimeException( 470 "Argument to RET was not a ReturnAddress", ex); 471 } 472 // RET has no Rop instruction. 473 return; 474 } 475 476 ropOpcode = jopToRopOpcode(opcode, cst); 477 rop = Rops.ropFor(ropOpcode, destType, sources, cst); 478 479 Insn moveResult = null; 480 if (dest != null && rop.isCallLike()) { 481 /* 482 * We're going to want to have a move-result in the next 483 * basic block. 484 */ 485 extraBlockCount++; 486 487 moveResult = new PlainInsn( 488 Rops.opMoveResult(((CstMethodRef) cst).getPrototype() 489 .getReturnType()), pos, dest, RegisterSpecList.EMPTY); 490 491 dest = null; 492 } else if (dest != null && rop.canThrow()) { 493 /* 494 * We're going to want to have a move-result-pseudo in the 495 * next basic block. 496 */ 497 extraBlockCount++; 498 499 moveResult = new PlainInsn( 500 Rops.opMoveResultPseudo(dest.getTypeBearer()), 501 pos, dest, RegisterSpecList.EMPTY); 502 503 dest = null; 504 } 505 if (ropOpcode == RegOps.NEW_ARRAY) { 506 /* 507 * In the original bytecode, this was either a primitive 508 * array constructor "newarray" or an object array 509 * constructor "anewarray". In the former case, there is 510 * no explicit constant, and in the latter, the constant 511 * is for the element type and not the array type. The rop 512 * instruction form for both of these is supposed to be 513 * the resulting array type, so we initialize / alter 514 * "cst" here, accordingly. Conveniently enough, the rop 515 * opcode already gets constructed with the proper array 516 * type. 517 */ 518 cst = CstType.intern(rop.getResult()); 519 } else if ((cst == null) && (sourceCount == 2)) { 520 TypeBearer lastType = sources.get(1).getTypeBearer(); 521 522 if (lastType.isConstant() 523 && advice.hasConstantOperation(rop, 524 sources.get(0), sources.get(1))) { 525 /* 526 * The target architecture has an instruction that can 527 * build in the constant found in the second argument, 528 * so pull it out of the sources and just use it as a 529 * constant here. 530 */ 531 cst = (Constant) lastType; 532 sources = sources.withoutLast(); 533 rop = Rops.ropFor(ropOpcode, destType, sources, cst); 534 } 535 } 536 537 SwitchList cases = getAuxCases(); 538 ArrayList<Constant> initValues = getInitValues(); 539 boolean canThrow = rop.canThrow(); 540 541 blockCanThrow |= canThrow; 542 543 if (cases != null) { 544 if (cases.size() == 0) { 545 // It's a default-only switch statement. It can happen! 546 insn = new PlainInsn(Rops.GOTO, pos, null, 547 RegisterSpecList.EMPTY); 548 primarySuccessorIndex = 0; 549 } else { 550 IntList values = cases.getValues(); 551 insn = new SwitchInsn(rop, pos, dest, sources, values); 552 primarySuccessorIndex = values.size(); 553 } 554 } else if (ropOpcode == RegOps.RETURN) { 555 /* 556 * Returns get turned into the combination of a move (if 557 * non-void and if the return doesn't already mention 558 * register 0) and a goto (to the return block). 559 */ 560 if (sources.size() != 0) { 561 RegisterSpec source = sources.get(0); 562 TypeBearer type = source.getTypeBearer(); 563 if (source.getReg() != 0) { 564 insns.add(new PlainInsn(Rops.opMove(type), pos, 565 RegisterSpec.make(0, type), 566 source)); 567 } 568 } 569 insn = new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY); 570 primarySuccessorIndex = 0; 571 updateReturnOp(rop, pos); 572 returns = true; 573 } else if (cst != null) { 574 if (canThrow) { 575 insn = 576 new ThrowingCstInsn(rop, pos, sources, catches, cst); 577 catchesUsed = true; 578 primarySuccessorIndex = catches.size(); 579 } else { 580 insn = new PlainCstInsn(rop, pos, dest, sources, cst); 581 } 582 } else if (canThrow) { 583 insn = new ThrowingInsn(rop, pos, sources, catches); 584 catchesUsed = true; 585 if (opcode == ByteOps.ATHROW) { 586 /* 587 * The op athrow is the only one where it's possible 588 * to have non-empty successors and yet not have a 589 * primary successor. 590 */ 591 primarySuccessorIndex = -1; 592 } else { 593 primarySuccessorIndex = catches.size(); 594 } 595 } else { 596 insn = new PlainInsn(rop, pos, dest, sources); 597 } 598 599 insns.add(insn); 600 601 if (moveResult != null) { 602 insns.add(moveResult); 603 } 604 605 /* 606 * If initValues is non-null, it means that the parser has 607 * seen a group of compatible constant initialization 608 * bytecodes that are applied to the current newarray. The 609 * action we take here is to convert these initialization 610 * bytecodes into a single fill-array-data ROP which lays out 611 * all the constant values in a table. 612 */ 613 if (initValues != null) { 614 extraBlockCount++; 615 insn = new FillArrayDataInsn(Rops.FILL_ARRAY_DATA, pos, 616 RegisterSpecList.make(moveResult.getResult()), initValues, 617 cst); 618 insns.add(insn); 619 } 620 } 621 622 /** 623 * Helper for {@link #run}, which gets the list of sources for the. 624 * instruction. 625 * 626 * @param opcode the opcode being translated 627 * @param stackPointer {@code >= 0;} the stack pointer after the 628 * instruction's arguments have been popped 629 * @return {@code non-null;} the sources 630 */ 631 private RegisterSpecList getSources(int opcode, int stackPointer) { 632 int count = argCount(); 633 634 if (count == 0) { 635 // We get an easy out if there aren't any sources. 636 return RegisterSpecList.EMPTY; 637 } 638 639 int localIndex = getLocalIndex(); 640 RegisterSpecList sources; 641 642 if (localIndex >= 0) { 643 // The instruction is operating on a local variable. 644 sources = new RegisterSpecList(1); 645 sources.set(0, RegisterSpec.make(localIndex, arg(0))); 646 } else { 647 sources = new RegisterSpecList(count); 648 int regAt = stackPointer; 649 for (int i = 0; i < count; i++) { 650 RegisterSpec spec = RegisterSpec.make(regAt, arg(i)); 651 sources.set(i, spec); 652 regAt += spec.getCategory(); 653 } 654 655 switch (opcode) { 656 case ByteOps.IASTORE: { 657 /* 658 * The Java argument order for array stores is 659 * (array, index, value), but the rop argument 660 * order is (value, array, index). The following 661 * code gets the right arguments in the right 662 * places. 663 */ 664 if (count != 3) { 665 throw new RuntimeException("shouldn't happen"); 666 } 667 RegisterSpec array = sources.get(0); 668 RegisterSpec index = sources.get(1); 669 RegisterSpec value = sources.get(2); 670 sources.set(0, value); 671 sources.set(1, array); 672 sources.set(2, index); 673 break; 674 } 675 case ByteOps.PUTFIELD: { 676 /* 677 * Similar to above: The Java argument order for 678 * putfield is (object, value), but the rop 679 * argument order is (value, object). 680 */ 681 if (count != 2) { 682 throw new RuntimeException("shouldn't happen"); 683 } 684 RegisterSpec obj = sources.get(0); 685 RegisterSpec value = sources.get(1); 686 sources.set(0, value); 687 sources.set(1, obj); 688 break; 689 } 690 } 691 } 692 693 sources.setImmutable(); 694 return sources; 695 } 696 697 /** 698 * Sets or updates the information about the return block. 699 * 700 * @param op {@code non-null;} the opcode to use 701 * @param pos {@code non-null;} the position to use 702 */ 703 private void updateReturnOp(Rop op, SourcePosition pos) { 704 if (op == null) { 705 throw new NullPointerException("op == null"); 706 } 707 708 if (pos == null) { 709 throw new NullPointerException("pos == null"); 710 } 711 712 if (returnOp == null) { 713 returnOp = op; 714 returnPosition = pos; 715 } else { 716 if (returnOp != op) { 717 throw new SimException("return op mismatch: " + op + ", " + 718 returnOp); 719 } 720 721 if (pos.getLine() > returnPosition.getLine()) { 722 // Pick the largest line number to be the "canonical" return. 723 returnPosition = pos; 724 } 725 } 726 } 727 728 /** 729 * Gets the register opcode for the given Java opcode. 730 * 731 * @param jop {@code >= 0;} the Java opcode 732 * @param cst {@code null-ok;} the constant argument, if any 733 * @return {@code >= 0;} the corresponding register opcode 734 */ 735 private int jopToRopOpcode(int jop, Constant cst) { 736 switch (jop) { 737 case ByteOps.POP: 738 case ByteOps.POP2: 739 case ByteOps.DUP: 740 case ByteOps.DUP_X1: 741 case ByteOps.DUP_X2: 742 case ByteOps.DUP2: 743 case ByteOps.DUP2_X1: 744 case ByteOps.DUP2_X2: 745 case ByteOps.SWAP: 746 case ByteOps.JSR: 747 case ByteOps.RET: 748 case ByteOps.MULTIANEWARRAY: { 749 // These need to be taken care of specially. 750 break; 751 } 752 case ByteOps.NOP: { 753 return RegOps.NOP; 754 } 755 case ByteOps.LDC: 756 case ByteOps.LDC2_W: { 757 return RegOps.CONST; 758 } 759 case ByteOps.ILOAD: 760 case ByteOps.ISTORE: { 761 return RegOps.MOVE; 762 } 763 case ByteOps.IALOAD: { 764 return RegOps.AGET; 765 } 766 case ByteOps.IASTORE: { 767 return RegOps.APUT; 768 } 769 case ByteOps.IADD: 770 case ByteOps.IINC: { 771 return RegOps.ADD; 772 } 773 case ByteOps.ISUB: { 774 return RegOps.SUB; 775 } 776 case ByteOps.IMUL: { 777 return RegOps.MUL; 778 } 779 case ByteOps.IDIV: { 780 return RegOps.DIV; 781 } 782 case ByteOps.IREM: { 783 return RegOps.REM; 784 } 785 case ByteOps.INEG: { 786 return RegOps.NEG; 787 } 788 case ByteOps.ISHL: { 789 return RegOps.SHL; 790 } 791 case ByteOps.ISHR: { 792 return RegOps.SHR; 793 } 794 case ByteOps.IUSHR: { 795 return RegOps.USHR; 796 } 797 case ByteOps.IAND: { 798 return RegOps.AND; 799 } 800 case ByteOps.IOR: { 801 return RegOps.OR; 802 } 803 case ByteOps.IXOR: { 804 return RegOps.XOR; 805 } 806 case ByteOps.I2L: 807 case ByteOps.I2F: 808 case ByteOps.I2D: 809 case ByteOps.L2I: 810 case ByteOps.L2F: 811 case ByteOps.L2D: 812 case ByteOps.F2I: 813 case ByteOps.F2L: 814 case ByteOps.F2D: 815 case ByteOps.D2I: 816 case ByteOps.D2L: 817 case ByteOps.D2F: { 818 return RegOps.CONV; 819 } 820 case ByteOps.I2B: { 821 return RegOps.TO_BYTE; 822 } 823 case ByteOps.I2C: { 824 return RegOps.TO_CHAR; 825 } 826 case ByteOps.I2S: { 827 return RegOps.TO_SHORT; 828 } 829 case ByteOps.LCMP: 830 case ByteOps.FCMPL: 831 case ByteOps.DCMPL: { 832 return RegOps.CMPL; 833 } 834 case ByteOps.FCMPG: 835 case ByteOps.DCMPG: { 836 return RegOps.CMPG; 837 } 838 case ByteOps.IFEQ: 839 case ByteOps.IF_ICMPEQ: 840 case ByteOps.IF_ACMPEQ: 841 case ByteOps.IFNULL: { 842 return RegOps.IF_EQ; 843 } 844 case ByteOps.IFNE: 845 case ByteOps.IF_ICMPNE: 846 case ByteOps.IF_ACMPNE: 847 case ByteOps.IFNONNULL: { 848 return RegOps.IF_NE; 849 } 850 case ByteOps.IFLT: 851 case ByteOps.IF_ICMPLT: { 852 return RegOps.IF_LT; 853 } 854 case ByteOps.IFGE: 855 case ByteOps.IF_ICMPGE: { 856 return RegOps.IF_GE; 857 } 858 case ByteOps.IFGT: 859 case ByteOps.IF_ICMPGT: { 860 return RegOps.IF_GT; 861 } 862 case ByteOps.IFLE: 863 case ByteOps.IF_ICMPLE: { 864 return RegOps.IF_LE; 865 } 866 case ByteOps.GOTO: { 867 return RegOps.GOTO; 868 } 869 case ByteOps.LOOKUPSWITCH: { 870 return RegOps.SWITCH; 871 } 872 case ByteOps.IRETURN: 873 case ByteOps.RETURN: { 874 return RegOps.RETURN; 875 } 876 case ByteOps.GETSTATIC: { 877 return RegOps.GET_STATIC; 878 } 879 case ByteOps.PUTSTATIC: { 880 return RegOps.PUT_STATIC; 881 } 882 case ByteOps.GETFIELD: { 883 return RegOps.GET_FIELD; 884 } 885 case ByteOps.PUTFIELD: { 886 return RegOps.PUT_FIELD; 887 } 888 case ByteOps.INVOKEVIRTUAL: { 889 return RegOps.INVOKE_VIRTUAL; 890 } 891 case ByteOps.INVOKESPECIAL: { 892 /* 893 * Determine whether the opcode should be 894 * INVOKE_DIRECT or INVOKE_SUPER. See vmspec-2 section 6 895 * on "invokespecial" as well as section 4.8.2 (7th 896 * bullet point) for the gory details. 897 */ 898 CstMethodRef ref = (CstMethodRef) cst; 899 if (ref.isInstanceInit() || 900 (ref.getDefiningClass() == method.getDefiningClass()) || 901 !method.getAccSuper()) { 902 return RegOps.INVOKE_DIRECT; 903 } 904 return RegOps.INVOKE_SUPER; 905 } 906 case ByteOps.INVOKESTATIC: { 907 return RegOps.INVOKE_STATIC; 908 } 909 case ByteOps.INVOKEINTERFACE: { 910 return RegOps.INVOKE_INTERFACE; 911 } 912 case ByteOps.NEW: { 913 return RegOps.NEW_INSTANCE; 914 } 915 case ByteOps.NEWARRAY: 916 case ByteOps.ANEWARRAY: { 917 return RegOps.NEW_ARRAY; 918 } 919 case ByteOps.ARRAYLENGTH: { 920 return RegOps.ARRAY_LENGTH; 921 } 922 case ByteOps.ATHROW: { 923 return RegOps.THROW; 924 } 925 case ByteOps.CHECKCAST: { 926 return RegOps.CHECK_CAST; 927 } 928 case ByteOps.INSTANCEOF: { 929 return RegOps.INSTANCE_OF; 930 } 931 case ByteOps.MONITORENTER: { 932 return RegOps.MONITOR_ENTER; 933 } 934 case ByteOps.MONITOREXIT: { 935 return RegOps.MONITOR_EXIT; 936 } 937 } 938 939 throw new RuntimeException("shouldn't happen"); 940 } 941} 942