-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathConcreteMemory.fs
More file actions
242 lines (199 loc) · 10.6 KB
/
Copy pathConcreteMemory.fs
File metadata and controls
242 lines (199 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
namespace VSharp.Core
open System
open System.Collections.Generic
open System.Runtime.Serialization
open System.Runtime.CompilerServices
open System.Threading
open VSharp
type public ConcreteMemory private (physToVirt, virtToPhys, dependencies) =
let mutable physToVirt = physToVirt
let mutable virtToPhys = virtToPhys
let mutable dependencies = dependencies
// ----------------------------- Helpers -----------------------------
static let nonCopyableTypes = [
typeof<Type>
typeof<Thread>
]
let cannotBeCopied typ = List.contains typ nonCopyableTypes
let getArrayIndicesWithValues (array : Array) =
let ubs = List.init array.Rank array.GetUpperBound
let lbs = List.init array.Rank array.GetLowerBound
let indices = List.map2 (fun lb ub -> [lb .. ub]) lbs ubs |> List.cartesian
indices |> Seq.map (fun index -> index, array.GetValue(Array.ofList index))
let copiedObjects = Dictionary<physicalAddress, physicalAddress>()
let rec deepCopyObject (phys : physicalAddress) =
let obj = phys.object
let typ = TypeUtils.getTypeOfConcrete obj
match obj with
| null -> phys
| _ when cannotBeCopied typ || TypeUtils.isPrimitive typ || typ.IsEnum || typ.IsPointer -> phys
| :? System.Reflection.Pointer -> phys
| _ -> deepCopyComplex phys typ
and deepCopyComplex (phys : physicalAddress) typ =
let copied = ref {object = null}
if copiedObjects.TryGetValue(phys, copied) then copied.Value
else createCopyComplex phys typ
and createCopyComplex (phys : physicalAddress) typ =
let obj = phys.object
match obj with
| :? Array as a when typ.GetElementType().IsPrimitive ->
let phys' = {object = a.Clone()}
copiedObjects.Add(phys, phys')
phys'
| :? Array as a ->
let rank = a.Rank
let dims = Array.init rank id
let lengths = Array.map a.GetLength dims
let lowerBounds = Array.map a.GetLowerBound dims
let a' = Array.CreateInstance(typ.GetElementType(), lengths, lowerBounds)
let phys' = {object = a'}
copiedObjects.Add(phys, phys')
let indices = Array.allIndicesOfArray (Array.toList lowerBounds) (Array.toList lengths)
for index in indices do
let index = List.toArray index
let v' = deepCopyObject {object = a.GetValue index}
a'.SetValue(v'.object, index)
phys'
| :? String as s ->
let phys' = {object = String(s)}
copiedObjects.Add(phys, phys')
phys'
| _ when typ.IsClass || typ.IsValueType ->
let obj' = FormatterServices.GetUninitializedObject typ
let phys' = {object = obj'}
copiedObjects.Add(phys, phys')
let fields = Reflection.fieldsOf false typ
for _, field in fields do
let v' = deepCopyObject {object = field.GetValue obj}
field.SetValue(obj', v'.object)
phys'
| _ -> internalfailf "ConcreteMemory, deepCopyObject: unexpected object %O" obj
// ----------------------------- Constructor -----------------------------
new () =
let physToVirt = Dictionary<physicalAddress, concreteHeapAddress>()
let virtToPhys = Dictionary<concreteHeapAddress, physicalAddress>()
let deps = Dictionary<concreteHeapAddress, concreteHeapAddress list>()
ConcreteMemory(physToVirt, virtToPhys, deps)
// ----------------------------- Primitives -----------------------------
member private x.ReadObject address =
assert(virtToPhys.ContainsKey address)
virtToPhys[address].object
member private x.WriteObject address obj =
assert(virtToPhys.ContainsKey address)
let physicalAddress = {object = obj}
virtToPhys[address] <- physicalAddress
member private x.getDepsList ds =
// TODO: rewrite it more effectively
let ds' = ds |> Set.ofList |> Set.toList
let ds'' = ds |> List.collect (fun a -> if dependencies.ContainsKey(a) then a::dependencies[a] else [a])
|> Set.ofList |> Set.toList
if ds' = ds'' then ds'
else x.getDepsList ds''
// ------------------------------- Copying -------------------------------
interface IConcreteMemory with
override x.Copy() =
let physToVirt' = Dictionary<physicalAddress, concreteHeapAddress>()
let virtToPhys' = Dictionary<concreteHeapAddress, physicalAddress>()
let deps' = Dictionary<concreteHeapAddress, concreteHeapAddress list>()
copiedObjects.Clear()
for kvp in physToVirt do
let phys, virt = kvp.Key, kvp.Value
let phys' = deepCopyObject phys
if virtToPhys.ContainsKey virt then
virtToPhys'.Add(virt, phys')
if dependencies.ContainsKey virt then
let d' = dependencies[virt] // TODO: deepcopy
deps'.Add(virt, d')
physToVirt'.Add(phys', virt)
ConcreteMemory(physToVirt', virtToPhys', deps')
// ----------------------------- Primitives -----------------------------
override x.Contains address =
virtToPhys.ContainsKey address
// TODO: leave only one function #refactor
override x.VirtToPhys virtAddress = x.ReadObject virtAddress
override x.TryVirtToPhys virtAddress =
let result = ref {object = null}
if virtToPhys.TryGetValue(virtAddress, result) then
Some result.Value.object
else None
override x.PhysToVirt physAddress =
let cm = x :> IConcreteMemory
match cm.TryPhysToVirt physAddress with
| Some address -> address
| None -> internalfailf "PhysToVirt: unable to get virtual address for object %O" physAddress
override x.TryPhysToVirt physAddress =
let result = ref List.empty
if physToVirt.TryGetValue({object = physAddress}, result) then
Some result.Value
else None
// ----------------------------- Allocation -----------------------------
override x.Allocate address (obj : obj) =
assert(virtToPhys.ContainsKey address |> not)
let physicalAddress = {object = obj}
virtToPhys.Add(address, physicalAddress)
if obj = String.Empty then physToVirt[physicalAddress] <- address
else physToVirt.Add(physicalAddress, address)
// ------------------------------- Reading -------------------------------
override x.ReadClassField address (field : fieldId) =
let object = x.ReadObject address
let fieldInfo = Reflection.getFieldInfo field
fieldInfo.GetValue(object)
override x.ReadArrayIndex address (indices : int list) =
match x.ReadObject address with
| :? Array as array -> array.GetValue(Array.ofList indices)
| :? String as string when List.length indices = 1 -> string.[List.head indices] :> obj
| obj -> internalfailf "reading array index from concrete memory: expected to read array, but got %O" obj
override x.GetAllArrayData address =
match x.ReadObject address with
| :? Array as array -> getArrayIndicesWithValues array
| :? String as string -> string.ToCharArray() |> getArrayIndicesWithValues
| obj -> internalfailf "reading array data concrete memory: expected to read array, but got %O" obj
override x.ReadArrayLowerBound address dimension =
match x.ReadObject address with
| :? Array as array -> array.GetLowerBound(dimension)
| :? String when dimension = 0 -> 0
| obj -> internalfailf "reading array lower bound from concrete memory: expected to read array, but got %O" obj
override x.ReadArrayLength address dimension =
match x.ReadObject address with
| :? Array as array -> array.GetLength(dimension)
| :? String as string when dimension = 0 -> string.Length
| obj -> internalfailf "reading array length from concrete memory: expected to read array, but got %O" obj
// ------------------------------- Writing -------------------------------
override x.WriteClassField address (field : fieldId) value =
let object = x.ReadObject address
let fieldInfo = Reflection.getFieldInfo field
fieldInfo.SetValue(object, value)
override x.WriteArrayIndex address (indices : int list) value =
match x.ReadObject address with
| :? Array as array ->
array.SetValue(value, Array.ofList indices)
// TODO: strings must be immutable! This is used by copying, so copy string another way #hack
| :? String as string when List.length indices = 1 ->
let charArray = string.ToCharArray()
charArray.SetValue(value, List.head indices)
let newString = String(charArray)
x.WriteObject address newString
| obj -> internalfailf "writing array index to concrete memory: expected to read array, but got %O" obj
override x.InitializeArray address (rfh : RuntimeFieldHandle) =
match x.ReadObject address with
| :? Array as array -> RuntimeHelpers.InitializeArray(array, rfh)
| obj -> internalfailf "initializing array in concrete memory: expected to read array, but got %O" obj
override x.CopyCharArrayToString arrayAddress stringAddress =
let array = x.ReadObject arrayAddress :?> char array
let string = new string(array) :> obj
x.WriteObject stringAddress string
let physAddress = {object = string}
physToVirt[physAddress] <- stringAddress
// ------------------------------- Dependencies -------------------------
override x.AddDep virtAddr1 virtAddr2 =
let value = if dependencies.ContainsKey virtAddr1 then virtAddr2::dependencies[virtAddr1] else [virtAddr2]
dependencies[virtAddr1] <- value
override x.GetDeps addr =
x.getDepsList [addr]
// ------------------------------- Remove -------------------------------
override x.Remove address =
let toRemove = x.getDepsList [address]
let removed = toRemove |> List.map (fun a ->
dependencies.Remove a |> ignore
virtToPhys.Remove a) |> List.forall id
assert removed