Skip to content

Commit 2517572

Browse files
author
Christian Wimmer
committed
Filter ClassSpecializer$SpeciesData.transformHelpers cache
1 parent 418ee81 commit 2517572

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,18 @@ protected AnalysisFuture<JavaConstant> patchArrayElement(ImageHeapObjectArray ar
683683
return task;
684684
}
685685

686+
/**
687+
* Returns true if the provided {@code object} was seen as reachable by the static analysis.
688+
*/
689+
public boolean isObjectReachable(Object object) {
690+
var javaConstant = asConstant(Objects.requireNonNull(object));
691+
Object existingTask = imageHeap.getSnapshot(javaConstant);
692+
if (existingTask instanceof ImageHeapConstant imageHeapConstant) {
693+
return imageHeapConstant.isReachable();
694+
}
695+
return false;
696+
}
697+
686698
/**
687699
* Add the object to the image heap and, if the object is a collection, rescan its elements.
688700
*/

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

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
import org.graalvm.nativeimage.hosted.RuntimeReflection;
4242

43+
import com.oracle.graal.pointsto.heap.ImageHeapScanner;
4344
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
4445
import com.oracle.graal.pointsto.meta.AnalysisType;
4546
import com.oracle.svm.core.SubstrateOptions;
@@ -48,7 +49,7 @@
4849
import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability;
4950
import com.oracle.svm.core.invoke.MethodHandleIntrinsic;
5051
import com.oracle.svm.core.util.VMError;
51-
import com.oracle.svm.hosted.FeatureImpl;
52+
import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl;
5253
import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl;
5354
import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl;
5455
import com.oracle.svm.util.ReflectionUtil;
@@ -157,7 +158,9 @@ public void duringSetup(DuringSetupAccess access) {
157158
}
158159

159160
@Override
160-
public void beforeAnalysis(BeforeAnalysisAccess access) {
161+
public void beforeAnalysis(BeforeAnalysisAccess a) {
162+
var access = (BeforeAnalysisAccessImpl) a;
163+
161164
/* java.lang.invoke functions called through reflection */
162165
Class<?> mhImplClazz = access.findClassByName("java.lang.invoke.MethodHandleImpl");
163166

@@ -200,7 +203,9 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
200203
access.registerSubtypeReachabilityHandler(MethodHandleFeature::scanBoundMethodHandle,
201204
access.findClassByName("java.lang.invoke.BoundMethodHandle"));
202205

203-
AnalysisMetaAccess metaAccess = ((FeatureImpl.BeforeAnalysisAccessImpl) access).getMetaAccess();
206+
AnalysisMetaAccess metaAccess = access.getMetaAccess();
207+
ImageHeapScanner heapScanner = access.getUniverse().getHeapScanner();
208+
204209
access.registerFieldValueTransformer(
205210
ReflectionUtil.lookupField(ReflectionUtil.lookupClass(false, "java.lang.invoke.ClassSpecializer"), "cache"),
206211
new FieldValueTransformerWithAvailability() {
@@ -241,6 +246,37 @@ private boolean isSpeciesReachable(Object speciesData) {
241246
access.registerFieldValueTransformer(
242247
ReflectionUtil.lookupField(ReflectionUtil.lookupClass(false, "java.lang.invoke.MethodType"), "internTable"),
243248
(receiver, originalValue) -> runtimeMethodTypeInternTable);
249+
250+
/*
251+
* SpeciesData.transformHelpers is a lazily initialized cache of MethodHandle objects. We do
252+
* not want to make a MethodHandle reachable just because the image builder initialized the
253+
* cache, so we filter out unreachable objects. This also solves the problem when late image
254+
* heap re-scanning after static analysis would see a method handle that was not yet cached
255+
* during static analysis, in which case image building would fail because new types would
256+
* be made reachable after analysis.
257+
*/
258+
access.registerFieldValueTransformer(
259+
ReflectionUtil.lookupField(ReflectionUtil.lookupClass(false, "java.lang.invoke.ClassSpecializer$SpeciesData"), "transformHelpers"),
260+
new FieldValueTransformerWithAvailability() {
261+
@Override
262+
public FieldValueTransformerWithAvailability.ValueAvailability valueAvailability() {
263+
return FieldValueTransformerWithAvailability.ValueAvailability.AfterAnalysis;
264+
}
265+
266+
@Override
267+
@SuppressWarnings("unchecked")
268+
public Object transform(Object receiver, Object originalValue) {
269+
MethodHandle[] originalArray = (MethodHandle[]) originalValue;
270+
MethodHandle[] filteredArray = new MethodHandle[originalArray.length];
271+
for (int i = 0; i < originalArray.length; i++) {
272+
MethodHandle handle = originalArray[i];
273+
if (handle != null && heapScanner.isObjectReachable(handle)) {
274+
filteredArray[i] = handle;
275+
}
276+
}
277+
return filteredArray;
278+
}
279+
});
244280
}
245281

246282
private static void registerMHImplFunctionsForReflection(DuringAnalysisAccess access) {

0 commit comments

Comments
 (0)