Skip to content

Commit b5f40fc

Browse files
authored
Concrete executor phases refactoring (#1446)
1 parent 66c3443 commit b5f40fc

24 files changed

+509
-214
lines changed

utbot-framework-test/src/test/kotlin/org/utbot/framework/concrete/constructors/BaseConstructorTest.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.utbot.framework.concrete.constructors
22

33
import org.utbot.engine.ValueConstructor
4-
import org.utbot.framework.concrete.UtModelConstructor
54
import org.utbot.framework.plugin.api.UtAssembleModel
65
import org.utbot.framework.plugin.api.util.UtContext
76
import org.utbot.framework.plugin.api.util.id
Lines changed: 62 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,30 @@
11
package org.utbot.framework.concrete
22

3-
import org.objectweb.asm.Type
4-
import org.utbot.common.StopWatch
5-
import org.utbot.common.ThreadBasedExecutor
6-
import org.utbot.common.withAccessibility
3+
import java.security.ProtectionDomain
4+
import java.util.IdentityHashMap
5+
import kotlin.reflect.jvm.javaMethod
76
import org.utbot.framework.UtSettings
87
import org.utbot.framework.assemble.AssembleModelGenerator
8+
import org.utbot.framework.concrete.constructors.ConstructOnlyUserClassesOrCachedObjectsStrategy
9+
import org.utbot.framework.concrete.constructors.UtModelConstructor
10+
import org.utbot.framework.concrete.mock.InstrumentationContext
11+
import org.utbot.framework.concrete.phases.PhasesController
12+
import org.utbot.framework.concrete.phases.start
913
import org.utbot.framework.plugin.api.Coverage
1014
import org.utbot.framework.plugin.api.EnvironmentModels
1115
import org.utbot.framework.plugin.api.FieldId
12-
import org.utbot.framework.plugin.api.Instruction
13-
import org.utbot.framework.plugin.api.MissingState
14-
import org.utbot.framework.plugin.api.TimeoutException
1516
import org.utbot.framework.plugin.api.UtAssembleModel
16-
import org.utbot.framework.plugin.api.UtExecutionFailure
1717
import org.utbot.framework.plugin.api.UtExecutionResult
1818
import org.utbot.framework.plugin.api.UtExecutionSuccess
19-
import org.utbot.framework.plugin.api.UtExplicitlyThrownException
20-
import org.utbot.framework.plugin.api.UtImplicitlyThrownException
2119
import org.utbot.framework.plugin.api.UtInstrumentation
2220
import org.utbot.framework.plugin.api.UtModel
23-
import org.utbot.framework.plugin.api.UtNewInstanceInstrumentation
24-
import org.utbot.framework.plugin.api.UtSandboxFailure
25-
import org.utbot.framework.plugin.api.UtStaticMethodInstrumentation
26-
import org.utbot.framework.plugin.api.visible.UtStreamConsumingException
27-
import org.utbot.framework.plugin.api.UtStreamConsumingFailure
28-
import org.utbot.framework.plugin.api.UtTimeoutException
29-
import org.utbot.framework.plugin.api.util.UtContext
30-
import org.utbot.framework.plugin.api.util.id
31-
import org.utbot.framework.plugin.api.util.jField
3221
import org.utbot.framework.plugin.api.util.singleExecutableId
33-
import org.utbot.framework.plugin.api.util.utContext
34-
import org.utbot.framework.plugin.api.util.withUtContext
35-
import org.utbot.framework.util.isInaccessibleViaReflection
3622
import org.utbot.instrumentation.instrumentation.ArgumentList
3723
import org.utbot.instrumentation.instrumentation.Instrumentation
3824
import org.utbot.instrumentation.instrumentation.InvokeInstrumentation
39-
import org.utbot.instrumentation.instrumentation.et.EtInstruction
40-
import org.utbot.instrumentation.instrumentation.et.ExplicitThrowInstruction
4125
import org.utbot.instrumentation.instrumentation.et.TraceHandler
4226
import org.utbot.instrumentation.instrumentation.instrumenter.Instrumenter
4327
import org.utbot.instrumentation.instrumentation.mock.MockClassVisitor
44-
import java.security.AccessControlException
45-
import java.security.ProtectionDomain
46-
import java.util.IdentityHashMap
47-
import kotlin.reflect.jvm.javaMethod
4828

4929
/**
5030
* Consists of the data needed to execute the method concretely. Also includes method arguments stored in models.
@@ -142,107 +122,78 @@ object UtExecutionInstrumentation : Instrumentation<UtConcreteExecutionResult> {
142122
throw IllegalArgumentException("Argument parameters must be of type UtConcreteExecutionData, but was: ${parameters?.javaClass}")
143123
}
144124
val (stateBefore, instrumentations, timeout) = parameters // smart cast to UtConcreteExecutionData
145-
val parametersModels = listOfNotNull(stateBefore.thisInstance) + stateBefore.parameters
146125

147126
val methodId = clazz.singleExecutableId(methodSignature)
148127
val returnClassId = methodId.returnType
149-
traceHandler.resetTrace()
150-
151-
return MockValueConstructor(instrumentationContext).use { constructor ->
152-
val params = try {
153-
constructor.constructMethodParameters(parametersModels)
154-
} catch (e: Throwable) {
155-
if (e.cause is AccessControlException) {
156-
return@use UtConcreteExecutionResult(
157-
MissingState,
158-
UtSandboxFailure(e.cause!!),
159-
Coverage()
160-
)
161-
}
162128

163-
throw e
129+
return PhasesController(
130+
instrumentationContext,
131+
traceHandler,
132+
delegateInstrumentation
133+
).computeConcreteExecutionResult {
134+
// construction
135+
val (params, statics, cache) = valueConstructionContext.start {
136+
val params = constructParameters(stateBefore)
137+
val statics = constructStatics(stateBefore)
138+
139+
mock(instrumentations)
140+
141+
Triple(params, statics, getCache())
164142
}
165-
val staticFields = constructor
166-
.constructStatics(
167-
stateBefore
168-
.statics
169-
.filterKeys { !it.isInaccessibleViaReflection }
170-
)
171-
.mapValues { (_, value) -> value.value }
172-
173-
val concreteExecutionResult = withStaticFields(staticFields) {
174-
val staticMethodsInstrumentation = instrumentations.filterIsInstance<UtStaticMethodInstrumentation>()
175-
constructor.mockStaticMethods(staticMethodsInstrumentation)
176-
val newInstanceInstrumentation = instrumentations.filterIsInstance<UtNewInstanceInstrumentation>()
177-
constructor.mockNewInstances(newInstanceInstrumentation)
178-
179-
traceHandler.resetTrace()
180-
val stopWatch = StopWatch()
181-
val context = UtContext(utContext.classLoader, stopWatch)
182-
val concreteResult = ThreadBasedExecutor.threadLocal.invokeWithTimeout(timeout, stopWatch) {
183-
withUtContext(context) {
184-
delegateInstrumentation.invoke(clazz, methodSignature, params.map { it.value })
185-
}
186-
}?.getOrThrow() as? Result<*> ?: Result.failure<Any?>(TimeoutException("Timeout $timeout elapsed"))
187-
val traceList = traceHandler.computeInstructionList()
188-
189-
val cache = constructor.objectToModelCache
190-
val utCompositeModelStrategy = ConstructOnlyUserClassesOrCachedObjectsStrategy(pathsToUserClasses, cache)
191-
val utModelConstructor = UtModelConstructor(cache, utCompositeModelStrategy)
192-
utModelConstructor.run {
193-
val concreteUtModelResult = concreteResult.fold({
194-
try {
195-
val model = construct(it, returnClassId)
196-
UtExecutionSuccess(model)
197-
} catch (e: Exception) {
198-
processExceptionDuringModelConstruction(e)
199-
}
200-
}) {
201-
sortOutException(it)
143+
144+
// preparation
145+
val savedStatics = preparationContext.start {
146+
val savedStatics = setStaticFields(statics)
147+
resetTrace()
148+
savedStatics
149+
}
150+
151+
try {
152+
// invocation
153+
val concreteResult = invocationContext.start {
154+
invoke(clazz, methodSignature, params.map { it.value }, timeout)
155+
}
156+
157+
// statistics collection
158+
val coverage = statisticsCollectionContext.start {
159+
getCoverage(clazz)
160+
}
161+
162+
// model construction
163+
val (executionResult, stateAfter) = modelConstructionContext.start {
164+
configureConstructor {
165+
this.cache = cache
166+
strategy = ConstructOnlyUserClassesOrCachedObjectsStrategy(pathsToUserClasses, cache)
202167
}
203168

204-
val stateAfterParametersWithThis = params.map { construct(it.value, it.clazz.id) }
205-
val stateAfterStatics = (staticFields.keys/* + traceHandler.computePutStatics()*/)
206-
.associateWith { fieldId ->
207-
fieldId.jField.run {
208-
val computedValue = withAccessibility { get(null) }
209-
val knownModel = stateBefore.statics[fieldId]
210-
val knownValue = staticFields[fieldId]
211-
if (knownModel != null && knownValue != null && knownValue == computedValue) {
212-
knownModel
213-
} else {
214-
construct(computedValue, fieldId.type)
215-
}
216-
}
217-
}
169+
val executionResult = convertToExecutionResult(concreteResult, returnClassId)
170+
171+
val stateAfterParametersWithThis = constructParameters(params)
172+
val stateAfterStatics = constructStatics(statics.keys/* + traceHandler.computePutStatics()*/)
218173
val (stateAfterThis, stateAfterParameters) = if (stateBefore.thisInstance == null) {
219174
null to stateAfterParametersWithThis
220175
} else {
221176
stateAfterParametersWithThis.first() to stateAfterParametersWithThis.drop(1)
222177
}
223178
val stateAfter = EnvironmentModels(stateAfterThis, stateAfterParameters, stateAfterStatics)
224-
UtConcreteExecutionResult(
225-
stateAfter,
226-
concreteUtModelResult,
227-
traceList.toApiCoverage(
228-
traceHandler.processingStorage.getInstructionsCount(
229-
Type.getInternalName(clazz)
230-
)
231-
)
232-
)
179+
180+
executionResult to stateAfter
233181
}
234-
}
235182

