jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java
changeset 25859 3317bb8137f4
parent 24572 5c9e5961d21c
child 26467 d69abed3a07d
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 2008, 2013, 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 java.lang.invoke;
       
    27 
       
    28 import static jdk.internal.org.objectweb.asm.Opcodes.*;
       
    29 import static java.lang.invoke.LambdaForm.*;
       
    30 import static java.lang.invoke.LambdaForm.BasicType.*;
       
    31 import static java.lang.invoke.MethodHandleStatics.*;
       
    32 
       
    33 import java.lang.invoke.LambdaForm.NamedFunction;
       
    34 import java.lang.invoke.MethodHandles.Lookup;
       
    35 import java.lang.reflect.Field;
       
    36 import java.util.Arrays;
       
    37 import java.util.HashMap;
       
    38 
       
    39 import sun.invoke.util.ValueConversions;
       
    40 import sun.invoke.util.Wrapper;
       
    41 
       
    42 import jdk.internal.org.objectweb.asm.ClassWriter;
       
    43 import jdk.internal.org.objectweb.asm.MethodVisitor;
       
    44 import jdk.internal.org.objectweb.asm.Type;
       
    45 
       
    46 /**
       
    47  * The flavor of method handle which emulates an invoke instruction
       
    48  * on a predetermined argument.  The JVM dispatches to the correct method
       
    49  * when the handle is created, not when it is invoked.
       
    50  *
       
    51  * All bound arguments are encapsulated in dedicated species.
       
    52  */
       
    53 /* non-public */ abstract class BoundMethodHandle extends MethodHandle {
       
    54 
       
    55     /* non-public */ BoundMethodHandle(MethodType type, LambdaForm form) {
       
    56         super(type, form);
       
    57     }
       
    58 
       
    59     //
       
    60     // BMH API and internals
       
    61     //
       
    62 
       
    63     static MethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) {
       
    64         // for some type signatures, there exist pre-defined concrete BMH classes
       
    65         try {
       
    66             switch (xtype) {
       
    67             case L_TYPE:
       
    68                 if (true)  return bindSingle(type, form, x);  // Use known fast path.
       
    69                 return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(L_TYPE).constructor[0].invokeBasic(type, form, x);
       
    70             case I_TYPE:
       
    71                 return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
       
    72             case J_TYPE:
       
    73                 return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(J_TYPE).constructor[0].invokeBasic(type, form, (long) x);
       
    74             case F_TYPE:
       
    75                 return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(F_TYPE).constructor[0].invokeBasic(type, form, (float) x);
       
    76             case D_TYPE:
       
    77                 return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(D_TYPE).constructor[0].invokeBasic(type, form, (double) x);
       
    78             default : throw newInternalError("unexpected xtype: " + xtype);
       
    79             }
       
    80         } catch (Throwable t) {
       
    81             throw newInternalError(t);
       
    82         }
       
    83     }
       
    84 
       
    85     static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
       
    86             return new Species_L(type, form, x);
       
    87     }
       
    88 
       
    89     MethodHandle cloneExtend(MethodType type, LambdaForm form, BasicType xtype, Object x) {
       
    90         try {
       
    91             switch (xtype) {
       
    92             case L_TYPE: return copyWithExtendL(type, form, x);
       
    93             case I_TYPE: return copyWithExtendI(type, form, ValueConversions.widenSubword(x));
       
    94             case J_TYPE: return copyWithExtendJ(type, form, (long) x);
       
    95             case F_TYPE: return copyWithExtendF(type, form, (float) x);
       
    96             case D_TYPE: return copyWithExtendD(type, form, (double) x);
       
    97             }
       
    98         } catch (Throwable t) {
       
    99             throw newInternalError(t);
       
   100         }
       
   101         throw newInternalError("unexpected type: " + xtype);
       
   102     }
       
   103 
       
   104     @Override
       
   105     MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
       
   106         MethodType type = type().dropParameterTypes(pos, pos+1);
       
   107         LambdaForm form = internalForm().bind(1+pos, speciesData());
       
   108         return cloneExtend(type, form, basicType, value);
       
   109     }
       
   110 
       
   111     @Override
       
   112     MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
       
   113         LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos + drops));
       
   114         try {
       
   115              return copyWith(srcType, form);
       
   116          } catch (Throwable t) {
       
   117              throw newInternalError(t);
       
   118          }
       
   119     }
       
   120 
       
   121     @Override
       
   122     MethodHandle permuteArguments(MethodType newType, int[] reorder) {
       
   123         try {
       
   124              return copyWith(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
       
   125          } catch (Throwable t) {
       
   126              throw newInternalError(t);
       
   127          }
       
   128     }
       
   129 
       
   130     /**
       
   131      * Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
       
   132      * static field containing this value, and they must accordingly implement this method.
       
   133      */
       
   134     /*non-public*/ abstract SpeciesData speciesData();
       
   135 
       
   136     /**
       
   137      * Return the number of fields in this BMH.  Equivalent to speciesData().fieldCount().
       
   138      */
       
   139     /*non-public*/ abstract int fieldCount();
       
   140 
       
   141     @Override
       
   142     final Object internalProperties() {
       
   143         return "/BMH="+internalValues();
       
   144     }
       
   145 
       
   146     @Override
       
   147     final Object internalValues() {
       
   148         Object[] boundValues = new Object[speciesData().fieldCount()];
       
   149         for (int i = 0; i < boundValues.length; ++i) {
       
   150             boundValues[i] = arg(i);
       
   151         }
       
   152         return Arrays.asList(boundValues);
       
   153     }
       
   154 
       
   155     /*non-public*/ final Object arg(int i) {
       
   156         try {
       
   157             switch (speciesData().fieldType(i)) {
       
   158             case L_TYPE: return          speciesData().getters[i].invokeBasic(this);
       
   159             case I_TYPE: return (int)    speciesData().getters[i].invokeBasic(this);
       
   160             case J_TYPE: return (long)   speciesData().getters[i].invokeBasic(this);
       
   161             case F_TYPE: return (float)  speciesData().getters[i].invokeBasic(this);
       
   162             case D_TYPE: return (double) speciesData().getters[i].invokeBasic(this);
       
   163             }
       
   164         } catch (Throwable ex) {
       
   165             throw newInternalError(ex);
       
   166         }
       
   167         throw new InternalError("unexpected type: " + speciesData().typeChars+"."+i);
       
   168     }
       
   169 
       
   170     //
       
   171     // cloning API
       
   172     //
       
   173 
       
   174     /*non-public*/ abstract BoundMethodHandle copyWith(MethodType mt, LambdaForm lf);
       
   175     /*non-public*/ abstract BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg);
       
   176     /*non-public*/ abstract BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int    narg);
       
   177     /*non-public*/ abstract BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long   narg);
       
   178     /*non-public*/ abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float  narg);
       
   179     /*non-public*/ abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg);
       
   180 
       
   181     // The following is a grossly irregular hack:
       
   182     @Override MethodHandle reinvokerTarget() {
       
   183         try {
       
   184             return (MethodHandle) arg(0);
       
   185         } catch (Throwable ex) {
       
   186             throw newInternalError(ex);
       
   187         }
       
   188     }
       
   189 
       
   190     //
       
   191     // concrete BMH classes required to close bootstrap loops
       
   192     //
       
   193 
       
   194     private  // make it private to force users to access the enclosing class first
       
   195     static final class Species_L extends BoundMethodHandle {
       
   196         final Object argL0;
       
   197         private Species_L(MethodType mt, LambdaForm lf, Object argL0) {
       
   198             super(mt, lf);
       
   199             this.argL0 = argL0;
       
   200         }
       
   201         // The following is a grossly irregular hack:
       
   202         @Override MethodHandle reinvokerTarget() { return (MethodHandle) argL0; }
       
   203         @Override
       
   204         /*non-public*/ SpeciesData speciesData() {
       
   205             return SPECIES_DATA;
       
   206         }
       
   207         @Override
       
   208         /*non-public*/ int fieldCount() {
       
   209             return 1;
       
   210         }
       
   211         /*non-public*/ static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
       
   212         /*non-public*/ static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
       
   213             return new Species_L(mt, lf, argL0);
       
   214         }
       
   215         @Override
       
   216         /*non-public*/ final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
       
   217             return new Species_L(mt, lf, argL0);
       
   218         }
       
   219         @Override
       
   220         /*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
       
   221             try {
       
   222                 return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
       
   223             } catch (Throwable ex) {
       
   224                 throw uncaughtException(ex);
       
   225             }
       
   226         }
       
   227         @Override
       
   228         /*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
       
   229             try {
       
   230                 return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
       
   231             } catch (Throwable ex) {
       
   232                 throw uncaughtException(ex);
       
   233             }
       
   234         }
       
   235         @Override
       
   236         /*non-public*/ final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
       
   237             try {
       
   238                 return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
       
   239             } catch (Throwable ex) {
       
   240                 throw uncaughtException(ex);
       
   241             }
       
   242         }
       
   243         @Override
       
   244         /*non-public*/ final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
       
   245             try {
       
   246                 return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
       
   247             } catch (Throwable ex) {
       
   248                 throw uncaughtException(ex);
       
   249             }
       
   250         }
       
   251         @Override
       
   252         /*non-public*/ final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
       
   253             try {
       
   254                 return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
       
   255             } catch (Throwable ex) {
       
   256                 throw uncaughtException(ex);
       
   257             }
       
   258         }
       
   259     }
       
   260 
       
   261     //
       
   262     // BMH species meta-data
       
   263     //
       
   264 
       
   265     /**
       
   266      * Meta-data wrapper for concrete BMH types.
       
   267      * Each BMH type corresponds to a given sequence of basic field types (LIJFD).
       
   268      * The fields are immutable; their values are fully specified at object construction.
       
   269      * Each BMH type supplies an array of getter functions which may be used in lambda forms.
       
   270      * A BMH is constructed by cloning a shorter BMH and adding one or more new field values.
       
   271      * As a degenerate and common case, the "shorter BMH" can be missing, and contributes zero prior fields.
       
   272      */
       
   273     static class SpeciesData {
       
   274         final String                             typeChars;
       
   275         final BasicType[]                        typeCodes;
       
   276         final Class<? extends BoundMethodHandle> clazz;
       
   277         // Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
       
   278         // Therefore, we need a non-final link in the chain.  Use array elements.
       
   279         final MethodHandle[]                     constructor;
       
   280         final MethodHandle[]                     getters;
       
   281         final NamedFunction[]                    nominalGetters;
       
   282         final SpeciesData[]                      extensions;
       
   283 
       
   284         /*non-public*/ int fieldCount() {
       
   285             return typeCodes.length;
       
   286         }
       
   287         /*non-public*/ BasicType fieldType(int i) {
       
   288             return typeCodes[i];
       
   289         }
       
   290         /*non-public*/ char fieldTypeChar(int i) {
       
   291             return typeChars.charAt(i);
       
   292         }
       
   293 
       
   294         public String toString() {
       
   295             return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+typeChars+"]";
       
   296         }
       
   297 
       
   298         /**
       
   299          * Return a {@link LambdaForm.Name} containing a {@link LambdaForm.NamedFunction} that
       
   300          * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
       
   301          * getter.
       
   302          */
       
   303         NamedFunction getterFunction(int i) {
       
   304             return nominalGetters[i];
       
   305         }
       
   306 
       
   307         static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
       
   308 
       
   309         private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
       
   310             this.typeChars = types;
       
   311             this.typeCodes = basicTypes(types);
       
   312             this.clazz = clazz;
       
   313             if (!INIT_DONE) {
       
   314                 this.constructor = new MethodHandle[1];  // only one ctor
       
   315                 this.getters = new MethodHandle[types.length()];
       
   316                 this.nominalGetters = new NamedFunction[types.length()];
       
   317             } else {
       
   318                 this.constructor = Factory.makeCtors(clazz, types, null);
       
   319                 this.getters = Factory.makeGetters(clazz, types, null);
       
   320                 this.nominalGetters = Factory.makeNominalGetters(types, null, this.getters);
       
   321             }
       
   322             this.extensions = new SpeciesData[ARG_TYPE_LIMIT];
       
   323         }
       
   324 
       
   325         private void initForBootstrap() {
       
   326             assert(!INIT_DONE);
       
   327             if (constructor[0] == null) {
       
   328                 String types = typeChars;
       
   329                 Factory.makeCtors(clazz, types, this.constructor);
       
   330                 Factory.makeGetters(clazz, types, this.getters);
       
   331                 Factory.makeNominalGetters(types, this.nominalGetters, this.getters);
       
   332             }
       
   333         }
       
   334 
       
   335         private SpeciesData(String typeChars) {
       
   336             // Placeholder only.
       
   337             this.typeChars = typeChars;
       
   338             this.typeCodes = basicTypes(typeChars);
       
   339             this.clazz = null;
       
   340             this.constructor = null;
       
   341             this.getters = null;
       
   342             this.nominalGetters = null;
       
   343             this.extensions = null;
       
   344         }
       
   345         private boolean isPlaceholder() { return clazz == null; }
       
   346 
       
   347         private static final HashMap<String, SpeciesData> CACHE = new HashMap<>();
       
   348         static { CACHE.put("", EMPTY); }  // make bootstrap predictable
       
   349         private static final boolean INIT_DONE;  // set after <clinit> finishes...
       
   350 
       
   351         SpeciesData extendWith(byte type) {
       
   352             return extendWith(BasicType.basicType(type));
       
   353         }
       
   354 
       
   355         SpeciesData extendWith(BasicType type) {
       
   356             int ord = type.ordinal();
       
   357             SpeciesData d = extensions[ord];
       
   358             if (d != null)  return d;
       
   359             extensions[ord] = d = get(typeChars+type.basicTypeChar());
       
   360             return d;
       
   361         }
       
   362 
       
   363         private static SpeciesData get(String types) {
       
   364             // Acquire cache lock for query.
       
   365             SpeciesData d = lookupCache(types);
       
   366             if (!d.isPlaceholder())
       
   367                 return d;
       
   368             synchronized (d) {
       
   369                 // Use synch. on the placeholder to prevent multiple instantiation of one species.
       
   370                 // Creating this class forces a recursive call to getForClass.
       
   371                 if (lookupCache(types).isPlaceholder())
       
   372                     Factory.generateConcreteBMHClass(types);
       
   373             }
       
   374             // Reacquire cache lock.
       
   375             d = lookupCache(types);
       
   376             // Class loading must have upgraded the cache.
       
   377             assert(d != null && !d.isPlaceholder());
       
   378             return d;
       
   379         }
       
   380         static SpeciesData getForClass(String types, Class<? extends BoundMethodHandle> clazz) {
       
   381             // clazz is a new class which is initializing its SPECIES_DATA field
       
   382             return updateCache(types, new SpeciesData(types, clazz));
       
   383         }
       
   384         private static synchronized SpeciesData lookupCache(String types) {
       
   385             SpeciesData d = CACHE.get(types);
       
   386             if (d != null)  return d;
       
   387             d = new SpeciesData(types);
       
   388             assert(d.isPlaceholder());
       
   389             CACHE.put(types, d);
       
   390             return d;
       
   391         }
       
   392         private static synchronized SpeciesData updateCache(String types, SpeciesData d) {
       
   393             SpeciesData d2;
       
   394             assert((d2 = CACHE.get(types)) == null || d2.isPlaceholder());
       
   395             assert(!d.isPlaceholder());
       
   396             CACHE.put(types, d);
       
   397             return d;
       
   398         }
       
   399 
       
   400         static {
       
   401             // pre-fill the BMH speciesdata cache with BMH's inner classes
       
   402             final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
       
   403             try {
       
   404                 for (Class<?> c : rootCls.getDeclaredClasses()) {
       
   405                     if (rootCls.isAssignableFrom(c)) {
       
   406                         final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
       
   407                         SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
       
   408                         assert(d != null) : cbmh.getName();
       
   409                         assert(d.clazz == cbmh);
       
   410                         assert(d == lookupCache(d.typeChars));
       
   411                     }
       
   412                 }
       
   413             } catch (Throwable e) {
       
   414                 throw newInternalError(e);
       
   415             }
       
   416 
       
   417             for (SpeciesData d : CACHE.values()) {
       
   418                 d.initForBootstrap();
       
   419             }
       
   420             // Note:  Do not simplify this, because INIT_DONE must not be
       
   421             // a compile-time constant during bootstrapping.
       
   422             INIT_DONE = Boolean.TRUE;
       
   423         }
       
   424     }
       
   425 
       
   426     static SpeciesData getSpeciesData(String types) {
       
   427         return SpeciesData.get(types);
       
   428     }
       
   429 
       
   430     /**
       
   431      * Generation of concrete BMH classes.
       
   432      *
       
   433      * A concrete BMH species is fit for binding a number of values adhering to a
       
   434      * given type pattern. Reference types are erased.
       
   435      *
       
   436      * BMH species are cached by type pattern.
       
   437      *
       
   438      * A BMH species has a number of fields with the concrete (possibly erased) types of
       
   439      * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs,
       
   440      * which can be included as names in lambda forms.
       
   441      */
       
   442     static class Factory {
       
   443 
       
   444         static final String JLO_SIG  = "Ljava/lang/Object;";
       
   445         static final String JLS_SIG  = "Ljava/lang/String;";
       
   446         static final String JLC_SIG  = "Ljava/lang/Class;";
       
   447         static final String MH       = "java/lang/invoke/MethodHandle";
       
   448         static final String MH_SIG   = "L"+MH+";";
       
   449         static final String BMH      = "java/lang/invoke/BoundMethodHandle";
       
   450         static final String BMH_SIG  = "L"+BMH+";";
       
   451         static final String SPECIES_DATA     = "java/lang/invoke/BoundMethodHandle$SpeciesData";
       
   452         static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
       
   453 
       
   454         static final String SPECIES_PREFIX_NAME = "Species_";
       
   455         static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
       
   456 
       
   457         static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
       
   458         static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
       
   459         static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
       
   460         static final String VOID_SIG   = "()V";
       
   461         static final String INT_SIG    = "()I";
       
   462 
       
   463         static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
       
   464 
       
   465         static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
       
   466 
       
   467         /**
       
   468          * Generate a concrete subclass of BMH for a given combination of bound types.
       
   469          *
       
   470          * A concrete BMH species adheres to the following schema:
       
   471          *
       
   472          * <pre>
       
   473          * class Species_[[types]] extends BoundMethodHandle {
       
   474          *     [[fields]]
       
   475          *     final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
       
   476          * }
       
   477          * </pre>
       
   478          *
       
   479          * The {@code [[types]]} signature is precisely the string that is passed to this
       
   480          * method.
       
   481          *
       
   482          * The {@code [[fields]]} section consists of one field definition per character in
       
   483          * the type signature, adhering to the naming schema described in the definition of
       
   484          * {@link #makeFieldName}.
       
   485          *
       
   486          * For example, a concrete BMH species for two reference and one integral bound values
       
   487          * would have the following shape:
       
   488          *
       
   489          * <pre>
       
   490          * class BoundMethodHandle { ... private static
       
   491          * final class Species_LLI extends BoundMethodHandle {
       
   492          *     final Object argL0;
       
   493          *     final Object argL1;
       
   494          *     final int argI2;
       
   495          *     private Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
       
   496          *         super(mt, lf);
       
   497          *         this.argL0 = argL0;
       
   498          *         this.argL1 = argL1;
       
   499          *         this.argI2 = argI2;
       
   500          *     }
       
   501          *     final SpeciesData speciesData() { return SPECIES_DATA; }
       
   502          *     final int fieldCount() { return 3; }
       
   503          *     static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
       
   504          *     static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
       
   505          *         return new Species_LLI(mt, lf, argL0, argL1, argI2);
       
   506          *     }
       
   507          *     final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
       
   508          *         return new Species_LLI(mt, lf, argL0, argL1, argI2);
       
   509          *     }
       
   510          *     final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
       
   511          *         return SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
       
   512          *     }
       
   513          *     final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
       
   514          *         return SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
       
   515          *     }
       
   516          *     final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
       
   517          *         return SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
       
   518          *     }
       
   519          *     final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
       
   520          *         return SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
       
   521          *     }
       
   522          *     public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
       
   523          *         return SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
       
   524          *     }
       
   525          * }
       
   526          * </pre>
       
   527          *
       
   528          * @param types the type signature, wherein reference types are erased to 'L'
       
   529          * @return the generated concrete BMH class
       
   530          */
       
   531         static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
       
   532             final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
       
   533 
       
   534             String shortTypes = LambdaForm.shortenSignature(types);
       
   535             final String className  = SPECIES_PREFIX_PATH + shortTypes;
       
   536             final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
       
   537             final int NOT_ACC_PUBLIC = 0;  // not ACC_PUBLIC
       
   538             cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
       
   539             cw.visitSource(sourceFile, null);
       
   540 
       
   541             // emit static types and SPECIES_DATA fields
       
   542             cw.visitField(NOT_ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null).visitEnd();
       
   543 
       
   544             // emit bound argument fields
       
   545             for (int i = 0; i < types.length(); ++i) {
       
   546                 final char t = types.charAt(i);
       
   547                 final String fieldName = makeFieldName(types, i);
       
   548                 final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
       
   549                 cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
       
   550             }
       
   551 
       
   552             MethodVisitor mv;
       
   553 
       
   554             // emit constructor
       
   555             mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
       
   556             mv.visitCode();
       
   557             mv.visitVarInsn(ALOAD, 0); // this
       
   558             mv.visitVarInsn(ALOAD, 1); // type
       
   559             mv.visitVarInsn(ALOAD, 2); // form
       
   560 
       
   561             mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false);
       
   562 
       
   563             for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
       
   564                 // i counts the arguments, j counts corresponding argument slots
       
   565                 char t = types.charAt(i);
       
   566                 mv.visitVarInsn(ALOAD, 0);
       
   567                 mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
       
   568                 mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
       
   569                 if (t == 'J' || t == 'D') {
       
   570                     ++j; // adjust argument register access
       
   571                 }
       
   572             }
       
   573 
       
   574             mv.visitInsn(RETURN);
       
   575             mv.visitMaxs(0, 0);
       
   576             mv.visitEnd();
       
   577 
       
   578             // emit implementation of reinvokerTarget()
       
   579             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "reinvokerTarget", "()" + MH_SIG, null, null);
       
   580             mv.visitCode();
       
   581             mv.visitVarInsn(ALOAD, 0);
       
   582             mv.visitFieldInsn(GETFIELD, className, "argL0", JLO_SIG);
       
   583             mv.visitTypeInsn(CHECKCAST, MH);
       
   584             mv.visitInsn(ARETURN);
       
   585             mv.visitMaxs(0, 0);
       
   586             mv.visitEnd();
       
   587 
       
   588             // emit implementation of speciesData()
       
   589             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
       
   590             mv.visitCode();
       
   591             mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
       
   592             mv.visitInsn(ARETURN);
       
   593             mv.visitMaxs(0, 0);
       
   594             mv.visitEnd();
       
   595 
       
   596             // emit implementation of fieldCount()
       
   597             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "fieldCount", INT_SIG, null, null);
       
   598             mv.visitCode();
       
   599             int fc = types.length();
       
   600             if (fc <= (ICONST_5 - ICONST_0)) {
       
   601                 mv.visitInsn(ICONST_0 + fc);
       
   602             } else {
       
   603                 mv.visitIntInsn(SIPUSH, fc);
       
   604             }
       
   605             mv.visitInsn(IRETURN);
       
   606             mv.visitMaxs(0, 0);
       
   607             mv.visitEnd();
       
   608             // emit make()  ...factory method wrapping constructor
       
   609             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_STATIC, "make", makeSignature(types, false), null, null);
       
   610             mv.visitCode();
       
   611             // make instance
       
   612             mv.visitTypeInsn(NEW, className);
       
   613             mv.visitInsn(DUP);
       
   614             // load mt, lf
       
   615             mv.visitVarInsn(ALOAD, 0);  // type
       
   616             mv.visitVarInsn(ALOAD, 1);  // form
       
   617             // load factory method arguments
       
   618             for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
       
   619                 // i counts the arguments, j counts corresponding argument slots
       
   620                 char t = types.charAt(i);
       
   621                 mv.visitVarInsn(typeLoadOp(t), j + 2); // parameters start at 3
       
   622                 if (t == 'J' || t == 'D') {
       
   623                     ++j; // adjust argument register access
       
   624                 }
       
   625             }
       
   626 
       
   627             // finally, invoke the constructor and return
       
   628             mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
       
   629             mv.visitInsn(ARETURN);
       
   630             mv.visitMaxs(0, 0);
       
   631             mv.visitEnd();
       
   632 
       
   633             // emit copyWith()
       
   634             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWith", makeSignature("", false), null, null);
       
   635             mv.visitCode();
       
   636             // make instance
       
   637             mv.visitTypeInsn(NEW, className);
       
   638             mv.visitInsn(DUP);
       
   639             // load mt, lf
       
   640             mv.visitVarInsn(ALOAD, 1);
       
   641             mv.visitVarInsn(ALOAD, 2);
       
   642             // put fields on the stack
       
   643             emitPushFields(types, className, mv);
       
   644             // finally, invoke the constructor and return
       
   645             mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
       
   646             mv.visitInsn(ARETURN);
       
   647             mv.visitMaxs(0, 0);
       
   648             mv.visitEnd();
       
   649 
       
   650             // for each type, emit copyWithExtendT()
       
   651             for (BasicType type : BasicType.ARG_TYPES) {
       
   652                 int ord = type.ordinal();
       
   653                 char btChar = type.basicTypeChar();
       
   654                 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE);
       
   655                 mv.visitCode();
       
   656                 // return SPECIES_DATA.extendWith(t).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
       
   657                 // obtain constructor
       
   658                 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
       
   659                 int iconstInsn = ICONST_0 + ord;
       
   660                 assert(iconstInsn <= ICONST_5);
       
   661                 mv.visitInsn(iconstInsn);
       
   662                 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false);
       
   663                 mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
       
   664                 mv.visitInsn(ICONST_0);
       
   665                 mv.visitInsn(AALOAD);
       
   666                 // load mt, lf
       
   667                 mv.visitVarInsn(ALOAD, 1);
       
   668                 mv.visitVarInsn(ALOAD, 2);
       
   669                 // put fields on the stack
       
   670                 emitPushFields(types, className, mv);
       
   671                 // put narg on stack
       
   672                 mv.visitVarInsn(typeLoadOp(btChar), 3);
       
   673                 // finally, invoke the constructor and return
       
   674                 mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + btChar, false), false);
       
   675                 mv.visitInsn(ARETURN);
       
   676                 mv.visitMaxs(0, 0);
       
   677                 mv.visitEnd();
       
   678             }
       
   679 
       
   680             // emit class initializer
       
   681             mv = cw.visitMethod(NOT_ACC_PUBLIC | ACC_STATIC, "<clinit>", VOID_SIG, null, null);
       
   682             mv.visitCode();
       
   683             mv.visitLdcInsn(types);
       
   684             mv.visitLdcInsn(Type.getObjectType(className));
       
   685             mv.visitMethodInsn(INVOKESTATIC, SPECIES_DATA, "getForClass", BMHSPECIES_DATA_GFC_SIG, false);
       
   686             mv.visitFieldInsn(PUTSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
       
   687             mv.visitInsn(RETURN);
       
   688             mv.visitMaxs(0, 0);
       
   689             mv.visitEnd();
       
   690 
       
   691             cw.visitEnd();
       
   692 
       
   693             // load class
       
   694             final byte[] classFile = cw.toByteArray();
       
   695             InvokerBytecodeGenerator.maybeDump(className, classFile);
       
   696             Class<? extends BoundMethodHandle> bmhClass =
       
   697                 //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
       
   698                 UNSAFE.defineClass(className, classFile, 0, classFile.length,
       
   699                                    BoundMethodHandle.class.getClassLoader(), null)
       
   700                     .asSubclass(BoundMethodHandle.class);
       
   701             UNSAFE.ensureClassInitialized(bmhClass);
       
   702 
       
   703             return bmhClass;
       
   704         }
       
   705 
       
   706         private static int typeLoadOp(char t) {
       
   707             switch (t) {
       
   708             case 'L': return ALOAD;
       
   709             case 'I': return ILOAD;
       
   710             case 'J': return LLOAD;
       
   711             case 'F': return FLOAD;
       
   712             case 'D': return DLOAD;
       
   713             default : throw newInternalError("unrecognized type " + t);
       
   714             }
       
   715         }
       
   716 
       
   717         private static void emitPushFields(String types, String className, MethodVisitor mv) {
       
   718             for (int i = 0; i < types.length(); ++i) {
       
   719                 char tc = types.charAt(i);
       
   720                 mv.visitVarInsn(ALOAD, 0);
       
   721                 mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
       
   722             }
       
   723         }
       
   724 
       
   725         static String typeSig(char t) {
       
   726             return t == 'L' ? JLO_SIG : String.valueOf(t);
       
   727         }
       
   728 
       
   729         //
       
   730         // Getter MH generation.
       
   731         //
       
   732 
       
   733         private static MethodHandle makeGetter(Class<?> cbmhClass, String types, int index) {
       
   734             String fieldName = makeFieldName(types, index);
       
   735             Class<?> fieldType = Wrapper.forBasicType(types.charAt(index)).primitiveType();
       
   736             try {
       
   737                 return LOOKUP.findGetter(cbmhClass, fieldName, fieldType);
       
   738             } catch (NoSuchFieldException | IllegalAccessException e) {
       
   739                 throw newInternalError(e);
       
   740             }
       
   741         }
       
   742 
       
   743         static MethodHandle[] makeGetters(Class<?> cbmhClass, String types, MethodHandle[] mhs) {
       
   744             if (mhs == null)  mhs = new MethodHandle[types.length()];
       
   745             for (int i = 0; i < mhs.length; ++i) {
       
   746                 mhs[i] = makeGetter(cbmhClass, types, i);
       
   747                 assert(mhs[i].internalMemberName().getDeclaringClass() == cbmhClass);
       
   748             }
       
   749             return mhs;
       
   750         }
       
   751 
       
   752         static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
       
   753             if (mhs == null)  mhs = new MethodHandle[1];
       
   754             if (types.equals(""))  return mhs;  // hack for empty BMH species
       
   755             mhs[0] = makeCbmhCtor(cbmh, types);
       
   756             return mhs;
       
   757         }
       
   758 
       
   759         static NamedFunction[] makeNominalGetters(String types, NamedFunction[] nfs, MethodHandle[] getters) {
       
   760             if (nfs == null)  nfs = new NamedFunction[types.length()];
       
   761             for (int i = 0; i < nfs.length; ++i) {
       
   762                 nfs[i] = new NamedFunction(getters[i]);
       
   763             }
       
   764             return nfs;
       
   765         }
       
   766 
       
   767         //
       
   768         // Auxiliary methods.
       
   769         //
       
   770 
       
   771         static SpeciesData speciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
       
   772             try {
       
   773                 Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
       
   774                 return (SpeciesData) F_SPECIES_DATA.get(null);
       
   775             } catch (ReflectiveOperationException ex) {
       
   776                 throw newInternalError(ex);
       
   777             }
       
   778         }
       
   779 
       
   780         /**
       
   781          * Field names in concrete BMHs adhere to this pattern:
       
   782          * arg + type + index
       
   783          * where type is a single character (L, I, J, F, D).
       
   784          */
       
   785         private static String makeFieldName(String types, int index) {
       
   786             assert index >= 0 && index < types.length();
       
   787             return "arg" + types.charAt(index) + index;
       
   788         }
       
   789 
       
   790         private static String makeSignature(String types, boolean ctor) {
       
   791             StringBuilder buf = new StringBuilder(SIG_INCIPIT);
       
   792             for (char c : types.toCharArray()) {
       
   793                 buf.append(typeSig(c));
       
   794             }
       
   795             return buf.append(')').append(ctor ? "V" : BMH_SIG).toString();
       
   796         }
       
   797 
       
   798         static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
       
   799             try {
       
   800                 return LOOKUP.findStatic(cbmh, "make", MethodType.fromMethodDescriptorString(makeSignature(types, false), null));
       
   801             } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
       
   802                 throw newInternalError(e);
       
   803             }
       
   804         }
       
   805     }
       
   806 
       
   807     private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
       
   808 
       
   809     /**
       
   810      * All subclasses must provide such a value describing their type signature.
       
   811      */
       
   812     static final SpeciesData SPECIES_DATA = SpeciesData.EMPTY;
       
   813 
       
   814     private static final SpeciesData[] SPECIES_DATA_CACHE = new SpeciesData[5];
       
   815     private static SpeciesData checkCache(int size, String types) {
       
   816         int idx = size - 1;
       
   817         SpeciesData data = SPECIES_DATA_CACHE[idx];
       
   818         if (data != null)  return data;
       
   819         SPECIES_DATA_CACHE[idx] = data = getSpeciesData(types);
       
   820         return data;
       
   821     }
       
   822     static SpeciesData speciesData_L()     { return checkCache(1, "L"); }
       
   823     static SpeciesData speciesData_LL()    { return checkCache(2, "LL"); }
       
   824     static SpeciesData speciesData_LLL()   { return checkCache(3, "LLL"); }
       
   825     static SpeciesData speciesData_LLLL()  { return checkCache(4, "LLLL"); }
       
   826     static SpeciesData speciesData_LLLLL() { return checkCache(5, "LLLLL"); }
       
   827 }