1 /* 2 * Copyright (c) 2017, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.experimental.bytecode; 25 26 import java.util.ArrayList; 27 import java.util.HashMap; 28 import java.util.Iterator; 29 import java.util.List; 30 import java.util.Map; 31 import java.util.Map.Entry; 32 import java.util.Vector; 33 import java.util.function.Consumer; 34 import java.util.function.Supplier; 35 import java.util.function.ToIntFunction; 36 37 public class TypedCodeBuilder<S, T, E, C extends TypedCodeBuilder<S, T, E, C>> extends MacroCodeBuilder<S, T, E, C> { 38 39 State lastStackMapState; 40 int lastStackMapPc = -1; 41 Map<CharSequence, LocalVarInfo> lvarOffsets = new HashMap<>(); 42 protected State state; 43 int depth = 0; 44 int currLocalOffset = 0; 45 46 class StatefulPendingJump extends PendingJump { 47 48 State state; 49 50 StatefulPendingJump(CharSequence label, int pc, State state) { 51 super(label, pc); 52 this.state = state; 53 } 54 55 @Override 56 boolean resolve(CharSequence label, int pc) { 57 boolean b = super.resolve(label, pc); 58 if (b) { 59 TypedCodeBuilder.this.state = TypedCodeBuilder.this.state.merge(state); 60 } 61 return b; 62 } 63 } 64 65 class LocalVarInfo { 66 CharSequence name; 67 int offset; 68 int depth; 69 TypeTag type; 70 71 LocalVarInfo(CharSequence name, int offset, int depth, TypeTag type) { 72 this.name = name; 73 this.offset = offset; 74 this.depth = depth; 75 this.type = type; 76 } 77 } 78 79 public TypedCodeBuilder(MethodBuilder<S, T, E> methodBuilder) { 80 super(methodBuilder); 81 T t = methodBuilder.desc; 82 state = new State(); 83 if ((methodBuilder.flags & Flag.ACC_STATIC.flag) == 0) { 84 T clazz = typeHelper.type(methodBuilder.thisClass); 85 state.load(clazz, currLocalOffset++); //TODO: uninit?? 86 } 87 Iterator<T> paramsIt = typeHelper.parameterTypes(t); 88 while (paramsIt.hasNext()) { 89 T p = paramsIt.next(); 90 state.load(p, currLocalOffset); 91 currLocalOffset += typeHelper.tag(p).width; 92 } 93 lastStackMapState = state.dup(); 94 stacksize = state.stack.size(); 95 localsize = state.locals.size(); 96 } 97 98 @Override 99 protected C emitOp(Opcode opcode, Object optPoolValue) { 100 updateState(opcode, optPoolValue); 101 return super.emitOp(opcode, optPoolValue); 102 } 103 104 @Override 105 protected SwitchBuilder makeSwitchBuilder() { 106 return new TypedSwitchBuilder(); 107 } 108 109 class TypedSwitchBuilder extends SwitchBuilder { 110 111 @Override 112 public SwitchBuilder withCase(int value, Consumer<? super C> case_, boolean fallthrough) { 113 super.withCase(value, c -> { 114 withLocalScope(() -> { 115 State prevState = state; 116 state = prevState.dup(); 117 emitStackMap(c.offset()); 118 case_.accept(c); 119 state = prevState; 120 }); 121 }, fallthrough); 122 return this; 123 } 124 125 @Override 126 public SwitchBuilder withDefault(Consumer<? super C> defaultCase) { 127 super.withDefault(c -> { 128 withLocalScope(() -> { 129 State prevState = state; 130 state = prevState.dup(); 131 emitStackMap(c.offset()); 132 defaultCase.accept(c); 133 state = prevState; 134 }); 135 }); 136 return this; 137 } 138 } 139 140 @Override 141 public StatefulTypedBuilder typed(TypeTag tag) { 142 return super.typed(tag, StatefulTypedBuilder::new); 143 } 144 145 public class StatefulTypedBuilder extends LabelledTypedBuilder { 146 147 TypeTag tag; 148 149 StatefulTypedBuilder(TypeTag tag) { 150 this.tag = tag; 151 } 152 153 @Override 154 public C astore_0() { 155 return storeAndUpdate(super::astore_0); 156 } 157 158 @Override 159 public C astore_1() { 160 return storeAndUpdate(super::astore_1); 161 } 162 163 @Override 164 public C astore_2() { 165 return storeAndUpdate(super::astore_2); 166 } 167 168 @Override 169 public C astore_3() { 170 return storeAndUpdate(super::astore_3); 171 } 172 173 @Override 174 public C astore(int n) { 175 return storeAndUpdate(() -> super.astore(n)); 176 } 177 178 @Override 179 public C aastore() { 180 return storeAndUpdate(super::aastore); 181 } 182 183 @Override 184 public C areturn() { 185 state.pop(tag); 186 state.push(typeHelper.nullType()); 187 return super.areturn(); 188 } 189 190 @Override 191 public C anewarray(S s) { 192 super.anewarray(s); 193 state.pop(); 194 state.push(typeHelper.arrayOf(typeHelper.type(s))); 195 return thisBuilder(); 196 } 197 198 @Override 199 public C aconst_null() { 200 super.aconst_null(); 201 state.pop(); 202 state.push(tag); 203 return thisBuilder(); 204 } 205 206 public C if_acmpeq(CharSequence label) { 207 return jumpAndUpdate(() -> super.if_acmpeq(label)); 208 } 209 210 public C if_acmpne(CharSequence label) { 211 return jumpAndUpdate(() -> super.if_acmpne(label)); 212 } 213 214 private C storeAndUpdate(Supplier<C> op) { 215 state.pop(tag); 216 state.push(typeHelper.nullType()); 217 return op.get(); 218 } 219 220 private C jumpAndUpdate(Supplier<C> op) { 221 state.pop(tag); 222 state.pop(tag); 223 state.push(typeHelper.nullType()); 224 state.push(typeHelper.nullType()); 225 return op.get(); 226 } 227 } 228 229 public class State { 230 public final ArrayList<T> stack; 231 public final Vector<T> locals; 232 boolean alive; 233 234 State(ArrayList<T> stack, Vector<T> locals) { 235 this.stack = stack; 236 this.locals = locals; 237 } 238 239 State() { 240 this(new ArrayList<>(), new Vector<>()); 241 } 242 243 void push(TypeTag tag) { 244 switch (tag) { 245 case A: 246 case V: 247 throw new IllegalStateException("Bad type tag"); 248 default: 249 push(typeHelper.fromTag(tag)); 250 } 251 } 252 253 void push(T t) { 254 stack.add(t); 255 if (width(t) == 2) { 256 stack.add(null); 257 } 258 if (stack.size() > stacksize) { 259 stacksize = stack.size(); 260 } 261 } 262 263 T peek() { 264 return stack.get(stack.size() - 1); 265 } 266 267 T tosType() { 268 T tos = peek(); 269 if (tos == null) { 270 //double slot 271 tos = stack.get(stack.size() - 2); 272 } 273 return tos; 274 } 275 276 T popInternal() { 277 return stack.remove(stack.size() - 1); 278 } 279 280 @SuppressWarnings("unchecked") 281 T pop() { 282 if (stack.size() == 0 || peek() == null) throw new IllegalStateException(); 283 return popInternal(); 284 } 285 286 T pop2() { 287 T o = stack.get(stack.size() - 2); 288 TypeTag t = typeHelper.tag(o); 289 if (t.width != 2) throw new IllegalStateException(); 290 popInternal(); 291 popInternal(); 292 return o; 293 } 294 295 T pop(TypeTag t) { 296 return (t.width() == 2) ? 297 pop2() : pop(); 298 } 299 300 void load(TypeTag tag, int index) { 301 if (tag == TypeTag.A) throw new IllegalStateException("Bad type tag"); 302 load(typeHelper.fromTag(tag), index); 303 } 304 305 void load(T t, int index) { 306 ensureDefined(index); 307 locals.set(index, t); 308 if (width(t) == 2) { 309 locals.add(null); 310 } 311 if (locals.size() > localsize) { 312 localsize = locals.size(); 313 } 314 } 315 316 void ensureDefined(int index) { 317 if (index >= locals.size()) { 318 locals.setSize(index + 1); 319 } 320 } 321 322 State dup() { 323 State newState = new State(new ArrayList<>(stack), new Vector<>(locals)); 324 return newState; 325 } 326 327 State merge(State that) { 328 if (!alive) { return that; } 329 if (that.stack.size() != stack.size()) { 330 throw new IllegalStateException("Bad stack size at merge point"); 331 } 332 for (int i = 0; i < stack.size(); i++) { 333 T t1 = stack.get(i); 334 T t2 = that.stack.get(i); 335 stack.set(i, merge(t1, t2, "Bad stack type at merge point")); 336 } 337 int nlocals = locals.size() > that.locals.size() ? that.locals.size() : locals.size(); 338 for (int i = 0; i < nlocals; i++) { 339 T t1 = locals.get(i); 340 T t2 = that.locals.get(i); 341 locals.set(i, merge(t1, t2, "Bad local type at merge point")); 342 } 343 if (locals.size() > nlocals) { 344 for (int i = nlocals; i < locals.size(); i++) { 345 locals.remove(i); 346 } 347 } 348 return this; 349 } 350 351 T merge(T t1, T t2, String msg) { 352 if (t1 == null && t2 == null) { 353 return t1; 354 } 355 T res; 356 TypeTag tag1 = typeHelper.tag(t1); 357 TypeTag tag2 = typeHelper.tag(t2); 358 if (tag1 != TypeTag.A && tag2 != TypeTag.A && 359 tag1 != TypeTag.Q && tag2 != TypeTag.Q) { 360 res = typeHelper.fromTag(TypeTag.commonSupertype(tag1, tag2)); 361 } else if (t1 == typeHelper.nullType()) { 362 res = t2; 363 } else if (t2 == typeHelper.nullType()) { 364 res = t1; 365 } else { 366 res = typeHelper.commonSupertype(t1, t2); 367 } 368 if (res == null) { 369 throw new IllegalStateException(msg); 370 } 371 return res; 372 } 373 374 @Override 375 public String toString() { 376 return String.format("[locals = %s, stack = %s]", locals, stack); 377 } 378 } 379 380 int width(T o) { 381 return o == typeHelper.nullType() ? 382 TypeTag.A.width() : 383 typeHelper.tag(o).width; 384 } 385 386 @SuppressWarnings("unchecked") 387 public void updateState(Opcode op, Object optValue) { 388 switch (op) { 389 case VALOAD: 390 case AALOAD: 391 state.pop(); 392 state.push(typeHelper.elemtype(state.pop())); 393 break; 394 case GOTO_: 395 state.alive = false; 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 case NEW: 828 state.push(typeHelper.type((S) optValue)); 829 break; 830 case NEWARRAY: 831 state.pop(); 832 state.push(typeHelper.arrayOf(typeHelper.fromTag((TypeTag) optValue))); 833 break; 834 case ANEWARRAY: 835 state.pop(); 836 state.push(typeHelper.arrayOf(typeHelper.arrayOf(typeHelper.type((S)optValue)))); 837 break; 838 case VNEWARRAY: 839 case VBOX: 840 case VUNBOX: 841 state.pop(); 842 state.push(typeHelper.type((S) optValue)); 843 break; 844 case MULTIVNEWARRAY: 845 case MULTIANEWARRAY: 846 for (int i = 0; i < (byte) ((Object[]) optValue)[1]; i++) { 847 state.pop(); 848 } 849 state.push(typeHelper.type((S) ((Object[]) optValue)[0])); 850 break; 851 case INVOKEINTERFACE: 852 case INVOKEVIRTUAL: 853 case INVOKESPECIAL: 854 case INVOKESTATIC: 855 case INVOKEDYNAMIC: 856 processInvoke(op, (T) optValue); 857 break; 858 case GETSTATIC: 859 state.push((T) optValue); 860 break; 861 case VGETFIELD: 862 case GETFIELD: 863 state.pop(); 864 state.push((T) optValue); 865 break; 866 case PUTSTATIC: { 867 TypeTag tag = typeHelper.tag((T) optValue); 868 if (tag.width == 1) { 869 state.pop(); 870 } else { 871 state.pop2(); 872 } 873 break; 874 } 875 case PUTFIELD: { 876 TypeTag tag = typeHelper.tag((T) optValue); 877 if (tag.width == 1) { 878 state.pop(); 879 } else { 880 state.pop2(); 881 } 882 state.pop(); 883 break; 884 } 885 case BIPUSH: 886 case SIPUSH: 887 state.push(TypeTag.I); 888 break; 889 case LDC: 890 case LDC_W: 891 case LDC2_W: 892 state.push((T)optValue); 893 break; 894 case IF_ACMPEQ: 895 case IF_ICMPEQ: 896 case IF_ACMPNE: 897 case IF_ICMPGE: 898 case IF_ICMPGT: 899 case IF_ICMPLE: 900 case IF_ICMPLT: 901 case IF_ICMPNE: 902 state.pop(); 903 state.pop(); 904 break; 905 case IF_NONNULL: 906 case IF_NULL: 907 case IFEQ: 908 case IFGE: 909 case IFGT: 910 case IFLE: 911 case IFLT: 912 case IFNE: 913 state.pop(); 914 break; 915 case INSTANCEOF: 916 state.pop(); 917 state.push(TypeTag.Z); 918 break; 919 case TYPED: 920 case CHECKCAST: 921 break; 922 923 default: 924 throw new UnsupportedOperationException("Unsupported opcode: " + op); 925 } 926 } 927 928 void processInvoke(Opcode opcode, T invokedType) { 929 Iterator<T> paramsIt = typeHelper.parameterTypes(invokedType); 930 while (paramsIt.hasNext()) { 931 T t = paramsIt.next(); 932 TypeTag tag = typeHelper.tag(t); 933 if (tag.width == 2) { 934 state.popInternal(); 935 state.popInternal(); 936 } else { 937 state.popInternal(); 938 } 939 } 940 if (opcode != Opcode.INVOKESTATIC && opcode != Opcode.INVOKEDYNAMIC) { 941 state.pop(); //receiver 942 } 943 T retType = typeHelper.returnType(invokedType); 944 TypeTag retTag = typeHelper.tag(retType); 945 if (retTag != TypeTag.V) 946 state.push(retType); 947 } 948 949 @Override 950 protected C ldc(ToIntFunction<PoolHelper<S, T, E>> indexFunc, boolean fat) { 951 LdcPoolHelper ldcPoolHelper = new LdcPoolHelper(); 952 int index = indexFunc.applyAsInt(ldcPoolHelper); 953 fat = typeHelper.tag(ldcPoolHelper.type).width() == 2; 954 return super.ldc(index, ldcPoolHelper.type, fat); 955 } 956 //where 957 class LdcPoolHelper implements PoolHelper<S, T, E> { 958 959 T type; 960 961 @Override 962 public int putClass(S symbol) { 963 type = typeHelper.type(symbol); 964 return poolHelper.putClass(symbol); 965 } 966 967 @Override 968 public int putInt(int i) { 969 type = typeHelper.fromTag(TypeTag.I); 970 return poolHelper.putInt(i); 971 } 972 973 @Override 974 public int putFloat(float f) { 975 type = typeHelper.fromTag(TypeTag.F); 976 return poolHelper.putFloat(f); 977 } 978 979 @Override 980 public int putLong(long l) { 981 type = typeHelper.fromTag(TypeTag.J); 982 return poolHelper.putLong(l); 983 } 984 985 @Override 986 public int putDouble(double d) { 987 type = typeHelper.fromTag(TypeTag.D); 988 return poolHelper.putDouble(d); 989 } 990 991 @Override 992 public int putString(String s) { 993 type = typeHelper.type(typeHelper.symbolFrom("java/lang/String")); 994 return poolHelper.putString(s); 995 } 996 997 @Override 998 public int putDynamicConstant(CharSequence constName, T constType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, E>> staticArgs) { 999 type = constType; 1000 return poolHelper.putDynamicConstant(constName, constType, bsmClass, bsmName, bsmType, staticArgs); 1001 } 1002 1003 @Override 1004 public int putFieldRef(S owner, CharSequence name, T type) { 1005 throw new IllegalStateException(); 1006 } 1007 1008 @Override 1009 public int putMethodRef(S owner, CharSequence name, T type, boolean isInterface) { 1010 throw new IllegalStateException(); 1011 } 1012 1013 @Override 1014 public int putUtf8(CharSequence s) { 1015 throw new IllegalStateException(); 1016 } 1017 1018 @Override 1019 public int putType(T t) { 1020 throw new IllegalStateException(); 1021 } 1022 1023 @Override 1024 public int putMethodType(T t) { 1025 type = typeHelper.type(typeHelper.symbolFrom("java/lang/invoke/MethodType")); 1026 return poolHelper.putMethodType(t); 1027 } 1028 1029 @Override 1030 public int putHandle(int refKind, S owner, CharSequence name, T t) { 1031 type = typeHelper.type(typeHelper.symbolFrom("java/lang/invoke/MethodHandle")); 1032 return poolHelper.putHandle(refKind, owner, name, t); 1033 } 1034 1035 @Override 1036 public int putHandle(int refKind, S owner, CharSequence name, T t, boolean isInterface) { 1037 type = typeHelper.type(typeHelper.symbolFrom("java/lang/invoke/MethodHandle")); 1038 return poolHelper.putHandle(refKind, owner, name, t, isInterface); 1039 } 1040 1041 @Override 1042 public int putInvokeDynamic(CharSequence invokedName, T invokedType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, E>> staticArgs) { 1043 throw new IllegalStateException(); 1044 } 1045 1046 @Override 1047 public int size() { 1048 throw new IllegalStateException(); 1049 } 1050 1051 @Override 1052 public E entries() { 1053 throw new IllegalStateException(); 1054 } 1055 } 1056 1057 public C load(int index) { 1058 return load(typeHelper.tag(state.locals.get(index)), index); 1059 } 1060 1061 public C store(int index) { 1062 return store(typeHelper.tag(state.tosType()), index); 1063 } 1064 1065 @Override 1066 public C withLocalSize(int localsize) { 1067 throw new IllegalStateException("Local size automatically computed"); 1068 } 1069 1070 @Override 1071 public C withStackSize(int stacksize) { 1072 throw new IllegalStateException("Stack size automatically computed"); 1073 } 1074 1075 public C withLocal(CharSequence name, T type) { 1076 int offset = currLocalOffset; 1077 TypeTag tag = typeHelper.tag(type); 1078 lvarOffsets.put(name, new LocalVarInfo(name, offset, depth, tag)); 1079 state.load(type, offset); 1080 currLocalOffset += tag.width; 1081 return thisBuilder(); 1082 } 1083 1084 public C load(CharSequence local) { 1085 return load(lvarOffsets.get(local).offset); 1086 } 1087 1088 public C store(CharSequence local) { 1089 return store(lvarOffsets.get(local).offset); 1090 } 1091 1092 @Override 1093 public C withTry(Consumer<? super C> tryBlock, Consumer<? super CatchBuilder> catchBlocks) { 1094 return super.withTry(c -> { 1095 withLocalScope(() -> { 1096 tryBlock.accept(c); 1097 }); 1098 }, catchBlocks); 1099 } 1100 1101 @Override 1102 protected CatchBuilder makeCatchBuilder(int start, int end) { 1103 return new TypedCatchBuilder(start, end); 1104 } 1105 1106 class TypedCatchBuilder extends CatchBuilder { 1107 1108 State initialState = state.dup(); 1109 1110 TypedCatchBuilder(int start, int end) { 1111 super(start, end); 1112 } 1113 1114 @Override 1115 protected void emitCatch(S exc, Consumer<? super C> catcher) { 1116 withLocalScope(() -> { 1117 state.push(typeHelper.type(exc)); 1118 emitStackMap(code.offset); 1119 super.emitCatch(exc, catcher); 1120 state = initialState; 1121 }); 1122 } 1123 1124 @Override 1125 protected void emitFinalizer() { 1126 withLocalScope(() -> { 1127 state.push(typeHelper.type(typeHelper.symbolFrom("java/lang/Throwable"))); 1128 emitStackMap(code.offset); 1129 super.emitFinalizer(); 1130 }); 1131 } 1132 } 1133 1134 protected void withLocalScope(Runnable runnable) { 1135 int prevDepth = depth; 1136 try { 1137 depth++; 1138 runnable.run(); 1139 } finally { 1140 Iterator<Entry<CharSequence, LocalVarInfo>> lvarIt = lvarOffsets.entrySet().iterator(); 1141 while (lvarIt.hasNext()) { 1142 LocalVarInfo lvi = lvarIt.next().getValue(); 1143 if (lvi.depth == depth) { 1144 int width = lvi.type.width; 1145 currLocalOffset -= width; 1146 lvarIt.remove(); 1147 } 1148 } 1149 depth = prevDepth; 1150 } 1151 } 1152 1153 @Override 1154 void addPendingJump(CharSequence label, int pc) { 1155 pendingJumps.add(new StatefulPendingJump(label, pc, state.dup())); 1156 } 1157 1158 @Override 1159 void resolveJumps(CharSequence label, int pc) { 1160 super.resolveJumps(label, pc); 1161 emitStackMap(pc); 1162 } 1163 1164 //TODO: optimize stackmap generation by avoiding intermediate classes 1165 protected void emitStackMap(int pc) { 1166 //stack map generation 1167 if (pc > lastStackMapPc) { 1168 writeStackMapFrame(pc); 1169 lastStackMapState = state.dup(); 1170 lastStackMapPc = pc; 1171 nstackmaps++; 1172 } 1173 } 1174 1175 @Override 1176 void build(GrowableByteBuffer buf) { 1177 if (stacksize == -1) { 1178 throw new IllegalStateException("Bad stack size"); 1179 } 1180 if (localsize == -1) { 1181 throw new IllegalStateException("Bad locals size"); 1182 } 1183 if (nstackmaps > 0) { 1184 GrowableByteBuffer stackmapsAttr = new GrowableByteBuffer(); 1185 stackmapsAttr.writeChar(nstackmaps); 1186 stackmapsAttr.writeBytes(stackmaps); 1187 withAttribute("StackMapTable", stackmapsAttr.bytes()); 1188 } 1189 super.build(buf); 1190 } 1191 1192 /** 1193 * Compare this frame with the previous frame and produce 1194 * an entry of compressed stack map frame. 1195 */ 1196 void writeStackMapFrame(int pc) { 1197 List<T> locals = state.locals; 1198 List<T> stack = state.stack; 1199 List<T> prev_locals = lastStackMapState.locals; 1200 int offset_delta = lastStackMapPc == -1 ? pc : pc - lastStackMapPc - 1; 1201 if (stack.size() == 1) { 1202 if (locals.size() == prev_locals.size() && prev_locals.equals(locals)) { 1203 sameLocals1StackItemFrame(offset_delta, stack.get(stack.size() - 1)); 1204 return; 1205 } 1206 } else if (stack.size() == 0) { 1207 int diff_length = prev_locals.size() - locals.size(); 1208 if (diff_length == 0) { 1209 sameFrame(offset_delta); 1210 return; 1211 } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) { 1212 appendFrame(offset_delta, prev_locals.size(), locals); 1213 return; 1214 } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) { 1215 chopFrame(offset_delta, diff_length); 1216 return; 1217 } 1218 } 1219 fullFrame(offset_delta, locals, stack); 1220 } 1221 } --- EOF ---