Skip to content

Commit 463a152

Browse files
authored
Get static field concretly (#904)
1 parent 4436830 commit 463a152

File tree

10 files changed

+225
-17
lines changed

10 files changed

+225
-17
lines changed

utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtExecutionInstrumentation.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,17 @@ object UtExecutionInstrumentation : Instrumentation<UtConcreteExecutionResult> {
234234
}
235235
}
236236

237+
override fun getStaticField(fieldId: FieldId): Result<UtModel> =
238+
delegateInstrumentation.getStaticField(fieldId).map { value ->
239+
val cache = IdentityHashMap<Any, UtModel>()
240+
val strategy = ConstructOnlyUserClassesOrCachedObjectsStrategy(
241+
pathsToUserClasses, cache
242+
)
243+
UtModelConstructor(cache, strategy).run {
244+
construct(value, fieldId.type)
245+
}
246+
}
247+
237248
private fun sortOutException(exception: Throwable): UtExecutionFailure {
238249
if (exception is TimeoutException) {
239250
return UtTimeoutException(exception)

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,32 @@ import com.jetbrains.rd.util.lifetime.Lifetime
55
import com.jetbrains.rd.util.lifetime.LifetimeDefinition
66
import com.jetbrains.rd.util.lifetime.isAlive
77
import com.jetbrains.rd.util.lifetime.throwIfNotAlive
8+
import java.io.Closeable
9+
import java.util.concurrent.atomic.AtomicLong
10+
import kotlin.concurrent.thread
11+
import kotlin.reflect.KCallable
12+
import kotlin.reflect.KFunction
13+
import kotlin.reflect.KProperty
14+
import kotlin.reflect.jvm.javaConstructor
15+
import kotlin.reflect.jvm.javaGetter
16+
import kotlin.reflect.jvm.javaMethod
17+
import kotlin.streams.toList
818
import kotlinx.coroutines.CancellationException
919
import kotlinx.coroutines.runBlocking
1020
import kotlinx.coroutines.sync.Mutex
1121
import kotlinx.coroutines.sync.withLock
1222
import mu.KotlinLogging
1323
import org.utbot.framework.plugin.api.ConcreteExecutionFailureException
24+
import org.utbot.framework.plugin.api.FieldId
1425
import org.utbot.framework.plugin.api.util.UtContext
1526
import org.utbot.framework.plugin.api.util.signature
1627
import org.utbot.instrumentation.instrumentation.Instrumentation
1728
import org.utbot.instrumentation.process.ChildProcessRunner
1829
import org.utbot.instrumentation.rd.UtInstrumentationProcess
19-
import org.utbot.rd.UtRdKLoggerFactory
30+
import org.utbot.instrumentation.rd.generated.ComputeStaticFieldParams
2031
import org.utbot.instrumentation.rd.generated.InvokeMethodCommandParams
2132
import org.utbot.instrumentation.util.ChildProcessError
22-
import java.io.Closeable
23-
import java.util.concurrent.atomic.AtomicLong
24-
import kotlin.concurrent.thread
25-
import kotlin.reflect.KCallable
26-
import kotlin.reflect.KFunction
27-
import kotlin.reflect.KProperty
28-
import kotlin.reflect.jvm.javaConstructor
29-
import kotlin.reflect.jvm.javaGetter
30-
import kotlin.reflect.jvm.javaMethod
31-
import kotlin.streams.toList
33+
import org.utbot.rd.UtRdKLoggerFactory
3234

3335
private val logger = KotlinLogging.logger {}
3436

@@ -298,4 +300,18 @@ fun ConcreteExecutor<*,*>.warmup() = runBlocking {
298300
withProcess {
299301
protocolModel.warmup.start(lifetime, Unit)
300302
}
301-
}
303+
}
304+
305+
/**
306+
* Extension function for the [ConcreteExecutor], which allows to collect static field value of [fieldId].
307+
*/
308+
fun <T> ConcreteExecutor<*, *>.computeStaticField(fieldId: FieldId): Result<T> = runBlocking {
309+
withProcess {
310+
val fieldIdSerialized = kryoHelper.writeObject(fieldId)
311+
val params = ComputeStaticFieldParams(fieldIdSerialized)
312+
313+
val result = protocolModel.computeStaticField.startSuspending(lifetime, params)
314+
315+
kryoHelper.readObject(result.result)
316+
}
317+
}

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/Instrumentation.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.utbot.instrumentation.instrumentation
22

33
import java.lang.instrument.ClassFileTransformer
4+
import org.utbot.framework.plugin.api.FieldId
45

56
/**
67
* Abstract class for the instrumentation.
@@ -24,6 +25,8 @@ interface Instrumentation<out TInvocationInstrumentation> : ClassFileTransformer
2425
parameters: Any? = null
2526
): TInvocationInstrumentation
2627

28+
fun getStaticField(fieldId: FieldId): Result<*>
29+
2730
/**
2831
* Will be called in the very beginning in the child process.
2932
*/

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeInstrumentation.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import java.lang.reflect.InvocationTargetException
77
import java.lang.reflect.Method
88
import java.lang.reflect.Modifier
99
import java.security.ProtectionDomain
10+
import org.utbot.common.withAccessibility
11+
import org.utbot.framework.plugin.api.FieldId
12+
import org.utbot.framework.plugin.api.util.jField
1013

1114
typealias ArgumentList = List<Any?>
1215

@@ -89,6 +92,19 @@ class InvokeInstrumentation : Instrumentation<Result<*>> {
8992
}
9093
}
9194

