@@ -114,38 +114,54 @@ open class UContext(
114114 }
115115
116116 fun mkHeapRefEq (lhs : UHeapRef , rhs : UHeapRef ): UBoolExpr =
117- when {
118- // fast checks
119- lhs is USymbolicHeapRef && rhs is USymbolicHeapRef -> super .mkEq(lhs, rhs, order = true )
120- lhs is UConcreteHeapRef && rhs is UConcreteHeapRef -> mkBool(lhs == rhs)
117+ mkHeapEqWithFastChecks(lhs, rhs) {
121118 // unfolding
122- else -> {
123- val (concreteRefsLhs, symbolicRefLhs) = splitUHeapRef(lhs, ignoreNullRefs = false )
124- val (concreteRefsRhs, symbolicRefRhs) = splitUHeapRef(rhs, ignoreNullRefs = false )
125-
126- val concreteRefLhsToGuard = concreteRefsLhs.associate { it.expr.address to it.guard }
127-
128- val conjuncts = mutableListOf<UBoolExpr >(falseExpr)
129-
130- concreteRefsRhs.forEach { (concreteRefRhs, guardRhs) ->
131- val guardLhs = concreteRefLhsToGuard.getOrDefault(concreteRefRhs.address, falseExpr)
132- // mkAnd instead of mkAnd with flat=false here is OK
133- val conjunct = mkAnd(guardLhs, guardRhs)
134- conjuncts + = conjunct
135- }
136-
137- if (symbolicRefLhs != null && symbolicRefRhs != null ) {
138- val refsEq = super .mkEq(symbolicRefLhs.expr, symbolicRefRhs.expr, order = true )
139- // mkAnd instead of mkAnd with flat=false here is OK
140- val conjunct = mkAnd(symbolicRefLhs.guard, symbolicRefRhs.guard, refsEq)
141- conjuncts + = conjunct
142- }
143-
144- // it's safe to use mkOr here
145- mkOr(conjuncts)
119+ val (concreteRefsLhs, symbolicRefLhs) = splitUHeapRef(lhs, ignoreNullRefs = false )
120+ val (concreteRefsRhs, symbolicRefRhs) = splitUHeapRef(rhs, ignoreNullRefs = false )
121+
122+ val concreteRefLhsToGuard = concreteRefsLhs.associate { it.expr.address to it.guard }
123+
124+ val conjuncts = mutableListOf<UBoolExpr >(falseExpr)
125+
126+ concreteRefsRhs.forEach { (concreteRefRhs, guardRhs) ->
127+ val guardLhs = concreteRefLhsToGuard.getOrDefault(concreteRefRhs.address, falseExpr)
128+ // mkAnd instead of mkAnd with flat=false here is OK
129+ val conjunct = mkAnd(guardLhs, guardRhs)
130+ conjuncts + = conjunct
146131 }
132+
133+ if (symbolicRefLhs != null && symbolicRefRhs != null ) {
134+ val refsEq = super .mkEq(symbolicRefLhs.expr, symbolicRefRhs.expr, order = true )
135+ // mkAnd instead of mkAnd with flat=false here is OK
136+ val conjunct = mkAnd(symbolicRefLhs.guard, symbolicRefRhs.guard, refsEq)
137+ conjuncts + = conjunct
138+ }
139+
140+ // it's safe to use mkOr here
141+ mkOr(conjuncts)
147142 }
148143
144+ private inline fun mkHeapEqWithFastChecks (
145+ lhs : UHeapRef ,
146+ rhs : UHeapRef ,
147+ blockOnFailedFastChecks : () -> UBoolExpr ,
148+ ): UBoolExpr = when {
149+ lhs is USymbolicHeapRef && rhs is USymbolicHeapRef -> super .mkEq(lhs, rhs, order = true )
150+ isAllocatedConcreteHeapRef(lhs) && isAllocatedConcreteHeapRef(rhs) -> mkBool(lhs == rhs)
151+ isStaticHeapRef(lhs) && isStaticHeapRef(rhs) -> mkBool(lhs == rhs)
152+
153+ isAllocatedConcreteHeapRef(lhs) && isStaticHeapRef(rhs) -> falseExpr
154+ isStaticHeapRef(lhs) && isAllocatedConcreteHeapRef(rhs) -> falseExpr
155+
156+ isStaticHeapRef(lhs) && rhs is UNullRef -> falseExpr
157+ lhs is UNullRef && isStaticHeapRef(rhs) -> falseExpr
158+
159+ lhs is USymbolicHeapRef && isStaticHeapRef(rhs) -> super .mkEq(lhs, rhs, order = true )
160+ isStaticHeapRef(lhs) && rhs is USymbolicHeapRef -> super .mkEq(lhs, rhs, order = true )
161+
162+ else -> blockOnFailedFastChecks()
163+ }
164+
149165 private val uConcreteHeapRefCache = mkAstInterner<UConcreteHeapRef >()
150166 fun mkConcreteHeapRef (address : UConcreteHeapAddress ): UConcreteHeapRef =
151167 uConcreteHeapRefCache.createIfContextActive {
0 commit comments