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 case NEW: 829 case VDEFAULT: 830 state.push(typeHelper.type((S) optValue)); 831 break; 832 case NEWARRAY: 833 state.pop(); 834 state.push(typeHelper.arrayOf(typeHelper.fromTag((TypeTag) optValue))); 835 break; 836 case ANEWARRAY: 837 state.pop(); 838 state.push(typeHelper.arrayOf(typeHelper.arrayOf(typeHelper.type((S)optValue)))); 839 break; 840 case VBOX: 841 case VUNBOX: 842 state.pop(); 843 state.push(typeHelper.type((S) optValue)); 844 break; 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 processInvoke(op, (T) optValue); 856 break; 857 case GETSTATIC: 858 state.push((T) optValue); 859 break; 860 case VGETFIELD: 861 case GETFIELD: 862 state.pop(); 863 state.push((T) optValue); 864 break; 865 case PUTSTATIC: { 866 TypeTag tag = typeHelper.tag((T) optValue); 867 if (tag.width == 1) { 868 state.pop(); 869 } else { 870 state.pop2(); 871 } 872 break; 873 } 874 case PUTFIELD: { 875 TypeTag tag = typeHelper.tag((T) optValue); 876 if (tag.width == 1) { 877 state.pop(); 878 } else { 879 state.pop2(); 880 } 881 state.pop(); 882 break; 883 } 884 case VWITHFIELD: { 885 TypeTag tag = typeHelper.tag((T) optValue); 886 if (tag.width == 1) { 887 state.pop(); 888 } else { 889 state.pop2(); 890 } 891 break; 892 } 893 case BIPUSH: 894 case SIPUSH: 895 state.push(TypeTag.I); 896 break; 897 case LDC: 898 case LDC_W: 899 case LDC2_W: 900 state.push(ldcType(optValue)); 901 break; 902 case IF_ACMPEQ: 903 case IF_ICMPEQ: 904 case IF_ACMPNE: 905 case IF_ICMPGE: 906 case IF_ICMPGT: 907 case IF_ICMPLE: 908 case IF_ICMPLT: 909 case IF_ICMPNE: 910 state.pop(); 911 state.pop(); 912 break; 913 case IF_NONNULL: 914 case IF_NULL: 915 case IFEQ: 916 case IFGE: 917 case IFGT: 918 case IFLE: 919 case IFLT: 920 case IFNE: 921 state.pop(); 922 break; 923 case INSTANCEOF: 924 state.pop(); 925 state.push(TypeTag.Z); 926 break; 927 case TYPED: 928 case CHECKCAST: 929 break; 930 931 default: 932 throw new UnsupportedOperationException("Unsupported opcode: " + op); 933 } 934 } 935 936 void processInvoke(Opcode opcode, T invokedType) { 937 Iterator<T> paramsIt = typeHelper.parameterTypes(invokedType); 938 while (paramsIt.hasNext()) { 939 T t = paramsIt.next(); 940 TypeTag tag = typeHelper.tag(t); 941 if (tag.width == 2) { 942 state.popInternal(); 943 state.popInternal(); 944 } else { 945 state.popInternal(); 946 } 947 } 948 if (opcode != Opcode.INVOKESTATIC) { 949 state.pop(); //receiver 950 } 951 T retType = typeHelper.returnType(invokedType); 952 TypeTag retTag = typeHelper.tag(retType); 953 if (retTag != TypeTag.V) 954 state.push(retType); 955 } 956 957 T ldcType(Object o) { 958 if (o instanceof Double) { 959 return typeHelper.fromTag(TypeTag.D); 960 } else if (o instanceof Long) { 961 return typeHelper.fromTag(TypeTag.J); 962 } else if (o instanceof Float) { 963 return typeHelper.fromTag(TypeTag.F); 964 } else if (o instanceof Integer) { 965 return typeHelper.fromTag(TypeTag.I); 966 } else if (o instanceof Class<?>) { 967 return typeHelper.type(typeHelper.symbolFrom("java/lang/Class")); 968 } else if (o instanceof String) { 969 return typeHelper.type(typeHelper.symbolFrom("java/lang/String")); 970 } else if (o instanceof MethodHandle) { 971 return typeHelper.type(typeHelper.symbolFrom("java/lang/invoke/MethodHandle")); 972 } else if (o instanceof MethodType) { 973 return typeHelper.type(typeHelper.symbolFrom("java/lang/invoke/MethodType")); 974 } else { 975 throw new IllegalStateException(); 976 } 977 } 978 979 public C load(int index) { 980 return load(typeHelper.tag(state.locals.get(index)), index); 981 } 982 983 public C store(int index) { 984 return store(typeHelper.tag(state.tosType()), index); 985 } 986 987 @Override 988 public C withLocalSize(int localsize) { 989 throw new IllegalStateException("Local size automatically computed"); 990 } 991 992 @Override 993 public C withStackSize(int stacksize) { 994 throw new IllegalStateException("Stack size automatically computed"); 995 } 996 997 public C withLocal(CharSequence name, T type) { 998 int offset = currLocalOffset; 999 TypeTag tag = typeHelper.tag(type); 1000 lvarOffsets.put(name, new LocalVarInfo(name, offset, depth, tag)); 1001 state.load(type, offset); 1002 currLocalOffset += tag.width; 1003 return thisBuilder(); 1004 } 1005 1006 public C load(CharSequence local) { 1007 return load(lvarOffsets.get(local).offset); 1008 } 1009 1010 public C store(CharSequence local) { 1011 return store(lvarOffsets.get(local).offset); 1012 } 1013 1014 @Override 1015 public C withTry(Consumer<? super C> tryBlock, Consumer<? super CatchBuilder> catchBlocks) { 1016 return super.withTry(c -> { 1017 withLocalScope(() -> { 1018 tryBlock.accept(c); 1019 }); 1020 }, catchBlocks); 1021 } 1022 1023 @Override 1024 protected CatchBuilder makeCatchBuilder(int start, int end) { 1025 return new TypedCatchBuilder(start, end); 1026 } 1027 1028 class TypedCatchBuilder extends CatchBuilder { 1029 1030 State initialState = state.dup(); 1031 1032 TypedCatchBuilder(int start, int end) { 1033 super(start, end); 1034 } 1035 1036 @Override 1037 protected void emitCatch(S exc, Consumer<? super C> catcher) { 1038 withLocalScope(() -> { 1039 state.push(typeHelper.type(exc)); 1040 emitStackMap(code.offset); 1041 super.emitCatch(exc, catcher); 1042 state = initialState; 1043 }); 1044 } 1045 1046 @Override 1047 protected void emitFinalizer() { 1048 withLocalScope(() -> { 1049 state.push(typeHelper.type(typeHelper.symbolFrom("java/lang/Throwable"))); 1050 emitStackMap(code.offset); 1051 super.emitFinalizer(); 1052 }); 1053 } 1054 } 1055 1056 protected void withLocalScope(Runnable runnable) { 1057 int prevDepth = depth; 1058 try { 1059 depth++; 1060 runnable.run(); 1061 } finally { 1062 Iterator<Entry<CharSequence, LocalVarInfo>> lvarIt = lvarOffsets.entrySet().iterator(); 1063 while (lvarIt.hasNext()) { 1064 LocalVarInfo lvi = lvarIt.next().getValue(); 1065 if (lvi.depth == depth) { 1066 int width = lvi.type.width; 1067 currLocalOffset -= width; 1068 lvarIt.remove(); 1069 } 1070 } 1071 depth = prevDepth; 1072 } 1073 } 1074 1075 @Override 1076 void addPendingJump(CharSequence label, int pc) { 1077 pendingJumps.add(new StatefulPendingJump(label, pc, state.dup())); 1078 } 1079 1080 @Override 1081 void resolveJumps(CharSequence label, int pc) { 1082 super.resolveJumps(label, pc); 1083 emitStackMap(pc); 1084 } 1085 1086 //TODO: optimize stackmap generation by avoiding intermediate classes 1087 protected void emitStackMap(int pc) { 1088 //stack map generation 1089 if (pc > lastStackMapPc) { 1090 writeStackMapFrame(pc); 1091 lastStackMapState = state.dup(); 1092 lastStackMapPc = pc; 1093 nstackmaps++; 1094 } 1095 } 1096 1097 @Override 1098 void build(GrowableByteBuffer buf) { 1099 if (stacksize == -1) { 1100 throw new IllegalStateException("Bad stack size"); 1101 } 1102 if (localsize == -1) { 1103 throw new IllegalStateException("Bad locals size"); 1104 } 1105 if (nstackmaps > 0) { 1106 GrowableByteBuffer stackmapsAttr = new GrowableByteBuffer(); 1107 stackmapsAttr.writeChar(nstackmaps); 1108 stackmapsAttr.writeBytes(stackmaps); 1109 withAttribute("StackMapTable", stackmapsAttr.bytes()); 1110 } 1111 super.build(buf); 1112 } 1113 1114 /** 1115 * Compare this frame with the previous frame and produce 1116 * an entry of compressed stack map frame. 1117 */ 1118 void writeStackMapFrame(int pc) { 1119 List<T> locals = state.locals; 1120 List<T> stack = state.stack; 1121 List<T> prev_locals = lastStackMapState.locals; 1122 int offset_delta = lastStackMapPc == -1 ? pc : pc - lastStackMapPc - 1; 1123 if (stack.size() == 1) { 1124 if (locals.size() == prev_locals.size() && prev_locals.equals(locals)) { 1125 sameLocals1StackItemFrame(offset_delta, stack.get(stack.size() - 1)); 1126 return; 1127 } 1128 } else if (stack.size() == 0) { 1129 int diff_length = prev_locals.size() - locals.size(); 1130 if (diff_length == 0) { 1131 sameFrame(offset_delta); 1132 return; 1133 } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) { 1134 appendFrame(offset_delta, prev_locals.size(), locals); 1135 return; 1136 } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) { 1137 chopFrame(offset_delta, diff_length); 1138 return; 1139 } 1140 } 1141 fullFrame(offset_delta, locals, stack); 1142 } 1143 }