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