2525package com .oracle .graal .pointsto ;
2626
2727import static com .oracle .graal .pointsto .meta .AnalysisUniverse .ESTIMATED_NUMBER_OF_TYPES ;
28- import static jdk .vm .ci .common .JVMCIError .shouldNotReachHere ;
2928
3029import java .io .PrintWriter ;
3130import java .lang .reflect .Executable ;
32- import java .lang .reflect .Field ;
3331import java .util .ArrayList ;
3432import java .util .Collections ;
3533import java .util .Comparator ;
4745import com .oracle .graal .pointsto .constraints .UnsupportedFeatures ;
4846import com .oracle .graal .pointsto .flow .AlwaysEnabledPredicateFlow ;
4947import com .oracle .graal .pointsto .flow .AnyPrimitiveSourceTypeFlow ;
50- import com .oracle .graal .pointsto .flow .FieldTypeFlow ;
5148import com .oracle .graal .pointsto .flow .FormalParamTypeFlow ;
5249import com .oracle .graal .pointsto .flow .InvokeTypeFlow ;
5350import com .oracle .graal .pointsto .flow .MethodFlowsGraph ;
7774import com .oracle .svm .common .meta .MultiMethod ;
7875import com .oracle .svm .util .AnnotationUtil ;
7976import com .oracle .svm .util .ClassUtil ;
77+ import com .oracle .svm .util .JVMCIReflectionUtil ;
8078
8179import jdk .graal .compiler .api .replacements .Fold ;
8280import 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 );
0 commit comments