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 sun.invoke.util.Wrapper;
  29 import static java.lang.invoke.MethodHandleStatics.*;
  30 import static java.lang.invoke.MethodHandleNatives.Constants.*;
  31  import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
  32 
  33 /**
  34  * Shared information for a group of method types, which differ
  35  * only by reference types, and therefore share a common erasure
  36  * and wrapping.
  37  * <p>
  38  * For an empirical discussion of the structure of method types,
  39  * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/">
  40  * the thread "Avoiding Boxing" on jvm-languages</a>.
  41  * There are approximately 2000 distinct erased method types in the JDK.
  42  * There are a little over 10 times that number of unerased types.
  43  * No more than half of these are likely to be loaded at once.
  44  * @author John Rose
  45  */
  46 final class MethodTypeForm {
  47     final int[] argToSlotTable, slotToArgTable;
  48     final long argCounts;               // packed slot & value counts
  49     final long primCounts;              // packed prim & double counts
  50     final MethodType erasedType;        // the canonical erasure
  51     final MethodType basicType;         // the canonical erasure, with primitives simplified
  52 
  53     // Cached adapter information:
  54     @Stable final MethodHandle[] methodHandles;
  55     // Indexes into methodHandles:
  56     static final int
  57             MH_BASIC_INV      =  0,  // cached instance of MH.invokeBasic
  58             MH_NF_INV         =  1,  // cached helper for LF.NamedFunction
  59             MH_UNINIT_CS      =  2,  // uninitialized call site
  60             MH_LIMIT          =  3;
  61 
  62     // Cached lambda form information, for basic types only:
  63     final @Stable LambdaForm[] lambdaForms;
  64     // Indexes into lambdaForms:
  65     static final int
  66             LF_INVVIRTUAL     =  0,  // DMH invokeVirtual
  67             LF_INVSTATIC      =  1,
  68             LF_INVSPECIAL     =  2,
  69             LF_NEWINVSPECIAL  =  3,
  70             LF_INVINTERFACE   =  4,
  71             LF_INVSTATIC_INIT =  5,  // DMH invokeStatic with <clinit> barrier
  72             LF_INTERPRET      =  6,  // LF interpreter
  73             LF_REBIND         =  7,  // BoundMethodHandle
  74             LF_DELEGATE       =  8,  // DelegatingMethodHandle
  75             LF_EX_LINKER      =  9,  // invokeExact_MT (for invokehandle)
  76             LF_EX_INVOKER     = 10,  // MHs.invokeExact
  77             LF_GEN_LINKER     = 11,  // generic invoke_MT (for invokehandle)
  78             LF_GEN_INVOKER    = 12,  // generic MHs.invoke
  79             LF_CS_LINKER      = 13,  // linkToCallSite_CS
  80             LF_MH_LINKER      = 14,  // linkToCallSite_MH
  81             LF_GWC            = 15,  // guardWithCatch (catchException)
  82             LF_GWT            = 16,  // guardWithTest
  83             LF_LIMIT          = 17;
  84 
  85     /** Return the type corresponding uniquely (1-1) to this MT-form.
  86      *  It might have any primitive returns or arguments, but will have no references except Object.
  87      */
  88     public MethodType erasedType() {
  89         return erasedType;
  90     }
  91 
  92     /** Return the basic type derived from the erased type of this MT-form.
  93      *  A basic type is erased (all references Object) and also has all primitive
  94      *  types (except int, long, float, double, void) normalized to int.
  95      *  Such basic types correspond to low-level JVM calling sequences.
  96      */
  97     public MethodType basicType() {
  98         return basicType;
  99     }
 100 
 101     private boolean assertIsBasicType() {
 102         // primitives must be flattened also
 103         assert(erasedType == basicType)
 104                 : "erasedType: " + erasedType + " != basicType: " + basicType;
 105         return true;
 106     }
 107 
 108     public MethodHandle cachedMethodHandle(int which) {
 109         assert(assertIsBasicType());
 110         return methodHandles[which];
 111     }
 112 
 113     synchronized public MethodHandle setCachedMethodHandle(int which, MethodHandle mh) {
 114         // Simulate a CAS, to avoid racy duplication of results.
 115         MethodHandle prev = methodHandles[which];
 116         if (prev != null)  return prev;
 117         return methodHandles[which] = mh;
 118     }
 119 
 120     public LambdaForm cachedLambdaForm(int which) {
 121         assert(assertIsBasicType());
 122         return lambdaForms[which];
 123     }
 124 
 125     synchronized public LambdaForm setCachedLambdaForm(int which, LambdaForm form) {
 126         // Simulate a CAS, to avoid racy duplication of results.
 127         LambdaForm prev = lambdaForms[which];
 128         if (prev != null) return prev;
 129         return lambdaForms[which] = form;
 130     }
 131 
 132     /**
 133      * Build an MTF for a given type, which must have all references erased to Object.
 134      * This MTF will stand for that type and all un-erased variations.
 135      * Eagerly compute some basic properties of the type, common to all variations.
 136      */
 137     protected MethodTypeForm(MethodType erasedType) {
 138         this.erasedType = erasedType;
 139 
 140         Class<?>[] ptypes = erasedType.ptypes();
 141         int ptypeCount = ptypes.length;
 142         int pslotCount = ptypeCount;            // temp. estimate
 143         int rtypeCount = 1;                     // temp. estimate
 144         int rslotCount = 1;                     // temp. estimate
 145 
 146         int[] argToSlotTab = null, slotToArgTab = null;
 147 
 148         // Walk the argument types, looking for primitives.
 149         int pac = 0, lac = 0, prc = 0, lrc = 0;
 150         Class<?>[] epts = ptypes;
 151         Class<?>[] bpts = epts;
 152         for (int i = 0; i < epts.length; i++) {
 153             Class<?> pt = epts[i];
 154             if (pt != Object.class) {
 155                 ++pac;
 156                 Wrapper w = Wrapper.forPrimitiveType(pt);
 157                 if (w.isDoubleWord())  ++lac;
 158                 if (w.isSubwordOrInt() && pt != int.class) {
 159                     if (bpts == epts)
 160                         bpts = bpts.clone();
 161                     bpts[i] = int.class;
 162                 }
 163             }
 164         }
 165         pslotCount += lac;                  // #slots = #args + #longs
 166         Class<?> rt = erasedType.returnType();
 167         Class<?> bt = rt;
 168         if (rt != Object.class) {
 169             ++prc;          // even void.class counts as a prim here
 170             Wrapper w = Wrapper.forPrimitiveType(rt);
 171             if (w.isDoubleWord())  ++lrc;
 172             if (w.isSubwordOrInt() && rt != int.class)
 173                 bt = int.class;
 174             // adjust #slots, #args
 175             if (rt == void.class)
 176                 rtypeCount = rslotCount = 0;
 177             else
 178                 rslotCount += lrc;
 179         }
 180         if (epts == bpts && bt == rt) {
 181             this.basicType = erasedType;
 182         } else {
 183             this.basicType = MethodType.makeImpl(bt, bpts, true);
 184             // fill in rest of data from the basic type:
 185             MethodTypeForm that = this.basicType.form();
 186             assert(this != that);
 187             this.primCounts = that.primCounts;
 188             this.argCounts = that.argCounts;
 189             this.argToSlotTable = that.argToSlotTable;
 190             this.slotToArgTable = that.slotToArgTable;
 191             this.methodHandles = null;
 192             this.lambdaForms = null;
 193             return;
 194         }
 195         if (lac != 0) {
 196             int slot = ptypeCount + lac;
 197             slotToArgTab = new int[slot+1];
 198             argToSlotTab = new int[1+ptypeCount];
 199             argToSlotTab[0] = slot;  // argument "-1" is past end of slots
 200             for (int i = 0; i < epts.length; i++) {
 201                 Class<?> pt = epts[i];
 202                 Wrapper w = Wrapper.forBasicType(pt);
 203                 if (w.isDoubleWord())  --slot;
 204                 --slot;
 205                 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
 206                 argToSlotTab[1+i]  = slot;
 207             }
 208             assert(slot == 0);  // filled the table
 209         } else if (pac != 0) {
 210             // have primitives but no long primitives; share slot counts with generic
 211             assert(ptypeCount == pslotCount);
 212             MethodTypeForm that = MethodType.genericMethodType(ptypeCount).form();
 213             assert(this != that);
 214             slotToArgTab = that.slotToArgTable;
 215             argToSlotTab = that.argToSlotTable;
 216         } else {
 217             int slot = ptypeCount; // first arg is deepest in stack
 218             slotToArgTab = new int[slot+1];
 219             argToSlotTab = new int[1+ptypeCount];
 220             argToSlotTab[0] = slot;  // argument "-1" is past end of slots
 221             for (int i = 0; i < ptypeCount; i++) {
 222                 --slot;
 223                 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
 224                 argToSlotTab[1+i]  = slot;
 225             }
 226         }
 227         this.primCounts = pack(lrc, prc, lac, pac);
 228         this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
 229         this.argToSlotTable = argToSlotTab;
 230         this.slotToArgTable = slotToArgTab;
 231 
 232         if (pslotCount >= 256)  throw newIllegalArgumentException("too many arguments");
 233 
 234         // Initialize caches, but only for basic types
 235         assert(basicType == erasedType);
 236         this.lambdaForms = new LambdaForm[LF_LIMIT];
 237         this.methodHandles = new MethodHandle[MH_LIMIT];
 238     }
 239 
 240     private static long pack(int a, int b, int c, int d) {
 241         assert(((a|b|c|d) & ~0xFFFF) == 0);
 242         long hw = ((a << 16) | b), lw = ((c << 16) | d);
 243         return (hw << 32) | lw;
 244     }
 245     private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
 246         assert(word <= 3);
 247         return (char)(packed >> ((3-word) * 16));
 248     }
 249 
 250     public int parameterCount() {                      // # outgoing values
 251         return unpack(argCounts, 3);
 252     }
 253     public int parameterSlotCount() {                  // # outgoing interpreter slots
 254         return unpack(argCounts, 2);
 255     }
 256     public int returnCount() {                         // = 0 (V), or 1
 257         return unpack(argCounts, 1);
 258     }
 259     public int returnSlotCount() {                     // = 0 (V), 2 (J/D), or 1
 260         return unpack(argCounts, 0);
 261     }
 262     public int primitiveParameterCount() {
 263         return unpack(primCounts, 3);
 264     }
 265     public int longPrimitiveParameterCount() {
 266         return unpack(primCounts, 2);
 267     }
 268     public int primitiveReturnCount() {                // = 0 (obj), or 1
 269         return unpack(primCounts, 1);
 270     }
 271     public int longPrimitiveReturnCount() {            // = 1 (J/D), or 0
 272         return unpack(primCounts, 0);
 273     }
 274     public boolean hasPrimitives() {
 275         return primCounts != 0;
 276     }
 277     public boolean hasNonVoidPrimitives() {
 278         if (primCounts == 0)  return false;
 279         if (primitiveParameterCount() != 0)  return true;
 280         return (primitiveReturnCount() != 0 && returnCount() != 0);
 281     }
 282     public boolean hasLongPrimitives() {
 283         return (longPrimitiveParameterCount() | longPrimitiveReturnCount()) != 0;
 284     }
 285     public int parameterToArgSlot(int i) {
 286         return argToSlotTable[1+i];
 287     }
 288     public int argSlotToParameter(int argSlot) {
 289         // Note:  Empty slots are represented by zero in this table.
 290         // Valid arguments slots contain incremented entries, so as to be non-zero.
 291         // We return -1 the caller to mean an empty slot.
 292         return slotToArgTable[argSlot] - 1;
 293     }
 294 
 295     static MethodTypeForm findForm(MethodType mt) {
 296         MethodType erased = canonicalize(mt, ERASE, ERASE);
 297         if (erased == null) {
 298             // It is already erased.  Make a new MethodTypeForm.
 299             return new MethodTypeForm(mt);
 300         } else {
 301             // Share the MethodTypeForm with the erased version.
 302             return erased.form();
 303         }
 304     }
 305 
 306     /** Codes for {@link #canonicalize(java.lang.Class, int)}.
 307      * ERASE means change every reference to {@code Object}.
 308      * WRAP means convert primitives (including {@code void} to their
 309      * corresponding wrapper types.  UNWRAP means the reverse of WRAP.
 310      * INTS means convert all non-void primitive types to int or long,
 311      * according to size.  LONGS means convert all non-void primitives
 312      * to long, regardless of size.  RAW_RETURN means convert a type
 313      * (assumed to be a return type) to int if it is smaller than an int,
 314      * or if it is void.
 315      */
 316     public static final int NO_CHANGE = 0, ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6;
 317 
 318     /** Canonicalize the types in the given method type.
 319      * If any types change, intern the new type, and return it.
 320      * Otherwise return null.
 321      */
 322     public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
 323         Class<?>[] ptypes = mt.ptypes();
 324         Class<?>[] ptc = MethodTypeForm.canonicalizeAll(ptypes, howArgs);
 325         Class<?> rtype = mt.returnType();
 326         Class<?> rtc = MethodTypeForm.canonicalize(rtype, howRet);
 327         if (ptc == null && rtc == null) {
 328             // It is already canonical.
 329             return null;
 330         }
 331         // Find the erased version of the method type:
 332         if (rtc == null)  rtc = rtype;
 333         if (ptc == null)  ptc = ptypes;
 334         return MethodType.makeImpl(rtc, ptc, true);
 335     }
 336 
 337     /** Canonicalize the given return or param type.
 338      *  Return null if the type is already canonicalized.
 339      */
 340     static Class<?> canonicalize(Class<?> t, int how) {
 341         Class<?> ct;
 342         if (t == Object.class) {
 343             // no change, ever
 344         } else if (!t.isPrimitive()) {
 345             switch (how) {
 346                 case UNWRAP:
 347                     ct = Wrapper.asPrimitiveType(t);
 348                     if (ct != t)  return ct;
 349                     break;
 350                 case RAW_RETURN:
 351                 case ERASE:
 352                     return Object.class;
 353             }
 354         } else if (t == void.class) {
 355             // no change, usually
 356             switch (how) {
 357                 case RAW_RETURN:
 358                     return int.class;
 359                 case WRAP:
 360                     return Void.class;
 361             }
 362         } else {
 363             // non-void primitive
 364             switch (how) {
 365                 case WRAP:
 366                     return Wrapper.asWrapperType(t);
 367                 case INTS:
 368                     if (t == int.class || t == long.class)
 369                         return null;  // no change
 370                     if (t == double.class)
 371                         return long.class;
 372                     return int.class;
 373                 case LONGS:
 374                     if (t == long.class)
 375                         return null;  // no change
 376                     return long.class;
 377                 case RAW_RETURN:
 378                     if (t == int.class || t == long.class ||
 379                         t == float.class || t == double.class)
 380                         return null;  // no change
 381                     // everything else returns as an int
 382                     return int.class;
 383             }
 384         }
 385         // no change; return null to signify
 386         return null;
 387     }
 388 
 389     /** Canonicalize each param type in the given array.
 390      *  Return null if all types are already canonicalized.
 391      */
 392     static Class<?>[] canonicalizeAll(Class<?>[] ts, int how) {
 393         Class<?>[] cs = null;
 394         for (int imax = ts.length, i = 0; i < imax; i++) {
 395             Class<?> c = canonicalize(ts[i], how);
 396             if (c == void.class)
 397                 c = null;  // a Void parameter was unwrapped to void; ignore
 398             if (c != null) {
 399                 if (cs == null)
 400                     cs = ts.clone();
 401                 cs[i] = c;
 402             }
 403         }
 404         return cs;
 405     }
 406 
 407     @Override
 408     public String toString() {
 409         return "Form"+erasedType;
 410     }
 411 
 412 }