Skip to content

Commit 6e859d9

Browse files
author
Christian Wimmer
committed
Eagerly initialize caches in method handle implementation
1 parent 98b7f8e commit 6e859d9

File tree

1 file changed

+46
-90
lines changed

1 file changed

+46
-90
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleFeature.java

Lines changed: 46 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,11 @@
2727
import java.lang.invoke.CallSite;
2828
import java.lang.invoke.MethodHandle;
2929
import java.lang.invoke.MethodType;
30-
import java.lang.reflect.Array;
30+
import java.lang.invoke.VarHandle;
3131
import java.lang.reflect.Field;
3232
import java.lang.reflect.InvocationTargetException;
3333
import java.lang.reflect.Member;
3434
import java.lang.reflect.Method;
35-
import java.util.Iterator;
3635
import java.util.Optional;
3736
import java.util.concurrent.ConcurrentHashMap;
3837
import java.util.function.Supplier;
@@ -108,20 +107,20 @@ public class MethodHandleFeature implements InternalFeature {
108107

109108
@Override
110109
public void duringSetup(DuringSetupAccess access) {
111-
Class<?> memberNameClass = access.findClassByName("java.lang.invoke.MemberName");
110+
Class<?> memberNameClass = ReflectionUtil.lookupClass("java.lang.invoke.MemberName");
112111
memberNameIsMethod = ReflectionUtil.lookupMethod(memberNameClass, "isMethod");
113112
memberNameIsConstructor = ReflectionUtil.lookupMethod(memberNameClass, "isConstructor");
114113
memberNameIsField = ReflectionUtil.lookupMethod(memberNameClass, "isField");
115114
memberNameGetMethodType = ReflectionUtil.lookupMethod(memberNameClass, "getMethodType");
116115

117-
Class<?> arrayAccessorClass = access.findClassByName("java.lang.invoke.MethodHandleImpl$ArrayAccessor");
116+
Class<?> arrayAccessorClass = ReflectionUtil.lookupClass("java.lang.invoke.MethodHandleImpl$ArrayAccessor");
118117
typedAccessors = ReflectionUtil.lookupField(arrayAccessorClass, "TYPED_ACCESSORS");
119-
Class<?> methodHandleImplClass = access.findClassByName("java.lang.invoke.MethodHandleImpl$Makers");
120-
typedCollectors = ReflectionUtil.lookupField(methodHandleImplClass, "TYPED_COLLECTORS");
118+
Class<?> makersClass = ReflectionUtil.lookupClass("java.lang.invoke.MethodHandleImpl$Makers");
119+
typedCollectors = ReflectionUtil.lookupField(makersClass, "TYPED_COLLECTORS");
121120

122121
if (JavaVersionUtil.JAVA_SPEC >= 22) {
123122
try {
124-
Class<?> referencedKeySetClass = access.findClassByName("jdk.internal.util.ReferencedKeySet");
123+
Class<?> referencedKeySetClass = ReflectionUtil.lookupClass("jdk.internal.util.ReferencedKeySet");
125124
Method create = ReflectionUtil.lookupMethod(referencedKeySetClass, "create", boolean.class, boolean.class, Supplier.class);
126125
// The following call must match the static initializer of MethodType#internTable.
127126
runtimeMethodTypeInternTable = create.invoke(null,
@@ -131,7 +130,7 @@ public void duringSetup(DuringSetupAccess access) {
131130
throw VMError.shouldNotReachHere(e);
132131
}
133132
} else {
134-
Class<?> concurrentWeakInternSetClass = access.findClassByName("java.lang.invoke.MethodType$ConcurrentWeakInternSet");
133+
Class<?> concurrentWeakInternSetClass = ReflectionUtil.lookupClass("java.lang.invoke.MethodType$ConcurrentWeakInternSet");
135134
runtimeMethodTypeInternTable = ReflectionUtil.newInstance(concurrentWeakInternSetClass);
136135
referencedKeySetAdd = ReflectionUtil.lookupMethod(concurrentWeakInternSetClass, "add", Object.class);
137136
}
@@ -148,45 +147,22 @@ public void duringSetup(DuringSetupAccess access) {
148147
public void beforeAnalysis(BeforeAnalysisAccess a) {
149148
var access = (BeforeAnalysisAccessImpl) a;
150149

151-
/* java.lang.invoke functions called through reflection */
152-
Class<?> mhImplClazz = access.findClassByName("java.lang.invoke.MethodHandleImpl");
153-
154-
access.registerReachabilityHandler(MethodHandleFeature::registerMHImplFunctionsForReflection,
155-
ReflectionUtil.lookupMethod(mhImplClazz, "getFunction", byte.class));
156-
157-
access.registerReachabilityHandler(MethodHandleFeature::registerMHImplConstantHandlesForReflection,
158-
ReflectionUtil.lookupMethod(mhImplClazz, "makeConstantHandle", int.class));
159-
160-
access.registerReachabilityHandler(MethodHandleFeature::registerMHImplCountingWrapperFunctionsForReflection,
161-
access.findClassByName("java.lang.invoke.MethodHandleImpl$CountingWrapper"));
162-
163-
access.registerReachabilityHandler(MethodHandleFeature::registerInvokersFunctionsForReflection,
164-
ReflectionUtil.lookupMethod(access.findClassByName("java.lang.invoke.Invokers"), "getFunction", byte.class));
165-
150+
eagerlyInitializeMHImplFunctions();
151+
eagerlyInitializeMHImplConstantHandles();
152+
eagerlyInitializeInvokersFunctions();
166153
eagerlyInitializeValueConversionsCaches();
154+
eagerlyInitializeCallSite();
167155

168-
access.registerClassInitializerReachabilityHandler(MethodHandleFeature::registerDelegatingMHFunctionsForReflection,
169-
access.findClassByName("java.lang.invoke.DelegatingMethodHandle"));
170-
171-
access.registerReachabilityHandler(MethodHandleFeature::registerCallSiteGetTargetForReflection,
172-
ReflectionUtil.lookupMethod(CallSite.class, "getTargetHandle"));
173-
174-
access.registerReachabilityHandler(MethodHandleFeature::registerUninitializedCallSiteForReflection,
175-
ReflectionUtil.lookupMethod(CallSite.class, "uninitializedCallSiteHandle"));
176-
177-
access.registerSubtypeReachabilityHandler(MethodHandleFeature::registerVarHandleMethodsForReflection,
178-
access.findClassByName("java.lang.invoke.VarHandle"));
179-
180-
access.registerSubtypeReachabilityHandler(MethodHandleFeature::scanBoundMethodHandle,
181-
access.findClassByName("java.lang.invoke.BoundMethodHandle"));
156+
access.registerSubtypeReachabilityHandler(MethodHandleFeature::registerVarHandleMethodsForReflection, VarHandle.class);
157+
access.registerSubtypeReachabilityHandler(MethodHandleFeature::scanBoundMethodHandle, ReflectionUtil.lookupClass("java.lang.invoke.BoundMethodHandle"));
182158

183159
AnalysisMetaAccess metaAccess = access.getMetaAccess();
184160
ImageHeapScanner heapScanner = access.getUniverse().getHeapScanner();
185161

186162
access.registerFieldValueTransformer(
187-
ReflectionUtil.lookupField(ReflectionUtil.lookupClass(false, "java.lang.invoke.ClassSpecializer"), "cache"),
163+
ReflectionUtil.lookupField(ReflectionUtil.lookupClass("java.lang.invoke.ClassSpecializer"), "cache"),
188164
new FieldValueTransformerWithAvailability() {
189-
private static final Class<?> speciesDataClass = ReflectionUtil.lookupClass(false, "java.lang.invoke.ClassSpecializer$SpeciesData");
165+
private static final Class<?> SPECIES_DATA_CLASS = ReflectionUtil.lookupClass("java.lang.invoke.ClassSpecializer$SpeciesData");
190166

191167
/*
192168
* The value of the ClassSpecializer.cache is not seen by the analysis
@@ -215,16 +191,16 @@ public Object transform(Object receiver, Object originalValue) {
215191
}
216192

217193
private boolean isSpeciesTypeInstantiated(Object speciesData) {
218-
Class<?> speciesClass = ReflectionUtil.readField(speciesDataClass, "speciesCode", speciesData);
194+
Class<?> speciesClass = ReflectionUtil.readField(SPECIES_DATA_CLASS, "speciesCode", speciesData);
219195
Optional<AnalysisType> analysisType = metaAccess.optionalLookupJavaType(speciesClass);
220196
return analysisType.isPresent() && analysisType.get().isInstantiated();
221197
}
222198
});
223199
access.registerFieldValueTransformer(
224-
ReflectionUtil.lookupField(ReflectionUtil.lookupClass(false, "java.lang.invoke.DirectMethodHandle"), "ACCESSOR_FORMS"),
200+
ReflectionUtil.lookupField(ReflectionUtil.lookupClass("java.lang.invoke.DirectMethodHandle"), "ACCESSOR_FORMS"),
225201
NewEmptyArrayFieldValueTransformer.INSTANCE);
226202
access.registerFieldValueTransformer(
227-
ReflectionUtil.lookupField(ReflectionUtil.lookupClass(false, "java.lang.invoke.MethodType"), "internTable"),
203+
ReflectionUtil.lookupField(ReflectionUtil.lookupClass("java.lang.invoke.MethodType"), "internTable"),
228204
(receiver, originalValue) -> runtimeMethodTypeInternTable);
229205

230206
/*
@@ -236,7 +212,7 @@ private boolean isSpeciesTypeInstantiated(Object speciesData) {
236212
* be made reachable after analysis.
237213
*/
238214
access.registerFieldValueTransformer(
239-
ReflectionUtil.lookupField(ReflectionUtil.lookupClass(false, "java.lang.invoke.ClassSpecializer$SpeciesData"), "transformHelpers"),
215+
ReflectionUtil.lookupField(ReflectionUtil.lookupClass("java.lang.invoke.ClassSpecializer$SpeciesData"), "transformHelpers"),
240216
new FieldValueTransformerWithAvailability() {
241217
@Override
242218
public boolean isAvailable() {
@@ -267,8 +243,8 @@ public Object transform(Object receiver, Object originalValue) {
267243
* method Feature.beforeCompilation()), thereby registering new elements into the image heap
268244
* (elements that were not tracked in the analysis).
269245
*/
270-
Class<?> lambdaFormClass = ReflectionUtil.lookupClass(false, "java.lang.invoke.LambdaForm");
271-
Class<?> basicTypeClass = ReflectionUtil.lookupClass(false, "java.lang.invoke.LambdaForm$BasicType");
246+
Class<?> lambdaFormClass = ReflectionUtil.lookupClass("java.lang.invoke.LambdaForm");
247+
Class<?> basicTypeClass = ReflectionUtil.lookupClass("java.lang.invoke.LambdaForm$BasicType");
272248
Method createFormsForMethod = ReflectionUtil.lookupMethod(lambdaFormClass, "createFormsFor", basicTypeClass);
273249
try {
274250
for (Object type : (Object[]) ReflectionUtil.readStaticField(basicTypeClass, "ALL_TYPES")) {
@@ -279,43 +255,31 @@ public Object transform(Object receiver, Object originalValue) {
279255
}
280256
}
281257

282-
private static void registerMHImplFunctionsForReflection(DuringAnalysisAccess access) {
283-
Class<?> mhImplClazz = access.findClassByName("java.lang.invoke.MethodHandleImpl");
284-
RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "checkSpreadArgument", Object.class, int.class));
285-
RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "guardWithCatch", MethodHandle.class, Class.class, MethodHandle.class, Object[].class));
286-
RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "tryFinally", MethodHandle.class, MethodHandle.class, Object[].class));
287-
RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "loop", access.findClassByName("[Ljava.lang.invoke.LambdaForm$BasicType;"),
288-
access.findClassByName("java.lang.invoke.MethodHandleImpl$LoopClauses"), Object[].class));
289-
RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "throwException", Throwable.class));
290-
RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "profileBoolean", boolean.class, int[].class));
291-
}
292-
293-
private static void registerMHImplConstantHandlesForReflection(DuringAnalysisAccess access) {
294-
Class<?> mhImplClazz = access.findClassByName("java.lang.invoke.MethodHandleImpl");
295-
RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "selectAlternative", boolean.class, MethodHandle.class, MethodHandle.class));
296-
RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "countedLoopPredicate", int.class, int.class));
297-
RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "countedLoopStep", int.class, int.class));
298-
RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "initIterator", Iterable.class));
299-
RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "iteratePredicate", Iterator.class));
300-
RuntimeReflection.register(ReflectionUtil.lookupMethod(mhImplClazz, "iterateNext", Iterator.class));
301-
RuntimeReflection.register(ReflectionUtil.lookupMethod(Array.class, "newInstance", Class.class, int.class));
258+
private static void eagerlyInitializeMHImplFunctions() {
259+
var methodHandleImplClass = ReflectionUtil.lookupClass("java.lang.invoke.MethodHandleImpl");
260+
int count = ((Object[]) ReflectionUtil.readStaticField(methodHandleImplClass, "NFS")).length;
261+
var getFunctionMethod = ReflectionUtil.lookupMethod(methodHandleImplClass, "getFunction", byte.class);
262+
for (int i = 0; i < count; i++) {
263+
ReflectionUtil.invokeMethod(getFunctionMethod, null, (byte) i);
264+
}
302265
}
303266