236-
concreteExecutionResult
183+
UtConcreteExecutionResult(
184+
stateAfter,
185+
executionResult,
186+
coverage
187+
)
188+
} finally {
189+
// postprocessing
190+
postprocessingContext.start {
191+
resetStaticFields(savedStatics)
192+
}
193+
}
237194
}
238195
}
239196

240-
private fun processExceptionDuringModelConstruction(e: Exception): UtExecutionResult =
241-
when (e) {
242-
is UtStreamConsumingException -> UtStreamConsumingFailure(e)
243-
else -> throw e
244-
}
245-
246197
override fun getStaticField(fieldId: FieldId): Result<UtModel> =
247198
delegateInstrumentation.getStaticField(fieldId).map { value ->
248199
val cache = IdentityHashMap<Any, UtModel>()
@@ -254,30 +205,6 @@ object UtExecutionInstrumentation : Instrumentation<UtConcreteExecutionResult> {
254205
}
255206
}
256207

257-
private fun sortOutException(exception: Throwable): UtExecutionFailure {
258-
if (exception is TimeoutException) {
259-
return UtTimeoutException(exception)
260-
}
261-
if (exception is AccessControlException ||
262-
exception is ExceptionInInitializerError && exception.exception is AccessControlException) {
263-
return UtSandboxFailure(exception)
264-
}
265-
// there also can be other cases, when we need to wrap internal exception... I suggest adding them on demand
266-
267-
val instrs = traceHandler.computeInstructionList()
268-
val isNested = if (instrs.isEmpty()) {
269-
false
270-
} else {
271-
instrs.first().callId != instrs.last().callId
272-
}
273-
return if (instrs.isNotEmpty() && instrs.last().instructionData is ExplicitThrowInstruction) {
274-
UtExplicitlyThrownException(exception, isNested)
275-
} else {
276-
UtImplicitlyThrownException(exception, isNested)
277-
}
278-
279-
}
280-
281208
override fun transform(
282209
loader: ClassLoader?,
283210
className: String,
@@ -305,36 +232,4 @@ object UtExecutionInstrumentation : Instrumentation<UtConcreteExecutionResult> {
305232

306233
return instrumenter.classByteCode
307234
}
308-
309-
private fun <T> withStaticFields(staticFields: Map<FieldId, Any?>, block: () -> T): T {
310-
val savedFields = mutableMapOf<FieldId, Any?>()
311-
try {
312-
staticFields.forEach { (fieldId, value) ->
313-
fieldId.jField.run {
314-
withAccessibility {
315-
savedFields[fieldId] = get(null)
316-
set(null, value)
317-
}
318-
}
319-
}
320-
return block()
321-
} finally {
322-
savedFields.forEach { (fieldId, value) ->
323-
fieldId.jField.run {
324-
withAccessibility {
325-
set(null, value)
326-
}
327-
}
328-
}
329-
}
330-
}
331235
}
332-
333-
/**
334-
* Transforms a list of internal [EtInstruction]s to a list of api [Instruction]s.
335-
*/
336-
private fun List<EtInstruction>.toApiCoverage(instructionsCount: Long? = null): Coverage =
337-
Coverage(
338-
map { Instruction(it.className, it.methodSignature, it.line, it.id) },
339-
instructionsCount
340-
)

