33
33
import java .lang .reflect .InvocationTargetException ;
34
34
import java .lang .reflect .Member ;
35
35
import java .lang .reflect .Method ;
36
+ import java .util .HashSet ;
36
37
import java .util .Map ;
37
- import java .util .Optional ;
38
+ import java .util .Set ;
38
39
import java .util .concurrent .ConcurrentHashMap ;
39
40
import java .util .function .Supplier ;
40
41
41
42
import org .graalvm .nativeimage .hosted .RuntimeReflection ;
42
43
43
44
import com .oracle .graal .pointsto .heap .ImageHeapScanner ;
44
45
import com .oracle .graal .pointsto .meta .AnalysisMetaAccess ;
45
- import com .oracle .graal .pointsto .meta .AnalysisType ;
46
46
import com .oracle .svm .core .BuildPhaseProvider ;
47
47
import com .oracle .svm .core .feature .AutomaticallyRegisteredFeature ;
48
48
import com .oracle .svm .core .feature .InternalFeature ;
@@ -107,6 +107,8 @@ public class MethodHandleFeature implements InternalFeature {
107
107
108
108
private MethodHandleInvokerRenamingSubstitutionProcessor substitutionProcessor ;
109
109
110
+ private Set <Object > heapSpeciesData = new HashSet <>();
111
+
110
112
@ Override
111
113
public void duringSetup (DuringSetupAccess access ) {
112
114
Class <?> memberNameClass = ReflectionUtil .lookupClass ("java.lang.invoke.MemberName" );
@@ -149,6 +151,8 @@ public void duringSetup(DuringSetupAccess access) {
149
151
150
152
accessImpl .registerObjectReachableCallback (memberNameClass , (a1 , member , reason ) -> registerHeapMemberName ((Member ) member ));
151
153
accessImpl .registerObjectReachableCallback (MethodType .class , (a1 , methodType , reason ) -> registerHeapMethodType (methodType ));
154
+ Class <?> speciesDataClass = ReflectionUtil .lookupClass ("java.lang.invoke.BoundMethodHandle$SpeciesData" );
155
+ accessImpl .registerObjectReachableCallback (speciesDataClass , (a1 , speciesData , reason ) -> registerHeapSpeciesData (speciesData ));
152
156
}
153
157
154
158
@ Override
@@ -167,9 +171,6 @@ public void beforeAnalysis(BeforeAnalysisAccess a) {
167
171
AnalysisMetaAccess metaAccess = access .getMetaAccess ();
168
172
ImageHeapScanner heapScanner = access .getUniverse ().getHeapScanner ();
169
173
170
- // GR-60093: currently, Species_L is needed at runtime but not seen by the analysis
171
- access .registerAsInHeap (ReflectionUtil .lookupClass ("java.lang.invoke.BoundMethodHandle$Species_L" ));
172
-
173
174
access .registerFieldValueTransformer (
174
175
ReflectionUtil .lookupField (ReflectionUtil .lookupClass ("java.lang.invoke.ClassSpecializer" ), "cache" ),
175
176
new FieldValueTransformerWithAvailability () {
@@ -194,18 +195,14 @@ public Object transform(Object receiver, Object originalValue) {
194
195
ConcurrentHashMap <Object , Object > originalMap = (ConcurrentHashMap <Object , Object >) originalValue ;
195
196
ConcurrentHashMap <Object , Object > filteredMap = new ConcurrentHashMap <>();
196
197
originalMap .forEach ((key , speciesData ) -> {
197
- if (isSpeciesTypeInstantiated (speciesData )) {
198
+ if (heapSpeciesData . contains (speciesData )) {
198
199
filteredMap .put (key , speciesData );
199
200
}
200
201
});
202
+ /* No uses of heapSpeciesData should be needed after this point. */
203
+ heapSpeciesData = null ;
201
204
return filteredMap ;
202
205
}
203
-
204
- private boolean isSpeciesTypeInstantiated (Object speciesData ) {
205
- Class <?> speciesClass = ReflectionUtil .readField (SPECIES_DATA_CLASS , "speciesCode" , speciesData );
206
- Optional <AnalysisType > analysisType = metaAccess .optionalLookupJavaType (speciesClass );
207
- return analysisType .isPresent () && analysisType .get ().isInstantiated ();
208
- }
209
206
});
210
207
access .registerFieldValueTransformer (
211
208
ReflectionUtil .lookupField (ReflectionUtil .lookupClass ("java.lang.invoke.DirectMethodHandle" ), "ACCESSOR_FORMS" ),
@@ -214,36 +211,37 @@ private boolean isSpeciesTypeInstantiated(Object speciesData) {
214
211
ReflectionUtil .lookupField (ReflectionUtil .lookupClass ("java.lang.invoke.MethodType" ), "internTable" ),
215
212
(receiver , originalValue ) -> runtimeMethodTypeInternTable );
216
213
214
+ FieldValueTransformerWithAvailability methodHandleArrayTransformer = new FieldValueTransformerWithAvailability () {
215
+ @ Override
216
+ public boolean isAvailable () {
217
+ return BuildPhaseProvider .isHostedUniverseBuilt ();
218
+ }
219
+
220
+ @ Override
221
+ @ SuppressWarnings ("unchecked" )
222
+ public Object transform (Object receiver , Object originalValue ) {
223
+ MethodHandle [] originalArray = (MethodHandle []) originalValue ;
224
+ MethodHandle [] filteredArray = new MethodHandle [originalArray .length ];
225
+ for (int i = 0 ; i < originalArray .length ; i ++) {
226
+ MethodHandle handle = originalArray [i ];
227
+ if (handle != null && heapScanner .isObjectReachable (handle )) {
228
+ filteredArray [i ] = handle ;
229
+ }
230
+ }
231
+ return filteredArray ;
232
+ }
233
+ };
234
+
217
235
/*
218
- * SpeciesData.transformHelpers is a lazily initialized cache of MethodHandle objects. We do
219
- * not want to make a MethodHandle reachable just because the image builder initialized the
220
- * cache, so we filter out unreachable objects. This also solves the problem when late image
221
- * heap re-scanning after static analysis would see a method handle that was not yet cached
222
- * during static analysis, in which case image building would fail because new types would
223
- * be made reachable after analysis.
236
+ * SpeciesData.transformHelpers and MethodHandleImpl.ARRAYS are lazily initialized caches of
237
+ * MethodHandle objects. We do not want to make a MethodHandle reachable just because the
238
+ * image builder initialized a cache, so we filter out unreachable objects. This also solves
239
+ * the problem when late image heap re-scanning after static analysis would see a method
240
+ * handle that was not yet cached during static analysis, in which case image building would
241
+ * fail because new types would be made reachable after analysis.
224
242
*/
225
- access .registerFieldValueTransformer (
226
- ReflectionUtil .lookupField (ReflectionUtil .lookupClass ("java.lang.invoke.ClassSpecializer$SpeciesData" ), "transformHelpers" ),
227
- new FieldValueTransformerWithAvailability () {
228
- @ Override
229
- public boolean isAvailable () {
230
- return BuildPhaseProvider .isHostedUniverseBuilt ();
231
- }
232
-
233
- @ Override
234
- @ SuppressWarnings ("unchecked" )
235
- public Object transform (Object receiver , Object originalValue ) {
236
- MethodHandle [] originalArray = (MethodHandle []) originalValue ;
237
- MethodHandle [] filteredArray = new MethodHandle [originalArray .length ];
238
- for (int i = 0 ; i < originalArray .length ; i ++) {
239
- MethodHandle handle = originalArray [i ];
240
- if (handle != null && heapScanner .isObjectReachable (handle )) {
241
- filteredArray [i ] = handle ;
242
- }
243
- }
244
- return filteredArray ;
245
- }
246
- });
243
+ access .registerFieldValueTransformer (ReflectionUtil .lookupField (ReflectionUtil .lookupClass ("java.lang.invoke.ClassSpecializer$SpeciesData" ), "transformHelpers" ), methodHandleArrayTransformer );
244
+ access .registerFieldValueTransformer (ReflectionUtil .lookupField (ReflectionUtil .lookupClass ("java.lang.invoke.MethodHandleImpl" ), "ARRAYS" ), methodHandleArrayTransformer );
247
245
248
246
if (JavaVersionUtil .JAVA_SPEC >= 24 ) {
249
247
/*
@@ -417,6 +415,11 @@ public void registerHeapMemberName(Member memberName) {
417
415
}
418
416
}
419
417
418
+ public void registerHeapSpeciesData (Object speciesData ) {
419
+ VMError .guarantee (heapSpeciesData != null , "The collected SpeciesData objects have already been processed." );
420
+ heapSpeciesData .add (speciesData );
421
+ }
422
+
420
423
@ Override
421
424
public void duringAnalysis (DuringAnalysisAccess a ) {
422
425
DuringAnalysisAccessImpl access = (DuringAnalysisAccessImpl ) a ;
0 commit comments