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