root/trunk/ProjectFortress/demos/Cfa.fss

Revision 4130, 14.4 KB (checked in by sukyoungryu, 3 months ago)

[disambiguator] Fixed handling getters and setters in ExprDisambiguator?. Fixed libraries and tests using getters.

Line 
1(*******************************************************************************
2    Copyright 2009 Sun Microsystems, Inc.,
3    4150 Network Circle, Santa Clara, California 95054, U.S.A.
4    All rights reserved.
5
6    U.S. Government Rights - Commercial software.
7    Government users are subject to the Sun Microsystems, Inc. standard
8    license agreement and applicable provisions of the FAR and its supplements.
9
10    Use is subject to license terms.
11
12    This distribution may include materials developed by third parties.
13
14    Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered
15    trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
16 ******************************************************************************)
17
18component Cfa
19import List.{...}
20import Map.{...}
21import Set.{...}
22import Syntax.{...}
23import DynamicSemantics.{...}
24import System.{args}
25export Executable
26
27(* Control flow analysis helper table ******************************************)
28(* function name |-> function id *)
29fids  : Map[\String, ZZ32\] := {[\String, ZZ32\]}
30(* function id   |-> function declaration *)
31fdecls: Map[\ZZ32, FnDecl\] := {[\ZZ32, FnDecl\]}
32(* function id   |-> function expression *)
33fexprs: Map[\ZZ32, FnExpr\] := {[\ZZ32, FnExpr\]}
34(* function id   |-> function body *)
35bodies: Map[\ZZ32, Expr\]   := {[\ZZ32, Expr\]}
36(* function id   |-> parameter name *)
37params: Map[\ZZ32, String\] := {[\ZZ32, String\]}
38emptySet: Set[\ZZ32\] = set[\ZZ32\]()
39
40(* For a given function id,
41   returns the corresponding function declaration or function expression.
42 *)
43fidToFunction(id: ZZ32) =
44  if fd <- fdecls.member(id)
45  then fd
46  else if f <- fexprs.member(id)
47       then f
48       else throw FailCalled("Function not found: " id)
49       end
50  end
51
52(* Initialize the helper tables before analyzing the program *******************)
53init() = do
54  atomic cfa_eqns := {[\ZZ32, Set[\ZZ32\]\]}
55  atomic new_eqn  := true
56  atomic iteration:= 0
57  atomic fids   := {[\String, ZZ32\]}
58  atomic fdecls := {[\ZZ32, FnDecl\]}
59  atomic fexprs := {[\ZZ32, FnExpr\]}
60  atomic bodies := {[\ZZ32, Expr\]}
61  atomic params := {[\ZZ32, String\]}
62end
63
64init(p: Program) = do
65  init()
66  initSyntax()
67  initDynamic()
68  init(fd), fd <- p.decls
69  init(p.expr)
70end
71
72(* For each function declaration,
73   add the following mappings to the tables:
74       function name |-> function id
75       function id   |-> function declaration
76       function id   |-> function body
77       function id   |-> parameter name
78   and initialize the helper tables from the function body
79 *)
80init(fd: FnDecl) = do
81  id = fd.getId()
82  atomic fids   := fids.add(fd.name, id)
83  atomic fdecls := fdecls.add(id, fd)
84  atomic params := params.add(id, fd.param)
85  atomic bodies := bodies.add(id, fd.body)
86  init(fd.body)
87end
88
89(* Var, True, and False do nothing. *)
90init(e: Expr) = ()
91
92(* For each function expression,
93   add the following mappings to the tables:
94       function id   |-> function expression
95       function id   |-> function body
96       function id   |-> parameter name
97   and initialize the helper tables from the function body
98 *)
99init(e: FnExpr) = do
100  id = e.getId()
101  atomic fexprs := fexprs.add(id, e)
102  atomic params := params.add(id, e.param)
103  atomic bodies := bodies.add(id, e.body)
104  init(e.body)
105end
106
107(* For each application expression,
108   initialize the helper tables from its subexpressions.
109 *)
110init(e: App) = do _ = (init(e.function), init(e.argument)) end
111
112(* For each if expression,
113   initialize the helper tables from its subexpressions.
114 *)
115init(e: If) = do _ = (init(e.cond), init(e.thenB), init(e.elseB)) end
116
117(* Debugging *******************************************************************)
118debug: Boolean := false
119indent = "    "
120
121(* print the helper tables *****************************************************)
122dumpHelperTables() =
123  if debug
124  then
125    println "(* print the helper tables ***************************************)"
126    println "(* fids  : function name |-> function id *)"
127    println fids//
128    println "(* fdecls: function id   |-> function declaration *)"
129    println fdecls//
130    println "(* bodies: function id   |-> function body *)"
131    println bodies//
132    println "(* params: function id   |-> parameter name *)"
133    println params//
134  end
135
136(* print the equation tables ***************************************************)
137dumpEquationsTables() =
138  if debug
139  then
140    println "(* print the equation tables *************************************)"
141    println "(* cfa_eqns: function id |-> { function id } *)"
142    println (indent "{")
143    println (indent indent cfa_eqn), cfa_eqn <- cfa_eqns
144    println (indent "}")//
145  end
146
147(* Control flow analysis table *************************************************)
148(* function id |-> { function id } *)
149cfa_eqns: Map[\ZZ32, Set[\ZZ32\]\] := {[\ZZ32, Set[\ZZ32\]\]}
150new_eqn: Boolean := true
151
152(* Add a (id, s) pair to the cfa_eqns table. *)
153add(id: ZZ32, s: Set[\ZZ32\]) = do
154  if debug then println("add(" id ", " s ")") end
155  atomic cfa_eqns := cfa_eqns.add(id, s)
156end
157
158(* Map id to s. *)
159update(id: ZZ32, s: Set[\ZZ32\]) = do
160  if debug then println("update(" id ", " s ")") end
161  atomic cfa_eqns := cfa_eqns.update(id, s)
162end
163
164(* Build control flow equations in the cfa_eqns table. *************************)
165iteration: ZZ32 := 0
166(* Build equations from the function declarations and the body expression.
167   Repeat it until no new equation is generated.
168 *)
169buildEquations(p: Program) = do
170  while new_eqn do
171    atomic iteration += 1
172    if debug then println("(* buildEquations iteration: " iteration
173                          " ****************)") end
174    atomic new_eqn := false
175    buildEquations(fd), fd <- p.decls
176    buildEquations(p.expr)
177    if debug then println "" end
178  end
179end
180
181(* For each function declaration,
182   add the following equation into the cfa_eqns table:
183
184       its_function_id CONTAINS its_function_id
185
186   and build equations from its body expression.
187 *)
188buildEquations(fd: FnDecl) = do
189  addEquation(fd.getId())
190  buildEquations(fd.body)
191end
192
193(* For each expression,
194   build equations into the cfa_eqns table.
195   True and False do not generate any equations.
196*)
197buildEquations(e: Expr) = ()
198
199(* For each function expression,
200   add the following equation into the cfa_eqns table:
201
202       its_function_id CONTAINS its_function_id
203
204   and build equations from its body expression.
205 *)
206buildEquations(e: FnExpr) = do
207  addEquation(e.getId())
208  buildEquations(e.body)
209end
210
211(* For each named function,
212   add the following equation into the cfa_eqns table:
213
214       the_variable_id CONTAINS its_function_id
215 *)
216buildEquations(e: Var) =
217  if id <- fids.member(e.name)
218  then addEquation(e.id, { id })
219  end
220
221(* For each if expression,
222   if its 'then' branch has a set of function ids, s, in the cfa_eqns table
223   then if its else branch has a set of function ids, s',
224        then add the following equation into the cfa_eqns table:
225
226            the_if_expression_id INCLUDES s UNION s'
227
228        else add the following equation into the cfa_eqns table:
229
230            the_if_expression_id INCLUDES s
231
232   else if its 'else' branch has a set of function ids, s',
233        then add the following equation into the cfa_eqns table:
234
235            the_if_expression_id INCLUDES s'
236
237   and build equations from its "then" and "else" branches.
238 *)
239buildEquations(e: If) = do
240  _ = (buildEquations(e.thenB), buildEquations(e.elseB))
241
242  id = e.getId()
243  if s <- cfa_eqns.member(e.thenB.getId())
244  then if s' <- cfa_eqns.member(e.elseB.getId())
245       then addEquation(id, s UNION s')
246       else addEquation(id, s)
247       end
248  else if s' <- cfa_eqns.member(e.elseB.getId())
249       then addEquation(id, s')
250       end
251  end
252end
253
254(* There are two kinds of equation building in this function:
255
256   For each function application, e1 e2,
257   if e1 has a set of function ids, ftns, in the cfa_eqns table
258   then for each function ftn in ftns
259        if ftn's body has a set of function ids, ftns' in the cfa_eqns table
260        then add the following equation into the cfa_eqns table:
261
262            the_appication_id INCLUDES ftns'
263
264   For each function application e1 e2,
265   if e1 has a set of function ids, ftns, in the cfa_eqns table
266   then for each function ftn in ftns and its parameter x
267        if e2 has a set of function ids, ftns', in the cfa_eqns table
268        then add the following equation into the cfa_eqns table:
269
270            x's_id INCLUDES ftns'
271
272   and build equations from its "then" and "else" branches.
273 *)
274buildEquations(e: App) = do
275  e1 = e.function
276  e2 = e.argument
277
278  if debug
279  then println("App(" e.getId() ", " e1.getId() ", " e2.getId() ") = " e)
280  end
281
282  _ = (buildEquations(e1), buildEquations(e2))
283
284  if ftns <- cfa_eqns.member(e1.getId())
285  then for ftn <- ftns do
286         if ftns' <- cfa_eqns.member(bodies[ftn].getId())
287         then addEquation(e.getId(), ftns')
288         end
289
290         if ftns' <- cfa_eqns.member(e2.getId())
291         then addEquation(x, ftns'), x <- collectVars(params[ftn], bodies[ftn])
292         end
293       end
294  end
295end
296
297(* Collect a set of variable ids of the given name in a given expression *******)
298(* There are no variables in True and False *)
299collectVars(name: String, e: Expr) = emptySet
300
301(* If a variable has the same name as the given name
302   then returns a singleton set of the variable's id
303   else returns an empty set
304 *)
305collectVars(name: String, e: Var) =
306  if name = e.name then { e.getId() } else emptySet end
307
308(* If a function expression's parameter has the same name as the given name
309   then returns an empty set
310   else returns a set of variable ids of the given name in the function body
311 *)
312collectVars(name: String, e: FnExpr) =
313  if name = e.param then emptySet else collectVars(name, e.body) end
314
315(* For an function application expression
316   collect a set of variable ids of the given name
317   in its function and argument expressions.
318 *)
319collectVars(name: String, e: App) =
320  collectVars(name, e.function) UNION collectVars(name, e.argument)
321
322(* For an if expression
323   collect a set of variable ids of the given name
324   in its true and false branches.
325 *)
326collectVars(name: String, e: If) =
327  collectVars(name, e.thenB) UNION collectVars(name, e.elseB)
328
329(* Add control flow equations into the cfa_eqns table. *************************)
330(* For a given function id,
331   if there exists an equation:
332
333            the_function_id INCLUDES function_ids_set
334
335   then if the function id is in the function_ids_set
336        then new equation is not generated.
337        else update the equation as follows:
338
339            the_function_id INCLUDES the_function_id UNION { the_function_id }
340
341   else add the following equation into the cfa_eqns table:
342
343            the_function_id CONTAINS the_function_id
344
345   if a new equation is generated, set the new_eqn flag.
346 *)
347addEquation(id: ZZ32) =
348  if fids' <- cfa_eqns.member(id)
349  then if NOT(id IN fids')
350       then atomic update(id, fids' UNION {[\ZZ32\]id})
351            atomic new_eqn  := true
352       end
353  else atomic add(id, {[\ZZ32\]id})
354       atomic new_eqn  := true
355  end
356
357(* For a given function id, 'id' and a set of function ids, 's',
358   if there exists an equation:
359
360            id INCLUDES s'
361
362   then if s is a subset or equal to s'
363        then new equation is not generated.
364        else update the equation as follows:
365
366            id INCLUDES s UNION s'
367
368   else add the following equation into the cfa_eqns table:
369
370            id INCLUDES s
371
372   if a new equation is generated, set the new_eqn flag.
373 *)
374addEquation(id: ZZ32, s: Set[\ZZ32\]) =
375  if s' <- cfa_eqns.member(id)
376  then if NOT(s SUBSETEQ s')
377       then atomic update(id, s UNION s')
378            atomic new_eqn := true
379       end
380  else atomic add(id, s)
381       atomic new_eqn := true
382  end
383(* '*)
384
385(* Control flow analysis main engin ********************************************)
386cfa(p: Program) = do
387  init(p)
388  dumpHelperTables()
389  buildEquations(p)
390  dumpEquationsTables()
391  if result <- cfa_eqns.member(p.expr.getId())
392  then result
393  else emptySet
394  end
395end
396
397(* Driver of the control flow analysis for a program *)
398doit(p: Program) = do
399  (* controfl flow analysis ****************************************************)
400  cfa_result = cfa(p)
401
402  (* print the result **********************************************************)
403  println "Test Program:"
404  if debug
405  then println (p.asString)//
406  else println (p.toSource())//
407  end
408
409  println "Evaluated value:"
410  result = (VDASH p).getValue()
411  if debug
412  then println (indent result.asString)//
413  else println (indent result.toSource())//
414  end
415
416  println "Control flow analysis result with " iteration " iterations:"
417  println (indent "{")
418  println (indent indent (fidToFunction(fid).toSource())), fid <- cfa_result
419  println (indent "}")//
420end
421
422(* test programs ***************************************************************)
423(* test program 1 *)
424test1() = do
425  println "(* Test program 1 **************************************************)"
426  (* f(x) = x
427     g(y) = f(y)
428     h(z) = f(z)
429     if f(true) then g(fn x => x) else h(fn y => false) end
430   *)
431  fd = FnDecl("f", "x", Var("x"))
432  gd = FnDecl("g", "y", App(Var("f"), Var("y")))
433  hd = FnDecl("h", "z", App(Var("f"), Var("z")))
434  fds = <|fd, gd, hd|>
435  body = If(App(Var("f"), False),
436            App(Var("g"), FnExpr("x", Var("x"))),
437            App(Var("h"), FnExpr("y", False)))
438  Program(fds, body)
439end
440
441(* test program 2 *)
442test2() = do
443  println "(* Test program 2 **************************************************)"
444  (* f(x) = true
445     g(y) = false
446     h(z) = if z then f else g end
447     (h(true)) false
448   *)
449  fd = FnDecl("f", "x", True)
450  gd = FnDecl("g", "y", False)
451  hd = FnDecl("h", "z", If(Var("z"), Var("f"), Var("g")))
452  fds = <|fd, gd, hd|>
453  body = App(App(Var("h"), True), False)
454  Program(fds, body)
455end
456
457(* test program 3 *)
458test3() = do
459  println "(* Test program 3 **************************************************)"
460  (* f_0(x) = x
461     ...
462     f_n(x) = f_{n-1}(x)
463     f_n(fn y => false)
464   *)
465  n = 50
466  fd0 = FnDecl("f_0", "x", Var("x"))
467  fds = <| FnDecl("f_" i, "x", App(Var("f_" (i-1)), Var("x"))) | i <- 1:n |>.addLeft(fd0)
468  body = App(Var("f_" n), FnExpr("y", False))
469  Program(fds, body)
470end
471
472(* Run test programs. *)
473tests() = do
474  doit(test1())
475  doit(test2())
476  recordTime(6.847)
477  doit(test3())
478  printTime(6.847)
479end
480
481printUsage() = println "Usage: fortress Cfa.fss [-[-]debug]"
482
483run() =
484  if |args| > 1
485  then printUsage()
486  else if |args| = 1
487       then if args[0] = "-debug" OR args[0] = "--debug"
488            then debug := true
489                 tests()
490            else printUsage()
491            end
492       else tests()
493       end
494  end
495
496end
Note: See TracBrowser for help on using the browser.