]> sourceware.org Git - systemtap.git/blob - elaborate.cxx
Merge branch 'master' of ssh://sources.redhat.com/git/systemtap
[systemtap.git] / elaborate.cxx
1 // elaboration functions
2 // Copyright (C) 2005-2008 Red Hat Inc.
3 // Copyright (C) 2008 Intel Corporation
4 //
5 // This file is part of systemtap, and is free software. You can
6 // redistribute it and/or modify it under the terms of the GNU General
7 // Public License (GPL); either version 2, or (at your option) any
8 // later version.
9
10 #include "config.h"
11 #include "elaborate.h"
12 #include "parse.h"
13 #include "tapsets.h"
14 #include "session.h"
15 #include "util.h"
16
17 extern "C" {
18 #include <sys/utsname.h>
19 #include <fnmatch.h>
20 }
21
22 #include <algorithm>
23 #include <fstream>
24 #include <map>
25 #include <cassert>
26 #include <set>
27 #include <vector>
28 #include <algorithm>
29 #include <iterator>
30
31
32 using namespace std;
33
34
35 // ------------------------------------------------------------------------
36
37 // Used in probe_point condition construction. Either argument may be
38 // NULL; if both, return NULL too. Resulting expression is a deep
39 // copy for symbol resolution purposes.
40 expression* add_condition (expression* a, expression* b)
41 {
42 if (!a && !b) return 0;
43 if (! a) return deep_copy_visitor::deep_copy(b);
44 if (! b) return deep_copy_visitor::deep_copy(a);
45 logical_and_expr la;
46 la.op = "&&";
47 la.left = a;
48 la.right = b;
49 la.tok = a->tok; // or could be b->tok
50 return deep_copy_visitor::deep_copy(& la);
51 }
52
53 // ------------------------------------------------------------------------
54
55
56
57 derived_probe::derived_probe (probe *p):
58 base (p)
59 {
60 assert (p);
61 this->locations = p->locations;
62 this->tok = p->tok;
63 this->privileged = p->privileged;
64 this->body = deep_copy_visitor::deep_copy(p->body);
65 }
66
67
68 derived_probe::derived_probe (probe *p, probe_point *l):
69 base (p)
70 {
71 assert (p);
72 this->tok = p->tok;
73 this->privileged = p->privileged;
74 this->body = deep_copy_visitor::deep_copy(p->body);
75
76 assert (l);
77 this->locations.push_back (l);
78 }
79
80
81 void
82 derived_probe::printsig (ostream& o) const
83 {
84 probe::printsig (o);
85 printsig_nested (o);
86 }
87
88 void
89 derived_probe::printsig_nested (ostream& o) const
90 {
91 // We'd like to enclose the probe derivation chain in a /* */
92 // comment delimiter. But just printing /* base->printsig() */ is
93 // not enough, since base might itself be a derived_probe. So we,
94 // er, "cleverly" encode our nesting state as a formatting flag for
95 // the ostream.
96 ios::fmtflags f = o.flags (ios::internal);
97 if (f & ios::internal)
98 {
99 // already nested
100 o << " <- ";
101 base->printsig (o);
102 }
103 else
104 {
105 // outermost nesting
106 o << " /* <- ";
107 base->printsig (o);
108 o << " */";
109 }
110 // restore flags
111 (void) o.flags (f);
112 }
113
114
115 void
116 derived_probe::collect_derivation_chain (std::vector<probe*> &probes_list)
117 {
118 probes_list.push_back(this);
119 base->collect_derivation_chain(probes_list);
120 }
121
122
123 probe_point*
124 derived_probe::sole_location () const
125 {
126 if (locations.size() == 0)
127 throw semantic_error ("derived_probe with no locations", this->tok);
128 else if (locations.size() > 1)
129 throw semantic_error ("derived_probe with too many locations", this->tok);
130 else
131 return locations[0];
132 }
133
134
135
136 // ------------------------------------------------------------------------
137 // Members of derived_probe_builder
138
139 bool
140 derived_probe_builder::get_param (std::map<std::string, literal*> const & params,
141 const std::string& key,
142 std::string& value)
143 {
144 map<string, literal *>::const_iterator i = params.find (key);
145 if (i == params.end())
146 return false;
147 literal_string * ls = dynamic_cast<literal_string *>(i->second);
148 if (!ls)
149 return false;
150 value = ls->value;
151 return true;
152 }
153
154
155 bool
156 derived_probe_builder::get_param (std::map<std::string, literal*> const & params,
157 const std::string& key,
158 int64_t& value)
159 {
160 map<string, literal *>::const_iterator i = params.find (key);
161 if (i == params.end())
162 return false;
163 if (i->second == NULL)
164 return false;
165 literal_number * ln = dynamic_cast<literal_number *>(i->second);
166 if (!ln)
167 return false;
168 value = ln->value;
169 return true;
170 }
171
172
173 bool
174 derived_probe_builder::has_null_param (std::map<std::string, literal*> const & params,
175 const std::string& key)
176 {
177 map<string, literal *>::const_iterator i = params.find(key);
178 return (i != params.end() && i->second == NULL);
179 }
180
181
182
183 // ------------------------------------------------------------------------
184 // Members of match_key.
185
186 match_key::match_key(string const & n)
187 : name(n),
188 have_parameter(false),
189 parameter_type(pe_unknown)
190 {
191 }
192
193 match_key::match_key(probe_point::component const & c)
194 : name(c.functor),
195 have_parameter(c.arg != NULL),
196 parameter_type(c.arg ? c.arg->type : pe_unknown)
197 {
198 }
199
200 match_key &
201 match_key::with_number()
202 {
203 have_parameter = true;
204 parameter_type = pe_long;
205 return *this;
206 }
207
208 match_key &
209 match_key::with_string()
210 {
211 have_parameter = true;
212 parameter_type = pe_string;
213 return *this;
214 }
215
216 string
217 match_key::str() const
218 {
219 if (have_parameter)
220 switch (parameter_type)
221 {
222 case pe_string: return name + "(string)";
223 case pe_long: return name + "(number)";
224 default: return name + "(...)";
225 }
226 return name;
227 }
228
229 bool
230 match_key::operator<(match_key const & other) const
231 {
232 return ((name < other.name)
233
234 || (name == other.name
235 && have_parameter < other.have_parameter)
236
237 || (name == other.name
238 && have_parameter == other.have_parameter
239 && parameter_type < other.parameter_type));
240 }
241
242 static bool
243 isglob(string const & str)
244 {
245 return(str.find('*') != str.npos);
246 }
247
248 bool
249 match_key::globmatch(match_key const & other) const
250 {
251 const char *other_str = other.name.c_str();
252 const char *name_str = name.c_str();
253
254 return ((fnmatch(name_str, other_str, FNM_NOESCAPE) == 0)
255 && have_parameter == other.have_parameter
256 && parameter_type == other.parameter_type);
257 }
258
259 // ------------------------------------------------------------------------
260 // Members of match_node
261 // ------------------------------------------------------------------------
262
263 match_node::match_node()
264 : end(NULL)
265 {}
266
267 match_node *
268 match_node::bind(match_key const & k)
269 {
270 if (k.name == "*")
271 throw semantic_error("invalid use of wildcard probe point component");
272
273 map<match_key, match_node *>::const_iterator i = sub.find(k);
274 if (i != sub.end())
275 return i->second;
276 match_node * n = new match_node();
277 sub.insert(make_pair(k, n));
278 return n;
279 }
280
281 void
282 match_node::bind(derived_probe_builder * e)
283 {
284 if (end)
285 throw semantic_error("duplicate probe point pattern");
286 end = e;
287 }
288
289 match_node *
290 match_node::bind(string const & k)
291 {
292 return bind(match_key(k));
293 }
294
295 match_node *
296 match_node::bind_str(string const & k)
297 {
298 return bind(match_key(k).with_string());
299 }
300
301 match_node *
302 match_node::bind_num(string const & k)
303 {
304 return bind(match_key(k).with_number());
305 }
306
307
308 void
309 match_node::find_and_build (systemtap_session& s,
310 probe* p, probe_point *loc, unsigned pos,
311 vector<derived_probe *>& results)
312 {
313 assert (pos <= loc->components.size());
314 if (pos == loc->components.size()) // matched all probe point components so far
315 {
316 derived_probe_builder *b = end; // may be 0 if only nested names are bound
317
318 if (! b)
319 {
320 string alternatives;
321 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
322 alternatives += string(" ") + i->first.str();
323
324 throw semantic_error (string("probe point truncated at position ") +
325 lex_cast<string> (pos) +
326 " (follow:" + alternatives + ")", loc->tok);
327 }
328
329 map<string, literal *> param_map;
330 for (unsigned i=0; i<pos; i++)
331 param_map[loc->components[i]->functor] = loc->components[i]->arg;
332 // maybe 0
333
334 b->build (s, p, loc, param_map, results);
335 }
336 else if (isglob(loc->components[pos]->functor)) // wildcard?
337 {
338 match_key match (* loc->components[pos]);
339
340 // Call find_and_build for each possible match. Ignore errors -
341 // unless we don't find any match.
342 unsigned int num_results = results.size();
343 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
344 {
345 const match_key& subkey = i->first;
346 match_node* subnode = i->second;
347
348 if (pending_interrupts) break;
349
350 if (match.globmatch(subkey))
351 {
352 if (s.verbose > 2)
353 clog << "wildcard '" << loc->components[pos]->functor
354 << "' matched '" << subkey.name << "'" << endl;
355
356 // When we have a wildcard, we need to create a copy of
357 // the probe point. Then we'll create a copy of the
358 // wildcard component, and substitute the non-wildcard
359 // functor.
360 probe_point *non_wildcard_pp = new probe_point(*loc);
361 probe_point::component *non_wildcard_component
362 = new probe_point::component(*loc->components[pos]);
363 non_wildcard_component->functor = subkey.name;
364 non_wildcard_pp->components[pos] = non_wildcard_component;
365
366 // NB: probe conditions are not attached at the wildcard
367 // (component/functor) level, but at the overall
368 // probe_point level.
369
370 // recurse (with the non-wildcard probe point)
371 try
372 {
373 subnode->find_and_build (s, p, non_wildcard_pp, pos+1,
374 results);
375 }
376 catch (const semantic_error& e)
377 {
378 // Ignore semantic_errors while expanding wildcards.
379 // If we get done and nothing was expanded, the code
380 // following the loop will complain.
381
382 // If this wildcard didn't match, cleanup.
383 delete non_wildcard_pp;
384 delete non_wildcard_component;
385 }
386 }
387 }
388 if (! loc->optional && num_results == results.size())
389 {
390 // We didn't find any wildcard matches (since the size of
391 // the result vector didn't change). Throw an error.
392 string alternatives;
393 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
394 alternatives += string(" ") + i->first.str();
395
396 throw semantic_error(string("probe point mismatch at position ") +
397 lex_cast<string> (pos) +
398 " (alternatives:" + alternatives + ")",
399 loc->tok);
400 }
401 }
402 else
403 {
404 match_key match (* loc->components[pos]);
405 sub_map_iterator_t i = sub.find (match);
406 if (i == sub.end()) // no match
407 {
408 string alternatives;
409 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
410 alternatives += string(" ") + i->first.str();
411
412 throw semantic_error (string("probe point mismatch at position ") +
413 lex_cast<string> (pos) +
414 " (alternatives:" + alternatives + ")",
415 loc->tok);
416 }
417
418 match_node* subnode = i->second;
419 // recurse
420 subnode->find_and_build (s, p, loc, pos+1, results);
421 }
422 }
423
424
425 void
426 match_node::build_no_more (systemtap_session& s)
427 {
428 for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
429 i->second->build_no_more (s);
430 if (end) end->build_no_more (s);
431 }
432
433
434 // ------------------------------------------------------------------------
435 // Alias probes
436 // ------------------------------------------------------------------------
437
438 struct alias_derived_probe: public derived_probe
439 {
440 alias_derived_probe (probe* base, probe_point *l, const probe_alias *a):
441 derived_probe (base, l), alias(a) {}
442
443 void upchuck () { throw semantic_error ("inappropriate", this->tok); }
444
445 // Alias probes are immediately expanded to other derived_probe
446 // types, and are not themselves emitted or listed in
447 // systemtap_session.probes
448
449 void join_group (systemtap_session&) { upchuck (); }
450
451 virtual const probe_alias *get_alias () const { return alias; }
452
453 private:
454 const probe_alias *alias; // Used to check for recursion
455 };
456
457
458 struct
459 alias_expansion_builder
460 : public derived_probe_builder
461 {
462 probe_alias * alias;
463
464 alias_expansion_builder(probe_alias * a)
465 : alias(a)
466 {}
467
468 virtual void build(systemtap_session & sess,
469 probe * use,
470 probe_point * location,
471 std::map<std::string, literal *> const &,
472 vector<derived_probe *> & finished_results)
473 {
474 // Don't build the alias expansion if infinite recursion is detected.
475 if (checkForRecursiveExpansion (use)) {
476 stringstream msg;
477 msg << "Recursive loop in alias expansion of " << *location << " at " << location->tok->location;
478 // semantic_errors thrown here are ignored.
479 sess.print_error (semantic_error (msg.str()));
480 return;
481 }
482
483 // We're going to build a new probe and wrap it up in an
484 // alias_expansion_probe so that the expansion loop recognizes it as
485 // such and re-expands its expansion.
486
487 alias_derived_probe * n = new alias_derived_probe (use, location /* soon overwritten */, this->alias);
488 n->body = new block();
489
490 // The new probe gets the location list of the alias (with incoming condition joined)
491 n->locations = alias->locations;
492 for (unsigned i=0; i<n->locations.size(); i++)
493 n->locations[i]->condition = add_condition (n->locations[i]->condition,
494 location->condition);
495
496 // the token location of the alias,
497 n->tok = location->tok;
498
499 // and statements representing the concatenation of the alias'
500 // body with the use's.
501 //
502 // NB: locals are *not* copied forward, from either alias or
503 // use. The expansion should have its locals re-inferred since
504 // there's concatenated code here and we only want one vardecl per
505 // resulting variable.
506
507 if (alias->epilogue_style)
508 n->body = new block (use->body, alias->body);
509 else
510 n->body = new block (alias->body, use->body);
511
512 derive_probes (sess, n, finished_results, location->optional);
513 }
514
515 bool checkForRecursiveExpansion (probe *use)
516 {
517 // Collect the derivation chain of this probe.
518 vector<probe*>derivations;
519 use->collect_derivation_chain (derivations);
520
521 // Check all probe points in the alias expansion against the currently-being-expanded probe point
522 // of each of the probes in the derivation chain, looking for a match. This
523 // indicates infinite recursion.
524 // The first element of the derivation chain will be the derived_probe representing 'use', so
525 // start the search with the second element.
526 assert (derivations.size() > 0);
527 assert (derivations[0] == use);
528 for (unsigned d = 1; d < derivations.size(); ++d) {
529 if (use->get_alias() == derivations[d]->get_alias())
530 return true; // recursion detected
531 }
532 return false;
533 }
534 };
535
536
537 // ------------------------------------------------------------------------
538 // Pattern matching
539 // ------------------------------------------------------------------------
540
541
542 // Register all the aliases we've seen in library files, and the user
543 // file, as patterns.
544
545 void
546 systemtap_session::register_library_aliases()
547 {
548 vector<stapfile*> files(library_files);
549 files.push_back(user_file);
550
551 for (unsigned f = 0; f < files.size(); ++f)
552 {
553 stapfile * file = files[f];
554 for (unsigned a = 0; a < file->aliases.size(); ++a)
555 {
556 probe_alias * alias = file->aliases[a];
557 try
558 {
559 for (unsigned n = 0; n < alias->alias_names.size(); ++n)
560 {
561 probe_point * name = alias->alias_names[n];
562 match_node * n = pattern_root;
563 for (unsigned c = 0; c < name->components.size(); ++c)
564 {
565 probe_point::component * comp = name->components[c];
566 // XXX: alias parameters
567 if (comp->arg)
568 throw semantic_error("alias component "
569 + comp->functor
570 + " contains illegal parameter");
571 n = n->bind(comp->functor);
572 }
573 n->bind(new alias_expansion_builder(alias));
574 }
575 }
576 catch (const semantic_error& e)
577 {
578 semantic_error* er = new semantic_error (e); // copy it
579 stringstream msg;
580 msg << e.msg2;
581 msg << " while registering probe alias ";
582 alias->printsig(msg);
583 er->msg2 = msg.str();
584 print_error (* er);
585 delete er;
586 }
587 }
588 }
589 }
590
591
592 static unsigned max_recursion = 100;
593
594 struct
595 recursion_guard
596 {
597 unsigned & i;
598 recursion_guard(unsigned & i) : i(i)
599 {
600 if (i > max_recursion)
601 throw semantic_error("recursion limit reached");
602 ++i;
603 }
604 ~recursion_guard()
605 {
606 --i;
607 }
608 };
609
610 // The match-and-expand loop.
611 void
612 derive_probes (systemtap_session& s,
613 probe *p, vector<derived_probe*>& dps,
614 bool optional)
615 {
616 for (unsigned i = 0; i < p->locations.size(); ++i)
617 {
618 if (pending_interrupts) break;
619
620 probe_point *loc = p->locations[i];
621
622 try
623 {
624 unsigned num_atbegin = dps.size();
625
626 // Pass down optional flag from e.g. alias reference to each
627 // probe_point instance. We do this by temporarily overriding
628 // the probe_point optional flag. We could instead deep-copy
629 // and set a flag on the copy permanently.
630 bool old_loc_opt = loc->optional;
631 loc->optional = loc->optional || optional;
632 s.pattern_root->find_and_build (s, p, loc, 0, dps); // <-- actual derivation!
633 loc->optional = old_loc_opt;
634 unsigned num_atend = dps.size();
635
636 if (! (loc->optional||optional) && // something required, but
637 num_atbegin == num_atend) // nothing new derived!
638 throw semantic_error ("no match");
639
640 if (loc->sufficient && (num_atend > num_atbegin))
641 {
642 if (s.verbose > 1)
643 {
644 clog << "Probe point ";
645 p->locations[i]->print(clog);
646 clog << " sufficient, skipped";
647 for (unsigned j = i+1; j < p->locations.size(); ++j)
648 {
649 clog << " ";
650 p->locations[j]->print(clog);
651 }
652 clog << endl;
653 }
654 break; // we need not try to derive for any other locations
655 }
656 }
657 catch (const semantic_error& e)
658 {
659 // XXX: prefer not to print_error at every nest/unroll level
660
661 semantic_error* er = new semantic_error (e); // copy it
662 stringstream msg;
663 msg << e.msg2;
664 msg << " while resolving probe point " << *loc;
665 er->msg2 = msg.str();
666 s.print_error (* er);
667 delete er;
668 }
669
670 }
671 }
672
673
674
675 // ------------------------------------------------------------------------
676 //
677 // Indexable usage checks
678 //
679
680 struct symbol_fetcher
681 : public throwing_visitor
682 {
683 symbol *&sym;
684
685 symbol_fetcher (symbol *&sym): sym(sym)
686 {}
687
688 void visit_symbol (symbol* e)
689 {
690 sym = e;
691 }
692
693 void visit_target_symbol (target_symbol* e)
694 {
695 sym = e;
696 }
697
698 void visit_arrayindex (arrayindex* e)
699 {
700 e->base->visit_indexable (this);
701 }
702
703 void throwone (const token* t)
704 {
705 throw semantic_error ("Expecting symbol or array index expression", t);
706 }
707 };
708
709 symbol *
710 get_symbol_within_expression (expression *e)
711 {
712 symbol *sym = NULL;
713 symbol_fetcher fetcher(sym);
714 e->visit (&fetcher);
715 return sym; // NB: may be null!
716 }
717
718 static symbol *
719 get_symbol_within_indexable (indexable *ix)
720 {
721 symbol *array = NULL;
722 hist_op *hist = NULL;
723 classify_indexable(ix, array, hist);
724 if (array)
725 return array;
726 else
727 return get_symbol_within_expression (hist->stat);
728 }
729
730 struct mutated_var_collector
731 : public traversing_visitor
732 {
733 set<vardecl *> * mutated_vars;
734
735 mutated_var_collector (set<vardecl *> * mm)
736 : mutated_vars (mm)
737 {}
738
739 void visit_assignment(assignment* e)
740 {
741 if (e->type == pe_stats && e->op == "<<<")
742 {
743 vardecl *vd = get_symbol_within_expression (e->left)->referent;
744 if (vd)
745 mutated_vars->insert (vd);
746 }
747 traversing_visitor::visit_assignment(e);
748 }
749
750 void visit_arrayindex (arrayindex *e)
751 {
752 if (is_active_lvalue (e))
753 {
754 symbol *sym;
755 if (e->base->is_symbol (sym))
756 mutated_vars->insert (sym->referent);
757 else
758 throw semantic_error("Assignment to read-only histogram bucket", e->tok);
759 }
760 traversing_visitor::visit_arrayindex (e);
761 }
762 };
763
764
765 struct no_var_mutation_during_iteration_check
766 : public traversing_visitor
767 {
768 systemtap_session & session;
769 map<functiondecl *,set<vardecl *> *> & function_mutates_vars;
770 vector<vardecl *> vars_being_iterated;
771
772 no_var_mutation_during_iteration_check
773 (systemtap_session & sess,
774 map<functiondecl *,set<vardecl *> *> & fmv)
775 : session(sess), function_mutates_vars (fmv)
776 {}
777
778 void visit_arrayindex (arrayindex *e)
779 {
780 if (is_active_lvalue(e))
781 {
782 vardecl *vd = get_symbol_within_indexable (e->base)->referent;
783 if (vd)
784 {
785 for (unsigned i = 0; i < vars_being_iterated.size(); ++i)
786 {
787 vardecl *v = vars_being_iterated[i];
788 if (v == vd)
789 {
790 string err = ("variable '" + v->name +
791 "' modified during 'foreach' iteration");
792 session.print_error (semantic_error (err, e->tok));
793 }
794 }
795 }
796 }
797 traversing_visitor::visit_arrayindex (e);
798 }
799
800 void visit_functioncall (functioncall* e)
801 {
802 map<functiondecl *,set<vardecl *> *>::const_iterator i
803 = function_mutates_vars.find (e->referent);
804
805 if (i != function_mutates_vars.end())
806 {
807 for (unsigned j = 0; j < vars_being_iterated.size(); ++j)
808 {
809 vardecl *m = vars_being_iterated[j];
810 if (i->second->find (m) != i->second->end())
811 {
812 string err = ("function call modifies var '" + m->name +
813 "' during 'foreach' iteration");
814 session.print_error (semantic_error (err, e->tok));
815 }
816 }
817 }
818
819 traversing_visitor::visit_functioncall (e);
820 }
821
822 void visit_foreach_loop(foreach_loop* s)
823 {
824 vardecl *vd = get_symbol_within_indexable (s->base)->referent;
825
826 if (vd)
827 vars_being_iterated.push_back (vd);
828
829 traversing_visitor::visit_foreach_loop (s);
830
831 if (vd)
832 vars_being_iterated.pop_back();
833 }
834 };
835
836
837 // ------------------------------------------------------------------------
838
839 struct stat_decl_collector
840 : public traversing_visitor
841 {
842 systemtap_session & session;
843
844 stat_decl_collector(systemtap_session & sess)
845 : session(sess)
846 {}
847
848 void visit_stat_op (stat_op* e)
849 {
850 symbol *sym = get_symbol_within_expression (e->stat);
851 if (session.stat_decls.find(sym->name) == session.stat_decls.end())
852 session.stat_decls[sym->name] = statistic_decl();
853 }
854
855 void visit_assignment (assignment* e)
856 {
857 if (e->op == "<<<")
858 {
859 symbol *sym = get_symbol_within_expression (e->left);
860 if (session.stat_decls.find(sym->name) == session.stat_decls.end())
861 session.stat_decls[sym->name] = statistic_decl();
862 }
863 else
864 traversing_visitor::visit_assignment(e);
865 }
866
867 void visit_hist_op (hist_op* e)
868 {
869 symbol *sym = get_symbol_within_expression (e->stat);
870 statistic_decl new_stat;
871
872 if (e->htype == hist_linear)
873 {
874 new_stat.type = statistic_decl::linear;
875 assert (e->params.size() == 3);
876 new_stat.linear_low = e->params[0];
877 new_stat.linear_high = e->params[1];
878 new_stat.linear_step = e->params[2];
879 }
880 else
881 {
882 assert (e->htype == hist_log);
883 new_stat.type = statistic_decl::logarithmic;
884 assert (e->params.size() == 0);
885 }
886
887 map<string, statistic_decl>::iterator i = session.stat_decls.find(sym->name);
888 if (i == session.stat_decls.end())
889 session.stat_decls[sym->name] = new_stat;
890 else
891 {
892 statistic_decl & old_stat = i->second;
893 if (!(old_stat == new_stat))
894 {
895 if (old_stat.type == statistic_decl::none)
896 i->second = new_stat;
897 else
898 {
899 // FIXME: Support multiple co-declared histogram types
900 semantic_error se("multiple histogram types declared on '" + sym->name + "'",
901 e->tok);
902 session.print_error (se);
903 }
904 }
905 }
906 }
907
908 };
909
910 static int
911 semantic_pass_stats (systemtap_session & sess)
912 {
913 stat_decl_collector sdc(sess);
914
915 for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++)
916 it->second->body->visit (&sdc);
917
918 for (unsigned i = 0; i < sess.probes.size(); ++i)
919 sess.probes[i]->body->visit (&sdc);
920
921 for (unsigned i = 0; i < sess.globals.size(); ++i)
922 {
923 vardecl *v = sess.globals[i];
924 if (v->type == pe_stats)
925 {
926
927 if (sess.stat_decls.find(v->name) == sess.stat_decls.end())
928 {
929 semantic_error se("unable to infer statistic parameters for global '" + v->name + "'");
930 sess.print_error (se);
931 }
932 }
933 }
934
935 return sess.num_errors();
936 }
937
938 // ------------------------------------------------------------------------
939
940 // Enforce variable-related invariants: no modification of
941 // a foreach()-iterated array.
942 static int
943 semantic_pass_vars (systemtap_session & sess)
944 {
945
946 map<functiondecl *, set<vardecl *> *> fmv;
947 no_var_mutation_during_iteration_check chk(sess, fmv);
948
949 for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++)
950 {
951 functiondecl * fn = it->second;
952 if (fn->body)
953 {
954 set<vardecl *> * m = new set<vardecl *>();
955 mutated_var_collector mc (m);
956 fn->body->visit (&mc);
957 fmv[fn] = m;
958 }
959 }
960
961 for (map<string,functiondecl*>::iterator it = sess.functions.begin(); it != sess.functions.end(); it++)
962 {
963 functiondecl * fn = it->second;
964 if (fn->body) fn->body->visit (&chk);
965 }
966
967 for (unsigned i = 0; i < sess.probes.size(); ++i)
968 {
969 if (sess.probes[i]->body)
970 sess.probes[i]->body->visit (&chk);
971 }
972
973 return sess.num_errors();
974 }
975
976
977 // ------------------------------------------------------------------------
978
979 // Rewrite probe condition expressions into probe bodies. Tricky and
980 // exciting business, this. This:
981 //
982 // probe foo if (g1 || g2) { ... }
983 // probe bar { ... g1 ++ ... }
984 //
985 // becomes:
986 //
987 // probe begin(MAX) { if (! (g1 || g2)) %{ disable_probe_foo %} }
988 // probe foo { if (! (g1 || g2)) next; ... }
989 // probe bar { ... g1 ++ ...;
990 // if (g1 || g2) %{ enable_probe_foo %} else %{ disable_probe_foo %}
991 // }
992 //
993 // XXX: As a first cut, do only the "inline probe condition" part of the
994 // transform.
995
996 static int
997 semantic_pass_conditions (systemtap_session & sess)
998 {
999 for (unsigned i = 0; i < sess.probes.size(); ++i)
1000 {
1001 derived_probe* p = sess.probes[i];
1002 expression* e = p->sole_location()->condition;
1003 if (e)
1004 {
1005 varuse_collecting_visitor vut;
1006 e->visit (& vut);
1007
1008 if (! vut.written.empty())
1009 {
1010 string err = ("probe condition must not modify any variables");
1011 sess.print_error (semantic_error (err, e->tok));
1012 }
1013 else if (vut.embedded_seen)
1014 {
1015 sess.print_error (semantic_error ("probe condition must not include impure embedded-C", e->tok));
1016 }
1017
1018 // Add the condition expression to the front of the
1019 // derived_probe body.
1020 if_statement *ifs = new if_statement ();
1021 ifs->tok = e->tok;
1022 ifs->thenblock = new next_statement ();
1023 ifs->thenblock->tok = e->tok;
1024 ifs->elseblock = NULL;
1025 unary_expression *notex = new unary_expression ();
1026 notex->op = "!";
1027 notex->tok = e->tok;
1028 notex->operand = e;
1029 ifs->condition = notex;
1030 p->body = new block (ifs, p->body);
1031 }
1032 }
1033
1034 return sess.num_errors();
1035 }
1036
1037
1038 // ------------------------------------------------------------------------
1039
1040
1041 static int semantic_pass_symbols (systemtap_session&);
1042 static int semantic_pass_optimize1 (systemtap_session&);
1043 static int semantic_pass_optimize2 (systemtap_session&);
1044 static int semantic_pass_types (systemtap_session&);
1045 static int semantic_pass_vars (systemtap_session&);
1046 static int semantic_pass_stats (systemtap_session&);
1047 static int semantic_pass_conditions (systemtap_session&);
1048
1049
1050 // Link up symbols to their declarations. Set the session's
1051 // files/probes/functions/globals vectors from the transitively
1052 // reached set of stapfiles in s.library_files, starting from
1053 // s.user_file. Perform automatic tapset inclusion and probe
1054 // alias expansion.
1055 static int
1056 semantic_pass_symbols (systemtap_session& s)
1057 {
1058 symresolution_info sym (s);
1059
1060 // NB: s.files can grow during this iteration, so size() can
1061 // return gradually increasing numbers.
1062 s.files.push_back (s.user_file);
1063 for (unsigned i = 0; i < s.files.size(); i++)
1064 {
1065 if (pending_interrupts) break;
1066 stapfile* dome = s.files[i];
1067
1068 // Pass 1: add globals and functions to systemtap-session master list,
1069 // so the find_* functions find them
1070
1071 for (unsigned i=0; i<dome->globals.size(); i++)
1072 s.globals.push_back (dome->globals[i]);
1073
1074 for (unsigned i=0; i<dome->functions.size(); i++)
1075 s.functions[dome->functions[i]->name] = dome->functions[i];
1076
1077 for (unsigned i=0; i<dome->embeds.size(); i++)
1078 s.embeds.push_back (dome->embeds[i]);
1079
1080 // Pass 2: process functions
1081
1082 for (unsigned i=0; i<dome->functions.size(); i++)
1083 {
1084 if (pending_interrupts) break;
1085 functiondecl* fd = dome->functions[i];
1086
1087 try
1088 {
1089 sym.current_function = fd;
1090 sym.current_probe = 0;
1091 fd->body->visit (& sym);
1092 }
1093 catch (const semantic_error& e)
1094 {
1095 s.print_error (e);
1096 }
1097 }
1098
1099 // Pass 3: derive probes and resolve any further symbols in the
1100 // derived results.
1101
1102 for (unsigned i=0; i<dome->probes.size(); i++)
1103 {
1104 if (pending_interrupts) break;
1105 probe* p = dome->probes [i];
1106 vector<derived_probe*> dps;
1107
1108 // much magic happens here: probe alias expansion, wildcard
1109 // matching, low-level derived_probe construction.
1110 derive_probes (s, p, dps);
1111
1112 for (unsigned j=0; j<dps.size(); j++)
1113 {
1114 if (pending_interrupts) break;
1115 derived_probe* dp = dps[j];
1116 s.probes.push_back (dp);
1117 dp->join_group (s);
1118
1119 try
1120 {
1121 sym.current_function = 0;
1122 sym.current_probe = dp;
1123 dp->body->visit (& sym);
1124
1125 // Process the probe-point condition expression.
1126 sym.current_function = 0;
1127 sym.current_probe = 0;
1128 if (dp->sole_location()->condition)
1129 dp->sole_location()->condition->visit (& sym);
1130 }
1131 catch (const semantic_error& e)
1132 {
1133 s.print_error (e);
1134 }
1135 }
1136 }
1137 }
1138
1139 // Inform all derived_probe builders that we're done with
1140 // all resolution, so it's time to release caches.
1141 s.pattern_root->build_no_more (s);
1142
1143 return s.num_errors(); // all those print_error calls
1144 }
1145
1146
1147 // Keep unread global variables for probe end value display.
1148 void add_global_var_display (systemtap_session& s)
1149 {
1150 varuse_collecting_visitor vut;
1151 for (unsigned i=0; i<s.probes.size(); i++)
1152 {
1153 s.probes[i]->body->visit (& vut);
1154
1155 if (s.probes[i]->sole_location()->condition)
1156 s.probes[i]->sole_location()->condition->visit (& vut);
1157 }
1158
1159 for (unsigned g=0; g < s.globals.size(); g++)
1160 {
1161 vardecl* l = s.globals[g];
1162 if (vut.read.find (l) != vut.read.end()
1163 || vut.written.find (l) == vut.written.end())
1164 continue;
1165
1166 print_format* pf = new print_format;
1167 probe* p = new probe;
1168 probe_point* pl = new probe_point;
1169 probe_point::component* c = new probe_point::component("end");
1170 token* print_tok = new token;
1171 vector<derived_probe*> dps;
1172 block *b = new block;
1173
1174 pl->components.push_back (c);
1175 p->tok = l->tok;
1176 p->locations.push_back (pl);
1177 print_tok->type = tok_identifier;
1178 print_tok->content = "printf";
1179
1180 // Create a symbol
1181 symbol* g_sym = new symbol;
1182 g_sym->name = l->name;
1183 g_sym->tok = l->tok;
1184 g_sym->type = l->type;
1185 g_sym->referent = l;
1186
1187 pf->print_to_stream = true;
1188 pf->print_with_format = true;
1189 pf->print_with_delim = false;
1190 pf->print_with_newline = false;
1191 pf->print_char = false;
1192 pf->raw_components += l->name;
1193 pf->tok = print_tok;
1194
1195 if (l->index_types.size() == 0) // Scalar
1196 {
1197 if (l->type == pe_stats)
1198 pf->raw_components += " @count=%#x @min=%#x @max=%#x @sum=%#x @avg=%#x\\n";
1199 else if (l->type == pe_string)
1200 pf->raw_components += "=\"%#s\"\\n";
1201 else
1202 pf->raw_components += "=%#x\\n";
1203 pf->components = print_format::string_to_components(pf->raw_components);
1204 expr_statement* feb = new expr_statement;
1205 feb->value = pf;
1206 feb->tok = print_tok;
1207 if (l->type == pe_stats)
1208 {
1209 struct stat_op* so [5];
1210 const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average};
1211
1212 for (unsigned si = 0;
1213 si < (sizeof(so)/sizeof(struct stat_op*));
1214 si++)
1215 {
1216 so[si]= new stat_op;
1217 so[si]->ctype = stypes[si];
1218 so[si]->type = pe_long;
1219 so[si]->stat = g_sym;
1220 so[si]->tok = l->tok;
1221 pf->args.push_back(so[si]);
1222 }
1223 }
1224 else
1225 pf->args.push_back(g_sym);
1226 b->statements.push_back(feb);
1227 }
1228 else // Array
1229 {
1230 int idx_count = l->index_types.size();
1231 symbol* idx_sym[idx_count];
1232 vardecl* idx_v[idx_count];
1233 // Create a foreach loop
1234 foreach_loop* fe = new foreach_loop;
1235 fe->sort_direction = 0;
1236 fe->limit = NULL;
1237
1238 // Create indices for the foreach loop
1239 for (int i=0; i < idx_count; i++)
1240 {
1241 char *idx_name;
1242 if (asprintf (&idx_name, "idx%d", i) < 0)
1243 return;
1244 idx_sym[i] = new symbol;
1245 idx_sym[i]->name = idx_name;
1246 idx_sym[i]->tok = l->tok;
1247 idx_v[i] = new vardecl;
1248 idx_v[i]->name = idx_name;
1249 idx_v[i]->type = l->index_types[i];
1250 idx_v[i]->tok = l->tok;
1251 idx_sym[i]->referent = idx_v[i];
1252 fe->indexes.push_back (idx_sym[i]);
1253 }
1254
1255 // Create a printf for the foreach loop
1256 pf->raw_components += "[";
1257 for (int i=0; i < idx_count; i++)
1258 {
1259 if (i > 0)
1260 pf->raw_components += ",";
1261 if (l->index_types[i] == pe_string)
1262 pf->raw_components += "\"%#s\"";
1263 else
1264 pf->raw_components += "%#d";
1265 }
1266 pf->raw_components += "]";
1267 if (l->type == pe_stats)
1268 pf->raw_components += " @count=%#x @min=%#x @max=%#x @sum=%#x @avg=%#x\\n";
1269 else if (l->type == pe_string)
1270 pf->raw_components += "=\"%#s\"\\n";
1271 else
1272 pf->raw_components += "=%#x\\n";
1273
1274 // Create an index for the array
1275 struct arrayindex* ai = new arrayindex;
1276 ai->tok = l->tok;
1277 ai->base = g_sym;
1278
1279 for (int i=0; i < idx_count; i++)
1280 {
1281 ai->indexes.push_back (idx_sym[i]);
1282 pf->args.push_back(idx_sym[i]);
1283 }
1284 if (l->type == pe_stats)
1285 {
1286 struct stat_op* so [5];
1287 const stat_component_type stypes[] = {sc_count, sc_min, sc_max, sc_sum, sc_average};
1288
1289 ai->type = pe_stats;
1290 for (unsigned si = 0;
1291 si < (sizeof(so)/sizeof(struct stat_op*));
1292 si++)
1293 {
1294 so[si]= new stat_op;
1295 so[si]->ctype = stypes[si];
1296 so[si]->type = pe_long;
1297 so[si]->stat = ai;
1298 so[si]->tok = l->tok;
1299 pf->args.push_back(so[si]);
1300 }
1301 }
1302 else
1303 pf->args.push_back(ai);
1304
1305 pf->components = print_format::string_to_components(pf->raw_components);
1306 expr_statement* feb = new expr_statement;
1307 feb->value = pf;
1308 fe->base = g_sym;
1309 fe->block = (statement*)feb;
1310 b->statements.push_back(fe);
1311 }
1312
1313 // Add created probe
1314 p->body = b;
1315 derive_probes (s, p, dps);
1316 for (unsigned i = 0; i < dps.size(); i++)
1317 {
1318 derived_probe* dp = dps[i];
1319 s.probes.push_back (dp);
1320 dp->join_group (s);
1321 }
1322 // Repopulate symbol and type info
1323 symresolution_info sym (s);
1324 sym.current_function = 0;
1325 sym.current_probe = dps[0];
1326 dps[0]->body->visit (& sym);
1327
1328 semantic_pass_types(s);
1329 // Mark that variable is read
1330 vut.read.insert (l);
1331 }
1332 }
1333
1334 int
1335 semantic_pass (systemtap_session& s)
1336 {
1337 int rc = 0;
1338
1339 try
1340 {
1341 s.register_library_aliases();
1342 register_standard_tapsets(s);
1343
1344 if (rc == 0) rc = semantic_pass_symbols (s);
1345 if (rc == 0) rc = semantic_pass_conditions (s);
1346 if (rc == 0 && ! s.unoptimized) rc = semantic_pass_optimize1 (s);
1347 if (rc == 0) rc = semantic_pass_types (s);
1348 if (rc == 0) add_global_var_display (s);
1349 if (rc == 0 && ! s.unoptimized) rc = semantic_pass_optimize2 (s);
1350 if (rc == 0) rc = semantic_pass_vars (s);
1351 if (rc == 0) rc = semantic_pass_stats (s);
1352
1353 if (s.probes.size() == 0 && !s.listing_mode)
1354 throw semantic_error ("no probes found");
1355 }
1356 catch (const semantic_error& e)
1357 {
1358 s.print_error (e);
1359 rc ++;
1360 }
1361
1362 return rc;
1363 }
1364
1365
1366 // ------------------------------------------------------------------------
1367
1368
1369 systemtap_session::systemtap_session ():
1370 // NB: pointer members must be manually initialized!
1371 pattern_root(new match_node),
1372 user_file (0),
1373 be_derived_probes(0),
1374 dwarf_derived_probes(0),
1375 uprobe_derived_probes(0),
1376 utrace_derived_probes(0),
1377 itrace_derived_probes(0),
1378 task_finder_derived_probes(0),
1379 timer_derived_probes(0),
1380 profile_derived_probes(0),
1381 mark_derived_probes(0),
1382 hrtimer_derived_probes(0),
1383 perfmon_derived_probes(0),
1384 procfs_derived_probes(0),
1385 op (0), up (0),
1386 sym_kprobes_text_start (0),
1387 sym_kprobes_text_end (0),
1388 sym_stext (0),
1389 module_cache (0),
1390 last_token (0)
1391 {
1392 }
1393
1394
1395 // Print this given token, but abbreviate it if the last one had the
1396 // same file name.
1397 void
1398 systemtap_session::print_token (ostream& o, const token* tok)
1399 {
1400 assert (tok);
1401
1402 if (last_token && last_token->location.file == tok->location.file)
1403 {
1404 stringstream tmpo;
1405 tmpo << *tok;
1406 string ts = tmpo.str();
1407 // search & replace the file name with nothing
1408 size_t idx = ts.find (tok->location.file);
1409 if (idx != string::npos)
1410 ts.replace (idx, tok->location.file.size(), "");
1411
1412 o << ts;
1413 }
1414 else
1415 o << *tok;
1416
1417 last_token = tok;
1418 }
1419
1420
1421
1422 void
1423 systemtap_session::print_error (const semantic_error& e)
1424 {
1425 string message_str;
1426 stringstream message;
1427
1428 // NB: we don't print error messages during listing mode.
1429 if (listing_mode) return;
1430
1431 message << "semantic error: " << e.what ();
1432 if (e.tok1 || e.tok2)
1433 message << ": ";
1434 if (e.tok1) print_token (message, e.tok1);
1435 message << e.msg2;
1436 if (e.tok2) print_token (message, e.tok2);
1437 message << endl;
1438 message_str = message.str();
1439
1440 // Duplicate elimination
1441 if (seen_errors.find (message_str) == seen_errors.end())
1442 {
1443 seen_errors.insert (message_str);
1444 cerr << message_str;
1445 }
1446
1447 if (e.chain)
1448 print_error (* e.chain);
1449 }
1450
1451 void
1452 systemtap_session::print_warning (const string& message_str, const token* tok)
1453 {
1454 // Duplicate elimination
1455 if (seen_warnings.find (message_str) == seen_warnings.end())
1456 {
1457 seen_warnings.insert (message_str);
1458 clog << "WARNING: " << message_str;
1459 if (tok) { clog << ": "; print_token (clog, tok); }
1460 clog << endl;
1461 }
1462 }
1463
1464
1465 // ------------------------------------------------------------------------
1466 // semantic processing: symbol resolution
1467
1468
1469 symresolution_info::symresolution_info (systemtap_session& s):
1470 session (s), current_function (0), current_probe (0)
1471 {
1472 }
1473
1474
1475 void
1476 symresolution_info::visit_block (block* e)
1477 {
1478 for (unsigned i=0; i<e->statements.size(); i++)
1479 {
1480 try
1481 {
1482 e->statements[i]->visit (this);
1483 }
1484 catch (const semantic_error& e)
1485 {
1486 session.print_error (e);
1487 }
1488 }
1489 }
1490
1491
1492 void
1493 symresolution_info::visit_foreach_loop (foreach_loop* e)
1494 {
1495 for (unsigned i=0; i<e->indexes.size(); i++)
1496 e->indexes[i]->visit (this);
1497
1498 symbol *array = NULL;
1499 hist_op *hist = NULL;
1500 classify_indexable (e->base, array, hist);
1501
1502 if (array)
1503 {
1504 if (!array->referent)
1505 {
1506 vardecl* d = find_var (array->name, e->indexes.size ());
1507 if (d)
1508 array->referent = d;
1509 else
1510 {
1511 stringstream msg;
1512 msg << "unresolved arity-" << e->indexes.size()
1513 << " global array " << array->name;
1514 throw semantic_error (msg.str(), e->tok);
1515 }
1516 }
1517 }
1518 else
1519 {
1520 assert (hist);
1521 hist->visit (this);
1522 }
1523
1524 if (e->limit)
1525 e->limit->visit (this);
1526
1527 e->block->visit (this);
1528 }
1529
1530
1531 struct
1532 delete_statement_symresolution_info:
1533 public traversing_visitor
1534 {
1535 symresolution_info *parent;
1536
1537 delete_statement_symresolution_info (symresolution_info *p):
1538 parent(p)
1539 {}
1540
1541 void visit_arrayindex (arrayindex* e)
1542 {
1543 parent->visit_arrayindex (e);
1544 }
1545 void visit_functioncall (functioncall* e)
1546 {
1547 parent->visit_functioncall (e);
1548 }
1549
1550 void visit_symbol (symbol* e)
1551 {
1552 if (e->referent)
1553 return;
1554
1555 vardecl* d = parent->find_var (e->name, -1);
1556 if (d)
1557 e->referent = d;
1558 else
1559 throw semantic_error ("unresolved array in delete statement", e->tok);
1560 }
1561 };
1562
1563 void
1564 symresolution_info::visit_delete_statement (delete_statement* s)
1565 {
1566 delete_statement_symresolution_info di (this);
1567 s->value->visit (&di);
1568 }
1569
1570
1571 void
1572 symresolution_info::visit_symbol (symbol* e)
1573 {
1574 if (e->referent)
1575 return;
1576
1577 vardecl* d = find_var (e->name, 0);
1578 if (d)
1579 e->referent = d;
1580 else
1581 {
1582 // new local
1583 vardecl* v = new vardecl;
1584 v->name = e->name;
1585 v->tok = e->tok;
1586 if (current_function)
1587 current_function->locals.push_back (v);
1588 else if (current_probe)
1589 current_probe->locals.push_back (v);
1590 else
1591 // must be probe-condition expression
1592 throw semantic_error ("probe condition must not reference undeclared global", e->tok);
1593 e->referent = v;
1594 }
1595 }
1596
1597
1598 void
1599 symresolution_info::visit_arrayindex (arrayindex* e)
1600 {
1601 for (unsigned i=0; i<e->indexes.size(); i++)
1602 e->indexes[i]->visit (this);
1603
1604 symbol *array = NULL;
1605 hist_op *hist = NULL;
1606 classify_indexable(e->base, array, hist);
1607
1608 if (array)
1609 {
1610 if (array->referent)
1611 return;
1612
1613 vardecl* d = find_var (array->name, e->indexes.size ());
1614 if (d)
1615 array->referent = d;
1616 else
1617 {
1618 // new local
1619 vardecl* v = new vardecl;
1620 v->set_arity(e->indexes.size());
1621 v->name = array->name;
1622 v->tok = array->tok;
1623 if (current_function)
1624 current_function->locals.push_back (v);
1625 else if (current_probe)
1626 current_probe->locals.push_back (v);
1627 else
1628 // must not happen
1629 throw semantic_error ("no current probe/function", e->tok);
1630 array->referent = v;
1631 }
1632 }
1633 else
1634 {
1635 assert (hist);
1636 hist->visit (this);
1637 }
1638 }
1639
1640
1641 void
1642 symresolution_info::visit_functioncall (functioncall* e)
1643 {
1644 // XXX: we could relax this, if we're going to examine the
1645 // vartracking data recursively. See testsuite/semko/fortytwo.stp.
1646 if (! (current_function || current_probe))
1647 {
1648 // must be probe-condition expression
1649 throw semantic_error ("probe condition must not reference function", e->tok);
1650 }
1651
1652 for (unsigned i=0; i<e->args.size(); i++)
1653 e->args[i]->visit (this);
1654
1655 if (e->referent)
1656 return;
1657
1658 functiondecl* d = find_function (e->function, e->args.size ());
1659 if (d)
1660 e->referent = d;
1661 else
1662 {
1663 stringstream msg;
1664 msg << "unresolved arity-" << e->args.size()
1665 << " function";
1666 throw semantic_error (msg.str(), e->tok);
1667 }
1668 }
1669
1670
1671 vardecl*
1672 symresolution_info::find_var (const string& name, int arity)
1673 {
1674 if (current_function || current_probe)
1675 {
1676 // search locals
1677 vector<vardecl*>& locals = (current_function ?
1678 current_function->locals :
1679 current_probe->locals);
1680
1681
1682 for (unsigned i=0; i<locals.size(); i++)
1683 if (locals[i]->name == name
1684 && locals[i]->compatible_arity(arity))
1685 {
1686 locals[i]->set_arity (arity);
1687 return locals[i];
1688 }
1689 }
1690
1691 // search function formal parameters (for scalars)
1692 if (arity == 0 && current_function)
1693 for (unsigned i=0; i<current_function->formal_args.size(); i++)
1694 if (current_function->formal_args[i]->name == name)
1695 {
1696 // NB: no need to check arity here: formal args always scalar
1697 current_function->formal_args[i]->set_arity (0);
1698 return current_function->formal_args[i];
1699 }
1700
1701 // search processed globals
1702 for (unsigned i=0; i<session.globals.size(); i++)
1703 if (session.globals[i]->name == name
1704 && session.globals[i]->compatible_arity(arity))
1705 {
1706 session.globals[i]->set_arity (arity);
1707 return session.globals[i];
1708 }
1709
1710 // search library globals
1711 for (unsigned i=0; i<session.library_files.size(); i++)
1712 {
1713 stapfile* f = session.library_files[i];
1714 for (unsigned j=0; j<f->globals.size(); j++)
1715 {
1716 vardecl* g = f->globals[j];
1717 if (g->name == name && g->compatible_arity (arity))
1718 {
1719 g->set_arity (arity);
1720
1721 // put library into the queue if not already there
1722 if (find (session.files.begin(), session.files.end(), f)
1723 == session.files.end())
1724 session.files.push_back (f);
1725
1726 return g;
1727 }
1728 }
1729 }
1730
1731 return 0;
1732 }
1733
1734
1735 functiondecl*
1736 symresolution_info::find_function (const string& name, unsigned arity)
1737 {
1738 // the common path
1739 if (session.functions.find(name) != session.functions.end())
1740 {
1741 functiondecl* fd = session.functions[name];
1742 assert (fd->name == name);
1743 if (fd->formal_args.size() == arity)
1744 return fd;
1745 }
1746
1747 // search library globals
1748 for (unsigned i=0; i<session.library_files.size(); i++)
1749 {
1750 stapfile* f = session.library_files[i];
1751 for (unsigned j=0; j<f->functions.size(); j++)
1752 if (f->functions[j]->name == name &&
1753 f->functions[j]->formal_args.size() == arity)
1754 {
1755 // put library into the queue if not already there
1756 if (0) // session.verbose_resolution
1757 cerr << " function " << name << " "
1758 << "is defined from " << f->name << endl;
1759
1760 if (find (session.files.begin(), session.files.end(), f)
1761 == session.files.end())
1762 session.files.push_back (f);
1763 // else .. print different message?
1764
1765 return f->functions[j];
1766 }
1767 }
1768
1769 return 0;
1770 }
1771
1772
1773
1774 // ------------------------------------------------------------------------
1775 // optimization
1776
1777
1778 // Do away with functiondecls that are never (transitively) called
1779 // from probes.
1780 void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p)
1781 {
1782 functioncall_traversing_visitor ftv;
1783 for (unsigned i=0; i<s.probes.size(); i++)
1784 {
1785 s.probes[i]->body->visit (& ftv);
1786 if (s.probes[i]->sole_location()->condition)
1787 s.probes[i]->sole_location()->condition->visit (& ftv);
1788 }
1789 vector<functiondecl*> new_unused_functions;
1790 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
1791 {
1792 functiondecl* fd = it->second;
1793 if (ftv.traversed.find(fd) == ftv.traversed.end())
1794 {
1795 if (fd->tok->location.file == s.user_file->name && // !tapset
1796 ! s.suppress_warnings)
1797 s.print_warning ("eliding unused function '" + fd->name + "'", fd->tok);
1798 else if (s.verbose>2)
1799 clog << "Eliding unused function " << fd->name
1800 << endl;
1801 // s.functions.erase (it); // NB: can't, since we're already iterating upon it
1802 new_unused_functions.push_back (fd);
1803 relaxed_p = false;
1804 }
1805 }
1806 for (unsigned i=0; i<new_unused_functions.size(); i++)
1807 {
1808 map<string,functiondecl*>::iterator where = s.functions.find (new_unused_functions[i]->name);
1809 assert (where != s.functions.end());
1810 s.functions.erase (where);
1811 if (s.tapset_compile_coverage)
1812 s.unused_functions.push_back (new_unused_functions[i]);
1813 }
1814 }
1815
1816
1817 // ------------------------------------------------------------------------
1818
1819 // Do away with local & global variables that are never
1820 // written nor read.
1821 void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterations)
1822 {
1823 varuse_collecting_visitor vut;
1824
1825 for (unsigned i=0; i<s.probes.size(); i++)
1826 {
1827 s.probes[i]->body->visit (& vut);
1828
1829 if (s.probes[i]->sole_location()->condition)
1830 s.probes[i]->sole_location()->condition->visit (& vut);
1831 }
1832
1833 // NB: Since varuse_collecting_visitor also traverses down
1834 // actually called functions, we don't need to explicitly
1835 // iterate over them. Uncalled ones should have been pruned
1836 // in _opt1 above.
1837 //
1838 // for (unsigned i=0; i<s.functions.size(); i++)
1839 // s.functions[i]->body->visit (& vut);
1840
1841 // Now in vut.read/written, we have a mixture of all locals, globals
1842
1843 for (unsigned i=0; i<s.probes.size(); i++)
1844 for (unsigned j=0; j<s.probes[i]->locals.size(); /* see below */)
1845 {
1846 vardecl* l = s.probes[i]->locals[j];
1847
1848 if (vut.read.find (l) == vut.read.end() &&
1849 vut.written.find (l) == vut.written.end())
1850 {
1851 if (l->tok->location.file == s.user_file->name && // !tapset
1852 ! s.suppress_warnings)
1853 s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
1854 else if (s.verbose>2)
1855 clog << "Eliding unused local variable "
1856 << l->name << " in " << s.probes[i]->name << endl;
1857 if (s.tapset_compile_coverage) {
1858 s.probes[i]->unused_locals.push_back
1859 (s.probes[i]->locals[j]);
1860 }
1861 s.probes[i]->locals.erase(s.probes[i]->locals.begin() + j);
1862 relaxed_p = false;
1863 // don't increment j
1864 }
1865 else
1866 {
1867 if (vut.written.find (l) == vut.written.end())
1868 if (iterations == 0 && ! s.suppress_warnings)
1869 {
1870 stringstream o;
1871 vector<vardecl*>::iterator it;
1872 for (it = s.probes[i]->locals.begin(); it != s.probes[i]->locals.end(); it++)
1873 if (l->name != (*it)->name)
1874 o << " " << (*it)->name;
1875 for (it = s.globals.begin(); it != s.globals.end(); it++)
1876 if (l->name != (*it)->name)
1877 o << " " << (*it)->name;
1878
1879 s.print_warning ("read-only local variable '" + l->name + "' " +
1880 (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok);
1881 }
1882 j++;
1883 }
1884 }
1885
1886 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
1887 {
1888 functiondecl *fd = it->second;
1889 for (unsigned j=0; j<fd->locals.size(); /* see below */)
1890 {
1891 vardecl* l = fd->locals[j];
1892 if (vut.read.find (l) == vut.read.end() &&
1893 vut.written.find (l) == vut.written.end())
1894 {
1895 if (l->tok->location.file == s.user_file->name && // !tapset
1896 ! s.suppress_warnings)
1897 s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
1898 else if (s.verbose>2)
1899 clog << "Eliding unused local variable "
1900 << l->name << " in function " << fd->name
1901 << endl;
1902 if (s.tapset_compile_coverage) {
1903 fd->unused_locals.push_back (fd->locals[j]);
1904 }
1905 fd->locals.erase(fd->locals.begin() + j);
1906 relaxed_p = false;
1907 // don't increment j
1908 }
1909 else
1910 {
1911 if (vut.written.find (l) == vut.written.end())
1912 if (iterations == 0 && ! s.suppress_warnings)
1913 {
1914 stringstream o;
1915 vector<vardecl*>::iterator it;
1916 for (it = fd->formal_args.begin() ;
1917 it != fd->formal_args.end(); it++)
1918 if (l->name != (*it)->name)
1919 o << " " << (*it)->name;
1920 for (it = fd->locals.begin(); it != fd->locals.end(); it++)
1921 if (l->name != (*it)->name)
1922 o << " " << (*it)->name;
1923 for (it = s.globals.begin(); it != s.globals.end(); it++)
1924 if (l->name != (*it)->name)
1925 o << " " << (*it)->name;
1926
1927 s.print_warning ("read-only local variable '" + l->name + "' " +
1928 (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok);
1929 }
1930
1931 j++;
1932 }
1933 }
1934 }
1935 for (unsigned i=0; i<s.globals.size(); /* see below */)
1936 {
1937 vardecl* l = s.globals[i];
1938 if (vut.read.find (l) == vut.read.end() &&
1939 vut.written.find (l) == vut.written.end())
1940 {
1941 if (l->tok->location.file == s.user_file->name && // !tapset
1942 ! s.suppress_warnings)
1943 s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
1944 else if (s.verbose>2)
1945 clog << "Eliding unused global variable "
1946 << l->name << endl;
1947 if (s.tapset_compile_coverage) {
1948 s.unused_globals.push_back(s.globals[i]);
1949 }
1950 s.globals.erase(s.globals.begin() + i);
1951 relaxed_p = false;
1952 // don't increment i
1953 }
1954 else
1955 {
1956 if (vut.written.find (l) == vut.written.end() && ! l->init) // no initializer
1957 if (iterations == 0 && ! s.suppress_warnings)
1958 {
1959 stringstream o;
1960 vector<vardecl*>::iterator it;
1961 for (it = s.globals.begin(); it != s.globals.end(); it++)
1962 if (l->name != (*it)->name)
1963 o << " " << (*it)->name;
1964
1965 s.print_warning ("read-only global variable '" + l->name + "' " +
1966 (o.str() == "" ? "" : ("(alternatives:" + o.str() + ")")), l->tok);
1967 }
1968
1969 i++;
1970 }
1971 }
1972 }
1973
1974
1975 // ------------------------------------------------------------------------
1976
1977 struct dead_assignment_remover: public traversing_visitor
1978 {
1979 systemtap_session& session;
1980 bool& relaxed_p;
1981 const varuse_collecting_visitor& vut;
1982 expression** current_expr;
1983
1984 dead_assignment_remover(systemtap_session& s, bool& r,
1985 const varuse_collecting_visitor& v):
1986 session(s), relaxed_p(r), vut(v), current_expr(0) {}
1987
1988 void visit_expr_statement (expr_statement* s);
1989 // XXX: other places where an assignment may be nested should be
1990 // handled too (e.g., loop/if conditionals, array indexes, function
1991 // parameters). Until then, they result in visit_assignment() being
1992 // called with null current_expr.
1993
1994 void visit_assignment (assignment* e);
1995 void visit_binary_expression (binary_expression* e);
1996 void visit_arrayindex (arrayindex* e);
1997 void visit_functioncall (functioncall* e);
1998 void visit_if_statement (if_statement* e);
1999 void visit_for_loop (for_loop* e);
2000 };
2001
2002
2003 void
2004 dead_assignment_remover::visit_expr_statement (expr_statement* s)
2005 {
2006 expression** last_expr = current_expr;
2007 current_expr = & s->value;
2008 s->value->visit (this);
2009 s->tok = s->value->tok; // in case it was replaced
2010 current_expr = last_expr;
2011 }
2012
2013
2014 void
2015 dead_assignment_remover::visit_assignment (assignment* e)
2016 {
2017 symbol* left = get_symbol_within_expression (e->left);
2018 vardecl* leftvar = left->referent; // NB: may be 0 for unresolved $target
2019 if (current_expr && // see XXX above: this case represents a missed
2020 // optimization opportunity
2021 *current_expr == e && // we're not nested any deeper than expected
2022 leftvar) // not unresolved $target; intended sideeffect cannot be elided
2023 {
2024 expression** last_expr = current_expr;
2025 e->left->visit (this);
2026 current_expr = &e->right;
2027 e->right->visit (this);
2028 current_expr = last_expr;
2029
2030 if (vut.read.find(leftvar) == vut.read.end()) // var never read?
2031 {
2032 // NB: Not so fast! The left side could be an array whose
2033 // index expressions may have side-effects. This would be
2034 // OK if we could replace the array assignment with a
2035 // statement-expression containing all the index expressions
2036 // and the rvalue... but we can't.
2037 // Another possibility is that we have an unread global variable
2038 // which are kept for probe end value display.
2039
2040 bool is_global = false;
2041 vector<vardecl*>::iterator it;
2042 for (it = session.globals.begin(); it != session.globals.end(); it++)
2043 if (leftvar->name == (*it)->name)
2044 {
2045 is_global = true;
2046 break;
2047 }
2048
2049 varuse_collecting_visitor vut;
2050 e->left->visit (& vut);
2051 if (vut.side_effect_free () && !is_global) // XXX: use _wrt() once we track focal_vars
2052 {
2053 /* PR 1119: NB: This is not necessary here. A write-only
2054 variable will also be elided soon at the next _opt2 iteration.
2055 if (e->left->tok->location.file == session.user_file->name && // !tapset
2056 ! session.suppress_warnings)
2057 clog << "WARNING: eliding write-only " << *e->left->tok << endl;
2058 else
2059 */
2060 if (session.verbose>2)
2061 clog << "Eliding assignment to " << leftvar->name
2062 << " at " << *e->tok << endl;
2063
2064 *current_expr = e->right; // goodbye assignment*
2065 relaxed_p = false;
2066 }
2067 }
2068 }
2069 }
2070
2071 void
2072 dead_assignment_remover::visit_binary_expression (binary_expression* e)
2073 {
2074 expression** last_expr = current_expr;
2075 current_expr = &e->left;
2076 e->left->visit (this);
2077 current_expr = &e->right;
2078 e->right->visit (this);
2079 current_expr = last_expr;
2080 }
2081
2082 void
2083 dead_assignment_remover::visit_arrayindex (arrayindex *e)
2084 {
2085 symbol *array = NULL;
2086 hist_op *hist = NULL;
2087 classify_indexable(e->base, array, hist);
2088
2089 if (array)
2090 {
2091 expression** last_expr = current_expr;
2092 for (unsigned i=0; i < e->indexes.size(); i++)
2093 {
2094 current_expr = & e->indexes[i];
2095 e->indexes[i]->visit (this);
2096 }
2097 current_expr = last_expr;
2098 }
2099 }
2100
2101 void
2102 dead_assignment_remover::visit_functioncall (functioncall* e)
2103 {
2104 expression** last_expr = current_expr;
2105 for (unsigned i=0; i<e->args.size(); i++)
2106 {
2107 current_expr = & e->args[i];
2108 e->args[i]->visit (this);
2109 }
2110 current_expr = last_expr;
2111 }
2112
2113 void
2114 dead_assignment_remover::visit_if_statement (if_statement* s)
2115 {
2116 expression** last_expr = current_expr;
2117 current_expr = & s->condition;
2118 s->condition->visit (this);
2119 s->thenblock->visit (this);
2120 if (s->elseblock)
2121 s->elseblock->visit (this);
2122 current_expr = last_expr;
2123 }
2124
2125 void
2126 dead_assignment_remover::visit_for_loop (for_loop* s)
2127 {
2128 expression** last_expr = current_expr;
2129 if (s->init) s->init->visit (this);
2130 current_expr = & s->cond;
2131 s->cond->visit (this);
2132 if (s->incr) s->incr->visit (this);
2133 s->block->visit (this);
2134 current_expr = last_expr;
2135 }
2136
2137 // Let's remove assignments to variables that are never read. We
2138 // rewrite "(foo = expr)" as "(expr)". This makes foo a candidate to
2139 // be optimized away as an unused variable, and expr a candidate to be
2140 // removed as a side-effect-free statement expression. Wahoo!
2141 void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p)
2142 {
2143 // Recompute the varuse data, which will probably match the opt2
2144 // copy of the computation, except for those totally unused
2145 // variables that opt2 removed.
2146 varuse_collecting_visitor vut;
2147 for (unsigned i=0; i<s.probes.size(); i++)
2148 s.probes[i]->body->visit (& vut); // includes reachable functions too
2149
2150 dead_assignment_remover dar (s, relaxed_p, vut);
2151 // This instance may be reused for multiple probe/function body trims.
2152
2153 for (unsigned i=0; i<s.probes.size(); i++)
2154 s.probes[i]->body->visit (& dar);
2155 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
2156 it->second->body->visit (& dar);
2157 // The rewrite operation is performed within the visitor.
2158
2159 // XXX: we could also zap write-only globals here
2160 }
2161
2162
2163 // ------------------------------------------------------------------------
2164
2165 struct dead_stmtexpr_remover: public traversing_visitor
2166 {
2167 systemtap_session& session;
2168 bool& relaxed_p;
2169 statement** current_stmt; // pointer to current stmt* being iterated
2170 set<vardecl*> focal_vars; // vars considered subject to side-effects
2171
2172 dead_stmtexpr_remover(systemtap_session& s, bool& r):
2173 session(s), relaxed_p(r), current_stmt(0) {}
2174
2175 void visit_block (block *s);
2176 void visit_null_statement (null_statement *s);
2177 void visit_if_statement (if_statement* s);
2178 void visit_foreach_loop (foreach_loop *s);
2179 void visit_for_loop (for_loop *s);
2180 // XXX: and other places where stmt_expr's might be nested
2181
2182 void visit_expr_statement (expr_statement *s);
2183 };
2184
2185
2186 void
2187 dead_stmtexpr_remover::visit_null_statement (null_statement *s)
2188 {
2189 // easy!
2190 if (session.verbose>2)
2191 clog << "Eliding side-effect-free null statement " << *s->tok << endl;
2192 *current_stmt = 0;
2193 }
2194
2195
2196 void
2197 dead_stmtexpr_remover::visit_block (block *s)
2198 {
2199 vector<statement*> new_stmts;
2200 for (unsigned i=0; i<s->statements.size(); i++ )
2201 {
2202 statement** last_stmt = current_stmt;
2203 current_stmt = & s->statements[i];
2204 s->statements[i]->visit (this);
2205 if (*current_stmt != 0)
2206 {
2207 // flatten nested blocks into this one
2208 block *b = dynamic_cast<block *>(*current_stmt);
2209 if (b)
2210 {
2211 if (session.verbose>2)
2212 clog << "Flattening nested block " << *b->tok << endl;
2213 new_stmts.insert(new_stmts.end(),
2214 b->statements.begin(), b->statements.end());
2215 relaxed_p = false;
2216 }
2217 else
2218 new_stmts.push_back (*current_stmt);
2219 }
2220 current_stmt = last_stmt;
2221 }
2222 if (new_stmts.size() == 0)
2223 {
2224 if (session.verbose>2)
2225 clog << "Eliding side-effect-free empty block " << *s->tok << endl;
2226 *current_stmt = 0;
2227 }
2228 else if (new_stmts.size() == 1)
2229 {
2230 if (session.verbose>2)
2231 clog << "Eliding side-effect-free singleton block " << *s->tok << endl;
2232 *current_stmt = new_stmts[0];
2233 }
2234 else
2235 {
2236 s->statements = new_stmts;
2237 }
2238 }
2239
2240 void
2241 dead_stmtexpr_remover::visit_if_statement (if_statement *s)
2242 {
2243 statement** last_stmt = current_stmt;
2244 current_stmt = & s->thenblock;
2245 s->thenblock->visit (this);
2246
2247 if (s->elseblock)
2248 {
2249 current_stmt = & s->elseblock;
2250 s->elseblock->visit (this);
2251 // null *current_stmt is OK here.
2252 }
2253 current_stmt = last_stmt;
2254
2255 if (s->thenblock == 0)
2256 {
2257 if (s->elseblock == 0)
2258 {
2259 // We may be able to elide this statement, if the condition
2260 // expression is side-effect-free.
2261 varuse_collecting_visitor vct;
2262 s->condition->visit(& vct);
2263 if (vct.side_effect_free ())
2264 {
2265 if (session.verbose>2)
2266 clog << "Eliding side-effect-free if statement "
2267 << *s->tok << endl;
2268 *current_stmt = 0; // yeah, baby
2269 }
2270 else
2271 {
2272 // We can still turn it into a simple expr_statement though...
2273 if (session.verbose>2)
2274 clog << "Creating simple evaluation from if statement "
2275 << *s->tok << endl;
2276 expr_statement *es = new expr_statement;
2277 es->value = s->condition;
2278 es->tok = es->value->tok;
2279 *current_stmt = es;
2280 }
2281 }
2282 else
2283 {
2284 // For an else without a then, we can invert the condition logic to
2285 // avoid having a null statement in the thenblock
2286 if (session.verbose>2)
2287 clog << "Inverting the condition of if statement "
2288 << *s->tok << endl;
2289 unary_expression *ue = new unary_expression;
2290 ue->operand = s->condition;
2291 ue->tok = ue->operand->tok;
2292 ue->op = "!";
2293 s->condition = ue;
2294 s->thenblock = s->elseblock;
2295 s->elseblock = 0;
2296 }
2297 }
2298 }
2299
2300 void
2301 dead_stmtexpr_remover::visit_foreach_loop (foreach_loop *s)
2302 {
2303 statement** last_stmt = current_stmt;
2304 current_stmt = & s->block;
2305 s->block->visit (this);
2306 current_stmt = last_stmt;
2307
2308 if (s->block == 0)
2309 {
2310 if (session.verbose>2)
2311 clog << "Eliding side-effect-free foreach statement " << *s->tok << endl;
2312 *current_stmt = 0; // yeah, baby
2313 }
2314 }
2315
2316 void
2317 dead_stmtexpr_remover::visit_for_loop (for_loop *s)
2318 {
2319 statement** last_stmt = current_stmt;
2320 current_stmt = & s->block;
2321 s->block->visit (this);
2322 current_stmt = last_stmt;
2323
2324 if (s->block == 0)
2325 {
2326 // We may be able to elide this statement, if the condition
2327 // expression is side-effect-free.
2328 varuse_collecting_visitor vct;
2329 if (s->init) s->init->visit(& vct);
2330 s->cond->visit(& vct);
2331 if (s->incr) s->incr->visit(& vct);
2332 if (vct.side_effect_free ())
2333 {
2334 if (session.verbose>2)
2335 clog << "Eliding side-effect-free for statement " << *s->tok << endl;
2336 *current_stmt = 0; // yeah, baby
2337 return;
2338 }
2339
2340 // Can't elide this whole statement; put a null in there.
2341 s->block = new null_statement();
2342 s->block->tok = s->tok;
2343 }
2344 }
2345
2346
2347
2348 void
2349 dead_stmtexpr_remover::visit_expr_statement (expr_statement *s)
2350 {
2351 // Run a varuse query against the operand expression. If it has no
2352 // side-effects, replace the entire statement expression by a null
2353 // statement. This replacement is done by overwriting the
2354 // current_stmt pointer.
2355 //
2356 // Unlike many other visitors, we do *not* traverse this outermost
2357 // one into the expression subtrees. There is no need - no
2358 // expr_statement nodes will be found there. (Function bodies
2359 // need to be visited explicitly by our caller.)
2360 //
2361 // NB. While we don't share nodes in the parse tree, let's not
2362 // deallocate *s anyway, just in case...
2363
2364 varuse_collecting_visitor vut;
2365 s->value->visit (& vut);
2366
2367 if (vut.side_effect_free_wrt (focal_vars) &&
2368 *current_stmt == s) // we're not nested any deeper than expected
2369 {
2370 /* PR 1119: NB: this message is not a good idea here. It can
2371 name some arbitrary RHS expression of an assignment.
2372 if (s->value->tok->location.file == session.user_file->name && // not tapset
2373 ! session.suppress_warnings)
2374 clog << "WARNING: eliding read-only " << *s->value->tok << endl;
2375 else
2376 */
2377 if (session.verbose>2)
2378 clog << "Eliding side-effect-free expression "
2379 << *s->tok << endl;
2380
2381 // NB: this 0 pointer is invalid to leave around for any length of
2382 // time, but the parent parse tree objects above handle it.
2383 * current_stmt = 0;
2384
2385 relaxed_p = false;
2386 }
2387 }
2388
2389
2390 void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
2391 {
2392 // Finally, let's remove some statement-expressions that have no
2393 // side-effect. These should be exactly those whose private varuse
2394 // visitors come back with an empty "written" and "embedded" lists.
2395
2396 dead_stmtexpr_remover duv (s, relaxed_p);
2397 // This instance may be reused for multiple probe/function body trims.
2398
2399 for (unsigned i=0; i<s.probes.size(); i++)
2400 {
2401 if (pending_interrupts) break;
2402
2403 derived_probe* p = s.probes[i];
2404
2405 duv.focal_vars.clear ();
2406 duv.focal_vars.insert (s.globals.begin(),
2407 s.globals.end());
2408 duv.focal_vars.insert (p->locals.begin(),
2409 p->locals.end());
2410
2411 duv.current_stmt = & p->body;
2412 p->body->visit (& duv);
2413 if (p->body == 0)
2414 {
2415 if (! s.suppress_warnings)
2416 s.print_warning ("side-effect-free probe '" + p->name + "'", p->tok);
2417
2418 p->body = new null_statement();
2419 p->body->tok = p->tok;
2420
2421 // XXX: possible duplicate warnings; see below
2422 }
2423 }
2424 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
2425 {
2426 if (pending_interrupts) break;
2427
2428 functiondecl* fn = it->second;
2429 duv.focal_vars.clear ();
2430 duv.focal_vars.insert (fn->locals.begin(),
2431 fn->locals.end());
2432 duv.focal_vars.insert (fn->formal_args.begin(),
2433 fn->formal_args.end());
2434 duv.focal_vars.insert (s.globals.begin(),
2435 s.globals.end());
2436
2437 duv.current_stmt = & fn->body;
2438 fn->body->visit (& duv);
2439 if (fn->body == 0)
2440 {
2441 if (! s.suppress_warnings)
2442 s.print_warning ("side-effect-free function '" + fn->name + "'", fn->tok);
2443
2444 fn->body = new null_statement();
2445 fn->body->tok = fn->tok;
2446
2447 // XXX: the next iteration of the outer optimization loop may
2448 // take this new null_statement away again, and thus give us a
2449 // fresh warning. It would be better if this fixup was performed
2450 // only after the relaxation iterations.
2451 // XXX: or else see bug #6469.
2452 }
2453 }
2454 }
2455
2456
2457 // ------------------------------------------------------------------------
2458
2459 // The goal of this visitor is to reduce top-level expressions in void context
2460 // into separate statements that evaluate each subcomponent of the expression.
2461 // The dead-statement-remover can later remove some parts if they have no side
2462 // effects.
2463 struct void_statement_reducer: public traversing_visitor
2464 {
2465 systemtap_session& session;
2466 bool& relaxed_p;
2467 statement** current_stmt; // pointer to current stmt* being iterated
2468 expr_statement* current_expr; // pointer to current expr being iterated
2469 set<vardecl*> focal_vars; // vars considered subject to side-effects
2470
2471 void_statement_reducer(systemtap_session& s, bool& r):
2472 session(s), relaxed_p(r), current_stmt(0), current_expr(0) {}
2473
2474 // these just maintain current_stmt while recursing, but don't visit
2475 // expressions in the conditional / loop controls.
2476 void visit_expr_statement (expr_statement* s);
2477 void visit_block (block *s);
2478 void visit_if_statement (if_statement* s);
2479 void visit_for_loop (for_loop* s);
2480 void visit_foreach_loop (foreach_loop* s);
2481
2482 // these expressions get rewritten into their statement equivalents
2483 void visit_logical_or_expr (logical_or_expr* e);
2484 void visit_logical_and_expr (logical_and_expr* e);
2485 void visit_ternary_expression (ternary_expression* e);
2486
2487 // all of these can be reduced into simpler statements
2488 void visit_binary_expression (binary_expression* e);
2489 void visit_unary_expression (unary_expression* e);
2490 void visit_comparison (comparison* e);
2491 void visit_concatenation (concatenation* e);
2492 void visit_functioncall (functioncall* e);
2493 void visit_print_format (print_format* e);
2494
2495 // these are a bit hairy to grok due to the intricacies of indexables and
2496 // stats, so I'm chickening out and skipping them...
2497 void visit_array_in (array_in* e) {}
2498 void visit_arrayindex (arrayindex* e) {}
2499 void visit_stat_op (stat_op* e) {}
2500 void visit_hist_op (hist_op* e) {}
2501
2502 // these can't be reduced because they always have an effect
2503 void visit_return_statement (return_statement* s) {}
2504 void visit_delete_statement (delete_statement* s) {}
2505 void visit_pre_crement (pre_crement* e) {}
2506 void visit_post_crement (post_crement* e) {}
2507 void visit_assignment (assignment* e) {}
2508 };
2509
2510
2511 void
2512 void_statement_reducer::visit_expr_statement (expr_statement* s)
2513 {
2514 assert(!current_expr); // it shouldn't be possible to have nested expr's
2515 current_expr = s;
2516 s->value->visit (this);
2517 current_expr = NULL;
2518 }
2519
2520 void
2521 void_statement_reducer::visit_block (block *s)
2522 {
2523 statement** last_stmt = current_stmt;
2524 for (unsigned i=0; i<s->statements.size(); i++ )
2525 {
2526 current_stmt = & s->statements[i];
2527 s->statements[i]->visit (this);
2528 }
2529 current_stmt = last_stmt;
2530 }
2531
2532 void
2533 void_statement_reducer::visit_if_statement (if_statement* s)
2534 {
2535 statement** last_stmt = current_stmt;
2536 current_stmt = & s->thenblock;
2537 s->thenblock->visit (this);
2538
2539 if (s->elseblock)
2540 {
2541 current_stmt = & s->elseblock;
2542 s->elseblock->visit (this);
2543 }
2544 current_stmt = last_stmt;
2545 }
2546
2547 void
2548 void_statement_reducer::visit_for_loop (for_loop* s)
2549 {
2550 statement** last_stmt = current_stmt;
2551 current_stmt = & s->block;
2552 s->block->visit (this);
2553 current_stmt = last_stmt;
2554 }
2555
2556 void
2557 void_statement_reducer::visit_foreach_loop (foreach_loop* s)
2558 {
2559 statement** last_stmt = current_stmt;
2560 current_stmt = & s->block;
2561 s->block->visit (this);
2562 current_stmt = last_stmt;
2563 }
2564
2565 void
2566 void_statement_reducer::visit_logical_or_expr (logical_or_expr* e)
2567 {
2568 // In void context, the evaluation of "a || b" is exactly like
2569 // "if (!a) b", so let's do that instead.
2570
2571 assert(current_expr && current_expr->value == e);
2572
2573 if (session.verbose>2)
2574 clog << "Creating if statement from unused logical-or "
2575 << *e->tok << endl;
2576
2577 if_statement *is = new if_statement;
2578 is->tok = e->tok;
2579 is->elseblock = 0;
2580 *current_stmt = is;
2581 current_expr = NULL;
2582
2583 unary_expression *ue = new unary_expression;
2584 ue->operand = e->left;
2585 ue->tok = e->tok;
2586 ue->op = "!";
2587 is->condition = ue;
2588
2589 expr_statement *es = new expr_statement;
2590 es->value = e->right;
2591 es->tok = es->value->tok;
2592 is->thenblock = es;
2593
2594 is->visit(this);
2595 relaxed_p = false;
2596 }
2597
2598 void
2599 void_statement_reducer::visit_logical_and_expr (logical_and_expr* e)
2600 {
2601 // In void context, the evaluation of "a && b" is exactly like
2602 // "if (a) b", so let's do that instead.
2603
2604 assert(current_expr && current_expr->value == e);
2605
2606 if (session.verbose>2)
2607 clog << "Creating if statement from unused logical-and "
2608 << *e->tok << endl;
2609
2610 if_statement *is = new if_statement;
2611 is->tok = e->tok;
2612 is->elseblock = 0;
2613 is->condition = e->left;
2614 *current_stmt = is;
2615 current_expr = NULL;
2616
2617 expr_statement *es = new expr_statement;
2618 es->value = e->right;
2619 es->tok = es->value->tok;
2620 is->thenblock = es;
2621
2622 is->visit(this);
2623 relaxed_p = false;
2624 }
2625
2626 void
2627 void_statement_reducer::visit_ternary_expression (ternary_expression* e)
2628 {
2629 // In void context, the evaluation of "a ? b : c" is exactly like
2630 // "if (a) b else c", so let's do that instead.
2631
2632 assert(current_expr && current_expr->value == e);
2633
2634 if (session.verbose>2)
2635 clog << "Creating if statement from unused ternary expression "
2636 << *e->tok << endl;
2637
2638 if_statement *is = new if_statement;
2639 is->tok = e->tok;
2640 is->condition = e->cond;
2641 *current_stmt = is;
2642 current_expr = NULL;
2643
2644 expr_statement *es = new expr_statement;
2645 es->value = e->truevalue;
2646 es->tok = es->value->tok;
2647 is->thenblock = es;
2648
2649 es = new expr_statement;
2650 es->value = e->falsevalue;
2651 es->tok = es->value->tok;
2652 is->elseblock = es;
2653
2654 is->visit(this);
2655 relaxed_p = false;
2656 }
2657
2658 void
2659 void_statement_reducer::visit_binary_expression (binary_expression* e)
2660 {
2661 // When the result of a binary operation isn't needed, it's just as good to
2662 // evaluate the operands as sequential statements in a block.
2663
2664 assert(current_expr && current_expr->value == e);
2665
2666 if (session.verbose>2)
2667 clog << "Eliding unused binary " << *e->tok << endl;
2668
2669 block *b = new block;
2670 b->tok = current_expr->tok;
2671 *current_stmt = b;
2672 current_expr = NULL;
2673
2674 expr_statement *es = new expr_statement;
2675 es->value = e->left;
2676 es->tok = es->value->tok;
2677 b->statements.push_back(es);
2678
2679 es = new expr_statement;
2680 es->value = e->right;
2681 es->tok = es->value->tok;
2682 b->statements.push_back(es);
2683
2684 b->visit(this);
2685 relaxed_p = false;
2686 }
2687
2688 void
2689 void_statement_reducer::visit_unary_expression (unary_expression* e)
2690 {
2691 // When the result of a unary operation isn't needed, it's just as good to
2692 // evaluate the operand directly
2693
2694 assert(current_expr && current_expr->value == e);
2695
2696 if (session.verbose>2)
2697 clog << "Eliding unused unary " << *e->tok << endl;
2698
2699 current_expr->value = e->operand;
2700 current_expr->tok = current_expr->value->tok;
2701 current_expr->value->visit(this);
2702
2703 relaxed_p = false;
2704 }
2705
2706 void
2707 void_statement_reducer::visit_comparison (comparison* e)
2708 {
2709 visit_binary_expression(e);
2710 }
2711
2712 void
2713 void_statement_reducer::visit_concatenation (concatenation* e)
2714 {
2715 visit_binary_expression(e);
2716 }
2717
2718 void
2719 void_statement_reducer::visit_functioncall (functioncall* e)
2720 {
2721 // If a function call is pure and its result ignored, we can elide the call
2722 // and just evaluate the arguments in sequence
2723
2724 if (!e->args.size())
2725 return;
2726
2727 varuse_collecting_visitor vut;
2728 vut.traversed.insert (e->referent);
2729 vut.current_function = e->referent;
2730 e->referent->body->visit (& vut);
2731 if (!vut.side_effect_free_wrt (focal_vars))
2732 return;
2733
2734 assert(current_expr && current_expr->value == e);
2735
2736 if (session.verbose>2)
2737 clog << "Eliding side-effect-free function call " << *e->tok << endl;
2738
2739 block *b = new block;
2740 b->tok = e->tok;
2741 *current_stmt = b;
2742 current_expr = NULL;
2743
2744 for (unsigned i=0; i<e->args.size(); i++ )
2745 {
2746 expr_statement *es = new expr_statement;
2747 es->value = e->args[i];
2748 es->tok = es->value->tok;
2749 b->statements.push_back(es);
2750 }
2751
2752 b->visit(this);
2753 relaxed_p = false;
2754 }
2755
2756 void
2757 void_statement_reducer::visit_print_format (print_format* e)
2758 {
2759 // When an sprint's return value is ignored, we can simply evaluate the
2760 // arguments in sequence
2761
2762 if (e->print_to_stream || !e->args.size())
2763 return;
2764
2765 assert(current_expr && current_expr->value == e);
2766
2767 if (session.verbose>2)
2768 clog << "Eliding unused print " << *e->tok << endl;
2769
2770 block *b = new block;
2771 b->tok = e->tok;
2772 *current_stmt = b;
2773 current_expr = NULL;
2774
2775 for (unsigned i=0; i<e->args.size(); i++ )
2776 {
2777 expr_statement *es = new expr_statement;
2778 es->value = e->args[i];
2779 es->tok = es->value->tok;
2780 b->statements.push_back(es);
2781 }
2782
2783 b->visit(this);
2784 relaxed_p = false;
2785 }
2786
2787
2788 void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p)
2789 {
2790 // Let's simplify statements with unused computed values.
2791
2792 void_statement_reducer vuv (s, relaxed_p);
2793 // This instance may be reused for multiple probe/function body trims.
2794
2795 vuv.focal_vars.insert (s.globals.begin(), s.globals.end());
2796
2797 for (unsigned i=0; i<s.probes.size(); i++)
2798 {
2799 derived_probe* p = s.probes[i];
2800 vuv.current_stmt = & p->body;
2801 p->body->visit (& vuv);
2802 }
2803 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
2804 {
2805 functiondecl* fn = it->second;
2806 vuv.current_stmt = & fn->body;
2807 fn->body->visit (& vuv);
2808 }
2809 }
2810
2811
2812 struct duplicate_function_remover: public functioncall_traversing_visitor
2813 {
2814 systemtap_session& s;
2815 map<functiondecl*, functiondecl*>& duplicate_function_map;
2816
2817 duplicate_function_remover(systemtap_session& sess,
2818 map<functiondecl*, functiondecl*>&dfm):
2819 s(sess), duplicate_function_map(dfm) {};
2820
2821 void visit_functioncall (functioncall* e);
2822 };
2823
2824 void
2825 duplicate_function_remover::visit_functioncall (functioncall *e)
2826 {
2827 functioncall_traversing_visitor::visit_functioncall (e);
2828
2829 // If the current function call reference points to a function that
2830 // is a duplicate, replace it.
2831 if (duplicate_function_map.count(e->referent) != 0)
2832 {
2833 if (s.verbose>2)
2834 clog << "Changing " << e->referent->name
2835 << " reference to "
2836 << duplicate_function_map[e->referent]->name
2837 << " reference\n";
2838 e->tok = duplicate_function_map[e->referent]->tok;
2839 e->function = duplicate_function_map[e->referent]->name;
2840 e->referent = duplicate_function_map[e->referent];
2841 }
2842 }
2843
2844 static string
2845 get_functionsig (functiondecl* f)
2846 {
2847 ostringstream s;
2848
2849 // Get the "name:args body" of the function in s. We have to
2850 // include the args since the function 'x1(a, b)' is different than
2851 // the function 'x2(b, a)' even if the bodies of the two functions
2852 // are exactly the same.
2853 f->printsig(s);
2854 f->body->print(s);
2855
2856 // printsig puts f->name + ':' on the front. Remove this
2857 // (otherwise, functions would never compare equal).
2858 string str = s.str().erase(0, f->name.size() + 1);
2859
2860 // Return the function signature.
2861 return str;
2862 }
2863
2864 void semantic_pass_opt6 (systemtap_session& s, bool& relaxed_p)
2865 {
2866 // Walk through all the functions, looking for duplicates.
2867 map<string, functiondecl*> functionsig_map;
2868 map<functiondecl*, functiondecl*> duplicate_function_map;
2869
2870
2871 vector<functiondecl*> newly_zapped_functions;
2872 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
2873 {
2874 functiondecl *fd = it->second;
2875 string functionsig = get_functionsig(fd);
2876
2877 if (functionsig_map.count(functionsig) == 0)
2878 {
2879 // This function is unique. Remember it.
2880 functionsig_map[functionsig] = fd;
2881 }
2882 else
2883 {
2884 // This function is a duplicate.
2885 duplicate_function_map[fd] = functionsig_map[functionsig];
2886 newly_zapped_functions.push_back (fd);
2887 relaxed_p = false;
2888 }
2889 }
2890 for (unsigned i=0; i<newly_zapped_functions.size(); i++)
2891 {
2892 map<string,functiondecl*>::iterator where = s.functions.find (newly_zapped_functions[i]->name);
2893 assert (where != s.functions.end());
2894 s.functions.erase (where);
2895 }
2896
2897
2898 // If we have duplicate functions, traverse down the tree, replacing
2899 // the appropriate function calls.
2900 // duplicate_function_remover::visit_functioncall() handles the
2901 // details of replacing the function calls.
2902 if (duplicate_function_map.size() != 0)
2903 {
2904 duplicate_function_remover dfr (s, duplicate_function_map);
2905
2906 for (unsigned i=0; i < s.probes.size(); i++)
2907 s.probes[i]->body->visit(&dfr);
2908 }
2909 }
2910
2911
2912 static int
2913 semantic_pass_optimize1 (systemtap_session& s)
2914 {
2915 // In this pass, we attempt to rewrite probe/function bodies to
2916 // eliminate some blatantly unnecessary code. This is run before
2917 // type inference, but after symbol resolution and derived_probe
2918 // creation. We run an outer "relaxation" loop that repeats the
2919 // optimizations until none of them find anything to remove.
2920
2921 int rc = 0;
2922
2923 bool relaxed_p = false;
2924 unsigned iterations = 0;
2925 while (! relaxed_p)
2926 {
2927 if (pending_interrupts) break;
2928
2929 relaxed_p = true; // until proven otherwise
2930
2931 semantic_pass_opt1 (s, relaxed_p);
2932 semantic_pass_opt2 (s, relaxed_p, iterations); // produce some warnings only on iteration=0
2933 semantic_pass_opt3 (s, relaxed_p);
2934 semantic_pass_opt4 (s, relaxed_p);
2935 semantic_pass_opt5 (s, relaxed_p);
2936
2937 iterations ++;
2938 }
2939
2940 return rc;
2941 }
2942
2943
2944 static int
2945 semantic_pass_optimize2 (systemtap_session& s)
2946 {
2947 // This is run after type inference. We run an outer "relaxation"
2948 // loop that repeats the optimizations until none of them find
2949 // anything to remove.
2950
2951 int rc = 0;
2952
2953 bool relaxed_p = false;
2954 while (! relaxed_p)
2955 {
2956 if (pending_interrupts) break;
2957 relaxed_p = true; // until proven otherwise
2958
2959 semantic_pass_opt6 (s, relaxed_p);
2960 }
2961
2962 return rc;
2963 }
2964
2965
2966
2967 // ------------------------------------------------------------------------
2968 // type resolution
2969
2970
2971 static int
2972 semantic_pass_types (systemtap_session& s)
2973 {
2974 int rc = 0;
2975
2976 // next pass: type inference
2977 unsigned iterations = 0;
2978 typeresolution_info ti (s);
2979
2980 ti.assert_resolvability = false;
2981 // XXX: maybe convert to exception-based error signalling
2982 while (1)
2983 {
2984 if (pending_interrupts) break;
2985
2986 iterations ++;
2987 ti.num_newly_resolved = 0;
2988 ti.num_still_unresolved = 0;
2989
2990 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
2991 {
2992 if (pending_interrupts) break;
2993
2994 functiondecl* fd = it->second;
2995 ti.current_probe = 0;
2996 ti.current_function = fd;
2997 ti.t = pe_unknown;
2998 fd->body->visit (& ti);
2999 // NB: we don't have to assert a known type for
3000 // functions here, to permit a "void" function.
3001 // The translator phase will omit the "retvalue".
3002 //
3003 // if (fd->type == pe_unknown)
3004 // ti.unresolved (fd->tok);
3005 }
3006
3007 for (unsigned j=0; j<s.probes.size(); j++)
3008 {
3009 if (pending_interrupts) break;
3010
3011 derived_probe* pn = s.probes[j];
3012 ti.current_function = 0;
3013 ti.current_probe = pn;
3014 ti.t = pe_unknown;
3015 pn->body->visit (& ti);
3016
3017 probe_point* pp = pn->sole_location();
3018 if (pp->condition)
3019 {
3020 ti.current_function = 0;
3021 ti.current_probe = 0;
3022 ti.t = pe_long; // NB: expected type
3023 pp->condition->visit (& ti);
3024 }
3025 }
3026
3027 for (unsigned j=0; j<s.globals.size(); j++)
3028 {
3029 vardecl* gd = s.globals[j];
3030 if (gd->type == pe_unknown)
3031 ti.unresolved (gd->tok);
3032 }
3033
3034 if (ti.num_newly_resolved == 0) // converged
3035 {
3036 if (ti.num_still_unresolved == 0)
3037 break; // successfully
3038 else if (! ti.assert_resolvability)
3039 ti.assert_resolvability = true; // last pass, with error msgs
3040 else
3041 { // unsuccessful conclusion
3042 rc ++;
3043 break;
3044 }
3045 }
3046 }
3047
3048 return rc + s.num_errors();
3049 }
3050
3051
3052
3053 typeresolution_info::typeresolution_info (systemtap_session& s):
3054 session(s), current_function(0), current_probe(0)
3055 {
3056 }
3057
3058
3059 void
3060 typeresolution_info::visit_literal_number (literal_number* e)
3061 {
3062 assert (e->type == pe_long);
3063 if ((t == e->type) || (t == pe_unknown))
3064 return;
3065
3066 mismatch (e->tok, e->type, t);
3067 }
3068
3069
3070 void
3071 typeresolution_info::visit_literal_string (literal_string* e)
3072 {
3073 assert (e->type == pe_string);
3074 if ((t == e->type) || (t == pe_unknown))
3075 return;
3076
3077 mismatch (e->tok, e->type, t);
3078 }
3079
3080
3081 void
3082 typeresolution_info::visit_logical_or_expr (logical_or_expr *e)
3083 {
3084 visit_binary_expression (e);
3085 }
3086
3087
3088 void
3089 typeresolution_info::visit_logical_and_expr (logical_and_expr *e)
3090 {
3091 visit_binary_expression (e);
3092 }
3093
3094
3095 void
3096 typeresolution_info::visit_comparison (comparison *e)
3097 {
3098 // NB: result of any comparison is an integer!
3099 if (t == pe_stats || t == pe_string)
3100 invalid (e->tok, t);
3101
3102 t = (e->right->type != pe_unknown) ? e->right->type : pe_unknown;
3103 e->left->visit (this);
3104 t = (e->left->type != pe_unknown) ? e->left->type : pe_unknown;
3105 e->right->visit (this);
3106
3107 if (e->left->type != pe_unknown &&
3108 e->right->type != pe_unknown &&
3109 e->left->type != e->right->type)
3110 mismatch (e->tok, e->left->type, e->right->type);
3111
3112 if (e->type == pe_unknown)
3113 {
3114 e->type = pe_long;
3115 resolved (e->tok, e->type);
3116 }
3117 }
3118
3119
3120 void
3121 typeresolution_info::visit_concatenation (concatenation *e)
3122 {
3123 if (t != pe_unknown && t != pe_string)
3124 invalid (e->tok, t);
3125
3126 t = pe_string;
3127 e->left->visit (this);
3128 t = pe_string;
3129 e->right->visit (this);
3130
3131 if (e->type == pe_unknown)
3132 {
3133 e->type = pe_string;
3134 resolved (e->tok, e->type);
3135 }
3136 }
3137
3138
3139 void
3140 typeresolution_info::visit_assignment (assignment *e)
3141 {
3142 if (t == pe_stats)
3143 invalid (e->tok, t);
3144
3145 if (e->op == "<<<") // stats aggregation
3146 {
3147 if (t == pe_string)
3148 invalid (e->tok, t);
3149
3150 t = pe_stats;
3151 e->left->visit (this);
3152 t = pe_long;
3153 e->right->visit (this);
3154 if (e->type == pe_unknown ||
3155 e->type == pe_stats)
3156 {
3157 e->type = pe_long;
3158 resolved (e->tok, e->type);
3159 }
3160 }
3161
3162 else if (e->left->type == pe_stats)
3163 invalid (e->left->tok, e->left->type);
3164
3165 else if (e->right->type == pe_stats)
3166 invalid (e->right->tok, e->right->type);
3167
3168 else if (e->op == "+=" || // numeric only
3169 e->op == "-=" ||
3170 e->op == "*=" ||
3171 e->op == "/=" ||
3172 e->op == "%=" ||
3173 e->op == "&=" ||
3174 e->op == "^=" ||
3175 e->op == "|=" ||
3176 e->op == "<<=" ||
3177 e->op == ">>=" ||
3178 false)
3179 {
3180 visit_binary_expression (e);
3181 }
3182 else if (e->op == ".=" || // string only
3183 false)
3184 {
3185 if (t == pe_long || t == pe_stats)
3186 invalid (e->tok, t);
3187
3188 t = pe_string;
3189 e->left->visit (this);
3190 t = pe_string;
3191 e->right->visit (this);
3192 if (e->type == pe_unknown)
3193 {
3194 e->type = pe_string;
3195 resolved (e->tok, e->type);
3196 }
3197 }
3198 else if (e->op == "=") // overloaded = for string & numeric operands
3199 {
3200 // logic similar to ternary_expression
3201 exp_type sub_type = t;
3202
3203 // Infer types across the l/r values
3204 if (sub_type == pe_unknown && e->type != pe_unknown)
3205 sub_type = e->type;
3206
3207 t = (sub_type != pe_unknown) ? sub_type :
3208 (e->right->type != pe_unknown) ? e->right->type :
3209 pe_unknown;
3210 e->left->visit (this);
3211 t = (sub_type != pe_unknown) ? sub_type :
3212 (e->left->type != pe_unknown) ? e->left->type :
3213 pe_unknown;
3214 e->right->visit (this);
3215
3216 if ((sub_type != pe_unknown) && (e->type == pe_unknown))
3217 {
3218 e->type = sub_type;
3219 resolved (e->tok, e->type);
3220 }
3221 if ((sub_type == pe_unknown) && (e->left->type != pe_unknown))
3222 {
3223 e->type = e->left->type;
3224 resolved (e->tok, e->type);
3225 }
3226
3227 if (e->left->type != pe_unknown &&
3228 e->right->type != pe_unknown &&
3229 e->left->type != e->right->type)
3230 mismatch (e->tok, e->left->type, e->right->type);
3231
3232 }
3233 else
3234 throw semantic_error ("unsupported assignment operator " + e->op);
3235 }
3236
3237
3238 void
3239 typeresolution_info::visit_binary_expression (binary_expression* e)
3240 {
3241 if (t == pe_stats || t == pe_string)
3242 invalid (e->tok, t);
3243
3244 t = pe_long;
3245 e->left->visit (this);
3246 t = pe_long;
3247 e->right->visit (this);
3248
3249 if (e->left->type != pe_unknown &&
3250 e->right->type != pe_unknown &&
3251 e->left->type != e->right->type)
3252 mismatch (e->tok, e->left->type, e->right->type);
3253
3254 if (e->type == pe_unknown)
3255 {
3256 e->type = pe_long;
3257 resolved (e->tok, e->type);
3258 }
3259 }
3260
3261
3262 void
3263 typeresolution_info::visit_pre_crement (pre_crement *e)
3264 {
3265 visit_unary_expression (e);
3266 }
3267
3268
3269 void
3270 typeresolution_info::visit_post_crement (post_crement *e)
3271 {
3272 visit_unary_expression (e);
3273 }
3274
3275
3276 void
3277 typeresolution_info::visit_unary_expression (unary_expression* e)
3278 {
3279 if (t == pe_stats || t == pe_string)
3280 invalid (e->tok, t);
3281
3282 t = pe_long;
3283 e->operand->visit (this);
3284
3285 if (e->type == pe_unknown)
3286 {
3287 e->type = pe_long;
3288 resolved (e->tok, e->type);
3289 }
3290 }
3291
3292
3293 void
3294 typeresolution_info::visit_ternary_expression (ternary_expression* e)
3295 {
3296 exp_type sub_type = t;
3297
3298 t = pe_long;
3299 e->cond->visit (this);
3300
3301 // Infer types across the true/false arms of the ternary expression.
3302
3303 if (sub_type == pe_unknown && e->type != pe_unknown)
3304 sub_type = e->type;
3305 t = sub_type;
3306 e->truevalue->visit (this);
3307 t = sub_type;
3308 e->falsevalue->visit (this);
3309
3310 if ((sub_type == pe_unknown) && (e->type != pe_unknown))
3311 ; // already resolved
3312 else if ((sub_type != pe_unknown) && (e->type == pe_unknown))
3313 {
3314 e->type = sub_type;
3315 resolved (e->tok, e->type);
3316 }
3317 else if ((sub_type == pe_unknown) && (e->truevalue->type != pe_unknown))
3318 {
3319 e->type = e->truevalue->type;
3320 resolved (e->tok, e->type);
3321 }
3322 else if ((sub_type == pe_unknown) && (e->falsevalue->type != pe_unknown))
3323 {
3324 e->type = e->falsevalue->type;
3325 resolved (e->tok, e->type);
3326 }
3327 else if (e->type != sub_type)
3328 mismatch (e->tok, sub_type, e->type);
3329 }
3330
3331
3332 template <class Referrer, class Referent>
3333 void resolve_2types (Referrer* referrer, Referent* referent,
3334 typeresolution_info* r, exp_type t, bool accept_unknown = false)
3335 {
3336 exp_type& re_type = referrer->type;
3337 const token* re_tok = referrer->tok;
3338 exp_type& te_type = referent->type;
3339 const token* te_tok = referent->tok;
3340
3341 if (t != pe_unknown && re_type == t && re_type == te_type)
3342 ; // do nothing: all three e->types in agreement
3343 else if (t == pe_unknown && re_type != pe_unknown && re_type == te_type)
3344 ; // do nothing: two known e->types in agreement
3345 else if (re_type != pe_unknown && te_type != pe_unknown && re_type != te_type)
3346 r->mismatch (re_tok, re_type, te_type);
3347 else if (re_type != pe_unknown && t != pe_unknown && re_type != t)
3348 r->mismatch (re_tok, re_type, t);
3349 else if (te_type != pe_unknown && t != pe_unknown && te_type != t)
3350 r->mismatch (te_tok, te_type, t);
3351 else if (re_type == pe_unknown && t != pe_unknown)
3352 {
3353 // propagate from upstream
3354 re_type = t;
3355 r->resolved (re_tok, re_type);
3356 // catch re_type/te_type mismatch later
3357 }
3358 else if (re_type == pe_unknown && te_type != pe_unknown)
3359 {
3360 // propagate from referent
3361 re_type = te_type;
3362 r->resolved (re_tok, re_type);
3363 // catch re_type/t mismatch later
3364 }
3365 else if (re_type != pe_unknown && te_type == pe_unknown)
3366 {
3367 // propagate to referent
3368 te_type = re_type;
3369 r->resolved (te_tok, te_type);
3370 // catch re_type/t mismatch later
3371 }
3372 else if (! accept_unknown)
3373 r->unresolved (re_tok);
3374 }
3375
3376
3377 void
3378 typeresolution_info::visit_symbol (symbol* e)
3379 {
3380 assert (e->referent != 0);
3381 resolve_2types (e, e->referent, this, t);
3382 }
3383
3384
3385 void
3386 typeresolution_info::visit_target_symbol (target_symbol* e)
3387 {
3388 // This occurs only if a target symbol was not resolved over in
3389 // tapset.cxx land, that error was properly suppressed, and the
3390 // later unused-expression-elimination pass didn't get rid of it
3391 // either. So we have a target symbol that is believed to be of
3392 // genuine use, yet unresolved by the provider.
3393
3394 if (session.verbose > 2)
3395 {
3396 clog << "Resolution problem with ";
3397 if (current_function)
3398 {
3399 clog << "function " << current_function->name << endl;
3400 current_function->body->print (clog);
3401 clog << endl;
3402 }
3403 else if (current_probe)
3404 {
3405 clog << "probe " << current_probe->name << endl;
3406 current_probe->body->print (clog);
3407 clog << endl;
3408 }
3409 else
3410 clog << "other" << endl;
3411 }
3412
3413 if (e->saved_conversion_error)
3414 throw (* (e->saved_conversion_error));
3415 else
3416 throw semantic_error("unresolved target-symbol expression", e->tok);
3417 }
3418
3419
3420 void
3421 typeresolution_info::visit_arrayindex (arrayindex* e)
3422 {
3423
3424 symbol *array = NULL;
3425 hist_op *hist = NULL;
3426 classify_indexable(e->base, array, hist);
3427
3428 // Every hist_op has type [int]:int, that is to say, every hist_op
3429 // is a pseudo-one-dimensional integer array type indexed by
3430 // integers (bucket numbers).
3431
3432 if (hist)
3433 {
3434 if (e->indexes.size() != 1)
3435 unresolved (e->tok);
3436 t = pe_long;
3437 e->indexes[0]->visit (this);
3438 if (e->indexes[0]->type != pe_long)
3439 unresolved (e->tok);
3440 hist->visit (this);
3441 if (e->type != pe_long)
3442 {
3443 e->type = pe_long;
3444 resolved (e->tok, pe_long);
3445 }
3446 return;
3447 }
3448
3449 // Now we are left with "normal" map inference and index checking.
3450
3451 assert (array);
3452 assert (array->referent != 0);
3453 resolve_2types (e, array->referent, this, t);
3454
3455 // now resolve the array indexes
3456
3457 // if (e->referent->index_types.size() == 0)
3458 // // redesignate referent as array
3459 // e->referent->set_arity (e->indexes.size ());
3460
3461 if (e->indexes.size() != array->referent->index_types.size())
3462 unresolved (e->tok); // symbol resolution should prevent this
3463 else for (unsigned i=0; i<e->indexes.size(); i++)
3464 {
3465 expression* ee = e->indexes[i];
3466 exp_type& ft = array->referent->index_types [i];
3467 t = ft;
3468 ee->visit (this);
3469 exp_type at = ee->type;
3470
3471 if ((at == pe_string || at == pe_long) && ft == pe_unknown)
3472 {
3473 // propagate to formal type
3474 ft = at;
3475 resolved (array->referent->tok, ft);
3476 // uses array decl as there is no token for "formal type"
3477 }
3478 if (at == pe_stats)
3479 invalid (ee->tok, at);
3480 if (ft == pe_stats)
3481 invalid (ee->tok, ft);
3482 if (at != pe_unknown && ft != pe_unknown && ft != at)
3483 mismatch (e->tok, at, ft);
3484 if (at == pe_unknown)
3485 unresolved (ee->tok);
3486 }
3487 }
3488
3489
3490 void
3491 typeresolution_info::visit_functioncall (functioncall* e)
3492 {
3493 assert (e->referent != 0);
3494
3495 resolve_2types (e, e->referent, this, t, true); // accept unknown type
3496
3497 if (e->type == pe_stats)
3498 invalid (e->tok, e->type);
3499
3500 // now resolve the function parameters
3501 if (e->args.size() != e->referent->formal_args.size())
3502 unresolved (e->tok); // symbol resolution should prevent this
3503 else for (unsigned i=0; i<e->args.size(); i++)
3504 {
3505 expression* ee = e->args[i];
3506 exp_type& ft = e->referent->formal_args[i]->type;
3507 const token* fe_tok = e->referent->formal_args[i]->tok;
3508 t = ft;
3509 ee->visit (this);
3510 exp_type at = ee->type;
3511
3512 if (((at == pe_string) || (at == pe_long)) && ft == pe_unknown)
3513 {
3514 // propagate to formal arg
3515 ft = at;
3516 resolved (e->referent->formal_args[i]->tok, ft);
3517 }
3518 if (at == pe_stats)
3519 invalid (e->tok, at);
3520 if (ft == pe_stats)
3521 invalid (fe_tok, ft);
3522 if (at != pe_unknown && ft != pe_unknown && ft != at)
3523 mismatch (e->tok, at, ft);
3524 if (at == pe_unknown)
3525 unresolved (e->tok);
3526 }
3527 }
3528
3529
3530 void
3531 typeresolution_info::visit_block (block* e)
3532 {
3533 for (unsigned i=0; i<e->statements.size(); i++)
3534 {
3535 try
3536 {
3537 t = pe_unknown;
3538 e->statements[i]->visit (this);
3539 }
3540 catch (const semantic_error& e)
3541 {
3542 session.print_error (e);
3543 }
3544 }
3545 }
3546
3547
3548 void
3549 typeresolution_info::visit_embeddedcode (embeddedcode*)
3550 {
3551 }
3552
3553
3554 void
3555 typeresolution_info::visit_if_statement (if_statement* e)
3556 {
3557 t = pe_long;
3558 e->condition->visit (this);
3559
3560 t = pe_unknown;
3561 e->thenblock->visit (this);
3562
3563 if (e->elseblock)
3564 {
3565 t = pe_unknown;
3566 e->elseblock->visit (this);
3567 }
3568 }
3569
3570
3571 void
3572 typeresolution_info::visit_for_loop (for_loop* e)
3573 {
3574 t = pe_unknown;
3575 if (e->init) e->init->visit (this);
3576 t = pe_long;
3577 e->cond->visit (this);
3578 t = pe_unknown;
3579 if (e->incr) e->incr->visit (this);
3580 t = pe_unknown;
3581 e->block->visit (this);
3582 }
3583
3584
3585 void
3586 typeresolution_info::visit_foreach_loop (foreach_loop* e)
3587 {
3588 // See also visit_arrayindex.
3589 // This is different in that, being a statement, we can't assign
3590 // a type to the outer array, only propagate to/from the indexes
3591
3592 // if (e->referent->index_types.size() == 0)
3593 // // redesignate referent as array
3594 // e->referent->set_arity (e->indexes.size ());
3595
3596 symbol *array = NULL;
3597 hist_op *hist = NULL;
3598 classify_indexable(e->base, array, hist);
3599
3600 if (hist)
3601 {
3602 if (e->indexes.size() != 1)
3603 unresolved (e->tok);
3604 t = pe_long;
3605 e->indexes[0]->visit (this);
3606 if (e->indexes[0]->type != pe_long)
3607 unresolved (e->tok);
3608 hist->visit (this);
3609 }
3610 else
3611 {
3612 assert (array);
3613 if (e->indexes.size() != array->referent->index_types.size())
3614 unresolved (e->tok); // symbol resolution should prevent this
3615 else for (unsigned i=0; i<e->indexes.size(); i++)
3616 {
3617 expression* ee = e->indexes[i];
3618 exp_type& ft = array->referent->index_types [i];
3619 t = ft;
3620 ee->visit (this);
3621 exp_type at = ee->type;
3622
3623 if ((at == pe_string || at == pe_long) && ft == pe_unknown)
3624 {
3625 // propagate to formal type
3626 ft = at;
3627 resolved (array->referent->tok, ft);
3628 // uses array decl as there is no token for "formal type"
3629 }
3630 if (at == pe_stats)
3631 invalid (ee->tok, at);
3632 if (ft == pe_stats)
3633 invalid (ee->tok, ft);
3634 if (at != pe_unknown && ft != pe_unknown && ft != at)
3635 mismatch (e->tok, at, ft);
3636 if (at == pe_unknown)
3637 unresolved (ee->tok);
3638 }
3639 }
3640
3641 if (e->limit)
3642 {
3643 t = pe_long;
3644 e->limit->visit (this);
3645 }
3646
3647 t = pe_unknown;
3648 e->block->visit (this);
3649 }
3650
3651
3652 void
3653 typeresolution_info::visit_null_statement (null_statement*)
3654 {
3655 }
3656
3657
3658 void
3659 typeresolution_info::visit_expr_statement (expr_statement* e)
3660 {
3661 t = pe_unknown;
3662 e->value->visit (this);
3663 }
3664
3665
3666 struct delete_statement_typeresolution_info:
3667 public throwing_visitor
3668 {
3669 typeresolution_info *parent;
3670 delete_statement_typeresolution_info (typeresolution_info *p):
3671 throwing_visitor ("invalid operand of delete expression"),
3672 parent (p)
3673 {}
3674
3675 void visit_arrayindex (arrayindex* e)
3676 {
3677 parent->visit_arrayindex (e);
3678 }
3679
3680 void visit_symbol (symbol* e)
3681 {
3682 exp_type ignored = pe_unknown;
3683 assert (e->referent != 0);
3684 resolve_2types (e, e->referent, parent, ignored);
3685 }
3686 };
3687
3688
3689 void
3690 typeresolution_info::visit_delete_statement (delete_statement* e)
3691 {
3692 delete_statement_typeresolution_info di (this);
3693 t = pe_unknown;
3694 e->value->visit (&di);
3695 }
3696
3697
3698 void
3699 typeresolution_info::visit_next_statement (next_statement*)
3700 {
3701 }
3702
3703
3704 void
3705 typeresolution_info::visit_break_statement (break_statement*)
3706 {
3707 }
3708
3709
3710 void
3711 typeresolution_info::visit_continue_statement (continue_statement*)
3712 {
3713 }
3714
3715
3716 void
3717 typeresolution_info::visit_array_in (array_in* e)
3718 {
3719 // all unary operators only work on numerics
3720 exp_type t1 = t;
3721 t = pe_unknown; // array value can be anything
3722 e->operand->visit (this);
3723
3724 if (t1 == pe_unknown && e->type != pe_unknown)
3725 ; // already resolved
3726 else if (t1 == pe_string || t1 == pe_stats)
3727 mismatch (e->tok, t1, pe_long);
3728 else if (e->type == pe_unknown)
3729 {
3730 e->type = pe_long;
3731 resolved (e->tok, e->type);
3732 }
3733 }
3734
3735
3736 void
3737 typeresolution_info::visit_return_statement (return_statement* e)
3738 {
3739 // This is like symbol, where the referent is
3740 // the return value of the function.
3741
3742 // translation pass will print error
3743 if (current_function == 0)
3744 return;
3745
3746 exp_type& e_type = current_function->type;
3747 t = current_function->type;
3748 e->value->visit (this);
3749
3750 if (e_type != pe_unknown && e->value->type != pe_unknown
3751 && e_type != e->value->type)
3752 mismatch (current_function->tok, e_type, e->value->type);
3753 if (e_type == pe_unknown &&
3754 (e->value->type == pe_long || e->value->type == pe_string))
3755 {
3756 // propagate non-statistics from value
3757 e_type = e->value->type;
3758 resolved (current_function->tok, e->value->type);
3759 }
3760 if (e->value->type == pe_stats)
3761 invalid (e->value->tok, e->value->type);
3762 }
3763
3764 void
3765 typeresolution_info::visit_print_format (print_format* e)
3766 {
3767 size_t unresolved_args = 0;
3768
3769 if (e->hist)
3770 {
3771 e->hist->visit(this);
3772 }
3773
3774 else if (e->print_with_format)
3775 {
3776 // If there's a format string, we can do both inference *and*
3777 // checking.
3778
3779 // First we extract the subsequence of formatting components
3780 // which are conversions (not just literal string components)
3781
3782 unsigned expected_num_args = 0;
3783 std::vector<print_format::format_component> components;
3784 for (size_t i = 0; i < e->components.size(); ++i)
3785 {
3786 if (e->components[i].type == print_format::conv_unspecified)
3787 throw semantic_error ("Unspecified conversion in print operator format string",
3788 e->tok);
3789 else if (e->components[i].type == print_format::conv_literal
3790 || e->components[i].type == print_format::conv_size)
3791 continue;
3792 components.push_back(e->components[i]);
3793 ++expected_num_args;
3794 if (e->components[i].widthtype == print_format::width_dynamic)
3795 ++expected_num_args;
3796 if (e->components[i].prectype == print_format::prec_dynamic)
3797 ++expected_num_args;
3798 }
3799
3800 // Then we check that the number of conversions and the number
3801 // of args agree.
3802
3803 if (expected_num_args != e->args.size())
3804 throw semantic_error ("Wrong number of args to formatted print operator",
3805 e->tok);
3806
3807 // Then we check that the types of the conversions match the types
3808 // of the args.
3809 unsigned argno = 0;
3810 for (size_t i = 0; i < components.size(); ++i)
3811 {
3812 // Check the dynamic width, if specified
3813 if (components[i].widthtype == print_format::width_dynamic)
3814 {
3815 check_arg_type (pe_long, e->args[argno]);
3816 ++argno;
3817 }
3818
3819 // Check the dynamic precision, if specified
3820 if (components[i].prectype == print_format::prec_dynamic)
3821 {
3822 check_arg_type (pe_long, e->args[argno]);
3823 ++argno;
3824 }
3825
3826 exp_type wanted = pe_unknown;
3827
3828 switch (components[i].type)
3829 {
3830 case print_format::conv_unspecified:
3831 case print_format::conv_literal:
3832 case print_format::conv_size:
3833 assert (false);
3834 break;
3835
3836 case print_format::conv_signed_decimal:
3837 case print_format::conv_unsigned_decimal:
3838 case print_format::conv_unsigned_octal:
3839 case print_format::conv_unsigned_ptr:
3840 case print_format::conv_unsigned_uppercase_hex:
3841 case print_format::conv_unsigned_lowercase_hex:
3842 case print_format::conv_binary:
3843 case print_format::conv_memory:
3844 wanted = pe_long;
3845 break;
3846
3847 case print_format::conv_string:
3848 wanted = pe_string;
3849 break;
3850 }
3851
3852 assert (wanted != pe_unknown);
3853 check_arg_type (wanted, e->args[argno]);
3854 ++argno;
3855 }
3856 }
3857 else
3858 {
3859 // Without a format string, the best we can do is require that
3860 // each argument resolve to a concrete type.
3861 for (size_t i = 0; i < e->args.size(); ++i)
3862 {
3863 t = pe_unknown;
3864 e->args[i]->visit (this);
3865 if (e->args[i]->type == pe_unknown)
3866 {
3867 unresolved (e->args[i]->tok);
3868 ++unresolved_args;
3869 }
3870 }
3871 }
3872
3873 if (unresolved_args == 0)
3874 {
3875 if (e->type == pe_unknown)
3876 {
3877 if (e->print_to_stream)
3878 e->type = pe_long;
3879 else
3880 e->type = pe_string;
3881 resolved (e->tok, e->type);
3882 }
3883 }
3884 else
3885 {
3886 e->type = pe_unknown;
3887 unresolved (e->tok);
3888 }
3889 }
3890
3891
3892 void
3893 typeresolution_info::visit_stat_op (stat_op* e)
3894 {
3895 t = pe_stats;
3896 e->stat->visit (this);
3897 if (e->type == pe_unknown)
3898 {
3899 e->type = pe_long;
3900 resolved (e->tok, e->type);
3901 }
3902 else if (e->type != pe_long)
3903 mismatch (e->tok, e->type, pe_long);
3904 }
3905
3906 void
3907 typeresolution_info::visit_hist_op (hist_op* e)
3908 {
3909 t = pe_stats;
3910 e->stat->visit (this);
3911 }
3912
3913
3914 void
3915 typeresolution_info::check_arg_type (exp_type wanted, expression* arg)
3916 {
3917 t = wanted;
3918 arg->visit (this);
3919
3920 if (arg->type == pe_unknown)
3921 {
3922 arg->type = wanted;
3923 resolved (arg->tok, wanted);
3924 }
3925 else if (arg->type != wanted)
3926 {
3927 mismatch (arg->tok, arg->type, wanted);
3928 }
3929 }
3930
3931
3932 void
3933 typeresolution_info::unresolved (const token* tok)
3934 {
3935 num_still_unresolved ++;
3936
3937 if (assert_resolvability)
3938 {
3939 stringstream msg;
3940 string nm = (current_function ? current_function->name :
3941 current_probe ? current_probe->name :
3942 "probe condition");
3943 msg << nm + " with unresolved type";
3944 session.print_error (semantic_error (msg.str(), tok));
3945 }
3946 }
3947
3948
3949 void
3950 typeresolution_info::invalid (const token* tok, exp_type pe)
3951 {
3952 num_still_unresolved ++;
3953
3954 if (assert_resolvability)
3955 {
3956 stringstream msg;
3957 string nm = (current_function ? current_function->name :
3958 current_probe ? current_probe->name :
3959 "probe condition");
3960 if (tok && tok->type == tok_operator)
3961 msg << nm + " uses invalid operator";
3962 else
3963 msg << nm + " with invalid type " << pe;
3964 session.print_error (semantic_error (msg.str(), tok));
3965 }
3966 }
3967
3968
3969 void
3970 typeresolution_info::mismatch (const token* tok, exp_type t1, exp_type t2)
3971 {
3972 num_still_unresolved ++;
3973
3974 if (assert_resolvability)
3975 {
3976 stringstream msg;
3977 string nm = (current_function ? current_function->name :
3978 current_probe ? current_probe->name :
3979 "probe condition");
3980 msg << nm + " with type mismatch (" << t1 << " vs. " << t2 << ")";
3981 session.print_error (semantic_error (msg.str(), tok));
3982 }
3983 }
3984
3985
3986 void
3987 typeresolution_info::resolved (const token*, exp_type)
3988 {
3989 num_newly_resolved ++;
3990 }
3991
This page took 0.220976 seconds and 6 git commands to generate.