Skip to content

Commit cdce35f

Browse files
committed
add phases
1 parent 63191d6 commit cdce35f

File tree

9 files changed

+448
-171
lines changed

9 files changed

+448
-171
lines changed
Lines changed: 62 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +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
48-
import org.utbot.framework.concrete.constructors.ConstructOnlyUserClassesOrCachedObjectsStrategy
49-
import org.utbot.framework.concrete.constructors.MockValueConstructor
50-
import org.utbot.framework.concrete.constructors.UtModelConstructor
51-
import org.utbot.framework.concrete.mock.InstrumentationContext
5228

5329
/**
5430
* Consists of the data needed to execute the method concretely. Also includes method arguments stored in models.
@@ -146,107 +122,78 @@ object UtExecutionInstrumentation : Instrumentation<UtConcreteExecutionResult> {
146122
throw IllegalArgumentException("Argument parameters must be of type UtConcreteExecutionData, but was: ${parameters?.javaClass}")
147123
}
148124
val (stateBefore, instrumentations, timeout) = parameters // smart cast to UtConcreteExecutionData
149-
val parametersModels = listOfNotNull(stateBefore.thisInstance) + stateBefore.parameters
150125

151126
val methodId = clazz.singleExecutableId(methodSignature)
152127
val returnClassId = methodId.returnType
153-
traceHandler.resetTrace()
154-
155-
return MockValueConstructor(instrumentationContext).use { constructor ->
156-
val params = try {
157-
constructor.constructMethodParameters(parametersModels)
158-
} catch (e: Throwable) {
159-
if (e.cause is AccessControlException) {
160-
return@use UtConcreteExecutionResult(
161-
MissingState,
162-
UtSandboxFailure(e.cause!!),
163-
Coverage()
164-
)
165-
}
166128

167-
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())
168142
}
169-
val staticFields = constructor
170-
.constructStatics(
171-
stateBefore
172-
.statics
173-
.filterKeys { !it.isInaccessibleViaReflection }
174-
)
175-
.mapValues { (_, value) -> value.value }
176-
177-
val concreteExecutionResult = withStaticFields(staticFields) {
178-
val staticMethodsInstrumentation = instrumentations.filterIsInstance<UtStaticMethodInstrumentation>()
179-
constructor.mockStaticMethods(staticMethodsInstrumentation)
180-
val newInstanceInstrumentation = instrumentations.filterIsInstance<UtNewInstanceInstrumentation>()
181-
constructor.mockNewInstances(newInstanceInstrumentation)
182-
183-
traceHandler.resetTrace()
184-
val stopWatch = StopWatch()
185-
val context = UtContext(utContext.classLoader, stopWatch)
186-
val concreteResult = ThreadBasedExecutor.threadLocal.invokeWithTimeout(timeout, stopWatch) {
187-
withUtContext(context) {
188-
delegateInstrumentation.invoke(clazz, methodSignature, params.map { it.value })
189-
}
190-
}?.getOrThrow() as? Result<*> ?: Result.failure<Any?>(TimeoutException("Timeout $timeout elapsed"))
191-
val traceList = traceHandler.computeInstructionList()
192-
193-
val cache = constructor.objectToModelCache
194-
val utCompositeModelStrategy = ConstructOnlyUserClassesOrCachedObjectsStrategy(pathsToUserClasses, cache)
195-
val utModelConstructor = UtModelConstructor(cache, utCompositeModelStrategy)
196-
utModelConstructor.run {
197-
val concreteUtModelResult = concreteResult.fold({
198-
try {
199-
val model = construct(it, returnClassId)
200-
UtExecutionSuccess(model)
201-
} catch (e: Exception) {
202-
processExceptionDuringModelConstruction(e)
203-
}
204-
}) {
205-
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)
206167
}
207168

208-
val stateAfterParametersWithThis = params.map { construct(it.value, it.clazz.id) }
209-
val stateAfterStatics = (staticFields.keys/* + traceHandler.computePutStatics()*/)
210-
.associateWith { fieldId ->
211-
fieldId.jField.run {
212-
val computedValue = withAccessibility { get(null) }
213-
val knownModel = stateBefore.statics[fieldId]
214-
val knownValue = staticFields[fieldId]
215-
if (knownModel != null && knownValue != null && knownValue == computedValue) {
216-
knownModel
217-
} else {
218-
construct(computedValue, fieldId.type)
219-
}
220-
}
221-
}
169+
val executionResult = convertToExecutionResult(concreteResult, returnClassId)
170+
171+
val stateAfterParametersWithThis = constructParameters(params)
172+
val stateAfterStatics = constructStatics(statics.keys/* + traceHandler.computePutStatics()*/)
222173
val (stateAfterThis, stateAfterParameters) = if (stateBefore.thisInstance == null) {
223174
null to stateAfterParametersWithThis
224175
} else {
225176
stateAfterParametersWithThis.first() to stateAfterParametersWithThis.drop(1)
226177
}
227178
val stateAfter = EnvironmentModels(stateAfterThis, stateAfterParameters, stateAfterStatics)
228-
UtConcreteExecutionResult(
229-
stateAfter,
230-
concreteUtModelResult,
231-
traceList.toApiCoverage(
232-
traceHandler.processingStorage.getInstructionsCount(
233-
Type.getInternalName(clazz)
234-
)
235-
)
236-
)
179+
180+
executionResult to stateAfter
237181
}
238-
}
239182

