Skip to content

Commit 11f4d12

Browse files
committed
Composition refactoring and array copying implementation
- RegionId made generic - No instantiator constructors - Composer is less than 70 lines now - No unclear heap interfaces extensions - Memcpy is entirely implemented
1 parent a4cf160 commit 11f4d12

11 files changed

Lines changed: 536 additions & 424 deletions

File tree

Lines changed: 19 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
package org.usvm
22

3-
import org.ksmt.expr.KExpr
4-
import org.ksmt.utils.cast
5-
63
@Suppress("MemberVisibilityCanBePrivate")
74
open class UComposer<Field, Type>(
85
ctx: UContext,
@@ -35,193 +32,33 @@ open class UComposer<Field, Type>(
3532
typeEvaluator.evalIs(composedAddress, type)
3633
}
3734

38-
override fun transform(expr: UArrayLength<Type>): USizeExpr = with(expr) {
39-
val composedAddress = compose(address)
40-
41-
val mappedRegion = region.map(
42-
inputArrayLengthKeyMapper,
43-
this@UComposer,
44-
inputArrayLengthInstantiatorConstructor
45-
)
46-
47-
mappedRegion.read(composedAddress)
48-
}
49-
50-
override fun <Sort : USort> transform(
51-
expr: UInputArrayReading<Type, Sort>
35+
fun <RegionId: URegionId<Key>, Key, Sort : USort> transformHR(
36+
expr: UHeapReading<RegionId, Key, Sort>,
37+
key: Key
5238
): UExpr<Sort> = with(expr) {
53-
val composedAddress = compose(address)
54-
val composedIndex = compose(index)
55-
56-
val instantiatorConstructor = { mappedUpdates: UMemoryUpdates<USymbolicArrayIndex, Sort> ->
57-
{ key: USymbolicArrayIndex, memoryRegion: UInputArrayMemoryRegion<Type, Sort> ->
58-
val arrayType = memoryRegion.inputArrayType
59-
val elementSort = memoryRegion.sort
60-
61-
heapEvaluator.applyUpdatesAndReadValue(
62-
mappedUpdates,
63-
{ mutableHeap, pinpointUpdate ->
64-
mutableHeap.writeArrayIndex(
65-
pinpointUpdate.key.first,
66-
pinpointUpdate.key.second,
67-
arrayType,
68-
elementSort,
69-
pinpointUpdate.value
70-
)
71-
},
72-
{ mutableHeap, rangeUpdate ->
73-
mutableHeap.memcpy(rangeUpdate.fromKey, rangeUpdate.toKey, rangeUpdate.region)
74-
},
75-
readingOperation = { it.readArrayIndex(key.first, key.second, arrayType, elementSort).cast() }
76-
)
77-
}
39+
val instantiator = { key: Key, memoryRegion: UMemoryRegion<RegionId, Key, Sort> ->
40+
// Create a copy of this heap to avoid its modification
41+
val heapToApplyUpdates = heapEvaluator.toMutableHeap()
42+
memoryRegion.applyTo(heapToApplyUpdates)
43+
region.regionId.read(key, sort, heapToApplyUpdates)
7844
}
7945

80-
val mappedRegion = region.map(inputArrayKeyMapper, this@UComposer, instantiatorConstructor)
81-
82-
mappedRegion.read(composedAddress to composedIndex)
46+
val mappedRegion = region.map(this@UComposer, instantiator)
47+
val mappedKey = region.regionId.keyMapper(this@UComposer)(key)
48+
mappedRegion.read(mappedKey)
8349
}
8450

85-
override fun <Sort : USort> transform(
86-
expr: UAllocatedArrayReading<Type, Sort>
87-
): UExpr<Sort> = with(expr) {
88-
val composedIndex = compose(index)
89-
val heapRef = uctx.mkConcreteHeapRef(region.allocatedAddress)
90-
91-
val allocatedArrayInstantiatorConstructor = { mappedUpdates: UMemoryUpdates<USizeExpr, Sort> ->
92-
{ key: USizeExpr, memoryRegion: UAllocatedArrayMemoryRegion<Type, Sort> ->
93-
val arrayType = memoryRegion.allocatedArrayType
94-
val elementSort = memoryRegion.sort
51+
override fun transform(expr: UArrayLength<Type>): USizeExpr =
52+
transformHR(expr, expr.address)
9553

96-
heapEvaluator.applyUpdatesAndReadValue(
97-
mappedUpdates,
98-
{ mutableHeap, pinpointUpdate ->
99-
mutableHeap.writeArrayIndex(
100-
heapRef,
101-
pinpointUpdate.key,
102-
arrayType,
103-
elementSort,
104-
pinpointUpdate.value
105-
)
106-
},
107-
{ mutableHeap, rangedUpdate ->
108-
mutableHeap.memcpy(rangedUpdate.fromKey, rangedUpdate.toKey, rangedUpdate.region)
109-
},
110-
readingOperation = { it.readArrayIndex(heapRef, key, arrayType, elementSort).cast() }
111-
)
112-
}
113-
}
54+
override fun <Sort : USort> transform(expr: UInputArrayReading<Type, Sort>): UExpr<Sort> =
55+
transformHR(expr, expr.address to expr.index)
11456

115-
val mappedRegion = region.map(
116-
allocatedArrayReadingKeyMapper,
117-
this@UComposer,
118-
allocatedArrayInstantiatorConstructor
119-
)
120-
121-
mappedRegion.read(composedIndex)
122-
}
57+
override fun <Sort : USort> transform(expr: UAllocatedArrayReading<Type, Sort>): UExpr<Sort> =
58+
transformHR(expr, expr.index)
12359

12460
override fun transform(expr: UConcreteHeapRef): UExpr<UAddressSort> = expr
12561

126-
override fun <Sort : USort> transform(expr: UFieldReading<Field, Sort>): UExpr<Sort> = with(expr) {
127-
val composedAddress = compose(address)
128-
129-
val instantiatorConstructor = { mappedUpdates: UMemoryUpdates<UHeapRef, Sort> ->
130-
{ key: UHeapRef, memoryRegion: UInputFieldMemoryRegion<Field, Sort> ->
131-
val field = memoryRegion.field
132-
133-
heapEvaluator.applyUpdatesAndReadValue(
134-
mappedUpdates,
135-
{ mutableHeap, pinpointUpdate ->
136-
mutableHeap.writeField(pinpointUpdate.key, field, sort, pinpointUpdate.value)
137-
},
138-
{ mutableHeap, rangedUpdate ->
139-
mutableHeap.memcpy(rangedUpdate.fromKey, rangedUpdate.toKey, rangedUpdate.region)
140-
},
141-
readingOperation = { it.readField(key, field, sort).cast() }
142-
)
143-
}
144-
}
145-
146-
val mappedRegion = region.map(fieldReadingKeyMapper, this@UComposer, instantiatorConstructor)
147-
148-
mappedRegion.read(composedAddress)
149-
}
150-
151-
// Extracted into a field to improve performance since it doesn't depend on input arguments
152-
private val inputArrayLengthInstantiatorConstructor: (UMemoryUpdates<UHeapRef, USizeSort>) -> UInstantiator<UInputArrayLengthId<Type>, UHeapRef, USizeSort> =
153-
{ mappedUpdates: UMemoryUpdates<UHeapRef, USizeSort> ->
154-
{ key: UHeapRef, memoryRegion: UInputArrayLengthMemoryRegion<Type> ->
155-
val arrayType = memoryRegion.inputLengthArrayType
156-
157-
heapEvaluator.applyUpdatesAndReadValue(
158-
mappedUpdates,
159-
{ mutableHeap, pinpointUpdate ->
160-
mutableHeap.writeArrayLength(
161-
pinpointUpdate.key,
162-
pinpointUpdate.value,
163-
arrayType
164-
)
165-
},
166-
{ _, _ -> error("URangeUpdateNode is unsupported for UArrayLength regions") },
167-
readingOperation = { it.readArrayLength(key, arrayType) }
168-
)
169-
}
170-
}
171-
172-
private val allocatedArrayReadingKeyMapper: (USizeExpr) -> KExpr<USizeSort> = { key: USizeExpr ->
173-
val composedKey = compose(key)
174-
// It is important to return the exact same key if there were no changes during composition
175-
if (composedKey === key) key else composedKey
176-
}
177-
178-
private val inputArrayLengthKeyMapper: (UHeapRef) -> UHeapRef = { key ->
179-
val composedKey = compose(key)
180-
// It is important to return the exact same key if there were no changes during composition
181-
if (composedKey === key) key else composedKey
182-
}
183-
184-
private val inputArrayKeyMapper: (USymbolicArrayIndex) -> USymbolicArrayIndex = { key ->
185-
val (heapRef, sizeExpr) = key
186-
val composedHeapRef = compose(heapRef)
187-
val composedSizeExpr = compose(sizeExpr)
188-
189-
// It is important to return the exact same key if there were no changes during composition
190-
if (composedHeapRef === heapRef && composedSizeExpr === sizeExpr) {
191-
key
192-
} else {
193-
composedHeapRef to composedSizeExpr
194-
}
195-
}
196-
197-
private val fieldReadingKeyMapper: (UHeapRef) -> KExpr<UAddressSort> = { key: UHeapRef ->
198-
val composedHeapRef = compose(key)
199-
// It is important to return the exact same key if there were no changes during composition
200-
if (composedHeapRef === key) key else composedHeapRef
201-
}
202-
203-
/**
204-
* Applies a sequence of [updates] to [this] and returns a result
205-
* of the [readingOperation] from the modified heap.
206-
*/
207-
private inline fun <Ref, Value, SizeT, Key, Sort : USort, R : UExpr<Sort>> UReadOnlyHeap<Ref, Value, SizeT, Field, Type>.applyUpdatesAndReadValue(
208-
updates: UMemoryUpdates<Key, Sort>,
209-
pinpointUpdateOperation: (UHeap<Ref, Value, SizeT, Field, Type>, UPinpointUpdateNode<Key, Sort>) -> Unit,
210-
rangeUpdateOperation: (UHeap<Ref, Value, SizeT, Field, Type>, URangedUpdateNode<Key, Sort>) -> Unit,
211-
readingOperation: (UHeap<Ref, Value, SizeT, Field, Type>) -> R
212-
): R {
213-
// Create a copy of this heap to avoid its modification
214-
val heapToApplyUpdates = toMutableHeap()
215-
216-
// Apply each update on the copy
217-
updates.forEach {
218-
when (it) {
219-
is UPinpointUpdateNode<Key, Sort> -> pinpointUpdateOperation(heapToApplyUpdates, it)
220-
is URangedUpdateNode<Key, Sort> -> rangeUpdateOperation(heapToApplyUpdates, it)
221-
}
222-
}
223-
224-
// Return a result of a reading from the modified heap
225-
return readingOperation(heapToApplyUpdates)
226-
}
62+
override fun <Sort : USort> transform(expr: UFieldReading<Field, Sort>): UExpr<Sort> =
63+
transformHR(expr, expr.address)
22764
}

usvm-core/src/main/kotlin/org/usvm/Expressions.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ class UArrayIndexRef<ArrayType>(
8585
abstract class USymbol<Sort : USort>(ctx: UContext) : UExpr<Sort>(ctx) {
8686
}
8787

88-
@Suppress("UNUSED_PARAMETER")
8988
class URegisterReading<Sort : USort> internal constructor(
9089
ctx: UContext,
9190
val idx: Int,
@@ -105,7 +104,7 @@ class URegisterReading<Sort : USort> internal constructor(
105104
override fun internHashCode(): Int = hash(idx, sort)
106105
}
107106

108-
abstract class UHeapReading<RegionId : URegionId, Key, Sort : USort>(
107+
abstract class UHeapReading<RegionId : URegionId<Key>, Key, Sort : USort>(
109108
ctx: UContext,
110109
val region: UMemoryRegion<RegionId, Key, Sort>
111110
) : USymbol<Sort>(ctx) {

0 commit comments

Comments
 (0)