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 jdk.experimental.bytecode.PoolHelper.StaticArgListBuilder;
  27 
  28 import java.lang.invoke.MethodHandle;
  29 import java.util.Iterator;
  30 import java.util.List;
  31 import java.util.function.BiFunction;
  32 import java.util.function.Consumer;
  33 import java.util.function.Function;
  34 import java.util.function.ToIntFunction;
  35 
  36 /**
  37  * Builder for class file code attributes. A code attribute is defined:
  38  * <pre>
  39  * {@code
  40  * Code_attribute {
  41  *    u2 attribute_name_index;
  42  *    u4 attribute_length;
  43  *    u2 max_stack;
  44  *    u2 max_locals;
  45  *    u4 code_length;
  46  *    u1 code[code_length];
  47  *    u2 exception_table_length;
  48  *    {   u2 start_pc;
  49  *        u2 end_pc;
  50  *        u2 handler_pc;
  51  *        u2 catch_type;
  52  *    } exception_table[exception_table_length];
  53  *    u2 attributes_count;
  54  *    attribute_info attributes[attributes_count];
  55  * } }
  56  * </pre>
  57  *
  58  * @param <S> the type of symbol representation
  59  * @param <T> the type of type descriptors representation
  60  * @param <E> the type of pool entries
  61  * @param <C> the type of this code builder
  62  */
  63 public class CodeBuilder<S, T, E, C extends CodeBuilder<S, T, E, C>> extends AttributeBuilder<S, T, E, C> {
  64 
  65     protected GrowableByteBuffer code = new GrowableByteBuffer();
  66     GrowableByteBuffer catchers = new GrowableByteBuffer();
  67     GrowableByteBuffer stackmaps = new GrowableByteBuffer();
  68     MethodBuilder<S, T, E> methodBuilder;
  69     int ncatchers;
  70     int stacksize = -1;
  71     int localsize = -1;
  72     int nstackmaps = 0;
  73 
  74     public enum JumpMode {
  75         NARROW,
  76         WIDE;
  77     }
  78 
  79     CodeBuilder(MethodBuilder<S, T, E> methodBuilder) {
  80         super(methodBuilder.poolHelper, methodBuilder.typeHelper);
  81         this.methodBuilder = methodBuilder;
  82     }
  83 
  84     public C getstatic(S owner, CharSequence name, T type) {
  85         emitOp(Opcode.GETSTATIC, type);
  86         code.writeChar(poolHelper.putFieldRef(owner, name, type));
  87         return thisBuilder();
  88     }
  89 
  90     public C putstatic(S owner, CharSequence name, T type) {
  91         emitOp(Opcode.PUTSTATIC, type);
  92         code.writeChar(poolHelper.putFieldRef(owner, name, type));
  93         return thisBuilder();
  94     }
  95 
  96     public C getfield(S owner, CharSequence name, T type) {
  97         emitOp(Opcode.GETFIELD, type);
  98         code.writeChar(poolHelper.putFieldRef(owner, name, type));
  99         return thisBuilder();
 100     }
 101 
 102     public C putfield(S owner, CharSequence name, T type) {
 103         emitOp(Opcode.PUTFIELD, type);
 104         code.writeChar(poolHelper.putFieldRef(owner, name, type));
 105         return thisBuilder();
 106     }
 107 
 108     public C withfield(S owner, CharSequence name, T type) {
 109         emitOp(Opcode.WITHFIELD, type);
 110         code.writeChar(poolHelper.putFieldRef(owner, name, type));
 111         return thisBuilder();
 112     }
 113 
 114     public C invokevirtual(S owner, CharSequence name, T type, boolean isInterface) {
 115         emitOp(Opcode.INVOKEVIRTUAL, type);
 116         code.writeChar(poolHelper.putMethodRef(owner, name, type, isInterface));
 117         return thisBuilder();
 118     }
 119 
 120     public C invokespecial(S owner, CharSequence name, T type, boolean isInterface) {
 121         emitOp(Opcode.INVOKESPECIAL, type);
 122         code.writeChar(poolHelper.putMethodRef(owner, name, type, isInterface));
 123         return thisBuilder();
 124     }
 125 
 126     public C invokestatic(S owner, CharSequence name, T type, boolean isInterface) {
 127         emitOp(Opcode.INVOKESTATIC, type);
 128         code.writeChar(poolHelper.putMethodRef(owner, name, type, isInterface));
 129         return thisBuilder();
 130     }
 131 
 132     public C invokeinterface(S owner, CharSequence name, T type) {
 133         emitOp(Opcode.INVOKEINTERFACE, type);
 134         code.writeChar(poolHelper.putMethodRef(owner, name, type, true));
 135         int nargs = 1;
 136         Iterator<T> it = typeHelper.parameterTypes(type);
 137         while (it.hasNext()) {
 138             nargs += typeHelper.tag(it.next()).width;
 139         }
 140         code.writeByte(nargs);
 141         code.writeByte(0);
 142         return thisBuilder();
 143     }
 144 
 145     public C invokedynamic(CharSequence invokedName, T invokedType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, E>> staticArgs) {
 146         emitOp(Opcode.INVOKEDYNAMIC, invokedType);
 147         code.writeChar(poolHelper.putInvokeDynamic(invokedName, invokedType, bsmClass, bsmName, bsmType, staticArgs));
 148         code.writeChar(0); //padding
 149         return thisBuilder();
 150     }
 151 
 152     public C new_(S clazz) {
 153         emitOp(Opcode.NEW, clazz);
 154         code.writeChar(poolHelper.putClass(clazz));
 155         return thisBuilder();
 156     }
 157 
 158     public C aconst_init(S clazz) {
 159         emitOp(Opcode.ACONST_INIT, clazz);
 160         code.writeChar(poolHelper.putClass(clazz));
 161         return thisBuilder();
 162     }
 163 
 164     public C newarray(TypeTag tag) {
 165         emitOp(Opcode.NEWARRAY, tag);
 166         int newarraycode = tag.newarraycode;
 167         if (newarraycode == -1) {
 168             throw new IllegalStateException("Bad tag " + tag);
 169         }
 170         code.writeByte(newarraycode);
 171         return thisBuilder();
 172     }
 173 
 174     public C anewarray(S array) {
 175         emitOp(Opcode.ANEWARRAY, array);
 176         int poolIdx = poolHelper.putClass(array);
 177         code.writeChar(poolIdx);
 178         return thisBuilder();
 179     }
 180 
 181     public C checkcast(S target) {
 182         emitOp(Opcode.CHECKCAST);
 183         int poolIdx = poolHelper.putClass(target);
 184         code.writeChar(poolIdx);
 185         return thisBuilder();
 186     }
 187 
 188     public C instanceof_(S target) {
 189         emitOp(Opcode.INSTANCEOF);
 190         int poolIdx = poolHelper.putClass(target);
 191         code.writeChar(poolIdx);
 192         return thisBuilder();
 193     }
 194 
 195     public C multianewarray(S array, byte dims) {
 196         emitOp(Opcode.MULTIANEWARRAY, new Object[]{array, dims});
 197         code.writeChar(poolHelper.putClass(array)).writeByte(dims);
 198         return thisBuilder();
 199     }
 200 
 201     public C ldc(int i) {
 202         return ldc(pool -> pool.putInt(i), false);
 203     }
 204 
 205     public C ldc(long l) {
 206         return ldc(pool -> pool.putLong(l), true);
 207     }
 208 
 209     public C ldc(float f) {
 210         return ldc(pool -> pool.putFloat(f), false);
 211     }
 212 
 213     public C ldc(double d) {
 214         return ldc(pool -> pool.putDouble(d), true);
 215     }
 216 
 217     public C ldc(String s) {
 218         return ldc(pool -> pool.putString(s), false);
 219     }
 220 
 221     public C ldc(CharSequence constName, T constType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, E>> staticArgs) {
 222         boolean fat = typeHelper.tag(constType).width() == 2;
 223         return ldc(pool -> pool.putDynamicConstant(constName, constType, bsmClass, bsmName, bsmType, staticArgs), fat);
 224     }
 225 
 226     public <Z> C ldc(Z z, BiFunction<PoolHelper<S, T, E>, Z, Integer> poolFunc) {
 227         return ldc(pool -> poolFunc.apply(pool, z), false);
 228     }
 229 
 230     protected C ldc(ToIntFunction<PoolHelper<S, T, E>> indexFunc, boolean fat) {
 231         // @@@ This should probably be abstract
 232         int index = indexFunc.applyAsInt(poolHelper);
 233         return ldc(index, null, fat);
 234     }
 235 
 236     protected final C ldc(int index, T type, boolean fat) {
 237         if (fat) {
 238             emitOp(Opcode.LDC2_W, type);
 239             code.writeChar(index);
 240         } else if (index > 63) {
 241             emitOp(Opcode.LDC_W, type);
 242             code.writeChar(index);
 243         } else {
 244             emitOp(Opcode.LDC, type);
 245             code.writeByte(index);
 246         }
 247         return thisBuilder();
 248     }
 249 
 250     //other non-CP dependent opcodes
 251     public C areturn() {
 252         return emitOp(Opcode.ARETURN);
 253     }
 254 
 255     public C ireturn() {
 256         return emitOp(Opcode.IRETURN);
 257     }
 258 
 259     public C freturn() {
 260         return emitOp(Opcode.FRETURN);
 261     }
 262 
 263     public C lreturn() {
 264         return emitOp(Opcode.LRETURN);
 265     }
 266 
 267     public C dreturn() {
 268         return emitOp(Opcode.DRETURN);
 269     }
 270 
 271     public C return_() {
 272         return emitOp(Opcode.RETURN);
 273     }
 274 
 275     protected C emitWideIfNeeded(Opcode opcode, int n) {
 276         boolean wide = n > Byte.MAX_VALUE;
 277         if (wide) {
 278             wide();
 279         }
 280         emitOp(opcode, n);
 281         if (wide) {
 282             code.writeChar(n);
 283         } else {
 284             code.writeByte(n);
 285         }
 286         return thisBuilder();
 287     }
 288 
 289     protected C emitWideIfNeeded(Opcode opcode, int n, int v) {
 290         boolean wide = n > Byte.MAX_VALUE || v > Byte.MAX_VALUE;
 291         if (wide) {
 292             wide();
 293         }
 294         emitOp(opcode, n);
 295         if (wide) {
 296             code.writeChar(n).writeChar(v);
 297         } else {
 298             code.writeByte(n).writeByte(v);
 299         }
 300         return thisBuilder();
 301     }
 302 
 303     public C aload(int i) {
 304         return emitWideIfNeeded(Opcode.ALOAD, i);
 305     }
 306 
 307     public C iload(int i) {
 308         return emitWideIfNeeded(Opcode.ILOAD, i);
 309     }
 310 
 311     public C fload(int i) {
 312         return emitWideIfNeeded(Opcode.FLOAD, i);
 313     }
 314 
 315     public C lload(int i) {
 316         return emitWideIfNeeded(Opcode.LLOAD, i);
 317     }
 318 
 319     public C dload(int i) {
 320         return emitWideIfNeeded(Opcode.DLOAD, i);
 321     }
 322 
 323     public C aload_0() {
 324         return emitOp(Opcode.ALOAD_0);
 325     }
 326 
 327     public C iload_0() {
 328         return emitOp(Opcode.ILOAD_0);
 329     }
 330 
 331     public C fload_0() {
 332         return emitOp(Opcode.FLOAD_0);
 333     }
 334 
 335     public C lload_0() {
 336         return emitOp(Opcode.LLOAD_0);
 337     }
 338 
 339     public C dload_0() {
 340         return emitOp(Opcode.DLOAD_0);
 341     }
 342 
 343     public C aload_1() {
 344         return emitOp(Opcode.ALOAD_1);
 345     }
 346 
 347     public C iload_1() {
 348         return emitOp(Opcode.ILOAD_1);
 349     }
 350 
 351     public C fload_1() {
 352         return emitOp(Opcode.FLOAD_1);
 353     }
 354 
 355     public C lload_1() {
 356         return emitOp(Opcode.LLOAD_1);
 357     }
 358 
 359     public C dload_1() {
 360         return emitOp(Opcode.DLOAD_1);
 361     }
 362 
 363     public C aload_2() {
 364         return emitOp(Opcode.ALOAD_2);
 365     }
 366 
 367     public C iload_2() {
 368         return emitOp(Opcode.ILOAD_2);
 369     }
 370 
 371     public C fload_2() {
 372         return emitOp(Opcode.FLOAD_2);
 373     }
 374 
 375     public C lload_2() {
 376         return emitOp(Opcode.LLOAD_2);
 377     }
 378 
 379     public C dload_2() {
 380         return emitOp(Opcode.DLOAD_2);
 381     }
 382 
 383     public C aload_3() {
 384         return emitOp(Opcode.ALOAD_3);
 385     }
 386 
 387     public C iload_3() {
 388         return emitOp(Opcode.ILOAD_3);
 389     }
 390 
 391     public C fload_3() {
 392         return emitOp(Opcode.FLOAD_3);
 393     }
 394 
 395     public C lload_3() {
 396         return emitOp(Opcode.LLOAD_3);
 397     }
 398 
 399     public C dload_3() {
 400         return emitOp(Opcode.DLOAD_3);
 401     }
 402 
 403     public C astore(int i) {
 404         return emitWideIfNeeded(Opcode.ASTORE, i);
 405     }
 406 
 407     public C istore(int i) {
 408         return emitWideIfNeeded(Opcode.ISTORE, i);
 409     }
 410 
 411     public C fstore(int i) {
 412         return emitWideIfNeeded(Opcode.FSTORE, i);
 413     }
 414 
 415     public C lstore(int i) {
 416         return emitWideIfNeeded(Opcode.LSTORE, i);
 417     }
 418 
 419     public C dstore(int i) {
 420         return emitWideIfNeeded(Opcode.DSTORE, i);
 421     }
 422 
 423     public C astore_0() {
 424         return emitOp(Opcode.ASTORE_0);
 425     }
 426 
 427     public C istore_0() {
 428         return emitOp(Opcode.ISTORE_0);
 429     }
 430 
 431     public C fstore_0() {
 432         return emitOp(Opcode.FSTORE_0);
 433     }
 434 
 435     public C lstore_0() {
 436         return emitOp(Opcode.LSTORE_0);
 437     }
 438 
 439     public C dstore_0() {
 440         return emitOp(Opcode.DSTORE_0);
 441     }
 442 
 443     public C astore_1() {
 444         return emitOp(Opcode.ASTORE_1);
 445     }
 446 
 447     public C istore_1() {
 448         return emitOp(Opcode.ISTORE_1);
 449     }
 450 
 451     public C fstore_1() {
 452         return emitOp(Opcode.FSTORE_1);
 453     }
 454 
 455     public C lstore_1() {
 456         return emitOp(Opcode.LSTORE_1);
 457     }
 458 
 459     public C dstore_1() {
 460         return emitOp(Opcode.DSTORE_1);
 461     }
 462 
 463     public C astore_2() {
 464         return emitOp(Opcode.ASTORE_2);
 465     }
 466 
 467     public C istore_2() {
 468         return emitOp(Opcode.ISTORE_2);
 469     }
 470 
 471     public C fstore_2() {
 472         return emitOp(Opcode.FSTORE_2);
 473     }
 474 
 475     public C lstore_2() {
 476         return emitOp(Opcode.LSTORE_2);
 477     }
 478 
 479     public C dstore_2() {
 480         return emitOp(Opcode.DSTORE_2);
 481     }
 482 
 483     public C astore_3() {
 484         return emitOp(Opcode.ASTORE_3);
 485     }
 486 
 487     public C istore_3() {
 488         return emitOp(Opcode.ISTORE_3);
 489     }
 490 
 491     public C fstore_3() {
 492         return emitOp(Opcode.FSTORE_3);
 493     }
 494 
 495     public C lstore_3() {
 496         return emitOp(Opcode.LSTORE_3);
 497     }
 498 
 499     public C dstore_3() {
 500         return emitOp(Opcode.DSTORE_3);
 501     }
 502 
 503     //...
 504 
 505     public C iaload() {
 506         return emitOp(Opcode.IALOAD);
 507     }
 508 
 509     public C laload() {
 510         return emitOp(Opcode.LALOAD);
 511     }
 512 
 513     public C faload() {
 514         return emitOp(Opcode.FALOAD);
 515     }
 516 
 517     public C daload() {
 518         return emitOp(Opcode.DALOAD);
 519     }
 520 
 521     public C aaload() {
 522         return emitOp(Opcode.AALOAD);
 523     }
 524 
 525     public C baload() {
 526         return emitOp(Opcode.BALOAD);
 527     }
 528 
 529     public C caload() {
 530         return emitOp(Opcode.CALOAD);
 531     }
 532 
 533     public C saload() {
 534         return emitOp(Opcode.SALOAD);
 535     }
 536 
 537     public C iastore() {
 538         return emitOp(Opcode.IASTORE);
 539     }
 540 
 541     public C lastore() {
 542         return emitOp(Opcode.LASTORE);
 543     }
 544 
 545     public C fastore() {
 546         return emitOp(Opcode.FASTORE);
 547     }
 548 
 549     public C dastore() {
 550         return emitOp(Opcode.DASTORE);
 551     }
 552 
 553     public C aastore() {
 554         return emitOp(Opcode.AASTORE);
 555     }
 556 
 557     public C bastore() {
 558         return emitOp(Opcode.BASTORE);
 559     }
 560 
 561     public C castore() {
 562         return emitOp(Opcode.CASTORE);
 563     }
 564 
 565     public C sastore() {
 566         return emitOp(Opcode.SASTORE);
 567     }
 568 
 569     public C nop() {
 570         return emitOp(Opcode.NOP);
 571     }
 572 
 573     public C aconst_null() {
 574         return emitOp(Opcode.ACONST_NULL);
 575     }
 576 
 577     public C iconst_0() {
 578         return emitOp(Opcode.ICONST_0);
 579     }
 580 
 581     public C iconst_1() {
 582         return emitOp(Opcode.ICONST_1);
 583     }
 584 
 585     public C iconst_2() {
 586         return emitOp(Opcode.ICONST_2);
 587     }
 588 
 589     public C iconst_3() {
 590         return emitOp(Opcode.ICONST_3);
 591     }
 592 
 593     public C iconst_4() {
 594         return emitOp(Opcode.ICONST_4);
 595     }
 596 
 597     public C iconst_5() {
 598         return emitOp(Opcode.ICONST_5);
 599     }
 600 
 601     public C iconst_m1() {
 602         return emitOp(Opcode.ICONST_M1);
 603     }
 604 
 605     public C lconst_0() {
 606         return emitOp(Opcode.LCONST_0);
 607     }
 608 
 609     public C lconst_1() {
 610         return emitOp(Opcode.LCONST_1);
 611     }
 612 
 613     public C fconst_0() {
 614         return emitOp(Opcode.FCONST_0);
 615     }
 616 
 617     public C fconst_1() {
 618         return emitOp(Opcode.FCONST_1);
 619     }
 620 
 621     public C fconst_2() {
 622         return emitOp(Opcode.FCONST_2);
 623     }
 624 
 625     public C dconst_0() {
 626         return emitOp(Opcode.DCONST_0);
 627     }
 628 
 629     public C dconst_1() {
 630         return emitOp(Opcode.DCONST_1);
 631     }
 632 
 633     public C sipush(int s) {
 634         emitOp(Opcode.SIPUSH);
 635         code.writeChar(s);
 636         return thisBuilder();
 637     }
 638 
 639     public C bipush(int b) {
 640         emitOp(Opcode.BIPUSH);
 641         code.writeByte(b);
 642         return thisBuilder();
 643     }
 644 
 645     public C pop() {
 646         return emitOp(Opcode.POP);
 647     }
 648 
 649     public C pop2() {
 650         return emitOp(Opcode.POP2);
 651     }
 652 
 653     public C dup() {
 654         return emitOp(Opcode.DUP);
 655     }
 656 
 657     public C dup_x1() {
 658         return emitOp(Opcode.DUP_X1);
 659     }
 660 
 661     public C dup_x2() {
 662         return emitOp(Opcode.DUP_X2);
 663     }
 664 
 665     public C dup2() {
 666         return emitOp(Opcode.DUP2);
 667     }
 668 
 669     public C dup2_x1() {
 670         return emitOp(Opcode.DUP2_X1);
 671     }
 672 
 673     public C dup2_x2() {
 674         return emitOp(Opcode.DUP2_X2);
 675     }
 676 
 677     public C swap() {
 678         return emitOp(Opcode.SWAP);
 679     }
 680 
 681     public C iadd() {
 682         return emitOp(Opcode.IADD);
 683     }
 684 
 685     public C ladd() {
 686         return emitOp(Opcode.LADD);
 687     }
 688 
 689     public C fadd() {
 690         return emitOp(Opcode.FADD);
 691     }
 692 
 693     public C dadd() {
 694         return emitOp(Opcode.DADD);
 695     }
 696 
 697     public C isub() {
 698         return emitOp(Opcode.ISUB);
 699     }
 700 
 701     public C lsub() {
 702         return emitOp(Opcode.LSUB);
 703     }
 704 
 705     public C fsub() {
 706         return emitOp(Opcode.FSUB);
 707     }
 708 
 709     public C dsub() {
 710         return emitOp(Opcode.DSUB);
 711     }
 712 
 713     public C imul() {
 714         return emitOp(Opcode.IMUL);
 715     }
 716 
 717     public C lmul() {
 718         return emitOp(Opcode.LMUL);
 719     }
 720 
 721     public C fmul() {
 722         return emitOp(Opcode.FMUL);
 723     }
 724 
 725     public C dmul() {
 726         return emitOp(Opcode.DMUL);
 727     }
 728 
 729     public C idiv() {
 730         return emitOp(Opcode.IDIV);
 731     }
 732 
 733     public C ldiv() {
 734         return emitOp(Opcode.LDIV);
 735     }
 736 
 737     public C fdiv() {
 738         return emitOp(Opcode.FDIV);
 739     }
 740 
 741     public C ddiv() {
 742         return emitOp(Opcode.DDIV);
 743     }
 744 
 745     public C irem() {
 746         return emitOp(Opcode.IREM);
 747     }
 748 
 749     public C lrem() {
 750         return emitOp(Opcode.LREM);
 751     }
 752 
 753     public C frem() {
 754         return emitOp(Opcode.FREM);
 755     }
 756 
 757     public C drem() {
 758         return emitOp(Opcode.DREM);
 759     }
 760 
 761     public C ineg() {
 762         return emitOp(Opcode.INEG);
 763     }
 764 
 765     public C lneg() {
 766         return emitOp(Opcode.LNEG);
 767     }
 768 
 769     public C fneg() {
 770         return emitOp(Opcode.FNEG);
 771     }
 772 
 773     public C dneg() {
 774         return emitOp(Opcode.DNEG);
 775     }
 776 
 777     public C ishl() {
 778         return emitOp(Opcode.ISHL);
 779     }
 780 
 781     public C lshl() {
 782         return emitOp(Opcode.LSHL);
 783     }
 784 
 785     public C ishr() {
 786         return emitOp(Opcode.ISHR);
 787     }
 788 
 789     public C lshr() {
 790         return emitOp(Opcode.LSHR);
 791     }
 792 
 793     public C iushr() {
 794         return emitOp(Opcode.IUSHR);
 795     }
 796 
 797     public C lushr() {
 798         return emitOp(Opcode.LUSHR);
 799     }
 800 
 801     public C iand() {
 802         return emitOp(Opcode.IAND);
 803     }
 804 
 805     public C land() {
 806         return emitOp(Opcode.LAND);
 807     }
 808 
 809     public C ior() {
 810         return emitOp(Opcode.IOR);
 811     }
 812 
 813     public C lor() {
 814         return emitOp(Opcode.LOR);
 815     }
 816 
 817     public C ixor() {
 818         return emitOp(Opcode.IXOR);
 819     }
 820 
 821     public C lxor() {
 822         return emitOp(Opcode.LXOR);
 823     }
 824 
 825     public C iinc(int index, int val) {
 826         return emitWideIfNeeded(Opcode.IINC, index, val);
 827     }
 828 
 829     public C i2l() {
 830         return emitOp(Opcode.I2L);
 831     }
 832 
 833     public C i2f() {
 834         return emitOp(Opcode.I2F);
 835     }
 836 
 837     public C i2d() {
 838         return emitOp(Opcode.I2D);
 839     }
 840 
 841     public C l2i() {
 842         return emitOp(Opcode.L2I);
 843     }
 844 
 845     public C l2f() {
 846         return emitOp(Opcode.L2F);
 847     }
 848 
 849     public C l2d() {
 850         return emitOp(Opcode.L2D);
 851     }
 852 
 853     public C f2i() {
 854         return emitOp(Opcode.F2I);
 855     }
 856 
 857     public C f2l() {
 858         return emitOp(Opcode.F2L);
 859     }
 860 
 861     public C f2d() {
 862         return emitOp(Opcode.F2D);
 863     }
 864 
 865     public C d2i() {
 866         return emitOp(Opcode.D2I);
 867     }
 868 
 869     public C d2l() {
 870         return emitOp(Opcode.D2L);
 871     }
 872 
 873     public C d2f() {
 874         return emitOp(Opcode.D2F);
 875     }
 876 
 877     public C i2b() {
 878         return emitOp(Opcode.I2B);
 879     }
 880 
 881     public C i2c() {
 882         return emitOp(Opcode.I2C);
 883     }
 884 
 885     public C i2s() {
 886         return emitOp(Opcode.I2S);
 887     }
 888 
 889     public C lcmp() {
 890         return emitOp(Opcode.LCMP);
 891     }
 892 
 893     public C fcmpl() {
 894         return emitOp(Opcode.FCMPL);
 895     }
 896 
 897     public C fcmpg() {
 898         return emitOp(Opcode.FCMPG);
 899     }
 900 
 901     public C dcmpl() {
 902         return emitOp(Opcode.DCMPL);
 903     }
 904 
 905     public C dcmpg() {
 906         return emitOp(Opcode.DCMPG);
 907     }
 908 
 909     public C ifeq(short target) {
 910         return emitNarrowJumpOp(Opcode.IFEQ, target);
 911     }
 912 
 913     public C ifne(short target) {
 914         return emitNarrowJumpOp(Opcode.IFNE, target);
 915     }
 916 
 917     public C iflt(short target) {
 918         return emitNarrowJumpOp(Opcode.IFLT, target);
 919     }
 920 
 921     public C ifge(short target) {
 922         return emitNarrowJumpOp(Opcode.IFGE, target);
 923     }
 924 
 925     public C ifgt(short target) {
 926         return emitNarrowJumpOp(Opcode.IFGT, target);
 927     }
 928 
 929     public C ifle(short target) {
 930         return emitNarrowJumpOp(Opcode.IFLE, target);
 931     }
 932 
 933     public C if_icmpeq(short target) {
 934         return emitNarrowJumpOp(Opcode.IF_ICMPEQ, target);
 935     }
 936 
 937     public C if_icmpne(short target) {
 938         return emitNarrowJumpOp(Opcode.IF_ICMPNE, target);
 939     }
 940 
 941     public C if_icmplt(short target) {
 942         return emitNarrowJumpOp(Opcode.IF_ICMPLT, target);
 943     }
 944 
 945     public C if_icmpge(short target) {
 946         return emitNarrowJumpOp(Opcode.IF_ICMPGE, target);
 947     }
 948 
 949     public C if_icmpgt(short target) {
 950         return emitNarrowJumpOp(Opcode.IF_ICMPGT, target);
 951     }
 952 
 953     public C if_icmple(short target) {
 954         return emitNarrowJumpOp(Opcode.IF_ICMPLE, target);
 955     }
 956 
 957     public C if_acmpeq(short target) {
 958         return emitNarrowJumpOp(Opcode.IF_ACMPEQ, target);
 959     }
 960 
 961     public C if_acmpne(short target) {
 962         return emitNarrowJumpOp(Opcode.IF_ACMPNE, target);
 963     }
 964 
 965     public C goto_(short target) {
 966         return emitNarrowJumpOp(Opcode.GOTO_, target);
 967     }
 968 
 969     public C jsr(short target) {
 970         return emitNarrowJumpOp(Opcode.JSR, target);
 971     }
 972 
 973     public C ret(int index) {
 974         return emitWideIfNeeded(Opcode.RET, index);
 975     }
 976 
 977     public C tableswitch(int low, int high, int defaultTarget, int... targets) {
 978         if (high - low + 1 != targets.length) throw new IllegalStateException("Bad targets length");
 979         emitOp(Opcode.TABLESWITCH);
 980         //padding
 981         int start = code.offset;
 982         if ((start % 4) != 0) {
 983             //add padding
 984             for (int i = 0; i < 4 - (start % 4); i++) {
 985                 code.writeByte(0);
 986             }
 987         }
 988         code.writeInt(defaultTarget)
 989                 .writeInt(low)
 990                 .writeInt(high);
 991         for (int target : targets) {
 992             code.writeInt(target);
 993         }
 994         return thisBuilder();
 995     }
 996 
 997     public C lookupswitch(int defaultTarget, int... npairs) {
 998         if (npairs.length % 2 != 0) throw new IllegalStateException("Bad npairs length");
 999         emitOp(Opcode.LOOKUPSWITCH);
1000         //padding
1001         int start = code.offset;
1002         for (int i = 0; i < (4 - (start % 4)); i++) {
1003             code.writeByte(0);
1004         }
1005         code.writeInt(defaultTarget)
1006                 .writeInt(npairs.length / 2);
1007         for (int i = 0; i < npairs.length; i += 2) {
1008             code.writeInt(npairs[i]);
1009             code.writeInt(npairs[i + 1]);
1010         }
1011         return thisBuilder();
1012     }
1013 
1014     public C arraylength() {
1015         return emitOp(Opcode.ARRAYLENGTH);
1016     }
1017 
1018     public C athrow() {
1019         return emitOp(Opcode.ATHROW);
1020     }
1021 
1022     public C monitorenter() {
1023         return emitOp(Opcode.MONITORENTER);
1024     }
1025 
1026     public C monitorexit() {
1027         return emitOp(Opcode.MONITOREXIT);
1028     }
1029 
1030     public C wide() {
1031         return emitOp(Opcode.WIDE);
1032     }
1033 
1034     public C if_null(short offset) {
1035         return emitNarrowJumpOp(Opcode.IF_NULL, offset);
1036     }
1037 
1038     public C if_nonnull(short offset) {
1039         return emitNarrowJumpOp(Opcode.IF_NONNULL, offset);
1040     }
1041 
1042     public C goto_w(int target) {
1043         return emitWideJumpOp(Opcode.GOTO_W, target);
1044     }
1045 
1046     public C jsr_w(int target) {
1047         return emitWideJumpOp(Opcode.JSR_W, target);
1048     }
1049 
1050     public C withCatch(S type, int start, int end, int offset) {
1051         catchers.writeChar(start);
1052         catchers.writeChar(end);
1053         catchers.writeChar(offset);
1054         catchers.writeChar(type != null ? poolHelper.putClass(type) : 0);
1055         ncatchers++;
1056         return thisBuilder();
1057     }
1058 
1059     public C withLocalSize(int localsize) {
1060         this.localsize = localsize;
1061         return thisBuilder();
1062     }
1063 
1064     public C withStackSize(int stacksize) {
1065         this.stacksize = stacksize;
1066         return thisBuilder();
1067     }
1068 
1069     protected int localsize() {
1070         return localsize;
1071     }
1072 
1073     void build(GrowableByteBuffer buf) {
1074         buf.writeChar(stacksize); //max stack size
1075         buf.writeChar(localsize()); //max locals
1076         buf.writeInt(code.offset);
1077         buf.writeBytes(code);
1078         buf.writeChar(ncatchers);
1079         buf.writeBytes(catchers);
1080         buf.writeChar(nattrs); //attributes
1081         buf.writeBytes(attributes);
1082     }
1083 
1084     byte[] build() {
1085         GrowableByteBuffer buf = new GrowableByteBuffer();
1086         build(buf);
1087         return buf.bytes();
1088     }
1089 
1090     protected C emitNarrowJumpOp(Opcode opcode, short target) {
1091         emitOp(opcode);
1092         emitOffset(code, JumpMode.NARROW, target);
1093         return thisBuilder();
1094     }
1095 
1096     protected C emitWideJumpOp(Opcode opcode, int target) {
1097         emitOp(opcode);
1098         emitOffset(code, JumpMode.WIDE, target);
1099         return thisBuilder();
1100     }
1101 
1102     protected C emitOp(Opcode opcode) {
1103         return emitOp(opcode, null);
1104     }
1105 
1106     protected C emitOp(Opcode opcode, Object optPoolValue) {
1107         code.writeByte(opcode.code);
1108         return thisBuilder();
1109     }
1110 
1111     protected void emitOffset(GrowableByteBuffer buf, JumpMode jumpMode, int offset) {
1112         if (jumpMode == JumpMode.NARROW) {
1113             buf.writeChar((short) offset);
1114         } else {
1115             buf.writeInt(offset);
1116         }
1117     }
1118 
1119     int offset() {
1120         return code.offset;
1121     }
1122 
1123     /*** stackmap support ***/
1124 
1125     /**
1126      * The tags and constants used in compressed stackmap.
1127      */
1128     static final int SAME_FRAME_SIZE = 64;
1129     static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
1130     static final int SAME_FRAME_EXTENDED = 251;
1131     static final int FULL_FRAME = 255;
1132     static final int MAX_LOCAL_LENGTH_DIFF = 4;
1133 
1134     @SuppressWarnings("unchecked")
1135     private void writeStackMapType(T t) {
1136         if (t == null) {
1137             stackmaps.writeByte(0);
1138         } else {
1139             switch (typeHelper.tag(t)) {
1140                 case B:
1141                 case C:
1142                 case S:
1143                 case I:
1144                 case Z:
1145                     stackmaps.writeByte(1);
1146                     break;
1147                 case F:
1148                     stackmaps.writeByte(2);
1149                     break;
1150                 case D:
1151                     stackmaps.writeByte(3);
1152                     break;
1153                 case J:
1154                     stackmaps.writeByte(4);
1155                     break;
1156                 case A:
1157                     if (t == typeHelper.nullType()) {
1158                         stackmaps.writeByte(5); //null
1159                     } else {
1160                         //TODO: uninit this, top?
1161                         stackmaps.writeByte(7);
1162                         stackmaps.writeChar(poolHelper.putClass(typeHelper.symbol(t)));
1163                     }
1164                     break;
1165                 default:
1166                     throw new IllegalStateException("Bad type");
1167             }
1168         }
1169     }
1170 
1171     public void sameFrame(int offsetDelta) {
1172         int frameType = (offsetDelta < SAME_FRAME_SIZE) ?
1173                 offsetDelta : SAME_FRAME_EXTENDED;
1174         stackmaps.writeByte(frameType);
1175         if (frameType == SAME_FRAME_EXTENDED) {
1176             stackmaps.writeChar(offsetDelta);
1177         }
1178     }
1179 
1180     public void sameLocals1StackItemFrame(int offsetDelta, T stackItem) {
1181         int frameType = (offsetDelta < SAME_FRAME_SIZE) ?
1182                 (SAME_FRAME_SIZE + offsetDelta) : SAME_LOCALS_1_STACK_ITEM_EXTENDED;
1183         stackmaps.writeByte(frameType);
1184         if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
1185             stackmaps.writeChar(offsetDelta);
1186         }
1187         writeStackMapType(stackItem);
1188     }
1189 
1190     public void appendFrame(int offsetDelta, int prevLocalsSize, List<T> locals) {
1191         int frameType = SAME_FRAME_EXTENDED + (locals.size() - prevLocalsSize);
1192         stackmaps.writeByte(frameType);
1193         stackmaps.writeChar(offsetDelta);
1194         for (int i = prevLocalsSize; i < locals.size(); i++) {
1195             writeStackMapType(locals.get(i));
1196         }
1197     }
1198 
1199     public void chopFrame(int offsetDelta, int droppedVars) {
1200         int frameType = SAME_FRAME_EXTENDED - droppedVars;
1201         stackmaps.writeByte(frameType);
1202         stackmaps.writeChar(offsetDelta);
1203     }
1204 
1205     public void fullFrame(int offsetDelta, List<T> locals, List<T> stackItems) {
1206         stackmaps.writeByte(FULL_FRAME);
1207         stackmaps.writeChar(offsetDelta);
1208         stackmaps.writeChar(locals.size());
1209         for (T local : locals) {
1210             writeStackMapType(local);
1211         }
1212 
1213         stackmaps.writeChar(stackItems.size());
1214         for (T stackType : stackItems) {
1215             writeStackMapType(stackType);
1216         }
1217     }
1218 }