@@ -3,6 +3,7 @@ package org.usvm.machine
3
3
import io.ksmt.sort.KFp64Sort
4
4
import io.ksmt.utils.asExpr
5
5
import org.jacodb.ets.model.EtsAnyType
6
+ import org.jacodb.ets.model.EtsArrayType
6
7
import org.jacodb.ets.model.EtsBooleanType
7
8
import org.jacodb.ets.model.EtsNullType
8
9
import org.jacodb.ets.model.EtsNumberType
@@ -28,7 +29,7 @@ import org.usvm.machine.expr.TsUndefinedSort
28
29
import org.usvm.machine.expr.TsUnresolvedSort
29
30
import org.usvm.machine.interpreter.TsStepScope
30
31
import org.usvm.machine.types.FakeType
31
- import org.usvm.types.UTypeStream
32
+ import org.usvm.memory.UReadOnlyMemory
32
33
import org.usvm.types.single
33
34
import org.usvm.util.mkFieldLValue
34
35
import kotlin.contracts.ExperimentalContracts
@@ -48,42 +49,51 @@ class TsContext(
48
49
* In TS we treat undefined value as a null reference in other objects.
49
50
* For real null represented in the language we create another reference.
50
51
*/
51
- private val undefinedValue: UExpr < UAddressSort > = mkNullRef()
52
- fun mkUndefinedValue (): UExpr < UAddressSort > = undefinedValue
52
+ private val undefinedValue: UHeapRef = mkNullRef()
53
+ fun mkUndefinedValue (): UHeapRef = undefinedValue
53
54
54
55
private val nullValue: UConcreteHeapRef = mkConcreteHeapRef(addressCounter.freshStaticAddress())
55
56
fun mkTsNullValue (): UConcreteHeapRef = nullValue
56
57
57
58
fun typeToSort (type : EtsType ): USort = when (type) {
58
59
is EtsBooleanType -> boolSort
59
60
is EtsNumberType -> fp64Sort
60
- is EtsRefType -> addressSort
61
61
is EtsNullType -> addressSort
62
62
is EtsUndefinedType -> addressSort
63
- is EtsUnknownType -> unresolvedSort
64
63
is EtsUnionType -> unresolvedSort
64
+ is EtsRefType -> addressSort
65
65
is EtsAnyType -> unresolvedSort
66
- else -> TODO (" Support all JacoDB types, encountered $type " )
66
+ is EtsUnknownType -> unresolvedSort
67
+ else -> TODO (" ${type::class .simpleName} is not yet supported: $type " )
67
68
}
68
69
69
- fun UHeapRef.getTypeStream (scope : TsStepScope ): UTypeStream <EtsType > =
70
- scope.calcOnState {
71
- memory.typeStreamOf(this @getTypeStream)
72
- }
70
+ // TODO: for now, ALL descriptors for array are UNKNOWN
71
+ // in order to make ALL reading/writing, including '.length' access consistent
72
+ // and possible in cases when the array type is not known.
73
+ // For example, when we access '.length' of some array, we do not care about its type,
74
+ // but we HAVE TO use some type consistent with the type used when this array was created.
75
+ // Note: Using UnknownType everywhere does not lead to any errors yet,
76
+ // since we do not rely on array types in any way.
77
+ fun arrayDescriptorOf (type : EtsArrayType ): EtsType = EtsUnknownType
78
+
79
+ fun UConcreteHeapRef.getFakeType (memory : UReadOnlyMemory <* >): FakeType {
80
+ check(isFakeObject())
81
+ return memory.typeStreamOf(this ).single() as FakeType
82
+ }
73
83
74
84
fun UConcreteHeapRef.getFakeType (scope : TsStepScope ): FakeType =
75
- getTypeStream( scope).single() as FakeType
85
+ scope.calcOnState { getFakeType(memory) }
76
86
77
87
@OptIn(ExperimentalContracts ::class )
78
- fun UExpr <out USort >.isFakeObject (): Boolean {
88
+ fun UExpr <* >.isFakeObject (): Boolean {
79
89
contract {
80
90
returns(true ) implies (this @isFakeObject is UConcreteHeapRef )
81
91
}
82
92
83
93
return sort == addressSort && this is UConcreteHeapRef && address > MAGIC_OFFSET
84
94
}
85
95
86
- fun UExpr <out USort >.toFakeObject (scope : TsStepScope ): UConcreteHeapRef {
96
+ fun UExpr <* >.toFakeObject (scope : TsStepScope ): UConcreteHeapRef {
87
97
if (isFakeObject()) {
88
98
return this
89
99
}
@@ -94,20 +104,20 @@ class TsContext(
94
104
when (sort) {
95
105
boolSort -> {
96
106
val lvalue = getIntermediateBoolLValue(ref.address)
97
- memory.write(lvalue, this @toFakeObject. asExpr(boolSort), guard = trueExpr)
98
- memory.types.allocate(ref.address, FakeType .fromBool (this @TsContext))
107
+ memory.write(lvalue, asExpr(boolSort), guard = trueExpr)
108
+ memory.types.allocate(ref.address, FakeType .mkBool (this @TsContext))
99
109
}
100
110
101
111
fp64Sort -> {
102
112
val lValue = getIntermediateFpLValue(ref.address)
103
- memory.write(lValue, this @toFakeObject. asExpr(fp64Sort), guard = trueExpr)
104
- memory.types.allocate(ref.address, FakeType .fromFp (this @TsContext))
113
+ memory.write(lValue, asExpr(fp64Sort), guard = trueExpr)
114
+ memory.types.allocate(ref.address, FakeType .mkFp (this @TsContext))
105
115
}
106
116
107
117
addressSort -> {
108
118
val lValue = getIntermediateRefLValue(ref.address)
109
- memory.write(lValue, this @toFakeObject. asExpr(addressSort), guard = trueExpr)
110
- memory.types.allocate(ref.address, FakeType .fromRef (this @TsContext))
119
+ memory.write(lValue, asExpr(addressSort), guard = trueExpr)
120
+ memory.types.allocate(ref.address, FakeType .mkRef (this @TsContext))
111
121
}
112
122
113
123
else -> TODO (" Not yet supported" )
@@ -117,29 +127,15 @@ class TsContext(
117
127
return ref
118
128
}
119
129
120
- fun UExpr <out USort >.extractSingleValueFromFakeObjectOrNull (scope : TsStepScope ): UExpr <out USort >? {
130
+ fun UExpr <* >.extractSingleValueFromFakeObjectOrNull (scope : TsStepScope ): UExpr <* >? {
121
131
if (! isFakeObject()) return null
122
132
123
133
val type = getFakeType(scope)
124
- return scope.calcOnState {
125
- when {
126
- type.boolTypeExpr.isTrue -> {
127
- val lValue = getIntermediateBoolLValue(address)
128
- memory.read(lValue).asExpr(boolSort)
129
- }
130
-
131
- type.fpTypeExpr.isTrue -> {
132
- val lValue = getIntermediateFpLValue(address)
133
- memory.read(lValue).asExpr(fp64Sort)
134
- }
135
-
136
- type.refTypeExpr.isTrue -> {
137
- val lValue = getIntermediateRefLValue(address)
138
- memory.read(lValue).asExpr(addressSort)
139
- }
140
-
141
- else -> null
142
- }
134
+ return when {
135
+ type.boolTypeExpr.isTrue -> extractBool(scope)
136
+ type.fpTypeExpr.isTrue -> extractFp(scope)
137
+ type.refTypeExpr.isTrue -> extractRef(scope)
138
+ else -> null
143
139
}
144
140
}
145
141
@@ -163,19 +159,34 @@ class TsContext(
163
159
return mkFieldLValue(addressSort, mkConcreteHeapRef(addr), IntermediateLValueField .REF )
164
160
}
165
161
166
- fun UConcreteHeapRef.extractBool (scope : TsStepScope ): UBoolExpr {
162
+ fun UConcreteHeapRef.extractBool (memory : UReadOnlyMemory <* >): UBoolExpr {
163
+ check(isFakeObject())
167
164
val lValue = getIntermediateBoolLValue(address)
168
- return scope.calcOnState { memory.read(lValue) }
165
+ return memory.read(lValue)
169
166
}
170
167
171
- fun UConcreteHeapRef.extractFp (scope : TsStepScope ): UExpr <KFp64Sort > {
168
+ fun UConcreteHeapRef.extractFp (memory : UReadOnlyMemory <* >): UExpr <KFp64Sort > {
169
+ check(isFakeObject())
172
170
val lValue = getIntermediateFpLValue(address)
173
- return scope.calcOnState { memory.read(lValue) }
171
+ return memory.read(lValue)
174
172
}
175
173
176
- fun UConcreteHeapRef.extractRef (scope : TsStepScope ): UHeapRef {
174
+ fun UConcreteHeapRef.extractRef (memory : UReadOnlyMemory <* >): UHeapRef {
175
+ check(isFakeObject())
177
176
val lValue = getIntermediateRefLValue(address)
178
- return scope.calcOnState { memory.read(lValue) }
177
+ return memory.read(lValue)
178
+ }
179
+
180
+ fun UConcreteHeapRef.extractBool (scope : TsStepScope ): UBoolExpr {
181
+ return scope.calcOnState { extractBool(memory) }
182
+ }
183
+
184
+ fun UConcreteHeapRef.extractFp (scope : TsStepScope ): UExpr <KFp64Sort > {
185
+ return scope.calcOnState { extractFp(memory) }
186
+ }
187
+
188
+ fun UConcreteHeapRef.extractRef (scope : TsStepScope ): UHeapRef {
189
+ return scope.calcOnState { extractRef(memory) }
179
190
}
180
191
}
181
192
0 commit comments