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