304-
private static void registerMHImplCountingWrapperFunctionsForReflection(DuringAnalysisAccess access) {
305-
RuntimeReflection.register(ReflectionUtil.lookupMethod(access.findClassByName("java.lang.invoke.MethodHandleImpl$CountingWrapper"), "maybeStopCounting", Object.class));
267+
private static void eagerlyInitializeMHImplConstantHandles() {
268+
var methodHandleImplClass = ReflectionUtil.lookupClass("java.lang.invoke.MethodHandleImpl");
269+
int count = ((Object[]) ReflectionUtil.readStaticField(methodHandleImplClass, "HANDLES")).length;
270+
var getConstantHandleMethod = ReflectionUtil.lookupMethod(methodHandleImplClass, "getConstantHandle", int.class);
271+
for (int i = 0; i < count; i++) {
272+
ReflectionUtil.invokeMethod(getConstantHandleMethod, null, i);
273+
}
306274
}
307275

308-
private static void registerInvokersFunctionsForReflection(DuringAnalysisAccess access) {
309-
Class<?> invokersClazz = access.findClassByName("java.lang.invoke.Invokers");
310-
RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "checkExactType", MethodHandle.class, MethodType.class));
311-
RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "checkGenericType", MethodHandle.class, MethodType.class));
312-
RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "getCallSiteTarget", CallSite.class));
313-
RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "checkCustomized", MethodHandle.class));
314-
RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "checkVarHandleGenericType", access.findClassByName("java.lang.invoke.VarHandle"),
315-
access.findClassByName("java.lang.invoke.VarHandle$AccessDescriptor")));
316-
RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "checkVarHandleExactType", access.findClassByName("java.lang.invoke.VarHandle"),
317-
access.findClassByName("java.lang.invoke.VarHandle$AccessDescriptor")));
318-
RuntimeReflection.register(ReflectionUtil.lookupMethod(invokersClazz, "directVarHandleTarget", access.findClassByName("java.lang.invoke.VarHandle")));
276+
private static void eagerlyInitializeInvokersFunctions() {
277+
var invokerksClass = ReflectionUtil.lookupClass("java.lang.invoke.Invokers");
278+
int count = ((Object[]) ReflectionUtil.readStaticField(invokerksClass, "NFS")).length;
279+
var getFunctionMethod = ReflectionUtil.lookupMethod(invokerksClass, "getFunction", byte.class);
280+
for (int i = 0; i < count; i++) {
281+
ReflectionUtil.invokeMethod(getFunctionMethod, null, (byte) i);
282+
}
319283
}
320284

