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