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 boolean alive; 236 237 State(ArrayList<T> stack, Vector<T> locals) { 238 this.stack = stack; 239 this.locals = locals; 240 } 241 242 State() { 243 this(new ArrayList<>(), new Vector<>()); 244 } 245 246 void push(TypeTag tag) { 247 switch (tag) { 248 case A: 249 case V: 250 throw new IllegalStateException("Bad type tag"); 251 default: 252 push(typeHelper.fromTag(tag)); 253 } 254 } 255 256 void push(T t) { 257 stack.add(t); 258 if (width(t) == 2) { 259 stack.add(null); 260 } 261 if (stack.size() > stacksize) { 262 stacksize = stack.size(); 263 } 264 } 265 266 T peek() { 267 return stack.get(stack.size() - 1); 268 } 269 270 T tosType() { 271 T tos = peek(); 272 if (tos == null) { 273 //double slot 274 tos = stack.get(stack.size() - 2); 275 } 276 return tos; 277 } 278 279 T popInternal() { 280 return stack.remove(stack.size() - 1); 281 } 282 283 @SuppressWarnings("unchecked") 284 T pop() { 285 if (stack.size() == 0 || peek() == null) throw new IllegalStateException(); 286 return popInternal(); 287 } 288 289 T pop2() { 290 T o = stack.get(stack.size() - 2); 291 TypeTag t = typeHelper.tag(o); 292 if (t.width != 2) throw new IllegalStateException(); 293 popInternal(); 294 popInternal(); 295 return o; 296 } 297 298 T pop(TypeTag t) { 299 return (t.width() == 2) ? 300 pop2() : pop(); 301 } 302 303 void load(TypeTag tag, int index) { 304 if (tag == TypeTag.A) throw new IllegalStateException("Bad type tag"); 305 load(typeHelper.fromTag(tag), index); 306 } 307 308 void load(T t, int index) { 309 ensureDefined(index); 310 locals.set(index, t); 311 if (width(t) == 2) { 312 locals.add(null); 313 } 314 if (locals.size() > localsize) { 315 localsize = locals.size(); 316 } 317 } 318 319 void ensureDefined(int index) { 320 if (index >= locals.size()) { 321 locals.setSize(index + 1); 322 } 323 } 324 325 State dup() { 326 State newState = new State(new ArrayList<>(stack), new Vector<>(locals)); 327 return newState; 328 } 329 330 State merge(State that) { 331 if (!alive) { return that; } 332 if (that.stack.size() != stack.size()) { 333 throw new IllegalStateException("Bad stack size at merge point"); 334 } 335 for (int i = 0; i < stack.size(); i++) { 336 T t1 = stack.get(i); 337 T t2 = that.stack.get(i); 338 stack.set(i, merge(t1, t2, "Bad stack type at merge point")); 339 } 340 int nlocals = locals.size() > that.locals.size() ? that.locals.size() : locals.size(); 341 for (int i = 0; i < nlocals; i++) { 342 T t1 = locals.get(i); 343 T t2 = that.locals.get(i); 344 locals.set(i, merge(t1, t2, "Bad local type at merge point")); 345 } 346 if (locals.size() > nlocals) { 347 for (int i = nlocals; i < locals.size(); i++) { 348 locals.remove(i); 349 } 350 } 351 return this; 352 } 353 354 T merge(T t1, T t2, String msg) { 355 if (t1 == null && t2 == null) { 356 return t1; 357 } 358 T res; 359 TypeTag tag1 = typeHelper.tag(t1); 360 TypeTag tag2 = typeHelper.tag(t2); 361 if (tag1 != TypeTag.A && tag2 != TypeTag.A && 362 tag1 != TypeTag.Q && tag2 != TypeTag.Q) { 363 res = typeHelper.fromTag(TypeTag.commonSupertype(tag1, tag2)); 364 } else if (t1 == typeHelper.nullType()) { 365 res = t2; 366 } else if (t2 == typeHelper.nullType()) { 367 res = t1; 368 } else { 369 res = typeHelper.commonSupertype(t1, t2); 370 } 371 if (res == null) { 372 throw new IllegalStateException(msg); 373 } 374 return res; 375 } 376 377 @Override 378 public String toString() { 379 return String.format("[locals = %s, stack = %s]", locals, stack); 380 } 381 } 382 383 int width(T o) { 384 return o == typeHelper.nullType() ? 385 TypeTag.A.width() : 386 typeHelper.tag(o).width; 387 } 388 389 @SuppressWarnings("unchecked") 390 public void updateState(Opcode op, Object optValue) { 391 switch (op) { 392 case VALOAD: 393 case AALOAD: 394 state.pop(); 395 state.push(typeHelper.elemtype(state.pop())); 396 break; 397 case GOTO_: 398 state.alive = false; 399 break; 400 case NOP: 401 case IINC: 402 case INEG: 403 case LNEG: 404 case FNEG: 405 case DNEG: 406 break; 407 case ACONST_NULL: 408 state.push(typeHelper.nullType()); 409 break; 410 case ICONST_M1: 411 case ICONST_0: 412 case ICONST_1: 413 case ICONST_2: 414 case ICONST_3: 415 case ICONST_4: 416 case ICONST_5: 417 state.push(TypeTag.I); 418 break; 419 case LCONST_0: 420 case LCONST_1: 421 state.push(TypeTag.J); 422 break; 423 case FCONST_0: 424 case FCONST_1: 425 case FCONST_2: 426 state.push(TypeTag.F); 427 break; 428 case DCONST_0: 429 case DCONST_1: 430 state.push(TypeTag.D); 431 break; 432 case ILOAD_0: 433 case FLOAD_0: 434 case ALOAD_0: 435 case LLOAD_0: 436 case DLOAD_0: 437 state.push(state.locals.get(0)); 438 break; 439 case ILOAD_1: 440 case FLOAD_1: 441 case ALOAD_1: 442 case LLOAD_1: 443 case DLOAD_1: 444 state.push(state.locals.get(1)); 445 break; 446 case ILOAD_2: 447 case FLOAD_2: 448 case ALOAD_2: 449 case LLOAD_2: 450 case DLOAD_2: 451 state.push(state.locals.get(2)); 452 break; 453 case ILOAD_3: 454 case FLOAD_3: 455 case ALOAD_3: 456 case LLOAD_3: 457 case DLOAD_3: 458 state.push(state.locals.get(3)); 459 break; 460 case ILOAD: 461 case FLOAD: 462 case ALOAD: 463 case LLOAD: 464 case DLOAD: 465 case VLOAD: 466 state.push(state.locals.get((Integer) optValue)); 467 break; 468 case IALOAD: 469 case BALOAD: 470 case CALOAD: 471 case SALOAD: 472 state.pop(); 473 state.pop(); 474 state.push(TypeTag.I); 475 break; 476 case LALOAD: 477 state.pop(); 478 state.pop(); 479 state.push(TypeTag.J); 480 break; 481 case FALOAD: 482 state.pop(); 483 state.pop(); 484 state.push(TypeTag.F); 485 break; 486 case DALOAD: 487 state.pop(); 488 state.pop(); 489 state.push(TypeTag.D); 490 break; 491 case ISTORE_0: 492 case FSTORE_0: 493 case ASTORE_0: 494 state.load(state.pop(), 0); 495 break; 496 case ISTORE_1: 497 case FSTORE_1: 498 case ASTORE_1: 499 state.load(state.pop(), 1); 500 break; 501 case ISTORE_2: 502 case FSTORE_2: 503 case ASTORE_2: 504 state.load(state.pop(), 2); 505 break; 506 case ISTORE_3: 507 case FSTORE_3: 508 case ASTORE_3: 509 state.load(state.pop(), 3); 510 break; 511 case ISTORE: 512 case FSTORE: 513 case ASTORE: 514 case VSTORE: 515 state.load(state.pop(), (int) optValue); 516 break; 517 case LSTORE_0: 518 case DSTORE_0: 519 state.load(state.pop2(), 0); 520 break; 521 case LSTORE_1: 522 case DSTORE_1: 523 state.load(state.pop2(), 1); 524 break; 525 case LSTORE_2: 526 case DSTORE_2: 527 state.load(state.pop2(), 2); 528 break; 529 case LSTORE_3: 530 case DSTORE_3: 531 state.load(state.pop2(), 3); 532 break; 533 case LSTORE: 534 case DSTORE: 535 state.load(state.pop2(), (int) optValue); 536 break; 537 case POP: 538 case LSHR: 539 case LSHL: 540 case LUSHR: 541 state.pop(); 542 break; 543 case VRETURN: 544 case ARETURN: 545 case IRETURN: 546 case FRETURN: 547 state.pop(); 548 break; 549 case ATHROW: 550 state.pop(); 551 break; 552 case POP2: 553 state.pop2(); 554 break; 555 case LRETURN: 556 case DRETURN: 557 state.pop2(); 558 break; 559 case DUP: 560 state.push(state.peek()); 561 break; 562 case RETURN: 563 break; 564 case ARRAYLENGTH: 565 state.pop(); 566 state.push(TypeTag.I); 567 break; 568 case ISUB: 569 case IADD: 570 case IMUL: 571 case IDIV: 572 case IREM: 573 case ISHL: 574 case ISHR: 575 case IUSHR: 576 case IAND: 577 case IOR: 578 case IXOR: 579 state.pop(); 580 state.pop(); 581 state.push(TypeTag.I); 582 break; 583 case VASTORE: 584 case AASTORE: 585 state.pop(); 586 state.pop(); 587 state.pop(); 588 break; 589 case LAND: 590 case LOR: 591 case LXOR: 592 case LREM: 593 case LDIV: 594 case LMUL: 595 case LSUB: 596 case LADD: 597 state.pop2(); 598 state.pop2(); 599 state.push(TypeTag.J); 600 break; 601 case LCMP: 602 state.pop2(); 603 state.pop2(); 604 state.push(TypeTag.I); 605 break; 606 case L2I: 607 state.pop2(); 608 state.push(TypeTag.I); 609 break; 610 case I2L: 611 state.pop(); 612 state.push(TypeTag.J); 613 break; 614 case I2F: 615 state.pop(); 616 state.push(TypeTag.F); 617 break; 618 case I2D: 619 state.pop(); 620 state.push(TypeTag.D); 621 break; 622 case L2F: 623 state.pop2(); 624 state.push(TypeTag.F); 625 break; 626 case L2D: 627 state.pop2(); 628 state.push(TypeTag.D); 629 break; 630 case F2I: 631 state.pop(); 632 state.push(TypeTag.I); 633 break; 634 case F2L: 635 state.pop(); 636 state.push(TypeTag.J); 637 break; 638 case F2D: 639 state.pop(); 640 state.push(TypeTag.D); 641 break; 642 case D2I: 643 state.pop2(); 644 state.push(TypeTag.I); 645 break; 646 case D2L: 647 state.pop2(); 648 state.push(TypeTag.J); 649 break; 650 case D2F: 651 state.pop2(); 652 state.push(TypeTag.F); 653 break; 654 case TABLESWITCH: 655 case LOOKUPSWITCH: 656 state.pop(); 657 break; 658 case DUP_X1: { 659 T val1 = state.pop(); 660 T val2 = state.pop(); 661 state.push(val1); 662 state.push(val2); 663 state.push(val1); 664 break; 665 } 666 case BASTORE: 667 state.pop(); 668 state.pop(); 669 state.pop(); 670 break; 671 case I2B: 672 case I2C: 673 case I2S: 674 break; 675 case FMUL: 676 case FADD: 677 case FSUB: 678 case FDIV: 679 case FREM: 680 state.pop(); 681 state.pop(); 682 state.push(TypeTag.F); 683 break; 684 case CASTORE: 685 case IASTORE: 686 case FASTORE: 687 case SASTORE: 688 state.pop(); 689 state.pop(); 690 state.pop(); 691 break; 692 case LASTORE: 693 case DASTORE: 694 state.pop2(); 695 state.pop(); 696 state.pop(); 697 break; 698 case DUP2: 699 if (state.peek() != null) { 700 //form 1 701 T value1 = state.pop(); 702 T value2 = state.pop(); 703 state.push(value2); 704 state.push(value1); 705 state.push(value2); 706 state.push(value1); 707 } else { 708 //form 2 709 T value = state.pop2(); 710 state.push(value); 711 state.push(value); 712 } 713 break; 714 case DUP2_X1: 715 if (state.peek() != null) { 716 T value1 = state.pop(); 717 T value2 = state.pop(); 718 T value3 = state.pop(); 719 state.push(value2); 720 state.push(value1); 721 state.push(value3); 722 state.push(value2); 723 state.push(value1); 724 } else { 725 T value1 = state.pop2(); 726 T value2 = state.pop(); 727 state.push(value1); 728 state.push(value2); 729 state.push(value1); 730 } 731 break; 732 case DUP2_X2: 733 if (state.peek() != null) { 734 T value1 = state.pop(); 735 T value2 = state.pop(); 736 if (state.peek() != null) { 737 // form 1 738 T value3 = state.pop(); 739 T value4 = state.pop(); 740 state.push(value2); 741 state.push(value1); 742 state.push(value4); 743 state.push(value3); 744 state.push(value2); 745 state.push(value1); 746 } else { 747 // form 3 748 T value3 = state.pop2(); 749 state.push(value2); 750 state.push(value1); 751 state.push(value3); 752 state.push(value2); 753 state.push(value1); 754 } 755 } else { 756 T value1 = state.pop2(); 757 if (state.peek() != null) { 758 // form 2 759 T value2 = state.pop(); 760 T value3 = state.pop(); 761 state.push(value1); 762 state.push(value3); 763 state.push(value2); 764 state.push(value1); 765 } else { 766 // form 4 767 T value2 = state.pop2(); 768 state.push(value1); 769 state.push(value2); 770 state.push(value1); 771 } 772 } 773 break; 774 case DUP_X2: { 775 T value1 = state.pop(); 776 if (state.peek() != null) { 777 // form 1 778 T value2 = state.pop(); 779 T value3 = state.pop(); 780 state.push(value1); 781 state.push(value3); 782 state.push(value2); 783 state.push(value1); 784 } else { 785 // form 2 786 T value2 = state.pop2(); 787 state.push(value1); 788 state.push(value2); 789 state.push(value1); 790 } 791 } 792 break; 793 case FCMPL: 794 case FCMPG: 795 state.pop(); 796 state.pop(); 797 state.push(TypeTag.I); 798 break; 799 case DCMPL: 800 case DCMPG: 801 state.pop2(); 802 state.pop2(); 803 state.push(TypeTag.I); 804 break; 805 case SWAP: { 806 T value1 = state.pop(); 807 T value2 = state.pop(); 808 state.push(value1); 809 state.push(value2); 810 break; 811 } 812 case DADD: 813 case DSUB: 814 case DMUL: 815 case DDIV: 816 case DREM: 817 state.pop2(); 818 state.pop2(); 819 state.push(TypeTag.D); 820 break; 821 case RET: 822 break; 823 case WIDE: 824 // must be handled by the caller. 825 return; 826 case MONITORENTER: 827 case MONITOREXIT: 828 state.pop(); 829 break; 830 case VNEW: 831 throw new UnsupportedOperationException("VNEW not implemented"); 832 case NEW: 833 case VDEFAULT: 834 state.push(typeHelper.type((S) optValue)); 835 break; 836 case NEWARRAY: 837 state.pop(); 838 state.push(typeHelper.arrayOf(typeHelper.fromTag((TypeTag) optValue))); 839 break; 840 case ANEWARRAY: 841 state.pop(); 842 state.push(typeHelper.arrayOf(typeHelper.arrayOf(typeHelper.type((S)optValue)))); 843 break; 844 case VBOX: 845 case VUNBOX: 846 state.pop(); 847 state.push(typeHelper.type((S) optValue)); 848 break; 849 case MULTIANEWARRAY: 850 for (int i = 0; i < (byte) ((Object[]) optValue)[1]; i++) { 851 state.pop(); 852 } 853 state.push(typeHelper.type((S) ((Object[]) optValue)[0])); 854 break; 855 case INVOKEINTERFACE: 856 case INVOKEVIRTUAL: 857 case INVOKESPECIAL: 858 case INVOKESTATIC: 859 processInvoke(op, (T) optValue); 860 break; 861 case GETSTATIC: 862 state.push((T) optValue); 863 break; 864 case VGETFIELD: 865 case GETFIELD: 866 state.pop(); 867 state.push((T) optValue); 868 break; 869 case PUTSTATIC: { 870 TypeTag tag = typeHelper.tag((T) optValue); 871 if (tag.width == 1) { 872 state.pop(); 873 } else { 874 state.pop2(); 875 } 876 break; 877 } 878 case PUTFIELD: { 879 TypeTag tag = typeHelper.tag((T) optValue); 880 if (tag.width == 1) { 881 state.pop(); 882 } else { 883 state.pop2(); 884 } 885 state.pop(); 886 break; 887 } 888 case VWITHFIELD: { 889 TypeTag tag = typeHelper.tag((T) optValue); 890 if (tag.width == 1) { 891 state.pop(); 892 } else { 893 state.pop2(); 894 } 895 break; 896 } 897 case BIPUSH: 898 case SIPUSH: 899 state.push(TypeTag.I); 900 break; 901 case LDC: 902 case LDC_W: 903 case LDC2_W: 904 state.push(ldcType(optValue)); 905 break; 906 case IF_ACMPEQ: 907 case IF_ICMPEQ: 908 case IF_ACMPNE: 909 case IF_ICMPGE: 910 case IF_ICMPGT: 911 case IF_ICMPLE: 912 case IF_ICMPLT: 913 case IF_ICMPNE: 914 state.pop(); 915 state.pop(); 916 break; 917 case IF_NONNULL: 918 case IF_NULL: 919 case IFEQ: 920 case IFGE: 921 case IFGT: 922 case IFLE: 923 case IFLT: 924 case IFNE: 925 state.pop(); 926 break; 927 case INSTANCEOF: 928 state.pop(); 929 state.push(TypeTag.Z); 930 break; 931 case TYPED: 932 case CHECKCAST: 933 break; 934 935 default: 936 throw new UnsupportedOperationException("Unsupported opcode: " + op); 937 } 938 } 939 940 void processInvoke(Opcode opcode, T invokedType) { 941 Iterator<T> paramsIt = typeHelper.parameterTypes(invokedType); 942 while (paramsIt.hasNext()) { 943 T t = paramsIt.next(); 944 TypeTag tag = typeHelper.tag(t); 945 if (tag.width == 2) { 946 state.popInternal(); 947 state.popInternal(); 948 } else { 949 state.popInternal(); 950 } 951 } 952 if (opcode != Opcode.INVOKESTATIC) { 953 state.pop(); //receiver 954 } 955 T retType = typeHelper.returnType(invokedType); 956 TypeTag retTag = typeHelper.tag(retType); 957 if (retTag != TypeTag.V) 958 state.push(retType); 959 } 960 961 T ldcType(Object o) { 962 if (o instanceof Double) { 963 return typeHelper.fromTag(TypeTag.D); 964 } else if (o instanceof Long) { 965 return typeHelper.fromTag(TypeTag.J); 966 } else if (o instanceof Float) { 967 return typeHelper.fromTag(TypeTag.F); 968 } else if (o instanceof Integer) { 969 return typeHelper.fromTag(TypeTag.I); 970 } else if (o instanceof Class<?>) { 971 return typeHelper.type(typeHelper.symbolFrom("java/lang/Class")); 972 } else if (o instanceof String) { 973 return typeHelper.type(typeHelper.symbolFrom("java/lang/String")); 974 } else if (o instanceof MethodHandle) { 975 return typeHelper.type(typeHelper.symbolFrom("java/lang/invoke/MethodHandle")); 976 } else if (o instanceof MethodType) { 977 return typeHelper.type(typeHelper.symbolFrom("java/lang/invoke/MethodType")); 978 } else { 979 throw new IllegalStateException(); 980 } 981 } 982 983 public C load(int index) { 984 return load(typeHelper.tag(state.locals.get(index)), index); 985 } 986 987 public C store(int index) { 988 return store(typeHelper.tag(state.tosType()), index); 989 } 990 991 @Override 992 public C withLocalSize(int localsize) { 993 throw new IllegalStateException("Local size automatically computed"); 994 } 995 996 @Override 997 public C withStackSize(int stacksize) { 998 throw new IllegalStateException("Stack size automatically computed"); 999 } 1000 1001 public C withLocal(CharSequence name, T type) { 1002 int offset = currLocalOffset; 1003 TypeTag tag = typeHelper.tag(type); 1004 lvarOffsets.put(name, new LocalVarInfo(name, offset, depth, tag)); 1005 state.load(type, offset); 1006 currLocalOffset += tag.width; 1007 return thisBuilder(); 1008 } 1009 1010 public C load(CharSequence local) { 1011 return load(lvarOffsets.get(local).offset); 1012 } 1013 1014 public C store(CharSequence local) { 1015 return store(lvarOffsets.get(local).offset); 1016 } 1017 1018 @Override 1019 public C withTry(Consumer<? super C> tryBlock, Consumer<? super CatchBuilder> catchBlocks) { 1020 return super.withTry(c -> { 1021 withLocalScope(() -> { 1022 tryBlock.accept(c); 1023 }); 1024 }, catchBlocks); 1025 } 1026 1027 @Override 1028 protected CatchBuilder makeCatchBuilder(int start, int end) { 1029 return new TypedCatchBuilder(start, end); 1030 } 1031 1032 class TypedCatchBuilder extends CatchBuilder { 1033 1034 State initialState = state.dup(); 1035 1036 TypedCatchBuilder(int start, int end) { 1037 super(start, end); 1038 } 1039 1040 @Override 1041 protected void emitCatch(S exc, Consumer<? super C> catcher) { 1042 withLocalScope(() -> { 1043 state.push(typeHelper.type(exc)); 1044 emitStackMap(code.offset); 1045 super.emitCatch(exc, catcher); 1046 state = initialState; 1047 }); 1048 } 1049 1050 @Override 1051 protected void emitFinalizer() { 1052 withLocalScope(() -> { 1053 state.push(typeHelper.type(typeHelper.symbolFrom("java/lang/Throwable"))); 1054 emitStackMap(code.offset); 1055 super.emitFinalizer(); 1056 }); 1057 } 1058 } 1059 1060 protected void withLocalScope(Runnable runnable) { 1061 int prevDepth = depth; 1062 try { 1063 depth++; 1064 runnable.run(); 1065 } finally { 1066 Iterator<Entry<CharSequence, LocalVarInfo>> lvarIt = lvarOffsets.entrySet().iterator(); 1067 while (lvarIt.hasNext()) { 1068 LocalVarInfo lvi = lvarIt.next().getValue(); 1069 if (lvi.depth == depth) { 1070 int width = lvi.type.width; 1071 currLocalOffset -= width; 1072 lvarIt.remove(); 1073 } 1074 } 1075 depth = prevDepth; 1076 } 1077 } 1078 1079 @Override 1080 void addPendingJump(CharSequence label, int pc) { 1081 pendingJumps.add(new StatefulPendingJump(label, pc, state.dup())); 1082 } 1083 1084 @Override 1085 void resolveJumps(CharSequence label, int pc) { 1086 super.resolveJumps(label, pc); 1087 emitStackMap(pc); 1088 } 1089 1090 //TODO: optimize stackmap generation by avoiding intermediate classes 1091 protected void emitStackMap(int pc) { 1092 //stack map generation 1093 if (pc > lastStackMapPc) { 1094 writeStackMapFrame(pc); 1095 lastStackMapState = state.dup(); 1096 lastStackMapPc = pc; 1097 nstackmaps++; 1098 } 1099 } 1100 1101 @Override 1102 void build(GrowableByteBuffer buf) { 1103 if (stacksize == -1) { 1104 throw new IllegalStateException("Bad stack size"); 1105 } 1106 if (localsize == -1) { 1107 throw new IllegalStateException("Bad locals size"); 1108 } 1109 if (nstackmaps > 0) { 1110 GrowableByteBuffer stackmapsAttr = new GrowableByteBuffer(); 1111 stackmapsAttr.writeChar(nstackmaps); 1112 stackmapsAttr.writeBytes(stackmaps); 1113 withAttribute("StackMapTable", stackmapsAttr.bytes()); 1114 } 1115 super.build(buf); 1116 } 1117 1118 /** 1119 * Compare this frame with the previous frame and produce 1120 * an entry of compressed stack map frame. 1121 */ 1122 void writeStackMapFrame(int pc) { 1123 List<T> locals = state.locals; 1124 List<T> stack = state.stack; 1125 List<T> prev_locals = lastStackMapState.locals; 1126 int offset_delta = lastStackMapPc == -1 ? pc : pc - lastStackMapPc - 1; 1127 if (stack.size() == 1) { 1128 if (locals.size() == prev_locals.size() && prev_locals.equals(locals)) { 1129 sameLocals1StackItemFrame(offset_delta, stack.get(stack.size() - 1)); 1130 return; 1131 } 1132 } else if (stack.size() == 0) { 1133 int diff_length = prev_locals.size() - locals.size(); 1134 if (diff_length == 0) { 1135 sameFrame(offset_delta); 1136 return; 1137 } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) { 1138 appendFrame(offset_delta, prev_locals.size(), locals); 1139 return; 1140 } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) { 1141 chopFrame(offset_delta, diff_length); 1142 return; 1143 } 1144 } 1145 fullFrame(offset_delta, locals, stack); 1146 } 1147 }