4646import com .oracle .graal .pointsto .api .PointstoOptions ;
4747import com .oracle .graal .pointsto .constraints .UnsupportedFeatures ;
4848import com .oracle .graal .pointsto .flow .AllSynchronizedTypeFlow ;
49+ import com .oracle .graal .pointsto .flow .AnyPrimitiveSourceTypeFlow ;
4950import com .oracle .graal .pointsto .flow .FieldTypeFlow ;
5051import com .oracle .graal .pointsto .flow .FormalParamTypeFlow ;
5152import com .oracle .graal .pointsto .flow .InvokeTypeFlow ;
6162import com .oracle .graal .pointsto .meta .AnalysisMethod ;
6263import com .oracle .graal .pointsto .meta .AnalysisType ;
6364import com .oracle .graal .pointsto .meta .AnalysisUniverse ;
65+ import com .oracle .graal .pointsto .meta .PointsToAnalysisField ;
6466import com .oracle .graal .pointsto .meta .PointsToAnalysisMethod ;
6567import com .oracle .graal .pointsto .reports .StatisticsPrinter ;
68+ import com .oracle .graal .pointsto .typestate .AnyPrimitiveTypeState ;
6669import com .oracle .graal .pointsto .typestate .PointsToStats ;
6770import com .oracle .graal .pointsto .typestate .TypeState ;
6871import com .oracle .graal .pointsto .util .AnalysisError ;
8992public abstract class PointsToAnalysis extends AbstractAnalysisEngine {
9093 /** The type of {@link java.lang.Object}. */
9194 private final AnalysisType objectType ;
95+ /**
96+ * Enables propagating primitive values interproceduraly using the typeflow graph. Only simple
97+ * constants are propagated. Arithmetic operations and merges of different constants result in a
98+ * special {@link AnyPrimitiveTypeState } state that leads to immediate saturation.
99+ * <p>
100+ * This optimization also handles word types, which are essentially primitive values.
101+ * <p>
102+ * Unsafe loads and stores are NOT modeled, because it would lead to merging of primitive and
103+ * objects states (all unsafe fields are merged into a single flow). Instead, all unsafe
104+ * accessed primitive fields are assigned the PrimitiveTypeState state and any unsafe read is
105+ * immediately represented as {@link com.oracle.graal.pointsto.flow.AnyPrimitiveSourceTypeFlow}.
106+ */
107+ private final boolean trackPrimitiveValues ;
108+ private AnyPrimitiveSourceTypeFlow anyPrimitiveSourceTypeFlow ;
92109 private TypeFlow <?> allSynchronizedTypeFlow ;
93110
94111 protected final boolean trackTypeFlowInputs ;
@@ -107,6 +124,8 @@ public PointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM
107124 ConstantReflectionProvider constantReflectionProvider , WordTypes wordTypes , UnsupportedFeatures unsupportedFeatures , DebugContext debugContext , TimerCollection timerCollection ) {
108125 super (options , universe , hostVM , metaAccess , snippetReflectionProvider , constantReflectionProvider , wordTypes , unsupportedFeatures , debugContext , timerCollection );
109126 this .typeFlowTimer = timerCollection .createTimer ("(typeflow)" );
127+ this .trackPrimitiveValues = PointstoOptions .TrackPrimitiveValues .getValue (options );
128+ this .anyPrimitiveSourceTypeFlow = new AnyPrimitiveSourceTypeFlow (null , null );
110129
111130 this .objectType = metaAccess .lookupJavaType (Object .class );
112131 /*
@@ -199,15 +218,26 @@ public void forceUnsafeUpdate(AnalysisField field) {
199218 }
200219
201220 @ Override
202- public void registerAsJNIAccessed (AnalysisField field , boolean writable ) {
221+ public void registerAsJNIAccessed (AnalysisField f , boolean writable ) {
222+ PointsToAnalysisField field = (PointsToAnalysisField ) f ;
203223 // Same as addRootField() and addRootStaticField():
204224 // create type flows for any subtype of the field's declared type
205225 TypeFlow <?> declaredTypeFlow = field .getType ().getTypeFlow (this , true );
206- if (field .isStatic ()) {
207- declaredTypeFlow .addUse (this , field .getStaticFieldFlow ());
208- } else {
209- FieldTypeFlow instanceFieldFlow = field .getDeclaringClass ().getContextInsensitiveAnalysisObject ().getInstanceFieldFlow (this , field , writable );
210- declaredTypeFlow .addUse (this , instanceFieldFlow );
226+ if (isSupportedJavaKind (field .getStorageKind ())) {
227+ if (field .isStatic ()) {
228+ if (field .getStorageKind ().isObject ()) {
229+ declaredTypeFlow .addUse (this , field .getStaticFieldFlow ());
230+ } else {
231+ field .saturatePrimitiveField ();
232+ }
233+ } else {
234+ FieldTypeFlow instanceFieldFlow = field .getDeclaringClass ().getContextInsensitiveAnalysisObject ().getInstanceFieldFlow (this , field , writable );
235+ if (field .getStorageKind ().isObject ()) {
236+ declaredTypeFlow .addUse (this , instanceFieldFlow );
237+ } else {
238+ field .saturatePrimitiveField ();
239+ }
240+ }
211241 }
212242 }
213243
@@ -224,6 +254,7 @@ public boolean trackConcreteAnalysisObjects(@SuppressWarnings("unused") Analysis
224254 public void cleanupAfterAnalysis () {
225255 super .cleanupAfterAnalysis ();
226256 allSynchronizedTypeFlow = null ;
257+ anyPrimitiveSourceTypeFlow = null ;
227258 unsafeLoads = null ;
228259 unsafeStores = null ;
229260
@@ -263,6 +294,10 @@ public TypeFlow<?> getAllSynchronizedTypeFlow() {
263294 return allSynchronizedTypeFlow ;
264295 }
265296
297+ public AnyPrimitiveSourceTypeFlow getAnyPrimitiveSourceTypeFlow () {
298+ return anyPrimitiveSourceTypeFlow ;
299+ }
300+
266301 @ Override
267302 public Iterable <AnalysisType > getAllSynchronizedTypes () {
268303 /*
@@ -306,10 +341,7 @@ public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecia
306341 for (int idx = 0 ; idx < paramCount ; idx ++) {
307342 AnalysisType declaredParamType = (AnalysisType ) signature .getParameterType (idx , declaringClass );
308343 FormalParamTypeFlow parameter = flowInfo .getParameter (idx );
309- if (declaredParamType .getJavaKind () == JavaKind .Object && parameter != null ) {
310- TypeFlow <?> initialParameterFlow = declaredParamType .getTypeFlow (this , true );
311- initialParameterFlow .addUse (this , parameter );
312- }
344+ processParam (declaredParamType , parameter );
313345 }
314346 });
315347 };
@@ -369,17 +401,25 @@ public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecia
369401 */
370402 AnalysisType declaredParamType = (AnalysisType ) signature .getParameterType (idx - 1 , declaringClass );
371403 TypeFlow <?> actualParameterFlow = invoke .getActualParameter (idx );
372- if (declaredParamType .getJavaKind () == JavaKind .Object && actualParameterFlow != null ) {
373- TypeFlow <?> initialParameterFlow = declaredParamType .getTypeFlow (this , true );
374- initialParameterFlow .addUse (this , actualParameterFlow );
375- }
404+ processParam (declaredParamType , actualParameterFlow );
376405 }
377406 });
378407 }
379408 return aMethod ;
380409
381410 }
382411
412+ private void processParam (AnalysisType declaredParamType , TypeFlow <?> actualParameterFlow ) {
413+ if (actualParameterFlow != null && isSupportedJavaKind (declaredParamType .getStorageKind ())) {
414+ if (declaredParamType .getStorageKind () == JavaKind .Object ) {
415+ TypeFlow <?> initialParameterFlow = declaredParamType .getTypeFlow (this , true );
416+ initialParameterFlow .addUse (this , actualParameterFlow );
417+ } else {
418+ actualParameterFlow .addState (this , TypeState .anyPrimitiveState ());
419+ }
420+ }
421+ }
422+
383423 public static PointsToAnalysisMethod assertPointsToAnalysisMethod (AnalysisMethod aMethod ) {
384424 assert aMethod instanceof PointsToAnalysisMethod : "Only points-to analysis methods are supported" ;
385425 return ((PointsToAnalysisMethod ) aMethod );
@@ -400,12 +440,7 @@ public AnalysisType addRootClass(AnalysisType type, boolean addFields, boolean a
400440 if (addFields ) {
401441 field .registerAsAccessed ("field of root class" );
402442 }
403- /*
404- * For system classes any instantiated (sub)type of the declared field type can be
405- * written to the field flow.
406- */
407- TypeFlow <?> fieldDeclaredTypeFlow = field .getType ().getTypeFlow (this , true );
408- fieldDeclaredTypeFlow .addUse (this , type .getContextInsensitiveAnalysisObject ().getInstanceFieldFlow (this , field , true ));
443+ processRootField (type , field );
409444 }
410445 if (type .getSuperclass () != null ) {
411446 addRootClass (type .getSuperclass (), addFields , addArrayClass );
@@ -424,16 +459,28 @@ public AnalysisType addRootField(Class<?> clazz, String fieldName) {
424459 AnalysisField field = (AnalysisField ) javaField ;
425460 if (field .getName ().equals (fieldName )) {
426461 field .registerAsAccessed ("root field" );
462+ processRootField (type , field );
463+ return field .getType ();
464+ }
465+ }
466+ throw shouldNotReachHere ("field not found: " + fieldName );
467+ }
468+
469+ private void processRootField (AnalysisType type , AnalysisField field ) {
470+ JavaKind storageKind = field .getStorageKind ();
471+ if (isSupportedJavaKind (storageKind )) {
472+ var fieldFlow = type .getContextInsensitiveAnalysisObject ().getInstanceFieldFlow (this , field , true );
473+ if (storageKind .isObject ()) {
427474 /*
428475 * For system classes any instantiated (sub)type of the declared field type can be
429476 * written to the field flow.
430477 */
431478 TypeFlow <?> fieldDeclaredTypeFlow = field .getType ().getTypeFlow (this , true );
432- fieldDeclaredTypeFlow .addUse (this , type .getContextInsensitiveAnalysisObject ().getInstanceFieldFlow (this , field , true ));
433- return field .getType ();
479+ fieldDeclaredTypeFlow .addUse (this , fieldFlow );
480+ } else {
481+ fieldFlow .addState (this , TypeState .anyPrimitiveState ());
434482 }
435483 }
436- throw shouldNotReachHere ("field not found: " + fieldName );
437484 }
438485
439486 @ SuppressWarnings ({"try" , "unused" })
@@ -444,8 +491,15 @@ public AnalysisType addRootStaticField(Class<?> clazz, String fieldName) {
444491 reflectField = clazz .getField (fieldName );
445492 AnalysisField field = metaAccess .lookupJavaField (reflectField );
446493 field .registerAsAccessed ("static root field" );
447- TypeFlow <?> fieldFlow = field .getType ().getTypeFlow (this , true );
448- fieldFlow .addUse (this , field .getStaticFieldFlow ());
494+ JavaKind storageKind = field .getStorageKind ();
495+ if (isSupportedJavaKind (storageKind )) {
496+ if (storageKind .isObject ()) {
497+ TypeFlow <?> fieldFlow = field .getType ().getTypeFlow (this , true );
498+ fieldFlow .addUse (this , field .getStaticFieldFlow ());
499+ } else {
500+ field .getStaticFieldFlow ().addState (this , TypeState .anyPrimitiveState ());
501+ }
502+ }
449503 return field .getType ();
450504
451505 } catch (NoSuchFieldException e ) {
@@ -457,6 +511,15 @@ public AnalysisType addRootStaticField(Class<?> clazz, String fieldName) {
457511 public void checkUserLimitations () {
458512 }
459513
514+ public boolean isSupportedJavaKind (JavaKind javaKind ) {
515+ return javaKind == JavaKind .Object || (trackPrimitiveValues && javaKind .isNumericInteger ());
516+ }
517+
518+ @ Override
519+ public boolean trackPrimitiveValues () {
520+ return trackPrimitiveValues ;
521+ }
522+
460523 public interface TypeFlowRunnable extends DebugContextRunnable {
461524 TypeFlow <?> getTypeFlow ();
462525 }
0 commit comments