--- /dev/null	2009-02-04 23:35:29.000000000 -0800
+++ new/src/share/classes/java/dyn/MethodTypeForm.java	2009-02-04 23:35:29.000000000 -0800
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.dyn;
+
+import impl.java.dyn.util.Wrappers;
+
+/**
+ * Shared information for a group of method types, which differ
+ * only by reference types, and therefore share a common erasure
+ * and wrapping.
+ * <p>
+ * For an empirical discussion of the structure of method types,
+ * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/">
+ * the thread "Avoiding Boxing" on jvm-languages</a>.
+ * There are approximately 2000 distinct erased method types in the JDK.
+ * There are a little over 10 times that number of unerased types.
+ * No more than half of these are likely to be loaded at once.
+ * @author John Rose
+ */
+class MethodTypeForm {
+    final int[] argToSlotTable, slotToArgTable;
+    final long argCounts;                // packed slot & value counts
+    final long primCounts;               // packed prim & double counts
+    final int vmslots;                   // total number of parameter slots
+    final MethodType erasedType;         // the canonical erasure
+    final MethodType wrappedType;        // erasure, with primitives wrapped
+
+    public static MethodTypeForm of(MethodType type) {
+        return type.form;
+    }
+
+    private MethodTypeForm(MethodType erase) {
+        this.erasedType = erase;
+        MethodType wt = canonType(erase, WRAP);
+        this.wrappedType = (wt == null) ? erase : wt;
+
+        int ptypeCount = erase.ptypes.length;
+        int pslotCount = ptypeCount;            // temp. estimate
+        int rtypeCount = 1;                     // temp. estimate
+        int rslotCount = 1;                     // temp. estimate
+
+        int[] argToSlotTab = null, slotToArgTab = null;
+
+        // Walk the argument types, looking for primitives.
+        if (wt != null) {
+            int pac = 0, lac = 0, prc = 0, lrc = 0;
+            Class<?> epts[] = erase.ptypes;
+            for (int i = 0; i < epts.length; i++) {
+                Class<?> pt = epts[i];
+                if (pt != Object.class) {
+                    assert(pt.isPrimitive());
+                    ++pac;
+                    if (hasTwoArgSlots(pt))  ++lac;
+                }
+            }
+            pslotCount += lac;                  // #slots = #args + #longs
+            Class<?> rt = erase.rtype;
+            if (rt != Object.class) {
+                ++prc;          // even void.class counts as a prim here
+                if (hasTwoArgSlots(rt))  ++lrc;
+                // adjust #slots, #args
+                if (rt == void.class)
+                    rtypeCount = rslotCount = 0;
+                else
+                    rslotCount += lrc;
+            }
+            if (lac != 0) {
+                int slot = ptypeCount + lac;
+                slotToArgTab = new int[slot+1];
+                argToSlotTab = new int[1+ptypeCount];
+                argToSlotTab[0] = slot;  // argument "-1" is past end of slots
+                for (int i = 0; i < epts.length; i++) {
+                    Class<?> pt = epts[i];
+                    if (hasTwoArgSlots(pt))  --slot;
+                    --slot;
+                    slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
+                    argToSlotTab[1+i]  = slot;
+                }
+                assert(slot == 0);  // filled the table
+            }
+            this.primCounts = pack(lrc, prc, lac, pac);
+        } else {
+            this.primCounts = 0;
+        }
+        this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
+        if (slotToArgTab == null) {
+            int slot = ptypeCount; // first arg is deepest in stack
+            slotToArgTab = new int[slot+1];
+            argToSlotTab = new int[1+ptypeCount];
+            argToSlotTab[0] = slot;  // argument "-1" is past end of slots
+            for (int i = 0; i < ptypeCount; i++) {
+                --slot;
+                slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
+                argToSlotTab[1+i]  = slot;
+            }
+        }
+        this.argToSlotTable = argToSlotTab;
+        this.slotToArgTable = slotToArgTab;
+
+        if (pslotCount >= 256)  throw new IllegalArgumentException("too many arguments");
+
+        // send a few bits down to the JVM:
+        this.vmslots = parameterSlotCount();
+    }
+
+    private static boolean hasTwoArgSlots(Class<?> type) {
+        return type == long.class || type == double.class;
+    }
+
+    private static long pack(int a, int b, int c, int d) {
+        assert(((a|b|c|d) & ~0xFFFF) == 0);
+        long hw = ((a << 16) | b), lw = ((c << 16) | d);
+        return (hw << 32) | lw;
+    }
+    private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
+        assert(word <= 3);
+        return (char)(packed >> ((3-word) * 16));
+    }
+
+    public int parameterCount() {                      // # outgoing values
+        return unpack(argCounts, 3);
+    }
+    public int parameterSlotCount() {                  // # outgoing interpreter slots
+        return unpack(argCounts, 2);
+    }
+    public int returnCount() {                         // = 0 (V), or 1
+        return unpack(argCounts, 1);
+    }
+    public int returnSlotCount() {                     // = 0 (V), 2 (J/D), or 1
+        return unpack(argCounts, 0);
+    }
+    public int primitiveParameterCount() {
+        return unpack(primCounts, 3);
+    }
+    public int longPrimitiveParameterCount() {
+        return unpack(primCounts, 2);
+    }
+    public int primitiveReturnCount() {                // = 0 (obj), or 1
+        return unpack(primCounts, 1);
+    }
+    public int longPrimitiveReturnCount() {            // = 1 (J/D), or 0
+        return unpack(primCounts, 0);
+    }
+    public int parameterToArgSlot(int i) {
+        return argToSlotTable[1+i];
+    }
+    public int argSlotToParameter(int argSlot) {
+        // Note:  Empty slots are represented by zero in this table.
+        // Valid arguments slots contain incremented entries, so as to be non-zero.
+        // We return -1 the caller to mean an empty slot.
+        return slotToArgTable[argSlot] - 1;
+    }
+
+    static final int ERASE = 1, WRAP = 2, UNWRAP = 4, ARGS_ONLY = 8;
+
+    static MethodTypeForm findForm(MethodType mt) {
+        MethodType erased = canonType(mt, ERASE);
+        if (erased == null) {
+            // It is already erased.  Make a new MethodTypeForm.
+            return new MethodTypeForm(mt);
+        } else {
+            // Share the MethodTypeForm with the erased version.
+            return erased.form;
+        }
+    }
+
+    /** Canonicalize the types in the given method type.
+     * If any types change, intern the new type, and return it.
+     * Otherwise return null.
+     */
+    static MethodType canonType(MethodType mt, int how) {
+        Class<?>[] ptc = MethodTypeForm.canonTypes(mt.ptypes, how);
+        Class<?> rtc = null;
+        if ((how & ARGS_ONLY) == 0)
+            rtc = MethodTypeForm.canonType(mt.rtype, how);
+        if (ptc == null && rtc == null) {
+            // It is already canonical.
+            return null;
+        }
+        // Find the erased version of the method type:
+        if (rtc == null)  rtc = mt.rtype;
+        if (ptc == null)  ptc = mt.ptypes;
+        return MethodType.makeImpl(rtc, ptc, true);
+    }
+
+    /** Canonicalize the given return or param type.
+     *  Return null if the type is already canonicalized.
+     */
+    static Class<?> canonType(Class<?> t, int how) {
+        if (t == Object.class) {
+            // no change, ever
+        } else if (!t.isPrimitive()) {
+            if ((how & UNWRAP) != 0) {
+                Class<?> pt = Wrappers.asPrimitiveType(t);
+                if (pt != t)
+                    return pt;
+            }
+            if ((how & ERASE) != 0)
+                return Object.class;
+        } else {
+            if ((how & WRAP) != 0) {
+                if ((how & ERASE) != 0)
+                    return Object.class;
+                return Wrappers.asWrapperType(t);
+            }
+        }
+        // no change; return null to signify
+        return null;
+    }
+
+    /** Canonicalize each param type in the given array.
+     *  Return null if all types are already canonicalized.
+     */
+    static Class<?>[] canonTypes(Class<?>[] ts, int how) {
+        Class<?>[] cs = null;
+        for (int imax = ts.length, i = 0; i < imax; i++) {
+            Class<?> c = canonType(ts[i], how);
+            if (c != null) {
+                if (cs == null)
+                    cs = ts.clone();
+                cs[i] = c;
+            }
+        }
+        return cs;
+    }
+}
