1 // Copyright 2017 The Bazel Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package com.google.devtools.build.android.desugar; 15 16 import static com.google.common.base.Preconditions.checkArgument; 17 import static com.google.common.base.Preconditions.checkNotNull; 18 import static com.google.common.base.Preconditions.checkState; 19 20 import com.google.auto.value.AutoValue; 21 import com.google.common.collect.ImmutableList; 22 import java.util.ArrayList; 23 import java.util.Optional; 24 import javax.annotation.Nullable; 25 import org.objectweb.asm.Handle; 26 import org.objectweb.asm.Label; 27 import org.objectweb.asm.MethodVisitor; 28 import org.objectweb.asm.Opcodes; 29 import org.objectweb.asm.Type; 30 31 /** 32 * Perform type inference for byte code (local variables and operand stack) with the help of stack 33 * map frames. 34 * 35 * <p>Note: This class only guarantees the correctness of reference types, but not the primitive 36 * types, though they might be correct too. 37 */ 38 public final class BytecodeTypeInference extends MethodVisitor { 39 40 private boolean used = false; 41 private final ArrayList<InferredType> localVariableSlots; 42 private final ArrayList<InferredType> operandStack = new ArrayList<>(); 43 private FrameInfo previousFrame; 44 /** For debugging purpose. */ 45 private final String methodSignature; 46 47 public BytecodeTypeInference(int access, String owner, String name, String methodDescriptor) { 48 super(Opcodes.ASM6); 49 localVariableSlots = createInitialLocalVariableTypes(access, owner, name, methodDescriptor); 50 previousFrame = FrameInfo.create(ImmutableList.copyOf(localVariableSlots), ImmutableList.of()); 51 this.methodSignature = owner + "." + name + methodDescriptor; 52 } 53 54 public void setDelegateMethodVisitor(MethodVisitor visitor) { 55 mv = visitor; 56 } 57 58 @Override 59 public void visitCode() { 60 checkState(!used, "Cannot reuse this method visitor."); 61 used = true; 62 super.visitCode(); 63 } 64 65 /** Returns the type of a value in the operand. 0 means the top of the stack. */ 66 public InferredType getTypeOfOperandFromTop(int offsetFromTop) { 67 int index = operandStack.size() - 1 - offsetFromTop; 68 checkState( 69 index >= 0, 70 "Invalid offset %s in the list of size %s. The current method is %s", 71 offsetFromTop, 72 operandStack.size(), 73 methodSignature); 74 return operandStack.get(index); 75 } 76 77 public String getOperandStackAsString() { 78 return operandStack.toString(); 79 } 80 81 public String getLocalsAsString() { 82 return localVariableSlots.toString(); 83 } 84 85 @Override 86 public void visitInsn(int opcode) { 87 switch (opcode) { 88 case Opcodes.NOP: 89 case Opcodes.INEG: 90 case Opcodes.LNEG: 91 case Opcodes.FNEG: 92 case Opcodes.DNEG: 93 case Opcodes.I2B: 94 case Opcodes.I2C: 95 case Opcodes.I2S: 96 case Opcodes.RETURN: 97 break; 98 case Opcodes.ACONST_NULL: 99 push(InferredType.NULL); 100 break; 101 case Opcodes.ICONST_M1: 102 case Opcodes.ICONST_0: 103 case Opcodes.ICONST_1: 104 case Opcodes.ICONST_2: 105 case Opcodes.ICONST_3: 106 case Opcodes.ICONST_4: 107 case Opcodes.ICONST_5: 108 push(InferredType.INT); 109 break; 110 case Opcodes.LCONST_0: 111 case Opcodes.LCONST_1: 112 push(InferredType.LONG); 113 push(InferredType.TOP); 114 break; 115 case Opcodes.FCONST_0: 116 case Opcodes.FCONST_1: 117 case Opcodes.FCONST_2: 118 push(InferredType.FLOAT); 119 break; 120 case Opcodes.DCONST_0: 121 case Opcodes.DCONST_1: 122 push(InferredType.DOUBLE); 123 push(InferredType.TOP); 124 break; 125 case Opcodes.IALOAD: 126 case Opcodes.BALOAD: 127 case Opcodes.CALOAD: 128 case Opcodes.SALOAD: 129 pop(2); 130 push(InferredType.INT); 131 break; 132 case Opcodes.LALOAD: 133 case Opcodes.D2L: 134 pop(2); 135 push(InferredType.LONG); 136 push(InferredType.TOP); 137 break; 138 case Opcodes.DALOAD: 139 case Opcodes.L2D: 140 pop(2); 141 push(InferredType.DOUBLE); 142 push(InferredType.TOP); 143 break; 144 case Opcodes.AALOAD: 145 InferredType arrayType = pop(2); 146 InferredType elementType = arrayType.getElementTypeIfArrayOrThrow(); 147 push(elementType); 148 break; 149 case Opcodes.IASTORE: 150 case Opcodes.BASTORE: 151 case Opcodes.CASTORE: 152 case Opcodes.SASTORE: 153 case Opcodes.FASTORE: 154 case Opcodes.AASTORE: 155 pop(3); 156 break; 157 case Opcodes.LASTORE: 158 case Opcodes.DASTORE: 159 pop(4); 160 break; 161 case Opcodes.POP: 162 case Opcodes.IRETURN: 163 case Opcodes.FRETURN: 164 case Opcodes.ARETURN: 165 case Opcodes.ATHROW: 166 case Opcodes.MONITORENTER: 167 case Opcodes.MONITOREXIT: 168 pop(); 169 break; 170 case Opcodes.POP2: 171 case Opcodes.LRETURN: 172 case Opcodes.DRETURN: 173 pop(2); 174 break; 175 case Opcodes.DUP: 176 push(top()); 177 break; 178 case Opcodes.DUP_X1: 179 { 180 InferredType top = pop(); 181 InferredType next = pop(); 182 push(top); 183 push(next); 184 push(top); 185 break; 186 } 187 case Opcodes.DUP_X2: 188 { 189 InferredType top = pop(); 190 InferredType next = pop(); 191 InferredType bottom = pop(); 192 push(top); 193 push(bottom); 194 push(next); 195 push(top); 196 break; 197 } 198 case Opcodes.DUP2: 199 { 200 InferredType top = pop(); 201 InferredType next = pop(); 202 push(next); 203 push(top); 204 push(next); 205 push(top); 206 break; 207 } 208 case Opcodes.DUP2_X1: 209 { 210 InferredType top = pop(); 211 InferredType next = pop(); 212 InferredType bottom = pop(); 213 push(next); 214 push(top); 215 push(bottom); 216 push(next); 217 push(top); 218 break; 219 } 220 case Opcodes.DUP2_X2: 221 { 222 InferredType t1 = pop(); 223 InferredType t2 = pop(); 224 InferredType t3 = pop(); 225 InferredType t4 = pop(); 226 push(t2); 227 push(t1); 228 push(t4); 229 push(t3); 230 push(t2); 231 push(t1); 232 break; 233 } 234 case Opcodes.SWAP: 235 { 236 InferredType top = pop(); 237 InferredType next = pop(); 238 push(top); 239 push(next); 240 break; 241 } 242 case Opcodes.IADD: 243 case Opcodes.ISUB: 244 case Opcodes.IMUL: 245 case Opcodes.IDIV: 246 case Opcodes.IREM: 247 case Opcodes.ISHL: 248 case Opcodes.ISHR: 249 case Opcodes.IUSHR: 250 case Opcodes.IAND: 251 case Opcodes.IOR: 252 case Opcodes.IXOR: 253 case Opcodes.L2I: 254 case Opcodes.D2I: 255 case Opcodes.FCMPL: 256 case Opcodes.FCMPG: 257 pop(2); 258 push(InferredType.INT); 259 break; 260 261 case Opcodes.LADD: 262 case Opcodes.LSUB: 263 case Opcodes.LMUL: 264 case Opcodes.LDIV: 265 case Opcodes.LREM: 266 case Opcodes.LAND: 267 case Opcodes.LOR: 268 case Opcodes.LXOR: 269 pop(4); 270 push(InferredType.LONG); 271 push(InferredType.TOP); 272 break; 273 274 case Opcodes.LSHL: 275 case Opcodes.LSHR: 276 case Opcodes.LUSHR: 277 pop(3); 278 push(InferredType.LONG); 279 push(InferredType.TOP); 280 break; 281 case Opcodes.I2L: 282 case Opcodes.F2L: 283 pop(); 284 push(InferredType.LONG); 285 push(InferredType.TOP); 286 break; 287 case Opcodes.I2F: 288 pop(); 289 push(InferredType.FLOAT); 290 break; 291 292 case Opcodes.LCMP: 293 case Opcodes.DCMPG: 294 case Opcodes.DCMPL: 295 pop(4); 296 push(InferredType.INT); 297 break; 298 299 case Opcodes.I2D: 300 case Opcodes.F2D: 301 pop(); 302 push(InferredType.DOUBLE); 303 push(InferredType.TOP); 304 break; 305 case Opcodes.F2I: 306 case Opcodes.ARRAYLENGTH: 307 pop(); 308 push(InferredType.INT); 309 break; 310 case Opcodes.FALOAD: 311 case Opcodes.FADD: 312 case Opcodes.FSUB: 313 case Opcodes.FMUL: 314 case Opcodes.FDIV: 315 case Opcodes.FREM: 316 case Opcodes.L2F: 317 case Opcodes.D2F: 318 pop(2); 319 push(InferredType.FLOAT); 320 break; 321 322 case Opcodes.DADD: 323 case Opcodes.DSUB: 324 case Opcodes.DMUL: 325 case Opcodes.DDIV: 326 case Opcodes.DREM: 327 pop(4); 328 push(InferredType.DOUBLE); 329 push(InferredType.TOP); 330 break; 331 default: 332 throw new RuntimeException("Unhandled opcode " + opcode); 333 } 334 super.visitInsn(opcode); 335 } 336 337 @Override 338 public void visitIntInsn(int opcode, int operand) { 339 switch (opcode) { 340 case Opcodes.BIPUSH: 341 case Opcodes.SIPUSH: 342 push(InferredType.INT); 343 break; 344 case Opcodes.NEWARRAY: 345 pop(); 346 switch (operand) { 347 case Opcodes.T_BOOLEAN: 348 pushDescriptor("[Z"); 349 break; 350 case Opcodes.T_CHAR: 351 pushDescriptor("[C"); 352 break; 353 case Opcodes.T_FLOAT: 354 pushDescriptor("[F"); 355 break; 356 case Opcodes.T_DOUBLE: 357 pushDescriptor("[D"); 358 break; 359 case Opcodes.T_BYTE: 360 pushDescriptor("[B"); 361 break; 362 case Opcodes.T_SHORT: 363 pushDescriptor("[S"); 364 break; 365 case Opcodes.T_INT: 366 pushDescriptor("[I"); 367 break; 368 case Opcodes.T_LONG: 369 pushDescriptor("[J"); 370 break; 371 default: 372 throw new RuntimeException("Unhandled operand value: " + operand); 373 } 374 break; 375 default: 376 throw new RuntimeException("Unhandled opcode " + opcode); 377 } 378 super.visitIntInsn(opcode, operand); 379 } 380 381 @Override 382 public void visitVarInsn(int opcode, int var) { 383 switch (opcode) { 384 case Opcodes.ILOAD: 385 push(InferredType.INT); 386 break; 387 case Opcodes.LLOAD: 388 push(InferredType.LONG); 389 push(InferredType.TOP); 390 break; 391 case Opcodes.FLOAD: 392 push(InferredType.FLOAT); 393 break; 394 case Opcodes.DLOAD: 395 push(InferredType.DOUBLE); 396 push(InferredType.TOP); 397 break; 398 case Opcodes.ALOAD: 399 push(getLocalVariableType(var)); 400 break; 401 case Opcodes.ISTORE: 402 case Opcodes.FSTORE: 403 case Opcodes.ASTORE: 404 { 405 InferredType type = pop(); 406 setLocalVariableTypes(var, type); 407 break; 408 } 409 case Opcodes.LSTORE: 410 case Opcodes.DSTORE: 411 { 412 InferredType type = pop(2); 413 setLocalVariableTypes(var, type); 414 setLocalVariableTypes(var + 1, InferredType.TOP); 415 break; 416 } 417 case Opcodes.RET: 418 throw new RuntimeException("The instruction RET is not supported"); 419 default: 420 throw new RuntimeException("Unhandled opcode " + opcode); 421 } 422 super.visitVarInsn(opcode, var); 423 } 424 425 @Override 426 public void visitTypeInsn(int opcode, String type) { 427 String descriptor = convertToDescriptor(type); 428 switch (opcode) { 429 case Opcodes.NEW: 430 pushDescriptor(descriptor); // This should be UNINITIALIZED(label). Okay for type inference. 431 break; 432 case Opcodes.ANEWARRAY: 433 pop(); 434 pushDescriptor('[' + descriptor); 435 break; 436 case Opcodes.CHECKCAST: 437 pop(); 438 pushDescriptor(descriptor); 439 break; 440 case Opcodes.INSTANCEOF: 441 pop(); 442 push(InferredType.INT); 443 break; 444 default: 445 throw new RuntimeException("Unhandled opcode " + opcode); 446 } 447 super.visitTypeInsn(opcode, type); 448 } 449 450 @Override 451 public void visitFieldInsn(int opcode, String owner, String name, String desc) { 452 switch (opcode) { 453 case Opcodes.GETSTATIC: 454 pushDescriptor(desc); 455 break; 456 case Opcodes.PUTSTATIC: 457 popDescriptor(desc); 458 break; 459 case Opcodes.GETFIELD: 460 pop(); 461 pushDescriptor(desc); 462 break; 463 case Opcodes.PUTFIELD: 464 popDescriptor(desc); 465 pop(); 466 break; 467 default: 468 throw new RuntimeException( 469 "Unhandled opcode " + opcode + ", owner=" + owner + ", name=" + name + ", desc" + desc); 470 } 471 super.visitFieldInsn(opcode, owner, name, desc); 472 } 473 474 @Override 475 public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { 476 if (opcode == Opcodes.INVOKESPECIAL && "<init>".equals(name)) { 477 int argumentSize = (Type.getArgumentsAndReturnSizes(desc) >> 2); 478 InferredType receiverType = getTypeOfOperandFromTop(argumentSize - 1); 479 if (receiverType.isUninitialized()) { 480 InferredType realType = InferredType.createNonUninitializedType('L' + owner + ';'); 481 replaceUninitializedTypeInStack(receiverType, realType); 482 } 483 } 484 switch (opcode) { 485 case Opcodes.INVOKESPECIAL: 486 case Opcodes.INVOKEVIRTUAL: 487 case Opcodes.INVOKESTATIC: 488 case Opcodes.INVOKEINTERFACE: 489 popDescriptor(desc); 490 if (opcode != Opcodes.INVOKESTATIC) { 491 pop(); // Pop receiver. 492 } 493 pushDescriptor(desc); 494 break; 495 default: 496 throw new RuntimeException( 497 String.format( 498 "Unhandled opcode %s, owner=%s, name=%s, desc=%s, itf=%s", 499 opcode, owner, name, desc, itf)); 500 } 501 super.visitMethodInsn(opcode, owner, name, desc, itf); 502 } 503 504 @Override 505 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { 506 popDescriptor(desc); 507 pushDescriptor(desc); 508 super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); 509 } 510 511 @Override 512 public void visitJumpInsn(int opcode, Label label) { 513 switch (opcode) { 514 case Opcodes.IFEQ: 515 case Opcodes.IFNE: 516 case Opcodes.IFLT: 517 case Opcodes.IFGE: 518 case Opcodes.IFGT: 519 case Opcodes.IFLE: 520 pop(); 521 break; 522 case Opcodes.IF_ICMPEQ: 523 case Opcodes.IF_ICMPNE: 524 case Opcodes.IF_ICMPLT: 525 case Opcodes.IF_ICMPGE: 526 case Opcodes.IF_ICMPGT: 527 case Opcodes.IF_ICMPLE: 528 case Opcodes.IF_ACMPEQ: 529 case Opcodes.IF_ACMPNE: 530 pop(2); 531 break; 532 case Opcodes.GOTO: 533 break; 534 case Opcodes.JSR: 535 throw new RuntimeException("The JSR instruction is not supported."); 536 case Opcodes.IFNULL: 537 case Opcodes.IFNONNULL: 538 pop(1); 539 break; 540 default: 541 throw new RuntimeException("Unhandled opcode " + opcode); 542 } 543 super.visitJumpInsn(opcode, label); 544 } 545 546 @Override 547 public void visitLdcInsn(Object cst) { 548 if (cst instanceof Integer) { 549 push(InferredType.INT); 550 } else if (cst instanceof Float) { 551 push(InferredType.FLOAT); 552 } else if (cst instanceof Long) { 553 push(InferredType.LONG); 554 push(InferredType.TOP); 555 } else if (cst instanceof Double) { 556 push(InferredType.DOUBLE); 557 push(InferredType.TOP); 558 } else if (cst instanceof String) { 559 pushDescriptor("Ljava/lang/String;"); 560 } else if (cst instanceof Type) { 561 pushDescriptor(((Type) cst).getDescriptor()); 562 } else if (cst instanceof Handle) { 563 pushDescriptor("Ljava/lang/invoke/MethodHandle;"); 564 } else { 565 throw new RuntimeException("Cannot handle constant " + cst + " for LDC instruction"); 566 } 567 super.visitLdcInsn(cst); 568 } 569 570 @Override 571 public void visitIincInsn(int var, int increment) { 572 setLocalVariableTypes(var, InferredType.INT); 573 super.visitIincInsn(var, increment); 574 } 575 576 @Override 577 public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { 578 pop(); 579 super.visitTableSwitchInsn(min, max, dflt, labels); 580 } 581 582 @Override 583 public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { 584 pop(); 585 super.visitLookupSwitchInsn(dflt, keys, labels); 586 } 587 588 @Override 589 public void visitMultiANewArrayInsn(String desc, int dims) { 590 pop(dims); 591 pushDescriptor(desc); 592 super.visitMultiANewArrayInsn(desc, dims); 593 } 594 595 @Override 596 public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { 597 switch (type) { 598 case Opcodes.F_NEW: 599 // Expanded form. 600 previousFrame = 601 FrameInfo.create( 602 convertTypesInStackMapFrame(nLocal, local), 603 convertTypesInStackMapFrame(nStack, stack)); 604 break; 605 case Opcodes.F_SAME: 606 // This frame type indicates that the frame has exactly the same local variables as the 607 // previous frame and that the operand stack is empty. 608 previousFrame = FrameInfo.create(previousFrame.locals(), ImmutableList.of()); 609 break; 610 case Opcodes.F_SAME1: 611 // This frame type indicates that the frame has exactly the same local variables as the 612 // previous frame and that the operand stack has one entry. 613 previousFrame = 614 FrameInfo.create(previousFrame.locals(), convertTypesInStackMapFrame(nStack, stack)); 615 break; 616 case Opcodes.F_APPEND: 617 // This frame type indicates that the frame has the same locals as the previous frame except 618 // that k additional locals are defined, and that the operand stack is empty. 619 previousFrame = 620 FrameInfo.create( 621 appendArrayToList(previousFrame.locals(), nLocal, local), ImmutableList.of()); 622 break; 623 case Opcodes.F_CHOP: 624 // This frame type indicates that the frame has the same local variables as the previous 625 // frame except that the last k local variables are absent, and that the operand stack is 626 // empty. 627 previousFrame = 628 FrameInfo.create( 629 removeBackFromList(previousFrame.locals(), nLocal), ImmutableList.of()); 630 break; 631 case Opcodes.F_FULL: 632 previousFrame = 633 FrameInfo.create( 634 convertTypesInStackMapFrame(nLocal, local), 635 convertTypesInStackMapFrame(nStack, stack)); 636 break; 637 default: 638 // continue below 639 } 640 // Update types for operand stack and local variables. 641 operandStack.clear(); 642 operandStack.addAll(previousFrame.stack()); 643 localVariableSlots.clear(); 644 localVariableSlots.addAll(previousFrame.locals()); 645 super.visitFrame(type, nLocal, local, nStack, stack); 646 } 647 648 private static String convertToDescriptor(String type) { 649 char firstChar = type.charAt(0); 650 switch (firstChar) { 651 case 'Z': 652 case 'B': 653 case 'C': 654 case 'S': 655 case 'I': 656 case 'J': 657 case 'D': 658 case 'F': 659 case '[': 660 return type; 661 default: 662 return 'L' + type + ';'; 663 } 664 } 665 666 private void push(InferredType type) { 667 operandStack.add(type); 668 } 669 670 private void replaceUninitializedTypeInStack(InferredType oldType, InferredType newType) { 671 checkArgument(oldType.isUninitialized(), "The old type is NOT uninitialized. %s", oldType); 672 for (int i = 0, size = operandStack.size(); i < size; ++i) { 673 InferredType type = operandStack.get(i); 674 if (type.equals(oldType)) { 675 operandStack.set(i, newType); 676 } 677 } 678 } 679 680 private final void pushDescriptor(String desc) { 681 int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; 682 switch (desc.charAt(index)) { 683 case 'V': 684 return; 685 case 'Z': 686 case 'C': 687 case 'B': 688 case 'S': 689 case 'I': 690 push(InferredType.INT); 691 break; 692 case 'F': 693 push(InferredType.FLOAT); 694 break; 695 case 'D': 696 push(InferredType.DOUBLE); 697 push(InferredType.TOP); 698 break; 699 case 'J': 700 push(InferredType.LONG); 701 push(InferredType.TOP); 702 break; 703 case 'L': 704 case '[': 705 push(InferredType.createNonUninitializedType(desc.substring(index))); 706 break; 707 default: 708 throw new RuntimeException("Unhandled type: " + desc); 709 } 710 } 711 712 private final InferredType pop() { 713 return pop(1); 714 } 715 716 private final void popDescriptor(String desc) { 717 char c = desc.charAt(0); 718 switch (c) { 719 case '(': 720 int argumentSize = (Type.getArgumentsAndReturnSizes(desc) >> 2) - 1; 721 if (argumentSize > 0) { 722 pop(argumentSize); 723 } 724 break; 725 case 'J': 726 case 'D': 727 pop(2); 728 break; 729 default: 730 pop(1); 731 break; 732 } 733 } 734 735 private final InferredType getLocalVariableType(int index) { 736 checkState( 737 index < localVariableSlots.size(), 738 "Cannot find type for var %s in method %s", 739 index, 740 methodSignature); 741 return localVariableSlots.get(index); 742 } 743 744 private final void setLocalVariableTypes(int index, InferredType type) { 745 while (localVariableSlots.size() <= index) { 746 localVariableSlots.add(InferredType.TOP); 747 } 748 localVariableSlots.set(index, type); 749 } 750 751 private final InferredType top() { 752 return operandStack.get(operandStack.size() - 1); 753 } 754 755 /** Pop elements from the end of the operand stack, and return the last popped element. */ 756 private final InferredType pop(int count) { 757 checkArgument( 758 count >= 1, "The count should be at least one: %s (In %s)", count, methodSignature); 759 checkState( 760 operandStack.size() >= count, 761 "There are no enough elements in the stack. count=%s, stack=%s (In %s)", 762 count, 763 operandStack, 764 methodSignature); 765 int expectedLastIndex = operandStack.size() - count - 1; 766 InferredType lastPopped = null; 767 for (int i = operandStack.size() - 1; i > expectedLastIndex; --i) { 768 lastPopped = operandStack.remove(i); 769 } 770 return lastPopped; 771 } 772 773 /** 774 * Create the types of local variables at the very beginning of the method with the information of 775 * the declaring class and the method descriptor. 776 */ 777 private static ArrayList<InferredType> createInitialLocalVariableTypes( 778 int access, String ownerClass, String methodName, String methodDescriptor) { 779 ArrayList<InferredType> types = new ArrayList<>(); 780 781 if (!BitFlags.isSet(access, Opcodes.ACC_STATIC)) { 782 // Instance method, and this is the receiver 783 types.add(InferredType.createNonUninitializedType(convertToDescriptor(ownerClass))); 784 } 785 Type[] argumentTypes = Type.getArgumentTypes(methodDescriptor); 786 for (Type argumentType : argumentTypes) { 787 switch (argumentType.getSort()) { 788 case Type.BOOLEAN: 789 case Type.BYTE: 790 case Type.CHAR: 791 case Type.SHORT: 792 case Type.INT: 793 types.add(InferredType.INT); 794 break; 795 case Type.FLOAT: 796 types.add(InferredType.FLOAT); 797 break; 798 case Type.LONG: 799 types.add(InferredType.LONG); 800 types.add(InferredType.TOP); 801 break; 802 case Type.DOUBLE: 803 types.add(InferredType.DOUBLE); 804 types.add(InferredType.TOP); 805 break; 806 case Type.ARRAY: 807 case Type.OBJECT: 808 types.add(InferredType.createNonUninitializedType(argumentType.getDescriptor())); 809 break; 810 default: 811 throw new RuntimeException( 812 "Unhandled argument type: " 813 + argumentType 814 + " in " 815 + ownerClass 816 + "." 817 + methodName 818 + methodDescriptor); 819 } 820 } 821 return types; 822 } 823 824 private static ImmutableList<InferredType> removeBackFromList( 825 ImmutableList<InferredType> list, int countToRemove) { 826 int origSize = list.size(); 827 int index = origSize - 1; 828 829 while (index >= 0 && countToRemove > 0) { 830 InferredType type = list.get(index); 831 if (type.equals(InferredType.TOP) && index > 0 && list.get(index - 1).isCategory2()) { 832 --index; // A category 2 takes two slots. 833 } 834 --index; // Eat this local variable. 835 --countToRemove; 836 } 837 checkState( 838 countToRemove == 0, 839 "countToRemove is %s but not 0. index=%s, list=%s", 840 countToRemove, 841 index, 842 list); 843 return list.subList(0, index + 1); 844 } 845 846 private ImmutableList<InferredType> appendArrayToList( 847 ImmutableList<InferredType> list, int size, Object[] array) { 848 ImmutableList.Builder<InferredType> builder = ImmutableList.builder(); 849 builder.addAll(list); 850 for (int i = 0; i < size; ++i) { 851 InferredType type = convertTypeInStackMapFrame(array[i]); 852 builder.add(type); 853 if (type.isCategory2()) { 854 builder.add(InferredType.TOP); 855 } 856 } 857 return builder.build(); 858 } 859 860 /** Convert the type in stack map frame to inference type. */ 861 private InferredType convertTypeInStackMapFrame(Object typeInStackMapFrame) { 862 if (typeInStackMapFrame == Opcodes.TOP) { 863 return InferredType.TOP; 864 } else if (typeInStackMapFrame == Opcodes.INTEGER) { 865 return InferredType.INT; 866 } else if (typeInStackMapFrame == Opcodes.FLOAT) { 867 return InferredType.FLOAT; 868 } else if (typeInStackMapFrame == Opcodes.DOUBLE) { 869 return InferredType.DOUBLE; 870 } else if (typeInStackMapFrame == Opcodes.LONG) { 871 return InferredType.LONG; 872 } else if (typeInStackMapFrame == Opcodes.NULL) { 873 return InferredType.NULL; 874 } else if (typeInStackMapFrame == Opcodes.UNINITIALIZED_THIS) { 875 return InferredType.UNINITIALIZED_THIS; 876 } else if (typeInStackMapFrame instanceof String) { 877 String referenceTypeName = (String) typeInStackMapFrame; 878 if (referenceTypeName.charAt(0) == '[') { 879 return InferredType.createNonUninitializedType(referenceTypeName); 880 } else { 881 return InferredType.createNonUninitializedType('L' + referenceTypeName + ';'); 882 } 883 } else if (typeInStackMapFrame instanceof Label) { 884 Label label = (Label) typeInStackMapFrame; 885 return InferredType.createUninitializedType(label); 886 } else { 887 throw new RuntimeException( 888 "Cannot reach here. Unhandled element: value=" 889 + typeInStackMapFrame 890 + ", class=" 891 + typeInStackMapFrame.getClass() 892 + ". The current method being desugared is " 893 + methodSignature); 894 } 895 } 896 897 private ImmutableList<InferredType> convertTypesInStackMapFrame(int size, Object[] array) { 898 ImmutableList.Builder<InferredType> builder = ImmutableList.builder(); 899 for (int i = 0; i < size; ++i) { 900 InferredType type = convertTypeInStackMapFrame(array[i]); 901 builder.add(type); 902 if (type.isCategory2()) { 903 builder.add(InferredType.TOP); 904 } 905 } 906 return builder.build(); 907 } 908 909 /** A value class to represent a frame. */ 910 @AutoValue 911 abstract static class FrameInfo { 912 913 static FrameInfo create(ImmutableList<InferredType> locals, ImmutableList<InferredType> stack) { 914 return new AutoValue_BytecodeTypeInference_FrameInfo(locals, stack); 915 } 916 917 abstract ImmutableList<InferredType> locals(); 918 919 abstract ImmutableList<InferredType> stack(); 920 } 921 922 /** This is the type used for type inference. */ 923 @AutoValue 924 public abstract static class InferredType { 925 926 public static final String UNINITIALIZED_PREFIX = "UNINIT@"; 927 928 public static final InferredType BOOLEAN = 929 new AutoValue_BytecodeTypeInference_InferredType("Z", /*uninitializationLabel=*/ null); 930 public static final InferredType BYTE = 931 new AutoValue_BytecodeTypeInference_InferredType("B", /*uninitializationLabel=*/ null); 932 public static final InferredType INT = 933 new AutoValue_BytecodeTypeInference_InferredType("I", /*uninitializationLabel=*/ null); 934 public static final InferredType FLOAT = 935 new AutoValue_BytecodeTypeInference_InferredType("F", /*uninitializationLabel=*/ null); 936 public static final InferredType LONG = 937 new AutoValue_BytecodeTypeInference_InferredType("J", /*uninitializationLabel=*/ null); 938 public static final InferredType DOUBLE = 939 new AutoValue_BytecodeTypeInference_InferredType("D", /*uninitializationLabel=*/ null); 940 /** Not a real value. */ 941 public static final InferredType TOP = 942 new AutoValue_BytecodeTypeInference_InferredType("TOP", /*uninitializationLabel=*/ null); 943 /** The value NULL */ 944 public static final InferredType NULL = 945 new AutoValue_BytecodeTypeInference_InferredType("NULL", /*uninitializationLabel=*/ null); 946 947 public static final InferredType UNINITIALIZED_THIS = 948 new AutoValue_BytecodeTypeInference_InferredType( 949 "UNINITIALIZED_THIS", /*uninitializationLabel=*/ null); 950 951 /** 952 * Create a type for a value. This method is not intended to be called outside of this class. 953 */ 954 private static InferredType create(String descriptor, @Nullable Label uninitializationLabel) { 955 if (UNINITIALIZED_PREFIX.equals(descriptor)) { 956 return new AutoValue_BytecodeTypeInference_InferredType( 957 UNINITIALIZED_PREFIX, checkNotNull(uninitializationLabel)); 958 } 959 checkArgument( 960 uninitializationLabel == null, 961 "The uninitializationLabel should be null for non-uninitialized value. %s", 962 descriptor); 963 char firstChar = descriptor.charAt(0); 964 if (firstChar == 'L' || firstChar == '[') { 965 // Reference, array. 966 return new AutoValue_BytecodeTypeInference_InferredType( 967 descriptor, /*uninitializationLabel=*/ null); 968 } 969 switch (descriptor) { 970 case "Z": 971 return BOOLEAN; 972 case "B": 973 return BYTE; 974 case "I": 975 return INT; 976 case "F": 977 return FLOAT; 978 case "J": 979 return LONG; 980 case "D": 981 return DOUBLE; 982 case "TOP": 983 return TOP; 984 case "NULL": 985 return NULL; 986 case "UNINITIALIZED_THIS": 987 return UNINITIALIZED_THIS; 988 default: 989 throw new RuntimeException("Invalid descriptor: " + descriptor); 990 } 991 } 992 993 /** Creates all types except UNINITIALIZED. This method can also create UNINTIALIZED_THIS. */ 994 static InferredType createNonUninitializedType(String descriptor) { 995 return create(descriptor, /*uninitializationLabel=*/ null); 996 } 997 998 /** Create a type for an UNINITIALIZED value. The uninitializationLabel is generated by ASM. */ 999 static InferredType createUninitializedType(Label uninitializationLabel) { 1000 return create(UNINITIALIZED_PREFIX, uninitializationLabel); 1001 } 1002 1003 abstract String descriptor(); 1004 /** 1005 * The label may be null. This field is meaningful if the current type is "UNINITIALIZED". For 1006 * other types, this field is null. 1007 */ 1008 @Nullable 1009 abstract Label uninitializationLabel(); 1010 1011 @Override 1012 public String toString() { 1013 return descriptor(); 1014 } 1015 1016 /** Is a category 2 value? */ 1017 public boolean isCategory2() { 1018 String descriptor = descriptor(); 1019 return descriptor.equals("J") || descriptor.equals("D"); 1020 } 1021 1022 /** If the type is an array, return the element type. Otherwise, throw an exception. */ 1023 public InferredType getElementTypeIfArrayOrThrow() { 1024 String descriptor = descriptor(); 1025 checkState(descriptor.charAt(0) == '[', "This type %s is not an array.", this); 1026 return createNonUninitializedType(descriptor.substring(1)); 1027 } 1028 1029 /** Is an uninitialized value? */ 1030 public boolean isUninitialized() { 1031 return descriptor().startsWith(UNINITIALIZED_PREFIX); 1032 } 1033 1034 /** Is a null value? */ 1035 public boolean isNull() { 1036 return NULL.equals(this); 1037 } 1038 1039 /** 1040 * If this type is a reference type, then return the internal name. Otherwise, returns empty. 1041 */ 1042 public Optional<String> getInternalName() { 1043 String descriptor = descriptor(); 1044 int length = descriptor.length(); 1045 if (length > 0 && descriptor.charAt(0) == 'L' && descriptor.charAt(length - 1) == ';') { 1046 return Optional.of(descriptor.substring(1, length - 1)); 1047 } else { 1048 return Optional.empty(); 1049 } 1050 } 1051 } 1052 } 1053