Skip to content

Commit 82ae059

Browse files
committed
[GR-69257] Simplify root fields registration.
PullRequest: graal/22640
2 parents 2c7c747 + 9dffad8 commit 82ae059

File tree

7 files changed

+77
-198
lines changed

7 files changed

+77
-198
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java

Lines changed: 60 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,9 @@
2525
package com.oracle.graal.pointsto;
2626

2727
import static com.oracle.graal.pointsto.meta.AnalysisUniverse.ESTIMATED_NUMBER_OF_TYPES;
28-
import static jdk.vm.ci.common.JVMCIError.shouldNotReachHere;
2928

3029
import java.io.PrintWriter;
3130
import java.lang.reflect.Executable;
32-
import java.lang.reflect.Field;
3331
import java.util.ArrayList;
3432
import java.util.Collections;
3533
import java.util.Comparator;
@@ -47,7 +45,6 @@
4745
import com.oracle.graal.pointsto.constraints.UnsupportedFeatures;
4846
import com.oracle.graal.pointsto.flow.AlwaysEnabledPredicateFlow;
4947
import com.oracle.graal.pointsto.flow.AnyPrimitiveSourceTypeFlow;
50-
import com.oracle.graal.pointsto.flow.FieldTypeFlow;
5148
import com.oracle.graal.pointsto.flow.FormalParamTypeFlow;
5249
import com.oracle.graal.pointsto.flow.InvokeTypeFlow;
5350
import com.oracle.graal.pointsto.flow.MethodFlowsGraph;
@@ -77,6 +74,7 @@
7774
import com.oracle.svm.common.meta.MultiMethod;
7875
import com.oracle.svm.util.AnnotationUtil;
7976
import com.oracle.svm.util.ClassUtil;
77+
import com.oracle.svm.util.JVMCIReflectionUtil;
8078

8179
import jdk.graal.compiler.api.replacements.Fold;
8280
import jdk.graal.compiler.api.replacements.SnippetReflectionProvider;
@@ -266,26 +264,9 @@ public void forceUnsafeUpdate() {
266264
}
267265

