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