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