268266
@Override
269-
public void registerAsJNIAccessed(AnalysisField f, boolean writable) {
270-
PointsToAnalysisField field = (PointsToAnalysisField) f;
271-
// Same as addRootField() and addRootStaticField():
272-
// create type flows for any subtype of the field's declared type
273-
TypeFlow<?> declaredTypeFlow = field.getType().getTypeFlow(this, true);
267+
public void registerAsJNIAccessed(AnalysisField field, boolean writable) {
274268
if (isSupportedJavaKind(field.getStorageKind())) {
275-
if (field.isStatic()) {
276-
if (field.getStorageKind().isObject()) {
277-
declaredTypeFlow.addUse(this, field.getStaticFieldFlow());
278-
} else {
279-
field.saturatePrimitiveField();
280-
}
281-
} else {
282-
FieldTypeFlow instanceFieldFlow = field.getDeclaringClass().getContextInsensitiveAnalysisObject().getInstanceFieldFlow(this, field, writable);
283-
if (field.getStorageKind().isObject()) {
284-
declaredTypeFlow.addUse(this, instanceFieldFlow);
285-
} else {
286-
field.saturatePrimitiveField();
287-
}
288-
}
269+
field.injectDeclaredType();
289270
}
290271
}
291272

@@ -519,7 +500,7 @@ public AnalysisType addRootClass(AnalysisType type, boolean addFields, boolean a
519500
if (addFields) {
520501
field.registerAsAccessed("field of root class");
521502
}
522-
processRootField(type, field);
503+
processRootField(field);
523504
}
524505
if (type.getSuperclass() != null) {
525506
addRootClass(type.getSuperclass(), addFields, addArrayClass);
@@ -531,77 +512,23 @@ public AnalysisType addRootClass(AnalysisType type, boolean addFields, boolean a
531512
}
532513

533514
@Override
534-
@SuppressWarnings("try")
535515
public AnalysisType addRootField(Class<?> clazz, String fieldName) {
536-
AnalysisType type = addRootClass(clazz, false, false);
537-
for (ResolvedJavaField javaField : type.getInstanceFields(true)) {
538-
var field = (PointsToAnalysisField) javaField;
539-
if (field.getName().equals(fieldName)) {
540-
return addRootField(type, field);
541-
}
542-
}
543-
throw shouldNotReachHere("field not found: " + fieldName);
516+
AnalysisType type = metaAccess.lookupJavaType(clazz);
517+
addRootClass(type, false, false);
518+
return addRootField((AnalysisField) JVMCIReflectionUtil.getDeclaredField(type, fieldName));
544519
}
545520

546521
@Override
547-
public AnalysisType addRootField(AnalysisField f) {
548-
var field = (PointsToAnalysisField) f;
549-
if (field.isStatic()) {
550-
return addRootStaticField(field);
551-
} else {
552-
return addRootField(field.getDeclaringClass(), field);
553-
}
554-
}
555-
556-
private AnalysisType addRootField(AnalysisType type, PointsToAnalysisField field) {
557-
field.registerAsAccessed("root field");
558-
processRootField(type, field);
522+
public AnalysisType addRootField(AnalysisField field) {
523+
field.registerAsAccessed((field.isStatic() ? "static" : "instance") + " root field");
524+
processRootField(field);
559525
return field.getType();
560526
}
561527

562-
private void processRootField(AnalysisType type, PointsToAnalysisField field) {
563-
JavaKind storageKind = field.getStorageKind();
564-
if (isSupportedJavaKind(storageKind)) {
565-
var fieldFlow = type.getContextInsensitiveAnalysisObject().getInstanceFieldFlow(this, field, true);
566-
if (storageKind.isObject()) {
567-
/*
568-
* For system classes any instantiated (sub)type of the declared field type can be
569-
* written to the field flow.
570-
*/
571-
TypeFlow<?> fieldDeclaredTypeFlow = field.getType().getTypeFlow(this, true);
572-
fieldDeclaredTypeFlow.addUse(this, fieldFlow);
573-
} else {
574-
fieldFlow.addState(this, TypeState.anyPrimitiveState());
575-
}
576-
}
577-
}
578-
579-
@SuppressWarnings({"try", "unused"})
580-
public AnalysisType addRootStaticField(Class<?> clazz, String fieldName) {
581-
addRootClass(clazz, false, false);
582-
Field reflectField;
583-
try {
584-
reflectField = clazz.getField(fieldName);
585-
var field = (PointsToAnalysisField) metaAccess.lookupJavaField(reflectField);
586-
return addRootStaticField(field);
587-
588-
} catch (NoSuchFieldException e) {
589-
throw shouldNotReachHere("field not found: " + fieldName);
590-
}
591-
}
592-
593-
private AnalysisType addRootStaticField(PointsToAnalysisField field) {
594-
field.registerAsAccessed("static root field");
595-
JavaKind storageKind = field.getStorageKind();
596-
if (isSupportedJavaKind(storageKind)) {
597-
if (storageKind.isObject()) {
598-
TypeFlow<?> fieldFlow = field.getType().getTypeFlow(this, true);
599-
fieldFlow.addUse(this, field.getStaticFieldFlow());
600-
} else {
601-
field.getStaticFieldFlow().addState(this, TypeState.anyPrimitiveState());
602-
}
528+
private void processRootField(AnalysisField field) {
529+
if (isSupportedJavaKind(field.getStorageKind())) {
530+
field.injectDeclaredType();
603531
}
604-
return field.getType();
605532
}
606533

607534
@Override
@@ -728,6 +655,53 @@ public void onTypeInstantiated(AnalysisType type) {
728655
});
729656
}
730657

658+
/**
659+
* Inject custom types in the analysis field type state. This utility is used for:
660+
* <ul>
661+
* <li>root fields - whose state is forced to be that of the declared type</li>
662+
* <li>unsafe accessed fields - whose state is conservatively also the declared type</li>
663+
* <li>lazily computed fields - for which writes are not visible during analysis</li>
664+
* <ul/>
665+
*/
666+
@Override
667+
public void injectFieldTypes(AnalysisField aField, List<AnalysisType> customTypes, boolean canBeNull) {
668+
assert aField.getStorageKind().isObject();
669+
var ptaField = (PointsToAnalysisField) aField;
670+
671+
/* Link the field with all declared types. */
672+
for (AnalysisType type : customTypes) {
673+
if (type.isPrimitive() || type.isWordType()) {
674+
continue;
675+
}
676+
type.getTypeFlow(this, canBeNull).addUse(this, ptaField.getInitialFlow());
677+
678+
if (type.isArray()) {
679+
AnalysisType fieldComponentType = type.getComponentType();
680+
ptaField.getInitialFlow().addUse(this, ptaField.getSinkFlow());
681+
if (!(fieldComponentType.isPrimitive() || fieldComponentType.isWordType())) {
682+
/*
683+
* Write the component type abstract object into the field array elements type
684+
* flow, i.e., the array elements type flow of the abstract object of the field
685+
* declared type.
686+
*
687+
* This is required so that the index loads from this array return all the
688+
* possible objects that can be stored in the array.
689+
*/
690+
TypeFlow<?> elementsFlow = type.getContextInsensitiveAnalysisObject().getArrayElementsFlow(this, true);
691+
fieldComponentType.getTypeFlow(this, false).addUse(this, elementsFlow);
692+
693+
/*
694+
* In the current implementation it is not necessary to do it recursively for
695+
* multidimensional arrays since we don't model individual array elements, so
696+
* from the point of view of the static analysis the field's array elements
697+
* value is non-null (in the case of an n-dimensional array that value is
698+
* another array, n-1 dimensional).
699+
*/
700+
}
701+
}
702+
}
703+
}
704+
731705
public static class ConstantObjectsProfiler {
732706

733707
static final ConcurrentHashMap<AnalysisType, MyInteger> constantTypes = new ConcurrentHashMap<>(ESTIMATED_NUMBER_OF_TYPES);

substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Collections;
3030
import java.util.Deque;
3131
import java.util.HashSet;
32+
import java.util.List;
3233
import java.util.Set;
3334

3435
import com.oracle.graal.pointsto.AbstractAnalysisEngine;
@@ -154,6 +155,15 @@ public AnalysisType addRootField(AnalysisField analysisField) {
154155
return analysisField.getType();
155156
}
156157

158+
@Override
159+
public void injectFieldTypes(AnalysisField aField, List<AnalysisType> customTypes, boolean canBeNull) {
160+
assert aField.getStorageKind().isObject();
161+
aField.registerAsAccessed("@UnknownObjectField annotated field.");
162+
for (AnalysisType declaredType : customTypes) {
163+
declaredType.registerAsReachable("injected field types for unknown annotated field " + aField.format("%H.%n"));
164+
}
165+
}
166+
157167
@Override
158168
public AnalysisMethod addRootMethod(AnalysisMethod m, boolean invokeSpecial, Object reason, MultiMethod.MultiMethodKey... otherRoots) {
159169
assert otherRoots.length == 0 : otherRoots;

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/CustomTypeFieldHandler.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@
3838
import com.oracle.graal.pointsto.meta.PointsToAnalysisField;
3939
import com.oracle.svm.hosted.analysis.FieldValueComputer;
4040

41-
public abstract class CustomTypeFieldHandler {
42-
protected final BigBang bb;
41+
public final class CustomTypeFieldHandler {
42+
private final BigBang bb;
4343
private final AnalysisMetaAccess metaAccess;
4444
private final FieldValueInterceptionSupport fieldValueInterceptionSupport = FieldValueInterceptionSupport.singleton();
4545
private Set<AnalysisField> processedFields = ConcurrentHashMap.newKeySet();
@@ -60,7 +60,7 @@ public void handleField(AnalysisField field) {
6060
assert field.isAccessed();
6161
if (fieldValueInterceptionSupport.hasFieldValueTransformer(field)) {
6262
if (field.getStorageKind().isObject() && !fieldValueInterceptionSupport.isValueAvailable(field, null, !field.isStatic())) {
63-
injectFieldTypes(field, List.of(field.getType()), true);
63+
bb.injectFieldTypes(field, List.of(field.getType()), true);
6464
} else if (bb.trackPrimitiveValues() && field.getStorageKind().isPrimitive() && field instanceof PointsToAnalysisField ptaField) {
6565
ptaField.saturatePrimitiveField();
6666
}
@@ -71,15 +71,13 @@ public void handleField(AnalysisField field) {
7171
assert !type.isPrimitive() : type + " for " + field;
7272
type.registerAsInstantiated("Is declared as the type of an unknown object field.");
7373
}
74-
injectFieldTypes(field, types, fieldValueComputer.canBeNull());
74+
bb.injectFieldTypes(field, types, fieldValueComputer.canBeNull());
7575
} else if (bb.trackPrimitiveValues() && field.getStorageKind().isPrimitive() && field instanceof PointsToAnalysisField ptaField) {
7676
ptaField.saturatePrimitiveField();
7777
}
7878
}
7979
}
8080

81-
public abstract void injectFieldTypes(AnalysisField aField, List<AnalysisType> customTypes, boolean canBeNull);
82-
8381
private List<AnalysisType> transformTypes(AnalysisField field, List<Class<?>> types) {
8482
List<AnalysisType> customTypes = new ArrayList<>();
8583
AnalysisType declaredType = field.getType();

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.lang.reflect.Executable;
2828
import java.lang.reflect.Method;
2929
import java.lang.reflect.Modifier;
30-
import java.util.List;
3130
import java.util.concurrent.ConcurrentHashMap;
3231

3332
import com.oracle.graal.pointsto.ClassInclusionPolicy;
@@ -87,7 +86,7 @@ public NativeImagePointsToAnalysis(OptionValues options, AnalysisUniverse univer
8786
this.annotationSubstitutionProcessor = annotationSubstitutionProcessor;
8887

8988
dynamicHubInitializer = new DynamicHubInitializer(this);
90-
customTypeFieldHandler = new PointsToCustomTypeFieldHandler(this, metaAccess);
89+
customTypeFieldHandler = new CustomTypeFieldHandler(this, metaAccess);
9190
callChecker = new CallChecker();
9291
}
9392

@@ -128,11 +127,6 @@ public void onFieldAccessed(AnalysisField field) {
128127
postTask(() -> customTypeFieldHandler.handleField(field));
129128
}
130129

131-
@Override
132-
public void injectFieldTypes(AnalysisField aField, List<AnalysisType> customTypes, boolean canBeNull) {
133-
customTypeFieldHandler.injectFieldTypes(aField, customTypes, canBeNull);
134-
}
135-
136130
@Override
137131
public void onTypeReachable(AnalysisType type) {
138132
postTask(_ -> {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
*/
2525
package com.oracle.svm.hosted.analysis;
2626

27-
import java.util.List;
28-
2927
import com.oracle.graal.pointsto.ClassInclusionPolicy;
3028
import com.oracle.graal.pointsto.meta.AnalysisField;
3129
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
@@ -58,16 +56,7 @@ public NativeImageReachabilityAnalysisEngine(OptionValues options, AnalysisUnive
5856
reachabilityMethodProcessingHandler, classInclusionPolicy);
5957
this.annotationSubstitutionProcessor = annotationSubstitutionProcessor;
6058
this.dynamicHubInitializer = new DynamicHubInitializer(this);
61-
this.unknownFieldHandler = new CustomTypeFieldHandler(this, metaAccess) {
62-
@Override
63-
public void injectFieldTypes(AnalysisField aField, List<AnalysisType> declaredTypes, boolean canBeNull) {
64-
assert aField.getStorageKind().isObject();
65-
aField.registerAsAccessed("@UnknownObjectField annotated field.");
66-
for (AnalysisType declaredType : declaredTypes) {
67-
declaredType.registerAsReachable("injected field types for unknown annotated field " + aField.format("%H.%n"));
68-
}
69-
}
70-
};
59+
this.unknownFieldHandler = new CustomTypeFieldHandler(this, metaAccess);
7160
}
7261

7362
@Override

0 commit comments

Comments
 (0)