@@ -64,15 +64,14 @@ import org.jacodb.ets.base.EtsType
6464import org.jacodb.ets.base.EtsTypeOfExpr
6565import org.jacodb.ets.base.EtsUnaryExpr
6666import org.jacodb.ets.base.EtsUnaryPlusExpr
67- import org.jacodb.ets.base.EtsUnclearRefType
6867import org.jacodb.ets.base.EtsUndefinedConstant
6968import org.jacodb.ets.base.EtsUnknownType
7069import org.jacodb.ets.base.EtsUnsignedRightShiftExpr
7170import org.jacodb.ets.base.EtsValue
7271import org.jacodb.ets.base.EtsVoidExpr
7372import org.jacodb.ets.base.EtsYieldExpr
73+ import org.jacodb.ets.base.STATIC_INIT_METHOD_NAME
7474import org.jacodb.ets.base.UNKNOWN_CLASS_NAME
75- import org.jacodb.ets.model.EtsField
7675import org.jacodb.ets.model.EtsFieldSignature
7776import org.jacodb.ets.model.EtsMethod
7877import org.jacodb.ets.model.EtsMethodSignature
@@ -86,12 +85,15 @@ import org.usvm.api.allocateArray
8685import org.usvm.isTrue
8786import org.usvm.machine.TsContext
8887import org.usvm.machine.interpreter.TsStepScope
88+ import org.usvm.machine.interpreter.isInitialized
89+ import org.usvm.machine.interpreter.markInitialized
8990import org.usvm.machine.operator.TsBinaryOperator
9091import org.usvm.machine.operator.TsUnaryOperator
9192import org.usvm.machine.state.TsMethodResult
9293import org.usvm.machine.state.TsState
9394import org.usvm.machine.state.localsCount
9495import org.usvm.machine.state.newStmt
96+ import org.usvm.machine.state.parametersWithThisCount
9597import org.usvm.machine.types.FakeType
9698import org.usvm.machine.types.mkFakeValue
9799import org.usvm.memory.ULValue
@@ -101,6 +103,7 @@ import org.usvm.util.mkArrayIndexLValue
101103import org.usvm.util.mkArrayLengthLValue
102104import org.usvm.util.mkFieldLValue
103105import org.usvm.util.mkRegisterStackLValue
106+ import org.usvm.util.resolveEtsField
104107import org.usvm.util.throwExceptionWithoutStackFrameDrop
105108
106109private val logger = KotlinLogging .logger {}
@@ -111,7 +114,7 @@ class TsExprResolver(
111114 private val localToIdx : (EtsMethod , EtsValue ) -> Int ,
112115) : EtsEntity.Visitor<UExpr<out USort>?> {
113116
114- private val simpleValueResolver: TsSimpleValueResolver =
117+ val simpleValueResolver: TsSimpleValueResolver =
115118 TsSimpleValueResolver (ctx, scope, localToIdx)
116119
117120 fun resolve (expr : EtsEntity ): UExpr <out USort >? {
@@ -446,11 +449,10 @@ class TsExprResolver(
446449 doWithState {
447450 val method = resolveInstanceCall(expr.instance, expr.method)
448451
452+ check(args.size == method.parametersWithThisCount)
449453 pushSortsForArguments(expr.instance, expr.args, localToIdx)
450-
451454 callStack.push(method, currentStatement)
452455 memory.stack.push(args.toTypedArray(), method.localsCount)
453-
454456 newStmt(method.cfg.stmts.first())
455457 }
456458 }
@@ -610,46 +612,47 @@ class TsExprResolver(
610612 state.throwExceptionWithoutStackFrameDrop(address, type)
611613 }
612614
613- private fun resolveInstanceField (
614- instance : EtsLocal ,
615+ private fun handleFieldRef (
616+ instance : EtsLocal ? ,
617+ instanceRef : UHeapRef ,
615618 field : EtsFieldSignature ,
616- ): EtsField {
617- // Perfect signature:
618- if (field.enclosingClass.name != UNKNOWN_CLASS_NAME ) {
619- val clazz = ctx.scene.projectAndSdkClasses.single { it.name == field.enclosingClass.name }
620- val fields = clazz.fields.filter { it.name == field.name }
621- if (fields.size == 1 ) return fields.single()
622- }
619+ ): UExpr <out USort >? = with (ctx) {
620+ val etsField = resolveEtsField(instance, field)
621+ val sort = typeToSort(etsField.type)
623622
624- // Unknown signature:
625- val instanceType = instance.type
626- if (instanceType is EtsClassType ) {
627- val classes = ctx.scene.projectAndSdkClasses.filter { it.name == instanceType.signature.name }
628- if (classes.size == 1 ) {
629- val clazz = classes.single()
630- return clazz.fields.single { it.name == field.name }
631- }
632- val fields = classes.flatMap { it.fields.filter { it.name == field.name } }
633- if (fields.size == 1 ) {
634- return fields.single()
635- }
636- } else if (instanceType is EtsUnclearRefType ) {
637- val classes = ctx.scene.projectAndSdkClasses.filter { it.name == instanceType.name }
638- if (classes.size == 1 ) {
639- val clazz = classes.single( )
640- return clazz.fields.single { it.name == field.name }
641- }
642- val fields = classes.flatMap { it.fields.filter { it.name == field.name } }
643- if (fields.size == 1 ) {
644- return fields.single()
623+ val expr = if (sort == unresolvedSort) {
624+ val boolLValue = mkFieldLValue(boolSort, instanceRef, field)
625+ val fpLValue = mkFieldLValue(fp64Sort, instanceRef, field)
626+ val refLValue = mkFieldLValue(addressSort, instanceRef, field)
627+
628+ scope.calcOnState {
629+ val bool = memory.read(boolLValue)
630+ val fp = memory.read(fpLValue)
631+ val ref = memory.read(refLValue)
632+
633+ // If a fake object is already created and assigned to the field,
634+ // there is no need to recreate another one
635+ val fakeRef = if (ref.isFakeObject() ) {
636+ ref
637+ } else {
638+ mkFakeValue(scope, bool, fp, ref )
639+ }
640+
641+ memory.write(refLValue, fakeRef.asExpr(addressSort), guard = trueExpr)
642+
643+ fakeRef
645644 }
646645 } else {
647- val fields = ctx.scene.projectAndSdkClasses.flatMap { it.fields.filter { it.name == field.name } }
648- if (fields.size == 1 ) {
649- return fields.single()
650- }
646+ val lValue = mkFieldLValue(sort, instanceRef, field)
647+ scope.calcOnState { memory.read(lValue) }
648+ }
649+
650+ // TODO: check 'field.type' vs 'etsField.type'
651+ if (assertIsSubtype(expr, field.type)) {
652+ expr
653+ } else {
654+ null
651655 }
652- error(" Cannot resolve field $field " )
653656 }
654657
655658 override fun visit (value : EtsInstanceFieldRef ): UExpr <out USort >? = with (ctx) {
@@ -683,46 +686,40 @@ class TsExprResolver(
683686 }
684687 }
685688
686- val field = resolveInstanceField (value.instance, value.field)
687- val sort = typeToSort(field.type)
689+ return handleFieldRef (value.instance, instanceRef , value.field)
690+ }
688691
689- val expr = if (sort == unresolvedSort ) {
690- val boolLValue = mkFieldLValue(boolSort, instanceRef, value.field)
691- val fpLValue = mkFieldLValue(fp64Sort, instanceRef, value.field)
692- val refLValue = mkFieldLValue(addressSort, instanceRef, value.field)
692+ override fun visit ( value : EtsStaticFieldRef ): UExpr < out USort > ? = with (ctx ) {
693+ val clazz = scene.projectAndSdkClasses.singleOrNull {
694+ it.signature == value.field.enclosingClass
695+ } ? : return null
693696
694- scope.calcOnState {
695- val bool = memory.read(boolLValue)
696- val fp = memory.read(fpLValue)
697- val ref = memory.read(refLValue)
697+ val instanceRef = scope.calcOnState { getStaticInstance(clazz) }
698698
699- // If a fake object is already created and assigned to the field,
700- // there is no need to recreate another one
701- val fakeRef = if (ref.isFakeObject()) {
702- ref
703- } else {
704- mkFakeValue(scope, bool, fp, ref)
699+ val initializer = clazz.methods.singleOrNull { it.name == STATIC_INIT_METHOD_NAME }
700+ if (initializer != null ) {
701+ val isInitialized = scope.calcOnState { isInitialized(clazz) }
702+ if (isInitialized) {
703+ scope.doWithState {
704+ // TODO: Handle static initializer result
705+ val result = methodResult
706+ if (result is TsMethodResult .Success && result.method == initializer) {
707+ methodResult = TsMethodResult .NoCall
708+ }
705709 }
706-
707- memory.write(refLValue, fakeRef.asExpr(addressSort), guard = trueExpr)
708-
709- fakeRef
710+ } else {
711+ scope.doWithState {
712+ markInitialized(clazz)
713+ pushSortsForArguments(instance = null , args = emptyList(), localToIdx)
714+ callStack.push(initializer, currentStatement)
715+ memory.stack.push(arrayOf(instanceRef), initializer.localsCount)
716+ newStmt(initializer.cfg.stmts.first())
717+ }
718+ return null
710719 }
711- } else {
712- val lValue = mkFieldLValue(sort, instanceRef, value.field)
713- scope.calcOnState { memory.read(lValue) }
714720 }
715721
716- if (assertIsSubtype(expr, value.type)) {
717- expr
718- } else {
719- null
720- }
721- }
722-
723- override fun visit (value : EtsStaticFieldRef ): UExpr <out USort >? {
724- logger.warn { " visit(${value::class .simpleName} ) is not implemented yet" }
725- error(" Not supported $value " )
722+ return handleFieldRef(instance = null , instanceRef, value.field)
726723 }
727724
728725 // endregion
0 commit comments