240-
concreteExecutionResult
183+
UtConcreteExecutionResult(
184+
stateAfter,
185+
executionResult,
186+
coverage
187+
)
188+
} finally {
189+
// postprocessing
190+
postprocessingContext.start {
191+
resetStaticFields(savedStatics)
192+
}
193+
}
241194
}
242195
}
243196

244-
private fun processExceptionDuringModelConstruction(e: Exception): UtExecutionResult =
245-
when (e) {
246-
is UtStreamConsumingException -> UtStreamConsumingFailure(e)
247-
else -> throw e
248-
}
249-
250197
override fun getStaticField(fieldId: FieldId): Result<UtModel> =
251198
delegateInstrumentation.getStaticField(fieldId).map { value ->
252199
val cache = IdentityHashMap<Any, UtModel>()
@@ -258,30 +205,6 @@ object UtExecutionInstrumentation : Instrumentation<UtConcreteExecutionResult> {
258205
}
259206
}
260207

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

310233
return instrumenter.classByteCode
311234
}
312-
313-
private fun <T> withStaticFields(staticFields: Map<FieldId, Any?>, block: () -> T): T {
314-
val savedFields = mutableMapOf<FieldId, Any?>()
315-
try {
316-
staticFields.forEach { (fieldId, value) ->
317-
fieldId.jField.run {
318-
withAccessibility {
319-
savedFields[fieldId] = get(null)
320-
set(null, value)
321-
}
322-
}
323-
}
324-
return block()
325-
} finally {
326-
savedFields.forEach { (fieldId, value) ->
327-
fieldId.jField.run {
328-
withAccessibility {
329-
set(null, value)
330-
}
331-
}
332-
}
333-
}
334-
}
335235
}
336-
337-
/**
338-
* Transforms a list of internal [EtInstruction]s to a list of api [Instruction]s.
339-
*/
340-
private fun List<EtInstruction>.toApiCoverage(instructionsCount: Long? = null): Coverage =
341-
Coverage(
342-
map { Instruction(it.className, it.methodSignature, it.line, it.id) },
343-
instructionsCount
344-
)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.utbot.framework.concrete.phases
2+
3+
import org.utbot.common.StopWatch
4+
import org.utbot.common.ThreadBasedExecutor
5+
import org.utbot.framework.plugin.api.TimeoutException
6+
import org.utbot.framework.plugin.api.util.UtContext
7+
import org.utbot.framework.plugin.api.util.utContext
8+
import org.utbot.framework.plugin.api.util.withUtContext
9+
import org.utbot.instrumentation.instrumentation.Instrumentation
10+
11+
class InvocationPhaseError(cause: Throwable) : PhaseError(
12+
message = "Error during user's code invocation phase",
13+
cause
14+
)
15+
16+
class InvocationContext(
17+
private val delegateInstrumentation: Instrumentation<Result<*>>
18+
) : PhaseContext<InvocationPhaseError> {
19+
20+
override fun wrapError(error: Throwable): InvocationPhaseError =
21+
InvocationPhaseError(error)
22+
23+
fun invoke(
24+
clazz: Class<*>,
25+
methodSignature: String,
26+
params: List<Any?>,
27+
timeout: Long,
28+
): Result<*> {
29+
val stopWatch = StopWatch()
30+
val context = UtContext(utContext.classLoader, stopWatch)
31+
val concreteResult = ThreadBasedExecutor.threadLocal.invokeWithTimeout(timeout, stopWatch) {
32+
withUtContext(context) {
33+
delegateInstrumentation.invoke(clazz, methodSignature, params)
34+
}
35+
}?.getOrThrow() as? Result<*> ?: Result.failure<Any?>(TimeoutException("Timeout $timeout elapsed"))
36+
return concreteResult
37+
}
38+
39+
}

0 commit comments

Comments
 (0)