First cut at constructing a call graph.
Chris Pressey
3 years ago
48 | 48 |
if options.dump_exit_contexts:
|
49 | 49 |
sys.stdout.write(json.dumps(analyzer.exit_contexts_map, indent=4, sort_keys=True, separators=(',', ':')))
|
50 | 50 |
sys.stdout.write("\n")
|
|
51 |
|
|
52 |
if options.dump_callgraph:
|
|
53 |
for routine in program.routines:
|
|
54 |
sys.stdout.write('-----------\n')
|
|
55 |
sys.stdout.write('{}\n'.format(routine.name))
|
|
56 |
for called_routine in routine.called_routines:
|
|
57 |
sys.stdout.write(' {}\n'.format(called_routine.name))
|
51 | 58 |
|
52 | 59 |
compilation_roster = None
|
53 | 60 |
if options.optimize_fallthru:
|
|
161 | 168 |
help="Dump the ordered fallthru map, in JSON, to stdout after analyzing the program."
|
162 | 169 |
)
|
163 | 170 |
argparser.add_argument(
|
|
171 |
"--dump-callgraph",
|
|
172 |
action="store_true",
|
|
173 |
help="Dump the call graph, in JSON, to stdout after analyzing the program."
|
|
174 |
)
|
|
175 |
argparser.add_argument(
|
164 | 176 |
"--parse-only",
|
165 | 177 |
action="store_true",
|
166 | 178 |
help="Only parse the program; do not analyze or compile it."
|
142 | 142 |
for routine in program.routines:
|
143 | 143 |
context = self.analyze_routine(routine)
|
144 | 144 |
routine.encountered_gotos = list(context.encountered_gotos()) if context else []
|
|
145 |
routine.called_routines = list(context.called_routines) if context else []
|
145 | 146 |
|
146 | 147 |
def analyze_routine(self, routine):
|
147 | 148 |
assert isinstance(routine, Routine)
|
|
514 | 515 |
type = self.get_type(instr.location)
|
515 | 516 |
if not isinstance(type, (RoutineType, VectorType)):
|
516 | 517 |
raise TypeMismatchError(instr, instr.location.name)
|
|
518 |
context.mark_as_called(instr.location)
|
517 | 519 |
if isinstance(type, VectorType):
|
518 | 520 |
type = type.of_type
|
519 | 521 |
for ref in type.inputs:
|
34 | 34 |
self._terminated = False
|
35 | 35 |
self._gotos_encountered = set()
|
36 | 36 |
self._pointer_assoc = dict()
|
|
37 |
self.called_routines = set()
|
37 | 38 |
|
38 | 39 |
for ref in inputs:
|
39 | 40 |
if self.is_constant(ref):
|
|
78 | 79 |
c._writeable = set(self._writeable)
|
79 | 80 |
c._pointer_assoc = dict(self._pointer_assoc)
|
80 | 81 |
c._gotos_encountered = set(self._gotos_encountered)
|
|
82 |
c.called_routines = set(self.called_routines)
|
81 | 83 |
return c
|
82 | 84 |
|
83 | 85 |
def update_from(self, other):
|
|
93 | 95 |
self._writeable = set(other._writeable)
|
94 | 96 |
self._terminated = other._terminated
|
95 | 97 |
self._pointer_assoc = dict(other._pointer_assoc)
|
|
98 |
self.called_routines = set(other.called_routines)
|
96 | 99 |
|
97 | 100 |
def each_meaningful(self):
|
98 | 101 |
for ref in self._range.keys():
|
|
325 | 328 |
return self.symtab.fetch_local_type(self.routine.name, ref.name).max_range
|
326 | 329 |
else:
|
327 | 330 |
return self.symtab.fetch_global_type(ref.name).max_range
|
|
331 |
|
|
332 |
def mark_as_called(self, routine):
|
|
333 |
self.called_routines.add(routine)
|