utbot-framework/src/main/kotlin/org/utbot/framework/concrete/IterableConstructors.kt renamed to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/IterableConstructors.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.utbot.framework.concrete
1+
package org.utbot.framework.concrete.constructors
22

33
import org.utbot.framework.plugin.api.ClassId
44
import org.utbot.framework.plugin.api.ConstructorId

utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt renamed to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/MockValueConstructor.kt

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
1-
package org.utbot.framework.concrete
1+
package org.utbot.framework.concrete.constructors
22

3+
import java.io.Closeable
4+
import java.lang.reflect.Modifier
5+
import java.util.IdentityHashMap
6+
import kotlin.reflect.KClass
7+
import org.mockito.Mockito
8+
import org.mockito.stubbing.Answer
9+
import org.objectweb.asm.Type
10+
import org.utbot.common.Reflection
311
import org.utbot.common.invokeCatching
12+
import org.utbot.engine.util.lambda.CapturedArgument
13+
import org.utbot.engine.util.lambda.constructLambda
14+
import org.utbot.engine.util.lambda.constructStaticLambda
15+
import org.utbot.framework.concrete.mock.InstanceMockController
16+
import org.utbot.framework.concrete.mock.InstrumentationContext
17+
import org.utbot.framework.concrete.mock.MethodMockController
18+
import org.utbot.framework.concrete.mock.MockController
419
import org.utbot.framework.plugin.api.ClassId
520
import org.utbot.framework.plugin.api.ConstructorId
621
import org.utbot.framework.plugin.api.ExecutableId
@@ -20,6 +35,7 @@ import org.utbot.framework.plugin.api.UtConcreteValue
2035
import org.utbot.framework.plugin.api.UtDirectSetFieldModel
2136
import org.utbot.framework.plugin.api.UtEnumConstantModel
2237
import org.utbot.framework.plugin.api.UtExecutableCallModel
38+
import org.utbot.framework.plugin.api.UtLambdaModel
2339
import org.utbot.framework.plugin.api.UtMockValue
2440
import org.utbot.framework.plugin.api.UtModel
2541
import org.utbot.framework.plugin.api.UtNewInstanceInstrumentation
@@ -31,25 +47,12 @@ import org.utbot.framework.plugin.api.UtVoidModel
3147
import org.utbot.framework.plugin.api.isMockModel
3248
import org.utbot.framework.plugin.api.util.constructor
3349
import org.utbot.framework.plugin.api.util.executableId
34-
import org.utbot.framework.plugin.api.util.jField
50+
import org.utbot.framework.plugin.api.util.isStatic
3551
import org.utbot.framework.plugin.api.util.jClass
52+
import org.utbot.framework.plugin.api.util.jField
3653
import org.utbot.framework.plugin.api.util.method
3754
import org.utbot.framework.plugin.api.util.utContext
3855
import org.utbot.framework.util.anyInstance
39-
import java.io.Closeable
40-
import java.lang.reflect.Field
41-
import java.lang.reflect.Modifier
42-
import java.util.IdentityHashMap
43-
import kotlin.reflect.KClass
44-
import org.mockito.Mockito
45-
import org.mockito.stubbing.Answer
46-
import org.objectweb.asm.Type
47-
import org.utbot.common.Reflection
48-
import org.utbot.engine.util.lambda.CapturedArgument
49-
import org.utbot.engine.util.lambda.constructLambda
50-
import org.utbot.engine.util.lambda.constructStaticLambda
51-
import org.utbot.framework.plugin.api.UtLambdaModel
52-
import org.utbot.framework.plugin.api.util.isStatic
5356
import org.utbot.instrumentation.process.runSandbox
5457

