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