1 /* 2 * Copyright (c) 2008, 2019, 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 30 import java.lang.ref.SoftReference; 31 32 import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException; 33 34 /** 35 * Shared information for a group of method types, which differ 36 * only by reference types, and therefore share a common erasure 37 * and wrapping. 38 * <p> 39 * For an empirical discussion of the structure of method types, 40 * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/"> 41 * the thread "Avoiding Boxing" on jvm-languages</a>. 42 * There are approximately 2000 distinct erased method types in the JDK. 43 * There are a little over 10 times that number of unerased types. 44 * No more than half of these are likely to be loaded at once. 45 * @author John Rose 46 */ 47 final class MethodTypeForm { 48 final short parameterSlotCount; 49 final short primitiveCount; 50 final MethodType erasedType; // the canonical erasure 51 final MethodType basicType; // the canonical erasure, with primitives simplified 52 53 // Cached adapter information: 54 final SoftReference<MethodHandle>[] methodHandles; 55 56 // Indexes into methodHandles: 57 static final int 58 MH_BASIC_INV = 0, // cached instance of MH.invokeBasic 59 MH_NF_INV = 1, // cached helper for LF.NamedFunction 60 MH_UNINIT_CS = 2, // uninitialized call site 61 MH_LIMIT = 3; 62 63 // Cached lambda form information, for basic types only: 64 final SoftReference<LambdaForm>[] lambdaForms; 65 66 // Indexes into lambdaForms: 67 static final int 68 LF_INVVIRTUAL = 0, // DMH invokeVirtual 69 LF_INVSTATIC = 1, 70 LF_INVSPECIAL = 2, 71 LF_NEWINVSPECIAL = 3, 72 LF_INVINTERFACE = 4, 73 LF_INVSTATIC_INIT = 5, // DMH invokeStatic with <clinit> barrier 74 LF_INTERPRET = 6, // LF interpreter 75 LF_REBIND = 7, // BoundMethodHandle 76 LF_DELEGATE = 8, // DelegatingMethodHandle 77 LF_DELEGATE_BLOCK_INLINING = 9, // Counting DelegatingMethodHandle w/ @DontInline 78 LF_EX_LINKER = 10, // invokeExact_MT (for invokehandle) 79 LF_EX_INVOKER = 11, // MHs.invokeExact 80 LF_GEN_LINKER = 12, // generic invoke_MT (for invokehandle) 81 LF_GEN_INVOKER = 13, // generic MHs.invoke 82 LF_CS_LINKER = 14, // linkToCallSite_CS 83 LF_MH_LINKER = 15, // linkToCallSite_MH 84 LF_GWC = 16, // guardWithCatch (catchException) 85 LF_GWT = 17, // guardWithTest 86 LF_TF = 18, // tryFinally 87 LF_LOOP = 19, // loop 88 LF_INVSPECIAL_IFC = 20, // DMH invokeSpecial of (private) interface method 89 LF_LIMIT = 21; 90 91 /** Return the type corresponding uniquely (1-1) to this MT-form. 92 * It might have any primitive returns or arguments, but will have no references except Object. 93 */ erasedType()94 public MethodType erasedType() { 95 return erasedType; 96 } 97 98 /** Return the basic type derived from the erased type of this MT-form. 99 * A basic type is erased (all references Object) and also has all primitive 100 * types (except int, long, float, double, void) normalized to int. 101 * Such basic types correspond to low-level JVM calling sequences. 102 */ basicType()103 public MethodType basicType() { 104 return basicType; 105 } 106 cachedMethodHandle(int which)107 public MethodHandle cachedMethodHandle(int which) { 108 SoftReference<MethodHandle> entry = methodHandles[which]; 109 return (entry != null) ? entry.get() : null; 110 } 111 setCachedMethodHandle(int which, MethodHandle mh)112 public synchronized MethodHandle setCachedMethodHandle(int which, MethodHandle mh) { 113 // Simulate a CAS, to avoid racy duplication of results. 114 SoftReference<MethodHandle> entry = methodHandles[which]; 115 if (entry != null) { 116 MethodHandle prev = entry.get(); 117 if (prev != null) { 118 return prev; 119 } 120 } 121 methodHandles[which] = new SoftReference<>(mh); 122 return mh; 123 } 124 cachedLambdaForm(int which)125 public LambdaForm cachedLambdaForm(int which) { 126 SoftReference<LambdaForm> entry = lambdaForms[which]; 127 return (entry != null) ? entry.get() : null; 128 } 129 setCachedLambdaForm(int which, LambdaForm form)130 public synchronized LambdaForm setCachedLambdaForm(int which, LambdaForm form) { 131 // Simulate a CAS, to avoid racy duplication of results. 132 SoftReference<LambdaForm> entry = lambdaForms[which]; 133 if (entry != null) { 134 LambdaForm prev = entry.get(); 135 if (prev != null) { 136 return prev; 137 } 138 } 139 lambdaForms[which] = new SoftReference<>(form); 140 return form; 141 } 142 143 /** 144 * Build an MTF for a given type, which must have all references erased to Object. 145 * This MTF will stand for that type and all un-erased variations. 146 * Eagerly compute some basic properties of the type, common to all variations. 147 */ 148 @SuppressWarnings({"rawtypes", "unchecked"}) MethodTypeForm(MethodType erasedType)149 protected MethodTypeForm(MethodType erasedType) { 150 this.erasedType = erasedType; 151 152 Class<?>[] ptypes = erasedType.ptypes(); 153 int pslotCount = ptypes.length; 154 155 // Walk the argument types, looking for primitives. 156 short primitiveCount = 0, longArgCount = 0; 157 Class<?>[] erasedPtypes = ptypes; 158 Class<?>[] basicPtypes = erasedPtypes; 159 for (int i = 0; i < erasedPtypes.length; i++) { 160 Class<?> ptype = erasedPtypes[i]; 161 if (ptype != Object.class) { 162 ++primitiveCount; 163 Wrapper w = Wrapper.forPrimitiveType(ptype); 164 if (w.isDoubleWord()) ++longArgCount; 165 if (w.isSubwordOrInt() && ptype != int.class) { 166 if (basicPtypes == erasedPtypes) 167 basicPtypes = basicPtypes.clone(); 168 basicPtypes[i] = int.class; 169 } 170 } 171 } 172 pslotCount += longArgCount; // #slots = #args + #longs 173 Class<?> returnType = erasedType.returnType(); 174 Class<?> basicReturnType = returnType; 175 if (returnType != Object.class) { 176 ++primitiveCount; // even void.class counts as a prim here 177 Wrapper w = Wrapper.forPrimitiveType(returnType); 178 if (w.isSubwordOrInt() && returnType != int.class) 179 basicReturnType = int.class; 180 } 181 if (erasedPtypes == basicPtypes && basicReturnType == returnType) { 182 // Basic type 183 this.basicType = erasedType; 184 185 if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments"); 186 187 this.primitiveCount = primitiveCount; 188 this.parameterSlotCount = (short)pslotCount; 189 this.lambdaForms = new SoftReference[LF_LIMIT]; 190 this.methodHandles = new SoftReference[MH_LIMIT]; 191 } else { 192 this.basicType = MethodType.makeImpl(basicReturnType, basicPtypes, true); 193 // fill in rest of data from the basic type: 194 MethodTypeForm that = this.basicType.form(); 195 assert(this != that); 196 197 this.parameterSlotCount = that.parameterSlotCount; 198 this.primitiveCount = that.primitiveCount; 199 this.methodHandles = null; 200 this.lambdaForms = null; 201 } 202 } 203 parameterCount()204 public int parameterCount() { 205 return erasedType.parameterCount(); 206 } parameterSlotCount()207 public int parameterSlotCount() { 208 return parameterSlotCount; 209 } hasPrimitives()210 public boolean hasPrimitives() { 211 return primitiveCount != 0; 212 } 213 findForm(MethodType mt)214 static MethodTypeForm findForm(MethodType mt) { 215 MethodType erased = canonicalize(mt, ERASE, ERASE); 216 if (erased == null) { 217 // It is already erased. Make a new MethodTypeForm. 218 return new MethodTypeForm(mt); 219 } else { 220 // Share the MethodTypeForm with the erased version. 221 return erased.form(); 222 } 223 } 224 225 /** Codes for {@link #canonicalize(java.lang.Class, int)}. 226 * ERASE means change every reference to {@code Object}. 227 * WRAP means convert primitives (including {@code void} to their 228 * corresponding wrapper types. UNWRAP means the reverse of WRAP. 229 * INTS means convert all non-void primitive types to int or long, 230 * according to size. LONGS means convert all non-void primitives 231 * to long, regardless of size. RAW_RETURN means convert a type 232 * (assumed to be a return type) to int if it is smaller than an int, 233 * or if it is void. 234 */ 235 public static final int ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6; 236 237 /** Canonicalize the types in the given method type. 238 * If any types change, intern the new type, and return it. 239 * Otherwise return null. 240 */ canonicalize(MethodType mt, int howRet, int howArgs)241 public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) { 242 Class<?>[] ptypes = mt.ptypes(); 243 Class<?>[] ptypesCanonical = canonicalizeAll(ptypes, howArgs); 244 Class<?> rtype = mt.returnType(); 245 Class<?> rtypeCanonical = canonicalize(rtype, howRet); 246 if (ptypesCanonical == null && rtypeCanonical == null) { 247 // It is already canonical. 248 return null; 249 } 250 // Find the erased version of the method type: 251 if (rtypeCanonical == null) rtypeCanonical = rtype; 252 if (ptypesCanonical == null) ptypesCanonical = ptypes; 253 return MethodType.makeImpl(rtypeCanonical, ptypesCanonical, true); 254 } 255 256 /** Canonicalize the given return or param type. 257 * Return null if the type is already canonicalized. 258 */ canonicalize(Class<?> t, int how)259 static Class<?> canonicalize(Class<?> t, int how) { 260 Class<?> ct; 261 if (t == Object.class) { 262 // no change, ever 263 } else if (!t.isPrimitive()) { 264 switch (how) { 265 case UNWRAP: 266 ct = Wrapper.asPrimitiveType(t); 267 if (ct != t) return ct; 268 break; 269 case RAW_RETURN: 270 case ERASE: 271 return Object.class; 272 } 273 } else if (t == void.class) { 274 // no change, usually 275 switch (how) { 276 case RAW_RETURN: 277 return int.class; 278 case WRAP: 279 return Void.class; 280 } 281 } else { 282 // non-void primitive 283 switch (how) { 284 case WRAP: 285 return Wrapper.asWrapperType(t); 286 case INTS: 287 if (t == int.class || t == long.class) 288 return null; // no change 289 if (t == double.class) 290 return long.class; 291 return int.class; 292 case LONGS: 293 if (t == long.class) 294 return null; // no change 295 return long.class; 296 case RAW_RETURN: 297 if (t == int.class || t == long.class || 298 t == float.class || t == double.class) 299 return null; // no change 300 // everything else returns as an int 301 return int.class; 302 } 303 } 304 // no change; return null to signify 305 return null; 306 } 307 308 /** Canonicalize each param type in the given array. 309 * Return null if all types are already canonicalized. 310 */ canonicalizeAll(Class<?>[] ts, int how)311 static Class<?>[] canonicalizeAll(Class<?>[] ts, int how) { 312 Class<?>[] cs = null; 313 for (int imax = ts.length, i = 0; i < imax; i++) { 314 Class<?> c = canonicalize(ts[i], how); 315 // Void parameters may be unwrapped to void; ignore those 316 if (c != null && c != void.class) { 317 if (cs == null) 318 cs = ts.clone(); 319 cs[i] = c; 320 } 321 } 322 return cs; 323 } 324 325 @Override toString()326 public String toString() { 327 return "Form"+erasedType; 328 } 329 } 330