Path: blob/master/jcl/src/java.base/share/classes/java/lang/invoke/HandleCache.java
12521 views
/*[INCLUDE-IF Sidecar17 & !OPENJDK_METHODHANDLES]*/1/*******************************************************************************2* Copyright (c) 2010, 2020 IBM Corp. and others3*4* This program and the accompanying materials are made available under5* the terms of the Eclipse Public License 2.0 which accompanies this6* distribution and is available at https://www.eclipse.org/legal/epl-2.0/7* or the Apache License, Version 2.0 which accompanies this distribution and8* is available at https://www.apache.org/licenses/LICENSE-2.0.9*10* This Source Code may also be made available under the following11* Secondary Licenses when the conditions for such availability set12* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU13* General Public License, version 2 with the GNU Classpath14* Exception [1] and GNU General Public License, version 2 with the15* OpenJDK Assembly Exception [2].16*17* [1] https://www.gnu.org/software/classpath/license.html18* [2] http://openjdk.java.net/legal/assembly-exception.html19*20* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception21*******************************************************************************/22package java.lang.invoke;2324import java.lang.ref.WeakReference;25import java.util.Collections;26import java.util.Map;27import java.util.WeakHashMap;2829/*30* ClassValue based Cache for mapping from a Class to its perClassCache.31*/32final class Cache extends ClassValue<Map<CacheKey, WeakReference<MethodHandle>>> {33@Override34protected Map<CacheKey, WeakReference<MethodHandle>> computeValue(Class<?> arg0) {35return Collections.synchronizedMap(new WeakHashMap<CacheKey, WeakReference<MethodHandle>>());36}37}3839/* Cache key for mapping the methodName and MethodType to the actual MethodHandle */40final class MethodCacheKey extends CacheKey {41private final MethodType type;42private final Class<?> specialCaller;4344public MethodCacheKey(String name, MethodType mt, Class<?> specialCaller) {45super(name, calculateHashcode(name, mt, specialCaller));4647this.type = mt;48this.specialCaller = specialCaller;49}5051private static int calculateHashcode(String name, MethodType mt, Class<?> specialCaller) {52/* Hash code based off MethodType.hashCode() */53int hash = 31 + mt.hashCode();54hash = 31 * hash + name.hashCode();5556if (specialCaller != null) {57hash = 31 * hash + specialCaller.hashCode();58}59return hash;60}6162@Override63public boolean equals(Object o) {64if ((o == null) || !(o instanceof MethodCacheKey)) {65return false;66}67MethodCacheKey other = (MethodCacheKey) o;68if ((other.type == type) && other.name.equals(name) && (other.specialCaller == this.specialCaller)) {69return true;70}71return false;72}73}7475final class FieldCacheKey extends CacheKey {76private final Class<?> fieldType;7778public FieldCacheKey(String fieldName, Class<?> fieldType) {79super(fieldName, calculateHashcode(fieldName, fieldType));80this.fieldType = fieldType;81}8283private static int calculateHashcode(String fieldName, Class<?> fieldType) {84/* Hash code based off MethodType.hashCode() */85int hash = 31 + fieldType.hashCode();86hash = 31 * hash + fieldName.hashCode();87return hash;88}899091@Override92public boolean equals(Object o){93if ((o == null) || !(o instanceof FieldCacheKey)) {94return false;95}96FieldCacheKey other = (FieldCacheKey) o;97if (other.fieldType == fieldType && other.name.equals(name)) {98return true;99}100return false;101}102}103104/* The handle cache itself - it holds onto the individual caches for:105* findVirtual106* findStatic107* findSpecial108* findConstructor109*/110final class HandleCache {111private static final Cache findVirtualCache = new Cache();112private static final Cache findStaticCache = new Cache();113private static final Cache findSpecialCache = new Cache();114private static final Cache findConstructorCache = new Cache();115private static final Cache staticFieldSetterCache = new Cache();116private static final Cache staticFieldGetterCache = new Cache();117private static final Cache fieldSetterCache = new Cache();118private static final Cache fieldGetterCache = new Cache();119120static Map<CacheKey, WeakReference<MethodHandle>> getVirtualCache(Class<?> c) {121return findVirtualCache.get(c);122}123static Map<CacheKey, WeakReference<MethodHandle>> getStaticCache(Class<?> c) {124return findStaticCache.get(c);125}126static Map<CacheKey, WeakReference<MethodHandle>> getSpecialCache(Class<?> c) {127return findSpecialCache.get(c);128}129static Map<CacheKey, WeakReference<MethodHandle>> getConstructorCache(Class<?> c) {130return findConstructorCache.get(c);131}132static Map<CacheKey, WeakReference<MethodHandle>> getFieldSetterCache(Class<?> c) {133return fieldSetterCache.get(c);134}135static Map<CacheKey, WeakReference<MethodHandle>> getFieldGetterCache(Class<?> c) {136return fieldGetterCache.get(c);137}138static Map<CacheKey, WeakReference<MethodHandle>> getStaticFieldSetterCache(Class<?> c) {139return staticFieldSetterCache.get(c);140}141static Map<CacheKey, WeakReference<MethodHandle>> getStaticFieldGetterCache(Class<?> c) {142return staticFieldGetterCache.get(c);143}144145/* Search the 'perClassCache' returned by one of the 'get{Virtual|Static|Special|Constructor}Cache(Class)' methods146* for the MethodHandle with matching name and type.147*/148public static MethodHandle getMethodFromPerClassCache(Map<CacheKey, WeakReference<MethodHandle>> perClassCache, String name, MethodType type) {149return getMethodWithSpecialCallerFromPerClassCache(perClassCache, name, type, null);150}151152public static MethodHandle getMethodWithSpecialCallerFromPerClassCache(Map<CacheKey, WeakReference<MethodHandle>> perClassCache, String name, MethodType type, Class<?> specialCaller) {153WeakReference<MethodHandle> handleRef = perClassCache.get(new MethodCacheKey(name, type, specialCaller));154if (handleRef != null) {155return handleRef.get();156}157return null;158}159160public static MethodHandle getFieldFromPerClassCache(Map<CacheKey, WeakReference<MethodHandle>> perClassCache, String name, Class<?> fieldType) {161WeakReference<MethodHandle> handleRef = perClassCache.get(new FieldCacheKey(name, fieldType));162if (handleRef != null) {163return handleRef.get();164}165return null;166}167168/* Update the cache to hold the <Name, Type> -> MethodHandle mapping */169public static MethodHandle putMethodInPerClassCache(Map<CacheKey, WeakReference<MethodHandle>> perClassCache, String name, MethodType type, MethodHandle handle) {170return putMethodWithSpecialCallerInPerClassCache(perClassCache, name, type, handle, null);171}172173/* Update the cache to hold the <Name, Type, SpecialCaller> -> MethodHandle mapping */174public static MethodHandle putMethodWithSpecialCallerInPerClassCache(Map<CacheKey, WeakReference<MethodHandle>> perClassCache, String name, MethodType type, MethodHandle handle, Class<?> specialCaller) {175return cacheHandle(perClassCache, new MethodCacheKey(name, type, specialCaller), handle);176}177178/* Update the cache to hold the <Name, FieldType> -> MethodHandle mapping */179public static MethodHandle putFieldInPerClassCache(Map<CacheKey, WeakReference<MethodHandle>> perClassCache, String fieldName, Class<?> fieldType, MethodHandle handle) {180return cacheHandle(perClassCache, new FieldCacheKey(fieldName, fieldType), handle);181}182183private static MethodHandle cacheHandle(Map<CacheKey, WeakReference<MethodHandle>> perClassCache, CacheKey cacheKey, MethodHandle handle){184/* Keep a strong reference to the FieldCacheKey in the MH being cached so that it won't185* be immediately collected. Uses a WeakHashMap<FieldCacheKey, WeakRef<MH>> to cache.186* Since the MH keeps a strong ref to the FieldCacheKey, as long as the MH is alive187* the Key can't be collected, despite being a weakref.188*/189handle.cacheKey = cacheKey;190perClassCache.put(handle.cacheKey, new WeakReference<MethodHandle>(handle));191return handle;192}193194}195196197198