1 /* 2 * Copyright (c) 2008, 2022, 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_INVNATIVE = 21, // NMH invokeNative 90 LF_VH_EX_INVOKER = 22, // VarHandle exact invoker 91 LF_VH_GEN_INVOKER = 23, // VarHandle generic invoker 92 LF_VH_GEN_LINKER = 24, // VarHandle generic linker 93 LF_COLLECTOR = 25, // collector handle 94 LF_LIMIT = 26; 95 96 /** Return the type corresponding uniquely (1-1) to this MT-form. 97 * It might have any primitive returns or arguments, but will have no references except Object. 98 */ 99 public MethodType erasedType() { 100 return erasedType; 101 } 102 103 /** Return the basic type derived from the erased type of this MT-form. 104 * A basic type is erased (all references Object) and also has all primitive 105 * types (except int, long, float, double, void) normalized to int. 106 * Such basic types correspond to low-level JVM calling sequences. 107 */ 108 public MethodType basicType() { 109 return basicType; 110 } 111 112 public MethodHandle cachedMethodHandle(int which) { 113 SoftReference<MethodHandle> entry = methodHandles[which]; 114 return (entry != null) ? entry.get() : null; 115 } 116 117 public synchronized MethodHandle setCachedMethodHandle(int which, MethodHandle mh) { 118 // Simulate a CAS, to avoid racy duplication of results. 119 SoftReference<MethodHandle> entry = methodHandles[which]; 120 if (entry != null) { 121 MethodHandle prev = entry.get(); 122 if (prev != null) { 123 return prev; 124 } 125 } 126 methodHandles[which] = new SoftReference<>(mh); 127 return mh; 128 } 129 130 public LambdaForm cachedLambdaForm(int which) { 131 SoftReference<LambdaForm> entry = lambdaForms[which]; 132 return (entry != null) ? entry.get() : null; 133 } 134 135 public synchronized LambdaForm setCachedLambdaForm(int which, LambdaForm form) { 136 // Simulate a CAS, to avoid racy duplication of results. 137 SoftReference<LambdaForm> entry = lambdaForms[which]; 138 if (entry != null) { 139 LambdaForm prev = entry.get(); 140 if (prev != null) { 141 return prev; 142 } 143 } 144 lambdaForms[which] = new SoftReference<>(form); 145 return form; 146 } 147 148 /** 149 * Build an MTF for a given type, which must have all references erased to Object. 150 * This MTF will stand for that type and all un-erased variations. 151 * Eagerly compute some basic properties of the type, common to all variations. 152 */ 153 @SuppressWarnings({"rawtypes", "unchecked"}) 154 protected MethodTypeForm(MethodType erasedType) { 155 this.erasedType = erasedType; 156 157 Class<?>[] ptypes = erasedType.ptypes(); 158 int pslotCount = ptypes.length; 159 160 // Walk the argument types, looking for primitives. 161 short primitiveCount = 0, longArgCount = 0; 162 Class<?>[] erasedPtypes = ptypes; 163 Class<?>[] basicPtypes = erasedPtypes; 164 for (int i = 0; i < erasedPtypes.length; i++) { 165 Class<?> ptype = erasedPtypes[i]; 166 if (ptype != Object.class) { 167 ++primitiveCount; 168 Wrapper w = Wrapper.forPrimitiveType(ptype); 169 if (w.isDoubleWord()) ++longArgCount; 170 if (w.isSubwordOrInt() && ptype != int.class) { 171 if (basicPtypes == erasedPtypes) 172 basicPtypes = basicPtypes.clone(); 173 basicPtypes[i] = int.class; 174 } 175 } 176 } 177 pslotCount += longArgCount; // #slots = #args + #longs 178 Class<?> returnType = erasedType.returnType(); 179 Class<?> basicReturnType = returnType; 180 if (returnType != Object.class) { 181 ++primitiveCount; // even void.class counts as a prim here 182 Wrapper w = Wrapper.forPrimitiveType(returnType); 183 if (w.isSubwordOrInt() && returnType != int.class) 184 basicReturnType = int.class; 185 } 186 if (erasedPtypes == basicPtypes && basicReturnType == returnType) { 187 // Basic type 188 this.basicType = erasedType; 189 190 if (pslotCount >= 256) throw newIllegalArgumentException("too many arguments"); 191 192 this.primitiveCount = primitiveCount; 193 this.parameterSlotCount = (short)pslotCount; 194 this.lambdaForms = new SoftReference[LF_LIMIT]; 195 this.methodHandles = new SoftReference[MH_LIMIT]; 196 } else { 197 this.basicType = MethodType.methodType(basicReturnType, basicPtypes, true); 198 // fill in rest of data from the basic type: 199 MethodTypeForm that = this.basicType.form(); 200 assert(this != that); 201 202 this.parameterSlotCount = that.parameterSlotCount; 203 this.primitiveCount = that.primitiveCount; 204 this.methodHandles = null; 205 this.lambdaForms = null; 206 } 207 } 208 209 public int parameterCount() { 210 return erasedType.parameterCount(); 211 } 212 public int parameterSlotCount() { 213 return parameterSlotCount; 214 } 215 public boolean hasPrimitives() { 216 return primitiveCount != 0; 217 } 218 219 static MethodTypeForm findForm(MethodType mt) { 220 MethodType erased = canonicalize(mt, ERASE); 221 if (erased == null) { 222 // It is already erased. Make a new MethodTypeForm. 223 return new MethodTypeForm(mt); 224 } else { 225 // Share the MethodTypeForm with the erased version. 226 return erased.form(); 227 } 228 } 229 230 /** Codes for {@link #canonicalize(java.lang.Class, int)}. 231 * ERASE means change every reference to {@code Object}. 232 * WRAP means convert primitives (including {@code void} to their 233 * corresponding wrapper types. UNWRAP means the reverse of WRAP. 234 */ 235 public static final int ERASE = 1, WRAP = 2, UNWRAP = 3; 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 */ 241 public static MethodType canonicalize(MethodType mt, int how) { 242 Class<?>[] ptypes = mt.ptypes(); 243 Class<?>[] ptypesCanonical = canonicalizeAll(ptypes, how); 244 Class<?> rtype = mt.returnType(); 245 Class<?> rtypeCanonical = canonicalize(rtype, how); 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.methodType(rtypeCanonical, ptypesCanonical, true); 254 } 255 256 /** Canonicalize the given return or param type. 257 * Return null if the type is already canonicalized. 258 */ 259 static Class<?> canonicalize(Class<?> t, int how) { 260 if (t == Object.class) { 261 // no change, ever 262 } else if (!t.isPrimitive()) { 263 switch (how) { 264 case UNWRAP: 265 Class<?> ct = Wrapper.asPrimitiveType(t); 266 if (ct != t) return ct; 267 break; 268 case ERASE: 269 return Object.class; 270 } 271 } else if (how == WRAP) { 272 return Wrapper.asWrapperType(t); 273 } 274 // no change; return null to signify 275 return null; 276 } 277 278 /** Canonicalize each param type in the given array. 279 * Return null if all types are already canonicalized. 280 */ 281 static Class<?>[] canonicalizeAll(Class<?>[] ts, int how) { 282 Class<?>[] cs = null; 283 for (int imax = ts.length, i = 0; i < imax; i++) { 284 Class<?> c = canonicalize(ts[i], how); 285 // Void parameters may be unwrapped to void; ignore those 286 if (c != null && c != void.class) { 287 if (cs == null) 288 cs = ts.clone(); 289 cs[i] = c; 290 } 291 } 292 return cs; 293 } 294 295 @Override 296 public String toString() { 297 return "Form"+erasedType; 298 } 299 }