A CIL Tutorial - Department of Computer Science - ETH Zürich

A CIL Tutorial - Department of Computer Science - ETH Zürich A CIL Tutorial - Department of Computer Science - ETH Zürich

29.01.2014 Views

CHAPTER 9. TYPE QUALIFIER INFERENCE 76 The function findColorNodes invokes the nodeColorFinder visitor on the le f with the graph g. let findColoredNodes (f : file) (g : graph) : unit = let vis = new nodeColorFinder g in visitCilFile vis f The function colors equal ensures that every color of c1 is somewhere in c2 and that every color of c2 is somewhere in c1. That is it checks that the lists have the same elements. let colors equal (c1 : colors) (c2 : colors) : bool = L.for all (fun c → L.mem c c2) c1 ∧ L.for all (fun c → L.mem c c1) c2 Now that the graph has been seeded by a few type qualiers, we can see where else in the graph they must ow. We'll accomplish this by doing the following. First, we put all the nodes in the graph into a queue. Then, for each node that we pop o the queue, we'll nd the least-upper-bound of the qualier on the node itself along with the qualiers on the nodes for incoming edges; these are the types that it must include. If the least-upper-bound qualier is dierent, we'll assign the new qualier to the node, and then add the nodes on outgoing edges to the end of the queue. When the qualier lattice has nite height, as it does here, we can be sure that the algorithm will terminate. The function enqueueNodes places each of the nodes in our graph on a queue and returns the queue. let enqueueNodes (g : graph) : int Q.t = let q = Q.create () in A.iteri (fun i → Q.add i q) g; q The function processNode folds over the incoming edges of a node, computing the least-upperbound of the types on the origin nodes. If the result is dierent from the starting type, it adds the new type to the graph and return true. Otherwise it returns false. let processNode (g : graph) (id : int) : bool = let c' = L.fold left (fun c id' → list union c g.(id').ncolors) g.(id).ncolors g.(id).incoming in if ¬(colors equal g.(id).ncolors c') then begin g.(id).ncolors ← c'; true end else false The function processQueue applies processNode to each node of the graph g on queue q. If processNode for some node returns true, it adds the destinations of the node's outgoing edges to the end of the queue.

CHAPTER 9. TYPE QUALIFIER INFERENCE 77 let processQueue (g : graph) (q : int Q.t) : unit = while ¬(Q.is empty q) do let id = Q.pop q in if processNode g id then begin L.iter (fun id' → Q.add id' q) g.(id).outgoing end done The function attr of color builds a new type attribute from the color c. let attr of color (c : T.color) : attribute = Attr(T.string of color c, [ ]) Once the inference algorithm is nished, we can add its results to the types in the program. If an inferred type qualier disagrees with one that the programmer has added explicitly, we keep the programmer's annotation, but issue a warning. The visitor colorAdder visits typ nodes in the AST. It reads the inferred color type using the typ's "Node" attribute, and adds it to the typ, respecting the above policy. class colorAdder (g : graph) = object(self) inherit nopCilVisitor method vtype (t : typ) = let oc = T.colors of type t in let ic = (t | > node of type | > A.get g).ncolors in if oc ≠ [ ] ∧ ¬(colors equal ic oc) then DoChildren else if list equal (=) ic oc then DoChildren else let nattr = L.map attr of color ic in ChangeTo (typeAddAttributes nattr t) end The function addInferredColors invokes the visitor colorAdder on the le f using the inference results in graph g. let addInferredColors (f : file) (g : graph) : unit = let vis = new colorAdder g in visitCilFile vis f Finally, we tie everything together with the function tut9, which is the entry point into the module. We must also remember to remove the node attributes we added for building the graph. We leave the inferred colors since these will need to be checked by a type-checking pass like the one in Chapter 7.

CHAPTER 9. TYPE QUALIFIER INFERENCE 77<br />

let processQueue (g : graph) (q : int Q.t) : unit =<br />

while ¬(Q.is empty q) do<br />

let id = Q.pop q in<br />

if processNode g id then begin<br />

L.iter (fun id' → Q.add id' q) g.(id).outgoing<br />

end<br />

done<br />

The function attr <strong>of</strong> color builds a new type attribute from the color c.<br />

let attr <strong>of</strong> color (c : T.color) : attribute = Attr(T.string <strong>of</strong> color c, [ ])<br />

Once the inference algorithm is nished, we can add its results to the types in the program. If an<br />

inferred type qualier disagrees with one that the programmer has added explicitly, we keep the<br />

programmer's annotation, but issue a warning.<br />

The visitor colorAdder visits typ nodes in the AST. It reads the inferred color type using the<br />

typ's "Node" attribute, and adds it to the typ, respecting the above policy.<br />

class colorAdder (g : graph) = object(self)<br />

inherit nopCilVisitor<br />

method vtype (t : typ) =<br />

let oc = T.colors <strong>of</strong> type t in<br />

let ic = (t | > node <strong>of</strong> type | > A.get g).ncolors in<br />

if oc ≠ [ ] ∧ ¬(colors equal ic oc) then DoChildren<br />

else if list equal (=) ic oc then DoChildren else<br />

let nattr = L.map attr <strong>of</strong> color ic in<br />

ChangeTo (typeAddAttributes nattr t)<br />

end<br />

The function addInferredColors invokes the visitor colorAdder on the le f using the inference<br />

results in graph g.<br />

let addInferredColors (f : file) (g : graph) : unit =<br />

let vis = new colorAdder g in<br />

visitCilFile vis f<br />

Finally, we tie everything together with the function tut9, which is the entry point into the module.<br />

We must also remember to remove the node attributes we added for building the graph. We leave the<br />

inferred colors since these will need to be checked by a type-checking pass like the one in Chapter 7.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!