jdk/src/share/classes/sun/dyn/MethodTypeImpl.java
changeset 8823 7cd28219a1e4
parent 8717 f75a1efb1412
parent 8822 8145ab9f5f86
child 8824 0762fa26f813
child 9033 a88f5656f05d
equal deleted inserted replaced
8717:f75a1efb1412 8823:7cd28219a1e4
     1 /*
       
     2  * Copyright (c) 2008, 2011, 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 sun.dyn;
       
    27 
       
    28 import java.dyn.*;
       
    29 import sun.dyn.util.Wrapper;
       
    30 import static sun.dyn.MemberName.newIllegalArgumentException;
       
    31 
       
    32 /**
       
    33  * Shared information for a group of method types, which differ
       
    34  * only by reference types, and therefore share a common erasure
       
    35  * and wrapping.
       
    36  * <p>
       
    37  * For an empirical discussion of the structure of method types,
       
    38  * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/">
       
    39  * the thread "Avoiding Boxing" on jvm-languages</a>.
       
    40  * There are approximately 2000 distinct erased method types in the JDK.
       
    41  * There are a little over 10 times that number of unerased types.
       
    42  * No more than half of these are likely to be loaded at once.
       
    43  * @author John Rose
       
    44  */
       
    45 public class MethodTypeImpl {
       
    46     final int[] argToSlotTable, slotToArgTable;
       
    47     final long argCounts;               // packed slot & value counts
       
    48     final long primCounts;              // packed prim & double counts
       
    49     final int vmslots;                  // total number of parameter slots
       
    50     final MethodType erasedType;        // the canonical erasure
       
    51 
       
    52     /*lazy*/ MethodType primsAsBoxes;   // replace prims by wrappers
       
    53     /*lazy*/ MethodType primArgsAsBoxes; // wrap args only; make raw return
       
    54     /*lazy*/ MethodType primsAsInts;    // replace prims by int/long
       
    55     /*lazy*/ MethodType primsAsLongs;   // replace prims by long
       
    56     /*lazy*/ MethodType primsAtEnd;     // reorder primitives to the end
       
    57 
       
    58     // Cached adapter information:
       
    59     /*lazy*/ ToGeneric   toGeneric;     // convert cs. with prims to w/o
       
    60     /*lazy*/ FromGeneric fromGeneric;   // convert cs. w/o prims to with
       
    61     /*lazy*/ SpreadGeneric[] spreadGeneric; // expand one argument to many
       
    62     /*lazy*/ FilterGeneric filterGeneric; // convert argument(s) on the fly
       
    63     /*lazy*/ MethodHandle genericInvoker; // hook for invokeGeneric
       
    64 
       
    65     public MethodType erasedType() {
       
    66         return erasedType;
       
    67     }
       
    68 
       
    69     public static MethodTypeImpl of(MethodType type) {
       
    70         return METHOD_TYPE_FRIEND.form(type);
       
    71     }
       
    72 
       
    73     /** Access methods for the internals of MethodType, supplied to
       
    74      *  MethodTypeImpl as a trusted agent.
       
    75      */
       
    76     static public interface MethodTypeFriend {
       
    77         Class<?>[]     ptypes(MethodType mt);
       
    78         MethodTypeImpl form(MethodType mt);
       
    79         void           setForm(MethodType mt, MethodTypeImpl form);
       
    80         MethodType     makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted);
       
    81         MethodTypeImpl newMethodTypeForm(MethodType mt);
       
    82         Invokers       getInvokers(MethodType mt);
       
    83         void           setInvokers(MethodType mt, Invokers inv);
       
    84     }
       
    85     public static void setMethodTypeFriend(Access token, MethodTypeFriend am) {
       
    86         Access.check(token);
       
    87         if (METHOD_TYPE_FRIEND != null)
       
    88             throw new InternalError();  // just once
       
    89         METHOD_TYPE_FRIEND = am;
       
    90     }
       
    91     static private MethodTypeFriend METHOD_TYPE_FRIEND;
       
    92 
       
    93     static MethodType makeImpl(Access token, Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
       
    94         Access.check(token);
       
    95         return METHOD_TYPE_FRIEND.makeImpl(rtype, ptypes, trusted);
       
    96     }
       
    97 
       
    98     protected MethodTypeImpl(MethodType erasedType) {
       
    99         this.erasedType = erasedType;
       
   100 
       
   101         Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(erasedType);
       
   102         int ptypeCount = ptypes.length;
       
   103         int pslotCount = ptypeCount;            // temp. estimate
       
   104         int rtypeCount = 1;                     // temp. estimate
       
   105         int rslotCount = 1;                     // temp. estimate
       
   106 
       
   107         int[] argToSlotTab = null, slotToArgTab = null;
       
   108 
       
   109         // Walk the argument types, looking for primitives.
       
   110         int pac = 0, lac = 0, prc = 0, lrc = 0;
       
   111         Class<?> epts[] = ptypes;
       
   112         for (int i = 0; i < epts.length; i++) {
       
   113             Class<?> pt = epts[i];
       
   114             if (pt != Object.class) {
       
   115                 assert(pt.isPrimitive());
       
   116                 ++pac;
       
   117                 if (hasTwoArgSlots(pt))  ++lac;
       
   118             }
       
   119         }
       
   120         pslotCount += lac;                  // #slots = #args + #longs
       
   121         Class<?> rt = erasedType.returnType();
       
   122         if (rt != Object.class) {
       
   123             ++prc;          // even void.class counts as a prim here
       
   124             if (hasTwoArgSlots(rt))  ++lrc;
       
   125             // adjust #slots, #args
       
   126             if (rt == void.class)
       
   127                 rtypeCount = rslotCount = 0;
       
   128             else
       
   129                 rslotCount += lrc;
       
   130         }
       
   131         if (lac != 0) {
       
   132             int slot = ptypeCount + lac;
       
   133             slotToArgTab = new int[slot+1];
       
   134             argToSlotTab = new int[1+ptypeCount];
       
   135             argToSlotTab[0] = slot;  // argument "-1" is past end of slots
       
   136             for (int i = 0; i < epts.length; i++) {
       
   137                 Class<?> pt = epts[i];
       
   138                 if (hasTwoArgSlots(pt))  --slot;
       
   139                 --slot;
       
   140                 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
       
   141                 argToSlotTab[1+i]  = slot;
       
   142             }
       
   143             assert(slot == 0);  // filled the table
       
   144         }
       
   145         this.primCounts = pack(lrc, prc, lac, pac);
       
   146         this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
       
   147         if (slotToArgTab == null) {
       
   148             int slot = ptypeCount; // first arg is deepest in stack
       
   149             slotToArgTab = new int[slot+1];
       
   150             argToSlotTab = new int[1+ptypeCount];
       
   151             argToSlotTab[0] = slot;  // argument "-1" is past end of slots
       
   152             for (int i = 0; i < ptypeCount; i++) {
       
   153                 --slot;
       
   154                 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
       
   155                 argToSlotTab[1+i]  = slot;
       
   156             }
       
   157         }
       
   158         this.argToSlotTable = argToSlotTab;
       
   159         this.slotToArgTable = slotToArgTab;
       
   160 
       
   161         if (pslotCount >= 256)  throw newIllegalArgumentException("too many arguments");
       
   162 
       
   163         // send a few bits down to the JVM:
       
   164         this.vmslots = parameterSlotCount();
       
   165 
       
   166         // short circuit some no-op canonicalizations:
       
   167         if (!hasPrimitives()) {
       
   168             primsAsBoxes = erasedType;
       
   169             primArgsAsBoxes = erasedType;
       
   170             primsAsInts  = erasedType;
       
   171             primsAsLongs = erasedType;
       
   172             primsAtEnd   = erasedType;
       
   173         }
       
   174     }
       
   175 
       
   176     /** Turn all primitive types to corresponding wrapper types.
       
   177      */
       
   178     public MethodType primsAsBoxes() {
       
   179         MethodType ct = primsAsBoxes;
       
   180         if (ct != null)  return ct;
       
   181         MethodType t = erasedType;
       
   182         ct = canonicalize(erasedType, WRAP, WRAP);
       
   183         if (ct == null)  ct = t;  // no prims to box
       
   184         return primsAsBoxes = ct;
       
   185     }
       
   186 
       
   187     /** Turn all primitive argument types to corresponding wrapper types.
       
   188      *  Subword and void return types are promoted to int.
       
   189      */
       
   190     public MethodType primArgsAsBoxes() {
       
   191         MethodType ct = primArgsAsBoxes;
       
   192         if (ct != null)  return ct;
       
   193         MethodType t = erasedType;
       
   194         ct = canonicalize(erasedType, RAW_RETURN, WRAP);
       
   195         if (ct == null)  ct = t;  // no prims to box
       
   196         return primArgsAsBoxes = ct;
       
   197     }
       
   198 
       
   199     /** Turn all primitive types to either int or long.
       
   200      *  Floating point return types are not changed, because
       
   201      *  they may require special calling sequences.
       
   202      *  A void return value is turned to int.
       
   203      */
       
   204     public MethodType primsAsInts() {
       
   205         MethodType ct = primsAsInts;
       
   206         if (ct != null)  return ct;
       
   207         MethodType t = erasedType;
       
   208         ct = canonicalize(t, RAW_RETURN, INTS);
       
   209         if (ct == null)  ct = t;  // no prims to int-ify
       
   210         return primsAsInts = ct;
       
   211     }
       
   212 
       
   213     /** Turn all primitive types to either int or long.
       
   214      *  Floating point return types are not changed, because
       
   215      *  they may require special calling sequences.
       
   216      *  A void return value is turned to int.
       
   217      */
       
   218     public MethodType primsAsLongs() {
       
   219         MethodType ct = primsAsLongs;
       
   220         if (ct != null)  return ct;
       
   221         MethodType t = erasedType;
       
   222         ct = canonicalize(t, RAW_RETURN, LONGS);
       
   223         if (ct == null)  ct = t;  // no prims to int-ify
       
   224         return primsAsLongs = ct;
       
   225     }
       
   226 
       
   227     /** Stably sort parameters into 3 buckets: ref, int, long. */
       
   228     public MethodType primsAtEnd() {
       
   229         MethodType ct = primsAtEnd;
       
   230         if (ct != null)  return ct;
       
   231         MethodType t = erasedType;
       
   232 
       
   233         int pac = primitiveParameterCount();
       
   234         if (pac == 0)
       
   235             return primsAtEnd = t;
       
   236 
       
   237         int argc = parameterCount();
       
   238         int lac = longPrimitiveParameterCount();
       
   239         if (pac == argc && (lac == 0 || lac == argc))
       
   240             return primsAtEnd = t;
       
   241 
       
   242         // known to have a mix of 2 or 3 of ref, int, long
       
   243         int[] reorder = primsAtEndOrder(t);
       
   244         ct = reorderParameters(t, reorder, null);
       
   245         //System.out.println("t="+t+" / reorder="+java.util.Arrays.toString(reorder)+" => "+ct);
       
   246         return primsAtEnd = ct;
       
   247     }
       
   248 
       
   249     /** Compute a new ordering of parameters so that all references
       
   250      *  are before all ints or longs, and all ints are before all longs.
       
   251      *  For this ordering, doubles count as longs, and all other primitive
       
   252      *  values count as ints.
       
   253      *  As a special case, if the parameters are already in the specified
       
   254      *  order, this method returns a null reference, rather than an array
       
   255      *  specifying a null permutation.
       
   256      *  <p>
       
   257      *  For example, the type {@code (int,boolean,int,Object,String)void}
       
   258      *  produces the order {@code {3,4,0,1,2}}, the type
       
   259      *  {@code (long,int,String)void} produces {@code {2,1,2}}, and
       
   260      *  the type {@code (Object,int)Object} produces {@code null}.
       
   261      */
       
   262     public static int[] primsAtEndOrder(MethodType mt) {
       
   263         MethodTypeImpl form = METHOD_TYPE_FRIEND.form(mt);
       
   264         if (form.primsAtEnd == form.erasedType)
       
   265             // quick check shows no reordering is necessary
       
   266             return null;
       
   267 
       
   268         int argc = form.parameterCount();
       
   269         int[] paramOrder = new int[argc];
       
   270 
       
   271         // 3-way bucket sort:
       
   272         int pac = form.primitiveParameterCount();
       
   273         int lac = form.longPrimitiveParameterCount();
       
   274         int rfill = 0, ifill = argc - pac, lfill = argc - lac;
       
   275 
       
   276         Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
       
   277         boolean changed = false;
       
   278         for (int i = 0; i < ptypes.length; i++) {
       
   279             Class<?> pt = ptypes[i];
       
   280             int ord;
       
   281             if (!pt.isPrimitive())             ord = rfill++;
       
   282             else if (!hasTwoArgSlots(pt))      ord = ifill++;
       
   283             else                               ord = lfill++;
       
   284             if (ord != i)  changed = true;
       
   285             assert(paramOrder[ord] == 0);
       
   286             paramOrder[ord] = i;
       
   287         }
       
   288         assert(rfill == argc - pac && ifill == argc - lac && lfill == argc);
       
   289         if (!changed) {
       
   290             form.primsAtEnd = form.erasedType;
       
   291             return null;
       
   292         }
       
   293         return paramOrder;
       
   294     }
       
   295 
       
   296     /** Put the existing parameters of mt into a new order, given by newParamOrder.
       
   297      *  The third argument is logically appended to mt.parameterArray,
       
   298      *  so that elements of newParamOrder can index either pre-existing or
       
   299      *  new parameter types.
       
   300      */
       
   301     public static MethodType reorderParameters(MethodType mt, int[] newParamOrder, Class<?>[] moreParams) {
       
   302         if (newParamOrder == null)  return mt;  // no-op reordering
       
   303         Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
       
   304         Class<?>[] ntypes = new Class<?>[newParamOrder.length];
       
   305         int maxParam = ptypes.length + (moreParams == null ? 0 : moreParams.length);
       
   306         boolean changed = (ntypes.length != ptypes.length);
       
   307         for (int i = 0; i < newParamOrder.length; i++) {
       
   308             int param = newParamOrder[i];
       
   309             if (param != i)  changed = true;
       
   310             Class<?> nt;
       
   311             if (param < ptypes.length)   nt = ptypes[param];
       
   312             else if (param == maxParam)  nt = mt.returnType();
       
   313             else                         nt = moreParams[param - ptypes.length];
       
   314             ntypes[i] = nt;
       
   315         }
       
   316         if (!changed)  return mt;
       
   317         return METHOD_TYPE_FRIEND.makeImpl(mt.returnType(), ntypes, true);
       
   318     }
       
   319 
       
   320     private static boolean hasTwoArgSlots(Class<?> type) {
       
   321         return type == long.class || type == double.class;
       
   322     }
       
   323 
       
   324     private static long pack(int a, int b, int c, int d) {
       
   325         assert(((a|b|c|d) & ~0xFFFF) == 0);
       
   326         long hw = ((a << 16) | b), lw = ((c << 16) | d);
       
   327         return (hw << 32) | lw;
       
   328     }
       
   329     private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
       
   330         assert(word <= 3);
       
   331         return (char)(packed >> ((3-word) * 16));
       
   332     }
       
   333 
       
   334     public int parameterCount() {                      // # outgoing values
       
   335         return unpack(argCounts, 3);
       
   336     }
       
   337     public int parameterSlotCount() {                  // # outgoing interpreter slots
       
   338         return unpack(argCounts, 2);
       
   339     }
       
   340     public int returnCount() {                         // = 0 (V), or 1
       
   341         return unpack(argCounts, 1);
       
   342     }
       
   343     public int returnSlotCount() {                     // = 0 (V), 2 (J/D), or 1
       
   344         return unpack(argCounts, 0);
       
   345     }
       
   346     public int primitiveParameterCount() {
       
   347         return unpack(primCounts, 3);
       
   348     }
       
   349     public int longPrimitiveParameterCount() {
       
   350         return unpack(primCounts, 2);
       
   351     }
       
   352     public int primitiveReturnCount() {                // = 0 (obj), or 1
       
   353         return unpack(primCounts, 1);
       
   354     }
       
   355     public int longPrimitiveReturnCount() {            // = 1 (J/D), or 0
       
   356         return unpack(primCounts, 0);
       
   357     }
       
   358     public boolean hasPrimitives() {
       
   359         return primCounts != 0;
       
   360     }
       
   361 //    public boolean hasNonVoidPrimitives() {
       
   362 //        if (primCounts == 0)  return false;
       
   363 //        if (primitiveParameterCount() != 0)  return true;
       
   364 //        return (primitiveReturnCount() != 0 && returnCount() != 0);
       
   365 //    }
       
   366     public boolean hasLongPrimitives() {
       
   367         return (longPrimitiveParameterCount() | longPrimitiveReturnCount()) != 0;
       
   368     }
       
   369     public int parameterToArgSlot(int i) {
       
   370         return argToSlotTable[1+i];
       
   371     }
       
   372     public int argSlotToParameter(int argSlot) {
       
   373         // Note:  Empty slots are represented by zero in this table.
       
   374         // Valid arguments slots contain incremented entries, so as to be non-zero.
       
   375         // We return -1 the caller to mean an empty slot.
       
   376         return slotToArgTable[argSlot] - 1;
       
   377     }
       
   378 
       
   379     public static void initForm(Access token, MethodType mt) {
       
   380         Access.check(token);
       
   381         MethodTypeImpl form = findForm(mt);
       
   382         METHOD_TYPE_FRIEND.setForm(mt, form);
       
   383         if (form.erasedType == mt) {
       
   384             // This is a principal (erased) type; show it to the JVM.
       
   385             MethodHandleImpl.init(token, mt);
       
   386         }
       
   387     }
       
   388 
       
   389     static MethodTypeImpl findForm(MethodType mt) {
       
   390         MethodType erased = canonicalize(mt, ERASE, ERASE);
       
   391         if (erased == null) {
       
   392             // It is already erased.  Make a new MethodTypeImpl.
       
   393             return METHOD_TYPE_FRIEND.newMethodTypeForm(mt);
       
   394         } else {
       
   395             // Share the MethodTypeImpl with the erased version.
       
   396             return METHOD_TYPE_FRIEND.form(erased);
       
   397         }
       
   398     }
       
   399 
       
   400     /** Codes for {@link #canonicalize(java.lang.Class, int).
       
   401      * ERASE means change every reference to {@code Object}.
       
   402      * WRAP means convert primitives (including {@code void} to their
       
   403      * corresponding wrapper types.  UNWRAP means the reverse of WRAP.
       
   404      * INTS means convert all non-void primitive types to int or long,
       
   405      * according to size.  LONGS means convert all non-void primitives
       
   406      * to long, regardless of size.  RAW_RETURN means convert a type
       
   407      * (assumed to be a return type) to int if it is smaller than an int,
       
   408      * or if it is void.
       
   409      */
       
   410     public static final int NO_CHANGE = 0, ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6;
       
   411 
       
   412     /** Canonicalize the types in the given method type.
       
   413      * If any types change, intern the new type, and return it.
       
   414      * Otherwise return null.
       
   415      */
       
   416     public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
       
   417         Class<?>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
       
   418         Class<?>[] ptc = MethodTypeImpl.canonicalizes(ptypes, howArgs);
       
   419         Class<?> rtype = mt.returnType();
       
   420         Class<?> rtc = MethodTypeImpl.canonicalize(rtype, howRet);
       
   421         if (ptc == null && rtc == null) {
       
   422             // It is already canonical.
       
   423             return null;
       
   424         }
       
   425         // Find the erased version of the method type:
       
   426         if (rtc == null)  rtc = rtype;
       
   427         if (ptc == null)  ptc = ptypes;
       
   428         return METHOD_TYPE_FRIEND.makeImpl(rtc, ptc, true);
       
   429     }
       
   430 
       
   431     /** Canonicalize the given return or param type.
       
   432      *  Return null if the type is already canonicalized.
       
   433      */
       
   434     static Class<?> canonicalize(Class<?> t, int how) {
       
   435         Class<?> ct;
       
   436         if (t == Object.class) {
       
   437             // no change, ever
       
   438         } else if (!t.isPrimitive()) {
       
   439             switch (how) {
       
   440                 case UNWRAP:
       
   441                     ct = Wrapper.asPrimitiveType(t);
       
   442                     if (ct != t)  return ct;
       
   443                     break;
       
   444                 case RAW_RETURN:
       
   445                 case ERASE:
       
   446                     return Object.class;
       
   447             }
       
   448         } else if (t == void.class) {
       
   449             // no change, usually
       
   450             switch (how) {
       
   451                 case RAW_RETURN:
       
   452                     return int.class;
       
   453                 case WRAP:
       
   454                     return Void.class;
       
   455             }
       
   456         } else {
       
   457             // non-void primitive
       
   458             switch (how) {
       
   459                 case WRAP:
       
   460                     return Wrapper.asWrapperType(t);
       
   461                 case INTS:
       
   462                     if (t == int.class || t == long.class)
       
   463                         return null;  // no change
       
   464                     if (t == double.class)
       
   465                         return long.class;
       
   466                     return int.class;
       
   467                 case LONGS:
       
   468                     if (t == long.class)
       
   469                         return null;  // no change
       
   470                     return long.class;
       
   471                 case RAW_RETURN:
       
   472                     if (t == int.class || t == long.class ||
       
   473                         t == float.class || t == double.class)
       
   474                         return null;  // no change
       
   475                     // everything else returns as an int
       
   476                     return int.class;
       
   477             }
       
   478         }
       
   479         // no change; return null to signify
       
   480         return null;
       
   481     }
       
   482 
       
   483     /** Canonicalize each param type in the given array.
       
   484      *  Return null if all types are already canonicalized.
       
   485      */
       
   486     static Class<?>[] canonicalizes(Class<?>[] ts, int how) {
       
   487         Class<?>[] cs = null;
       
   488         for (int imax = ts.length, i = 0; i < imax; i++) {
       
   489             Class<?> c = canonicalize(ts[i], how);
       
   490             if (c != null) {
       
   491                 if (cs == null)
       
   492                     cs = ts.clone();
       
   493                 cs[i] = c;
       
   494             }
       
   495         }
       
   496         return cs;
       
   497     }
       
   498 
       
   499     public static Invokers invokers(Access token, MethodType type) {
       
   500         Access.check(token);
       
   501         return invokers(type);
       
   502     }
       
   503     /*non-public*/ static Invokers invokers(MethodType type) {
       
   504         Invokers inv = METHOD_TYPE_FRIEND.getInvokers(type);
       
   505         if (inv != null)  return inv;
       
   506         inv = new Invokers(type);
       
   507         METHOD_TYPE_FRIEND.setInvokers(type, inv);
       
   508         return inv;
       
   509     }
       
   510 
       
   511     @Override
       
   512     public String toString() {
       
   513         return "Form"+erasedType;
       
   514     }
       
   515 
       
   516 }