@@ -30,14 +30,14 @@ interface UTypeEvaluator<Type> {
30
30
* Manages allocated objects separately from input ones. Indeed, we know the type of an allocated object
31
31
* precisely, thus we can evaluate the subtyping constraints for them concretely (modulo generic type variables).
32
32
*/
33
- class UTypeConstraints <Type >(
33
+ open class UTypeConstraints <Type >(
34
34
private val typeSystem : UTypeSystem <Type >,
35
35
private val equalityConstraints : UEqualityConstraints ,
36
- private val concreteRefToType : MutableMap <UConcreteHeapAddress , Type > = mutableMapOf(),
36
+ protected val concreteRefToType : MutableMap <UConcreteHeapAddress , Type > = mutableMapOf(),
37
37
symbolicRefToTypeRegion : MutableMap <USymbolicHeapRef , UTypeRegion <Type >> = mutableMapOf(),
38
38
) : UTypeEvaluator<Type> {
39
39
init {
40
- equalityConstraints.subscribe(::intersectConstraints )
40
+ equalityConstraints.subscribe(::intersectRegions )
41
41
}
42
42
43
43
val symbolicRefToTypeRegion get(): Map <USymbolicHeapRef , UTypeRegion <Type >> = _symbolicRefToTypeRegion
@@ -57,7 +57,7 @@ class UTypeConstraints<Type>(
57
57
)
58
58
}
59
59
60
- private fun contradiction () {
60
+ protected fun contradiction () {
61
61
isContradicting = true
62
62
}
63
63
@@ -68,11 +68,13 @@ class UTypeConstraints<Type>(
68
68
concreteRefToType[ref] = type
69
69
}
70
70
71
- private fun getRegion (symbolicRef : USymbolicHeapRef ) =
72
- _symbolicRefToTypeRegion [equalityConstraints.equalReferences.find(symbolicRef)] ? : topTypeRegion
71
+ fun getTypeRegion (symbolicRef : USymbolicHeapRef , useRepresentative : Boolean = false): UTypeRegion <Type > {
72
+ val representative = if (useRepresentative) equalityConstraints.equalReferences.find(symbolicRef) else symbolicRef
73
+ return _symbolicRefToTypeRegion [representative] ? : topTypeRegion
74
+ }
73
75
74
76
75
- private fun setRegion (symbolicRef : USymbolicHeapRef , value : UTypeRegion <Type >) {
77
+ private fun setTypeRegion (symbolicRef : USymbolicHeapRef , value : UTypeRegion <Type >) {
76
78
_symbolicRefToTypeRegion [equalityConstraints.equalReferences.find(symbolicRef)] = value
77
79
}
78
80
@@ -96,23 +98,7 @@ class UTypeConstraints<Type>(
96
98
}
97
99
98
100
is USymbolicHeapRef -> {
99
- val constraints = getRegion(ref)
100
- val newConstraints = constraints.addSupertype(type)
101
- if (newConstraints.isContradicting) {
102
- // the only left option here is to be equal to null
103
- equalityConstraints.makeEqual(ref, ref.uctx.nullRef)
104
- } else {
105
- // Inferring new symbolic disequalities here
106
- for ((key, value) in _symbolicRefToTypeRegion .entries) {
107
- // TODO: cache intersections?
108
- if (key != ref && value.intersect(newConstraints).isEmpty) {
109
- // If we have two inputs of incomparable reference types, then they are either non equal,
110
- // or both nulls
111
- equalityConstraints.makeNonEqualOrBothNull(ref, key)
112
- }
113
- }
114
- setRegion(ref, newConstraints)
115
- }
101
+ updateRegionCanBeEqualNull(ref) { it.addSupertype(type) }
116
102
}
117
103
118
104
else -> error(" Provided heap ref must be either concrete or purely symbolic one, found $ref " )
@@ -139,23 +125,7 @@ class UTypeConstraints<Type>(
139
125
}
140
126
141
127
is USymbolicHeapRef -> {
142
- val constraints = getRegion(ref)
143
- val newConstraints = constraints.excludeSupertype(type)
144
- equalityConstraints.makeNonEqual(ref, ref.uctx.nullRef)
145
- if (newConstraints.isContradicting || equalityConstraints.isContradicting) {
146
- // the [ref] can't be equal to null
147
- contradiction()
148
- } else {
149
- // Inferring new symbolic disequalities here
150
- for ((key, value) in _symbolicRefToTypeRegion .entries) {
151
- // TODO: cache intersections?
152
- if (key != ref && value.intersect(newConstraints).isEmpty) {
153
- // If we have two inputs of incomparable reference types, then they are non equal
154
- equalityConstraints.makeNonEqual(ref, key)
155
- }
156
- }
157
- setRegion(ref, newConstraints)
158
- }
128
+ updateRegionCannotBeEqualNull(ref) { it.excludeSupertype(type) }
159
129
}
160
130
161
131
else -> error(" Provided heap ref must be either concrete or purely symbolic one, found $ref " )
@@ -165,7 +135,7 @@ class UTypeConstraints<Type>(
165
135
/* *
166
136
* @return a type stream corresponding to the [ref].
167
137
*/
168
- internal fun readTypeStream (ref : UHeapRef ): UTypeStream <Type > =
138
+ internal fun getTypeStream (ref : UHeapRef ): UTypeStream <Type > =
169
139
when (ref) {
170
140
is UConcreteHeapRef -> {
171
141
val concreteType = concreteRefToType[ref.address]
@@ -180,15 +150,61 @@ class UTypeConstraints<Type>(
180
150
is UNullRef -> error(" Null ref should be handled explicitly earlier" )
181
151
182
152
is USymbolicHeapRef -> {
183
- getRegion (ref).typeStream
153
+ getTypeRegion (ref).typeStream
184
154
}
185
155
186
156
else -> error(" Unexpected ref: $ref " )
187
157
}
188
158
189
- private fun intersectConstraints (ref1 : USymbolicHeapRef , ref2 : USymbolicHeapRef ) {
190
- val newRegion = getRegion(ref1).intersect(getRegion(ref2))
191
- setRegion(ref1, newRegion)
159
+ private fun intersectRegions (ref1 : USymbolicHeapRef , ref2 : USymbolicHeapRef ) {
160
+ val region = getTypeRegion(ref2)
161
+ updateRegionCanBeEqualNull(ref1, region::intersect)
162
+ }
163
+
164
+ protected fun updateRegionCannotBeEqualNull (
165
+ ref : USymbolicHeapRef ,
166
+ regionMapper : (UTypeRegion <Type >) -> UTypeRegion <Type >,
167
+ ) {
168
+ val region = getTypeRegion(ref)
169
+ val newRegion = regionMapper(region)
170
+ if (newRegion == region) {
171
+ return
172
+ }
173
+ equalityConstraints.makeNonEqual(ref, ref.uctx.nullRef)
174
+ if (newRegion.isEmpty || equalityConstraints.isContradicting) {
175
+ contradiction()
176
+ return
177
+ }
178
+ for ((key, value) in _symbolicRefToTypeRegion .entries) {
179
+ // TODO: cache intersections?
180
+ if (key != ref && value.intersect(newRegion).isEmpty) {
181
+ // If we have two inputs of incomparable reference types, then they are non equal
182
+ equalityConstraints.makeNonEqual(ref, key)
183
+ }
184
+ }
185
+ setTypeRegion(ref, newRegion)
186
+ }
187
+
188
+ protected fun updateRegionCanBeEqualNull (
189
+ ref : USymbolicHeapRef ,
190
+ regionMapper : (UTypeRegion <Type >) -> UTypeRegion <Type >,
191
+ ) {
192
+ val region = getTypeRegion(ref)
193
+ val newRegion = regionMapper(region)
194
+ if (newRegion == region) {
195
+ return
196
+ }
197
+ if (newRegion.isEmpty) {
198
+ equalityConstraints.makeEqual(ref, ref.uctx.nullRef)
199
+ }
200
+ for ((key, value) in _symbolicRefToTypeRegion .entries) {
201
+ // TODO: cache intersections?
202
+ if (key != ref && value.intersect(newRegion).isEmpty) {
203
+ // If we have two inputs of incomparable reference types, then they are non equal
204
+ equalityConstraints.makeNonEqualOrBothNull(ref, key)
205
+ }
206
+ }
207
+ setTypeRegion(ref, newRegion)
192
208
}
193
209
194
210
/* *
@@ -209,9 +225,9 @@ class UTypeConstraints<Type>(
209
225
// accordingly to the [UIsExpr] specification, [nullRef] always satisfies the [type]
210
226
return @mapper symbolicRef.ctx.trueExpr
211
227
}
212
- val typeRegion = getRegion (symbolicRef)
228
+ val typeRegion = getTypeRegion (symbolicRef)
213
229
214
- if (typeRegion.addSupertype(type).isContradicting ) {
230
+ if (typeRegion.addSupertype(type).isEmpty ) {
215
231
symbolicRef.ctx.falseExpr
216
232
} else {
217
233
symbolicRef.uctx.mkIsExpr(symbolicRef, type)
0 commit comments