95+
/**
96+
* Get field by reflection and return raw value.
97+
*/
98+
override fun getStaticField(fieldId: FieldId): Result<Any?> =
99+
if (!fieldId.isStatic) {
100+
Result.failure(IllegalArgumentException("Field must be static!"))
101+
} else {
102+
val field = fieldId.jField
103+
val value = field.withAccessibility {
104+
field.get(null)
105+
}
106+
Result.success(value)
107+
}
92108

93109
/**
94110
* Does not change bytecode.

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import org.utbot.instrumentation.util.StaticEnvironment
66
import java.lang.reflect.Field
77
import java.lang.reflect.Modifier
88
import java.security.ProtectionDomain
9+
import org.utbot.framework.plugin.api.FieldId
910

1011
/**
1112
* This instrumentation allows supplying [StaticEnvironment] and saving static fields. This makes call pure.
@@ -43,6 +44,9 @@ class InvokeWithStaticsInstrumentation : Instrumentation<Result<*>> {
4344
return invokeResult
4445
}
4546

47+
override fun getStaticField(fieldId: FieldId): Result<*> =
48+
invokeInstrumentation.getStaticField(fieldId)
49+
4650
private fun setStaticFields(staticEnvironment: StaticEnvironment?) {
4751
staticEnvironment?.run {
4852
listOfFields.forEach { (fieldId, value) ->

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/coverage/CoverageInstrumentation.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import org.utbot.instrumentation.util.CastProbesArrayException
1313
import org.utbot.instrumentation.util.ChildProcessError
1414
import org.utbot.instrumentation.util.NoProbesArrayException
1515
import java.security.ProtectionDomain
16+
import org.utbot.framework.plugin.api.FieldId
17+
import org.utbot.framework.plugin.api.util.jField
1618

1719
data class CoverageInfo(
1820
val methodToInstrRange: Map<String, IntRange>,
@@ -47,6 +49,8 @@ object CoverageInstrumentation : Instrumentation<Result<*>> {
4749
}
4850
}
4951

52+
override fun getStaticField(fieldId: FieldId): Result<*> =
53+
invokeWithStatics.getStaticField(fieldId)
5054

5155
/**
5256
* Collects coverage from the given [clazz] via reflection.

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/et/ExecutionTraceInstrumentation.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import org.utbot.instrumentation.instrumentation.Instrumentation
55
import org.utbot.instrumentation.instrumentation.InvokeWithStaticsInstrumentation
66
import org.utbot.instrumentation.instrumentation.instrumenter.Instrumenter
77
import java.security.ProtectionDomain
8+
import org.utbot.framework.plugin.api.FieldId
89

910
/**
1011
* This instrumentation allows to get execution trace during each call.
@@ -33,6 +34,10 @@ class ExecutionTraceInstrumentation : Instrumentation<Trace> {
3334

3435
return trace
3536
}
37+
38+
override fun getStaticField(fieldId: FieldId): Result<*> =
39+
invokeWithStatics.getStaticField(fieldId)
40+
3641
/**
3742
* Transforms bytecode such way that it becomes possible to get an execution trace during a call.
3843
*

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/ChildProcess.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ import java.time.LocalDateTime
3838
import java.time.format.DateTimeFormatter
3939
import java.util.concurrent.TimeUnit
4040
import kotlin.system.measureTimeMillis
41+
import org.utbot.framework.plugin.api.FieldId
42+
import org.utbot.instrumentation.rd.generated.ComputeStaticFieldResult
4143

4244
/**
4345
* We use this ClassLoader to separate user's classes and our dependency classes.
@@ -199,7 +201,7 @@ private fun <T, R> RdCall<T, R>.measureExecutionForTermination(block: (T) -> R)
199201
}
200202
}
201203

202-
private suspend fun ProtocolModel.setup(kryoHelper: KryoHelper, onStop: () -> Unit) {
204+
private fun ProtocolModel.setup(kryoHelper: KryoHelper, onStop: () -> Unit) {
203205
warmup.measureExecutionForTermination {
204206
logDebug { "received warmup request" }
205207
val time = measureTimeMillis {
@@ -250,6 +252,11 @@ private suspend fun ProtocolModel.setup(kryoHelper: KryoHelper, onStop: () -> Un
250252
val result = (instrumentation as CoverageInstrumentation).collectCoverageInfo(anyClass)
251253
CollectCoverageResult(kryoHelper.writeObject(result))
252254
}
255+
computeStaticField.measureExecutionForTermination { params ->
256+
val fieldId = kryoHelper.readObject<FieldId>(params.fieldId)
257+
val result = instrumentation.getStaticField(fieldId)
258+
ComputeStaticFieldResult(kryoHelper.writeObject(result))
259+
}
253260
}
254261

255262
private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {

0 commit comments

Comments
 (0)