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 int vmslots;                  // total number of parameter slots
  51     final MethodType erasedType;        // the canonical erasure
  52     final MethodType basicType;         // the canonical erasure, with primitives simplified
  53 
  54     // Cached adapter information:
  55     @Stable String typeString;           // argument type signature characters
  56     @Stable MethodHandle genericInvoker; // JVM hook for inexact invoke
  57     @Stable MethodHandle basicInvoker;   // cached instance of MH.invokeBasic
  58     @Stable MethodHandle namedFunctionInvoker; // cached helper for LF.NamedFunction
  59 
  60     // Cached lambda form information, for basic types only:
  61     final @Stable LambdaForm[] lambdaForms;
  62     // Indexes into lambdaForms:
  63     static final int
  64             LF_INVVIRTUAL     =  0,  // DMH invokeVirtual
  65             LF_INVSTATIC      =  1,
  66             LF_INVSPECIAL     =  2,
  67             LF_NEWINVSPECIAL  =  3,
  68             LF_INVINTERFACE   =  4,
  69             LF_INVSTATIC_INIT =  5,  // DMH invokeStatic with <clinit> barrier
  70             LF_INTERPRET      =  6,  // LF interpreter
  71             LF_COUNTER        =  7,  // CMH wrapper
  72             LF_REINVOKE       =  8,  // other wrapper
  73             LF_EX_LINKER      =  9,  // invokeExact_MT
  74             LF_EX_INVOKER     = 10,  // invokeExact MH
  75             LF_GEN_LINKER     = 11,
  76             LF_GEN_INVOKER    = 12,
  77             LF_CS_LINKER      = 13,  // linkToCallSite_CS
  78             LF_MH_LINKER      = 14,  // linkToCallSite_MH
  79             LF_GWC            = 15,
  80             LF_LIMIT          = 16;
  81 
  82     public MethodType erasedType() {
  83         return erasedType;
  84     }
  85 
  86     public MethodType basicType() {
  87         return basicType;
  88     }
  89 
  90     public LambdaForm cachedLambdaForm(int which) {
  91         return lambdaForms[which];
  92     }
  93 
  94     synchronized public LambdaForm setCachedLambdaForm(int which, LambdaForm form) {
  95         // Simulate a CAS, to avoid racy duplication of results.
  96         LambdaForm prev = lambdaForms[which];
  97         if (prev != null) return prev;
  98         return lambdaForms[which] = form;
  99     }
 100 
 101     public MethodHandle basicInvoker() {
 102         assert(erasedType == basicType) : "erasedType: " + erasedType + " != basicType: " + basicType;  // primitives must be flattened also
 103         MethodHandle invoker = basicInvoker;
 104         if (invoker != null)  return invoker;
 105         invoker = DirectMethodHandle.make(invokeBasicMethod(basicType));
 106         basicInvoker = invoker;
 107         return invoker;
 108     }
 109 
 110     // This next one is called from LambdaForm.NamedFunction.<init>.
 111     /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) {
 112         assert(basicType == basicType.basicType());
 113         try {
 114             // Do approximately the same as this public API call:
 115             //   Lookup.findVirtual(MethodHandle.class, name, type);
 116             // But bypass access and corner case checks, since we know exactly what we need.
 117             return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType);
 118          } catch (ReflectiveOperationException ex) {
 119             throw newInternalError("JVM cannot find invoker for "+basicType, ex);
 120         }
 121     }
 122 
 123     /**
 124      * Build an MTF for a given type, which must have all references erased to Object.
 125      * This MTF will stand for that type and all un-erased variations.
 126      * Eagerly compute some basic properties of the type, common to all variations.
 127      */
 128     protected MethodTypeForm(MethodType erasedType) {
 129         this.erasedType = erasedType;
 130 
 131         Class<?>[] ptypes = erasedType.ptypes();
 132         int ptypeCount = ptypes.length;
 133         int pslotCount = ptypeCount;            // temp. estimate
 134         int rtypeCount = 1;                     // temp. estimate
 135         int rslotCount = 1;                     // temp. estimate
 136 
 137         int[] argToSlotTab = null, slotToArgTab = null;
 138 
 139         // Walk the argument types, looking for primitives.
 140         int pac = 0, lac = 0, prc = 0, lrc = 0;
 141         Class<?>[] epts = ptypes;
 142         Class<?>[] bpts = epts;
 143         for (int i = 0; i < epts.length; i++) {
 144             Class<?> pt = epts[i];
 145             if (pt != Object.class) {
 146                 ++pac;
 147                 Wrapper w = Wrapper.forPrimitiveType(pt);
 148                 if (w.isDoubleWord())  ++lac;
 149                 if (w.isSubwordOrInt() && pt != int.class) {
 150                     if (bpts == epts)
 151                         bpts = bpts.clone();
 152                     bpts[i] = int.class;
 153                 }
 154             }
 155         }
 156         pslotCount += lac;                  // #slots = #args + #longs
 157         Class<?> rt = erasedType.returnType();
 158         Class<?> bt = rt;
 159         if (rt != Object.class) {
 160             ++prc;          // even void.class counts as a prim here
 161             Wrapper w = Wrapper.forPrimitiveType(rt);
 162             if (w.isDoubleWord())  ++lrc;
 163             if (w.isSubwordOrInt() && rt != int.class)
 164                 bt = int.class;
 165             // adjust #slots, #args
 166             if (rt == void.class)
 167                 rtypeCount = rslotCount = 0;
 168             else
 169                 rslotCount += lrc;
 170         }
 171         if (epts == bpts && bt == rt) {
 172             this.basicType = erasedType;
 173         } else {
 174             this.basicType = MethodType.makeImpl(bt, bpts, true);
 175         }
 176         if (lac != 0) {
 177             int slot = ptypeCount + lac;
 178             slotToArgTab = new int[slot+1];
 179             argToSlotTab = new int[1+ptypeCount];
 180             argToSlotTab[0] = slot;  // argument "-1" is past end of slots
 181             for (int i = 0; i < epts.length; i++) {
 182                 Class<?> pt = epts[i];
 183                 Wrapper w = Wrapper.forBasicType(pt);
 184                 if (w.isDoubleWord())  --slot;
 185                 --slot;
 186                 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
 187                 argToSlotTab[1+i]  = slot;
 188             }
 189             assert(slot == 0);  // filled the table
 190         }
 191         this.primCounts = pack(lrc, prc, lac, pac);
 192         this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
 193         if (slotToArgTab == null) {
 194             int slot = ptypeCount; // first arg is deepest in stack
 195             slotToArgTab = new int[slot+1];
 196             argToSlotTab = new int[1+ptypeCount];
 197             argToSlotTab[0] = slot;  // argument "-1" is past end of slots
 198             for (int i = 0; i < ptypeCount; i++) {
 199                 --slot;
 200                 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
 201                 argToSlotTab[1+i]  = slot;
 202             }
 203         }
 204         this.argToSlotTable = argToSlotTab;
 205         this.slotToArgTable = slotToArgTab;
 206 
 207         if (pslotCount >= 256)  throw newIllegalArgumentException("too many arguments");
 208 
 209         // send a few bits down to the JVM:
 210         this.vmslots = parameterSlotCount();
 211 
 212         if (basicType == erasedType) {
 213             lambdaForms = new LambdaForm[LF_LIMIT];
 214         } else {
 215             lambdaForms = null;  // could be basicType.form().lambdaForms;
 216         }
 217     }
 218 
 219     private static long pack(int a, int b, int c, int d) {
 220         assert(((a|b|c|d) & ~0xFFFF) == 0);
 221         long hw = ((a << 16) | b), lw = ((c << 16) | d);
 222         return (hw << 32) | lw;
 223     }
 224     private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
 225         assert(word <= 3);
 226         return (char)(packed >> ((3-word) * 16));
 227     }
 228 
 229     public int parameterCount() {                      // # outgoing values
 230         return unpack(argCounts, 3);
 231     }
 232     public int parameterSlotCount() {                  // # outgoing interpreter slots
 233         return unpack(argCounts, 2);
 234     }
 235     public int returnCount() {                         // = 0 (V), or 1
 236         return unpack(argCounts, 1);
 237     }
 238     public int returnSlotCount() {                     // = 0 (V), 2 (J/D), or 1
 239         return unpack(argCounts, 0);
 240     }
 241     public int primitiveParameterCount() {
 242         return unpack(primCounts, 3);
 243     }
 244     public int longPrimitiveParameterCount() {
 245         return unpack(primCounts, 2);
 246     }
 247     public int primitiveReturnCount() {                // = 0 (obj), or 1
 248         return unpack(primCounts, 1);
 249     }
 250     public int longPrimitiveReturnCount() {            // = 1 (J/D), or 0
 251         return unpack(primCounts, 0);
 252     }
 253     public boolean hasPrimitives() {
 254         return primCounts != 0;
 255     }
 256     public boolean hasNonVoidPrimitives() {
 257         if (primCounts == 0)  return false;
 258         if (primitiveParameterCount() != 0)  return true;
 259         return (primitiveReturnCount() != 0 && returnCount() != 0);
 260     }
 261     public boolean hasLongPrimitives() {
 262         return (longPrimitiveParameterCount() | longPrimitiveReturnCount()) != 0;
 263     }
 264     public int parameterToArgSlot(int i) {
 265         return argToSlotTable[1+i];
 266     }
 267     public int argSlotToParameter(int argSlot) {
 268         // Note:  Empty slots are represented by zero in this table.
 269         // Valid arguments slots contain incremented entries, so as to be non-zero.
 270         // We return -1 the caller to mean an empty slot.
 271         return slotToArgTable[argSlot] - 1;
 272     }
 273 
 274     static MethodTypeForm findForm(MethodType mt) {
 275         MethodType erased = canonicalize(mt, ERASE, ERASE);
 276         if (erased == null) {
 277             // It is already erased.  Make a new MethodTypeForm.
 278             return new MethodTypeForm(mt);
 279         } else {
 280             // Share the MethodTypeForm with the erased version.
 281             return erased.form();
 282         }
 283     }
 284 
 285     /** Codes for {@link #canonicalize(java.lang.Class, int)}.
 286      * ERASE means change every reference to {@code Object}.
 287      * WRAP means convert primitives (including {@code void} to their
 288      * corresponding wrapper types.  UNWRAP means the reverse of WRAP.
 289      * INTS means convert all non-void primitive types to int or long,
 290      * according to size.  LONGS means convert all non-void primitives
 291      * to long, regardless of size.  RAW_RETURN means convert a type
 292      * (assumed to be a return type) to int if it is smaller than an int,
 293      * or if it is void.
 294      */
 295     public static final int NO_CHANGE = 0, ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6;
 296 
 297     /** Canonicalize the types in the given method type.
 298      * If any types change, intern the new type, and return it.
 299      * Otherwise return null.
 300      */
 301     public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
 302         Class<?>[] ptypes = mt.ptypes();
 303         Class<?>[] ptc = MethodTypeForm.canonicalizes(ptypes, howArgs);
 304         Class<?> rtype = mt.returnType();
 305         Class<?> rtc = MethodTypeForm.canonicalize(rtype, howRet);
 306         if (ptc == null && rtc == null) {
 307             // It is already canonical.
 308             return null;
 309         }
 310         // Find the erased version of the method type:
 311         if (rtc == null)  rtc = rtype;
 312         if (ptc == null)  ptc = ptypes;
 313         return MethodType.makeImpl(rtc, ptc, true);
 314     }
 315 
 316     /** Canonicalize the given return or param type.
 317      *  Return null if the type is already canonicalized.
 318      */
 319     static Class<?> canonicalize(Class<?> t, int how) {
 320         Class<?> ct;
 321         if (t == Object.class) {
 322             // no change, ever
 323         } else if (!t.isPrimitive()) {
 324             switch (how) {
 325                 case UNWRAP:
 326                     ct = Wrapper.asPrimitiveType(t);
 327                     if (ct != t)  return ct;
 328                     break;
 329                 case RAW_RETURN:
 330                 case ERASE:
 331                     return Object.class;
 332             }
 333         } else if (t == void.class) {
 334             // no change, usually
 335             switch (how) {
 336                 case RAW_RETURN:
 337                     return int.class;
 338                 case WRAP:
 339                     return Void.class;
 340             }
 341         } else {
 342             // non-void primitive
 343             switch (how) {
 344                 case WRAP:
 345                     return Wrapper.asWrapperType(t);
 346                 case INTS:
 347                     if (t == int.class || t == long.class)
 348                         return null;  // no change
 349                     if (t == double.class)
 350                         return long.class;
 351                     return int.class;
 352                 case LONGS:
 353                     if (t == long.class)
 354                         return null;  // no change
 355                     return long.class;
 356                 case RAW_RETURN:
 357                     if (t == int.class || t == long.class ||
 358                         t == float.class || t == double.class)
 359                         return null;  // no change
 360                     // everything else returns as an int
 361                     return int.class;
 362             }
 363         }
 364         // no change; return null to signify
 365         return null;
 366     }
 367 
 368     /** Canonicalize each param type in the given array.
 369      *  Return null if all types are already canonicalized.
 370      */
 371     static Class<?>[] canonicalizes(Class<?>[] ts, int how) {
 372         Class<?>[] cs = null;
 373         for (int imax = ts.length, i = 0; i < imax; i++) {
 374             Class<?> c = canonicalize(ts[i], how);
 375             if (c == void.class)
 376                 c = null;  // a Void parameter was unwrapped to void; ignore
 377             if (c != null) {
 378                 if (cs == null)
 379                     cs = ts.clone();
 380                 cs[i] = c;
 381             }
 382         }
 383         return cs;
 384     }
 385 
 386     @Override
 387     public String toString() {
 388         return "Form"+erasedType;
 389     }
 390 
 391 }