321285
/**
@@ -344,21 +308,13 @@ private static void eagerlyInitializeValueConversionsCaches() {
344308
}
345309
}
346310

347-
private static void registerDelegatingMHFunctionsForReflection(DuringAnalysisAccess access) {
348-
Class<?> delegatingMHClazz = access.findClassByName("java.lang.invoke.DelegatingMethodHandle");
349-
RuntimeReflection.register(ReflectionUtil.lookupMethod(delegatingMHClazz, "getTarget"));
350-
}
351-
352-
private static void registerCallSiteGetTargetForReflection(DuringAnalysisAccess access) {
353-
RuntimeReflection.register(ReflectionUtil.lookupMethod(CallSite.class, "getTarget"));
354-
}
355-
356-
private static void registerUninitializedCallSiteForReflection(DuringAnalysisAccess access) {
357-
RuntimeReflection.register(ReflectionUtil.lookupMethod(CallSite.class, "uninitializedCallSite", Object[].class));
311+
private static void eagerlyInitializeCallSite() {
312+
ReflectionUtil.invokeMethod(ReflectionUtil.lookupMethod(CallSite.class, "getTargetHandle"), null);
313+
ReflectionUtil.invokeMethod(ReflectionUtil.lookupMethod(CallSite.class, "uninitializedCallSiteHandle"), null);
358314
}
359315

360316
private static void registerVarHandleMethodsForReflection(FeatureAccess access, Class<?> subtype) {
361-
if (subtype.getPackage().getName().equals("java.lang.invoke") && subtype != access.findClassByName("java.lang.invoke.VarHandle")) {
317+
if (subtype.getPackage().getName().equals("java.lang.invoke") && subtype != VarHandle.class) {
362318
RuntimeReflection.register(subtype.getDeclaredMethods());
363319
}
364320
}

0 commit comments

Comments
 (0)