1 /*
   2  * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package java.dyn;
  27 
  28 import impl.java.dyn.util.Wrappers;
  29 
  30 /**
  31  * Shared information for a group of method types, which differ
  32  * only by reference types, and therefore share a common erasure
  33  * and wrapping.
  34  * <p>
  35  * For an empirical discussion of the structure of method types,
  36  * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/">
  37  * the thread "Avoiding Boxing" on jvm-languages</a>.
  38  * There are approximately 2000 distinct erased method types in the JDK.
  39  * There are a little over 10 times that number of unerased types.
  40  * No more than half of these are likely to be loaded at once.
  41  * @author John Rose
  42  */
  43 class MethodTypeForm {
  44     final int[] argToSlotTable, slotToArgTable;
  45     final long argCounts;                // packed slot & value counts
  46     final long primCounts;               // packed prim & double counts
  47     final int vmslots;                   // total number of parameter slots
  48     final MethodType erasedType;         // the canonical erasure
  49     final MethodType wrappedType;        // erasure, with primitives wrapped
  50 
  51     public static MethodTypeForm of(MethodType type) {
  52         return type.form;
  53     }
  54 
  55     private MethodTypeForm(MethodType erase) {
  56         this.erasedType = erase;
  57         MethodType wt = canonType(erase, WRAP);
  58         this.wrappedType = (wt == null) ? erase : wt;
  59 
  60         int ptypeCount = erase.ptypes.length;
  61         int pslotCount = ptypeCount;            // temp. estimate
  62         int rtypeCount = 1;                     // temp. estimate
  63         int rslotCount = 1;                     // temp. estimate
  64 
  65         int[] argToSlotTab = null, slotToArgTab = null;
  66 
  67         // Walk the argument types, looking for primitives.
  68         if (wt != null) {
  69             int pac = 0, lac = 0, prc = 0, lrc = 0;
  70             Class<?> epts[] = erase.ptypes;
  71             for (int i = 0; i < epts.length; i++) {
  72                 Class<?> pt = epts[i];
  73                 if (pt != Object.class) {
  74                     assert(pt.isPrimitive());
  75                     ++pac;
  76                     if (hasTwoArgSlots(pt))  ++lac;
  77                 }
  78             }
  79             pslotCount += lac;                  // #slots = #args + #longs
  80             Class<?> rt = erase.rtype;
  81             if (rt != Object.class) {
  82                 ++prc;          // even void.class counts as a prim here
  83                 if (hasTwoArgSlots(rt))  ++lrc;
  84                 // adjust #slots, #args
  85                 if (rt == void.class)
  86                     rtypeCount = rslotCount = 0;
  87                 else
  88                     rslotCount += lrc;
  89             }
  90             if (lac != 0) {
  91                 int slot = ptypeCount + lac;
  92                 slotToArgTab = new int[slot+1];
  93                 argToSlotTab = new int[1+ptypeCount];
  94                 argToSlotTab[0] = slot;  // argument "-1" is past end of slots
  95                 for (int i = 0; i < epts.length; i++) {
  96                     Class<?> pt = epts[i];
  97                     if (hasTwoArgSlots(pt))  --slot;
  98                     --slot;
  99                     slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
 100                     argToSlotTab[1+i]  = slot;
 101                 }
 102                 assert(slot == 0);  // filled the table
 103             }
 104             this.primCounts = pack(lrc, prc, lac, pac);
 105         } else {
 106             this.primCounts = 0;
 107         }
 108         this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
 109         if (slotToArgTab == null) {
 110             int slot = ptypeCount; // first arg is deepest in stack
 111             slotToArgTab = new int[slot+1];
 112             argToSlotTab = new int[1+ptypeCount];
 113             argToSlotTab[0] = slot;  // argument "-1" is past end of slots
 114             for (int i = 0; i < ptypeCount; i++) {
 115                 --slot;
 116                 slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
 117                 argToSlotTab[1+i]  = slot;
 118             }
 119         }
 120         this.argToSlotTable = argToSlotTab;
 121         this.slotToArgTable = slotToArgTab;
 122 
 123         if (pslotCount >= 256)  throw new IllegalArgumentException("too many arguments");
 124 
 125         // send a few bits down to the JVM:
 126         this.vmslots = parameterSlotCount();
 127     }
 128 
 129     private static boolean hasTwoArgSlots(Class<?> type) {
 130         return type == long.class || type == double.class;
 131     }
 132 
 133     private static long pack(int a, int b, int c, int d) {
 134         assert(((a|b|c|d) & ~0xFFFF) == 0);
 135         long hw = ((a << 16) | b), lw = ((c << 16) | d);
 136         return (hw << 32) | lw;
 137     }
 138     private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
 139         assert(word <= 3);
 140         return (char)(packed >> ((3-word) * 16));
 141     }
 142 
 143     public int parameterCount() {                      // # outgoing values
 144         return unpack(argCounts, 3);
 145     }
 146     public int parameterSlotCount() {                  // # outgoing interpreter slots
 147         return unpack(argCounts, 2);
 148     }
 149     public int returnCount() {                         // = 0 (V), or 1
 150         return unpack(argCounts, 1);
 151     }
 152     public int returnSlotCount() {                     // = 0 (V), 2 (J/D), or 1
 153         return unpack(argCounts, 0);
 154     }
 155     public int primitiveParameterCount() {
 156         return unpack(primCounts, 3);
 157     }
 158     public int longPrimitiveParameterCount() {
 159         return unpack(primCounts, 2);
 160     }
 161     public int primitiveReturnCount() {                // = 0 (obj), or 1
 162         return unpack(primCounts, 1);
 163     }
 164     public int longPrimitiveReturnCount() {            // = 1 (J/D), or 0
 165         return unpack(primCounts, 0);
 166     }
 167     public int parameterToArgSlot(int i) {
 168         return argToSlotTable[1+i];
 169     }
 170     public int argSlotToParameter(int argSlot) {
 171         // Note:  Empty slots are represented by zero in this table.
 172         // Valid arguments slots contain incremented entries, so as to be non-zero.
 173         // We return -1 the caller to mean an empty slot.
 174         return slotToArgTable[argSlot] - 1;
 175     }
 176 
 177     static final int ERASE = 1, WRAP = 2, UNWRAP = 4, ARGS_ONLY = 8;
 178 
 179     static MethodTypeForm findForm(MethodType mt) {
 180         MethodType erased = canonType(mt, ERASE);
 181         if (erased == null) {
 182             // It is already erased.  Make a new MethodTypeForm.
 183             return new MethodTypeForm(mt);
 184         } else {
 185             // Share the MethodTypeForm with the erased version.
 186             return erased.form;
 187         }
 188     }
 189 
 190     /** Canonicalize the types in the given method type.
 191      * If any types change, intern the new type, and return it.
 192      * Otherwise return null.
 193      */
 194     static MethodType canonType(MethodType mt, int how) {
 195         Class<?>[] ptc = MethodTypeForm.canonTypes(mt.ptypes, how);
 196         Class<?> rtc = null;
 197         if ((how & ARGS_ONLY) == 0)
 198             rtc = MethodTypeForm.canonType(mt.rtype, how);
 199         if (ptc == null && rtc == null) {
 200             // It is already canonical.
 201             return null;
 202         }
 203         // Find the erased version of the method type:
 204         if (rtc == null)  rtc = mt.rtype;
 205         if (ptc == null)  ptc = mt.ptypes;
 206         return MethodType.makeImpl(rtc, ptc, true);
 207     }
 208 
 209     /** Canonicalize the given return or param type.
 210      *  Return null if the type is already canonicalized.
 211      */
 212     static Class<?> canonType(Class<?> t, int how) {
 213         if (t == Object.class) {
 214             // no change, ever
 215         } else if (!t.isPrimitive()) {
 216             if ((how & UNWRAP) != 0) {
 217                 Class<?> pt = Wrappers.asPrimitiveType(t);
 218                 if (pt != t)
 219                     return pt;
 220             }
 221             if ((how & ERASE) != 0)
 222                 return Object.class;
 223         } else {
 224             if ((how & WRAP) != 0) {
 225                 if ((how & ERASE) != 0)
 226                     return Object.class;
 227                 return Wrappers.asWrapperType(t);
 228             }
 229         }
 230         // no change; return null to signify
 231         return null;
 232     }
 233 
 234     /** Canonicalize each param type in the given array.
 235      *  Return null if all types are already canonicalized.
 236      */
 237     static Class<?>[] canonTypes(Class<?>[] ts, int how) {
 238         Class<?>[] cs = null;
 239         for (int imax = ts.length, i = 0; i < imax; i++) {
 240             Class<?> c = canonType(ts[i], how);
 241             if (c != null) {
 242                 if (cs == null)
 243                     cs = ts.clone();
 244                 cs[i] = c;
 245             }
 246         }
 247         return cs;
 248     }
 249 }