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