1
1
package org.utbot.framework.concrete
2
2
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
7
6
import org.utbot.framework.UtSettings
8
7
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
9
13
import org.utbot.framework.plugin.api.Coverage
10
14
import org.utbot.framework.plugin.api.EnvironmentModels
11
15
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
15
16
import org.utbot.framework.plugin.api.UtAssembleModel
16
- import org.utbot.framework.plugin.api.UtExecutionFailure
17
17
import org.utbot.framework.plugin.api.UtExecutionResult
18
18
import org.utbot.framework.plugin.api.UtExecutionSuccess
19
- import org.utbot.framework.plugin.api.UtExplicitlyThrownException
20
- import org.utbot.framework.plugin.api.UtImplicitlyThrownException
21
19
import org.utbot.framework.plugin.api.UtInstrumentation
22
20
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
32
21
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
36
22
import org.utbot.instrumentation.instrumentation.ArgumentList
37
23
import org.utbot.instrumentation.instrumentation.Instrumentation
38
24
import org.utbot.instrumentation.instrumentation.InvokeInstrumentation
39
- import org.utbot.instrumentation.instrumentation.et.EtInstruction
40
- import org.utbot.instrumentation.instrumentation.et.ExplicitThrowInstruction
41
25
import org.utbot.instrumentation.instrumentation.et.TraceHandler
42
26
import org.utbot.instrumentation.instrumentation.instrumenter.Instrumenter
43
27
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
28
49
29
/* *
50
30
* 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> {
142
122
throw IllegalArgumentException (" Argument parameters must be of type UtConcreteExecutionData, but was: ${parameters?.javaClass} " )
143
123
}
144
124
val (stateBefore, instrumentations, timeout) = parameters // smart cast to UtConcreteExecutionData
145
- val parametersModels = listOfNotNull(stateBefore.thisInstance) + stateBefore.parameters
146
125
147
126
val methodId = clazz.singleExecutableId(methodSignature)
148
127
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
- }
162
128
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())
164
142
}
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)
202
167
}
203
168
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()*/ )
218
173
val (stateAfterThis, stateAfterParameters) = if (stateBefore.thisInstance == null ) {
219
174
null to stateAfterParametersWithThis
220
175
} else {
221
176
stateAfterParametersWithThis.first() to stateAfterParametersWithThis.drop(1 )
222
177
}
223
178
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
233
181
}
234
- }
235
182
236
- concreteExecutionResult
183
+ UtConcreteExecutionResult (
184
+ stateAfter,
185
+ executionResult,
186
+ coverage
187
+ )
188
+ } finally {
189
+ // postprocessing
190
+ postprocessingContext.start {
191
+ resetStaticFields(savedStatics)
192
+ }
193
+ }
237
194
}
238
195
}
239
196
240
- private fun processExceptionDuringModelConstruction (e : Exception ): UtExecutionResult =
241
- when (e) {
242
- is UtStreamConsumingException -> UtStreamConsumingFailure (e)
243
- else -> throw e
244
- }
245
-
246
197
override fun getStaticField (fieldId : FieldId ): Result <UtModel > =
247
198
delegateInstrumentation.getStaticField(fieldId).map { value ->
248
199
val cache = IdentityHashMap <Any , UtModel >()
@@ -254,30 +205,6 @@ object UtExecutionInstrumentation : Instrumentation<UtConcreteExecutionResult> {
254
205
}
255
206
}
256
207
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
-
281
208
override fun transform (
282
209
loader : ClassLoader ? ,
283
210
className : String ,
@@ -305,36 +232,4 @@ object UtExecutionInstrumentation : Instrumentation<UtConcreteExecutionResult> {
305
232
306
233
return instrumenter.classByteCode
307
234
}
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
- }
331
235
}
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
- )
0 commit comments