Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
fb0adca
Draft: model synthesis
Jun 20, 2022
11c47d9
m
AbdullinAM Jun 20, 2022
4aaa8e5
first prototype, needs debugging and tuning
AbdullinAM Jun 22, 2022
9c63ba0
prototype
AbdullinAM Jun 28, 2022
707fa6d
refactor
AbdullinAM Jun 29, 2022
10c4193
very early prototype
AbdullinAM Jul 8, 2022
4285a5c
UtConstraintModel implemented
AbdullinAM Jul 12, 2022
22e2266
partial UtConstraint to UtExpression convertion
AbdullinAM Jul 14, 2022
6b47a9a
working prototypes
AbdullinAM Jul 19, 2022
a75a840
bugfixes + expression support in constraints
AbdullinAM Jul 21, 2022
fb392f6
m
AbdullinAM Jul 26, 2022
5f35311
everything kind of works, but some constraints need to be added
AbdullinAM Jul 27, 2022
ba9bb62
first working protoype with arrays
AbdullinAM Aug 1, 2022
065924f
renaming
AbdullinAM Aug 1, 2022
8cc7515
first tests and fixes
AbdullinAM Aug 2, 2022
4a14606
more expressions supported
AbdullinAM Aug 3, 2022
bbf525b
some cleanup + more expressions supported
AbdullinAM Aug 8, 2022
850b530
cleanup
AbdullinAM Aug 8, 2022
8799691
support for multidimensional arrays + fix for array generation
AbdullinAM Aug 9, 2022
60df4a4
first support of lists
AbdullinAM Aug 10, 2022
8963a7e
support sets
AbdullinAM Aug 10, 2022
1578c96
small refactorings
AbdullinAM Aug 11, 2022
1dd4b25
maps
AbdullinAM Aug 12, 2022
313757d
some cleanup and parameters
AbdullinAM Aug 12, 2022
faa0047
test write fix
AbdullinAM Aug 12, 2022
94740c9
m
AbdullinAM Aug 22, 2022
9920283
Merge branch 'main' into abdullin/constraint-model-synthesis
AbdullinAM Aug 22, 2022
fd22077
merge with master
AbdullinAM Aug 24, 2022
4e97b5f
first prototype of constraint scoring selector
AbdullinAM Aug 26, 2022
2544b31
m
AbdullinAM Aug 30, 2022
e585371
fixes
AbdullinAM Aug 31, 2022
d2564e9
Merge branch 'main' into abdullin/constraint-model-synthesis
AbdullinAM Sep 7, 2022
bb1acbc
Merge branch 'main' into abdullin/constraint-model-synthesis
AbdullinAM Sep 7, 2022
c6fbeb0
Split constraint models into a set of non-intersecting subsets before…
AbdullinAM Sep 12, 2022
2553ef7
m
AbdullinAM Sep 12, 2022
e943a16
some cleanup
AbdullinAM Sep 13, 2022
cd5fff8
more cleanup
AbdullinAM Sep 13, 2022
c2a7d31
order models in the subsets
AbdullinAM Sep 13, 2022
d1b09c8
simple caching of synthesis unit contexts
AbdullinAM Sep 13, 2022
eedccb9
option to enable/disable caching of synthesis contexts
AbdullinAM Sep 14, 2022
11eea4d
m
AbdullinAM Sep 14, 2022
9712e70
tests
AbdullinAM Sep 14, 2022
1c6b679
unit tests fixed
AbdullinAM Sep 19, 2022
4e37763
Merge branch 'main' into abdullin/constraint-model-synthesis
AbdullinAM Sep 28, 2022
34ed6fe
merge with main
AbdullinAM Sep 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
first support of lists
  • Loading branch information
