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