@@ -19,9 +19,11 @@ import org.jacodb.ets.model.EtsRefType
1919import org.jacodb.ets.model.EtsReturnStmt
2020import org.jacodb.ets.model.EtsStaticFieldRef
2121import org.jacodb.ets.model.EtsStmt
22+ import org.jacodb.ets.model.EtsStringType
2223import org.jacodb.ets.model.EtsThis
2324import org.jacodb.ets.model.EtsThrowStmt
2425import org.jacodb.ets.model.EtsType
26+ import org.jacodb.ets.model.EtsUndefinedType
2527import org.jacodb.ets.model.EtsUnknownType
2628import org.jacodb.ets.model.EtsValue
2729import org.jacodb.ets.model.EtsVoidType
@@ -169,15 +171,15 @@ class TsInterpreter(
169171 if (isAllocatedConcreteHeapRef(resolvedInstance)) {
170172 val type = scope.calcOnState { memory.typeStreamOf(resolvedInstance) }.single()
171173 if (type is EtsClassType ) {
172- val classes = ctx. scene.projectAndSdkClasses.filter { it.name == type.typeName }
174+ val classes = scene.projectAndSdkClasses.filter { it.name == type.typeName }
173175 if (classes.isEmpty()) {
174176 logger.warn { " Could not resolve class: ${type.typeName} " }
175- scope.assert (ctx. falseExpr)
177+ scope.assert (falseExpr)
176178 return
177179 }
178180 if (classes.size > 1 ) {
179181 logger.warn { " Multiple classes with name: ${type.typeName} " }
180- scope.assert (ctx. falseExpr)
182+ scope.assert (falseExpr)
181183 return
182184 }
183185 val cls = classes.single()
@@ -189,14 +191,14 @@ class TsInterpreter(
189191 logger.warn {
190192 " Could not resolve method: ${stmt.callee} on type: $type "
191193 }
192- scope.assert (ctx. falseExpr)
194+ scope.assert (falseExpr)
193195 return
194196 }
195197 } else {
196- val methods = ctx. resolveEtsMethods(stmt.callee)
198+ val methods = resolveEtsMethods(stmt.callee)
197199 if (methods.isEmpty()) {
198200 logger.warn { " Could not resolve method: ${stmt.callee} " }
199- scope.assert (ctx. falseExpr)
201+ scope.assert (falseExpr)
200202 return
201203 }
202204 concreteMethods + = methods
@@ -213,7 +215,7 @@ class TsInterpreter(
213215 val type = requireNotNull(method.enclosingClass).type
214216
215217 val constraint = scope.calcOnState {
216- val ref = stmt.instance.asExpr(ctx. addressSort)
218+ val ref = stmt.instance.asExpr(addressSort)
217219 .takeIf { ! it.isFakeObject() }
218220 ? : uncoveredInstance.asExpr(addressSort)
219221 // TODO mistake, should be separated into several hierarchies
@@ -303,7 +305,7 @@ class TsInterpreter(
303305 }
304306
305307 check(args.size == numFormal) {
306- " Expected ${ numFormal} arguments, got ${args.size} "
308+ " Expected $numFormal arguments, got ${args.size} "
307309 }
308310
309311 args + = stmt.instance!!
@@ -577,7 +579,12 @@ class TsInterpreter(
577579 }
578580
579581 private fun exprResolverWithScope (scope : TsStepScope ): TsExprResolver =
580- TsExprResolver (ctx, scope, ::mapLocalToIdx, graph.hierarchy)
582+ TsExprResolver (
583+ ctx = ctx,
584+ scope = scope,
585+ localToIdx = ::mapLocalToIdx,
586+ hierarchy = graph.hierarchy,
587+ )
581588
582589 // (method, localName) -> idx
583590 private val localVarToIdx: MutableMap <EtsMethod , Map <String , Int >> = hashMapOf()
@@ -608,40 +615,38 @@ class TsInterpreter(
608615 else -> error(" Unexpected local: $local " )
609616 }
610617
611- fun getInitialState (method : EtsMethod , targets : List <TsTarget >): TsState {
618+ fun getInitialState (method : EtsMethod , targets : List <TsTarget >): TsState = with (ctx) {
612619 val state = TsState (
613620 ctx = ctx,
614621 ownership = MutabilityOwnership (),
615622 entrypoint = method,
616623 targets = UTargetsSet .from(targets),
617624 )
618625
626+ state.memory.types.allocate(mkTsNullValue().address, EtsNullType )
627+
619628 val solver = ctx.solver<EtsType >()
620629
621630 // TODO check for statics
622- val thisInstanceRef = mkRegisterStackLValue(ctx.addressSort, method.parameters.count())
623- val thisRef = state.memory.read(thisInstanceRef).asExpr(ctx.addressSort)
624-
625- state.pathConstraints + = with (ctx) {
626- mkNot(
627- mkOr(
628- ctx.mkHeapRefEq(thisRef, ctx.mkTsNullValue()),
629- ctx.mkHeapRefEq(thisRef, ctx.mkUndefinedValue())
630- )
631- )
632- }
631+ val thisIdx = mapLocalToIdx(method, EtsThis (method.enclosingClass!! .type))
632+ ? : error(" Cannot find index for 'this' in method: $method " )
633+ val thisInstanceRef = mkRegisterStackLValue(addressSort, thisIdx)
634+ val thisRef = state.memory.read(thisInstanceRef).asExpr(addressSort)
633635
634- method.enclosingClass?. let { thisClass ->
635- // TODO not equal but subtype for abstract/interfaces
636- val thisTypeConstraint = state.memory.types.evalTypeEquals(thisRef, thisClass.type)
637- state.pathConstraints + = thisTypeConstraint
638- }
636+ state.pathConstraints + = mkNot(mkHeapRefEq(thisRef, mkTsNullValue()))
637+ state.pathConstraints + = mkNot(mkHeapRefEq(thisRef, mkUndefinedValue()))
638+
639+ // TODO not equal but subtype for abstract/interfaces
640+ state.pathConstraints + = state.memory.types.evalTypeEquals(thisRef, method.enclosingClass !! .type)
639641
640642 method.parameters.forEachIndexed { i, param ->
643+ val ref by lazy {
644+ val lValue = mkRegisterStackLValue(addressSort, i)
645+ state.memory.read(lValue).asExpr(addressSort)
646+ }
647+
641648 val parameterType = param.type
642649 if (parameterType is EtsRefType ) {
643- val argLValue = mkRegisterStackLValue(ctx.addressSort, i)
644- val ref = state.memory.read(argLValue).asExpr(ctx.addressSort)
645650 val resolvedParameterType = graph.cp
646651 .projectAndSdkClasses
647652 .singleOrNull { it.name == parameterType.typeName }
@@ -653,6 +658,21 @@ class TsInterpreter(
653658 val auxiliaryType = (resolvedParameterType as ? EtsClassType )?.toAuxiliaryType(graph.hierarchy)
654659 ? : resolvedParameterType
655660 state.pathConstraints + = state.memory.types.evalIsSubtype(ref, auxiliaryType)
661+
662+ state.pathConstraints + = mkNot(mkHeapRefEq(ref, mkTsNullValue()))
663+ state.pathConstraints + = mkNot(mkHeapRefEq(ref, mkUndefinedValue()))
664+ }
665+ if (parameterType == EtsNullType ) {
666+ state.pathConstraints + = mkHeapRefEq(ref, mkTsNullValue())
667+ }
668+ if (parameterType == EtsUndefinedType ) {
669+ state.pathConstraints + = mkHeapRefEq(ref, mkUndefinedValue())
670+ }
671+ if (parameterType == EtsStringType ) {
672+ state.pathConstraints + = state.memory.types.evalTypeEquals(ref, EtsStringType )
673+
674+ state.pathConstraints + = mkNot(mkHeapRefEq(ref, mkTsNullValue()))
675+ state.pathConstraints + = mkNot(mkHeapRefEq(ref, mkUndefinedValue()))
656676 }
657677 }
658678
@@ -663,35 +683,32 @@ class TsInterpreter(
663683 state.memory.stack.push(method.parametersWithThisCount, method.localsCount)
664684 state.newStmt(method.cfg.instructions.first())
665685
666- state.memory.types.allocate(ctx. mkTsNullValue().address, EtsNullType )
686+ state.memory.types.allocate(mkTsNullValue().address, EtsNullType )
667687
668- return state
688+ state
669689 }
670690
671691 private fun mockMethodCall (scope : TsStepScope , method : EtsMethodSignature ) {
672692 scope.doWithState {
673- with (ctx) {
674- if (method.returnType is EtsVoidType ) {
675- methodResult = TsMethodResult .Success .MockedCall (method, ctx.voidValue)
676- return @doWithState
677- }
693+ if (method.returnType is EtsVoidType ) {
694+ methodResult = TsMethodResult .Success .MockedCall (method, ctx.voidValue)
695+ return @doWithState
696+ }
678697
679- val resultSort = typeToSort(method.returnType)
680- val resultValue = when (resultSort) {
681- is UAddressSort -> makeSymbolicRefUntyped()
682- is TsUnresolvedSort -> {
683- mkFakeValue(
684- scope,
685- makeSymbolicPrimitive(ctx.boolSort),
686- makeSymbolicPrimitive(ctx.fp64Sort),
687- makeSymbolicRefUntyped()
688- )
689- }
698+ val resultSort = ctx.typeToSort(method.returnType)
699+ val resultValue = when (resultSort) {
700+ is UAddressSort -> makeSymbolicRefUntyped()
690701
691- else -> makeSymbolicPrimitive(resultSort)
692- }
693- methodResult = TsMethodResult .Success .MockedCall (method, resultValue)
702+ is TsUnresolvedSort -> ctx.mkFakeValue(
703+ scope,
704+ makeSymbolicPrimitive(ctx.boolSort),
705+ makeSymbolicPrimitive(ctx.fp64Sort),
706+ makeSymbolicRefUntyped()
707+ )
708+
709+ else -> makeSymbolicPrimitive(resultSort)
694710 }
711+ methodResult = TsMethodResult .Success .MockedCall (method, resultValue)
695712 }
696713 }
697714
0 commit comments