|
28 | 28 | import java.lang.invoke.MethodHandle;
|
29 | 29 | import java.lang.invoke.MethodType;
|
30 | 30 | import java.lang.invoke.VarHandle;
|
| 31 | +import java.lang.ref.SoftReference; |
31 | 32 | import java.lang.reflect.Field;
|
32 | 33 | import java.lang.reflect.InvocationTargetException;
|
33 | 34 | import java.lang.reflect.Member;
|
34 | 35 | import java.lang.reflect.Method;
|
| 36 | +import java.util.Map; |
35 | 37 | import java.util.Optional;
|
36 | 38 | import java.util.concurrent.ConcurrentHashMap;
|
37 | 39 | import java.util.function.Supplier;
|
@@ -240,6 +242,52 @@ public Object transform(Object receiver, Object originalValue) {
|
240 | 242 | }
|
241 | 243 | });
|
242 | 244 |
|
| 245 | + if (JavaVersionUtil.JAVA_SPEC >= 24) { |
| 246 | + /* |
| 247 | + * StringConcatFactory$InlineHiddenClassStrategy was added in JDK 24, as well as its |
| 248 | + * CACHE field, so there is no need to filter for previous JDK versions. |
| 249 | + */ |
| 250 | + Class<?> referencedKeyMapClazz = ReflectionUtil.lookupClass("jdk.internal.util.ReferencedKeyMap"); |
| 251 | + Method createMethod = ReflectionUtil.lookupMethod(referencedKeyMapClazz, "create", boolean.class, Supplier.class); |
| 252 | + Method concurrentHashMapSupplierMethod = ReflectionUtil.lookupMethod(referencedKeyMapClazz, "concurrentHashMapSupplier"); |
| 253 | + Class<?> methodHandlePair = ReflectionUtil.lookupClass("java.lang.invoke.StringConcatFactory$InlineHiddenClassStrategy$MethodHandlePair"); |
| 254 | + Method constructorGetter = ReflectionUtil.lookupMethod(methodHandlePair, "constructor"); |
| 255 | + Method concatenatorGetter = ReflectionUtil.lookupMethod(methodHandlePair, "concatenator"); |
| 256 | + |
| 257 | + /* |
| 258 | + * StringConcatFactory$InlineHiddenClassStrategy.CACHE is a cache like |
| 259 | + * SpeciesData.transformHelpers, so it needs a similar transformation for the same |
| 260 | + * reasons. |
| 261 | + */ |
| 262 | + access.registerFieldValueTransformer( |
| 263 | + ReflectionUtil.lookupField(ReflectionUtil.lookupClass("java.lang.invoke.StringConcatFactory$InlineHiddenClassStrategy"), "CACHE"), |
| 264 | + new FieldValueTransformerWithAvailability() { |
| 265 | + @Override |
| 266 | + public boolean isAvailable() { |
| 267 | + return BuildPhaseProvider.isHostedUniverseBuilt(); |
| 268 | + } |
| 269 | + |
| 270 | + @Override |
| 271 | + @SuppressWarnings("unchecked") |
| 272 | + public Object transform(Object receiver, Object originalValue) { |
| 273 | + Map<Object, SoftReference<Object>> cache = (Map<Object, SoftReference<Object>>) originalValue; |
| 274 | + Map<Object, Object> result = ReflectionUtil.invokeMethod(createMethod, null, true, ReflectionUtil.invokeMethod(concurrentHashMapSupplierMethod, null)); |
| 275 | + |
| 276 | + for (var entry : cache.entrySet()) { |
| 277 | + SoftReference<Object> value = entry.getValue(); |
| 278 | + Object object = value.get(); |
| 279 | + MethodHandle constructor = ReflectionUtil.invokeMethod(constructorGetter, object); |
| 280 | + MethodHandle concatenator = ReflectionUtil.invokeMethod(concatenatorGetter, object); |
| 281 | + if (constructor != null && concatenator != null && heapScanner.isObjectReachable(constructor) && heapScanner.isObjectReachable(concatenator)) { |
| 282 | + result.put(entry.getKey(), value); |
| 283 | + } |
| 284 | + } |
| 285 | + |
| 286 | + return result; |
| 287 | + } |
| 288 | + }); |
| 289 | + } |
| 290 | + |
243 | 291 | /*
|
244 | 292 | * Retrieve all six basic types from the java.lang.invoke.LambdaForm$BasicType class (void,
|
245 | 293 | * int, long, float, double, Object) and invoke the
|
|
0 commit comments