5558
/**

utbot-framework/src/main/kotlin/org/utbot/framework/concrete/OptionalConstructors.kt renamed to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/OptionalConstructors.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
package org.utbot.framework.concrete
1+
package org.utbot.framework.concrete.constructors
22

3+
import java.util.Optional
4+
import java.util.OptionalDouble
5+
import java.util.OptionalInt
6+
import java.util.OptionalLong
7+
import kotlin.reflect.KFunction1
38
import org.utbot.framework.plugin.api.ClassId
49
import org.utbot.framework.plugin.api.MethodId
510
import org.utbot.framework.plugin.api.UtAssembleModel
@@ -10,11 +15,6 @@ import org.utbot.framework.plugin.api.util.intClassId
1015
import org.utbot.framework.plugin.api.util.jClass
1116
import org.utbot.framework.plugin.api.util.longClassId
1217
import org.utbot.framework.plugin.api.util.objectClassId
13-
import java.util.Optional
14-
import java.util.OptionalDouble
15-
import java.util.OptionalInt
16-
import java.util.OptionalLong
17-
import kotlin.reflect.KFunction1
1818

1919

2020
internal sealed class OptionalConstructorBase : UtAssembleModelConstructorBase() {

utbot-framework/src/main/kotlin/org/utbot/framework/concrete/PrimitiveWrapperConstructor.kt renamed to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/PrimitiveWrapperConstructor.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.utbot.framework.concrete
1+
package org.utbot.framework.concrete.constructors
22

33
import org.utbot.framework.plugin.api.ClassId
44
import org.utbot.framework.plugin.api.UtAssembleModel

utbot-framework/src/main/kotlin/org/utbot/framework/concrete/StreamConstructors.kt renamed to utbot-framework/src/main/kotlin/org/utbot/framework/concrete/constructors/StreamConstructors.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.utbot.framework.concrete
1+
package org.utbot.framework.concrete.constructors
22

33
import org.utbot.framework.plugin.api.ClassId
44
import org.utbot.framework.plugin.api.MethodId

0 commit comments

Comments
 (0)