AbdullinAM committed Aug 10, 2022
commit 60df4a42393ba0ca8fe97f89cdd7c58d5afc8506
Original file line number Diff line number Diff line change
Expand Up @@ -455,14 +455,14 @@ sealed class UtConstraintModel(

data class UtPrimitiveConstraintModel(
override val variable: UtConstraintVariable,
override val utConstraints: Set<UtConstraint>
override val utConstraints: Set<UtConstraint>,
val concrete: Any? = null
) : UtConstraintModel(variable, utConstraints) {
}

data class UtReferenceConstraintModel(
override val variable: UtConstraintVariable,
override val utConstraints: Set<UtConstraint>,
val concrete: Any? = null
) : UtConstraintModel(variable, utConstraints) {
fun isNull() = utConstraints.any {
it is UtRefEqConstraint && it.lhv == variable && it.rhv is UtConstraintNull
Expand All @@ -475,20 +475,35 @@ data class UtReferenceToConstraintModel(
override val utConstraints: Set<UtConstraint> = emptySet()
) : UtConstraintModel(variable, utConstraints)

data class UtArrayConstraintModel(
sealed class UtElementContainerConstraintModel(
override val variable: UtConstraintVariable,
val length: UtModel,
val elements: Map<UtModel, UtModel>,
open val length: UtModel,
open val elements: Map<UtModel, UtModel>,
override val utConstraints: Set<UtConstraint> = emptySet()
) : UtConstraintModel(variable, utConstraints) {
val allConstraints: Set<UtConstraint> get() = elements.toList().fold((length as UtConstraintModel).utConstraints) { acc, pair ->
acc +
((pair.first as? UtConstraintModel)?.utConstraints ?: emptySet()) +
((pair.second as? UtConstraintModel)?.utConstraints ?: emptySet()) +
((pair.second as? UtArrayConstraintModel)?.allConstraints ?: emptySet())
}
val allConstraints: Set<UtConstraint>
get() = elements.toList().fold((length as UtConstraintModel).utConstraints) { acc, pair ->
acc +
((pair.first as? UtConstraintModel)?.utConstraints ?: emptySet()) +
((pair.second as? UtConstraintModel)?.utConstraints ?: emptySet()) +
((pair.second as? UtArrayConstraintModel)?.allConstraints ?: emptySet())
}
}

data class UtArrayConstraintModel(
override val variable: UtConstraintVariable,
override val length: UtModel,
override val elements: Map<UtModel, UtModel>,
override val utConstraints: Set<UtConstraint> = emptySet()
) : UtElementContainerConstraintModel(variable, length, elements, utConstraints)

data class UtListConstraintModel(
override val variable: UtConstraintVariable,
override val length: UtModel,
override val elements: Map<UtModel, UtModel>,
override val utConstraints: Set<UtConstraint> = emptySet()
) : UtElementContainerConstraintModel(variable, length, elements, utConstraints)

/**
* Model for complex objects with assemble instructions.
*
Expand Down Expand Up @@ -588,12 +603,12 @@ data class UtDirectSetFieldModel(
val fieldModel: UtModel,
) : UtStatementModel(instance) {
override fun toString(): String = withToStringThreadLocalReentrancyGuard {
val modelRepresentation = when (fieldModel) {
is UtAssembleModel -> fieldModel.modelName
else -> fieldModel.toString()
}
"${instance.modelName}.${fieldId.name} = $modelRepresentation"
val modelRepresentation = when (fieldModel) {
is UtAssembleModel -> fieldModel.modelName
else -> fieldModel.toString()
}
"${instance.modelName}.${fieldId.name} = $modelRepresentation"
}

}

Expand Down Expand Up @@ -1058,7 +1073,7 @@ class BuiltinMethodId(

open class TypeParameters(val parameters: List<ClassId> = emptyList())

class WildcardTypeParameter: TypeParameters(emptyList())
class WildcardTypeParameter : TypeParameters(emptyList())

interface TestCaseGenerator {
fun init(
Expand Down Expand Up @@ -1199,6 +1214,7 @@ enum class CodegenLanguage(
"-cp", classPath,
"-XDignore.symbol.file" // to let javac use classes from rt.jar
).plus(sourcesFiles)

KOTLIN -> listOf("-d", buildDirectory, "-jvm-target", jvmTarget, "-cp", classPath).plus(sourcesFiles)
}
if (this == KOTLIN && System.getenv("KOTLIN_HOME") == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import org.utbot.framework.plugin.api.*
import org.utbot.framework.plugin.api.constraint.UtConstraintTransformer
import org.utbot.framework.plugin.api.constraint.UtConstraintVariableCollector
import org.utbot.framework.plugin.api.util.intClassId
import org.utbot.framework.plugin.api.util.isPrimitive
import org.utbot.framework.plugin.api.util.objectClassId

/**
* Constructs path conditions using calculated model. Can construct them for initial and current memory states that reflect
Expand Down Expand Up @@ -122,7 +124,7 @@ class ConstraintResolver(
value.addr.variable,
collectAtoms(value, addrs),
addrs[value.addr.variable.addr]!!.map { it.variable }.toSet(),
value.concrete?.value
value.concrete
)
}

Expand Down Expand Up @@ -154,27 +156,31 @@ class ConstraintResolver(
variable: UtConstraintVariable,
atoms: Set<UtConstraint>,
aliases: Set<UtConstraintVariable>,
concrete: Any? = null
concrete: Concrete? = null
): UtModel = when {
variable.isPrimitive -> buildPrimitiveModel(atoms, variable, aliases)
variable.isPrimitive -> buildPrimitiveModel(variable, atoms, aliases)
variable.addr == NULL_ADDR -> UtNullModel(variable.classId)
variable.addr in resolvedConstraints -> UtReferenceToConstraintModel(
variable,
resolvedConstraints.getValue(variable.addr)
)

variable.isArray -> buildArrayModel(atoms, variable, aliases).also {
variable.isArray -> buildArrayModel(variable, atoms, aliases).also {
resolvedConstraints[variable.addr] = it
}

else -> buildObjectModel(atoms, variable, aliases, concrete).also {
resolvedConstraints[variable.addr] = it
else -> when (concrete) {
null -> buildObjectModel(variable, atoms, aliases).also {
resolvedConstraints[variable.addr] = it
}

else -> buildConcreteModel(concrete, variable, atoms, aliases)
}
}

private fun buildPrimitiveModel(
atoms: Set<UtConstraint>,
variable: UtConstraintVariable,
atoms: Set<UtConstraint>,
aliases: Set<UtConstraintVariable>
): UtModel {
assert(variable.isPrimitive)
Expand All @@ -185,15 +191,14 @@ class ConstraintResolver(
}.map { it.accept(UtConstraintTransformer(aliases.associateWith { variable })) }.toSet()

return UtPrimitiveConstraintModel(
variable, primitiveConstraints
variable, primitiveConstraints, concrete = holder.eval(variable.expr).value()
)
}

private fun buildObjectModel(
atoms: Set<UtConstraint>,
variable: UtConstraintVariable,
aliases: Set<UtConstraintVariable>,
concrete: Any? = null
atoms: Set<UtConstraint>,
aliases: Set<UtConstraintVariable>
): UtModel {
assert(!variable.isPrimitive && !variable.isArray)
assert(aliases.all { !it.isPrimitive && !it.isArray })
Expand All @@ -204,13 +209,13 @@ class ConstraintResolver(
}.toSet()

return UtReferenceConstraintModel(
variable, refConstraints, concrete
variable, refConstraints
)
}

private fun buildArrayModel(
atoms: Set<UtConstraint>,
variable: UtConstraintVariable,
atoms: Set<UtConstraint>,
aliases: Set<UtConstraintVariable>
): UtModel {
assert(variable.isArray)
Expand All @@ -226,43 +231,46 @@ class ConstraintResolver(
val concreteLength = lengths.firstOrNull()?.let { holder.eval(it.expr).value() as Int } ?: 100

val indexMap = atoms
.flatMap {
it.accept(UtConstraintVariableCollector { index ->
index is UtConstraintArrayAccess && index.instance in allAliases
})
.flatten { index ->
index is UtConstraintArrayAccess && index.instance in allAliases
}
.map { (it as UtConstraintArrayAccess).index }
.filter { (holder.eval(it.expr).value() as Int) < concreteLength }
.groupBy { holder.eval(varBuilder[it]) }
.map { it.value.toSet() }
.groupBy { holder.eval(varBuilder[it]).value() }
.mapValues { it.value.toSet() }

var indexCount = 0
val elements = indexMap.associate { indices ->
val elements = indexMap.map { (key, indices) ->
val indexVariable = UtConstraintParameter(
"${variable}_index${indexCount++}", intClassId
)

val indexModel = UtPrimitiveConstraintModel(
indexVariable,
indices.map { UtEqConstraint(indexVariable, it) }.toSet()
indices.map { UtEqConstraint(indexVariable, it) }.toSet(),
concrete = key
)

val arrayAccess = UtConstraintArrayAccess(variable, indexVariable, elementClassId)
val actualExpr = aliases.flatMap { base ->
val actualExpr = allAliases.flatMap { base ->
indices.map { UtConstraintArrayAccess(base, it, elementClassId) }
}.mapNotNull { varBuilder.backMapping[it] }.first()
val elementType = when {
elementClassId.isPrimitive -> elementClassId
else -> varBuilder.evalType(actualExpr as UtAddrExpression)!!.classId
}
val arrayAccess = UtConstraintArrayAccess(variable, indexVariable, elementType)
varBuilder.backMapping[arrayAccess] = actualExpr
val indexAliases = indices.flatMap { idx ->
allAliases.map { UtConstraintArrayAccess(it, idx, elementClassId) }
}.toSet()
val res = buildModel(arrayAccess, atoms, indexAliases, null).withConstraints(
val res = buildModel(arrayAccess, atoms, indexAliases).withConstraints(
indices.map { UtEqConstraint(it, indexVariable) }.toSet() + setOf(
UtGeConstraint(indexVariable, UtConstraintNumericConstant(0)),
UtLtConstraint(indexVariable, lengthVariable)
)
)
(indexModel as UtModel) to res
}
}.toMap()

return UtArrayConstraintModel(
variable,
Expand All @@ -272,6 +280,60 @@ class ConstraintResolver(
)
}

private fun buildConcreteModel(
concrete: Concrete,
variable: UtConstraintVariable,
atoms: Set<UtConstraint>,
aliases: Set<UtConstraintVariable>
): UtModel = when (concrete.value) {
is ListWrapper -> buildListModel(concrete.value, variable, atoms, aliases)
else -> TODO()
}

private fun buildListModel(
concrete: ListWrapper,
variable: UtConstraintVariable,
atoms: Set<UtConstraint>,
aliases: Set<UtConstraintVariable>
): UtModel {
val allAliases = aliases + variable
val refConstraints = atoms.filter { constraint ->
allAliases.any { it in constraint }
}.toSet()

val default = { buildObjectModel(variable, atoms, aliases) }
val elementData = atoms
.flatten { it is UtConstraintFieldAccess && it.instance == variable && it.fieldId.name == "elementData" }
.firstOrNull() as? UtConstraintFieldAccess ?: return default()
val storageArray = atoms
.flatten { it is UtConstraintFieldAccess && it.instance == elementData && it.fieldId.name == "storage" }
.firstOrNull() as? UtConstraintFieldAccess ?: return default()
val aliasArrays = aliases.map {
UtConstraintFieldAccess(UtConstraintFieldAccess(it, elementData.fieldId), storageArray.fieldId)
}.toSet()
val array = buildArrayModel(storageArray, atoms, aliasArrays) as UtArrayConstraintModel
val concreteLength = (array.length as UtPrimitiveConstraintModel).concrete as Int
val concreteIndices = array.elements.toList().associate { (index, value) ->
(index as UtPrimitiveConstraintModel).concrete as Int to ((index as UtModel) to value)
}
val completedElements = (0 until concreteLength).associate {
if (it in concreteIndices) concreteIndices[it]!!
else {
UtPrimitiveConstraintModel(
UtConstraintNumericConstant(it),
emptySet(),
it
) to UtNullModel(objectClassId)
}
}
return UtListConstraintModel(
variable,
array.length,
completedElements,
array.utConstraints + refConstraints
)
}

private val UtExpression.variable get() = accept(varBuilder)
private val UtConstraintVariable.expr get() = varBuilder[this]
private val UtConstraintVariable.addr get() = holder.concreteAddr(expr as UtAddrExpression)
Expand All @@ -283,4 +345,9 @@ class ConstraintResolver(
is UtArrayConstraintModel -> copy(utConstraints = utConstraints + constraints)
else -> this
}

private fun Set<UtConstraint>.flatten(predicate: (UtConstraintVariable) -> Boolean): Set<UtConstraintVariable> =
this.flatMap {
it.accept(UtConstraintVariableCollector(predicate))
}.toSet()
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class UtVarBuilder(
operator fun get(variable: UtConstraintVariable) = backMapping[variable]
?: throw IllegalArgumentException()

fun evalType(addr: UtAddrExpression) = holder.findTypeOrNull(addr)

override fun visit(expr: UtArraySelectExpression): UtConstraintVariable {
val res = when (val base = expr.arrayExpression.accept(this)) {
is UtConstraintParameter -> when (base.name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class Resolver(
is NullUnit -> UtNullModel(unit.classId)
is ReferenceToUnit -> resolve(synthesisUnitContext[unit.reference])
is ArrayUnit -> unitToModel.getOrPut(unit) { resolveArray(unit) }
is ListUnit -> unitToModel.getOrPut(unit) { resolveList(unit) }
}

private fun resolveMethodUnit(unit: MethodUnit): UtModel =
Expand Down Expand Up @@ -76,6 +77,37 @@ class Resolver(
return model
}

private fun resolveList(unit: ListUnit): UtModel {
val elements = unit.elements.associate {
resolve(synthesisUnitContext[it.first]) to resolve(synthesisUnitContext[it.second])
}

val instantiationChain = mutableListOf<UtStatementModel>()
val modificationChain = mutableListOf<UtStatementModel>()

val model = UtAssembleModel(
nextDefaultModelId++,
unit.classId,
nextModelName("refModel_${unit.classId.simpleName}"),
instantiationChain,
modificationChain
)

instantiationChain.add(
UtExecutableCallModel(model, unit.constructorId, listOf(), model)
)

for ((_, value) in elements) {
modificationChain.add(
UtExecutableCallModel(
model, unit.addId, listOf(value),
)
)
}

return model
}

private fun resolveArray(unit: ArrayUnit): UtModel {
val lengthModel = resolve(synthesisUnitContext[unit.length]) as UtPrimitiveModel
val elements = unit.elements.associate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class CompositeUnitExpander(
statementsStorage.items
.filter { (method, info) ->
val sameClass = method.classId == classId
val modifiesSomething = info.modifiedFields.any { it.declaringClass == classId }
val modifiesSomething = true//info.modifiedFields.any { it.declaringClass == classId }
sameClass && modifiesSomething
}
.keys
Expand Down
Loading