1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.experimental.bytecode; 27 28 import java.lang.invoke.MethodHandle; 29 import java.lang.invoke.MethodType; 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 import java.util.Iterator; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.Map.Entry; 36 import java.util.Vector; 37 import java.util.function.Consumer; 38 import java.util.function.Supplier; 39 40 public class TypedCodeBuilder<S, T, E, C extends TypedCodeBuilder<S, T, E, C>> extends MacroCodeBuilder<S, T, E, C> { 41 42 State lastStackMapState; 43 int lastStackMapPc = -1; 44 Map<CharSequence, LocalVarInfo> lvarOffsets = new HashMap<>(); 45 protected State state; 46 int depth = 0; 47 int currLocalOffset = 0; 48 49 class StatefulPendingJump extends PendingJump { 50 51 State state; 52 53 StatefulPendingJump(CharSequence label, int pc, State state) { 54 super(label, pc); 55 this.state = state; 56 } 57 58 @Override 59 boolean resolve(CharSequence label, int pc) { 60 boolean b = super.resolve(label, pc); 61 if (b) { 62 TypedCodeBuilder.this.state = TypedCodeBuilder.this.state.merge(state); 63 } 64 return b; 65 } 66 } 67 68 class LocalVarInfo { 69 CharSequence name; 70 int offset; 71 int depth; 72 TypeTag type; 73 74 LocalVarInfo(CharSequence name, int offset, int depth, TypeTag type) { 75 this.name = name; 76 this.offset = offset; 77 this.depth = depth; 78 this.type = type; 79 } 80 } 81 82 public TypedCodeBuilder(MethodBuilder<S, T, E> methodBuilder) { 83 super(methodBuilder); 84 T t = methodBuilder.desc; 85 state = new State(); 86 if ((methodBuilder.flags & Flag.ACC_STATIC.flag) == 0) { 87 T clazz = typeHelper.type(methodBuilder.thisClass); 88 state.load(clazz, currLocalOffset++); //TODO: uninit?? 89 } 90 Iterator<T> paramsIt = typeHelper.parameterTypes(t); 91 while (paramsIt.hasNext()) { 92 T p = paramsIt.next(); 93 state.load(p, currLocalOffset); 94 currLocalOffset += typeHelper.tag(p).width; 95 } 96 lastStackMapState = state.dup(); 97 stacksize = state.stack.size(); 98 localsize = state.locals.size(); 99 } 100 101 @Override 102 protected C emitOp(Opcode opcode, Object optPoolValue) { 103 updateState(opcode, optPoolValue); 104 return super.emitOp(opcode, optPoolValue); 105 } 106 107 @Override 108 protected SwitchBuilder makeSwitchBuilder() { 109 return new TypedSwitchBuilder(); 110 } 111 112 class TypedSwitchBuilder extends SwitchBuilder { 113 114 @Override 115 public SwitchBuilder withCase(int value, Consumer<? super C> case_, boolean fallthrough) { 116 super.withCase(value, c -> { 117 withLocalScope(() -> { 118 State prevState = state; 119 state = prevState.dup(); 120 emitStackMap(c.offset()); 121 case_.accept(c); 122 state = prevState; 123 }); 124 }, fallthrough); 125 return this; 126 } 127 128 @Override 129 public SwitchBuilder withDefault(Consumer<? super C> defaultCase) { 130 super.withDefault(c -> { 131 withLocalScope(() -> { 132 State prevState = state; 133 state = prevState.dup(); 134 emitStackMap(c.offset()); 135 defaultCase.accept(c); 136 state = prevState; 137 }); 138 }); 139 return this; 140 } 141 } 142 143 @Override 144 public StatefulTypedBuilder typed(TypeTag tag) { 145 return super.typed(tag, StatefulTypedBuilder::new); 146 } 147 148 public class StatefulTypedBuilder extends LabelledTypedBuilder { 149 150 TypeTag tag; 151 152 StatefulTypedBuilder(TypeTag tag) { 153 this.tag = tag; 154 } 155 156 @Override 157 public C astore_0() { 158 return storeAndUpdate(super::astore_0); 159 } 160 161 @Override 162 public C astore_1() { 163 return storeAndUpdate(super::astore_1); 164 } 165 166 @Override 167 public C astore_2() { 168 return storeAndUpdate(super::astore_2); 169 } 170 171 @Override 172 public C astore_3() { 173 return storeAndUpdate(super::astore_3); 174 } 175 176 @Override 177 public C astore(int n) { 178 return storeAndUpdate(() -> super.astore(n)); 179 } 180 181 @Override 182 public C aastore() { 183 return storeAndUpdate(super::aastore); 184 } 185 186 @Override 187 public C areturn() { 188 state.pop(tag); 189 state.push(typeHelper.nullType()); 190 return super.areturn(); 191 } 192 193 @Override 194 public C anewarray(S s) { 195 super.anewarray(s); 196 state.pop(); 197 state.push(typeHelper.arrayOf(typeHelper.type(s))); 198 return thisBuilder(); 199 } 200 201 @Override 202 public C aconst_null() { 203 super.aconst_null(); 204 state.pop(); 205 state.push(tag); 206 return thisBuilder(); 207 } 208 209 public C if_acmpeq(CharSequence label) { 210 return jumpAndUpdate(() -> super.if_acmpeq(label)); 211 } 212 213 public C if_acmpne(CharSequence label) { 214 return jumpAndUpdate(() -> super.if_acmpne(label)); 215 } 216 217 private C storeAndUpdate(Supplier<C> op) { 218 state.pop(tag); 219 state.push(typeHelper.nullType()); 220 return op.get(); 221 } 222 223 private C jumpAndUpdate(Supplier<C> op) { 224 state.pop(tag); 225 state.pop(tag); 226 state.push(typeHelper.nullType()); 227 state.push(typeHelper.nullType()); 228 return op.get(); 229 } 230 } 231 232 public class State { 233 public final ArrayList<T> stack; 234 public final Vector<T> locals; 235 236 State(ArrayList<T> stack, Vector<T> locals) { 237 this.stack = stack; 238 this.locals = locals; 239 } 240 241 State() { 242 this(new ArrayList<>(), new Vector<>()); 243 } 244 245 void push(TypeTag tag) { 246 switch (tag) { 247 case A: 248 case V: 249 throw new IllegalStateException("Bad type tag"); 250 default: 251 push(typeHelper.fromTag(tag)); 252 } 253 } 254 255 void push(T t) { 256 stack.add(t); 257 if (width(t) == 2) { 258 stack.add(null); 259 } 260 if (stack.size() > stacksize) { 261 stacksize = stack.size(); 262 } 263 } 264 265 T peek() { 266 return stack.get(stack.size() - 1); 267 } 268 269 T tosType() { 270 T tos = peek(); 271 if (tos == null) { 272 //double slot 273 tos = stack.get(stack.size() - 2); 274 } 275 return tos; 276 } 277 278 T popInternal() { 279 return stack.remove(stack.size() - 1); 280 } 281 282 @SuppressWarnings("unchecked") 283 T pop() { 284 if (stack.size() == 0 || peek() == null) throw new IllegalStateException(); 285 return popInternal(); 286 } 287 288 T pop2() { 289 T o = stack.get(stack.size() - 2); 290 TypeTag t = typeHelper.tag(o); 291 if (t.width != 2) throw new IllegalStateException(); 292 popInternal(); 293 popInternal(); 294 return o; 295 } 296 297 T pop(TypeTag t) { 298 return (t.width() == 2) ? 299 pop2() : pop(); 300 } 301 302 void load(TypeTag tag, int index) { 303 if (tag == TypeTag.A) throw new IllegalStateException("Bad type tag"); 304 load(typeHelper.fromTag(tag), index); 305 } 306 307 void load(T t, int index) { 308 ensureDefined(index); 309 locals.set(index, t); 310 if (width(t) == 2) { 311 locals.add(null); 312 } 313 if (locals.size() > localsize) { 314 localsize = locals.size(); 315 } 316 } 317 318 void ensureDefined(int index) { 319 if (index >= locals.size()) { 320 locals.setSize(index + 1); 321 } 322 } 323 324 State dup() { 325 State newState = new State(new ArrayList<>(stack), new Vector<>(locals)); 326 return newState; 327 } 328 329 State merge(State that) { 330 if (that.stack.size() != stack.size()) { 331 throw new IllegalStateException("Bad stack size at merge point"); 332 } 333 for (int i = 0; i < stack.size(); i++) { 334 T t1 = stack.get(i); 335 T t2 = that.stack.get(i); 336 stack.set(i, merge(t1, t2, "Bad stack type at merge point")); 337 } 338 int nlocals = locals.size() > that.locals.size() ? that.locals.size() : locals.size(); 339 for (int i = 0; i < nlocals; i++) { 340 T t1 = locals.get(i); 341 T t2 = that.locals.get(i); 342 locals.set(i, merge(t1, t2, "Bad local type at merge point")); 343 } 344 if (locals.size() > nlocals) { 345 for (int i = nlocals; i < locals.size(); i++) { 346 locals.remove(i); 347 } 348 } 349 return this; 350 } 351 352 T merge(T t1, T t2, String msg) { 353 if (t1 == null && t2 == null) { 354 return t1; 355 } 356 T res; 357 TypeTag tag1 = typeHelper.tag(t1); 358 TypeTag tag2 = typeHelper.tag(t2); 359 if (tag1 != TypeTag.A && tag2 != TypeTag.A && 360 tag1 != TypeTag.Q && tag2 != TypeTag.Q) { 361 res = typeHelper.fromTag(TypeTag.commonSupertype(tag1, tag2)); 362 } else if (t1 == typeHelper.nullType()) { 363 res = t2; 364 } else if (t2 == typeHelper.nullType()) { 365 res = t1; 366 } else { 367 res = typeHelper.commonSupertype(t1, t2); 368 } 369 if (res == null) { 370 throw new IllegalStateException(msg); 371 } 372 return res; 373 } 374 375 @Override 376 public String toString() { 377 return String.format("[locals = %s, stack = %s]", locals, stack); 378 } 379 } 380 381 int width(T o) { 382 return o == typeHelper.nullType() ? 383 TypeTag.A.width() : 384 typeHelper.tag(o).width; 385 } 386 387 @SuppressWarnings("unchecked") 388 public void updateState(Opcode op, Object optValue) { 389 switch (op) { 390 case VALOAD: 391 case AALOAD: 392 state.pop(); 393 state.push(typeHelper.elemtype(state.pop())); 394 break; 395 case GOTO_: 396 break; 397 case NOP: 398 case INEG: 399 case LNEG: 400 case FNEG: 401 case DNEG: 402 break; 403 case ACONST_NULL: 404 state.push(typeHelper.nullType()); 405 break; 406 case ICONST_M1: 407 case ICONST_0: 408 case ICONST_1: 409 case ICONST_2: 410 case ICONST_3: 411 case ICONST_4: 412 case ICONST_5: 413 state.push(TypeTag.I); 414 break; 415 case LCONST_0: 416 case LCONST_1: 417 state.push(TypeTag.J); 418 break; 419 case FCONST_0: 420 case FCONST_1: 421 case FCONST_2: 422 state.push(TypeTag.F); 423 break; 424 case DCONST_0: 425 case DCONST_1: 426 state.push(TypeTag.D); 427 break; 428 case ILOAD_0: 429 case FLOAD_0: 430 case ALOAD_0: 431 case LLOAD_0: 432 case DLOAD_0: 433 state.push(state.locals.get(0)); 434 break; 435 case ILOAD_1: 436 case FLOAD_1: 437 case ALOAD_1: 438 case LLOAD_1: 439 case DLOAD_1: 440 state.push(state.locals.get(1)); 441 break; 442 case ILOAD_2: 443 case FLOAD_2: 444 case ALOAD_2: 445 case LLOAD_2: 446 case DLOAD_2: 447 state.push(state.locals.get(2)); 448 break; 449 case ILOAD_3: 450 case FLOAD_3: 451 case ALOAD_3: 452 case LLOAD_3: 453 case DLOAD_3: 454 state.push(state.locals.get(3)); 455 break; 456 case ILOAD: 457 case FLOAD: 458 case ALOAD: 459 case LLOAD: 460 case DLOAD: 461 case VLOAD: 462 state.push(state.locals.get((Integer) optValue)); 463 break; 464 case IALOAD: 465 case BALOAD: 466 case CALOAD: 467 case SALOAD: 468 state.pop(); 469 state.pop(); 470 state.push(TypeTag.I); 471 break; 472 case LALOAD: 473 state.pop(); 474 state.pop(); 475 state.push(TypeTag.J); 476 break; 477 case FALOAD: 478 state.pop(); 479 state.pop(); 480 state.push(TypeTag.F); 481 break; 482 case DALOAD: 483 state.pop(); 484 state.pop(); 485 state.push(TypeTag.D); 486 break; 487 case ISTORE_0: 488 case FSTORE_0: 489 case ASTORE_0: 490 state.load(state.pop(), 0); 491 break; 492 case ISTORE_1: 493 case FSTORE_1: 494 case ASTORE_1: 495 state.load(state.pop(), 1); 496 break; 497 case ISTORE_2: 498 case FSTORE_2: 499 case ASTORE_2: 500 state.load(state.pop(), 2); 501 break; 502 case ISTORE_3: 503 case FSTORE_3: 504 case ASTORE_3: 505 state.load(state.pop(), 3); 506 break; 507 case ISTORE: 508 case FSTORE: 509 case ASTORE: 510 case VSTORE: 511 state.load(state.pop(), (int) optValue); 512 break; 513 case LSTORE_0: 514 case DSTORE_0: 515 state.load(state.pop2(), 0); 516 break; 517 case LSTORE_1: 518 case DSTORE_1: 519 state.load(state.pop2(), 1); 520 break; 521 case LSTORE_2: 522 case DSTORE_2: 523 state.load(state.pop2(), 2); 524 break; 525 case LSTORE_3: 526 case DSTORE_3: 527 state.load(state.pop2(), 3); 528 break; 529 case LSTORE: 530 case DSTORE: 531 state.load(state.pop2(), (int) optValue); 532 break; 533 case POP: 534 case LSHR: 535 case LSHL: 536 case LUSHR: 537 state.pop(); 538 break; 539 case VRETURN: 540 case ARETURN: 541 case IRETURN: 542 case FRETURN: 543 state.pop(); 544 break; 545 case ATHROW: 546 state.pop(); 547 break; 548 case POP2: 549 state.pop2(); 550 break; 551 case LRETURN: 552 case DRETURN: 553 state.pop2(); 554 break; 555 case DUP: 556 state.push(state.peek()); 557 break; 558 case RETURN: 559 break; 560 case ARRAYLENGTH: 561 state.pop(); 562 state.push(TypeTag.I); 563 break; 564 case ISUB: 565 case IADD: 566 case IMUL: 567 case IDIV: 568 case IREM: 569 case ISHL: 570 case ISHR: 571 case IUSHR: 572 case IAND: 573 case IOR: 574 case IXOR: 575 state.pop(); 576 state.pop(); 577 state.push(TypeTag.I); 578 break; 579 case VASTORE: 580 case AASTORE: 581 state.pop(); 582 state.pop(); 583 state.pop(); 584 break; 585 case LAND: 586 case LOR: 587 case LXOR: 588 case LREM: 589 case LDIV: 590 case LMUL: 591 case LSUB: 592 case LADD: 593 state.pop2(); 594 state.pop2(); 595 state.push(TypeTag.J); 596 break; 597 case LCMP: 598 state.pop2(); 599 state.pop2(); 600 state.push(TypeTag.I); 601 break; 602 case L2I: 603 state.pop2(); 604 state.push(TypeTag.I); 605 break; 606 case I2L: 607 state.pop(); 608 state.push(TypeTag.J); 609 break; 610 case I2F: 611 state.pop(); 612 state.push(TypeTag.F); 613 break; 614 case I2D: 615 state.pop(); 616 state.push(TypeTag.D); 617 break; 618 case L2F: 619 state.pop2(); 620 state.push(TypeTag.F); 621 break; 622 case L2D: 623 state.pop2(); 624 state.push(TypeTag.D); 625 break; 626 case F2I: 627 state.pop(); 628 state.push(TypeTag.I); 629 break; 630 case F2L: 631 state.pop(); 632 state.push(TypeTag.J); 633 break; 634 case F2D: 635 state.pop(); 636 state.push(TypeTag.D); 637 break; 638 case D2I: 639 state.pop2(); 640 state.push(TypeTag.I); 641 break; 642 case D2L: 643 state.pop2(); 644 state.push(TypeTag.J); 645 break; 646 case D2F: 647 state.pop2(); 648 state.push(TypeTag.F); 649 break; 650 case TABLESWITCH: 651 case LOOKUPSWITCH: 652 state.pop(); 653 break; 654 case DUP_X1: { 655 T val1 = state.pop(); 656 T val2 = state.pop(); 657 state.push(val1); 658 state.push(val2); 659 state.push(val1); 660 break; 661 } 662 case BASTORE: 663 state.pop(); 664 state.pop(); 665 state.pop(); 666 break; 667 case I2B: 668 case I2C: 669 case I2S: 670 break; 671 case FMUL: 672 case FADD: 673 case FSUB: 674 case FDIV: 675 case FREM: 676 state.pop(); 677 state.pop(); 678 state.push(TypeTag.F); 679 break; 680 case CASTORE: 681 case IASTORE: 682 case FASTORE: 683 case SASTORE: 684 state.pop(); 685 state.pop(); 686 state.pop(); 687 break; 688 case LASTORE: 689 case DASTORE: 690 state.pop2(); 691 state.pop(); 692 state.pop(); 693 break; 694 case DUP2: 695 if (state.peek() != null) { 696 //form 1 697 T value1 = state.pop(); 698 T value2 = state.pop(); 699 state.push(value2); 700 state.push(value1); 701 state.push(value2); 702 state.push(value1); 703 } else { 704 //form 2 705 T value = state.pop2(); 706 state.push(value); 707 state.push(value); 708 } 709 break; 710 case DUP2_X1: 711 if (state.peek() != null) { 712 T value1 = state.pop(); 713 T value2 = state.pop(); 714 T value3 = state.pop(); 715 state.push(value2); 716 state.push(value1); 717 state.push(value3); 718 state.push(value2); 719 state.push(value1); 720 } else { 721 T value1 = state.pop2(); 722 T value2 = state.pop(); 723 state.push(value1); 724 state.push(value2); 725 state.push(value1); 726 } 727 break; 728 case DUP2_X2: 729 if (state.peek() != null) { 730 T value1 = state.pop(); 731 T value2 = state.pop(); 732 if (state.peek() != null) { 733 // form 1 734 T value3 = state.pop(); 735 T value4 = state.pop(); 736 state.push(value2); 737 state.push(value1); 738 state.push(value4); 739 state.push(value3); 740 state.push(value2); 741 state.push(value1); 742 } else { 743 // form 3 744 T value3 = state.pop2(); 745 state.push(value2); 746 state.push(value1); 747 state.push(value3); 748 state.push(value2); 749 state.push(value1); 750 } 751 } else { 752 T value1 = state.pop2(); 753 if (state.peek() != null) { 754 // form 2 755 T value2 = state.pop(); 756 T value3 = state.pop(); 757 state.push(value1); 758 state.push(value3); 759 state.push(value2); 760 state.push(value1); 761 } else { 762 // form 4 763 T value2 = state.pop2(); 764 state.push(value1); 765 state.push(value2); 766 state.push(value1); 767 } 768 } 769 break; 770 case DUP_X2: { 771 T value1 = state.pop(); 772 if (state.peek() != null) { 773 // form 1 774 T value2 = state.pop(); 775 T value3 = state.pop(); 776 state.push(value1); 777 state.push(value3); 778 state.push(value2); 779 state.push(value1); 780 } else { 781 // form 2 782 T value2 = state.pop2(); 783 state.push(value1); 784 state.push(value2); 785 state.push(value1); 786 } 787 } 788 break; 789 case FCMPL: 790 case FCMPG: 791 state.pop(); 792 state.pop(); 793 state.push(TypeTag.I); 794 break; 795 case DCMPL: 796 case DCMPG: 797 state.pop2(); 798 state.pop2(); 799 state.push(TypeTag.I); 800 break; 801 case SWAP: { 802 T value1 = state.pop(); 803 T value2 = state.pop(); 804 state.push(value1); 805 state.push(value2); 806 break; 807 } 808 case DADD: 809 case DSUB: 810 case DMUL: 811 case DDIV: 812 case DREM: 813 state.pop2(); 814 state.pop2(); 815 state.push(TypeTag.D); 816 break; 817 case RET: 818 break; 819 case WIDE: 820 // must be handled by the caller. 821 return; 822 case MONITORENTER: 823 case MONITOREXIT: 824 state.pop(); 825 break; 826 case VNEW: 827 throw new UnsupportedOperationException("VNEW not implemented"); 828 //processVnew(op, (T) optValue); 829 //break; 830 case NEW: 831 case VDEFAULT: 832 state.push(typeHelper.type((S) optValue)); 833 break; 834 case NEWARRAY: 835 state.pop(); 836 state.push(typeHelper.arrayOf(typeHelper.fromTag((TypeTag) optValue))); 837 break; 838 case ANEWARRAY: 839 state.pop(); 840 state.push(typeHelper.arrayOf(typeHelper.arrayOf(typeHelper.type((S)optValue)))); 841 break; 842 case VBOX: 843 case VUNBOX: 844 state.pop(); 845 state.push(typeHelper.type((S) optValue)); 846 break; 847 case MULTIANEWARRAY: 848 for (int i = 0; i < (byte) ((Object[]) optValue)[1]; i++) { 849 state.pop(); 850 } 851 state.push(typeHelper.type((S) ((Object[]) optValue)[0])); 852 break; 853 case INVOKEINTERFACE: 854 case INVOKEVIRTUAL: 855 case INVOKESPECIAL: 856 case INVOKESTATIC: 857 processInvoke(op, (T) optValue); 858 break; 859 case GETSTATIC: 860 state.push((T) optValue); 861 break; 862 case VGETFIELD: 863 case GETFIELD: 864 state.pop(); 865 state.push((T) optValue); 866 break; 867 case PUTSTATIC: { 868 TypeTag tag = typeHelper.tag((T) optValue); 869 if (tag.width == 1) { 870 state.pop(); 871 } else { 872 state.pop2(); 873 } 874 break; 875 } 876 case PUTFIELD: { 877 TypeTag tag = typeHelper.tag((T) optValue); 878 if (tag.width == 1) { 879 state.pop(); 880 } else { 881 state.pop2(); 882 } 883 state.pop(); 884 break; 885 } 886 case VWITHFIELD: { 887 TypeTag tag = typeHelper.tag((T) optValue); 888 if (tag.width == 1) { 889 state.pop(); 890 } else { 891 state.pop2(); 892 } 893 // state.pop(); state.push(); 894 break; 895 } 896 case BIPUSH: 897 case SIPUSH: 898 state.push(TypeTag.I); 899 break; 900 case LDC: 901 case LDC_W: 902 case LDC2_W: 903 state.push(ldcType(optValue)); 904 break; 905 case IF_ACMPEQ: 906 case IF_ICMPEQ: 907 case IF_ACMPNE: 908 case IF_ICMPGE: 909 case IF_ICMPGT: 910 case IF_ICMPLE: 911 case IF_ICMPLT: 912 case IF_ICMPNE: 913 state.pop(); 914 state.pop(); 915 break; 916 case IF_NONNULL: 917 case IF_NULL: 918 case IFEQ: 919 case IFGE: 920 case IFGT: 921 case IFLE: 922 case IFLT: 923 case IFNE: 924 state.pop(); 925 break; 926 case INSTANCEOF: 927 state.pop(); 928 state.push(TypeTag.Z); 929 break; 930 case TYPED: 931 case CHECKCAST: 932 break; 933 934 default: 935 throw new UnsupportedOperationException("Unsupported opcode: " + op); 936 } 937 } 938 939 void processInvoke(Opcode opcode, T invokedType) { 940 Iterator<T> paramsIt = typeHelper.parameterTypes(invokedType); 941 while (paramsIt.hasNext()) { 942 T t = paramsIt.next(); 943 TypeTag tag = typeHelper.tag(t); 944 if (tag.width == 2) { 945 state.popInternal(); 946 state.popInternal(); 947 } else { 948 state.popInternal(); 949 } 950 } 951 if (opcode != Opcode.INVOKESTATIC) { 952 state.pop(); //receiver 953 } 954 T retType = typeHelper.returnType(invokedType); 955 TypeTag retTag = typeHelper.tag(retType); 956 if (retTag != TypeTag.V) 957 state.push(retType); 958 } 959 960 T ldcType(Object o) { 961 if (o instanceof Double) { 962 return typeHelper.fromTag(TypeTag.D); 963 } else if (o instanceof Long) { 964 return typeHelper.fromTag(TypeTag.J); 965 } else if (o instanceof Float) { 966 return typeHelper.fromTag(TypeTag.F); 967 } else if (o instanceof Integer) { 968 return typeHelper.fromTag(TypeTag.I); 969 } else if (o instanceof Class<?>) { 970 return typeHelper.type(typeHelper.symbolFrom("java/lang/Class")); 971 } else if (o instanceof String) { 972 return typeHelper.type(typeHelper.symbolFrom("java/lang/String")); 973 } else if (o instanceof MethodHandle) { 974 return typeHelper.type(typeHelper.symbolFrom("java/lang/invoke/MethodHandle")); 975 } else if (o instanceof MethodType) { 976 return typeHelper.type(typeHelper.symbolFrom("java/lang/invoke/MethodType")); 977 } else { 978 throw new IllegalStateException(); 979 } 980 } 981 982 public C load(int index) { 983 return load(typeHelper.tag(state.locals.get(index)), index); 984 } 985 986 public C store(int index) { 987 return store(typeHelper.tag(state.tosType()), index); 988 } 989 990 @Override 991 public C withLocalSize(int localsize) { 992 throw new IllegalStateException("Local size automatically computed"); 993 } 994 995 @Override 996 public C withStackSize(int stacksize) { 997 throw new IllegalStateException("Stack size automatically computed"); 998 } 999 1000 public C withLocal(CharSequence name, T type) { 1001 int offset = currLocalOffset; 1002 TypeTag tag = typeHelper.tag(type); 1003 lvarOffsets.put(name, new LocalVarInfo(name, offset, depth, tag)); 1004 state.load(type, offset); 1005 currLocalOffset += tag.width; 1006 return thisBuilder(); 1007 } 1008 1009 public C load(CharSequence local) { 1010 return load(lvarOffsets.get(local).offset); 1011 } 1012 1013 public C store(CharSequence local) { 1014 return store(lvarOffsets.get(local).offset); 1015 } 1016 1017 @Override 1018 public C withTry(Consumer<? super C> tryBlock, Consumer<? super CatchBuilder> catchBlocks) { 1019 return super.withTry(c -> { 1020 withLocalScope(() -> { 1021 tryBlock.accept(c); 1022 }); 1023 }, catchBlocks); 1024 } 1025 1026 @Override 1027 protected CatchBuilder makeCatchBuilder(int start, int end) { 1028 return new TypedCatchBuilder(start, end); 1029 } 1030 1031 class TypedCatchBuilder extends CatchBuilder { 1032 1033 State initialState = state.dup(); 1034 1035 TypedCatchBuilder(int start, int end) { 1036 super(start, end); 1037 } 1038 1039 @Override 1040 protected void emitCatch(S exc, Consumer<? super C> catcher) { 1041 withLocalScope(() -> { 1042 state.push(typeHelper.type(exc)); 1043 emitStackMap(code.offset); 1044 super.emitCatch(exc, catcher); 1045 state = initialState; 1046 }); 1047 } 1048 1049 @Override 1050 protected void emitFinalizer() { 1051 withLocalScope(() -> { 1052 state.push(typeHelper.type(typeHelper.symbolFrom("java/lang/Throwable"))); 1053 emitStackMap(code.offset); 1054 super.emitFinalizer(); 1055 }); 1056 } 1057 } 1058 1059 protected void withLocalScope(Runnable runnable) { 1060 int prevDepth = depth; 1061 try { 1062 depth++; 1063 runnable.run(); 1064 } finally { 1065 Iterator<Entry<CharSequence, LocalVarInfo>> lvarIt = lvarOffsets.entrySet().iterator(); 1066 while (lvarIt.hasNext()) { 1067 LocalVarInfo lvi = lvarIt.next().getValue(); 1068 if (lvi.depth == depth) { 1069 int width = lvi.type.width; 1070 currLocalOffset -= width; 1071 lvarIt.remove(); 1072 } 1073 } 1074 depth = prevDepth; 1075 } 1076 } 1077 1078 @Override 1079 void addPendingJump(CharSequence label, int pc) { 1080 pendingJumps.add(new StatefulPendingJump(label, pc, state.dup())); 1081 } 1082 1083 @Override 1084 void resolveJumps(CharSequence label, int pc) { 1085 super.resolveJumps(label, pc); 1086 emitStackMap(pc); 1087 } 1088 1089 //TODO: optimize stackmap generation by avoiding intermediate classes 1090 protected void emitStackMap(int pc) { 1091 //stack map generation 1092 if (pc > lastStackMapPc) { 1093 writeStackMapFrame(pc); 1094 lastStackMapState = state.dup(); 1095 lastStackMapPc = pc; 1096 nstackmaps++; 1097 } 1098 } 1099 1100 @Override 1101 void build(GrowableByteBuffer buf) { 1102 if (stacksize == -1) { 1103 throw new IllegalStateException("Bad stack size"); 1104 } 1105 if (localsize == -1) { 1106 throw new IllegalStateException("Bad locals size"); 1107 } 1108 if (nstackmaps > 0) { 1109 GrowableByteBuffer stackmapsAttr = new GrowableByteBuffer(); 1110 stackmapsAttr.writeChar(nstackmaps); 1111 stackmapsAttr.writeBytes(stackmaps); 1112 withAttribute("StackMapTable", stackmapsAttr.bytes()); 1113 } 1114 super.build(buf); 1115 } 1116 1117 /** 1118 * Compare this frame with the previous frame and produce 1119 * an entry of compressed stack map frame. 1120 */ 1121 void writeStackMapFrame(int pc) { 1122 List<T> locals = state.locals; 1123 List<T> stack = state.stack; 1124 List<T> prev_locals = lastStackMapState.locals; 1125 int offset_delta = lastStackMapPc == -1 ? pc : pc - lastStackMapPc - 1; 1126 if (stack.size() == 1) { 1127 if (locals.size() == prev_locals.size() && prev_locals.equals(locals)) { 1128 sameLocals1StackItemFrame(offset_delta, stack.get(stack.size() - 1)); 1129 return; 1130 } 1131 } else if (stack.size() == 0) { 1132 int diff_length = prev_locals.size() - locals.size(); 1133 if (diff_length == 0) { 1134 sameFrame(offset_delta); 1135 return; 1136 } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) { 1137 appendFrame(offset_delta, prev_locals.size(), locals); 1138 return; 1139 } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) { 1140 chopFrame(offset_delta, diff_length); 1141 return; 1142 } 1143 } 1144 fullFrame(offset_delta, locals, stack); 1145 } 1146 }