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