-
Notifications
You must be signed in to change notification settings - Fork 36
Expand file tree
/
Copy pathDistanceWeighter.fs
More file actions
120 lines (104 loc) · 5.16 KB
/
DistanceWeighter.fs
File metadata and controls
120 lines (104 loc) · 5.16 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
namespace VSharp.Interpreter.IL
open System
open VSharp
open VSharp.Interpreter.IL.CilStateOperations
type ShortestDistanceWeighter(target : codeLocation) =
let infinity = UInt32.MaxValue
let handleInfinity n = if n = infinity then None else Some n
let logarithmicScale weight =
if weight = 0u then 0u
elif weight = 1u then 1u
else double weight |> Math.Log2 |> Math.Ceiling |> uint
let callGraphDistanceToTarget = CallGraph.findCallGraphDistanceTo target.method
// Returns the number proportional to distance from the offset in frameOffset of frameMethod to target. Uses both
// call graph for interprocedural and CFG for intraprocedural distance approximation.
let frameWeight (frameMethod : Method) frameOffset frameNumber =
let frameMethodCFG = frameMethod.CFG
let frameDist = frameMethodCFG.DistancesFrom frameOffset
let checkDist () = Dict.tryGetValue frameDist target.offset infinity <> infinity
let callWeight callMethod =
let callGraphDistance = Dict.tryGetValue callGraphDistanceToTarget callMethod infinity
if callGraphDistance = infinity then infinity
else 2u * (callGraphDistance + 1u) + frameNumber
match () with
| _ when frameMethod = target.method && checkDist () -> frameNumber
| _ when Seq.isEmpty frameMethodCFG.Calls -> infinity
| _ ->
frameMethodCFG.Calls |> Seq.map (fun kvp ->
if Dict.tryGetValue frameDist kvp.Key infinity = infinity then infinity
else callWeight kvp.Value.Callee)
|> Seq.min
let calculateCallWeight (state : cilState) =
let frameWeights =
state.ipStack
|> Seq.choose (fun ip ->
let optOffset = offsetOf ip
if Option.isSome optOffset
then Some (methodOf ip, optOffset |> Option.get)
else None)
|> Seq.mapi (fun number (method, offset) ->
// TODO: do not execute this for frames with frameNumber > current minimum
frameWeight method offset (uint number), uint number)
if Seq.isEmpty frameWeights then None
else
let w, n = Seq.minBy fst frameWeights
if w = infinity then None else Some (w, n)
// Returns the number proportional to distance from loc to target in CFG.
let localWeight loc (tagets : codeLocation seq) =
let localCFG = loc.method.CFG
let dist = localCFG.DistancesFrom loc.offset
tagets
|> Seq.fold (fun m l -> min m (Dict.tryGetValue dist l.offset infinity)) infinity
|> handleInfinity
|> Option.map logarithmicScale
let targetWeight currLoc =
localWeight currLoc [target]
// Returns the number proportional to distance from loc to relevant calls in this method
let preTargetWeight currLoc =
let localCFG = currLoc.method.CFG
let targets =
localCFG.Calls
|> Seq.filter (fun kv -> callGraphDistanceToTarget.ContainsKey kv.Value.Callee)
|> Seq.map (fun kv -> { offset = localCFG.ResolveBasicBlock kv.Key; method = currLoc.method })
localWeight currLoc targets |> Option.map ((+) 32u)
// Returns the number proportional to distance from loc to return of this method
let postTargetWeight currLoc =
let localCFG = currLoc.method.CFG
let targets = localCFG.Sinks |> Seq.map (fun offset -> { offset = localCFG.ResolveBasicBlock offset; method = currLoc.method })
localWeight currLoc targets |> Option.map ((+) 32u)
interface IWeighter with
override x.Weight(state) =
option {
match tryCurrentLoc state with
| Some currLoc ->
let! callWeight = calculateCallWeight state
let! weight =
match callWeight with
| 0u, _ -> targetWeight currLoc
| _, 0u -> preTargetWeight currLoc
| _ -> postTargetWeight currLoc
return weight * logarithmicScale state.stepsNumber
| None -> return 1u
}
type IntraproceduralShortestDistanceToUncoveredWeighter(statistics : SILIStatistics) =
let minDistance (method : Method) fromLoc =
let infinity = UInt32.MaxValue
if method.IsAbstract then None
else
let cfg = method.CFG
let minDistance =
cfg.DistancesFrom fromLoc
|> Seq.fold (fun min kvp ->
let loc = { offset = kvp.Key; method = method }
let distance = kvp.Value
// TODO: check all instructions of basic block for coverage
if distance < min && distance <> 0u && not <| statistics.IsCovered loc then distance
else min) infinity
Some minDistance
interface IWeighter with
override x.Weight(state) =
state.ipStack |> Seq.tryPick (fun ip ->
match ipOperations.ip2codeLocation ip with
| Some loc when loc.method.InCoverageZone -> minDistance loc.method loc.offset
| Some _ -> None
| None -> Some 1u)