test/jdk/lib/testlibrary/bytecode/jdk/experimental/bytecode/TypedCodeBuilder.java
changeset 48826 c4d9d1b08e2e
child 48827 8772acd913e5
equal deleted inserted replaced
48825:ef8a98bc71f8 48826:c4d9d1b08e2e
       
     1 /*
       
     2  * Copyright (c) 2017, 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.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 package jdk.experimental.bytecode;
       
    25 
       
    26 import java.util.ArrayList;
       
    27 import java.util.HashMap;
       
    28 import java.util.Iterator;
       
    29 import java.util.List;
       
    30 import java.util.Map;
       
    31 import java.util.Map.Entry;
       
    32 import java.util.Vector;
       
    33 import java.util.function.Consumer;
       
    34 import java.util.function.Supplier;
       
    35 import java.util.function.ToIntFunction;
       
    36 
       
    37 public class TypedCodeBuilder<S, T, E, C extends TypedCodeBuilder<S, T, E, C>> extends MacroCodeBuilder<S, T, E, C> {
       
    38 
       
    39     State lastStackMapState;
       
    40     int lastStackMapPc = -1;
       
    41     Map<CharSequence, LocalVarInfo> lvarOffsets = new HashMap<>();
       
    42     protected State state;
       
    43     int depth = 0;
       
    44     int currLocalOffset = 0;
       
    45 
       
    46     class StatefulPendingJump extends PendingJump {
       
    47 
       
    48         State state;
       
    49 
       
    50         StatefulPendingJump(CharSequence label, int pc, State state) {
       
    51             super(label, pc);
       
    52             this.state = state;
       
    53         }
       
    54 
       
    55         @Override
       
    56         boolean resolve(CharSequence label, int pc) {
       
    57             boolean b = super.resolve(label, pc);
       
    58             if (b) {
       
    59                 TypedCodeBuilder.this.state = TypedCodeBuilder.this.state.merge(state);
       
    60             }
       
    61             return b;
       
    62         }
       
    63     }
       
    64 
       
    65     class LocalVarInfo {
       
    66         CharSequence name;
       
    67         int offset;
       
    68         int depth;
       
    69         TypeTag type;
       
    70 
       
    71         LocalVarInfo(CharSequence name, int offset, int depth, TypeTag type) {
       
    72             this.name = name;
       
    73             this.offset = offset;
       
    74             this.depth = depth;
       
    75             this.type = type;
       
    76         }
       
    77     }
       
    78 
       
    79     public TypedCodeBuilder(MethodBuilder<S, T, E> methodBuilder) {
       
    80         super(methodBuilder);
       
    81         T t = methodBuilder.desc;
       
    82         state = new State();
       
    83         if ((methodBuilder.flags & Flag.ACC_STATIC.flag) == 0) {
       
    84             T clazz = typeHelper.type(methodBuilder.thisClass);
       
    85             state.load(clazz, currLocalOffset++); //TODO: uninit??
       
    86         }
       
    87         Iterator<T> paramsIt = typeHelper.parameterTypes(t);
       
    88         while (paramsIt.hasNext()) {
       
    89             T p = paramsIt.next();
       
    90             state.load(p, currLocalOffset);
       
    91             currLocalOffset += typeHelper.tag(p).width;
       
    92         }
       
    93         lastStackMapState = state.dup();
       
    94         stacksize = state.stack.size();
       
    95         localsize = state.locals.size();
       
    96     }
       
    97 
       
    98     @Override
       
    99     protected C emitOp(Opcode opcode, Object optPoolValue) {
       
   100         updateState(opcode, optPoolValue);
       
   101         return super.emitOp(opcode, optPoolValue);
       
   102     }
       
   103 
       
   104     @Override
       
   105     protected SwitchBuilder makeSwitchBuilder() {
       
   106         return new TypedSwitchBuilder();
       
   107     }
       
   108 
       
   109     class TypedSwitchBuilder extends SwitchBuilder {
       
   110 
       
   111         @Override
       
   112         public SwitchBuilder withCase(int value, Consumer<? super C> case_, boolean fallthrough) {
       
   113             super.withCase(value, c -> {
       
   114                 withLocalScope(() -> {
       
   115                     State prevState = state;
       
   116                     state = prevState.dup();
       
   117                     emitStackMap(c.offset());
       
   118                     case_.accept(c);
       
   119                     state = prevState;
       
   120                 });
       
   121             }, fallthrough);
       
   122             return this;
       
   123         }
       
   124 
       
   125         @Override
       
   126         public SwitchBuilder withDefault(Consumer<? super C> defaultCase) {
       
   127             super.withDefault(c -> {
       
   128                 withLocalScope(() -> {
       
   129                     State prevState = state;
       
   130                     state = prevState.dup();
       
   131                     emitStackMap(c.offset());
       
   132                     defaultCase.accept(c);
       
   133                     state = prevState;
       
   134                 });
       
   135             });
       
   136             return this;
       
   137         }
       
   138     }
       
   139 
       
   140     @Override
       
   141     public StatefulTypedBuilder typed(TypeTag tag) {
       
   142         return super.typed(tag, StatefulTypedBuilder::new);
       
   143     }
       
   144 
       
   145     public class StatefulTypedBuilder extends LabelledTypedBuilder {
       
   146 
       
   147         TypeTag tag;
       
   148 
       
   149         StatefulTypedBuilder(TypeTag tag) {
       
   150             this.tag = tag;
       
   151         }
       
   152 
       
   153         @Override
       
   154         public C astore_0() {
       
   155             return storeAndUpdate(super::astore_0);
       
   156         }
       
   157 
       
   158         @Override
       
   159         public C astore_1() {
       
   160             return storeAndUpdate(super::astore_1);
       
   161         }
       
   162 
       
   163         @Override
       
   164         public C astore_2() {
       
   165             return storeAndUpdate(super::astore_2);
       
   166         }
       
   167 
       
   168         @Override
       
   169         public C astore_3() {
       
   170             return storeAndUpdate(super::astore_3);
       
   171         }
       
   172 
       
   173         @Override
       
   174         public C astore(int n) {
       
   175             return storeAndUpdate(() -> super.astore(n));
       
   176         }
       
   177 
       
   178         @Override
       
   179         public C aastore() {
       
   180             return storeAndUpdate(super::aastore);
       
   181         }
       
   182 
       
   183         @Override
       
   184         public C areturn() {
       
   185             state.pop(tag);
       
   186             state.push(typeHelper.nullType());
       
   187             return super.areturn();
       
   188         }
       
   189 
       
   190         @Override
       
   191         public C anewarray(S s) {
       
   192             super.anewarray(s);
       
   193             state.pop();
       
   194             state.push(typeHelper.arrayOf(typeHelper.type(s)));
       
   195             return thisBuilder();
       
   196         }
       
   197 
       
   198         @Override
       
   199         public C aconst_null() {
       
   200             super.aconst_null();
       
   201             state.pop();
       
   202             state.push(tag);
       
   203             return thisBuilder();
       
   204         }
       
   205 
       
   206         public C if_acmpeq(CharSequence label) {
       
   207             return jumpAndUpdate(() -> super.if_acmpeq(label));
       
   208         }
       
   209 
       
   210         public C if_acmpne(CharSequence label) {
       
   211             return jumpAndUpdate(() -> super.if_acmpne(label));
       
   212         }
       
   213 
       
   214         private C storeAndUpdate(Supplier<C> op) {
       
   215             state.pop(tag);
       
   216             state.push(typeHelper.nullType());
       
   217             return op.get();
       
   218         }
       
   219 
       
   220         private C jumpAndUpdate(Supplier<C> op) {
       
   221             state.pop(tag);
       
   222             state.pop(tag);
       
   223             state.push(typeHelper.nullType());
       
   224             state.push(typeHelper.nullType());
       
   225             return op.get();
       
   226         }
       
   227     }
       
   228 
       
   229     public class State {
       
   230         public final ArrayList<T> stack;
       
   231         public final Vector<T> locals;
       
   232         boolean alive;
       
   233 
       
   234         State(ArrayList<T> stack, Vector<T> locals) {
       
   235             this.stack = stack;
       
   236             this.locals = locals;
       
   237         }
       
   238 
       
   239         State() {
       
   240             this(new ArrayList<>(), new Vector<>());
       
   241         }
       
   242 
       
   243         void push(TypeTag tag) {
       
   244             switch (tag) {
       
   245                 case A:
       
   246                 case V:
       
   247                     throw new IllegalStateException("Bad type tag");
       
   248                 default:
       
   249                     push(typeHelper.fromTag(tag));
       
   250             }
       
   251         }
       
   252 
       
   253         void push(T t) {
       
   254             stack.add(t);
       
   255             if (width(t) == 2) {
       
   256                 stack.add(null);
       
   257             }
       
   258             if (stack.size() > stacksize) {
       
   259                 stacksize = stack.size();
       
   260             }
       
   261         }
       
   262 
       
   263         T peek() {
       
   264             return stack.get(stack.size() - 1);
       
   265         }
       
   266 
       
   267         T tosType() {
       
   268             T tos = peek();
       
   269             if (tos == null) {
       
   270                 //double slot
       
   271                 tos = stack.get(stack.size() - 2);
       
   272             }
       
   273             return tos;
       
   274         }
       
   275 
       
   276         T popInternal() {
       
   277             return stack.remove(stack.size() - 1);
       
   278         }
       
   279 
       
   280         @SuppressWarnings("unchecked")
       
   281         T pop() {
       
   282             if (stack.size() == 0 || peek() == null) throw new IllegalStateException();
       
   283             return popInternal();
       
   284         }
       
   285 
       
   286         T pop2() {
       
   287             T o = stack.get(stack.size() - 2);
       
   288             TypeTag t = typeHelper.tag(o);
       
   289             if (t.width != 2) throw new IllegalStateException();
       
   290             popInternal();
       
   291             popInternal();
       
   292             return o;
       
   293         }
       
   294 
       
   295         T pop(TypeTag t) {
       
   296             return (t.width() == 2) ?
       
   297                 pop2() : pop();
       
   298         }
       
   299 
       
   300         void load(TypeTag tag, int index) {
       
   301             if (tag == TypeTag.A) throw new IllegalStateException("Bad type tag");
       
   302             load(typeHelper.fromTag(tag), index);
       
   303         }
       
   304 
       
   305         void load(T t, int index) {
       
   306             ensureDefined(index);
       
   307             locals.set(index, t);
       
   308             if (width(t) == 2) {
       
   309                 locals.add(null);
       
   310             }
       
   311             if (locals.size() > localsize) {
       
   312                 localsize = locals.size();
       
   313             }
       
   314         }
       
   315 
       
   316         void ensureDefined(int index) {
       
   317             if (index >= locals.size()) {
       
   318                 locals.setSize(index + 1);
       
   319             }
       
   320         }
       
   321 
       
   322         State dup() {
       
   323             State newState = new State(new ArrayList<>(stack), new Vector<>(locals));
       
   324             return newState;
       
   325         }
       
   326 
       
   327         State merge(State that) {
       
   328             if (!alive) { return that; }
       
   329             if (that.stack.size() != stack.size()) {
       
   330                 throw new IllegalStateException("Bad stack size at merge point");
       
   331             }
       
   332             for (int i = 0; i < stack.size(); i++) {
       
   333                 T t1 = stack.get(i);
       
   334                 T t2 = that.stack.get(i);
       
   335                 stack.set(i, merge(t1, t2, "Bad stack type at merge point"));
       
   336             }
       
   337             int nlocals = locals.size() > that.locals.size() ? that.locals.size() : locals.size();
       
   338             for (int i = 0; i < nlocals; i++) {
       
   339                 T t1 = locals.get(i);
       
   340                 T t2 = that.locals.get(i);
       
   341                 locals.set(i, merge(t1, t2, "Bad local type at merge point"));
       
   342             }
       
   343             if (locals.size() > nlocals) {
       
   344                 for (int i = nlocals; i < locals.size(); i++) {
       
   345                     locals.remove(i);
       
   346                 }
       
   347             }
       
   348             return this;
       
   349         }
       
   350 
       
   351         T merge(T t1, T t2, String msg) {
       
   352             if (t1 == null && t2 == null) {
       
   353                 return t1;
       
   354             }
       
   355             T res;
       
   356             TypeTag tag1 = typeHelper.tag(t1);
       
   357             TypeTag tag2 = typeHelper.tag(t2);
       
   358             if (tag1 != TypeTag.A && tag2 != TypeTag.A &&
       
   359                     tag1 != TypeTag.Q && tag2 != TypeTag.Q) {
       
   360                 res = typeHelper.fromTag(TypeTag.commonSupertype(tag1, tag2));
       
   361             } else if (t1 == typeHelper.nullType()) {
       
   362                 res = t2;
       
   363             } else if (t2 == typeHelper.nullType()) {
       
   364                 res = t1;
       
   365             } else {
       
   366                 res = typeHelper.commonSupertype(t1, t2);
       
   367             }
       
   368             if (res == null) {
       
   369                 throw new IllegalStateException(msg);
       
   370             }
       
   371             return res;
       
   372         }
       
   373 
       
   374         @Override
       
   375         public String toString() {
       
   376             return String.format("[locals = %s, stack = %s]", locals, stack);
       
   377         }
       
   378     }
       
   379 
       
   380     int width(T o) {
       
   381         return o == typeHelper.nullType() ?
       
   382                 TypeTag.A.width() :
       
   383                 typeHelper.tag(o).width;
       
   384     }
       
   385 
       
   386     @SuppressWarnings("unchecked")
       
   387     public void updateState(Opcode op, Object optValue) {
       
   388         switch (op) {
       
   389             case VALOAD:
       
   390             case AALOAD:
       
   391                 state.pop();
       
   392                 state.push(typeHelper.elemtype(state.pop()));
       
   393                 break;
       
   394             case GOTO_:
       
   395                 state.alive = false;
       
   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             case NEW:
       
   828                 state.push(typeHelper.type((S) optValue));
       
   829                 break;
       
   830             case NEWARRAY:
       
   831                 state.pop();
       
   832                 state.push(typeHelper.arrayOf(typeHelper.fromTag((TypeTag) optValue)));
       
   833                 break;
       
   834             case ANEWARRAY:
       
   835                 state.pop();
       
   836                 state.push(typeHelper.arrayOf(typeHelper.arrayOf(typeHelper.type((S)optValue))));
       
   837                 break;
       
   838             case VNEWARRAY:
       
   839             case VBOX:
       
   840             case VUNBOX:
       
   841                 state.pop();
       
   842                 state.push(typeHelper.type((S) optValue));
       
   843                 break;
       
   844             case MULTIVNEWARRAY:
       
   845             case MULTIANEWARRAY:
       
   846                 for (int i = 0; i < (byte) ((Object[]) optValue)[1]; i++) {
       
   847                     state.pop();
       
   848                 }
       
   849                 state.push(typeHelper.type((S) ((Object[]) optValue)[0]));
       
   850                 break;
       
   851             case INVOKEINTERFACE:
       
   852             case INVOKEVIRTUAL:
       
   853             case INVOKESPECIAL:
       
   854             case INVOKESTATIC:
       
   855             case INVOKEDYNAMIC:
       
   856                 processInvoke(op, (T) optValue);
       
   857                 break;
       
   858             case GETSTATIC:
       
   859                 state.push((T) optValue);
       
   860                 break;
       
   861             case VGETFIELD:
       
   862             case GETFIELD:
       
   863                 state.pop();
       
   864                 state.push((T) optValue);
       
   865                 break;
       
   866             case PUTSTATIC: {
       
   867                 TypeTag tag = typeHelper.tag((T) optValue);
       
   868                 if (tag.width == 1) {
       
   869                     state.pop();
       
   870                 } else {
       
   871                     state.pop2();
       
   872                 }
       
   873                 break;
       
   874             }
       
   875             case PUTFIELD: {
       
   876                 TypeTag tag = typeHelper.tag((T) optValue);
       
   877                 if (tag.width == 1) {
       
   878                     state.pop();
       
   879                 } else {
       
   880                     state.pop2();
       
   881                 }
       
   882                 state.pop();
       
   883                 break;
       
   884             }
       
   885             case BIPUSH:
       
   886             case SIPUSH:
       
   887                 state.push(TypeTag.I);
       
   888                 break;
       
   889             case LDC:
       
   890             case LDC_W:
       
   891             case LDC2_W:
       
   892                 state.push((T)optValue);
       
   893                 break;
       
   894             case IF_ACMPEQ:
       
   895             case IF_ICMPEQ:
       
   896             case IF_ACMPNE:
       
   897             case IF_ICMPGE:
       
   898             case IF_ICMPGT:
       
   899             case IF_ICMPLE:
       
   900             case IF_ICMPLT:
       
   901             case IF_ICMPNE:
       
   902                 state.pop();
       
   903                 state.pop();
       
   904                 break;
       
   905             case IF_NONNULL:
       
   906             case IF_NULL:
       
   907             case IFEQ:
       
   908             case IFGE:
       
   909             case IFGT:
       
   910             case IFLE:
       
   911             case IFLT:
       
   912             case IFNE:
       
   913                 state.pop();
       
   914                 break;
       
   915             case INSTANCEOF:
       
   916                 state.pop();
       
   917                 state.push(TypeTag.Z);
       
   918                 break;
       
   919             case TYPED:
       
   920             case CHECKCAST:
       
   921                 break;
       
   922 
       
   923             default:
       
   924                 throw new UnsupportedOperationException("Unsupported opcode: " + op);
       
   925         }
       
   926     }
       
   927 
       
   928     void processInvoke(Opcode opcode, T invokedType) {
       
   929         Iterator<T> paramsIt = typeHelper.parameterTypes(invokedType);
       
   930         while (paramsIt.hasNext()) {
       
   931             T t = paramsIt.next();
       
   932             TypeTag tag = typeHelper.tag(t);
       
   933             if (tag.width == 2) {
       
   934                 state.popInternal();
       
   935                 state.popInternal();
       
   936             } else {
       
   937                 state.popInternal();
       
   938             }
       
   939         }
       
   940         if (opcode != Opcode.INVOKESTATIC && opcode != Opcode.INVOKEDYNAMIC) {
       
   941             state.pop(); //receiver
       
   942         }
       
   943         T retType = typeHelper.returnType(invokedType);
       
   944         TypeTag retTag = typeHelper.tag(retType);
       
   945         if (retTag != TypeTag.V)
       
   946             state.push(retType);
       
   947     }
       
   948 
       
   949     @Override
       
   950     protected C ldc(ToIntFunction<PoolHelper<S, T, E>> indexFunc, boolean fat) {
       
   951         LdcPoolHelper ldcPoolHelper = new LdcPoolHelper();
       
   952         int index = indexFunc.applyAsInt(ldcPoolHelper);
       
   953         fat = typeHelper.tag(ldcPoolHelper.type).width() == 2;
       
   954         return super.ldc(index, ldcPoolHelper.type, fat);
       
   955     }
       
   956     //where
       
   957         class LdcPoolHelper implements PoolHelper<S, T, E> {
       
   958 
       
   959             T type;
       
   960 
       
   961             @Override
       
   962             public int putClass(S symbol) {
       
   963                 type = typeHelper.type(symbol);
       
   964                 return poolHelper.putClass(symbol);
       
   965             }
       
   966 
       
   967             @Override
       
   968             public int putInt(int i) {
       
   969                 type = typeHelper.fromTag(TypeTag.I);
       
   970                 return poolHelper.putInt(i);
       
   971             }
       
   972 
       
   973             @Override
       
   974             public int putFloat(float f) {
       
   975                 type = typeHelper.fromTag(TypeTag.F);
       
   976                 return poolHelper.putFloat(f);
       
   977             }
       
   978 
       
   979             @Override
       
   980             public int putLong(long l) {
       
   981                 type = typeHelper.fromTag(TypeTag.J);
       
   982                 return poolHelper.putLong(l);
       
   983             }
       
   984 
       
   985             @Override
       
   986             public int putDouble(double d) {
       
   987                 type = typeHelper.fromTag(TypeTag.D);
       
   988                 return poolHelper.putDouble(d);
       
   989             }
       
   990 
       
   991             @Override
       
   992             public int putString(String s) {
       
   993                 type = typeHelper.type(typeHelper.symbolFrom("java/lang/String"));
       
   994                 return poolHelper.putString(s);
       
   995             }
       
   996 
       
   997             @Override
       
   998             public int putDynamicConstant(CharSequence constName, T constType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, E>> staticArgs) {
       
   999                 type = constType;
       
  1000                 return poolHelper.putDynamicConstant(constName, constType, bsmClass, bsmName, bsmType, staticArgs);
       
  1001             }
       
  1002 
       
  1003             @Override
       
  1004             public int putFieldRef(S owner, CharSequence name, T type) {
       
  1005                 throw new IllegalStateException();
       
  1006             }
       
  1007 
       
  1008             @Override
       
  1009             public int putMethodRef(S owner, CharSequence name, T type, boolean isInterface) {
       
  1010                 throw new IllegalStateException();
       
  1011             }
       
  1012 
       
  1013             @Override
       
  1014             public int putUtf8(CharSequence s) {
       
  1015                 throw new IllegalStateException();
       
  1016             }
       
  1017 
       
  1018             @Override
       
  1019             public int putType(T t) {
       
  1020                 throw new IllegalStateException();
       
  1021             }
       
  1022 
       
  1023             @Override
       
  1024             public int putMethodType(T t) {
       
  1025                 type = typeHelper.type(typeHelper.symbolFrom("java/lang/invoke/MethodType"));
       
  1026                 return poolHelper.putMethodType(t);
       
  1027             }
       
  1028 
       
  1029             @Override
       
  1030             public int putHandle(int refKind, S owner, CharSequence name, T t) {
       
  1031                 type = typeHelper.type(typeHelper.symbolFrom("java/lang/invoke/MethodHandle"));
       
  1032                 return poolHelper.putHandle(refKind, owner, name, t);
       
  1033             }
       
  1034 
       
  1035             @Override
       
  1036             public int putInvokeDynamic(CharSequence invokedName, T invokedType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, E>> staticArgs) {
       
  1037                 throw new IllegalStateException();
       
  1038             }
       
  1039 
       
  1040             @Override
       
  1041             public int size() {
       
  1042                 throw new IllegalStateException();
       
  1043             }
       
  1044 
       
  1045             @Override
       
  1046             public E entries() {
       
  1047                 throw new IllegalStateException();
       
  1048             }
       
  1049     }
       
  1050 
       
  1051     public C load(int index) {
       
  1052         return load(typeHelper.tag(state.locals.get(index)), index);
       
  1053     }
       
  1054 
       
  1055     public C store(int index) {
       
  1056         return store(typeHelper.tag(state.tosType()), index);
       
  1057     }
       
  1058 
       
  1059     @Override
       
  1060     public C withLocalSize(int localsize) {
       
  1061         throw new IllegalStateException("Local size automatically computed");
       
  1062     }
       
  1063 
       
  1064     @Override
       
  1065     public C withStackSize(int stacksize) {
       
  1066         throw new IllegalStateException("Stack size automatically computed");
       
  1067     }
       
  1068 
       
  1069     public C withLocal(CharSequence name, T type) {
       
  1070         int offset = currLocalOffset;
       
  1071         TypeTag tag = typeHelper.tag(type);
       
  1072         lvarOffsets.put(name, new LocalVarInfo(name, offset, depth, tag));
       
  1073         state.load(type, offset);
       
  1074         currLocalOffset += tag.width;
       
  1075         return thisBuilder();
       
  1076     }
       
  1077 
       
  1078     public C load(CharSequence local) {
       
  1079         return load(lvarOffsets.get(local).offset);
       
  1080     }
       
  1081 
       
  1082     public C store(CharSequence local) {
       
  1083         return store(lvarOffsets.get(local).offset);
       
  1084     }
       
  1085 
       
  1086     @Override
       
  1087     public C withTry(Consumer<? super C> tryBlock, Consumer<? super CatchBuilder> catchBlocks) {
       
  1088         return super.withTry(c -> {
       
  1089             withLocalScope(() -> {
       
  1090                 tryBlock.accept(c);
       
  1091             });
       
  1092         }, catchBlocks);
       
  1093     }
       
  1094 
       
  1095     @Override
       
  1096     protected CatchBuilder makeCatchBuilder(int start, int end) {
       
  1097         return new TypedCatchBuilder(start, end);
       
  1098     }
       
  1099 
       
  1100     class TypedCatchBuilder extends CatchBuilder {
       
  1101 
       
  1102         State initialState = state.dup();
       
  1103 
       
  1104         TypedCatchBuilder(int start, int end) {
       
  1105             super(start, end);
       
  1106         }
       
  1107 
       
  1108         @Override
       
  1109         protected void emitCatch(S exc, Consumer<? super C> catcher) {
       
  1110             withLocalScope(() -> {
       
  1111                 state.push(typeHelper.type(exc));
       
  1112                 emitStackMap(code.offset);
       
  1113                 super.emitCatch(exc, catcher);
       
  1114                 state = initialState;
       
  1115             });
       
  1116         }
       
  1117 
       
  1118         @Override
       
  1119         protected void emitFinalizer() {
       
  1120             withLocalScope(() -> {
       
  1121                 state.push(typeHelper.type(typeHelper.symbolFrom("java/lang/Throwable")));
       
  1122                 emitStackMap(code.offset);
       
  1123                 super.emitFinalizer();
       
  1124             });
       
  1125         }
       
  1126     }
       
  1127 
       
  1128     protected void withLocalScope(Runnable runnable) {
       
  1129         int prevDepth = depth;
       
  1130         try {
       
  1131             depth++;
       
  1132             runnable.run();
       
  1133         } finally {
       
  1134             Iterator<Entry<CharSequence, LocalVarInfo>> lvarIt = lvarOffsets.entrySet().iterator();
       
  1135             while (lvarIt.hasNext()) {
       
  1136                 LocalVarInfo lvi = lvarIt.next().getValue();
       
  1137                 if (lvi.depth == depth) {
       
  1138                     int width = lvi.type.width;
       
  1139                     currLocalOffset -= width;
       
  1140                     lvarIt.remove();
       
  1141                 }
       
  1142             }
       
  1143             depth = prevDepth;
       
  1144         }
       
  1145     }
       
  1146 
       
  1147     @Override
       
  1148     void addPendingJump(CharSequence label, int pc) {
       
  1149         pendingJumps.add(new StatefulPendingJump(label, pc, state.dup()));
       
  1150     }
       
  1151 
       
  1152     @Override
       
  1153     void resolveJumps(CharSequence label, int pc) {
       
  1154         super.resolveJumps(label, pc);
       
  1155         emitStackMap(pc);
       
  1156     }
       
  1157 
       
  1158     //TODO: optimize stackmap generation by avoiding intermediate classes
       
  1159     protected void emitStackMap(int pc) {
       
  1160         //stack map generation
       
  1161         if (pc > lastStackMapPc) {
       
  1162             writeStackMapFrame(pc);
       
  1163             lastStackMapState = state.dup();
       
  1164             lastStackMapPc = pc;
       
  1165             nstackmaps++;
       
  1166         }
       
  1167     }
       
  1168 
       
  1169     @Override
       
  1170     void build(GrowableByteBuffer buf) {
       
  1171         if (stacksize == -1) {
       
  1172             throw new IllegalStateException("Bad stack size");
       
  1173         }
       
  1174         if (localsize == -1) {
       
  1175             throw new IllegalStateException("Bad locals size");
       
  1176         }
       
  1177         if (nstackmaps > 0) {
       
  1178             GrowableByteBuffer stackmapsAttr = new GrowableByteBuffer();
       
  1179             stackmapsAttr.writeChar(nstackmaps);
       
  1180             stackmapsAttr.writeBytes(stackmaps);
       
  1181             withAttribute("StackMapTable", stackmapsAttr.bytes());
       
  1182         }
       
  1183         super.build(buf);
       
  1184     }
       
  1185 
       
  1186     /**
       
  1187      * Compare this frame with the previous frame and produce
       
  1188      * an entry of compressed stack map frame.
       
  1189      */
       
  1190     void writeStackMapFrame(int pc) {
       
  1191         List<T> locals = state.locals;
       
  1192         List<T> stack = state.stack;
       
  1193         List<T> prev_locals = lastStackMapState.locals;
       
  1194         int offset_delta = lastStackMapPc == -1 ? pc : pc - lastStackMapPc - 1;
       
  1195         if (stack.size() == 1) {
       
  1196             if (locals.size() == prev_locals.size() && prev_locals.equals(locals)) {
       
  1197                 sameLocals1StackItemFrame(offset_delta, stack.get(stack.size() - 1));
       
  1198                 return;
       
  1199             }
       
  1200         } else if (stack.size() == 0) {
       
  1201             int diff_length = prev_locals.size() - locals.size();
       
  1202             if (diff_length == 0) {
       
  1203                 sameFrame(offset_delta);
       
  1204                 return;
       
  1205             } else if (-MAX_LOCAL_LENGTH_DIFF < diff_length && diff_length < 0) {
       
  1206                 appendFrame(offset_delta, prev_locals.size(), locals);
       
  1207                 return;
       
  1208             } else if (0 < diff_length && diff_length < MAX_LOCAL_LENGTH_DIFF) {
       
  1209                 chopFrame(offset_delta, diff_length);
       
  1210                 return;
       
  1211             }
       
  1212         }
       
  1213         fullFrame(offset_delta, locals, stack);
       
  1214     }
       
  1215 }