@@ -25,6 +25,7 @@ import org.jacodb.ets.model.EtsMethodSignature
2525import org.usvm.UAddressSort
2626import org.usvm.UConcreteHeapRef
2727import org.usvm.UExpr
28+ import org.usvm.UHeapRef
2829import org.usvm.USort
2930import org.usvm.api.GlobalFieldValue
3031import org.usvm.api.TsParametersState
@@ -66,7 +67,7 @@ class TsTestResolver {
6667
6768 is TsMethodResult .Success -> {
6869 afterMemoryScope.withMode(ResolveMode .CURRENT ) {
69- resolveExpr(res.value, method.returnType)
70+ resolveExpr(res.value, res.value, method.returnType)
7071 }
7172 }
7273
@@ -115,11 +116,13 @@ open class TsTestStateResolver(
115116) {
116117 fun resolveLValue (lValue : ULValue <* , * >, type : EtsType ): TsValue {
117118 val expr = memory.read(lValue)
118- return resolveExpr(expr, type)
119+ val symbolicRef = if (lValue.sort is UAddressSort ) finalStateMemory.read(lValue).asExpr(ctx.addressSort) else null
120+ return resolveExpr(expr, symbolicRef, type)
119121 }
120122
121123 fun resolveExpr (
122124 expr : UExpr <out USort >,
125+ symbolicRef : UExpr <out USort >? = null,
123126 type : EtsType ,
124127 ): TsValue = with (ctx) {
125128 if (expr.isFakeObject()) {
@@ -128,57 +131,66 @@ open class TsTestStateResolver(
128131
129132 return when (type) {
130133 is EtsPrimitiveType -> resolvePrimitive(expr, type)
131- is EtsRefType -> resolveRef(expr.asExpr(ctx.addressSort), type)
132- else -> resolveUnknownExpr(expr)
134+ is EtsRefType -> resolveRef(expr.asExpr(ctx.addressSort), symbolicRef?.asExpr(ctx.addressSort) ? : expr.asExpr(ctx.addressSort), type)
135+ else -> resolveUnknownExpr(expr, symbolicRef )
133136 }
134137 }
135138
136- fun resolveUnknownExpr (expr : UExpr <out USort >): TsValue = with (expr .tctx) {
137- when (expr .sort) {
138- fp64Sort -> resolvePrimitive(expr , EtsNumberType )
139- boolSort -> resolvePrimitive(expr , EtsBooleanType )
139+ fun resolveUnknownExpr (heapRef : UExpr <out USort >, finalStateMemoryRef : UExpr < out USort > ? ): TsValue = with (heapRef .tctx) {
140+ when (heapRef .sort) {
141+ fp64Sort -> resolvePrimitive(heapRef , EtsNumberType )
142+ boolSort -> resolvePrimitive(heapRef , EtsBooleanType )
140143 addressSort -> {
141- if (expr .isFakeObject()) {
142- resolveFakeObject(expr )
144+ if (heapRef .isFakeObject()) {
145+ resolveFakeObject(heapRef )
143146 } else {
144- resolveRef(expr .asExpr(ctx.addressSort), EtsUnknownType )
147+ resolveRef(heapRef.asExpr(ctx.addressSort), finalStateMemoryRef? .asExpr(ctx.addressSort), EtsUnknownType )
145148 }
146149 }
147150
148151 else -> TODO ()
149152 }
150153 }
151154
152- private fun resolveRef (expr : UExpr <UAddressSort >, type : EtsType ): TsValue {
153- val instance = model.eval(expr) as UConcreteHeapRef
155+ private fun resolveRef (
156+ heapRef : UExpr <UAddressSort >,
157+ finalStateMemoryRef : UExpr <UAddressSort >? ,
158+ type : EtsType
159+ ): TsValue {
160+ val concreteRef = evaluateInModel(heapRef) as UConcreteHeapRef
154161
155- if (instance .address == 0 ) {
162+ if (concreteRef .address == 0 ) {
156163 return TsValue .TsUndefined
157164 }
158165
159- if (model.eval(ctx.mkHeapRefEq(expr , ctx.mkTsNullValue())).isTrue) {
166+ if (model.eval(ctx.mkHeapRefEq(heapRef , ctx.mkTsNullValue())).isTrue) {
160167 return TsValue .TsNull
161168 }
162169
163170 return when (type) {
164- is EtsClassType -> resolveClass(instance , type)
165- is EtsArrayType -> resolveArray(instance , type)
171+ is EtsClassType -> resolveClass(concreteRef, finalStateMemoryRef ? : heapRef , type)
172+ is EtsArrayType -> resolveArray(concreteRef, finalStateMemoryRef ? : heapRef , type)
166173 is EtsUnknownType -> {
167- val type = finalStateMemory.types.getTypeStream(expr ).first()
168- resolveRef(expr , type)
174+ val type = finalStateMemory.types.getTypeStream(heapRef ).first()
175+ resolveRef(heapRef, finalStateMemoryRef , type)
169176 }
170177
171178 else -> error(" Unexpected type: $type " )
172179 }
173180 }
174181
175- private fun resolveArray (expr : UConcreteHeapRef , type : EtsArrayType ): TsValue .TsArray <* > {
176- val arrayLengthLValue = UArrayLengthLValue (expr, type, ctx.sizeSort)
182+
183+ private fun resolveArray (
184+ concreteRef : UConcreteHeapRef ,
185+ heapRef : UHeapRef ,
186+ type : EtsArrayType
187+ ): TsValue .TsArray <* > {
188+ val arrayLengthLValue = UArrayLengthLValue (heapRef, type, ctx.sizeSort)
177189 val length = model.eval(memory.read(arrayLengthLValue)) as KBitVec32Value
178190
179191 val values = (0 until length.intValue).map {
180192 val index = ctx.mkSizeExpr(it)
181- val lValue = UArrayIndexLValue (ctx.addressSort, expr , index, type)
193+ val lValue = UArrayIndexLValue (ctx.addressSort, heapRef , index, type)
182194 val value = memory.read(lValue)
183195
184196 if (model.eval(ctx.mkHeapRefEq(value, ctx.mkUndefinedValue())).isTrue) {
@@ -229,15 +241,15 @@ open class TsTestStateResolver(
229241 // Note that everything about details of fake object we need to read from final state of the memory
230242 // since they are allocated objects
231243 val value = finalStateMemory.read(lValue)
232- resolveExpr(model.eval(value), EtsBooleanType )
244+ resolveExpr(model.eval(value), value, EtsBooleanType )
233245 }
234246
235247 model.eval(type.fpTypeExpr).isTrue -> {
236248 val lValue = ctx.getIntermediateFpLValue(expr.address)
237249 // Note that everything about details of fake object we need to read from final state of the memory
238250 // since they are allocated objects
239251 val value = finalStateMemory.read(lValue)
240- resolveExpr(model.eval(value), EtsNumberType )
252+ resolveExpr(model.eval(value), value, EtsNumberType )
241253 }
242254
243255 model.eval(type.refTypeExpr).isTrue -> {
@@ -247,7 +259,7 @@ open class TsTestStateResolver(
247259 val value = finalStateMemory.read(lValue)
248260 val ref = model.eval(value)
249261 // TODO mistake with signature, use TypeStream instead
250- resolveExpr(ref, EtsClassType (ctx.scene.projectAndSdkClasses.first().signature))
262+ resolveExpr(ref, value, EtsClassType (ctx.scene.projectAndSdkClasses.first().signature))
251263 }
252264
253265 else -> error(" Unsupported" )
@@ -270,22 +282,10 @@ open class TsTestStateResolver(
270282 }
271283
272284 private fun resolveClass (
273- expr : UExpr <out USort >,
285+ concreteRef : UConcreteHeapRef ,
286+ heapRef : UHeapRef ,
274287 classType : EtsClassType ,
275288 ): TsValue {
276- if (expr is UConcreteHeapRef && expr.address == 0 ) {
277- return TsValue .TsUndefined
278- }
279-
280- val nullRef = ctx.mkTsNullValue()
281- if (model.eval(ctx.mkHeapRefEq(expr.asExpr(ctx.addressSort), nullRef)).isTrue) {
282- return TsValue .TsNull
283- }
284-
285- check(expr.sort == ctx.addressSort) {
286- " Expected address sort, but got ${expr.sort} "
287- }
288-
289289 val clazz = ctx.scene.projectAndSdkClasses.firstOrNull { it.signature == classType.signature }
290290 ? : if (classType.signature.name == " Object" ) {
291291 EtsClassImpl (
@@ -306,7 +306,7 @@ open class TsTestStateResolver(
306306 }
307307
308308 val properties = clazz.fields.associate { field ->
309- val lValue = UFieldLValue (ctx.addressSort, expr.asExpr(ctx.addressSort) , field.name)
309+ val lValue = UFieldLValue (ctx.addressSort, heapRef , field.name)
310310 // read from final state memory since it is a fake object
311311 val fieldExpr = finalStateMemory.read(lValue)
312312
0 commit comments